messageTray: show the summary with new notifications when the user becomes active
If the user was inactive while a notification was shown, we show the summary when the user becomes active again. This ensures that we inform the user of the existance of new notifications that the user might have missed. When the user comes back from away, the summary is now only shown if it has new notifications. https://bugzilla.gnome.org/show_bug.cgi?id=643014
This commit is contained in:
parent
ecdd0875df
commit
30ca25e978
@ -1344,9 +1344,7 @@ const MessageTray = new Lang.Class({
|
||||
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
|
||||
this._onStatusChanged(proxy.status);
|
||||
}));
|
||||
this._userStatus = GnomeSession.PresenceStatus.AVAILABLE;
|
||||
this._busy = false;
|
||||
this._backFromAway = false;
|
||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
||||
this._onStatusChanged(status);
|
||||
}));
|
||||
@ -1392,6 +1390,12 @@ const MessageTray = new Lang.Class({
|
||||
this._summaryItemTitleWidth = 0;
|
||||
this._pointerBarrier = 0;
|
||||
|
||||
this._unseenNotifications = [];
|
||||
this._idleMonitorWatchId = 0;
|
||||
this._backFromAway = false;
|
||||
|
||||
this.idleMonitor = new Shell.IdleMonitor();
|
||||
|
||||
// To simplify the summary item animation code, we pretend
|
||||
// that there's an invisible SummaryItem to the left of the
|
||||
// leftmost real summary item, and that it's expanded when all
|
||||
@ -1635,6 +1639,10 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_onNotificationDestroy: function(notification) {
|
||||
let unseenNotificationsIndex = this._unseenNotifications.indexOf(notification);
|
||||
if (unseenNotificationsIndex != -1)
|
||||
this._unseenNotifications.splice(unseenNotificationsIndex, 1);
|
||||
|
||||
if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) {
|
||||
this._updateNotificationTimeout(0);
|
||||
this._notificationRemoved = true;
|
||||
@ -1918,16 +1926,10 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_onStatusChanged: function(status) {
|
||||
this._backFromAway = (this._userStatus == GnomeSession.PresenceStatus.IDLE && this._userStatus != status);
|
||||
this._userStatus = status;
|
||||
|
||||
if (status == GnomeSession.PresenceStatus.BUSY) {
|
||||
// remove notification and allow the summary to be closed now
|
||||
this._updateNotificationTimeout(0);
|
||||
if (this._summaryTimeoutId) {
|
||||
Mainloop.source_remove(this._summaryTimeoutId);
|
||||
this._summaryTimeoutId = 0;
|
||||
}
|
||||
this._unsetSummaryTimeout();
|
||||
this._busy = true;
|
||||
} else if (status != GnomeSession.PresenceStatus.IDLE) {
|
||||
// We preserve the previous value of this._busy if the status turns to IDLE
|
||||
@ -1957,6 +1959,7 @@ const MessageTray = new Lang.Class({
|
||||
this._pointerInTray = false;
|
||||
this._pointerInSummary = false;
|
||||
this._updateNotificationTimeout(0);
|
||||
this._unsetSummaryTimeout();
|
||||
this._updateState();
|
||||
}
|
||||
return false;
|
||||
@ -1967,6 +1970,7 @@ const MessageTray = new Lang.Class({
|
||||
this._pointerInTray = false;
|
||||
this._pointerInSummary = false;
|
||||
this._updateNotificationTimeout(0);
|
||||
this._unsetSummaryTimeout();
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
@ -2012,15 +2016,13 @@ const MessageTray = new Lang.Class({
|
||||
|| notificationsVisible;
|
||||
|
||||
if (this._summaryState == State.HIDDEN && !mustHideSummary) {
|
||||
if (this._backFromAway) {
|
||||
// Immediately set this to false, so that we don't schedule a timeout later
|
||||
this._backFromAway = false;
|
||||
if (!this._busy)
|
||||
this._showSummary(LONGER_SUMMARY_TIMEOUT);
|
||||
} else if (notificationsDone && this._newSummaryItems.length > 0 && !this._busy) {
|
||||
this._showSummary(SUMMARY_TIMEOUT);
|
||||
} else if (summarySummoned) {
|
||||
if (summarySummoned) {
|
||||
this._showSummary(0);
|
||||
} else if (notificationsDone && !this._busy) {
|
||||
if (this._backFromAway && this._unseenNotifications.length > 0)
|
||||
this._showSummary(LONGER_SUMMARY_TIMEOUT);
|
||||
else if (this._newSummaryItems.length > 0)
|
||||
this._showSummary(SUMMARY_TIMEOUT);
|
||||
}
|
||||
} else if (this._summaryState == State.SHOWN) {
|
||||
if (!summaryPinned || mustHideSummary)
|
||||
@ -2109,8 +2111,32 @@ const MessageTray = new Lang.Class({
|
||||
});
|
||||
},
|
||||
|
||||
_onIdleMonitorWatch: function(monitor, id, userBecameIdle) {
|
||||
this.idleMonitor.remove_watch(this._idleMonitorWatchId);
|
||||
this._idleMonitorWatchId = 0;
|
||||
|
||||
if (userBecameIdle) {
|
||||
// The user became idle, which means the user was active while the notifications were
|
||||
// shown and we can unset this._unseenNotifications .
|
||||
this._unseenNotiications = [];
|
||||
} else if (this._unseenNotifications.length == 1 && this._unseenNotifications[0] == this._notification) {
|
||||
// The user became active while the only notification in this._unseenNotifications is being shown
|
||||
// as this._notification , so we can unset this._unseenNotifications .
|
||||
this._unseenNotifications = [];
|
||||
} else {
|
||||
// The user became active and we have one or more unseen notifications. We should show
|
||||
// the message tray to the user to inform the user about the missed notifications.
|
||||
this._backFromAway = true;
|
||||
this._updateState();
|
||||
}
|
||||
},
|
||||
|
||||
_showNotification: function() {
|
||||
this._notification = this._notificationQueue.shift();
|
||||
this._unseenNotifications.push(this._notification);
|
||||
if (this._idleMonitorWatchId == 0)
|
||||
this._idleMonitorWatchId = this.idleMonitor.add_watch(1000,
|
||||
Lang.bind(this, this._onIdleMonitorWatch));
|
||||
this._notificationClickedId = this._notification.connect('done-displaying',
|
||||
Lang.bind(this, this._escapeTray));
|
||||
this._notificationBin.child = this._notification.actor;
|
||||
@ -2189,6 +2215,13 @@ const MessageTray = new Lang.Class({
|
||||
Lang.bind(this, this._notificationTimeout));
|
||||
},
|
||||
|
||||
_unsetSummaryTimeout: function(timeout) {
|
||||
if (this._summaryTimeoutId) {
|
||||
Mainloop.source_remove(this._summaryTimeoutId);
|
||||
this._summaryTimeoutId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_notificationTimeout: function() {
|
||||
let [x, y, mods] = global.get_pointer();
|
||||
if (y > this._lastSeenMouseY + 10 && !this.actor.hover) {
|
||||
@ -2272,6 +2305,7 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_showSummary: function(timeout) {
|
||||
this._updateSeenSummaryItems();
|
||||
this._summaryBin.opacity = 0;
|
||||
this._summaryBin.y = this.actor.height;
|
||||
this._tween(this._summaryBin, '_summaryState', State.SHOWN,
|
||||
@ -2286,8 +2320,6 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_showSummaryCompleted: function(timeout) {
|
||||
this._newSummaryItems = [];
|
||||
|
||||
if (timeout != 0) {
|
||||
this._summaryTimeoutId =
|
||||
Mainloop.timeout_add(timeout * 1000,
|
||||
@ -2302,6 +2334,7 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_hideSummary: function() {
|
||||
this._updateSeenSummaryItems();
|
||||
this._tween(this._summaryBin, '_summaryState', State.HIDDEN,
|
||||
{ opacity: 0,
|
||||
time: ANIMATION_TIME,
|
||||
@ -2309,13 +2342,20 @@ const MessageTray = new Lang.Class({
|
||||
onComplete: this._hideSummaryCompleted,
|
||||
onCompleteScope: this,
|
||||
});
|
||||
this._newSummaryItems = [];
|
||||
},
|
||||
|
||||
_hideSummaryCompleted: function() {
|
||||
this._setExpandedSummaryItem(null);
|
||||
},
|
||||
|
||||
_updateSeenSummaryItems: function() {
|
||||
if (this._backFromAway) {
|
||||
this._backFromAway = false;
|
||||
this._unseenNotifications = [];
|
||||
}
|
||||
this._newSummaryItems = [];
|
||||
},
|
||||
|
||||
_showSummaryBoxPointer: function() {
|
||||
this._summaryBoxPointerItem = this._clickedSummaryItem;
|
||||
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
|
||||
|
@ -109,6 +109,7 @@ shell_public_headers_h = \
|
||||
shell-generic-container.h \
|
||||
shell-gtk-embed.h \
|
||||
shell-global.h \
|
||||
shell-idle-monitor.h \
|
||||
shell-mobile-providers.h \
|
||||
shell-mount-operation.h \
|
||||
shell-network-agent.h \
|
||||
@ -155,6 +156,7 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-generic-container.c \
|
||||
shell-gtk-embed.c \
|
||||
shell-global.c \
|
||||
shell-idle-monitor.c \
|
||||
shell-keyring-prompt.h \
|
||||
shell-keyring-prompt.c \
|
||||
shell-mobile-providers.c \
|
||||
|
412
src/shell-idle-monitor.c
Normal file
412
src/shell-idle-monitor.c
Normal file
@ -0,0 +1,412 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c
|
||||
*
|
||||
* Copyright (C) 2012 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors: William Jon McCann <mccann@jhu.edu>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "shell-idle-monitor.h"
|
||||
|
||||
#define SHELL_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitorPrivate))
|
||||
|
||||
struct ShellIdleMonitorPrivate
|
||||
{
|
||||
Display *display;
|
||||
|
||||
GHashTable *watches;
|
||||
int sync_event_base;
|
||||
XSyncCounter counter;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Display *display;
|
||||
guint id;
|
||||
XSyncValue interval;
|
||||
ShellIdleMonitorWatchFunc callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify notify;
|
||||
XSyncAlarm xalarm_positive;
|
||||
XSyncAlarm xalarm_negative;
|
||||
} ShellIdleMonitorWatch;
|
||||
|
||||
static guint32 watch_serial = 1;
|
||||
|
||||
G_DEFINE_TYPE (ShellIdleMonitor, shell_idle_monitor, G_TYPE_OBJECT)
|
||||
|
||||
static gint64
|
||||
_xsyncvalue_to_int64 (XSyncValue value)
|
||||
{
|
||||
return ((guint64) XSyncValueHigh32 (value)) << 32
|
||||
| (guint64) XSyncValueLow32 (value);
|
||||
}
|
||||
|
||||
static XSyncValue
|
||||
_int64_to_xsyncvalue (gint64 value)
|
||||
{
|
||||
XSyncValue ret;
|
||||
|
||||
XSyncIntsToValue (&ret, value, ((guint64)value) >> 32);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_idle_monitor_dispose (GObject *object)
|
||||
{
|
||||
ShellIdleMonitor *monitor;
|
||||
|
||||
monitor = SHELL_IDLE_MONITOR (object);
|
||||
|
||||
if (monitor->priv->watches != NULL) {
|
||||
g_hash_table_destroy (monitor->priv->watches);
|
||||
monitor->priv->watches = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (shell_idle_monitor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_find_alarm (gpointer key,
|
||||
ShellIdleMonitorWatch *watch,
|
||||
XSyncAlarm *alarm)
|
||||
{
|
||||
/* g_debug ("Searching for %d in %d,%d", (int)*alarm, (int)watch->xalarm_positive, (int)watch->xalarm_negative); */
|
||||
if (watch->xalarm_positive == *alarm
|
||||
|| watch->xalarm_negative == *alarm) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static ShellIdleMonitorWatch *
|
||||
find_watch_for_alarm (ShellIdleMonitor *monitor,
|
||||
XSyncAlarm alarm)
|
||||
{
|
||||
ShellIdleMonitorWatch *watch;
|
||||
|
||||
watch = g_hash_table_find (monitor->priv->watches,
|
||||
(GHRFunc)_find_alarm,
|
||||
&alarm);
|
||||
return watch;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_alarm_notify_event (ShellIdleMonitor *monitor,
|
||||
XSyncAlarmNotifyEvent *alarm_event)
|
||||
{
|
||||
ShellIdleMonitorWatch *watch;
|
||||
gboolean condition;
|
||||
|
||||
if (alarm_event->state == XSyncAlarmDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
watch = find_watch_for_alarm (monitor, alarm_event->alarm);
|
||||
|
||||
if (watch == NULL) {
|
||||
/* g_debug ("Unable to find watch for alarm %d", (int)alarm_event->alarm); */
|
||||
return;
|
||||
}
|
||||
|
||||
/* g_debug ("Watch %d fired, idle time = %" G_GINT64_FORMAT,
|
||||
watch->id,
|
||||
_xsyncvalue_to_int64 (alarm_event->counter_value)); */
|
||||
|
||||
if (alarm_event->alarm == watch->xalarm_positive) {
|
||||
condition = TRUE;
|
||||
} else {
|
||||
condition = FALSE;
|
||||
}
|
||||
|
||||
if (watch->callback != NULL) {
|
||||
watch->callback (monitor,
|
||||
watch->id,
|
||||
condition,
|
||||
watch->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static GdkFilterReturn
|
||||
xevent_filter (GdkXEvent *xevent,
|
||||
GdkEvent *event,
|
||||
ShellIdleMonitor *monitor)
|
||||
{
|
||||
XEvent *ev;
|
||||
XSyncAlarmNotifyEvent *alarm_event;
|
||||
|
||||
ev = xevent;
|
||||
if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) {
|
||||
return GDK_FILTER_CONTINUE;
|
||||
}
|
||||
|
||||
alarm_event = xevent;
|
||||
|
||||
handle_alarm_notify_event (monitor, alarm_event);
|
||||
|
||||
return GDK_FILTER_CONTINUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
init_xsync (ShellIdleMonitor *monitor)
|
||||
{
|
||||
int sync_error_base;
|
||||
int res;
|
||||
int major;
|
||||
int minor;
|
||||
int i;
|
||||
int ncounters;
|
||||
XSyncSystemCounter *counters;
|
||||
|
||||
res = XSyncQueryExtension (monitor->priv->display,
|
||||
&monitor->priv->sync_event_base,
|
||||
&sync_error_base);
|
||||
if (! res) {
|
||||
g_warning ("ShellIdleMonitor: Sync extension not present");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
res = XSyncInitialize (monitor->priv->display, &major, &minor);
|
||||
if (! res) {
|
||||
g_warning ("ShellIdleMonitor: Unable to initialize Sync extension");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
counters = XSyncListSystemCounters (monitor->priv->display, &ncounters);
|
||||
for (i = 0; i < ncounters; i++) {
|
||||
if (counters[i].name != NULL
|
||||
&& strcmp (counters[i].name, "IDLETIME") == 0) {
|
||||
monitor->priv->counter = counters[i].counter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XSyncFreeSystemCounterList (counters);
|
||||
|
||||
if (monitor->priv->counter == None) {
|
||||
g_warning ("ShellIdleMonitor: IDLETIME counter not found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GObject *
|
||||
shell_idle_monitor_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties)
|
||||
{
|
||||
ShellIdleMonitor *monitor;
|
||||
|
||||
monitor = SHELL_IDLE_MONITOR (G_OBJECT_CLASS (shell_idle_monitor_parent_class)->constructor (type,
|
||||
n_construct_properties,
|
||||
construct_properties));
|
||||
|
||||
monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
|
||||
if (! init_xsync (monitor)) {
|
||||
g_object_unref (monitor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return G_OBJECT (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_idle_monitor_class_init (ShellIdleMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = shell_idle_monitor_dispose;
|
||||
object_class->constructor = shell_idle_monitor_constructor;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ShellIdleMonitorPrivate));
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_next_watch_serial (void)
|
||||
{
|
||||
guint32 serial;
|
||||
|
||||
serial = watch_serial++;
|
||||
|
||||
if ((gint32)watch_serial < 0) {
|
||||
watch_serial = 1;
|
||||
}
|
||||
|
||||
/* FIXME: make sure it isn't in the hash */
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
static ShellIdleMonitorWatch *
|
||||
idle_monitor_watch_new (guint interval)
|
||||
{
|
||||
ShellIdleMonitorWatch *watch;
|
||||
|
||||
watch = g_slice_new0 (ShellIdleMonitorWatch);
|
||||
watch->interval = _int64_to_xsyncvalue ((gint64)interval);
|
||||
watch->id = get_next_watch_serial ();
|
||||
watch->xalarm_positive = None;
|
||||
watch->xalarm_negative = None;
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static void
|
||||
idle_monitor_watch_free (ShellIdleMonitorWatch *watch)
|
||||
{
|
||||
if (watch == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (watch->notify != NULL) {
|
||||
watch->notify (watch->user_data);
|
||||
}
|
||||
|
||||
if (watch->xalarm_positive != None) {
|
||||
XSyncDestroyAlarm (watch->display, watch->xalarm_positive);
|
||||
}
|
||||
if (watch->xalarm_negative != None) {
|
||||
XSyncDestroyAlarm (watch->display, watch->xalarm_negative);
|
||||
}
|
||||
g_slice_free (ShellIdleMonitorWatch, watch);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_idle_monitor_init (ShellIdleMonitor *monitor)
|
||||
{
|
||||
monitor->priv = SHELL_IDLE_MONITOR_GET_PRIVATE (monitor);
|
||||
|
||||
monitor->priv->watches = g_hash_table_new_full (NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(GDestroyNotify)idle_monitor_watch_free);
|
||||
|
||||
monitor->priv->counter = None;
|
||||
}
|
||||
|
||||
ShellIdleMonitor *
|
||||
shell_idle_monitor_new (void)
|
||||
{
|
||||
GObject *idle_monitor;
|
||||
|
||||
idle_monitor = g_object_new (SHELL_TYPE_IDLE_MONITOR,
|
||||
NULL);
|
||||
|
||||
return SHELL_IDLE_MONITOR (idle_monitor);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_xsync_alarm_set (ShellIdleMonitor *monitor,
|
||||
ShellIdleMonitorWatch *watch)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
XSyncValue delta;
|
||||
guint flags;
|
||||
|
||||
flags = XSyncCACounter
|
||||
| XSyncCAValueType
|
||||
| XSyncCATestType
|
||||
| XSyncCAValue
|
||||
| XSyncCADelta
|
||||
| XSyncCAEvents;
|
||||
|
||||
XSyncIntToValue (&delta, 0);
|
||||
attr.trigger.counter = monitor->priv->counter;
|
||||
attr.trigger.value_type = XSyncAbsolute;
|
||||
attr.trigger.wait_value = watch->interval;
|
||||
attr.delta = delta;
|
||||
attr.events = TRUE;
|
||||
|
||||
attr.trigger.test_type = XSyncPositiveTransition;
|
||||
if (watch->xalarm_positive != None) {
|
||||
/* g_debug ("ShellIdleMonitor: updating alarm for positive transition wait=%" G_GINT64_FORMAT,
|
||||
_xsyncvalue_to_int64 (attr.trigger.wait_value)); */
|
||||
XSyncChangeAlarm (monitor->priv->display, watch->xalarm_positive, flags, &attr);
|
||||
} else {
|
||||
/* g_debug ("ShellIdleMonitor: creating new alarm for positive transition wait=%" G_GINT64_FORMAT,
|
||||
_xsyncvalue_to_int64 (attr.trigger.wait_value)); */
|
||||
watch->xalarm_positive = XSyncCreateAlarm (monitor->priv->display, flags, &attr);
|
||||
}
|
||||
|
||||
attr.trigger.wait_value = _int64_to_xsyncvalue (_xsyncvalue_to_int64 (watch->interval) - 1);
|
||||
attr.trigger.test_type = XSyncNegativeTransition;
|
||||
if (watch->xalarm_negative != None) {
|
||||
/* g_debug ("ShellIdleMonitor: updating alarm for negative transition wait=%" G_GINT64_FORMAT,
|
||||
_xsyncvalue_to_int64 (attr.trigger.wait_value)); */
|
||||
XSyncChangeAlarm (monitor->priv->display, watch->xalarm_negative, flags, &attr);
|
||||
} else {
|
||||
/* g_debug ("ShellIdleMonitor: creating new alarm for negative transition wait=%" G_GINT64_FORMAT,
|
||||
_xsyncvalue_to_int64 (attr.trigger.wait_value)); */
|
||||
watch->xalarm_negative = XSyncCreateAlarm (monitor->priv->display, flags, &attr);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
guint
|
||||
shell_idle_monitor_add_watch (ShellIdleMonitor *monitor,
|
||||
guint interval,
|
||||
ShellIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
ShellIdleMonitorWatch *watch;
|
||||
|
||||
g_return_val_if_fail (SHELL_IS_IDLE_MONITOR (monitor), 0);
|
||||
g_return_val_if_fail (callback != NULL, 0);
|
||||
|
||||
watch = idle_monitor_watch_new (interval);
|
||||
watch->display = monitor->priv->display;
|
||||
watch->callback = callback;
|
||||
watch->user_data = user_data;
|
||||
watch->notify = notify;
|
||||
|
||||
_xsync_alarm_set (monitor, watch);
|
||||
|
||||
g_hash_table_insert (monitor->priv->watches,
|
||||
GUINT_TO_POINTER (watch->id),
|
||||
watch);
|
||||
return watch->id;
|
||||
}
|
||||
|
||||
void
|
||||
shell_idle_monitor_remove_watch (ShellIdleMonitor *monitor,
|
||||
guint id)
|
||||
{
|
||||
g_return_if_fail (SHELL_IS_IDLE_MONITOR (monitor));
|
||||
|
||||
g_hash_table_remove (monitor->priv->watches,
|
||||
GUINT_TO_POINTER (id));
|
||||
}
|
72
src/shell-idle-monitor.h
Normal file
72
src/shell-idle-monitor.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.h
|
||||
*
|
||||
* Copyright (C) 2012 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors: William Jon McCann <mccann@jhu.edu>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_IDLE_MONITOR_H
|
||||
#define __SHELL_IDLE_MONITOR_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SHELL_TYPE_IDLE_MONITOR (shell_idle_monitor_get_type ())
|
||||
#define SHELL_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitor))
|
||||
#define SHELL_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitorClass))
|
||||
#define SHELL_IS_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SHELL_TYPE_IDLE_MONITOR))
|
||||
#define SHELL_IS_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SHELL_TYPE_IDLE_MONITOR))
|
||||
#define SHELL_IDLE_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitorClass))
|
||||
|
||||
typedef struct ShellIdleMonitorPrivate ShellIdleMonitorPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GObject parent;
|
||||
ShellIdleMonitorPrivate *priv;
|
||||
} ShellIdleMonitor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
} ShellIdleMonitorClass;
|
||||
|
||||
typedef void (*ShellIdleMonitorWatchFunc) (ShellIdleMonitor *monitor,
|
||||
guint id,
|
||||
gboolean condition,
|
||||
gpointer user_data);
|
||||
|
||||
GType shell_idle_monitor_get_type (void);
|
||||
|
||||
ShellIdleMonitor * shell_idle_monitor_new (void);
|
||||
|
||||
guint shell_idle_monitor_add_watch (ShellIdleMonitor *monitor,
|
||||
guint interval,
|
||||
ShellIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
void shell_idle_monitor_remove_watch (ShellIdleMonitor *monitor,
|
||||
guint id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_IDLE_MONITOR_H */
|
Loading…
Reference in New Issue
Block a user