gdkwindow-x11.c 168 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
/* GDK - The GIMP Drawing Kit
2 3
 * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
 * Josh MacDonald, Ryan Lortie
Elliot Lee's avatar
Elliot Lee committed
4 5
 *
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
13
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
16
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18

19
/*
20
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
21 22 23 24 25
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

26
#include "config.h"
27

28
#include "gdkwindow-x11.h"
29

Owen Taylor's avatar
Started  
Owen Taylor committed
30
#include "gdkwindow.h"
31
#include "gdkwindowimpl.h"
32
#include "gdkvisualprivate.h"
33
#include "gdkinternals.h"
34
#include "gdkdeviceprivate.h"
35
#include "gdkframeclockprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
36
#include "gdkasync.h"
37
#include "gdkeventsource.h"
Matthias Clasen's avatar
Matthias Clasen committed
38
#include "gdkdisplay-x11.h"
39
#include "gdkglcontext-x11.h"
Matthias Clasen's avatar
Matthias Clasen committed
40
#include "gdkprivate-x11.h"
41
#include "gdk-private.h"
42

43 44 45
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
46 47 48 49 50 51
#include <netinet/in.h>
#include <unistd.h>

#include <cairo-xlib.h>

#include "MwmUtil.h"
52

53 54 55
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
Elliot Lee's avatar
Elliot Lee committed
56

57 58
#include <X11/extensions/shape.h>

59 60 61 62
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif

63 64 65 66 67 68 69 70 71 72 73 74
#ifdef HAVE_XCOMPOSITE
#include <X11/extensions/Xcomposite.h>
#endif

#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif

#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif

75
const int _gdk_x11_event_mask_table[21] =
Elliot Lee's avatar
Elliot Lee committed
76 77 78 79 80 81 82 83
{
  ExposureMask,
  PointerMotionMask,
  PointerMotionHintMask,
  ButtonMotionMask,
  Button1MotionMask,
  Button2MotionMask,
  Button3MotionMask,
84 85
  ButtonPressMask,
  ButtonReleaseMask,
Elliot Lee's avatar
Elliot Lee committed
86 87 88 89 90 91 92
  KeyPressMask,
  KeyReleaseMask,
  EnterWindowMask,
  LeaveWindowMask,
  FocusChangeMask,
  StructureNotifyMask,
  PropertyChangeMask,
93
  VisibilityChangeMask,
94 95
  0,                    /* PROXIMITY_IN */
  0,                    /* PROXIMTY_OUT */
96 97
  SubstructureNotifyMask,
  ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
Elliot Lee's avatar
Elliot Lee committed
98
};
99 100

const gint _gdk_x11_event_mask_table_size = G_N_ELEMENTS (_gdk_x11_event_mask_table);
Elliot Lee's avatar
Elliot Lee committed
101

102
/* Forward declarations */
103
static void     gdk_x11_window_apply_fullscreen_mode (GdkWindow  *window);
104
static gboolean gdk_window_icon_name_set          (GdkWindow  *window);
105 106 107
static void     set_wm_name                       (GdkDisplay  *display,
						   Window       xwindow,
						   const gchar *name);
108
static void     move_to_current_desktop           (GdkWindow *window);
109 110
static void     gdk_window_x11_set_background     (GdkWindow      *window,
                                                   cairo_pattern_t *pattern);
Elliot Lee's avatar
Elliot Lee committed
111

112
static void        gdk_window_impl_x11_finalize   (GObject            *object);
113

114 115 116 117 118 119 120 121
#define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window)           \
  (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL ||   \
   GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP ||       \
   GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN)

#define WINDOW_IS_TOPLEVEL(window)                      \
  (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL ||   \
   GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
122

Matthias Clasen's avatar
Matthias Clasen committed
123 124 125 126 127 128 129 130
/* Return whether time1 is considered later than time2 as far as xserver
 * time is concerned.  Accounts for wraparound.
 */
#define XSERVER_TIME_IS_LATER(time1, time2)                        \
  ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) ||  \
    (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 ))     \
  )

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
struct _GdkX11Window {
  GdkWindow parent;
};

struct _GdkX11WindowClass {
  GdkWindowClass parent_class;
};

G_DEFINE_TYPE (GdkX11Window, gdk_x11_window, GDK_TYPE_WINDOW)

static void
gdk_x11_window_class_init (GdkX11WindowClass *x11_window_class)
{
}

static void
gdk_x11_window_init (GdkX11Window *x11_window)
{
}


