Logo Search packages:      
Sourcecode: guifications version File versions  Download package

gf_notification.c

/*
 * Guifications - The end all, be all, toaster popup plugin
 * Copyright (C) 2003-2004 Gary Kramlich
 *
 * 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.
 */
#include <stdlib.h>
#include <time.h>
#include <glib.h>
#include <gdk/gdk.h>

#include <debug.h>
#include <xmlnode.h>

#include "gf_event_info.h"
#include "gf_gtk_utils.h"
#include "gf_item.h"
#include "gf_notification.h"
#include "gf_preferences.h"
#include "gf_theme.h"
#include "gf_theme_ops.h"
#include "gf_utils.h"

struct _GfNotification {
      GfTheme *theme;
      gchar *n_type;
      gchar *alias;

      gboolean use_gtk;
      gchar *background;
      gint width;
      gint height;

      GList *items;
};

/*******************************************************************************
 * API
 ******************************************************************************/
GfNotification *
gf_notification_new(GfTheme *theme) {
      GfNotification *notification;

      g_return_val_if_fail(theme, NULL);

      notification = g_new0(GfNotification, 1);
      notification->theme = theme;
      notification->use_gtk = TRUE;
      notification->height = 140;
      notification->width = 120;

      return notification;
}

GfNotification *
gf_notification_new_from_xmlnode(GfTheme *theme, xmlnode *node) {
      GfNotification *notification;
      GfItem *item;
      xmlnode *child;
      const gchar *data;

      g_return_val_if_fail(theme, NULL);
      g_return_val_if_fail(node, NULL);

      notification = gf_notification_new(theme);

      notification->n_type = g_strdup(xmlnode_get_attrib(node, "type"));
      if(!notification->n_type) {
            gaim_debug_info("Guifications", "** Error: Notification type unknown\n");
            gf_notification_destroy(notification);
            return NULL;
      }

      if(!g_utf8_collate(notification->n_type, GF_NOTIFICATION_MASTER))
            gf_theme_set_master(theme, notification);

      data = xmlnode_get_attrib(node, "use_gtk");
      if(data)
            notification->use_gtk = atoi(data);

      data = xmlnode_get_attrib(node, "background");
      if(data)
            notification->background = g_strdup(data);

      data = xmlnode_get_attrib(node, "width");
      if(data)
            notification->width = atoi(data);

      data = xmlnode_get_attrib(node, "height");
      if(data)
            notification->height = atoi(data);

      data = xmlnode_get_attrib(node, "alias");
      if(data)
            notification->alias = g_strdup(data);

      if(notification->use_gtk) {
            if(notification->width < GF_NOTIFICATION_MIN ||
               notification->height < GF_NOTIFICATION_MIN)
            {
                  gaim_debug_info("Guifications", "** Error: notification '%s' is using the "
                                          "gtk background but %dx%d is less than the %dx%d minimum\n",
                                          notification->n_type,
                                          notification->width, notification->height,
                                          GF_NOTIFICATION_MIN, GF_NOTIFICATION_MIN);
                  gf_notification_destroy(notification);
                  return NULL;
            }
      } else if(!notification->background) {
            gaim_debug_info("Guifications", "** Error: notification '%s' is not using the "
                                    "gtk background and does not have a background image\n",
                                    notification->n_type);
            gf_notification_destroy(notification);
            return NULL;
      }

      child = xmlnode_get_child(node, "item");

      while(child) {
            item = gf_item_new_from_xmlnode(notification, child);

            if(item)
                  gf_notification_add_item(notification, item);

            child = xmlnode_get_next_twin(child);
      }

      return notification;
}

GfNotification *
gf_notification_copy(GfNotification *notification) {
      GfNotification *new_notification;
      GList *l;

      g_return_val_if_fail(notification, NULL);

      new_notification = gf_notification_new(notification->theme);

      if(notification->n_type)
            new_notification->n_type = g_strdup(notification->n_type);

      if(notification->background)
            new_notification->background = g_strdup(notification->background);

      if(notification->alias)
            new_notification->alias = g_strdup(notification->alias);

      new_notification->use_gtk = notification->use_gtk;
      new_notification->width = notification->width;
      new_notification->height = notification->height;

      for(l = notification->items; l; l = l->next) {
            GfItem *item;

            item = gf_item_copy(GF_ITEM(l->data));
            new_notification->items = g_list_append(new_notification->items, item);
      }

      return new_notification;
}

