mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-18 09:00:34 +00:00
eabac453e6
The history before this was kind of twisted as several different approaches were tested, so that was all squashed into this initial commit to hide the uninteresting changes and files that were later removed.
1459 lines
38 KiB
C
1459 lines
38 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
* gdkdisplay-x11.c
|
|
*
|
|
* Copyright 2001 Sun Microsystems Inc.
|
|
* Copyright (C) 2004 Nokia Corporation
|
|
*
|
|
* Erwann Chenede <erwann.chenede@sun.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#include <glib.h>
|
|
#include "gdkx.h"
|
|
#include "gdkdisplay.h"
|
|
#include "gdkdisplay-x11.h"
|
|
#include "gdkscreen.h"
|
|
#include "gdkscreen-x11.h"
|
|
#include "gdkinternals.h"
|
|
#include "gdkinputprivate.h"
|
|
#include "xsettings-client.h"
|
|
#include "gdkalias.h"
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#ifdef HAVE_XKB
|
|
#include <X11/XKBlib.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_XFIXES
|
|
#include <X11/extensions/Xfixes.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SHAPE_EXT
|
|
#include <X11/extensions/shape.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_XCOMPOSITE
|
|
#include <X11/extensions/Xcomposite.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_XDAMAGE
|
|
#include <X11/extensions/Xdamage.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_RANDR
|
|
#include <X11/extensions/Xrandr.h>
|
|
#endif
|
|
|
|
|
|
static void gdk_display_x11_dispose (GObject *object);
|
|
static void gdk_display_x11_finalize (GObject *object);
|
|
|
|
#ifdef HAVE_X11R6
|
|
static void gdk_internal_connection_watch (Display *display,
|
|
XPointer arg,
|
|
gint fd,
|
|
gboolean opening,
|
|
XPointer *watch_data);
|
|
#endif /* HAVE_X11R6 */
|
|
|
|
/* Note that we never *directly* use WM_LOCALE_NAME, WM_PROTOCOLS,
|
|
* but including them here has the side-effect of getting them
|
|
* into the internal Xlib cache
|
|
*/
|
|
static const char *const precache_atoms[] = {
|
|
"UTF8_STRING",
|
|
"WM_CLIENT_LEADER",
|
|
"WM_DELETE_WINDOW",
|
|
"WM_ICON_NAME",
|
|
"WM_LOCALE_NAME",
|
|
"WM_NAME",
|
|
"WM_PROTOCOLS",
|
|
"WM_TAKE_FOCUS",
|
|
"WM_WINDOW_ROLE",
|
|
"_NET_ACTIVE_WINDOW",
|
|
"_NET_CURRENT_DESKTOP",
|
|
"_NET_FRAME_EXTENTS",
|
|
"_NET_STARTUP_ID",
|
|
"_NET_WM_CM_S0",
|
|
"_NET_WM_DESKTOP",
|
|
"_NET_WM_ICON",
|
|
"_NET_WM_ICON_NAME",
|
|
"_NET_WM_NAME",
|
|
"_NET_WM_PID",
|
|
"_NET_WM_PING",
|
|
"_NET_WM_STATE",
|
|
"_NET_WM_STATE_ABOVE",
|
|
"_NET_WM_STATE_BELOW",
|
|
"_NET_WM_STATE_FULLSCREEN",
|
|
"_NET_WM_STATE_MODAL",
|
|
"_NET_WM_STATE_MAXIMIZED_VERT",
|
|
"_NET_WM_STATE_MAXIMIZED_HORZ",
|
|
"_NET_WM_STATE_SKIP_TASKBAR",
|
|
"_NET_WM_STATE_SKIP_PAGER",
|
|
"_NET_WM_STATE_STICKY",
|
|
"_NET_WM_SYNC_REQUEST",
|
|
"_NET_WM_SYNC_REQUEST_COUNTER",
|
|
"_NET_WM_WINDOW_TYPE",
|
|
"_NET_WM_WINDOW_TYPE_NORMAL",
|
|
"_NET_WM_USER_TIME",
|
|
"_NET_VIRTUAL_ROOTS"
|
|
};
|
|
|
|
G_DEFINE_TYPE (GdkDisplayX11, _gdk_display_x11, GDK_TYPE_DISPLAY)
|
|
|
|
static void
|
|
_gdk_display_x11_class_init (GdkDisplayX11Class * class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
|
|
object_class->dispose = gdk_display_x11_dispose;
|
|
object_class->finalize = gdk_display_x11_finalize;
|
|
}
|
|
|
|
static void
|
|
_gdk_display_x11_init (GdkDisplayX11 *display)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gdk_display_open:
|
|
* @display_name: the name of the display to open
|
|
* @returns: a #GdkDisplay, or %NULL if the display
|
|
* could not be opened.
|
|
*
|
|
* Opens a display.
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
GdkDisplay *
|
|
gdk_display_open (const gchar *display_name)
|
|
{
|
|
Display *xdisplay;
|
|
GdkDisplay *display;
|
|
GdkDisplayX11 *display_x11;
|
|
GdkWindowAttr attr;
|
|
gint argc;
|
|
gchar *argv[1];
|
|
const char *sm_client_id;
|
|
|
|
XClassHint *class_hint;
|
|
gulong pid;
|
|
gint i;
|
|
#if defined(HAVE_XFIXES) || defined(HAVE_SHAPE_EXT)
|
|
gint ignore;
|
|
gint maj, min;
|
|
#endif
|
|
|
|
xdisplay = XOpenDisplay (display_name);
|
|
if (!xdisplay)
|
|
return NULL;
|
|
|
|
display = g_object_new (GDK_TYPE_DISPLAY_X11, NULL);
|
|
display_x11 = GDK_DISPLAY_X11 (display);
|
|
|
|
display_x11->use_xshm = TRUE;
|
|
display_x11->xdisplay = xdisplay;
|
|
|
|
#ifdef HAVE_X11R6
|
|
/* Set up handlers for Xlib internal connections */
|
|
XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
|
|
#endif /* HAVE_X11R6 */
|
|
|
|
_gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
|
|
|
|
/* RandR must be initialized before we initialize the screens */
|
|
display_x11->have_randr13 = FALSE;
|
|
#ifdef HAVE_RANDR
|
|
if (XRRQueryExtension (display_x11->xdisplay,
|
|
&display_x11->xrandr_event_base, &ignore))
|
|
{
|
|
int major, minor;
|
|
|
|
XRRQueryVersion (display_x11->xdisplay, &major, &minor);
|
|
|
|
if ((major == 1 && minor >= 3) || major > 1)
|
|
display_x11->have_randr13 = TRUE;
|
|
|
|
gdk_x11_register_standard_event_type (display, display_x11->xrandr_event_base, RRNumberEvents);
|
|
}
|
|
#endif
|
|
|
|
/* initialize the display's screens */
|
|
display_x11->screens = g_new (GdkScreen *, ScreenCount (display_x11->xdisplay));
|
|
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
|
|
display_x11->screens[i] = _gdk_x11_screen_new (display, i);
|
|
|
|
/* We need to initialize events after we have the screen
|
|
* structures in places
|
|
*/
|
|
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
|
|
_gdk_x11_events_init_screen (display_x11->screens[i]);
|
|
|
|
/*set the default screen */
|
|
display_x11->default_screen = display_x11->screens[DefaultScreen (display_x11->xdisplay)];
|
|
|
|
attr.window_type = GDK_WINDOW_TOPLEVEL;
|
|
attr.wclass = GDK_INPUT_OUTPUT;
|
|
attr.x = 10;
|
|
attr.y = 10;
|
|
attr.width = 10;
|
|
attr.height = 10;
|
|
attr.event_mask = 0;
|
|
|
|
display_x11->leader_gdk_window = gdk_window_new (GDK_SCREEN_X11 (display_x11->default_screen)->root_window,
|
|
&attr, GDK_WA_X | GDK_WA_Y);
|
|
(_gdk_x11_window_get_toplevel (display_x11->leader_gdk_window))->is_leader = TRUE;
|
|
|
|
display_x11->leader_window = GDK_WINDOW_XID (display_x11->leader_gdk_window);
|
|
|
|
display_x11->leader_window_title_set = FALSE;
|
|
|
|
display_x11->have_render = GDK_UNKNOWN;
|
|
|
|
#ifdef HAVE_XFIXES
|
|
if (XFixesQueryExtension (display_x11->xdisplay,
|
|
&display_x11->xfixes_event_base,
|
|
&ignore))
|
|
{
|
|
display_x11->have_xfixes = TRUE;
|
|
|
|
gdk_x11_register_standard_event_type (display,
|
|
display_x11->xfixes_event_base,
|
|
XFixesNumberEvents);
|
|
}
|
|
else
|
|
#endif
|
|
display_x11->have_xfixes = FALSE;
|
|
|
|
#ifdef HAVE_XCOMPOSITE
|
|
if (XCompositeQueryExtension (display_x11->xdisplay,
|
|
&ignore, &ignore))
|
|
{
|
|
int major, minor;
|
|
|
|
XCompositeQueryVersion (display_x11->xdisplay, &major, &minor);
|
|
|
|
/* Prior to Composite version 0.4, composited windows clipped their
|
|
* parents, so you had to use IncludeInferiors to draw to the parent
|
|
* This isn't useful for our purposes, so require 0.4
|
|
*/
|
|
display_x11->have_xcomposite = major > 0 || (major == 0 && minor >= 4);
|
|
}
|
|
else
|
|
#endif
|
|
display_x11->have_xcomposite = FALSE;
|
|
|
|
#ifdef HAVE_XDAMAGE
|
|
if (XDamageQueryExtension (display_x11->xdisplay,
|
|
&display_x11->xdamage_event_base,
|
|
&ignore))
|
|
{
|
|
display_x11->have_xdamage = TRUE;
|
|
|
|
gdk_x11_register_standard_event_type (display,
|
|
display_x11->xdamage_event_base,
|
|
XDamageNumberEvents);
|
|
}
|
|
else
|
|
#endif
|
|
display_x11->have_xdamage = FALSE;
|
|
|
|
display_x11->have_shapes = FALSE;
|
|
display_x11->have_input_shapes = FALSE;
|
|
#ifdef HAVE_SHAPE_EXT
|
|
if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &ignore, &ignore))
|
|
{
|
|
display_x11->have_shapes = TRUE;
|
|
#ifdef ShapeInput
|
|
if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
|
|
display_x11->have_input_shapes = (maj == 1 && min >= 1);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
display_x11->trusted_client = TRUE;
|
|
{
|
|
Window root, child;
|
|
int rootx, rooty, winx, winy;
|
|
unsigned int xmask;
|
|
|
|
gdk_error_trap_push ();
|
|
XQueryPointer (display_x11->xdisplay,
|
|
GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window,
|
|
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
|
|
gdk_flush ();
|
|
if (G_UNLIKELY (gdk_error_trap_pop () == BadWindow))
|
|
{
|
|
g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display));
|
|
display_x11->trusted_client = FALSE;
|
|
}
|
|
}
|
|
|
|
if (_gdk_synchronize)
|
|
XSynchronize (display_x11->xdisplay, True);
|
|
|
|
class_hint = XAllocClassHint();
|
|
class_hint->res_name = g_get_prgname ();
|
|
|
|
class_hint->res_class = (char *)gdk_get_program_class ();
|
|
|
|
/* XmbSetWMProperties sets the RESOURCE_NAME environment variable
|
|
* from argv[0], so we just synthesize an argument array here.
|
|
*/
|
|
argc = 1;
|
|
argv[0] = g_get_prgname ();
|
|
|
|
XmbSetWMProperties (display_x11->xdisplay,
|
|
display_x11->leader_window,
|
|
NULL, NULL, argv, argc, NULL, NULL,
|
|
class_hint);
|
|
XFree (class_hint);
|
|
|
|
sm_client_id = _gdk_get_sm_client_id ();
|
|
if (sm_client_id)
|
|
_gdk_windowing_display_set_sm_client_id (display, sm_client_id);
|
|
|
|
pid = getpid ();
|
|
XChangeProperty (display_x11->xdisplay,
|
|
display_x11->leader_window,
|
|
gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
|
|
XA_CARDINAL, 32, PropModeReplace, (guchar *) & pid, 1);
|
|
|
|
/* We don't yet know a valid time. */
|
|
display_x11->user_time = 0;
|
|
|
|
#ifdef HAVE_XKB
|
|
{
|
|
gint xkb_major = XkbMajorVersion;
|
|
gint xkb_minor = XkbMinorVersion;
|
|
if (XkbLibraryVersion (&xkb_major, &xkb_minor))
|
|
{
|
|
xkb_major = XkbMajorVersion;
|
|
xkb_minor = XkbMinorVersion;
|
|
|
|
if (XkbQueryExtension (display_x11->xdisplay,
|
|
NULL, &display_x11->xkb_event_type, NULL,
|
|
&xkb_major, &xkb_minor))
|
|
{
|
|
Bool detectable_autorepeat_supported;
|
|
|
|
display_x11->use_xkb = TRUE;
|
|
|
|
XkbSelectEvents (display_x11->xdisplay,
|
|
XkbUseCoreKbd,
|
|
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
|
|
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
|
|
|
|
/* keep this in sync with _gdk_keymap_state_changed() */
|
|
XkbSelectEventDetails (display_x11->xdisplay,
|
|
XkbUseCoreKbd, XkbStateNotify,
|
|
XkbAllStateComponentsMask,
|
|
XkbGroupLockMask|XkbModifierLockMask);
|
|
|
|
XkbSetDetectableAutoRepeat (display_x11->xdisplay,
|
|
True,
|
|
&detectable_autorepeat_supported);
|
|
|
|
GDK_NOTE (MISC, g_message ("Detectable autorepeat %s.",
|
|
detectable_autorepeat_supported ?
|
|
"supported" : "not supported"));
|
|
|
|
display_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
display_x11->use_sync = FALSE;
|
|
#ifdef HAVE_XSYNC
|
|
{
|
|
int major, minor;
|
|
int error_base, event_base;
|
|
|
|
if (XSyncQueryExtension (display_x11->xdisplay,
|
|
&event_base, &error_base) &&
|
|
XSyncInitialize (display_x11->xdisplay,
|
|
&major, &minor))
|
|
display_x11->use_sync = TRUE;
|
|
}
|
|
#endif
|
|
|
|
_gdk_windowing_image_init (display);
|
|
_gdk_events_init (display);
|
|
_gdk_input_init (display);
|
|
_gdk_dnd_init (display);
|
|
|
|
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
|
|
gdk_display_request_selection_notification (display,
|
|
GDK_SCREEN_X11 (display_x11->screens[i])->cm_selection_atom);
|
|
|
|
g_signal_emit_by_name (gdk_display_manager_get(),
|
|
"display_opened", display);
|
|
|
|
return display;
|
|
}
|
|
|
|
#ifdef HAVE_X11R6
|
|
/*
|
|
* XLib internal connection handling
|
|
*/
|
|
typedef struct _GdkInternalConnection GdkInternalConnection;
|
|
|
|
struct _GdkInternalConnection
|
|
{
|
|
gint fd;
|
|
GSource *source;
|
|
Display *display;
|
|
};
|
|
|
|
static gboolean
|
|
process_internal_connection (GIOChannel *gioc,
|
|
GIOCondition cond,
|
|
gpointer data)
|
|
{
|
|
GdkInternalConnection *connection = (GdkInternalConnection *)data;
|
|
|
|
GDK_THREADS_ENTER ();
|
|
|
|
XProcessInternalConnection ((Display*)connection->display, connection->fd);
|
|
|
|
GDK_THREADS_LEAVE ();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GdkInternalConnection *
|
|
gdk_add_connection_handler (Display *display,
|
|
guint fd)
|
|
{
|
|
GIOChannel *io_channel;
|
|
GdkInternalConnection *connection;
|
|
|
|
connection = g_new (GdkInternalConnection, 1);
|
|
|
|
connection->fd = fd;
|
|
connection->display = display;
|
|
|
|
io_channel = g_io_channel_unix_new (fd);
|
|
|
|
connection->source = g_io_create_watch (io_channel, G_IO_IN);
|
|
g_source_set_callback (connection->source,
|
|
(GSourceFunc)process_internal_connection, connection, NULL);
|
|
g_source_attach (connection->source, NULL);
|
|
|
|
g_io_channel_unref (io_channel);
|
|
|
|
return connection;
|
|
}
|
|
|
|
static void
|
|
gdk_remove_connection_handler (GdkInternalConnection *connection)
|
|
{
|
|
g_source_destroy (connection->source);
|
|
g_free (connection);
|
|
}
|
|
|
|
static void
|
|
gdk_internal_connection_watch (Display *display,
|
|
XPointer arg,
|
|
gint fd,
|
|
gboolean opening,
|
|
XPointer *watch_data)
|
|
{
|
|
if (opening)
|
|
*watch_data = (XPointer)gdk_add_connection_handler (display, fd);
|
|
else
|
|
gdk_remove_connection_handler ((GdkInternalConnection *)*watch_data);
|
|
}
|
|
#endif /* HAVE_X11R6 */
|
|
|
|
/**
|
|
* gdk_display_get_name:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Gets the name of the display.
|
|
*
|
|
* Returns: a string representing the display name. This string is owned
|
|
* by GDK and should not be modified or freed.
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
G_CONST_RETURN gchar *
|
|
gdk_display_get_name (GdkDisplay *display)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
|
|
|
return (gchar *) DisplayString (GDK_DISPLAY_X11 (display)->xdisplay);
|
|
}
|
|
|
|
/**
|
|
* gdk_display_get_n_screens:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Gets the number of screen managed by the @display.
|
|
*
|
|
* Returns: number of screens.
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
gint
|
|
gdk_display_get_n_screens (GdkDisplay *display)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
|
|
|
|
return ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay);
|
|
}
|
|
|
|
/**
|
|
* gdk_display_get_screen:
|
|
* @display: a #GdkDisplay
|
|
* @screen_num: the screen number
|
|
*
|
|
* Returns a screen object for one of the screens of the display.
|
|
*
|
|
* Returns: the #GdkScreen object
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
GdkScreen *
|
|
gdk_display_get_screen (GdkDisplay *display,
|
|
gint screen_num)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
|
g_return_val_if_fail (ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay) > screen_num, NULL);
|
|
|
|
return GDK_DISPLAY_X11 (display)->screens[screen_num];
|
|
}
|
|
|
|
/**
|
|
* gdk_display_get_default_screen:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Get the default #GdkScreen for @display.
|
|
*
|
|
* Returns: the default #GdkScreen object for @display
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
GdkScreen *
|
|
gdk_display_get_default_screen (GdkDisplay *display)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
|
|
|
return GDK_DISPLAY_X11 (display)->default_screen;
|
|
}
|
|
|
|
gboolean
|
|
_gdk_x11_display_is_root_window (GdkDisplay *display,
|
|
Window xroot_window)
|
|
{
|
|
GdkDisplayX11 *display_x11;
|
|
gint i;
|
|
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
|
|
|
display_x11 = GDK_DISPLAY_X11 (display);
|
|
|
|
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
|
|
{
|
|
if (GDK_SCREEN_XROOTWIN (display_x11->screens[i]) == xroot_window)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#define XSERVER_TIME_IS_LATER(time1, time2) \
|
|
( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) || \
|
|
(( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 )) \
|
|
)
|
|
|
|
/**
|
|
* gdk_display_pointer_ungrab:
|
|
* @display: a #GdkDisplay.
|
|
* @time_: a timestap (e.g. %GDK_CURRENT_TIME).
|
|
*
|
|
* Release any pointer grab.
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
void
|
|
gdk_display_pointer_ungrab (GdkDisplay *display,
|
|
guint32 time_)
|
|
{
|
|
Display *xdisplay;
|
|
GdkDisplayX11 *display_x11;
|
|
|
|
g_return_if_fail (GDK_IS_DISPLAY (display));
|
|
|
|
display_x11 = GDK_DISPLAY_X11 (display);
|
|
xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
|
|
|
_gdk_input_ungrab_pointer (display, time_);
|
|
XUngrabPointer (xdisplay, time_);
|
|
XFlush (xdisplay);
|
|
|
|
if (time_ == GDK_CURRENT_TIME ||
|
|
display->pointer_grab.time == GDK_CURRENT_TIME ||
|
|
!XSERVER_TIME_IS_LATER (display->pointer_grab.time, time_))
|
|
{
|
|
_gdk_display_unset_has_pointer_grab (display,
|
|
FALSE,
|
|
FALSE,
|
|
time_);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gdk_display_keyboard_ungrab:
|
|
* @display: a #GdkDisplay.
|
|
* @time_: a timestap (e.g #GDK_CURRENT_TIME).
|
|
*
|
|
* Release any keyboard grab
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
void
|
|
gdk_display_keyboard_ungrab (GdkDisplay *display,
|
|
guint32 time)
|
|
{
|
|
Display *xdisplay;
|
|
GdkDisplayX11 *display_x11;
|
|
|
|
g_return_if_fail (GDK_IS_DISPLAY (display));
|
|
|
|
display_x11 = GDK_DISPLAY_X11 (display);
|
|
xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
|
|
|
XUngrabKeyboard (xdisplay, time);
|
|
XFlush (xdisplay);
|
|
|
|
if (time == GDK_CURRENT_TIME ||
|
|
display_x11->keyboard_xgrab_time == GDK_CURRENT_TIME ||
|
|
!XSERVER_TIME_IS_LATER (display_x11->keyboard_xgrab_time, time))
|
|
display_x11->keyboard_xgrab_window = NULL;
|
|
}
|
|
|
|
/**
|
|
* gdk_display_beep:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Emits a short beep on @display
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
void
|
|
gdk_display_beep (GdkDisplay *display)
|
|
{
|
|
g_return_if_fail (GDK_IS_DISPLAY (display));
|
|
|
|
XBell (GDK_DISPLAY_XDISPLAY (display), 0);
|
|
}
|
|
|
|
/**
|
|
* gdk_display_sync:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Flushes any requests queued for the windowing system and waits until all
|
|
* requests have been handled. This is often used for making sure that the
|
|
* display is synchronized with the current state of the program. Calling
|
|
* gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors
|
|
* generated from earlier requests are handled before the error trap is
|
|
* removed.
|
|
*
|
|
* This is most useful for X11. On windowing systems where requests are
|
|
* handled synchronously, this function will do nothing.
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
void
|
|
gdk_display_sync (GdkDisplay *display)
|
|
{
|
|
g_return_if_fail (GDK_IS_DISPLAY (display));
|
|
|
|
XSync (GDK_DISPLAY_XDISPLAY (display), False);
|
|
}
|
|
|
|
/**
|
|
* gdk_display_flush:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Flushes any requests queued for the windowing system; this happens automatically
|
|
* when the main loop blocks waiting for new events, but if your application
|
|
* is drawing without returning control to the main loop, you may need
|
|
* to call this function explicitely. A common case where this function
|
|
* needs to be called is when an application is executing drawing commands
|
|
* from a thread other than the thread where the main loop is running.
|
|
*
|
|
* This is most useful for X11. On windowing systems where requests are
|
|
* handled synchronously, this function will do nothing.
|
|
*
|
|
* Since: 2.4
|
|
*/
|
|
void
|
|
gdk_display_flush (GdkDisplay *display)
|
|
{
|
|
g_return_if_fail (GDK_IS_DISPLAY (display));
|
|
|
|
if (!display->closed)
|
|
XFlush (GDK_DISPLAY_XDISPLAY (display));
|
|
}
|
|
|
|
/**
|
|
* gdk_display_get_default_group:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Returns the default group leader window for all toplevel windows
|
|
* on @display. This window is implicitly created by GDK.
|
|
* See gdk_window_set_group().
|
|
*
|
|
* Return value: The default group leader window for @display
|
|
*
|
|
* Since: 2.4
|
|
**/
|
|
GdkWindow *
|
|
gdk_display_get_default_group (GdkDisplay *display)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
|
|
|
return GDK_DISPLAY_X11 (display)->leader_gdk_window;
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_display_grab:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Call XGrabServer() on @display.
|
|
* To ungrab the display again, use gdk_x11_display_ungrab().
|
|
*
|
|
* gdk_x11_display_grab()/gdk_x11_display_ungrab() calls can be nested.
|
|
*
|
|
* Since: 2.2
|
|
**/
|
|
void
|
|
gdk_x11_display_grab (GdkDisplay *display)
|
|
{
|
|
GdkDisplayX11 *display_x11;
|
|
|
|
g_return_if_fail (GDK_IS_DISPLAY (display));
|
|
|
|
display_x11 = GDK_DISPLAY_X11 (display);
|
|
|
|
if (display_x11->grab_count == 0)
|
|
XGrabServer (display_x11->xdisplay);
|
|
display_x11->grab_count++;
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_display_ungrab:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Ungrab @display after it has been grabbed with
|
|
* gdk_x11_display_grab().
|
|
*
|
|
* Since: 2.2
|
|
**/
|
|
void
|
|
gdk_x11_display_ungrab (GdkDisplay *display)
|
|
{
|
|
GdkDisplayX11 *display_x11;
|
|
|
|
g_return_if_fail (GDK_IS_DISPLAY (display));
|
|
|
|
display_x11 = GDK_DISPLAY_X11 (display);;
|
|
g_return_if_fail (display_x11->grab_count > 0);
|
|
|
|
display_x11->grab_count--;
|
|
if (display_x11->grab_count == 0)
|
|
{
|
|
XUngrabServer (display_x11->xdisplay);
|
|
XFlush (display_x11->xdisplay);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_display_x11_dispose (GObject *object)
|
|
{
|
|
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (object);
|
|
gint i;
|
|
|
|
g_list_foreach (display_x11->input_devices, (GFunc) g_object_run_dispose, NULL);
|
|
|
|
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
|
|
_gdk_screen_close (display_x11->screens[i]);
|
|
|
|
_gdk_events_uninit (GDK_DISPLAY_OBJECT (object));
|
|
|
|
G_OBJECT_CLASS (_gdk_display_x11_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gdk_display_x11_finalize (GObject *object)
|
|
{
|
|
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (object);
|
|
gint i;
|
|
|
|
/* Keymap */
|
|
if (display_x11->keymap)
|
|
g_object_unref (display_x11->keymap);
|
|
|
|
/* Free motif Dnd */
|
|
if (display_x11->motif_target_lists)
|
|
{
|
|
for (i = 0; i < display_x11->motif_n_target_lists; i++)
|
|
g_list_free (display_x11->motif_target_lists[i]);
|
|
g_free (display_x11->motif_target_lists);
|
|
}
|
|
|
|
_gdk_x11_cursor_display_finalize (GDK_DISPLAY_OBJECT(display_x11));
|
|
|
|
/* Atom Hashtable */
|
|
g_hash_table_destroy (display_x11->atom_from_virtual);
|
|
g_hash_table_destroy (display_x11->atom_to_virtual);
|
|
|
|
/* Leader Window */
|
|
XDestroyWindow (display_x11->xdisplay, display_x11->leader_window);
|
|
|
|
/* list of filters for client messages */
|
|
g_list_foreach (display_x11->client_filters, (GFunc) g_free, NULL);
|
|
g_list_free (display_x11->client_filters);
|
|
|
|
/* List of event window extraction functions */
|
|
g_slist_foreach (display_x11->event_types, (GFunc)g_free, NULL);
|
|
g_slist_free (display_x11->event_types);
|
|
|
|
/* input GdkDevice list */
|
|
g_list_foreach (display_x11->input_devices, (GFunc) g_object_unref, NULL);
|
|
g_list_free (display_x11->input_devices);
|
|
|
|
/* input GdkWindow list */
|
|
g_list_foreach (display_x11->input_windows, (GFunc) g_free, NULL);
|
|
g_list_free (display_x11->input_windows);
|
|
|
|
/* Free all GdkScreens */
|
|
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
|
|
g_object_unref (display_x11->screens[i]);
|
|
g_free (display_x11->screens);
|
|
|
|
g_free (display_x11->startup_notification_id);
|
|
|
|
/* X ID hashtable */
|
|
g_hash_table_destroy (display_x11->xid_ht);
|
|
|
|
XCloseDisplay (display_x11->xdisplay);
|
|
|
|
G_OBJECT_CLASS (_gdk_display_x11_parent_class)->finalize (object);
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_lookup_xdisplay:
|
|
* @xdisplay: a pointer to an X Display
|
|
*
|
|
* Find the #GdkDisplay corresponding to @display, if any exists.
|
|
*
|
|
* Return value: the #GdkDisplay, if found, otherwise %NULL.
|
|
*
|
|
* Since: 2.2
|
|
**/
|
|
GdkDisplay *
|
|
gdk_x11_lookup_xdisplay (Display *xdisplay)
|
|
{
|
|
GSList *tmp_list;
|
|
|
|
for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
|
|
{
|
|
if (GDK_DISPLAY_XDISPLAY (tmp_list->data) == xdisplay)
|
|
return tmp_list->data;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* _gdk_x11_display_screen_for_xrootwin:
|
|
* @display: a #GdkDisplay
|
|
* @xrootwin: window ID for one of of the screen's of the display.
|
|
*
|
|
* Given the root window ID of one of the screen's of a #GdkDisplay,
|
|
* finds the screen.
|
|
*
|
|
* Return value: the #GdkScreen corresponding to @xrootwin, or %NULL.
|
|
**/
|
|
GdkScreen *
|
|
_gdk_x11_display_screen_for_xrootwin (GdkDisplay *display,
|
|
Window xrootwin)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay); i++)
|
|
{
|
|
GdkScreen *screen = gdk_display_get_screen (display, i);
|
|
if (GDK_SCREEN_XROOTWIN (screen) == xrootwin)
|
|
return screen;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_display_get_xdisplay:
|
|
* @display: a #GdkDisplay
|
|
* @returns: an X display.
|
|
*
|
|
* Returns the X display of a #GdkDisplay.
|
|
*
|
|
* Since: 2.2
|
|
*/
|
|
Display *
|
|
gdk_x11_display_get_xdisplay (GdkDisplay *display)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
|
return GDK_DISPLAY_X11 (display)->xdisplay;
|
|
}
|
|
|
|
void
|
|
_gdk_windowing_set_default_display (GdkDisplay *display)
|
|
{
|
|
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
|
|
const gchar *startup_id;
|
|
|
|
if (!display)
|
|
{
|
|
gdk_display = NULL;
|
|
return;
|
|
}
|
|
|
|
gdk_display = GDK_DISPLAY_XDISPLAY (display);
|
|
|
|
g_free (display_x11->startup_notification_id);
|
|
display_x11->startup_notification_id = NULL;
|
|
|
|
startup_id = g_getenv ("DESKTOP_STARTUP_ID");
|
|
if (startup_id && *startup_id != '\0')
|
|
{
|
|
gchar *time_str;
|
|
|
|
if (!g_utf8_validate (startup_id, -1, NULL))
|
|
g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
|
|
else
|
|
display_x11->startup_notification_id = g_strdup (startup_id);
|
|
|
|
/* Find the launch time from the startup_id, if it's there. Newer spec
|
|
* states that the startup_id is of the form <unique>_TIME<timestamp>
|
|
*/
|
|
time_str = g_strrstr (startup_id, "_TIME");
|
|
if (time_str != NULL)
|
|
{
|
|
gulong retval;
|
|
gchar *end;
|
|
errno = 0;
|
|
|
|
/* Skip past the "_TIME" part */
|
|
time_str += 5;
|
|
|
|
retval = strtoul (time_str, &end, 0);
|
|
if (end != time_str && errno == 0)
|
|
display_x11->user_time = retval;
|
|
}
|
|
|
|
/* Clear the environment variable so it won't be inherited by
|
|
* child processes and confuse things.
|
|
*/
|
|
g_unsetenv ("DESKTOP_STARTUP_ID");
|
|
|
|
/* Set the startup id on the leader window so it
|
|
* applies to all windows we create on this display
|
|
*/
|
|
XChangeProperty (display_x11->xdisplay,
|
|
display_x11->leader_window,
|
|
gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
|
|
gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
|
|
PropModeReplace,
|
|
(guchar *)startup_id, strlen (startup_id));
|
|
}
|
|
}
|
|
|
|
static void
|
|
broadcast_xmessage (GdkDisplay *display,
|
|
const char *message_type,
|
|
const char *message_type_begin,
|
|
const char *message)
|
|
{
|
|
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
|
GdkScreen *screen = gdk_display_get_default_screen (display);
|
|
GdkWindow *root_window = gdk_screen_get_root_window (screen);
|
|
Window xroot_window = GDK_WINDOW_XID (root_window);
|
|
|
|
Atom type_atom;
|
|
Atom type_atom_begin;
|
|
Window xwindow;
|
|
|
|
if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
|
|
return;
|
|
|
|
{
|
|
XSetWindowAttributes attrs;
|
|
|
|
attrs.override_redirect = True;
|
|
attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
|
|
|
|
xwindow =
|
|
XCreateWindow (xdisplay,
|
|
xroot_window,
|
|
-100, -100, 1, 1,
|
|
0,
|
|
CopyFromParent,
|
|
CopyFromParent,
|
|
(Visual *)CopyFromParent,
|
|
CWOverrideRedirect | CWEventMask,
|
|
&attrs);
|
|
}
|
|
|
|
type_atom = gdk_x11_get_xatom_by_name_for_display (display,
|
|
message_type);
|
|
type_atom_begin = gdk_x11_get_xatom_by_name_for_display (display,
|
|
message_type_begin);
|
|
|
|
{
|
|
XClientMessageEvent xclient;
|
|
const char *src;
|
|
const char *src_end;
|
|
char *dest;
|
|
char *dest_end;
|
|
|
|
memset(&xclient, 0, sizeof (xclient));
|
|
xclient.type = ClientMessage;
|
|
xclient.message_type = type_atom_begin;
|
|
xclient.display =xdisplay;
|
|
xclient.window = xwindow;
|
|
xclient.format = 8;
|
|
|
|
src = message;
|
|
src_end = message + strlen (message) + 1; /* +1 to include nul byte */
|
|
|
|
while (src != src_end)
|
|
{
|
|
dest = &xclient.data.b[0];
|
|
dest_end = dest + 20;
|
|
|
|
while (dest != dest_end &&
|
|
src != src_end)
|
|
{
|
|
*dest = *src;
|
|
++dest;
|
|
++src;
|
|
}
|
|
|
|
while (dest != dest_end)
|
|
{
|
|
*dest = 0;
|
|
++dest;
|
|
}
|
|
|
|
XSendEvent (xdisplay,
|
|
xroot_window,
|
|
False,
|
|
PropertyChangeMask,
|
|
(XEvent *)&xclient);
|
|
|
|
xclient.message_type = type_atom;
|
|
}
|
|
}
|
|
|
|
XDestroyWindow (xdisplay, xwindow);
|
|
XFlush (xdisplay);
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_display_broadcast_startup_message:
|
|
* @display: a #GdkDisplay
|
|
* @message_type: startup notification message type ("new", "change",
|
|
* or "remove")
|
|
* @...: a list of key/value pairs (as strings), terminated by a
|
|
* %NULL key. (A %NULL value for a key will cause that key to be
|
|
* skipped in the output.)
|
|
*
|
|
* Sends a startup notification message of type @message_type to
|
|
* @display.
|
|
*
|
|
* This is a convenience function for use by code that implements the
|
|
* freedesktop startup notification specification. Applications should
|
|
* not normally need to call it directly. See the <ulink
|
|
* url="http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt">Startup
|
|
* Notification Protocol specification</ulink> for
|
|
* definitions of the message types and keys that can be used.
|
|
*
|
|
* Since: 2.12
|
|
**/
|
|
void
|
|
gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
|
|
const char *message_type,
|
|
...)
|
|
{
|
|
GString *message;
|
|
va_list ap;
|
|
const char *key, *value, *p;
|
|
|
|
message = g_string_new (message_type);
|
|
g_string_append_c (message, ':');
|
|
|
|
va_start (ap, message_type);
|
|
while ((key = va_arg (ap, const char *)))
|
|
{
|
|
value = va_arg (ap, const char *);
|
|
if (!value)
|
|
continue;
|
|
|
|
g_string_append_printf (message, " %s=\"", key);
|
|
for (p = value; *p; p++)
|
|
{
|
|
switch (*p)
|
|
{
|
|
case ' ':
|
|
case '"':
|
|
case '\\':
|
|
g_string_append_c (message, '\\');
|
|
break;
|
|
}
|
|
|
|
g_string_append_c (message, *p);
|
|
}
|
|
g_string_append_c (message, '\"');
|
|
}
|
|
va_end (ap);
|
|
|
|
broadcast_xmessage (display,
|
|
"_NET_STARTUP_INFO",
|
|
"_NET_STARTUP_INFO_BEGIN",
|
|
message->str);
|
|
|
|
g_string_free (message, TRUE);
|
|
}
|
|
|
|
/**
|
|
* gdk_notify_startup_complete:
|
|
*
|
|
* Indicates to the GUI environment that the application has finished
|
|
* loading. If the applications opens windows, this function is
|
|
* normally called after opening the application's initial set of
|
|
* windows.
|
|
*
|
|
* GTK+ will call this function automatically after opening the first
|
|
* #GtkWindow unless gtk_window_set_auto_startup_notification() is called
|
|
* to disable that feature.
|
|
*
|
|
* Since: 2.2
|
|
**/
|
|
void
|
|
gdk_notify_startup_complete (void)
|
|
{
|
|
GdkDisplay *display;
|
|
GdkDisplayX11 *display_x11;
|
|
|
|
display = gdk_display_get_default ();
|
|
if (!display)
|
|
return;
|
|
|
|
display_x11 = GDK_DISPLAY_X11 (display);
|
|
|
|
if (display_x11->startup_notification_id == NULL)
|
|
return;
|
|
|
|
gdk_notify_startup_complete_with_id (display_x11->startup_notification_id);
|
|
}
|
|
|
|
/**
|
|
* gdk_notify_startup_complete_with_id:
|
|
* @startup_id: a startup-notification identifier, for which notification
|
|
* process should be completed
|
|
*
|
|
* Indicates to the GUI environment that the application has finished
|
|
* loading, using a given identifier.
|
|
*
|
|
* GTK+ will call this function automatically for #GtkWindow with custom
|
|
* startup-notification identifier unless
|
|
* gtk_window_set_auto_startup_notification() is called to disable
|
|
* that feature.
|
|
*
|
|
* Since: 2.12
|
|
**/
|
|
void
|
|
gdk_notify_startup_complete_with_id (const gchar* startup_id)
|
|
{
|
|
GdkDisplay *display;
|
|
|
|
display = gdk_display_get_default ();
|
|
if (!display)
|
|
return;
|
|
|
|
gdk_x11_display_broadcast_startup_message (display, "remove",
|
|
"ID", startup_id,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* gdk_display_supports_selection_notification:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Returns whether #GdkEventOwnerChange events will be
|
|
* sent when the owner of a selection changes.
|
|
*
|
|
* Return value: whether #GdkEventOwnerChange events will
|
|
* be sent.
|
|
*
|
|
* Since: 2.6
|
|
**/
|
|
gboolean
|
|
gdk_display_supports_selection_notification (GdkDisplay *display)
|
|
{
|
|
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
|
|
|
|
return display_x11->have_xfixes;
|
|
}
|
|
|
|
/**
|
|
* gdk_display_request_selection_notification:
|
|
* @display: a #GdkDisplay
|
|
* @selection: the #GdkAtom naming the selection for which
|
|
* ownership change notification is requested
|
|
*
|
|
* Request #GdkEventOwnerChange events for ownership changes
|
|
* of the selection named by the given atom.
|
|
*
|
|
* Return value: whether #GdkEventOwnerChange events will
|
|
* be sent.
|
|
*
|
|
* Since: 2.6
|
|
**/
|
|
gboolean
|
|
gdk_display_request_selection_notification (GdkDisplay *display,
|
|
GdkAtom selection)
|
|
|
|
{
|
|
#ifdef HAVE_XFIXES
|
|
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
|
|
Atom atom;
|
|
|
|
if (display_x11->have_xfixes)
|
|
{
|
|
atom = gdk_x11_atom_to_xatom_for_display (display,
|
|
selection);
|
|
XFixesSelectSelectionInput (display_x11->xdisplay,
|
|
display_x11->leader_window,
|
|
atom,
|
|
XFixesSetSelectionOwnerNotifyMask |
|
|
XFixesSelectionWindowDestroyNotifyMask |
|
|
XFixesSelectionClientCloseNotifyMask);
|
|
return TRUE;
|
|
}
|
|
else
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gdk_display_supports_clipboard_persistence
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Returns whether the speicifed display supports clipboard
|
|
* persistance; i.e. if it's possible to store the clipboard data after an
|
|
* application has quit. On X11 this checks if a clipboard daemon is
|
|
* running.
|
|
*
|
|
* Returns: %TRUE if the display supports clipboard persistance.
|
|
*
|
|
* Since: 2.6
|
|
*/
|
|
gboolean
|
|
gdk_display_supports_clipboard_persistence (GdkDisplay *display)
|
|
{
|
|
Atom clipboard_manager;
|
|
|
|
/* It might make sense to cache this */
|
|
clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
|
|
return XGetSelectionOwner (GDK_DISPLAY_X11 (display)->xdisplay, clipboard_manager) != None;
|
|
}
|
|
|
|
/**
|
|
* gdk_display_store_clipboard
|
|
* @display: a #GdkDisplay
|
|
* @clipboard_window: a #GdkWindow belonging to the clipboard owner
|
|
* @time_: a timestamp
|
|
* @targets: an array of targets that should be saved, or %NULL
|
|
* if all available targets should be saved.
|
|
* @n_targets: length of the @targets array
|
|
*
|
|
* Issues a request to the clipboard manager to store the
|
|
* clipboard data. On X11, this is a special program that works
|
|
* according to the freedesktop clipboard specification, available at
|
|
* <ulink url="http://www.freedesktop.org/Standards/clipboard-manager-spec">
|
|
* http://www.freedesktop.org/Standards/clipboard-manager-spec</ulink>.
|
|
*
|
|
* Since: 2.6
|
|
*/
|
|
void
|
|
gdk_display_store_clipboard (GdkDisplay *display,
|
|
GdkWindow *clipboard_window,
|
|
guint32 time_,
|
|
const GdkAtom *targets,
|
|
gint n_targets)
|
|
{
|
|
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
|
|
Atom clipboard_manager, save_targets;
|
|
|
|
g_return_if_fail (GDK_WINDOW_IS_X11 (clipboard_window));
|
|
|
|
clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
|
|
save_targets = gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS");
|
|
|
|
gdk_error_trap_push ();
|
|
|
|
if (XGetSelectionOwner (display_x11->xdisplay, clipboard_manager) != None)
|
|
{
|
|
Atom property_name = None;
|
|
Atom *xatoms;
|
|
int i;
|
|
|
|
if (n_targets > 0)
|
|
{
|
|
property_name = gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property);
|
|
|
|
xatoms = g_new (Atom, n_targets);
|
|
for (i = 0; i < n_targets; i++)
|
|
xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, targets[i]);
|
|
|
|
XChangeProperty (display_x11->xdisplay, GDK_WINDOW_XID (clipboard_window),
|
|
property_name, XA_ATOM,
|
|
32, PropModeReplace, (guchar *)xatoms, n_targets);
|
|
g_free (xatoms);
|
|
|
|
}
|
|
|
|
XConvertSelection (display_x11->xdisplay,
|
|
clipboard_manager, save_targets, property_name,
|
|
GDK_WINDOW_XID (clipboard_window), time_);
|
|
|
|
}
|
|
gdk_error_trap_pop ();
|
|
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_display_get_user_time:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Returns the timestamp of the last user interaction on
|
|
* @display. The timestamp is taken from events caused
|
|
* by user interaction such as key presses or pointer
|
|
* movements. See gdk_x11_window_set_user_time().
|
|
*
|
|
* Returns: the timestamp of the last user interaction
|
|
*
|
|
* Since: 2.8
|
|
*/
|
|
guint32
|
|
gdk_x11_display_get_user_time (GdkDisplay *display)
|
|
{
|
|
return GDK_DISPLAY_X11 (display)->user_time;
|
|
}
|
|
|
|
/**
|
|
* gdk_display_supports_shapes:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Returns %TRUE if gdk_window_shape_combine_mask() can
|
|
* be used to create shaped windows on @display.
|
|
*
|
|
* Returns: %TRUE if shaped windows are supported
|
|
*
|
|
* Since: 2.10
|
|
*/
|
|
gboolean
|
|
gdk_display_supports_shapes (GdkDisplay *display)
|
|
{
|
|
return GDK_DISPLAY_X11 (display)->have_shapes;
|
|
}
|
|
|
|
/**
|
|
* gdk_display_supports_input_shapes:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Returns %TRUE if gdk_window_input_shape_combine_mask() can
|
|
* be used to modify the input shape of windows on @display.
|
|
*
|
|
* Returns: %TRUE if windows with modified input shape are supported
|
|
*
|
|
* Since: 2.10
|
|
*/
|
|
gboolean
|
|
gdk_display_supports_input_shapes (GdkDisplay *display)
|
|
{
|
|
return GDK_DISPLAY_X11 (display)->have_input_shapes;
|
|
}
|
|
|
|
|
|
/**
|
|
* gdk_x11_display_get_startup_notification_id:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Gets the startup notification ID for a display.
|
|
*
|
|
* Returns: the startup notification ID for @display
|
|
*
|
|
* Since: 2.12
|
|
*/
|
|
G_CONST_RETURN gchar *
|
|
gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
|
|
{
|
|
return GDK_DISPLAY_X11 (display)->startup_notification_id;
|
|
}
|
|
|
|
/**
|
|
* gdk_display_supports_composite:
|
|
* @display: a #GdkDisplay
|
|
*
|
|
* Returns %TRUE if gdk_window_set_composited() can be used
|
|
* to redirect drawing on the window using compositing.
|
|
*
|
|
* Currently this only works on X11 with XComposite and
|
|
* XDamage extensions available.
|
|
*
|
|
* Returns: %TRUE if windows may be composited.
|
|
*
|
|
* Since: 2.12
|
|
*/
|
|
gboolean
|
|
gdk_display_supports_composite (GdkDisplay *display)
|
|
{
|
|
GdkDisplayX11 *x11_display = GDK_DISPLAY_X11 (display);
|
|
|
|
return x11_display->have_xcomposite &&
|
|
x11_display->have_xdamage &&
|
|
x11_display->have_xfixes;
|
|
}
|
|
|
|
|
|
#define __GDK_DISPLAY_X11_C__
|
|
#include "gdkaliasdef.c"
|