152
G_DEFINE_TYPE (GdkWindowImplX11, gdk_window_impl_x11, GDK_TYPE_WINDOW_IMPL)
153 154 155

static void
gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
156
{  
157 158
  impl->device_cursor = g_hash_table_new_full (NULL, NULL,
                                               NULL, g_object_unref);
159
  impl->window_scale = 1;
160
  impl->frame_sync_enabled = TRUE;
rhlabs's avatar
rhlabs committed
161 162
}

163 164 165 166 167 168 169
GdkToplevelX11 *
_gdk_x11_window_get_toplevel (GdkWindow *window)
{
  GdkWindowImplX11 *impl;
  
  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);

170
  if (!WINDOW_IS_TOPLEVEL (window))
171 172
    return NULL;

173
  impl = GDK_WINDOW_IMPL_X11 (window->impl);
174 175

  if (!impl->toplevel)
176 177 178 179
    {
      impl->toplevel = g_new0 (GdkToplevelX11, 1);
      impl->toplevel->have_focused = TRUE;
    }
180 181 182 183

  return impl->toplevel;
}

184
/**
185 186
 * _gdk_x11_window_update_size:
 * @impl: a #GdkWindowImplX11.
187
 * 
188
 * Updates the state of the window (in particular the drawable's
189 190 191
 * cairo surface) when its size has changed.
 **/
void
192
_gdk_x11_window_update_size (GdkWindowImplX11 *impl)
193 194 195 196
{
  if (impl->cairo_surface)
    {
      cairo_xlib_surface_set_size (impl->cairo_surface,
197
                                   impl->unscaled_width, impl->unscaled_height);
198 199 200
    }
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214
void
gdk_x11_window_get_unscaled_size (GdkWindow *window,
                                  int *unscaled_width,
                                  int *unscaled_height)
{
  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);

  if (unscaled_width)
    *unscaled_width = impl->unscaled_width;

  if (unscaled_height)
    *unscaled_height = impl->unscaled_height;
}

215 216 217 218 219 220 221
static void
set_sync_counter(Display     *display,
		 XSyncCounter counter,
                 gint64       value)
{
    XSyncValue sync_value;

222 223 224 225
    XSyncIntsToValue (&sync_value,
                      value & G_GINT64_CONSTANT(0xFFFFFFFF),
                      value >> 32);
    XSyncSetCounter (display, counter, sync_value);
226 227
}

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
static void
window_pre_damage (GdkWindow *window)
{
  GdkWindow *toplevel_window = gdk_window_get_toplevel (window);
  GdkWindowImplX11 *impl;

  if (!toplevel_window || !WINDOW_IS_TOPLEVEL (toplevel_window))
    return;

  impl = GDK_WINDOW_IMPL_X11 (toplevel_window->impl);

  if (impl->toplevel->in_frame &&
      impl->toplevel->current_counter_value % 2 == 0)
    {
      impl->toplevel->current_counter_value += 1;
243 244 245
      set_sync_counter (GDK_WINDOW_XDISPLAY (impl->wrapper),
		        impl->toplevel->extended_update_counter,
                        impl->toplevel->current_counter_value);
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    }
}

static void
on_surface_changed (void *data)
{
  GdkWindow *window = data;

  window_pre_damage (window);
}

/* We want to know when cairo drawing causes damage to the window,
 * so we engage in the _NET_WM_FRAME_DRAWN protocol with the
 * window only when there actually is drawing. To do that we use
 * a technique (hack) suggested by Uli Schlachter - if we set
 * a dummy "mime data" on the cairo surface (this facility is
 * used to attach JPEG data to an imager), then cairo wil flush
 * and remove the mime data before making any changes to the window.
 */

static void
hook_surface_changed (GdkWindow *window)
{
  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);

  if (impl->cairo_surface)
    cairo_surface_set_mime_data (impl->cairo_surface,
                                 "x-gdk/change-notify",
                                 (unsigned char *)"X",
                                 1,
                                 on_surface_changed,
                                 window);
}