xmlnode *
gf_notification_to_xmlnode(GfNotification *notification) {
      GList *l;
      xmlnode *parent, *child;
      gchar *data;

      parent = xmlnode_new("notification");
      xmlnode_set_attrib(parent, "type", notification->n_type);

      xmlnode_set_attrib(parent, "use_gtk", (notification->use_gtk) ? "1" : "0");

      if(notification->background)
            xmlnode_set_attrib(parent, "background", notification->background);

      if(notification->alias)
            xmlnode_set_attrib(parent, "alias", notification->alias);

      data = g_strdup_printf("%d", notification->width);
      xmlnode_set_attrib(parent, "width", data);
      g_free(data);

      data = g_strdup_printf("%d", notification->height);
      xmlnode_set_attrib(parent, "height", data);
      g_free(data);

      for(l = notification->items; l; l = l->next) {
            if((child = gf_item_to_xmlnode(GF_ITEM(l->data))))
                  xmlnode_insert_child(parent, child);
      }

      return parent;
}

void
gf_notification_destroy(GfNotification *notification) {
      GfItem *item;
      GList *l;

      g_return_if_fail(notification);

      if(notification->n_type) {
            g_free(notification->n_type);
            notification->n_type = NULL;
      }

      if(notification->background) {
            g_free(notification->background);
            notification->background = NULL;
      }

      if(notification->alias) {
            g_free(notification->alias);
            notification->alias = NULL;
      }

      if(notification->items) {
            for(l = notification->items; l; l = l->next) {
                  item = GF_ITEM(l->data);
                  gf_item_destroy(item);
            }

            g_list_free(notification->items);
            notification->items = NULL;
      }

      g_free(notification);
}

void
gf_notification_set_type(GfNotification *notification, const gchar *n_type) {
      g_return_if_fail(notification);
      g_return_if_fail(n_type);

      if(notification->n_type)
            g_free(notification->n_type);

      notification->n_type = g_strdup(n_type);
}

const gchar *
gf_notification_get_type(GfNotification *notification) {
      g_return_val_if_fail(notification, NULL);

      return notification->n_type;
}

void
gf_notification_set_use_gtk(GfNotification *notification, gboolean value) {
      g_return_if_fail(notification);

      notification->use_gtk = value;
}

gboolean
gf_notification_get_use_gtk(GfNotification *notification) {
      g_return_val_if_fail(notification, FALSE);

      return notification->use_gtk;
}

void
gf_notification_set_background(GfNotification *notification,
                                             const gchar *background)
{
      g_return_if_fail(notification);

      if(notification->background)
            g_free(notification->background);

      notification->background = g_strdup(background);
}

const gchar *
gf_notification_get_background(GfNotification *notification) {
      g_return_val_if_fail(notification, NULL);

      return notification->background;
}

void
gf_notification_set_width(GfNotification *notification, gint width) {
      g_return_if_fail(notification);

      notification->width = width;
}

gint
gf_notification_get_width(GfNotification *notification) {
      g_return_val_if_fail(notification, -1);

      return notification->width;
}

void
gf_notification_set_height(GfNotification *notification, gint height) {
      g_return_if_fail(notification);

      notification->height = height;
}

gint
gf_notification_get_height(GfNotification *notification) {
      g_return_val_if_fail(notification, -1);

      return notification->height;
}

void
gf_notification_add_item(GfNotification *notification, GfItem *item) {
      g_return_if_fail(notification);
      g_return_if_fail(item);

      notification->items = g_list_append(notification->items, item);
}

void
gf_notification_remove_item(GfNotification *notification, GfItem *item) {
      g_return_if_fail(notification);
      g_return_if_fail(item);

      notification->items = g_list_remove(notification->items, item);
}

GList *
gf_notification_get_items(GfNotification *notification) {
      g_return_val_if_fail(notification, NULL);

      return notification->items;
}

const gchar *
gf_notification_get_alias(const GfNotification *notification) {
      g_return_val_if_fail(notification, NULL);

      return notification->alias;
}

void
gf_notification_set_alias(GfNotification *notification, const gchar *alias) {
      g_return_if_fail(notification);

      if(notification->alias)
            g_free(notification->alias);

      notification->alias = (alias) ? g_strdup(alias) : NULL;
}

/*******************************************************************************
 * Finding, rendering, all that fun stuff...
 ******************************************************************************/
void
gf_notifications_swap(GfNotification *notification1, GfNotification *notification2) {
      GfNotification *notification = NULL;
      GList *l = NULL, *l1 = NULL, *l2 = NULL;

      g_return_if_fail(notification1);
      g_return_if_fail(notification2);

      if(notification1->theme != notification2->theme)
            return;

      for(l = gf_theme_get_notifications(notification1->theme); l; l = l->next) {
            if(l->data == notification1)
                  l1 = l;
            if(l->data == notification2)
                  l2 = l;
      }

      g_return_if_fail(l1);
      g_return_if_fail(l2);

      /* swap 'em */
      notification = l1->data;
      l1->data = l2->data;
      l2->data = notification;
}

