mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 17:40:40 -05:00
core: Refactor startup notification into a separate object
This is kind of in a middle ground at the moment. Even though it handles sequences not coming from libsn, they're added nowhere at the moment, we'll rely on the app launch context being in the x11 side at the moment. Also, even though we do create internal sequence objects, we keep exposing SnStartupSequences to make gnome-shell happy, we could consider making this object "public" (and the sequence objects with it), things stay private at the moment. https://bugzilla.gnome.org/show_bug.cgi?id=762268
This commit is contained in:
parent
bed82427c6
commit
56beedf9f2
@ -198,6 +198,8 @@ libmutter_la_SOURCES = \
|
|||||||
core/screen.c \
|
core/screen.c \
|
||||||
core/screen-private.h \
|
core/screen-private.h \
|
||||||
meta/screen.h \
|
meta/screen.h \
|
||||||
|
core/startup-notification.c \
|
||||||
|
core/startup-notification-private.h \
|
||||||
meta/types.h \
|
meta/types.h \
|
||||||
core/restart.c \
|
core/restart.c \
|
||||||
core/stack.c \
|
core/stack.c \
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <meta/boxes.h>
|
#include <meta/boxes.h>
|
||||||
#include <meta/display.h>
|
#include <meta/display.h>
|
||||||
#include "keybindings-private.h"
|
#include "keybindings-private.h"
|
||||||
|
#include "startup-notification-private.h"
|
||||||
#include "meta-gesture-tracker-private.h"
|
#include "meta-gesture-tracker-private.h"
|
||||||
#include <meta/prefs.h>
|
#include <meta/prefs.h>
|
||||||
#include <meta/barrier.h>
|
#include <meta/barrier.h>
|
||||||
@ -276,9 +277,8 @@ struct _MetaDisplay
|
|||||||
int xinput_event_base;
|
int xinput_event_base;
|
||||||
int xinput_opcode;
|
int xinput_opcode;
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
MetaStartupNotification *startup_notification;
|
||||||
SnDisplay *sn_display;
|
|
||||||
#endif
|
|
||||||
int xsync_event_base;
|
int xsync_event_base;
|
||||||
int xsync_error_base;
|
int xsync_error_base;
|
||||||
int shape_event_base;
|
int shape_event_base;
|
||||||
|
@ -400,28 +400,6 @@ meta_display_remove_pending_pings_for_window (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
static void
|
|
||||||
sn_error_trap_push (SnDisplay *sn_display,
|
|
||||||
Display *xdisplay)
|
|
||||||
{
|
|
||||||
MetaDisplay *display;
|
|
||||||
display = meta_display_for_x_display (xdisplay);
|
|
||||||
if (display != NULL)
|
|
||||||
meta_error_trap_push (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_error_trap_pop (display);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
enable_compositor (MetaDisplay *display)
|
enable_compositor (MetaDisplay *display)
|
||||||
{
|
{
|
||||||
@ -527,6 +505,20 @@ gesture_tracker_state_changed (MetaGestureTracker *tracker,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_startup_notification_changed (MetaStartupNotification *sn,
|
||||||
|
gpointer sequence,
|
||||||
|
MetaDisplay *display)
|
||||||
|
{
|
||||||
|
if (!display->screen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_slist_free (display->screen->startup_sequences);
|
||||||
|
display->screen->startup_sequences =
|
||||||
|
meta_startup_notification_get_sequences (display->startup_notification);
|
||||||
|
g_signal_emit_by_name (display->screen, "startup-sequence-changed", sequence);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_display_open:
|
* meta_display_open:
|
||||||
*
|
*
|
||||||
@ -630,12 +622,6 @@ meta_display_open (void)
|
|||||||
|
|
||||||
display->screen = NULL;
|
display->screen = NULL;
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
display->sn_display = sn_display_new (display->xdisplay,
|
|
||||||
sn_error_trap_push,
|
|
||||||
sn_error_trap_pop);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Get events */
|
/* Get events */
|
||||||
meta_display_init_events (display);
|
meta_display_init_events (display);
|
||||||
meta_display_init_events_x11 (display);
|
meta_display_init_events_x11 (display);
|
||||||
@ -916,6 +902,10 @@ meta_display_open (void)
|
|||||||
|
|
||||||
display->screen = screen;
|
display->screen = screen;
|
||||||
|
|
||||||
|
display->startup_notification = meta_startup_notification_get (display);
|
||||||
|
g_signal_connect (display->startup_notification, "changed",
|
||||||
|
G_CALLBACK (on_startup_notification_changed), display);
|
||||||
|
|
||||||
meta_screen_init_workspaces (screen);
|
meta_screen_init_workspaces (screen);
|
||||||
|
|
||||||
enable_compositor (display);
|
enable_compositor (display);
|
||||||
@ -1100,6 +1090,7 @@ meta_display_close (MetaDisplay *display,
|
|||||||
|
|
||||||
meta_display_remove_autoraise_callback (display);
|
meta_display_remove_autoraise_callback (display);
|
||||||
|
|
||||||
|
g_clear_object (&display->startup_notification);
|
||||||
g_clear_object (&display->gesture_tracker);
|
g_clear_object (&display->gesture_tracker);
|
||||||
|
|
||||||
if (display->focus_timeout_id)
|
if (display->focus_timeout_id)
|
||||||
@ -1112,14 +1103,6 @@ meta_display_close (MetaDisplay *display,
|
|||||||
|
|
||||||
meta_screen_free (display->screen, timestamp);
|
meta_screen_free (display->screen, timestamp);
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
if (display->sn_display)
|
|
||||||
{
|
|
||||||
sn_display_unref (display->sn_display);
|
|
||||||
display->sn_display = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Must be after all calls to meta_window_unmanage() since they
|
/* Must be after all calls to meta_window_unmanage() since they
|
||||||
* unregister windows
|
* unregister windows
|
||||||
*/
|
*/
|
||||||
|
@ -85,11 +85,7 @@ struct _MetaScreen
|
|||||||
/* Cache the current monitor */
|
/* Cache the current monitor */
|
||||||
int last_monitor_index;
|
int last_monitor_index;
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
SnMonitorContext *sn_context;
|
|
||||||
GSList *startup_sequences;
|
GSList *startup_sequences;
|
||||||
guint startup_sequence_timeout;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Window wm_cm_selection_window;
|
Window wm_cm_selection_window;
|
||||||
guint work_area_later;
|
guint work_area_later;
|
||||||
|
@ -71,11 +71,6 @@ static void prefs_changed_callback (MetaPreference pref,
|
|||||||
static void set_desktop_geometry_hint (MetaScreen *screen);
|
static void set_desktop_geometry_hint (MetaScreen *screen);
|
||||||
static void set_desktop_viewport_hint (MetaScreen *screen);
|
static void set_desktop_viewport_hint (MetaScreen *screen);
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
static void meta_screen_sn_event (SnMonitorEvent *event,
|
|
||||||
void *user_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void on_monitors_changed (MetaMonitorManager *manager,
|
static void on_monitors_changed (MetaMonitorManager *manager,
|
||||||
MetaScreen *screen);
|
MetaScreen *screen);
|
||||||
|
|
||||||
@ -730,17 +725,6 @@ meta_screen_new (MetaDisplay *display,
|
|||||||
|
|
||||||
meta_prefs_add_listener (prefs_changed_callback, screen);
|
meta_prefs_add_listener (prefs_changed_callback, screen);
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
screen->sn_context =
|
|
||||||
sn_monitor_context_new (screen->display->sn_display,
|
|
||||||
screen->number,
|
|
||||||
meta_screen_sn_event,
|
|
||||||
screen,
|
|
||||||
NULL);
|
|
||||||
screen->startup_sequences = NULL;
|
|
||||||
screen->startup_sequence_timeout = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
|
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
|
||||||
screen->number, screen->screen_name, screen->xroot);
|
screen->number, screen->screen_name, screen->xroot);
|
||||||
|
|
||||||
@ -800,24 +784,6 @@ meta_screen_free (MetaScreen *screen,
|
|||||||
|
|
||||||
meta_screen_ungrab_keys (screen);
|
meta_screen_ungrab_keys (screen);
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
g_slist_foreach (screen->startup_sequences,
|
|
||||||
(GFunc) sn_startup_sequence_unref, NULL);
|
|
||||||
g_slist_free (screen->startup_sequences);
|
|
||||||
screen->startup_sequences = NULL;
|
|
||||||
|
|
||||||
if (screen->startup_sequence_timeout != 0)
|
|
||||||
{
|
|
||||||
g_source_remove (screen->startup_sequence_timeout);
|
|
||||||
screen->startup_sequence_timeout = 0;
|
|
||||||
}
|
|
||||||
if (screen->sn_context)
|
|
||||||
{
|
|
||||||
sn_monitor_context_unref (screen->sn_context);
|
|
||||||
screen->sn_context = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
meta_ui_free (screen->ui);
|
meta_ui_free (screen->ui);
|
||||||
|
|
||||||
meta_stack_free (screen->stack);
|
meta_stack_free (screen->stack);
|
||||||
@ -2538,208 +2504,6 @@ meta_screen_unshow_desktop (MetaScreen *screen)
|
|||||||
meta_screen_update_showing_desktop_hint (screen);
|
meta_screen_update_showing_desktop_hint (screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
|
||||||
static gboolean startup_sequence_timeout (void *data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_startup_feedback (MetaScreen *screen)
|
|
||||||
{
|
|
||||||
if (screen->startup_sequences != NULL)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_STARTUP,
|
|
||||||
"Setting busy cursor\n");
|
|
||||||
meta_screen_set_cursor (screen, META_CURSOR_BUSY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_STARTUP,
|
|
||||||
"Setting default cursor\n");
|
|
||||||
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_sequence (MetaScreen *screen,
|
|
||||||
SnStartupSequence *sequence)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_STARTUP,
|
|
||||||
"Adding sequence %s\n",
|
|
||||||
sn_startup_sequence_get_id (sequence));
|
|
||||||
sn_startup_sequence_ref (sequence);
|
|
||||||
screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
|
|
||||||
sequence);
|
|
||||||
|
|
||||||
/* our timeout just polls every second, instead of bothering
|
|
||||||
* to compute exactly when we may next time out
|
|
||||||
*/
|
|
||||||
if (screen->startup_sequence_timeout == 0)
|
|
||||||
{
|
|
||||||
screen->startup_sequence_timeout = g_timeout_add_seconds (1,
|
|
||||||
startup_sequence_timeout,
|
|
||||||
screen);
|
|
||||||
g_source_set_name_by_id (screen->startup_sequence_timeout,
|
|
||||||
"[mutter] startup_sequence_timeout");
|
|
||||||
}
|
|
||||||
|
|
||||||
update_startup_feedback (screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_sequence (MetaScreen *screen,
|
|
||||||
SnStartupSequence *sequence)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_STARTUP,
|
|
||||||
"Removing sequence %s\n",
|
|
||||||
sn_startup_sequence_get_id (sequence));
|
|
||||||
|
|
||||||
screen->startup_sequences = g_slist_remove (screen->startup_sequences,
|
|
||||||
sequence);
|
|
||||||
|
|
||||||
if (screen->startup_sequences == NULL &&
|
|
||||||
screen->startup_sequence_timeout != 0)
|
|
||||||
{
|
|
||||||
g_source_remove (screen->startup_sequence_timeout);
|
|
||||||
screen->startup_sequence_timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_startup_feedback (screen);
|
|
||||||
|
|
||||||
sn_startup_sequence_unref (sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
GSList *list;
|
|
||||||
GTimeVal now;
|
|
||||||
} CollectTimedOutData;
|
|
||||||
|
|
||||||
/* This should be fairly long, as it should never be required unless
|
|
||||||
* apps or .desktop files are buggy, and it's confusing if
|
|
||||||
* OpenOffice or whatever seems to stop launching - people
|
|
||||||
* might decide they need to launch it again.
|
|
||||||
*/
|
|
||||||
#define STARTUP_TIMEOUT 15000
|
|
||||||
|
|
||||||
static void
|
|
||||||
collect_timed_out_foreach (void *element,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
CollectTimedOutData *ctod = data;
|
|
||||||
SnStartupSequence *sequence = element;
|
|
||||||
long tv_sec, tv_usec;
|
|
||||||
double elapsed;
|
|
||||||
|
|
||||||
sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
|
|
||||||
|
|
||||||
elapsed =
|
|
||||||
((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC +
|
|
||||||
(ctod->now.tv_usec - tv_usec))) / 1000.0;
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_STARTUP,
|
|
||||||
"Sequence used %g seconds vs. %g max: %s\n",
|
|
||||||
elapsed, (double) STARTUP_TIMEOUT,
|
|
||||||
sn_startup_sequence_get_id (sequence));
|
|
||||||
|
|
||||||
if (elapsed > STARTUP_TIMEOUT)
|
|
||||||
ctod->list = g_slist_prepend (ctod->list, sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
startup_sequence_timeout (void *data)
|
|
||||||
{
|
|
||||||
MetaScreen *screen = data;
|
|
||||||
CollectTimedOutData ctod;
|
|
||||||
GSList *l;
|
|
||||||
|
|
||||||
ctod.list = NULL;
|
|
||||||
g_get_current_time (&ctod.now);
|
|
||||||
g_slist_foreach (screen->startup_sequences,
|
|
||||||
collect_timed_out_foreach,
|
|
||||||
&ctod);
|
|
||||||
|
|
||||||
for (l = ctod.list; l != NULL; l = l->next)
|
|
||||||
{
|
|
||||||
SnStartupSequence *sequence = l->data;
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_STARTUP,
|
|
||||||
"Timed out sequence %s\n",
|
|
||||||
sn_startup_sequence_get_id (sequence));
|
|
||||||
|
|
||||||
sn_startup_sequence_complete (sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_slist_free (ctod.list);
|
|
||||||
|
|
||||||
if (screen->startup_sequences != NULL)
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* remove */
|
|
||||||
screen->startup_sequence_timeout = 0;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_screen_sn_event (SnMonitorEvent *event,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
MetaScreen *screen;
|
|
||||||
SnStartupSequence *sequence;
|
|
||||||
|
|
||||||
screen = user_data;
|
|
||||||
|
|
||||||
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)");
|
|
||||||
add_sequence (screen, sequence);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SN_MONITOR_EVENT_COMPLETED:
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_STARTUP,
|
|
||||||
"Received startup completed for %s\n",
|
|
||||||
sn_startup_sequence_get_id (sequence));
|
|
||||||
remove_sequence (screen,
|
|
||||||
sn_monitor_event_get_startup_sequence (event));
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (screen), screen_signals[STARTUP_SEQUENCE_CHANGED], 0, sequence);
|
|
||||||
|
|
||||||
sn_startup_sequence_unref (sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_screen_get_startup_sequences: (skip)
|
* meta_screen_get_startup_sequences: (skip)
|
||||||
* @screen:
|
* @screen:
|
||||||
@ -2751,7 +2515,6 @@ meta_screen_get_startup_sequences (MetaScreen *screen)
|
|||||||
{
|
{
|
||||||
return screen->startup_sequences;
|
return screen->startup_sequences;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Sets the initial_timestamp and initial_workspace properties
|
/* Sets the initial_timestamp and initial_workspace properties
|
||||||
* of a window according to information given us by the
|
* of a window according to information given us by the
|
||||||
|
48
src/core/startup-notification-private.h
Normal file
48
src/core/startup-notification-private.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001, 2002 Havoc Pennington
|
||||||
|
* Copyright (C) 2002, 2003 Red Hat Inc.
|
||||||
|
* Some ICCCM manager selection code derived from fvwm2,
|
||||||
|
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
|
||||||
|
* Copyright (C) 2003 Rob Adams
|
||||||
|
* Copyright (C) 2004-2006 Elijah Newren
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef META_STARTUP_NOTIFICATION_PRIVATE_H
|
||||||
|
#define META_STARTUP_NOTIFICATION_PRIVATE_H
|
||||||
|
|
||||||
|
#include "display-private.h"
|
||||||
|
|
||||||
|
#define META_TYPE_STARTUP_NOTIFICATION (meta_startup_notification_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaStartupNotification,
|
||||||
|
meta_startup_notification,
|
||||||
|
META, STARTUP_NOTIFICATION,
|
||||||
|
GObject)
|
||||||
|
|
||||||
|
MetaStartupNotification *
|
||||||
|
meta_startup_notification_get (MetaDisplay *display);
|
||||||
|
|
||||||
|
gboolean meta_startup_notification_handle_xevent (MetaStartupNotification *sn,
|
||||||
|
XEvent *xevent);
|
||||||
|
|
||||||
|
void meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
|
||||||
|
const gchar *id);
|
||||||
|
|
||||||
|
GSList * meta_startup_notification_get_sequences (MetaStartupNotification *sn);
|
||||||
|
|
||||||
|
#endif /* META_STARTUP_NOTIFICATION_PRIVATE_H */
|
767
src/core/startup-notification.c
Normal file
767
src/core/startup-notification.c
Normal file
@ -0,0 +1,767 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001, 2002 Havoc Pennington
|
||||||
|
* Copyright (C) 2002, 2003 Red Hat Inc.
|
||||||
|
* Some ICCCM manager selection code derived from fvwm2,
|
||||||
|
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
|
||||||
|
* Copyright (C) 2003 Rob Adams
|
||||||
|
* Copyright (C) 2004-2006 Elijah Newren
|
||||||
|
*
|
||||||
|
* 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 <glib-object.h>
|
||||||
|
|
||||||
|
#include <meta/errors.h>
|
||||||
|
#include "display-private.h"
|
||||||
|
#include "screen-private.h"
|
||||||
|
#include "startup-notification-private.h"
|
||||||
|
|
||||||
|
/* This should be fairly long, as it should never be required unless
|
||||||
|
* apps or .desktop files are buggy, and it's confusing if
|
||||||
|
* OpenOffice or whatever seems to stop launching - people
|
||||||
|
* might decide they need to launch it again.
|
||||||
|
*/
|
||||||
|
#define STARTUP_TIMEOUT 15000000
|
||||||
|
|
||||||
|
typedef struct _MetaStartupNotificationSequence MetaStartupNotificationSequence;
|
||||||
|
typedef struct _MetaStartupNotificationSequenceClass MetaStartupNotificationSequenceClass;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_SN_0,
|
||||||
|
PROP_SN_DISPLAY,
|
||||||
|
N_SN_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_SEQ_0,
|
||||||
|
PROP_SEQ_ID,
|
||||||
|
PROP_SEQ_TIMESTAMP,
|
||||||
|
N_SEQ_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SN_CHANGED,
|
||||||
|
N_SN_SIGNALS
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint sn_signals[N_SN_SIGNALS];
|
||||||
|
static GParamSpec *sn_props[N_SN_PROPS];
|
||||||
|
static GParamSpec *seq_props[N_SEQ_PROPS];
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GSList *list;
|
||||||
|
gint64 now;
|
||||||
|
} CollectTimedOutData;
|
||||||
|
|
||||||
|
struct _MetaStartupNotification
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
MetaDisplay *display;
|
||||||
|
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
SnDisplay *sn_display;
|
||||||
|
SnMonitorContext *sn_context;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GSList *startup_sequences;
|
||||||
|
guint startup_sequence_timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE \
|
||||||
|
(meta_startup_notification_sequence_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (MetaStartupNotificationSequence,
|
||||||
|
meta_startup_notification_sequence,
|
||||||
|
META, STARTUP_NOTIFICATION_SEQUENCE,
|
||||||
|
GObject)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gchar *id;
|
||||||
|
time_t timestamp;
|
||||||
|
} MetaStartupNotificationSequencePrivate;
|
||||||
|
|
||||||
|
struct _MetaStartupNotificationSequenceClass {
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
void (* complete) (MetaStartupNotificationSequence *sequence);
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MetaStartupNotification,
|
||||||
|
meta_startup_notification,
|
||||||
|
G_TYPE_OBJECT)
|
||||||
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaStartupNotificationSequence,
|
||||||
|
meta_startup_notification_sequence,
|
||||||
|
G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_SEQ_X11_0,
|
||||||
|
PROP_SEQ_X11_SEQ,
|
||||||
|
N_SEQ_X11_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _MetaStartupNotificationSequenceX11 {
|
||||||
|
MetaStartupNotificationSequence parent_instance;
|
||||||
|
SnStartupSequence *seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *seq_x11_props[N_SEQ_X11_PROPS];
|
||||||
|
|
||||||
|
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11 \
|
||||||
|
(meta_startup_notification_sequence_x11_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaStartupNotificationSequenceX11,
|
||||||
|
meta_startup_notification_sequence_x11,
|
||||||
|
META, STARTUP_NOTIFICATION_SEQUENCE_X11,
|
||||||
|
MetaStartupNotificationSequence)
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MetaStartupNotificationSequenceX11,
|
||||||
|
meta_startup_notification_sequence_x11,
|
||||||
|
META_TYPE_STARTUP_NOTIFICATION_SEQUENCE)
|
||||||
|
|
||||||
|
static void meta_startup_notification_ensure_timeout (MetaStartupNotification *sn);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_update_feedback (MetaStartupNotification *sn)
|
||||||
|
{
|
||||||
|
MetaScreen *screen = sn->display->screen;
|
||||||
|
|
||||||
|
if (sn->startup_sequences != NULL)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_STARTUP,
|
||||||
|
"Setting busy cursor\n");
|
||||||
|
meta_screen_set_cursor (screen, META_CURSOR_BUSY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_STARTUP,
|
||||||
|
"Setting default cursor\n");
|
||||||
|
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_init (MetaStartupNotificationSequence *seq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequence *seq;
|
||||||
|
MetaStartupNotificationSequencePrivate *priv;
|
||||||
|
|
||||||
|
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
|
||||||
|
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||||
|
g_free (priv->id);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_startup_notification_sequence_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequence *seq;
|
||||||
|
MetaStartupNotificationSequencePrivate *priv;
|
||||||
|
|
||||||
|
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
|
||||||
|
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SEQ_ID:
|
||||||
|
priv->id = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_SEQ_TIMESTAMP:
|
||||||
|
priv->timestamp = g_value_get_int64 (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequence *seq;
|
||||||
|
MetaStartupNotificationSequencePrivate *priv;
|
||||||
|
|
||||||
|
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
|
||||||
|
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SEQ_ID:
|
||||||
|
g_value_set_string (value, priv->id);
|
||||||
|
break;
|
||||||
|
case PROP_SEQ_TIMESTAMP:
|
||||||
|
g_value_set_int64 (value, priv->timestamp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_class_init (MetaStartupNotificationSequenceClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class;
|
||||||
|
|
||||||
|
object_class = G_OBJECT_CLASS (klass);
|
||||||
|
object_class->finalize = meta_startup_notification_sequence_finalize;
|
||||||
|
object_class->set_property = meta_startup_notification_sequence_set_property;
|
||||||
|
object_class->get_property = meta_startup_notification_sequence_get_property;
|
||||||
|
|
||||||
|
seq_props[PROP_SEQ_ID] =
|
||||||
|
g_param_spec_string ("id",
|
||||||
|
"ID",
|
||||||
|
"ID",
|
||||||
|
NULL,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
seq_props[PROP_SEQ_TIMESTAMP] =
|
||||||
|
g_param_spec_int64 ("timestamp",
|
||||||
|
"Timestamp",
|
||||||
|
"Timestamp",
|
||||||
|
G_MININT64, G_MAXINT64, 0,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_SEQ_PROPS, seq_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
meta_startup_notification_sequence_get_id (MetaStartupNotificationSequence *seq)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequencePrivate *priv;
|
||||||
|
|
||||||
|
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||||
|
return priv->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
static gint64
|
||||||
|
meta_startup_notification_sequence_get_timestamp (MetaStartupNotificationSequence *seq)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequencePrivate *priv;
|
||||||
|
|
||||||
|
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||||
|
return priv->timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_complete (MetaStartupNotificationSequence *seq)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequenceClass *klass;
|
||||||
|
|
||||||
|
klass = META_STARTUP_NOTIFICATION_SEQUENCE_GET_CLASS (seq);
|
||||||
|
|
||||||
|
if (klass->complete)
|
||||||
|
klass->complete (seq);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_x11_complete (MetaStartupNotificationSequence *seq)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequenceX11 *seq_x11;
|
||||||
|
|
||||||
|
seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (seq);
|
||||||
|
sn_startup_sequence_complete (seq_x11->seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_x11_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequenceX11 *seq;
|
||||||
|
|
||||||
|
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
|
||||||
|
sn_startup_sequence_unref (seq->seq);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_startup_notification_sequence_x11_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_x11_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequenceX11 *seq;
|
||||||
|
|
||||||
|
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SEQ_X11_SEQ:
|
||||||
|
seq->seq = g_value_get_pointer (value);
|
||||||
|
sn_startup_sequence_ref (seq->seq);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_x11_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequenceX11 *seq;
|
||||||
|
|
||||||
|
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SEQ_X11_SEQ:
|
||||||
|
g_value_set_pointer (value, seq->seq);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_x11_init (MetaStartupNotificationSequenceX11 *seq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sequence_x11_class_init (MetaStartupNotificationSequenceX11Class *klass)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequenceClass *seq_class;
|
||||||
|
GObjectClass *object_class;
|
||||||
|
|
||||||
|
seq_class = META_STARTUP_NOTIFICATION_SEQUENCE_CLASS (klass);
|
||||||
|
seq_class->complete = meta_startup_notification_sequence_x11_complete;
|
||||||
|
|
||||||
|
object_class = G_OBJECT_CLASS (klass);
|
||||||
|
object_class->finalize = meta_startup_notification_sequence_x11_finalize;
|
||||||
|
object_class->set_property = meta_startup_notification_sequence_x11_set_property;
|
||||||
|
object_class->get_property = meta_startup_notification_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 MetaStartupNotificationSequence *
|
||||||
|
meta_startup_notification_sequence_x11_new (SnStartupSequence *seq)
|
||||||
|
{
|
||||||
|
return g_object_new (META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11,
|
||||||
|
"id", sn_startup_sequence_get_id (seq),
|
||||||
|
"timestamp", sn_startup_sequence_get_timestamp (seq) * 1000,
|
||||||
|
"seq", seq,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_add_sequence_internal (MetaStartupNotification *sn,
|
||||||
|
MetaStartupNotificationSequence *seq)
|
||||||
|
{
|
||||||
|
sn->startup_sequences = g_slist_prepend (sn->startup_sequences,
|
||||||
|
g_object_ref (seq));
|
||||||
|
|
||||||
|
meta_startup_notification_ensure_timeout (sn);
|
||||||
|
meta_startup_notification_update_feedback (sn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
collect_timed_out_foreach (void *element,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequence *sequence = element;
|
||||||
|
CollectTimedOutData *ctod = data;
|
||||||
|
gint64 elapsed, timestamp;
|
||||||
|
|
||||||
|
timestamp = meta_startup_notification_sequence_get_timestamp (sequence);
|
||||||
|
elapsed = ctod->now - timestamp;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_STARTUP,
|
||||||
|
"Sequence used %ld ms vs. %d max: %s\n",
|
||||||
|
elapsed, STARTUP_TIMEOUT,
|
||||||
|
meta_startup_notification_sequence_get_id (sequence));
|
||||||
|
|
||||||
|
if (elapsed > STARTUP_TIMEOUT)
|
||||||
|
ctod->list = g_slist_prepend (ctod->list, sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
startup_sequence_timeout (void *data)
|
||||||
|
{
|
||||||
|
MetaStartupNotification *sn = data;
|
||||||
|
CollectTimedOutData ctod;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
ctod.list = NULL;
|
||||||
|
ctod.now = g_get_monotonic_time ();
|
||||||
|
g_slist_foreach (sn->startup_sequences,
|
||||||
|
collect_timed_out_foreach,
|
||||||
|
&ctod);
|
||||||
|
|
||||||
|
for (l = ctod.list; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequence *sequence = l->data;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_STARTUP,
|
||||||
|
"Timed out sequence %s\n",
|
||||||
|
meta_startup_notification_sequence_get_id (sequence));
|
||||||
|
|
||||||
|
meta_startup_notification_sequence_complete (sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free (ctod.list);
|
||||||
|
|
||||||
|
if (sn->startup_sequences != NULL)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* remove */
|
||||||
|
sn->startup_sequence_timeout = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_ensure_timeout (MetaStartupNotification *sn)
|
||||||
|
{
|
||||||
|
if (sn->startup_sequence_timeout != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* our timeout just polls every second, instead of bothering
|
||||||
|
* to compute exactly when we may next time out
|
||||||
|
*/
|
||||||
|
sn->startup_sequence_timeout = g_timeout_add_seconds (1,
|
||||||
|
startup_sequence_timeout,
|
||||||
|
sn);
|
||||||
|
g_source_set_name_by_id (sn->startup_sequence_timeout,
|
||||||
|
"[mutter] startup_sequence_timeout");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_remove_sequence_internal (MetaStartupNotification *sn,
|
||||||
|
MetaStartupNotificationSequence *seq)
|
||||||
|
{
|
||||||
|
sn->startup_sequences = g_slist_remove (sn->startup_sequences, seq);
|
||||||
|
meta_startup_notification_update_feedback (sn);
|
||||||
|
|
||||||
|
if (sn->startup_sequences == NULL &&
|
||||||
|
sn->startup_sequence_timeout != 0)
|
||||||
|
{
|
||||||
|
g_source_remove (sn->startup_sequence_timeout);
|
||||||
|
sn->startup_sequence_timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaStartupNotificationSequence *
|
||||||
|
meta_startup_notification_lookup_sequence (MetaStartupNotification *sn,
|
||||||
|
const gchar *id)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequence *seq;
|
||||||
|
const gchar *seq_id;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
for (l = sn->startup_sequences; l; l = l->next)
|
||||||
|
{
|
||||||
|
seq = l->data;
|
||||||
|
seq_id = meta_startup_notification_sequence_get_id (seq);
|
||||||
|
|
||||||
|
if (g_str_equal (seq_id, id))
|
||||||
|
return l->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_init (MetaStartupNotification *sn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||||
|
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
sn_monitor_context_unref (sn->sn_context);
|
||||||
|
sn_display_unref (sn->sn_display);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sn->startup_sequence_timeout)
|
||||||
|
g_source_remove (sn->startup_sequence_timeout);
|
||||||
|
|
||||||
|
g_slist_foreach (sn->startup_sequences, (GFunc) g_object_unref, NULL);
|
||||||
|
g_slist_free (sn->startup_sequences);
|
||||||
|
sn->startup_sequences = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_startup_notification_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SN_DISPLAY:
|
||||||
|
sn->display = g_value_get_object (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SN_DISPLAY:
|
||||||
|
g_value_set_object (value, sn->display);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
static void
|
||||||
|
sn_error_trap_push (SnDisplay *sn_display,
|
||||||
|
Display *xdisplay)
|
||||||
|
{
|
||||||
|
MetaDisplay *display;
|
||||||
|
display = meta_display_for_x_display (xdisplay);
|
||||||
|
if (display != NULL)
|
||||||
|
meta_error_trap_push (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_error_trap_pop (display);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_sn_event (SnMonitorEvent *event,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
MetaStartupNotification *sn = user_data;
|
||||||
|
MetaStartupNotificationSequence *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_notification_sequence_x11_new (sequence);
|
||||||
|
meta_startup_notification_add_sequence_internal (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));
|
||||||
|
|
||||||
|
meta_startup_notification_remove_sequence (sn, sn_startup_sequence_get_id (sequence));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_emit (sn, sn_signals[SN_CHANGED], 0, sequence);
|
||||||
|
|
||||||
|
sn_startup_sequence_unref (sequence);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||||
|
|
||||||
|
g_assert (sn->display != NULL);
|
||||||
|
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
sn->sn_display = sn_display_new (sn->display->xdisplay,
|
||||||
|
sn_error_trap_push,
|
||||||
|
sn_error_trap_pop);
|
||||||
|
sn->sn_context =
|
||||||
|
sn_monitor_context_new (sn->sn_display,
|
||||||
|
sn->display->screen->number,
|
||||||
|
meta_startup_notification_sn_event,
|
||||||
|
sn,
|
||||||
|
NULL);
|
||||||
|
#endif
|
||||||
|
sn->startup_sequences = NULL;
|
||||||
|
sn->startup_sequence_timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_startup_notification_class_init (MetaStartupNotificationClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->constructed = meta_startup_notification_constructed;
|
||||||
|
object_class->finalize = meta_startup_notification_finalize;
|
||||||
|
object_class->set_property = meta_startup_notification_set_property;
|
||||||
|
object_class->get_property = meta_startup_notification_get_property;
|
||||||
|
|
||||||
|
sn_props[PROP_SN_DISPLAY] =
|
||||||
|
g_param_spec_object ("display",
|
||||||
|
"Display",
|
||||||
|
"Display",
|
||||||
|
META_TYPE_DISPLAY,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
sn_signals[SN_CHANGED] =
|
||||||
|
g_signal_new ("changed",
|
||||||
|
META_TYPE_STARTUP_NOTIFICATION,
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0, NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_SN_PROPS, sn_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaStartupNotification *
|
||||||
|
meta_startup_notification_get (MetaDisplay *display)
|
||||||
|
{
|
||||||
|
static MetaStartupNotification *notification = NULL;
|
||||||
|
|
||||||
|
if (!notification)
|
||||||
|
notification = g_object_new (META_TYPE_STARTUP_NOTIFICATION,
|
||||||
|
"display", display,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
|
||||||
|
const gchar *id)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequence *seq;
|
||||||
|
|
||||||
|
seq = meta_startup_notification_lookup_sequence (sn, id);
|
||||||
|
if (seq)
|
||||||
|
meta_startup_notification_remove_sequence_internal (sn, seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_startup_notification_handle_xevent (MetaStartupNotification *sn,
|
||||||
|
XEvent *xevent)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
return sn_display_process_event (sn->sn_display, xevent);
|
||||||
|
#endif
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GSList *
|
||||||
|
meta_startup_notification_get_sequences (MetaStartupNotification *sn)
|
||||||
|
{
|
||||||
|
GSList *sequences = NULL;
|
||||||
|
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
/* We return a list of SnStartupSequences here */
|
||||||
|
for (l = sn->startup_sequences; l; l = l->next)
|
||||||
|
{
|
||||||
|
MetaStartupNotificationSequenceX11 *seq_x11;
|
||||||
|
|
||||||
|
if (!META_IS_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data);
|
||||||
|
sequences = g_slist_prepend (sequences, seq_x11->seq);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return sequences;
|
||||||
|
}
|
@ -1671,13 +1671,12 @@ meta_display_handle_xevent (MetaDisplay *display,
|
|||||||
meta_spew_event_print (display, event);
|
meta_spew_event_print (display, event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
if (meta_startup_notification_handle_xevent (display->startup_notification,
|
||||||
if (sn_display_process_event (display->sn_display, event))
|
event))
|
||||||
{
|
{
|
||||||
bypass_gtk = bypass_compositor = TRUE;
|
bypass_gtk = bypass_compositor = TRUE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
#ifdef HAVE_WAYLAND
|
||||||
if (meta_is_wayland_compositor () &&
|
if (meta_is_wayland_compositor () &&
|
||||||
|
Loading…
Reference in New Issue
Block a user