static void
unhook_surface_changed (GdkWindow *window)
{
  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);

  if (impl->cairo_surface)
    cairo_surface_set_mime_data (impl->cairo_surface,
                                 "x-gdk/change-notify",
                                 NULL, 0,
                                 NULL, NULL);
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305
static void
gdk_x11_window_predict_presentation_time (GdkWindow *window)
{
  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
  GdkFrameClock *clock;
  GdkFrameTimings *timings;
  gint64 presentation_time;
  gint64 refresh_interval;

  if (!WINDOW_IS_TOPLEVEL (window))
    return;

  clock = gdk_window_get_frame_clock (window);

306
  timings = gdk_frame_clock_get_current_timings (clock);
307 308

  gdk_frame_clock_get_refresh_info (clock,
309
                                    timings->frame_time,
310 311 312 313
                                    &refresh_interval, &presentation_time);

  if (presentation_time != 0)
    {
314
      if (timings->slept_before)
315 316 317 318 319
        {
          presentation_time += refresh_interval;
        }
      else
        {
320
          if (presentation_time < timings->frame_time + refresh_interval / 2)
321 322 323 324 325
            presentation_time += refresh_interval;
        }
    }
  else
    {
326 327
      if (timings->slept_before)
        presentation_time = timings->frame_time + refresh_interval + refresh_interval / 2;
328
      else
329
        presentation_time = timings->frame_time + refresh_interval;
330 331 332 333 334
    }

  if (presentation_time < impl->toplevel->throttled_presentation_time)
    presentation_time = impl->toplevel->throttled_presentation_time;

335
  timings->predicted_presentation_time = presentation_time;
336 337
}

338
static void
339 340
gdk_x11_window_begin_frame (GdkWindow *window,
                            gboolean   force_frame)
341 342 343 344 345 346 347 348 349 350 351
{
  GdkWindowImplX11 *impl;

  g_return_if_fail (GDK_IS_WINDOW (window));

  impl = GDK_WINDOW_IMPL_X11 (window->impl);

  if (!WINDOW_IS_TOPLEVEL (window) ||
      impl->toplevel->extended_update_counter == None)
    return;

352 353
  impl->toplevel->in_frame = TRUE;

354 355 356 357 358 359 360 361 362 363 364
  if (impl->toplevel->configure_counter_value != 0 &&
      impl->toplevel->configure_counter_value_is_extended)
    {
      impl->toplevel->current_counter_value = impl->toplevel->configure_counter_value;
      if ((impl->toplevel->current_counter_value % 2) == 1)
        impl->toplevel->current_counter_value += 1;

      impl->toplevel->configure_counter_value = 0;

      window_pre_damage (window);
    }
365 366 367 368 369 370 371
  else if (force_frame)
    {
      /* When mapping the window, we really want to freeze the
         rendering of the window by the compositor until we've
         actually painted something into the window's buffer. */
      window_pre_damage (window);
    }
372 373 374 375
  else
    {
      hook_surface_changed (window);
    }
376 377 378 379 380
}

static void
gdk_x11_window_end_frame (GdkWindow *window)
{
381 382
  GdkFrameClock *clock;
  GdkFrameTimings *timings;
383 384 385 386 387 388 389
  GdkWindowImplX11 *impl;

  g_return_if_fail (GDK_IS_WINDOW (window));

  impl = GDK_WINDOW_IMPL_X11 (window->impl);

  if (!WINDOW_IS_TOPLEVEL (window) ||
390 391
      impl->toplevel->extended_update_counter == None ||
      !impl->toplevel->in_frame)
392 393
    return;

394
  clock = gdk_window_get_frame_clock (window);
395
  timings = gdk_frame_clock_get_current_timings (clock);
396

397 398
  impl->toplevel->in_frame = FALSE;

399
  if (impl->toplevel->current_counter_value % 2 == 1)
400
    {
Owen W. Taylor's avatar
Owen W. Taylor committed
401 402 403 404 405 406 407 408 409 410 411 412
#ifdef G_ENABLE_DEBUG
      if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
        {
          XImage *image = XGetImage (GDK_WINDOW_XDISPLAY (window),
                                     GDK_WINDOW_XID (window),
                                     0, 0, 1, 1,
                                     (1 << 24) - 1,
                                     ZPixmap);
          XDestroyImage (image);
        }
#endif /* G_ENABLE_DEBUG */

413 414 415 416
      /* An increment of 3 means that the frame was not drawn as fast as possible,
       * but rather at a particular time. This can trigger different handling from
       * the compositor.
       */
417
      if (timings->slept_before)
418 419 420 421
        impl->toplevel->current_counter_value += 3;
      else
        impl->toplevel->current_counter_value += 1;

422 423 424 425
      set_sync_counter(GDK_WINDOW_XDISPLAY (impl->wrapper),
		       impl->toplevel->extended_update_counter,
		       impl->toplevel->current_counter_value);

426 427
      if (impl->frame_sync_enabled &&
          gdk_x11_screen_supports_net_wm_hint (gdk_window_get_screen (window),
428 429 430
					       gdk_atom_intern_static_string ("_NET_WM_FRAME_DRAWN")))
        {
          impl->toplevel->frame_pending = TRUE;
431
          _gdk_frame_clock_freeze (gdk_window_get_frame_clock (window));
432
          timings->cookie = impl->toplevel->current_counter_value;
433
        }
434
    }
435 436

  unhook_surface_changed (window);
437

438 439 440 441 442 443 444 445 446 447
  if (impl->toplevel->configure_counter_value != 0 &&
      !impl->toplevel->configure_counter_value_is_extended)
    {
      set_sync_counter (GDK_WINDOW_XDISPLAY (window),
                        impl->toplevel->update_counter,
                        impl->toplevel->configure_counter_value);

      impl->toplevel->configure_counter_value = 0;
    }

448
  if (!impl->toplevel->frame_pending)
449
    timings->complete = TRUE;
450 451
}