GList *
gf_notifications_for_event(const gchar *n_type) {
      GfTheme *theme;
      GfNotification *notification;
      GList *l = NULL, *t, *n;

      g_return_val_if_fail(n_type, NULL);

      for(t = gf_themes_get_loaded(); t; t = t->next) {
            theme = GF_THEME(t->data);

            for(n = gf_theme_get_notifications(theme); n; n = n->next) {
                  notification = GF_NOTIFICATION(n->data);

                  if(!g_ascii_strcasecmp(notification->n_type, n_type))
                        l = g_list_append(l, notification);
            }
      }

      return l;
}

GfNotification *
gf_notification_find_for_event(const gchar *n_type) {
      GfNotification *notification = NULL;
      GList *n = NULL;
      gint c;
      time_t t;

      g_return_val_if_fail(n_type, NULL);

      n = gf_notifications_for_event(n_type);
      if(!n)
            return NULL;

      t = time(NULL);
      srand(t);
      c = rand() % g_list_length(n);

      notification = GF_NOTIFICATION(g_list_nth_data(n, c));
      g_list_free(n);

      return notification;
}

GfNotification *
gf_notification_find_for_theme(GfTheme *theme, const gchar *n_type) {
      GfNotification *notification = NULL;
      GList *n = NULL, *t = NULL;
      gint len;

      g_return_val_if_fail(theme, NULL);
      g_return_val_if_fail(n_type, NULL);

      /* Get the list of notifications for a theme */
      for(t = gf_theme_get_notifications(theme); t; t = t->next) {
            notification = GF_NOTIFICATION(t->data);

            if(!gf_utils_strcmp(notification->n_type, n_type))
                  n = g_list_append(n, notification);
      }

      len = g_list_length(n);

      if(len == 0)
            notification = NULL;
      else if(len == 1)
            notification = GF_NOTIFICATION(n->data);
      else {
            gint c;
            time_t t;

            t = time(NULL);
            srand(t);

            c = rand() % len;
            notification = GF_NOTIFICATION(g_list_nth_data(n, c));
      }

      g_list_free(n);

      return notification;
}

GdkPixbuf *
gf_notification_render(GfNotification *notification, GfEventInfo *info) {
      GfItem *item = NULL;
      GdkPixbuf *pixbuf = NULL;
      GList *l = NULL;
      gchar *filename;
      const gchar *path;

      g_return_val_if_fail(notification, NULL);
      g_return_val_if_fail(info, NULL);

      if(notification->background) {
            /* create the pixbuf, return if it failed */
            path = gf_theme_get_path(notification->theme);
            filename = g_build_filename(path, notification->background, NULL);
            pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
            g_free(filename);

            if(!pixbuf) {
                  gaim_debug_info("Guifications", "Couldn't not load notification background\n");
                  return NULL;
            }
      } else {
            GdkPixmap *pixmap = NULL;

            pixmap = gf_gtk_theme_get_bg_pixmap();

            if(pixmap) {
                  GdkPixbuf *tile = NULL;
                  gint width, height;

                  gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &width, &height);

                  tile = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(pixmap), NULL,
                                                                        0, 0, 0, 0, width, height);

                  if(!tile) {
                        gaim_debug_info("Guifications", "Failed to get the gtk theme "
                                                "background image\n");
                        return NULL;
                  }

                  pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
                                                      notification->width, notification->height);

                  gf_gtk_pixbuf_tile(pixbuf, tile);
                  g_object_unref(G_OBJECT(tile));
            } else {
                  GdkColor color;
                  guint32 pixel;

                  pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
                                                      notification->width, notification->height);

                  if(!pixbuf) {
                        gaim_debug_info("Guifications", "Failed to create notification background\n");
                        return NULL;
                  }

                  gf_gtk_theme_get_bg_color(&color);
                  pixel = gf_gtk_color_pixel_from_gdk(&color);
                  gdk_pixbuf_fill(pixbuf, pixel);
            }
      }

      /* render the items */
      for(l = notification->items; l; l = l->next) {
            item = GF_ITEM(l->data);

            gf_item_render(item, pixbuf, info);
      }

      /* display it already!! */
      return pixbuf;
}

GfTheme *
gf_notification_get_theme(GfNotification *notification) {
      g_return_val_if_fail(notification, NULL);

      return notification->theme;
}

Generated by  Doxygen 1.6.0   Back to index