|
|
|
/* $Id: daemon.c 2337 2007-01-11 19:17:30Z nick $
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Christian Hammond <chipx86@chipx86.com>
|
|
|
|
* Copyright (C) 2005 John (J5) Palmieri <johnp@redhat.com>
|
|
|
|
* Copyright (C) 2006 Nick Schermer <nick@xfce.org>
|
|
|
|
*
|
|
|
|
* 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, 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <tqsignalmapper.h>
|
|
|
|
#include <tqevent.h>
|
|
|
|
#include <tqsize.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <knotifyclient.h>
|
|
|
|
#include <kaboutdata.h>
|
|
|
|
#include <kcmdlineargs.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kglobalsettings.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "daemon.h"
|
|
|
|
|
|
|
|
NotifierContainer* GTKNotifierContainer = NULL;
|
|
|
|
void real_handleGTKMain();
|
|
|
|
|
|
|
|
NotifierContainer::NotifierContainer() : TQWidget() {
|
|
|
|
mPopupList.clear();
|
|
|
|
|
|
|
|
// Determine bottom of desktop
|
|
|
|
TQPoint cursorPos = TQCursor::pos();
|
|
|
|
TQRect r = KGlobalSettings::desktopGeometry(cursorPos);
|
|
|
|
mTopOfStack = r.height();
|
|
|
|
mRightOfStack = r.width();
|
|
|
|
}
|
|
|
|
|
|
|
|
NotifierContainer::~NotifierContainer() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifierContainer::handleGTKMain() {
|
|
|
|
real_handleGTKMain();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifierContainer::displayMessage(TQString title, TQString message, TQString icon, int x, int y) {
|
|
|
|
TQPixmap px;
|
|
|
|
KIconLoader* il = KGlobal::iconLoader();
|
|
|
|
px = il->loadIcon( icon, KIcon::NoGroup );
|
|
|
|
// if (px.isNull()) {
|
|
|
|
// px = il->loadIcon( "gnome_apps", KIcon::NoGroup );
|
|
|
|
// }
|
|
|
|
|
|
|
|
KPassivePopup *pop = new KPassivePopup( KPassivePopup::Boxed, this, "" );
|
|
|
|
pop->setAutoDelete( true );
|
|
|
|
pop->setView( title, message, icon );
|
|
|
|
pop->setTimeout( -1 );
|
|
|
|
TQPoint leftCorner( x, y);
|
|
|
|
if (leftCorner.isNull()) {
|
|
|
|
if (mPopupList.isEmpty()) {
|
|
|
|
// Determine bottom of desktop
|
|
|
|
TQPoint cursorPos = TQCursor::pos();
|
|
|
|
TQRect r = KGlobalSettings::desktopGeometry(cursorPos);
|
|
|
|
mTopOfStack = r.height();
|
|
|
|
mRightOfStack = r.width();
|
|
|
|
}
|
|
|
|
TQSize popupSize = pop->tqsizeHint();
|
|
|
|
mTopOfStack = mTopOfStack-popupSize.height();
|
|
|
|
if (mTopOfStack < 0) mTopOfStack = 0;
|
|
|
|
leftCorner.setX(mRightOfStack-popupSize.width());
|
|
|
|
leftCorner.setY(mTopOfStack);
|
|
|
|
}
|
|
|
|
connect(pop, SIGNAL(hidden(KPassivePopup*)), this, SLOT(popupClosed(KPassivePopup*)));
|
|
|
|
mPopupList.append(pop);
|
|
|
|
pop->show(leftCorner);
|
|
|
|
|
|
|
|
processEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifierContainer::processEvents() {
|
|
|
|
tqApp->processEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifierContainer::popupClosed(KPassivePopup* popup) {
|
|
|
|
// Remove the popup from our list of popups
|
|
|
|
mPopupList.remove(popup);
|
|
|
|
|
|
|
|
if (mPopupList.isEmpty()) {
|
|
|
|
// Determine bottom of desktop
|
|
|
|
TQPoint cursorPos = TQCursor::pos();
|
|
|
|
TQRect r = KGlobalSettings::desktopGeometry(cursorPos);
|
|
|
|
mTopOfStack = r.height();
|
|
|
|
mRightOfStack = r.width();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef signals
|
|
|
|
|
|
|
|
#include <dbus/dbus.h>
|
|
|
|
#include <dbus/dbus-glib.h>
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
#include <glib-object.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
#include <gdk/gdkx.h>
|
|
|
|
|
|
|
|
#include "notificationdaemon-dbus-glue.h"
|
|
|
|
|
|
|
|
#define IMAGE_SIZE 48
|
|
|
|
|
|
|
|
#define NW_GET_NOTIFY_ID(nw) \
|
|
|
|
(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(nw), "_notify_id")))
|
|
|
|
#define NW_GET_NOTIFY_SENDER(nw) \
|
|
|
|
(g_object_get_data(G_OBJECT(nw), "_notify_sender"))
|
|
|
|
#define NW_GET_DAEMON(nw) \
|
|
|
|
(g_object_get_data(G_OBJECT(nw), "_notify_daemon"))
|
|
|
|
|
|
|
|
static const char *description =
|
|
|
|
I18N_NOOP("A DBUS notification to TDE interface.");
|
|
|
|
static const char *message =
|
|
|
|
I18N_NOOP("First release October 2011.");
|
|
|
|
static const char *version = "0.01";
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GTimeVal expiration;
|
|
|
|
GTimeVal paused_diff;
|
|
|
|
gboolean has_timeout;
|
|
|
|
gboolean paused;
|
|
|
|
guint id;
|
|
|
|
GtkWindow *nw;
|
|
|
|
|
|
|
|
} NotifyTimeout;
|
|
|
|
|
|
|
|
static DBusConnection *dbus_conn = NULL;
|
|
|
|
|
|
|
|
#define CHECK_DBUS_VERSION(major, minor) \
|
|
|
|
(DBUS_MAJOR_VER > (major) || \
|
|
|
|
(DBUS_MAJOR_VER == (major) && DBUS_MINOR_VER >= (minor)))
|
|
|
|
|
|
|
|
#if !CHECK_DBUS_VERSION(0, 60)
|
|
|
|
/* This is a hack that will go away in time. For now, it's fairly safe. */
|
|
|
|
struct _DBusGMethodInvocation
|
|
|
|
{
|
|
|
|
DBusGConnection *connection;
|
|
|
|
DBusGMessage *message;
|
|
|
|
const DBusGObjectInfo *object;
|
|
|
|
const DBusGMethodInfo *method;
|
|
|
|
};
|
|
|
|
#endif /* D-BUS < 0.60 */
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(NotifyDaemon, notify_daemon, G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
static void
|
|
|
|
notify_daemon_finalize(GObject *object)
|
|
|
|
{
|
|
|
|
NotifyDaemon *daemon = NOTIFY_DAEMON(object);
|
|
|
|
GObjectClass *parent_class = G_OBJECT_CLASS(notify_daemon_parent_class);
|
|
|
|
|
|
|
|
if (parent_class->finalize != NULL)
|
|
|
|
parent_class->finalize(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
notify_daemon_class_init(NotifyDaemonClass *daemon_class)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS(daemon_class);
|
|
|
|
|
|
|
|
object_class->finalize = notify_daemon_finalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
notify_daemon_init(NotifyDaemon *daemon)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
notify_daemon_notify_handler(NotifyDaemon *daemon,
|
|
|
|
const gchar *app_name,
|
|
|
|
guint id,
|
|
|
|
const gchar *icon,
|
|
|
|
const gchar *summary,
|
|
|
|
const gchar *body,
|
|
|
|
gchar **actions,
|
|
|
|
GHashTable *hints,
|
|
|
|
int timeout, DBusGMethodInvocation *context)
|
|
|
|
{
|
|
|
|
NotifyDaemonPrivate *priv = daemon->priv;
|
|
|
|
NotifyTimeout *nt = NULL;
|
|
|
|
GtkWindow *nw = NULL;
|
|
|
|
GValue *data;
|
|
|
|
gboolean use_pos_data = FALSE;
|
|
|
|
gboolean new_notification = FALSE;
|
|
|
|
gint x = 0;
|
|
|
|
gint y = 0;
|
|
|
|
guint return_id;
|
|
|
|
gchar *sender;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
/* deal with x, and y hints */
|
|
|
|
if ((data = (GValue *)g_hash_table_lookup(hints, "x")) != NULL)
|
|
|
|
{
|
|
|
|
x = g_value_get_int(data);
|
|
|
|
|
|
|
|
if ((data = (GValue *)g_hash_table_lookup(hints, "y")) != NULL)
|
|
|
|
{
|
|
|
|
y = g_value_get_int(data);
|
|
|
|
use_pos_data = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send a notification request to KDE here...
|
|
|
|
TQString messageText = TQString(body);
|
|
|
|
|
|
|
|
GTKNotifierContainer->displayMessage(TQString(summary), TQString(body), TQString(icon), x, y);
|
|
|
|
|
|
|
|
return_id = 0;
|
|
|
|
|
|
|
|
dbus_g_method_return(context, return_id);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
notify_daemon_close_notification_handler(NotifyDaemon *daemon,
|
|
|
|
guint id, GError **error)
|
|
|
|
{
|
|
|
|
// Do nothing
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
notify_daemon_get_capabilities(NotifyDaemon *daemon, char ***caps)
|
|
|
|
{
|
|
|
|
*caps = g_new0(char *, 6);
|
|
|
|
|
|
|
|
(*caps)[0] = g_strdup("actions");
|
|
|
|
(*caps)[1] = g_strdup("body");
|
|
|
|
(*caps)[2] = g_strdup("body-hyperlinks");
|
|
|
|
(*caps)[3] = g_strdup("body-markup");
|
|
|
|
(*caps)[4] = g_strdup("icon-static");
|
|
|
|
(*caps)[5] = NULL;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
notify_daemon_reload_settings (NotifyDaemon *daemon)
|
|
|
|
{
|
|
|
|
// Do nothing
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
notify_daemon_get_server_information(NotifyDaemon *daemon,
|
|
|
|
char **out_name,
|
|
|
|
char **out_vendor,
|
|
|
|
char **out_version,
|
|
|
|
char **out_spec_ver)
|
|
|
|
{
|
|
|
|
*out_name = g_strdup("Notification Daemon");
|
|
|
|
*out_vendor = g_strdup("Trinity Desktop Project");
|
|
|
|
*out_version = g_strdup(VERSION);
|
|
|
|
*out_spec_ver = g_strdup("0.1");
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
NotifyDaemon *daemon;
|
|
|
|
DBusGConnection *connection;
|
|
|
|
DBusGProxy *bus_proxy;
|
|
|
|
GError *error;
|
|
|
|
guint request_name_result;
|
|
|
|
|
|
|
|
g_set_application_name ("notification-daemon-tde");
|
|
|
|
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
|
|
g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
error = NULL;
|
|
|
|
|
|
|
|
connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
|
|
|
|
|
|
|
|
if (connection == NULL)
|
|
|
|
{
|
|
|
|
g_printerr("Failed to open connection to bus: %s\n",
|
|
|
|
error->message);
|
|
|
|
g_error_free(error);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
dbus_conn = dbus_g_connection_get_connection(connection);
|
|
|
|
|
|
|
|
dbus_g_object_type_install_info(NOTIFY_TYPE_DAEMON,
|
|
|
|
&dbus_glib_notification_daemon_tde_object_info);
|
|
|
|
|
|
|
|
bus_proxy = dbus_g_proxy_new_for_name(connection,
|
|
|
|
"org.freedesktop.DBus",
|
|
|
|
"/org/freedesktop/DBus",
|
|
|
|
"org.freedesktop.DBus");
|
|
|
|
|
|
|
|
if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error,
|
|
|
|
G_TYPE_STRING, "org.freedesktop.Notifications",
|
|
|
|
G_TYPE_UINT, 0,
|
|
|
|
G_TYPE_INVALID,
|
|
|
|
G_TYPE_UINT, &request_name_result,
|
|
|
|
G_TYPE_INVALID))
|
|
|
|
{
|
|
|
|
g_error("Could not aquire name: %s", error->message);
|
|
|
|
}
|
|
|
|
|
|
|
|
daemon = static_cast<NotifyDaemon*>(g_object_new(NOTIFY_TYPE_DAEMON, NULL));
|
|
|
|
|
|
|
|
dbus_g_connection_register_g_object(connection,
|
|
|
|
"/org/freedesktop/Notifications",
|
|
|
|
G_OBJECT(daemon));
|
|
|
|
|
|
|
|
KAboutData aboutData("notification-daemon-tde", I18N_NOOP("TDE DBUS Notification Daemon"), version,
|
|
|
|
description, KAboutData::License_GPL,
|
|
|
|
"(c) 2011, Timothy Pearson",
|
|
|
|
message, 0 /* TODO: Website */, "kb9vqf@pearsoncomputing.net");
|
|
|
|
|
|
|
|
KCmdLineArgs::init(argc, argv, &aboutData);
|
|
|
|
|
|
|
|
KApplication app;
|
|
|
|
NotifierContainer nc;
|
|
|
|
app.setMainWidget(&nc);
|
|
|
|
GTKNotifierContainer = &nc;
|
|
|
|
TQTimer *gtkEventProcessor = new TQTimer( &app );
|
|
|
|
TQObject::connect( gtkEventProcessor, SIGNAL(timeout()), &nc, SLOT(handleGTKMain()) );
|
|
|
|
gtkEventProcessor->start( 100, FALSE ); // Every 0.1 seconds poll gtk for DBUS events
|
|
|
|
app.disableSessionManagement();
|
|
|
|
app.exec();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void real_handleGTKMain() {
|
|
|
|
while (gtk_events_pending())
|
|
|
|
gtk_main_iteration();
|
|
|
|
}
|