452 453 454 455 456
/*****************************************************
 * X11 specific implementations of generic functions *
 *****************************************************/

static cairo_surface_t *
457
gdk_x11_create_cairo_surface (GdkWindowImplX11 *impl,
458 459 460 461 462 463 464 465 466 467 468 469 470
			      int width,
			      int height)
{
  GdkVisual *visual;
    
  visual = gdk_window_get_visual (impl->wrapper);
  return cairo_xlib_surface_create (GDK_WINDOW_XDISPLAY (impl->wrapper),
                                    GDK_WINDOW_IMPL_X11 (impl)->xid,
                                    GDK_VISUAL_XVISUAL (visual),
                                    width, height);
}

static cairo_surface_t *
471
gdk_x11_ref_cairo_surface (GdkWindow *window)
472
{
473
  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
474

475
  if (GDK_WINDOW_DESTROYED (window))
476 477 478 479
    return NULL;

  if (!impl->cairo_surface)
    {
480
      impl->cairo_surface = gdk_x11_create_cairo_surface (impl,
481 482 483
                                                          gdk_window_get_width (window) * impl->window_scale,
                                                          gdk_window_get_height (window) * impl->window_scale);
      cairo_surface_set_device_scale (impl->cairo_surface, impl->window_scale, impl->window_scale);
484 485 486

      if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel->in_frame)
        hook_surface_changed (window);
487
    }
488 489

  cairo_surface_reference (impl->cairo_surface);
490 491 492 493

  return impl->cairo_surface;
}

494 495 496
static void
gdk_window_impl_x11_finalize (GObject *object)
{
497
  GdkWindow *wrapper;
498
  GdkWindowImplX11 *impl;
499

500 501
  g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));

502
  impl = GDK_WINDOW_IMPL_X11 (object);
503

504
  wrapper = impl->wrapper;
505

506 507 508
  if (WINDOW_IS_TOPLEVEL (wrapper) && impl->toplevel->in_frame)
    unhook_surface_changed (wrapper);

509
  _gdk_x11_window_grab_check_destroy (wrapper);
510

511
  if (!GDK_WINDOW_DESTROYED (wrapper))
512
    {
513
      GdkDisplay *display = GDK_WINDOW_DISPLAY (wrapper);
514

515
      _gdk_x11_display_remove_window (display, impl->xid);
516
      if (impl->toplevel && impl->toplevel->focus_window)
517
        _gdk_x11_display_remove_window (display, impl->toplevel->focus_window);
518 519
    }

520
  g_free (impl->toplevel);
521

522
  if (impl->cursor)
523
    g_object_unref (impl->cursor);
524

525
  g_hash_table_destroy (impl->device_cursor);
526

Matthias Clasen's avatar
Matthias Clasen committed
527
  G_OBJECT_CLASS (gdk_window_impl_x11_parent_class)->finalize (object);
528
}
529

Benjamin Otte's avatar
Benjamin Otte committed
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
typedef struct {
  GdkDisplay *display;
  Pixmap pixmap;
} FreePixmapData;

static void
free_pixmap (gpointer datap)
{
  FreePixmapData *data = datap;

  if (!gdk_display_is_closed (data->display))
    {
      XFreePixmap (GDK_DISPLAY_XDISPLAY (data->display),
                   data->pixmap);
    }

  g_object_unref (data->display);
  g_slice_free (FreePixmapData, data);
}

