mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 19:42:05 +00:00
Move window pings to MetaWindow
This will make it possible to use on Wayland as well...
This commit is contained in:
parent
8a3501ffe1
commit
aa3643cdde
@ -43,14 +43,11 @@ static void meta_window_present_delete_dialog (MetaWindow *window,
|
|||||||
guint32 timestamp);
|
guint32 timestamp);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
delete_ping_reply_func (MetaDisplay *display,
|
delete_ping_reply_func (MetaWindow *window,
|
||||||
Window xwindow,
|
|
||||||
guint32 timestamp,
|
guint32 timestamp,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_PING,
|
meta_topic (META_DEBUG_PING, "Got reply to delete ping for %s\n", window->desc);
|
||||||
"Got reply to delete ping for %s\n",
|
|
||||||
((MetaWindow*)user_data)->desc);
|
|
||||||
|
|
||||||
/* we do nothing */
|
/* we do nothing */
|
||||||
}
|
}
|
||||||
@ -68,12 +65,10 @@ dialog_exited (GPid pid, int status, gpointer user_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
delete_ping_timeout_func (MetaDisplay *display,
|
delete_ping_timeout_func (MetaWindow *window,
|
||||||
Window xwindow,
|
|
||||||
guint32 timestamp,
|
guint32 timestamp,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
MetaWindow *window = user_data;
|
|
||||||
char *window_title;
|
char *window_title;
|
||||||
gchar *window_content, *tmp;
|
gchar *window_content, *tmp;
|
||||||
GPid dialog_pid;
|
GPid dialog_pid;
|
||||||
@ -137,12 +132,11 @@ void
|
|||||||
meta_window_check_alive (MetaWindow *window,
|
meta_window_check_alive (MetaWindow *window,
|
||||||
guint32 timestamp)
|
guint32 timestamp)
|
||||||
{
|
{
|
||||||
meta_display_ping_window (window->display,
|
meta_window_ping (window,
|
||||||
window,
|
|
||||||
timestamp,
|
timestamp,
|
||||||
delete_ping_reply_func,
|
delete_ping_reply_func,
|
||||||
delete_ping_timeout_func,
|
delete_ping_timeout_func,
|
||||||
window);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -57,11 +57,6 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
|
|||||||
|
|
||||||
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
|
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
|
||||||
|
|
||||||
typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
|
|
||||||
Window xwindow,
|
|
||||||
guint32 timestamp,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
META_LIST_DEFAULT = 0, /* normal windows */
|
META_LIST_DEFAULT = 0, /* normal windows */
|
||||||
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
|
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
|
||||||
@ -182,7 +177,7 @@ struct _MetaDisplay
|
|||||||
guint32 window_sequence_counter;
|
guint32 window_sequence_counter;
|
||||||
|
|
||||||
/* Pings which we're waiting for a reply from */
|
/* Pings which we're waiting for a reply from */
|
||||||
GSList *pending_pings;
|
GHashTable *pending_pings;
|
||||||
|
|
||||||
/* Pending focus change */
|
/* Pending focus change */
|
||||||
guint focus_timeout_id;
|
guint focus_timeout_id;
|
||||||
@ -448,15 +443,6 @@ void meta_display_retheme_all (void);
|
|||||||
void meta_display_set_cursor_theme (const char *theme,
|
void meta_display_set_cursor_theme (const char *theme,
|
||||||
int size);
|
int size);
|
||||||
|
|
||||||
void meta_display_ping_window (MetaDisplay *display,
|
|
||||||
MetaWindow *window,
|
|
||||||
guint32 timestamp,
|
|
||||||
MetaWindowPingFunc ping_reply_func,
|
|
||||||
MetaWindowPingFunc ping_timeout_func,
|
|
||||||
void *user_data);
|
|
||||||
gboolean meta_display_window_has_pending_pings (MetaDisplay *display,
|
|
||||||
MetaWindow *window);
|
|
||||||
|
|
||||||
int meta_resize_gravity_from_grab_op (MetaGrabOp op);
|
int meta_resize_gravity_from_grab_op (MetaGrabOp op);
|
||||||
|
|
||||||
gboolean meta_grab_op_is_moving (MetaGrabOp op);
|
gboolean meta_grab_op_is_moving (MetaGrabOp op);
|
||||||
|
@ -83,41 +83,6 @@
|
|||||||
g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK || \
|
g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK || \
|
||||||
g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP)
|
g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP)
|
||||||
|
|
||||||
/*
|
|
||||||
* SECTION:pings
|
|
||||||
*
|
|
||||||
* Sometimes we want to see whether a window is responding,
|
|
||||||
* so we send it a "ping" message and see whether it sends us back a "pong"
|
|
||||||
* message within a reasonable time. Here we have a system which lets us
|
|
||||||
* nominate one function to be called if we get the pong in time and another
|
|
||||||
* function if we don't. The system is rather more complicated than it needs
|
|
||||||
* to be, since we only ever use it to destroy windows which are asked to
|
|
||||||
* close themselves and don't do so within a reasonable amount of time, and
|
|
||||||
* therefore we always use the same callbacks. It's possible that we might
|
|
||||||
* use it for other things in future, or on the other hand we might decide
|
|
||||||
* that we're never going to do so and simplify it a bit.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MetaPingData:
|
|
||||||
*
|
|
||||||
* Describes a ping on a window. When we send a ping to a window, we build
|
|
||||||
* one of these structs, and it eventually gets passed to the timeout function
|
|
||||||
* or to the function which handles the response from the window. If the window
|
|
||||||
* does or doesn't respond to the ping, we use this information to deal with
|
|
||||||
* these facts; we have a handler function for each.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
MetaDisplay *display;
|
|
||||||
Window xwindow;
|
|
||||||
guint32 timestamp;
|
|
||||||
MetaWindowPingFunc ping_reply_func;
|
|
||||||
MetaWindowPingFunc ping_timeout_func;
|
|
||||||
void *user_data;
|
|
||||||
guint ping_timeout_id;
|
|
||||||
} MetaPingData;
|
|
||||||
|
|
||||||
G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
|
G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
|
||||||
|
|
||||||
/* Signals */
|
/* Signals */
|
||||||
@ -172,8 +137,6 @@ static guint32 event_get_time (MetaDisplay *display,
|
|||||||
XEvent *event);
|
XEvent *event);
|
||||||
static void process_request_frame_extents (MetaDisplay *display,
|
static void process_request_frame_extents (MetaDisplay *display,
|
||||||
XEvent *event);
|
XEvent *event);
|
||||||
static void process_pong_message (MetaDisplay *display,
|
|
||||||
XEvent *event);
|
|
||||||
static void process_selection_request (MetaDisplay *display,
|
static void process_selection_request (MetaDisplay *display,
|
||||||
XEvent *event);
|
XEvent *event);
|
||||||
static void process_selection_clear (MetaDisplay *display,
|
static void process_selection_clear (MetaDisplay *display,
|
||||||
@ -321,62 +284,6 @@ meta_display_class_init (MetaDisplayClass *klass)
|
|||||||
G_PARAM_READABLE));
|
G_PARAM_READABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ping_data_free:
|
|
||||||
*
|
|
||||||
* Destructor for #MetaPingData structs. Will destroy the
|
|
||||||
* event source for the struct as well.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
ping_data_free (MetaPingData *ping_data)
|
|
||||||
{
|
|
||||||
/* Remove the timeout */
|
|
||||||
if (ping_data->ping_timeout_id != 0)
|
|
||||||
g_source_remove (ping_data->ping_timeout_id);
|
|
||||||
|
|
||||||
g_free (ping_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove_pending_pings_for_window:
|
|
||||||
* @display: The display the window appears on
|
|
||||||
* @xwindow: The X ID of the window whose pings we should remove
|
|
||||||
*
|
|
||||||
* Frees every pending ping structure for the given X window on the
|
|
||||||
* given display. This means that we also destroy the timeouts.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
remove_pending_pings_for_window (MetaDisplay *display, Window xwindow)
|
|
||||||
{
|
|
||||||
GSList *tmp;
|
|
||||||
GSList *dead;
|
|
||||||
|
|
||||||
/* could obviously be more efficient, don't care */
|
|
||||||
|
|
||||||
/* build list to be removed */
|
|
||||||
dead = NULL;
|
|
||||||
for (tmp = display->pending_pings; tmp; tmp = tmp->next)
|
|
||||||
{
|
|
||||||
MetaPingData *ping_data = tmp->data;
|
|
||||||
|
|
||||||
if (ping_data->xwindow == xwindow)
|
|
||||||
dead = g_slist_prepend (dead, ping_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove what we found */
|
|
||||||
for (tmp = dead; tmp; tmp = tmp->next)
|
|
||||||
{
|
|
||||||
MetaPingData *ping_data = tmp->data;
|
|
||||||
|
|
||||||
display->pending_pings = g_slist_remove (display->pending_pings, ping_data);
|
|
||||||
ping_data_free (ping_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_slist_free (dead);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
static void
|
static void
|
||||||
sn_error_trap_push (SnDisplay *sn_display,
|
sn_error_trap_push (SnDisplay *sn_display,
|
||||||
@ -528,7 +435,6 @@ meta_display_open (void)
|
|||||||
the_display->server_grab_count = 0;
|
the_display->server_grab_count = 0;
|
||||||
the_display->display_opening = TRUE;
|
the_display->display_opening = TRUE;
|
||||||
|
|
||||||
the_display->pending_pings = NULL;
|
|
||||||
the_display->autoraise_timeout_id = 0;
|
the_display->autoraise_timeout_id = 0;
|
||||||
the_display->autoraise_window = NULL;
|
the_display->autoraise_window = NULL;
|
||||||
the_display->focus_window = NULL;
|
the_display->focus_window = NULL;
|
||||||
@ -600,6 +506,8 @@ meta_display_open (void)
|
|||||||
|
|
||||||
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
|
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
|
||||||
meta_unsigned_long_equal);
|
meta_unsigned_long_equal);
|
||||||
|
the_display->pending_pings = g_hash_table_new (meta_unsigned_long_hash,
|
||||||
|
meta_unsigned_long_equal);
|
||||||
the_display->wayland_windows = g_hash_table_new (NULL, NULL);
|
the_display->wayland_windows = g_hash_table_new (NULL, NULL);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -2887,7 +2795,13 @@ handle_other_xevent (MetaDisplay *display,
|
|||||||
|
|
||||||
if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING)
|
if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING)
|
||||||
{
|
{
|
||||||
process_pong_message (display, event);
|
guint32 timestamp = event->xclient.data.l[1];
|
||||||
|
window = g_hash_table_lookup (display->pending_pings, ×tamp);
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
meta_window_pong (window, timestamp);
|
||||||
|
else
|
||||||
|
meta_verbose ("Received invalid _NET_WM_PING for unknown timestamp %d\n", timestamp);
|
||||||
|
|
||||||
/* We don't want ping reply events going into
|
/* We don't want ping reply events going into
|
||||||
* the GTK+ event loop because gtk+ will treat
|
* the GTK+ event loop because gtk+ will treat
|
||||||
@ -3794,9 +3708,6 @@ meta_display_unregister_x_window (MetaDisplay *display,
|
|||||||
g_return_if_fail (g_hash_table_lookup (display->xids, &xwindow) != NULL);
|
g_return_if_fail (g_hash_table_lookup (display->xids, &xwindow) != NULL);
|
||||||
|
|
||||||
g_hash_table_remove (display->xids, &xwindow);
|
g_hash_table_remove (display->xids, &xwindow);
|
||||||
|
|
||||||
/* Remove any pending pings */
|
|
||||||
remove_pending_pings_for_window (display, xwindow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -4644,120 +4555,6 @@ meta_set_syncing (gboolean setting)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* How long, in milliseconds, we should wait after pinging a window
|
|
||||||
* before deciding it's not going to get back to us.
|
|
||||||
*/
|
|
||||||
#define PING_TIMEOUT_DELAY 5000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* meta_display_ping_timeout:
|
|
||||||
* @data: All the information about this ping. It is a #MetaPingData
|
|
||||||
* cast to a #gpointer in order to be passable to a timeout function.
|
|
||||||
* This function will also free this parameter.
|
|
||||||
*
|
|
||||||
* Does whatever it is we decided to do when a window didn't respond
|
|
||||||
* to a ping. We also remove the ping from the display's list of
|
|
||||||
* pending pings. This function is called by the event loop when the timeout
|
|
||||||
* times out which we created at the start of the ping.
|
|
||||||
*
|
|
||||||
* Returns: Always returns %FALSE, because this function is called as a
|
|
||||||
* timeout and we don't want to run the timer again.
|
|
||||||
*/
|
|
||||||
static gboolean
|
|
||||||
meta_display_ping_timeout (gpointer data)
|
|
||||||
{
|
|
||||||
MetaPingData *ping_data;
|
|
||||||
|
|
||||||
ping_data = data;
|
|
||||||
|
|
||||||
ping_data->ping_timeout_id = 0;
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_PING,
|
|
||||||
"Ping %u on window %lx timed out\n",
|
|
||||||
ping_data->timestamp, ping_data->xwindow);
|
|
||||||
|
|
||||||
(* ping_data->ping_timeout_func) (ping_data->display, ping_data->xwindow,
|
|
||||||
ping_data->timestamp, ping_data->user_data);
|
|
||||||
|
|
||||||
ping_data->display->pending_pings =
|
|
||||||
g_slist_remove (ping_data->display->pending_pings,
|
|
||||||
ping_data);
|
|
||||||
ping_data_free (ping_data);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* meta_display_ping_window:
|
|
||||||
* @display: The #MetaDisplay that the window is on
|
|
||||||
* @window: The #MetaWindow to send the ping to
|
|
||||||
* @timestamp: The timestamp of the ping. Used for uniqueness.
|
|
||||||
* Cannot be CurrentTime; use a real timestamp!
|
|
||||||
* @ping_reply_func: The callback to call if we get a response.
|
|
||||||
* @ping_timeout_func: The callback to call if we don't get a response.
|
|
||||||
* @user_data: Arbitrary data that will be passed to the callback
|
|
||||||
* function. (In practice it's often a pointer to
|
|
||||||
* the window.)
|
|
||||||
*
|
|
||||||
* Sends a ping request to a window. The window must respond to
|
|
||||||
* the request within a certain amount of time. If it does, we
|
|
||||||
* will call one callback; if the time passes and we haven't had
|
|
||||||
* a response, we call a different callback. The window must have
|
|
||||||
* the hint showing that it can respond to a ping; if it doesn't,
|
|
||||||
* we call the "got a response" callback immediately and return.
|
|
||||||
* This function returns straight away after setting things up;
|
|
||||||
* the callbacks will be called from the event loop.
|
|
||||||
*
|
|
||||||
* FIXME: This should probably be a method on windows, rather than displays
|
|
||||||
* for one of their windows.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
meta_display_ping_window (MetaDisplay *display,
|
|
||||||
MetaWindow *window,
|
|
||||||
guint32 timestamp,
|
|
||||||
MetaWindowPingFunc ping_reply_func,
|
|
||||||
MetaWindowPingFunc ping_timeout_func,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
MetaPingData *ping_data;
|
|
||||||
|
|
||||||
if (timestamp == CurrentTime)
|
|
||||||
{
|
|
||||||
meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!window->net_wm_ping)
|
|
||||||
{
|
|
||||||
if (ping_reply_func)
|
|
||||||
(* ping_reply_func) (display, window->xwindow, timestamp, user_data);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ping_data = g_new (MetaPingData, 1);
|
|
||||||
ping_data->display = display;
|
|
||||||
ping_data->xwindow = window->xwindow;
|
|
||||||
ping_data->timestamp = timestamp;
|
|
||||||
ping_data->ping_reply_func = ping_reply_func;
|
|
||||||
ping_data->ping_timeout_func = ping_timeout_func;
|
|
||||||
ping_data->user_data = user_data;
|
|
||||||
ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY,
|
|
||||||
meta_display_ping_timeout,
|
|
||||||
ping_data);
|
|
||||||
|
|
||||||
display->pending_pings = g_slist_prepend (display->pending_pings, ping_data);
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_PING,
|
|
||||||
"Sending ping with timestamp %u to window %s\n",
|
|
||||||
timestamp, window->desc);
|
|
||||||
meta_window_send_icccm_message (window,
|
|
||||||
display->atom__NET_WM_PING,
|
|
||||||
timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_request_frame_extents (MetaDisplay *display,
|
process_request_frame_extents (MetaDisplay *display,
|
||||||
XEvent *event)
|
XEvent *event)
|
||||||
@ -4818,91 +4615,6 @@ process_request_frame_extents (MetaDisplay *display,
|
|||||||
meta_XFree (hints);
|
meta_XFree (hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* process_pong_message:
|
|
||||||
* @display: the display we got the pong from
|
|
||||||
* @event: the #XEvent which is a pong; we can tell which
|
|
||||||
* ping it corresponds to because it bears the
|
|
||||||
* same timestamp.
|
|
||||||
*
|
|
||||||
* Process the pong (the response message) from the ping we sent
|
|
||||||
* to the window. This involves removing the timeout, calling the
|
|
||||||
* reply handler function, and freeing memory.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
process_pong_message (MetaDisplay *display,
|
|
||||||
XEvent *event)
|
|
||||||
{
|
|
||||||
GSList *tmp;
|
|
||||||
guint32 timestamp = event->xclient.data.l[1];
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n",
|
|
||||||
timestamp);
|
|
||||||
|
|
||||||
for (tmp = display->pending_pings; tmp; tmp = tmp->next)
|
|
||||||
{
|
|
||||||
MetaPingData *ping_data = tmp->data;
|
|
||||||
|
|
||||||
if (timestamp == ping_data->timestamp)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_PING,
|
|
||||||
"Matching ping found for pong %u\n",
|
|
||||||
ping_data->timestamp);
|
|
||||||
|
|
||||||
/* Remove the ping data from the list */
|
|
||||||
display->pending_pings = g_slist_remove (display->pending_pings,
|
|
||||||
ping_data);
|
|
||||||
|
|
||||||
/* Remove the timeout */
|
|
||||||
if (ping_data->ping_timeout_id != 0)
|
|
||||||
{
|
|
||||||
g_source_remove (ping_data->ping_timeout_id);
|
|
||||||
ping_data->ping_timeout_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call callback */
|
|
||||||
(* ping_data->ping_reply_func) (display,
|
|
||||||
ping_data->xwindow,
|
|
||||||
ping_data->timestamp,
|
|
||||||
ping_data->user_data);
|
|
||||||
|
|
||||||
ping_data_free (ping_data);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* meta_display_window_has_pending_pings:
|
|
||||||
* @display: The #MetaDisplay of the window.
|
|
||||||
* @window: The #MetaWindow whose pings we want to know about.
|
|
||||||
*
|
|
||||||
* Finds whether a window has any pings waiting on it.
|
|
||||||
*
|
|
||||||
* FIXME: This should probably be a method on windows, rather than displays
|
|
||||||
* for one of their windows.
|
|
||||||
*
|
|
||||||
* Returns: %TRUE if there is at least one ping which has been sent
|
|
||||||
* to the window without getting a response; %FALSE otherwise.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
meta_display_window_has_pending_pings (MetaDisplay *display,
|
|
||||||
MetaWindow *window)
|
|
||||||
{
|
|
||||||
GSList *tmp;
|
|
||||||
|
|
||||||
for (tmp = display->pending_pings; tmp; tmp = tmp->next)
|
|
||||||
{
|
|
||||||
MetaPingData *ping_data = tmp->data;
|
|
||||||
|
|
||||||
if (ping_data->xwindow == window->xwindow)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
MetaGroup*
|
MetaGroup*
|
||||||
get_focussed_group (MetaDisplay *display)
|
get_focussed_group (MetaDisplay *display)
|
||||||
{
|
{
|
||||||
|
@ -466,6 +466,8 @@ struct _MetaWindow
|
|||||||
|
|
||||||
/* Bypass compositor hints */
|
/* Bypass compositor hints */
|
||||||
guint bypass_compositor;
|
guint bypass_compositor;
|
||||||
|
|
||||||
|
GSList *pending_pings;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaWindowClass
|
struct _MetaWindowClass
|
||||||
@ -747,4 +749,16 @@ void meta_window_handle_enter (MetaWindow *window,
|
|||||||
void meta_window_set_surface_mapped (MetaWindow *window,
|
void meta_window_set_surface_mapped (MetaWindow *window,
|
||||||
gboolean surface_mapped);
|
gboolean surface_mapped);
|
||||||
|
|
||||||
|
typedef void (* MetaWindowPingFunc) (MetaWindow *window,
|
||||||
|
guint32 timestamp,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void meta_window_ping (MetaWindow *window,
|
||||||
|
guint32 timestamp,
|
||||||
|
MetaWindowPingFunc ping_reply_func,
|
||||||
|
MetaWindowPingFunc ping_timeout_func,
|
||||||
|
void *user_data);
|
||||||
|
void meta_window_pong (MetaWindow *window,
|
||||||
|
guint32 timestamp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,6 +73,26 @@
|
|||||||
|
|
||||||
static int destroying_windows_disallowed = 0;
|
static int destroying_windows_disallowed = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MetaPingData:
|
||||||
|
*
|
||||||
|
* Describes a ping on a window. When we send a ping to a window, we build
|
||||||
|
* one of these structs, and it eventually gets passed to the timeout function
|
||||||
|
* or to the function which handles the response from the window. If the window
|
||||||
|
* does or doesn't respond to the ping, we use this information to deal with
|
||||||
|
* these facts; we have a handler function for each.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
MetaWindow *window;
|
||||||
|
guint32 timestamp;
|
||||||
|
MetaWindowPingFunc ping_reply_func;
|
||||||
|
MetaWindowPingFunc ping_timeout_func;
|
||||||
|
void *user_data;
|
||||||
|
guint ping_timeout_id;
|
||||||
|
} MetaPingData;
|
||||||
|
|
||||||
|
static void ping_data_free (MetaPingData *ping_data);
|
||||||
|
|
||||||
static void update_sm_hints (MetaWindow *window);
|
static void update_sm_hints (MetaWindow *window);
|
||||||
static void update_net_frame_extents (MetaWindow *window);
|
static void update_net_frame_extents (MetaWindow *window);
|
||||||
@ -2051,6 +2071,8 @@ meta_window_unmanage (MetaWindow *window,
|
|||||||
if (window->surface)
|
if (window->surface)
|
||||||
meta_wayland_surface_free (window->surface);
|
meta_wayland_surface_free (window->surface);
|
||||||
|
|
||||||
|
g_slist_free_full (window->pending_pings, (GDestroyNotify) ping_data_free);
|
||||||
|
|
||||||
meta_prefs_remove_listener (prefs_changed_callback, window);
|
meta_prefs_remove_listener (prefs_changed_callback, window);
|
||||||
|
|
||||||
meta_screen_queue_check_fullscreen (window->screen);
|
meta_screen_queue_check_fullscreen (window->screen);
|
||||||
@ -11960,3 +11982,194 @@ meta_window_set_surface_mapped (MetaWindow *window,
|
|||||||
window->surface_mapped = surface_mapped;
|
window->surface_mapped = surface_mapped;
|
||||||
meta_window_queue (window, META_QUEUE_CALC_SHOWING);
|
meta_window_queue (window, META_QUEUE_CALC_SHOWING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SECTION:pings
|
||||||
|
*
|
||||||
|
* Sometimes we want to see whether a window is responding,
|
||||||
|
* so we send it a "ping" message and see whether it sends us back a "pong"
|
||||||
|
* message within a reasonable time. Here we have a system which lets us
|
||||||
|
* nominate one function to be called if we get the pong in time and another
|
||||||
|
* function if we don't. The system is rather more complicated than it needs
|
||||||
|
* to be, since we only ever use it to destroy windows which are asked to
|
||||||
|
* close themselves and don't do so within a reasonable amount of time, and
|
||||||
|
* therefore we always use the same callbacks. It's possible that we might
|
||||||
|
* use it for other things in future, or on the other hand we might decide
|
||||||
|
* that we're never going to do so and simplify it a bit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ping_data_free:
|
||||||
|
*
|
||||||
|
* Destructor for #MetaPingData structs. Will destroy the
|
||||||
|
* event source for the struct as well.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ping_data_free (MetaPingData *ping_data)
|
||||||
|
{
|
||||||
|
MetaWindow *window = ping_data->window;
|
||||||
|
MetaDisplay *display = window->display;
|
||||||
|
|
||||||
|
/* Remove the timeout */
|
||||||
|
if (ping_data->ping_timeout_id != 0)
|
||||||
|
g_source_remove (ping_data->ping_timeout_id);
|
||||||
|
|
||||||
|
g_hash_table_remove (display->pending_pings, &ping_data->timestamp);
|
||||||
|
|
||||||
|
g_free (ping_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* meta_window_pong:
|
||||||
|
* @window: the window we got the pong on
|
||||||
|
* @timestamp: the timestamp that the client sent back
|
||||||
|
*
|
||||||
|
* Process the pong (the response message) from the ping we sent
|
||||||
|
* to the window. This involves removing the timeout, calling the
|
||||||
|
* reply handler function, and freeing memory.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
meta_window_pong (MetaWindow *window,
|
||||||
|
guint32 timestamp)
|
||||||
|
{
|
||||||
|
GSList *tmp;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n",
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
for (tmp = window->pending_pings; tmp; tmp = tmp->next)
|
||||||
|
{
|
||||||
|
MetaPingData *ping_data = tmp->data;
|
||||||
|
|
||||||
|
if (timestamp == ping_data->timestamp)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_PING,
|
||||||
|
"Matching ping found for pong %u\n",
|
||||||
|
ping_data->timestamp);
|
||||||
|
|
||||||
|
/* Remove the ping data from the list */
|
||||||
|
window->pending_pings = g_slist_remove (window->pending_pings, ping_data);
|
||||||
|
|
||||||
|
/* Remove the timeout */
|
||||||
|
if (ping_data->ping_timeout_id != 0)
|
||||||
|
{
|
||||||
|
g_source_remove (ping_data->ping_timeout_id);
|
||||||
|
ping_data->ping_timeout_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call callback */
|
||||||
|
(* ping_data->ping_reply_func) (window,
|
||||||
|
ping_data->timestamp,
|
||||||
|
ping_data->user_data);
|
||||||
|
|
||||||
|
/* Remove the ping data from the list */
|
||||||
|
window->pending_pings = g_slist_remove (window->pending_pings, ping_data);
|
||||||
|
|
||||||
|
ping_data_free (ping_data);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How long, in milliseconds, we should wait after pinging a window
|
||||||
|
* before deciding it's not going to get back to us.
|
||||||
|
*/
|
||||||
|
#define PING_TIMEOUT_DELAY 5000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ping_timeout:
|
||||||
|
* @data: All the information about this ping. It is a #MetaPingData
|
||||||
|
* cast to a #gpointer in order to be passable to a timeout function.
|
||||||
|
* This function will also free this parameter.
|
||||||
|
*
|
||||||
|
* Does whatever it is we decided to do when a window didn't respond
|
||||||
|
* to a ping. We also remove the ping from the display's list of
|
||||||
|
* pending pings. This function is called by the event loop when the timeout
|
||||||
|
* times out which we created at the start of the ping.
|
||||||
|
*
|
||||||
|
* Returns: Always returns %FALSE, because this function is called as a
|
||||||
|
* timeout and we don't want to run the timer again.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
ping_timeout (gpointer data)
|
||||||
|
{
|
||||||
|
MetaPingData *ping_data;
|
||||||
|
|
||||||
|
ping_data = data;
|
||||||
|
|
||||||
|
ping_data->ping_timeout_id = 0;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_PING,
|
||||||
|
"Ping %u on window %s timed out\n",
|
||||||
|
ping_data->timestamp, ping_data->window->desc);
|
||||||
|
|
||||||
|
(* ping_data->ping_timeout_func) (ping_data->window, ping_data->timestamp, ping_data->user_data);
|
||||||
|
|
||||||
|
ping_data_free (ping_data);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* meta_window_ping:
|
||||||
|
* @window: The #MetaWindow to send the ping to
|
||||||
|
* @timestamp: The timestamp of the ping. Used for uniqueness.
|
||||||
|
* Cannot be CurrentTime; use a real timestamp!
|
||||||
|
* @ping_reply_func: The callback to call if we get a response.
|
||||||
|
* @ping_timeout_func: The callback to call if we don't get a response.
|
||||||
|
* @user_data: Arbitrary data that will be passed to the callback
|
||||||
|
* function. (In practice it's often a pointer to
|
||||||
|
* the window.)
|
||||||
|
*
|
||||||
|
* Sends a ping request to a window. The window must respond to
|
||||||
|
* the request within a certain amount of time. If it does, we
|
||||||
|
* will call one callback; if the time passes and we haven't had
|
||||||
|
* a response, we call a different callback. The window must have
|
||||||
|
* the hint showing that it can respond to a ping; if it doesn't,
|
||||||
|
* we call the "got a response" callback immediately and return.
|
||||||
|
* This function returns straight away after setting things up;
|
||||||
|
* the callbacks will be called from the event loop.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
meta_window_ping (MetaWindow *window,
|
||||||
|
guint32 timestamp,
|
||||||
|
MetaWindowPingFunc ping_reply_func,
|
||||||
|
MetaWindowPingFunc ping_timeout_func,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaPingData *ping_data;
|
||||||
|
MetaDisplay *display = window->display;
|
||||||
|
|
||||||
|
if (timestamp == CurrentTime)
|
||||||
|
{
|
||||||
|
meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window->net_wm_ping)
|
||||||
|
{
|
||||||
|
if (ping_reply_func)
|
||||||
|
(* ping_reply_func) (window, timestamp, user_data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ping_data = g_new (MetaPingData, 1);
|
||||||
|
ping_data->window = window;
|
||||||
|
ping_data->timestamp = timestamp;
|
||||||
|
ping_data->ping_reply_func = ping_reply_func;
|
||||||
|
ping_data->ping_timeout_func = ping_timeout_func;
|
||||||
|
ping_data->user_data = user_data;
|
||||||
|
ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY, ping_timeout, ping_data);
|
||||||
|
|
||||||
|
g_hash_table_insert (display->pending_pings, &ping_data->timestamp, window);
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_PING,
|
||||||
|
"Sending ping with timestamp %u to window %s\n",
|
||||||
|
timestamp, window->desc);
|
||||||
|
meta_window_send_icccm_message (window,
|
||||||
|
display->atom__NET_WM_PING,
|
||||||
|
timestamp);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user