mutter/src/x11/meta-startup-notification-x11.c
Carlos Garnacho ab7ef5f8bf core: Fix differing sequence timestamp precision expectations
Calculations were being done at places accounting on usec precision,
however those are still treated as having msec precision at places. Let's
consolidate for the latter since it requires less changes across the board
and usec precision doesn't buy us anything here.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/541
2019-04-17 18:41:13 +02:00

371 lines
11 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2018 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "meta-startup-notification-x11.h"
#include <gio/gdesktopappinfo.h>
#include "core/display-private.h"
#include "core/startup-notification-private.h"
#include "meta/meta-x11-errors.h"
#include "x11/meta-x11-display-private.h"
#ifdef HAVE_STARTUP_NOTIFICATION
enum
{
PROP_SEQ_X11_0,
PROP_SEQ_X11_SEQ,
N_SEQ_X11_PROPS
};
struct _MetaStartupSequenceX11
{
MetaStartupSequence parent_instance;
SnStartupSequence *seq;
};
struct _MetaX11StartupNotification
{
SnDisplay *sn_display;
SnMonitorContext *sn_context;
};
static GParamSpec *seq_x11_props[N_SEQ_X11_PROPS];
G_DEFINE_TYPE (MetaStartupSequenceX11,
meta_startup_sequence_x11,
META_TYPE_STARTUP_SEQUENCE)
static void
meta_startup_sequence_x11_complete (MetaStartupSequence *seq)
{
MetaStartupSequenceX11 *seq_x11;
seq_x11 = META_STARTUP_SEQUENCE_X11 (seq);
sn_startup_sequence_complete (seq_x11->seq);
}
static void
meta_startup_sequence_x11_finalize (GObject *object)
{
MetaStartupSequenceX11 *seq_x11;
seq_x11 = META_STARTUP_SEQUENCE_X11 (object);
sn_startup_sequence_unref (seq_x11->seq);
G_OBJECT_CLASS (meta_startup_sequence_x11_parent_class)->finalize (object);
}
static void
meta_startup_sequence_x11_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaStartupSequenceX11 *seq_x11;
seq_x11 = META_STARTUP_SEQUENCE_X11 (object);
switch (prop_id)
{
case PROP_SEQ_X11_SEQ:
seq_x11->seq = g_value_get_pointer (value);
sn_startup_sequence_ref (seq_x11->seq);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_startup_sequence_x11_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaStartupSequenceX11 *seq_x11;
seq_x11 = META_STARTUP_SEQUENCE_X11 (object);
switch (prop_id)
{
case PROP_SEQ_X11_SEQ:
g_value_set_pointer (value, seq_x11->seq);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_startup_sequence_x11_init (MetaStartupSequenceX11 *seq)
{
}
static void
meta_startup_sequence_x11_class_init (MetaStartupSequenceX11Class *klass)
{
MetaStartupSequenceClass *seq_class;
GObjectClass *object_class;
seq_class = META_STARTUP_SEQUENCE_CLASS (klass);
seq_class->complete = meta_startup_sequence_x11_complete;
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_startup_sequence_x11_finalize;
object_class->set_property = meta_startup_sequence_x11_set_property;
object_class->get_property = meta_startup_sequence_x11_get_property;
seq_x11_props[PROP_SEQ_X11_SEQ] =
g_param_spec_pointer ("seq",
"Sequence",
"Sequence",
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_SEQ_X11_PROPS,
seq_x11_props);
}
static MetaStartupSequence *
meta_startup_sequence_x11_new (SnStartupSequence *seq)
{
gint64 timestamp;
timestamp = sn_startup_sequence_get_timestamp (seq);
return g_object_new (META_TYPE_STARTUP_SEQUENCE_X11,
"id", sn_startup_sequence_get_id (seq),
"icon-name", sn_startup_sequence_get_icon_name (seq),
"application-id", sn_startup_sequence_get_application_id (seq),
"wmclass", sn_startup_sequence_get_wmclass (seq),
"name", sn_startup_sequence_get_name (seq),
"workspace", sn_startup_sequence_get_workspace (seq),
"timestamp", timestamp,
"seq", seq,
NULL);
}
static void
sn_error_trap_push (SnDisplay *sn_display,
Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display != NULL)
meta_x11_error_trap_push (display->x11_display);
}
static void
sn_error_trap_pop (SnDisplay *sn_display,
Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display != NULL)
meta_x11_error_trap_pop (display->x11_display);
}
static void
meta_startup_notification_sn_event (SnMonitorEvent *event,
void *user_data)
{
MetaX11Display *x11_display = user_data;
MetaStartupNotification *sn = x11_display->display->startup_notification;
MetaStartupSequence *seq;
SnStartupSequence *sequence;
sequence = sn_monitor_event_get_startup_sequence (event);
sn_startup_sequence_ref (sequence);
switch (sn_monitor_event_get_type (event))
{
case SN_MONITOR_EVENT_INITIATED:
{
const char *wmclass;
wmclass = sn_startup_sequence_get_wmclass (sequence);
meta_topic (META_DEBUG_STARTUP,
"Received startup initiated for %s wmclass %s\n",
sn_startup_sequence_get_id (sequence),
wmclass ? wmclass : "(unset)");
seq = meta_startup_sequence_x11_new (sequence);
meta_startup_notification_add_sequence (sn, seq);
g_object_unref (seq);
}
break;
case SN_MONITOR_EVENT_COMPLETED:
{
meta_topic (META_DEBUG_STARTUP,
"Received startup completed for %s\n",
sn_startup_sequence_get_id (sequence));
seq = meta_startup_notification_lookup_sequence (sn, sn_startup_sequence_get_id (sequence));
if (seq)
{
meta_startup_sequence_complete (seq);
meta_startup_notification_remove_sequence (sn, seq);
}
}
break;
case SN_MONITOR_EVENT_CHANGED:
meta_topic (META_DEBUG_STARTUP,
"Received startup changed for %s\n",
sn_startup_sequence_get_id (sequence));
break;
case SN_MONITOR_EVENT_CANCELED:
meta_topic (META_DEBUG_STARTUP,
"Received startup canceled for %s\n",
sn_startup_sequence_get_id (sequence));
break;
}
sn_startup_sequence_unref (sequence);
}
#endif
void
meta_x11_startup_notification_init (MetaX11Display *x11_display)
{
#ifdef HAVE_STARTUP_NOTIFICATION
MetaX11StartupNotification *x11_sn;
x11_sn = g_new0 (MetaX11StartupNotification, 1);
x11_sn->sn_display = sn_display_new (x11_display->xdisplay,
sn_error_trap_push,
sn_error_trap_pop);
x11_sn->sn_context =
sn_monitor_context_new (x11_sn->sn_display,
meta_x11_display_get_screen_number (x11_display),
meta_startup_notification_sn_event,
x11_display,
NULL);
x11_display->startup_notification = x11_sn;
#endif
}
void
meta_x11_startup_notification_release (MetaX11Display *x11_display)
{
#ifdef HAVE_STARTUP_NOTIFICATION
MetaX11StartupNotification *x11_sn = x11_display->startup_notification;
x11_display->startup_notification = NULL;
if (x11_sn)
{
sn_monitor_context_unref (x11_sn->sn_context);
sn_display_unref (x11_sn->sn_display);
g_free (x11_sn);
}
#endif
}
gboolean
meta_x11_startup_notification_handle_xevent (MetaX11Display *x11_display,
XEvent *xevent)
{
MetaX11StartupNotification *x11_sn = x11_display->startup_notification;
if (!x11_sn)
return FALSE;
return sn_display_process_event (x11_sn->sn_display, xevent);
}
typedef void (* SetAppIdFunc) (SnLauncherContext *context,
const char *app_id);
gchar *
meta_x11_startup_notification_launch (MetaX11Display *x11_display,
GAppInfo *app_info,
uint32_t timestamp,
int workspace)
{
gchar *startup_id = NULL;
#ifdef HAVE_STARTUP_NOTIFICATION
MetaX11StartupNotification *x11_sn = x11_display->startup_notification;
SnLauncherContext *sn_launcher;
int screen;
screen = meta_x11_display_get_screen_number (x11_display);
sn_launcher = sn_launcher_context_new (x11_sn->sn_display, screen);
sn_launcher_context_set_name (sn_launcher, g_app_info_get_name (app_info));
sn_launcher_context_set_workspace (sn_launcher, workspace);
sn_launcher_context_set_binary_name (sn_launcher,
g_app_info_get_executable (app_info));
if (G_IS_DESKTOP_APP_INFO (app_info))
{
const char *application_id;
SetAppIdFunc func = NULL;
GModule *self;
application_id =
g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (app_info));
self = g_module_open (NULL, G_MODULE_BIND_MASK);
/* This here is a terrible workaround to bypass a libsn bug that is not
* likely to get fixed at this point.
* sn_launcher_context_set_application_id is correctly defined in the
* sn-launcher.h file, but it's mistakenly called
* sn_launcher_set_application_id in the C file.
*
* We look up the symbol instead, but still prefer the correctly named
* function, if one were ever to be added.
*/
if (!g_module_symbol (self, "sn_launcher_context_set_application_id",
(gpointer *) &func))
{
g_module_symbol (self, "sn_launcher_set_application_id",
(gpointer *) &func);
}
if (func)
func (sn_launcher, application_id);
g_module_close (self);
}
sn_launcher_context_initiate (sn_launcher,
g_get_prgname (),
g_app_info_get_name (app_info),
timestamp);
startup_id = g_strdup (sn_launcher_context_get_startup_id (sn_launcher));
/* Fire and forget, we have a SnMonitor in addition */
sn_launcher_context_unref (sn_launcher);
#endif /* HAVE_STARTUP_NOTIFICATION */
return startup_id;
}