static void
attach_free_pixmap_handler (cairo_surface_t *surface,
                            GdkDisplay      *display,
                            Pixmap           pixmap)
{
  static const cairo_user_data_key_t key;
  FreePixmapData *data;
  
  data = g_slice_new (FreePixmapData);
  data->display = g_object_ref (display);
  data->pixmap = pixmap;

  cairo_surface_set_user_data (surface, &key, data, free_pixmap);
}

/* Cairo does not guarantee we get an xlib surface if we call
 * cairo_surface_create_similar(). In some cases however, we must use a
 * pixmap or bitmap in the X11 API.
 * These functions ensure an Xlib surface.
 */
570 571 572 573
cairo_surface_t *
_gdk_x11_window_create_bitmap_surface (GdkWindow *window,
                                       int        width,
                                       int        height)
Benjamin Otte's avatar
Benjamin Otte committed
574 575 576 577 578 579 580 581 582
{
  cairo_surface_t *surface;
  Pixmap pixmap;

  pixmap = XCreatePixmap (GDK_WINDOW_XDISPLAY (window),
                          GDK_WINDOW_XID (window),
                          width, height, 1);
  surface = cairo_xlib_surface_create_for_bitmap (GDK_WINDOW_XDISPLAY (window),
                                                  pixmap,
583
                                                  GDK_X11_SCREEN (GDK_WINDOW_SCREEN (window))->xscreen,
Benjamin Otte's avatar
Benjamin Otte committed
584 585 586 587 588 589
                                                  width, height);
  attach_free_pixmap_handler (surface, GDK_WINDOW_DISPLAY (window), pixmap);

  return surface;
}

590
/* Create a surface backed with a pixmap without alpha on the same screen as window */
Benjamin Otte's avatar
Benjamin Otte committed
591 592 593 594 595
static cairo_surface_t *
gdk_x11_window_create_pixmap_surface (GdkWindow *window,
                                      int        width,
                                      int        height)
{
596 597
  GdkScreen *screen = gdk_window_get_screen (window);
  GdkVisual *visual = gdk_screen_get_system_visual (screen);
Benjamin Otte's avatar
Benjamin Otte committed
598 599 600 601 602 603
  cairo_surface_t *surface;
  Pixmap pixmap;

  pixmap = XCreatePixmap (GDK_WINDOW_XDISPLAY (window),
                          GDK_WINDOW_XID (window),
                          width, height,
604
                          gdk_visual_get_depth (visual));
Benjamin Otte's avatar
Benjamin Otte committed
605 606
  surface = cairo_xlib_surface_create (GDK_WINDOW_XDISPLAY (window),
                                       pixmap,
607
                                       GDK_VISUAL_XVISUAL (visual),
Benjamin Otte's avatar
Benjamin Otte committed
608 609 610 611 612 613
                                       width, height);
  attach_free_pixmap_handler (surface, GDK_WINDOW_DISPLAY (window), pixmap);

  return surface;
}

Soeren Sandmann's avatar
Soeren Sandmann committed
614 615 616 617 618
static void
tmp_unset_bg (GdkWindow *window)
{
  GdkWindowImplX11 *impl;

619
  impl = GDK_WINDOW_IMPL_X11 (window->impl);
Soeren Sandmann's avatar
Soeren Sandmann committed
620

621
  impl->no_bg = TRUE;
Soeren Sandmann's avatar
Soeren Sandmann committed
622

623 624
  XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
                              GDK_WINDOW_XID (window), None);
Soeren Sandmann's avatar
Soeren Sandmann committed
625 626 627 628 629 630 631
}

static void
tmp_reset_bg (GdkWindow *window)
{
  GdkWindowImplX11 *impl;

632
  impl = GDK_WINDOW_IMPL_X11 (window->impl);
Soeren Sandmann's avatar
Soeren Sandmann committed
633

634
  impl->no_bg = FALSE;
Soeren Sandmann's avatar
Soeren Sandmann committed
635

636
  gdk_window_x11_set_background (window, window->background);
Soeren Sandmann's avatar
Soeren Sandmann committed
637 638
}

639 640 641 642 643 644 645
/* Unsetting and resetting window backgrounds.
 *
 * In many cases it is possible to avoid flicker by unsetting the
 * background of windows. For example if the background of the
 * parent window is unset when a window is unmapped, a brief flicker
 * of background painting is avoided.
 */
Soeren Sandmann's avatar
Soeren Sandmann committed
646 647 648 649 650 651
void
_gdk_x11_window_tmp_unset_bg (GdkWindow *window,
			      gboolean   recurse)
{
  g_return_if_fail (GDK_IS_WINDOW (window));
  
652 653
  if (window->input_only || window->destroyed ||
      (window->window_type != GDK_WINDOW_ROOT &&
654 655 656 657 658
       !GDK_WINDOW_IS_MAPPED (window)))
    return;
  
  if (_gdk_window_has_impl (window) &&
      GDK_WINDOW_IS_X11 (window) &&
659 660
      window->window_type != GDK_WINDOW_ROOT &&
      window->window_type != GDK_WINDOW_FOREIGN)
661
    tmp_unset_bg (window);
Soeren Sandmann's avatar
Soeren Sandmann committed
662 663 664 665 666

  if (recurse)
    {
      GList *l;

667
      for (l = window->children; l != NULL; l = l->next)
Soeren Sandmann's avatar
Soeren Sandmann committed
668 669 670 671
	_gdk_x11_window_tmp_unset_bg (l->data, TRUE);
    }
}

672
void
673
_gdk_x11_window_tmp_unset_parent_bg (GdkWindow *window)
674
{
675
  if (GDK_WINDOW_TYPE (window->parent) == GDK_WINDOW_ROOT)
676
    return;
677
  
678
  window = _gdk_window_get_impl_window (window->parent);
679
  _gdk_x11_window_tmp_unset_bg (window,	FALSE);
680 681
}

Soeren Sandmann's avatar
Soeren Sandmann committed
682 683 684 685 686 687
void
_gdk_x11_window_tmp_reset_bg (GdkWindow *window,
			      gboolean   recurse)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

688 689
  if (window->input_only || window->destroyed ||
      (window->window_type != GDK_WINDOW_ROOT &&
690 691
       !GDK_WINDOW_IS_MAPPED (window)))
    return;
Soeren Sandmann's avatar
Soeren Sandmann committed
692

693 694 695
  
  if (_gdk_window_has_impl (window) &&
      GDK_WINDOW_IS_X11 (window) &&
696 697
      window->window_type != GDK_WINDOW_ROOT &&
      window->window_type != GDK_WINDOW_FOREIGN)
698
    tmp_reset_bg (window);
Soeren Sandmann's avatar
Soeren Sandmann committed
699 700 701 702 703

  if (recurse)
    {
      GList *l;

704
      for (l = window->children; l != NULL; l = l->next)
Soeren Sandmann's avatar
Soeren Sandmann committed
705 706 707 708
	_gdk_x11_window_tmp_reset_bg (l->data, TRUE);
    }
}

709
void
710
_gdk_x11_window_tmp_reset_parent_bg (GdkWindow *window)
711
{
712
  if (GDK_WINDOW_TYPE (window->parent) == GDK_WINDOW_ROOT)
713 714
    return;
  
715
  window = _gdk_window_get_impl_window (window->parent);
716

717
  _gdk_x11_window_tmp_reset_bg (window, FALSE);
718 719
}

Elliot Lee's avatar
Elliot Lee committed
720
void
721
_gdk_x11_screen_init_root_window (GdkScreen *screen)
Elliot Lee's avatar
Elliot Lee committed
722
{
723
  GdkWindow *window;
724
  GdkWindowImplX11 *impl;
725
  GdkX11Screen *x11_screen;
726

727
  x11_screen = GDK_X11_SCREEN (screen);
728

729
  g_assert (x11_screen->root_window == NULL);
730

731
  window = x11_screen->root_window = _gdk_display_create_window (gdk_screen_get_display (screen));
732

733
  window->impl = g_object_new (GDK_TYPE_WINDOW_IMPL_X11, NULL);
734 735
  window->impl_window = window;
  window->visual = gdk_screen_get_system_visual (screen);
736

737
  impl = GDK_WINDOW_IMPL_X11 (window->impl);
738
  
739
  impl->xid = x11_screen->xroot_window;
740
  impl->wrapper = window;
741
  impl->window_scale = x11_screen->window_scale;
742
  
743
  window->window_type = GDK_WINDOW_ROOT;
744
  window->depth = DefaultDepthOfScreen (x11_screen->xscreen);
745

746 747 748 749
  window->x = 0;
  window->y = 0;
  window->abs_x = 0;
  window->abs_y = 0;
750 751
  impl->unscaled_width = WidthOfScreen (x11_screen->xscreen);
  impl->unscaled_height = HeightOfScreen (x11_screen->xscreen);
752 753
  window->width = WidthOfScreen (x11_screen->xscreen) / impl->window_scale;
  window->height = HeightOfScreen (x11_screen->xscreen) / impl->window_scale;
754
  window->viewable = TRUE;
755 756

  /* see init_randr_support() in gdkscreen-x11.c */
757
  window->event_mask = GDK_STRUCTURE_MASK;
758

759
  _gdk_window_update_size (x11_screen->root_window);
760

761 762 763
  _gdk_x11_display_add_window (x11_screen->display,
                               &x11_screen->xroot_window,
                               x11_screen->root_window);
Elliot Lee's avatar
Elliot Lee committed
764 765
}

766 767 768
static void
set_wm_protocols (GdkWindow *window)
{
769
  GdkDisplay *display = gdk_window_get_display (window);
770 771
  Atom protocols[4];
  int n = 0;
772
  
773
  protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW");
774
  protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
775
  protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING");
776

777
#ifdef HAVE_XSYNC
778
  if (GDK_X11_DISPLAY (display)->use_sync)
779 780 781 782
    protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST");
#endif
  
  XSetWMProtocols (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), protocols, n);
783
}
784

785 786 787 788 789 790 791 792
static const gchar *
get_default_title (void)
{
  const char *title;

  title = g_get_application_name ();
  if (!title)
    title = g_get_prgname ();
Matthias Clasen's avatar
Matthias Clasen committed
793 794
  if (!title)
    title = "";
795 796 797 798 799 800 801

  return title;
}

static void
check_leader_window_title (GdkDisplay *display)
{
802
  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
803

804
  if (display_x11->leader_window && !display_x11->leader_window_title_set)
805 806 807 808 809 810 811 812 813
    {
      set_wm_name (display,
		   display_x11->leader_window,
		   get_default_title ());
      
      display_x11->leader_window_title_set = TRUE;
    }
}

814
static Window
815 816
create_focus_window (GdkDisplay *display,
		     XID         parent)
817
{
818
  GdkX11Display *display_x11;
819 820 821
  GdkEventMask event_mask;
  Display *xdisplay;
  Window focus_window;
822
  XSetWindowAttributes attrs;
823 824

  xdisplay = GDK_DISPLAY_XDISPLAY (display);
825
  display_x11 = GDK_X11_DISPLAY (display);
826

827 828 829 830 831
  focus_window = XCreateWindow (xdisplay, parent,
                                -1, -1, 1, 1, 0,
                                0, /* depth */
                                InputOnly,
                                CopyFromParent,
832
                                0, &attrs);
833 834 835 836 837

  event_mask = (GDK_KEY_PRESS_MASK |
                GDK_KEY_RELEASE_MASK |
                GDK_FOCUS_CHANGE_MASK);

838 839 840
  gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
                                      focus_window,
                                      event_mask, 0);
841

842 843 844 845 846
  XMapWindow (xdisplay, focus_window);

  return focus_window;
}

847 848 849 850 851 852 853 854 855
static void
ensure_sync_counter (GdkWindow *window)
{
#ifdef HAVE_XSYNC
  if (!GDK_WINDOW_DESTROYED (window))
    {
      GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
      GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);

856
      if (toplevel &&
857
	  toplevel->update_counter == None &&
858
	  GDK_X11_DISPLAY (display)->use_sync)
859 860 861 862
	{
	  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
	  XSyncValue value;
	  Atom atom;
863
	  XID counters[2];
864 865 866 867

	  XSyncIntToValue (&value, 0);
	  
	  toplevel->update_counter = XSyncCreateCounter (xdisplay, value);
868
	  toplevel->extended_update_counter = XSyncCreateCounter (xdisplay, value);
869 870 871
	  
	  atom = gdk_x11_get_xatom_by_name_for_display (display,
							"_NET_WM_SYNC_REQUEST_COUNTER");
872 873 874

	  counters[0] = toplevel->update_counter;
	  counters[1] = toplevel->extended_update_counter;
875 876 877
	  XChangeProperty (xdisplay, GDK_WINDOW_XID (window),
			   atom, XA_CARDINAL,
			   32, PropModeReplace,
878
			   (guchar *)counters, 2);
879
	  
880
	  toplevel->current_counter_value = 0;
881 882 883 884 885
	}
    }
#endif
}

886
static void
887 888
setup_toplevel_window (GdkWindow *window, 
		       GdkWindow *parent)
889 890
{
  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
891
  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
892
  GdkDisplay *display = gdk_window_get_display (window);
893 894
  Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
  XID xid = GDK_WINDOW_XID (window);
895
  GdkX11Screen *x11_screen = GDK_X11_SCREEN (GDK_WINDOW_SCREEN (parent));
896 897
  XSizeHints size_hints;
  long pid;
898
  Window leader_window;
899

900
  set_wm_protocols (window);
901

902
  if (!window->input_only)
903 904 905 906
    {
      /* The focus window is off the visible area, and serves to receive key
       * press events so they don't get sent to child windows.
       */
907
      toplevel->focus_window = create_focus_window (display, xid);
908
      _gdk_x11_display_add_window (x11_screen->display,
909 910
                                   &toplevel->focus_window,
                                   window);
911
    }
912

913
  check_leader_window_title (x11_screen->display);
914

915 916 917 918 919
  /* FIXME: Is there any point in doing this? Do any WM's pay
   * attention to PSize, and even if they do, is this the
   * correct value???
   */
  size_hints.flags = PSize;
920 921
  size_hints.width = window->width * impl->window_scale;
  size_hints.height = window->height * impl->window_scale;
922 923 924 925 926 927 928 929
  
  XSetWMNormalHints (xdisplay, xid, &size_hints);
  
  /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
  XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
  
  pid = getpid ();
  XChangeProperty (xdisplay, xid,
930
		   gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_PID"),
931 932 933
		   XA_CARDINAL, 32,
		   PropModeReplace,
		   (guchar *)&pid, 1);
934

935
  leader_window = GDK_X11_DISPLAY (x11_screen->display)->leader_window;
936 937
  if (!leader_window)
    leader_window = xid;
938
  XChangeProperty (xdisplay, xid, 
939
		   gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "WM_CLIENT_LEADER"),
940
		   XA_WINDOW, 32, PropModeReplace,
941
		   (guchar *) &leader_window, 1);
942

943 944
  if (toplevel->focus_window != None)
    XChangeProperty (xdisplay, xid, 
945
                     gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_USER_TIME_WINDOW"),
946 947 948
                     XA_WINDOW, 32, PropModeReplace,
                     (guchar *) &toplevel->focus_window, 1);

949
  if (!window->focus_on_map)
950
    gdk_x11_window_set_user_time (window, 0);
951 952
  else if (GDK_X11_DISPLAY (x11_screen->display)->user_time != 0)
    gdk_x11_window_set_user_time (window, GDK_X11_DISPLAY (x11_screen->display)->user_time);
953 954

  ensure_sync_counter (window);
955 956

  /* Start off in a frozen state - we'll finish this when we first paint */
957
  gdk_x11_window_begin_frame (window, TRUE);
958 959
}

960 961 962 963
static void
on_frame_clock_before_paint (GdkFrameClock *clock,
                             GdkWindow     *window)
{
964
  gdk_x11_window_predict_presentation_time (window);
965
  gdk_x11_window_begin_frame (window, FALSE);
966 967 968 969 970 971 972
}

static void
on_frame_clock_after_paint (GdkFrameClock *clock,
                            GdkWindow     *window)
{
  gdk_x11_window_end_frame (window);
973

974 975
}

976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
static void
connect_frame_clock (GdkWindow *window)
{
  GdkWindowImplX11 *impl;

  impl = GDK_WINDOW_IMPL_X11 (window->impl);
  if (WINDOW_IS_TOPLEVEL (window) && !impl->frame_clock_connected)
    {
      GdkFrameClock *frame_clock = gdk_window_get_frame_clock (window);

      g_signal_connect (frame_clock, "before-paint",
                        G_CALLBACK (on_frame_clock_before_paint), window);
      g_signal_connect (frame_clock, "after-paint",
                        G_CALLBACK (on_frame_clock_after_paint), window);

      impl->frame_clock_connected = TRUE;
    }
}

995
void
996 997 998 999 1000 1001 1002
_gdk_x11_display_create_window_impl (GdkDisplay    *display,
                                     GdkWindow     *window,
                                     GdkWindow     *real_parent,
                                     GdkScreen     *screen,
                                     GdkEventMask   event_mask,
                                     GdkWindowAttr *attributes,
                                     gint           attributes_mask)
Elliot Lee's avatar
Elliot Lee committed
1003
{
1004
  GdkWindowImplX11 *impl;
1005
  GdkX11Screen *x11_screen;
1006
  GdkX11Display *display_x11;
1007

Elliot Lee's avatar
Elliot Lee committed
1008 1009
  Window xparent;