view src/applet.c @ 2906:538c58b43eff

[gaim-migrate @ 2919] save save me from this wandered around the town all the thousand things i might miss and you think we'll suffer much think we'll close our eyes just to see the light pass us by with tomorrow coming hope that i don't let you down again said i'm so glad to be here does it mean a thing if only i could breathe what you breathe if only i could see what you see sit we'll take our time watching the flowers grow all the friends we've known say goodbye and you did you suffer much did you close your eyes just to see the night rush on by gathered all around you hope that we don't let you down again i said i'm so glad to be here does it mean a thing if only i could breathe what you breathe if only i could see what you see i said i'm so glad to be here does it mean a thing if only i could breathe what you breathe if only i could see what you see if only i could just believe a thing --Moist, "Breathe" (as transcribed by http://www.veddma.com/veddma/moist.htm) Patches from: Ari Pollak Ben Miller Mark Doliner Sean Egan Vincas Ciziunas Thanks everyone. Somewhere in the middle of all of this it started to get really tedious and annoying. I think it's getting close to the point where I quit. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 21 Dec 2001 10:23:04 +0000
parents 87d11d2a7d59
children 32c78c57b351
line wrap: on
line source

/**************************************************************
**
** GaimGnomeAppletMgr
** Author - Quinticent (John Palmieri: johnp@martianrock.com)
**
** Purpose - Takes over the task of managing the GNOME applet
**           code and provides a centralized codebase for
**	     GNOME integration for Gaim.
**
**
** gaim
**
** Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
**
** 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 
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef USE_APPLET
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libart_lgpl/art_affine.h>
#include <libart_lgpl/art_rgb_affine.h>
#include <libart_lgpl/art_rgb_rgba_affine.h>
#include "gaim.h"
#include "applet.h"
#include "pixmaps/aimicon.xpm"

static int connecting = 0;

gboolean applet_buddy_show = FALSE;

GtkWidget *applet;
static GtkWidget *icon;

static GtkAllocation *get_applet_pos(gboolean);
static gint sizehint = 48;

static PanelBackType backtype = PANEL_BACK_NONE;
static GdkColor *backcolor = NULL;
static char *backfile = NULL;

static void make_background(guchar *dest)
{
	guchar *p;
	int r,g,b,i;

	if (backcolor && (backtype == PANEL_BACK_COLOR)) {
		guchar *p;
		int r,g,b,i;

		r = backcolor->red>>8;
		g = backcolor->green>>8;
		b = backcolor->blue>>8;
		p = dest;
		for (i = 0; i < sizehint * sizehint; i++) {
			*p++ = r;
			*p++ = g;
			*p++ = b;
		}
		return;
	} else if (backfile && (backtype == PANEL_BACK_PIXMAP)) {
		GdkPixbuf *pb = gdk_pixbuf_new_from_file(backfile);
		if (pb) {
			int dw = sizehint;
			int dh = sizehint;
			int offx = applet->allocation.x;
			int offy = applet->allocation.y;
			int drs = dw * 3;
			guchar *tile = gdk_pixbuf_get_pixels(pb);
			int w = gdk_pixbuf_get_width(pb);
			int h = gdk_pixbuf_get_height(pb);
			int rowstride = gdk_pixbuf_get_rowstride(pb);
			int has_alpha = gdk_pixbuf_get_has_alpha(pb);

			guchar *p;
			int i,j,x,y,a;
			guchar *imgrow;
			int off;

			p = dest;
			y = offy % h;            
			off = drs - (dw*3); /*the space after width ends until next row*/
			for(j=0;j<dh;j++) {      
				x = offx % w;    
				imgrow = tile + y * rowstride + (has_alpha?/*x*4*/x<<2:x*3);
				for(i=0;i<dw;i++) {
					*(p++) = *(imgrow++);
					*(p++) = *(imgrow++);
					*(p++) = *(imgrow++);
					if(has_alpha) {
						a = *(imgrow++);
						if(a!=255) {
							guchar *pp = p-3;
							pp[0] = (pp[0]*a)>>8;
							pp[1] = (pp[1]*a)>>8;
							pp[2] = (pp[2]*a)>>8;
						}
					}
					x++;
					if(x>=w) {
						x = 0;
						imgrow = tile + y * rowstride;
					}
				}
				p += off; 
				y++;
				if(y>=h)
					y = 0;
			}
			gdk_pixbuf_unref(pb);
			return;
		}
	}

	r = applet->style->bg[GTK_WIDGET_STATE(applet)].red>>8;
	g = applet->style->bg[GTK_WIDGET_STATE(applet)].green>>8;
	b = applet->style->bg[GTK_WIDGET_STATE(applet)].blue>>8;
	p = dest;
	for (i = 0; i < sizehint * sizehint; i++) {
		*p++ = r;
		*p++ = g;
		*p++ = b;
	}
}

static GdkPixmap *get_applet_icon(const char *name)
{
	GdkPixmap *cache;
	GdkGC *gc;
	char *path;
	GdkPixbuf *pb, *scale = NULL;
	guchar *dst;
	double affine[6];

	if (!applet)
		return NULL;

	cache = gdk_pixmap_new(applet->window, sizehint, sizehint,
			gtk_widget_get_visual(applet)->depth); 
	gc = gdk_gc_new(cache);
	gdk_gc_copy(gc, applet->style->bg_gc[GTK_WIDGET_STATE(applet)]);

	path = gnome_pixmap_file(name);
	if (path)
		scale = gdk_pixbuf_new_from_file(path);
	g_free(path);
	if (!scale)
		return NULL;
	pb = gdk_pixbuf_scale_simple(scale, sizehint, sizehint, GDK_INTERP_HYPER);
	gdk_pixbuf_unref(scale);

	dst = g_new0(guchar, sizehint*sizehint*3);
	make_background(dst);

	art_affine_identity(affine);
	if (gdk_pixbuf_get_has_alpha(pb))
		art_rgb_rgba_affine(dst, 0, 0, sizehint, sizehint, sizehint * 3,
				gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb),
				gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb),
				affine, ART_FILTER_NEAREST, NULL);
	else
		art_rgb_affine(dst, 0, 0, sizehint, sizehint, sizehint * 3,
				gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb),
				gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb),
				affine, ART_FILTER_NEAREST, NULL);

	gdk_pixbuf_unref(pb);
	gdk_draw_rgb_image(cache, gc, 0, 0, sizehint, sizehint,
			GDK_RGB_DITHER_NORMAL, dst, sizehint * 3);
	g_free(dst);

	gdk_gc_unref(gc);
	return cache;
}

static gboolean update_applet()
{
	char buf[BUF_LONG];
	GSList *c = connections;
	GdkPixmap *newpix;

	if (connecting) {
		newpix = get_applet_icon(GAIM_GNOME_CONNECT_ICON);
		applet_set_tooltips(_("Attempting to sign on...."));
	} else if (!connections) {
		newpix = get_applet_icon(GAIM_GNOME_OFFLINE_ICON);
		applet_set_tooltips(_("Offline. Click to bring up login box."));
	} else if (awaymessage) {
		int dsr = 0;

		if ((away_options & OPT_AWAY_QUEUE) && message_queue) {
			GSList *m = message_queue;
			while (m) {
				struct queued_message *qm = m->data;
				if (qm->flags & WFLAG_RECV)
					dsr++;
				m = m->next;
			}
		}

		if (dsr) {
			newpix = get_applet_icon(GAIM_GNOME_MSG_PENDING_ICON);
			g_snprintf(buf, sizeof(buf), _("Away: %d pending."), dsr);
		} else {
			newpix = get_applet_icon(GAIM_GNOME_AWAY_ICON);
			g_snprintf(buf, sizeof(buf), _("Away."));
		}

		applet_set_tooltips(buf);
	} else {
		newpix = get_applet_icon(GAIM_GNOME_ONLINE_ICON);
		g_snprintf(buf, sizeof buf, "Online: ");
		while (c) {
			strcat(buf, ((struct gaim_connection *)c->data)->username);
			c = g_slist_next(c);
			if (c)
				strcat(buf, ", ");
		}
		applet_set_tooltips(buf);
	}

	if (newpix) {
		gtk_pixmap_set(GTK_PIXMAP(icon), newpix, NULL);
		gdk_pixmap_unref(newpix);
	}

	return TRUE;
}

static void back_changed(AppletWidget *applet, PanelBackType type, char *file, GdkColor *clr)
{
	backtype = type;
	if (backfile)
		g_free(backfile);
	if (file)
		backfile = g_strdup(file);
	else
		backfile = NULL;
	if (backcolor)
		gdk_color_free(backcolor);
	if (clr)
		backcolor = gdk_color_copy(clr);
	else
		backcolor = NULL;
	update_applet();
}

#ifdef HAVE_PANEL_PIXEL_SIZE
static void applet_change_pixel_size(GtkWidget *w, int size, gpointer data)
{
	sizehint = size;
	gtk_widget_set_usize(icon, sizehint, sizehint);
	update_applet();
}
#endif

extern GtkWidget *mainwindow;
void applet_show_login(AppletWidget *widget, gpointer data)
{
	show_login();
	if (blist_options & OPT_BLIST_NEAR_APPLET) {
		GtkAllocation *a = get_applet_pos(FALSE);
		gtk_widget_set_uposition(mainwindow, a->x, a->y);
	}
}

void applet_do_signon(AppletWidget *widget, gpointer data)
{
	applet_show_login(NULL, 0);
}

void insert_applet_away()
{
	GSList *awy = away_messages;
	struct away_message *a;
	char *awayname;

	applet_widget_register_callback_dir(APPLET_WIDGET(applet), "away/", _("Away"));
	applet_widget_register_callback(APPLET_WIDGET(applet),
					"away/new",
					_("New Away Message"),
					(AppletCallbackFunc)create_away_mess, NULL);

	while (awy) {
		a = (struct away_message *)awy->data;

		awayname = g_malloc(sizeof *awayname * (6 + strlen(a->name)));
		awayname[0] = '\0';
		strcat(awayname, "away/");
		strcat(awayname, a->name);
		applet_widget_register_callback(APPLET_WIDGET(applet),
						awayname,
						a->name, (AppletCallbackFunc)do_away_message, a);

		awy = awy->next;
		g_free(awayname);
	}
}

void remove_applet_away()
{
	GSList *awy = away_messages;
	struct away_message *a;
	char *awayname;

	if (!applet)
		return;

	applet_widget_unregister_callback(APPLET_WIDGET(applet), "away/new");

	while (awy) {
		a = (struct away_message *)awy->data;

		awayname = g_malloc(sizeof *awayname * (6 + strlen(a->name)));
		awayname[0] = '\0';
		strcat(awayname, "away/");
		strcat(awayname, a->name);
		applet_widget_unregister_callback(APPLET_WIDGET(applet), awayname);

		awy = g_slist_next(awy);
		g_free(awayname);
	}
	applet_widget_unregister_callback_dir(APPLET_WIDGET(applet), "away/");
	applet_widget_unregister_callback(APPLET_WIDGET(applet), "away");
}

static GtkAllocation *get_applet_pos(gboolean for_blist)
{
	gint x, y, pad;
	GtkRequisition buddy_req, applet_req;
	GtkAllocation *result = g_new0(GtkAllocation, 1);
	GNOME_Panel_OrientType orient = applet_widget_get_panel_orient(APPLET_WIDGET(applet));
	pad = 5;

	gdk_window_get_position(gtk_widget_get_parent_window(icon), &x, &y);
	if (for_blist) {
		if (blist_options & OPT_BLIST_SAVED_WINDOWS) {
			buddy_req.width = blist_pos.width;
			buddy_req.height = blist_pos.height;
		} else {
			buddy_req = blist->requisition;
		}
	} else {
		buddy_req = mainwindow->requisition;
	}
	applet_req = icon->requisition;

	switch (orient) {
	case ORIENT_UP:
		result->x = x;
		result->y = y - (buddy_req.height + pad);
		break;
	case ORIENT_DOWN:
		result->x = x;
		result->y = y + applet_req.height + pad;
		break;
	case ORIENT_LEFT:
		result->x = x - (buddy_req.width + pad);
		result->y = y;
		break;
	case ORIENT_RIGHT:
		result->x = x + applet_req.width + pad;
		result->y = y;
		break;
	}

	if (result->x < 0)
		result->x = 0;
	if (result->y < 0)
		result->y = 0;
	if (result->x > gdk_screen_width() - buddy_req.width)
		result->x = gdk_screen_width() - buddy_req.width;
	if (result->y > gdk_screen_height() - buddy_req.height)
		result->y = gdk_screen_height() - buddy_req.height;

	return result;
}

void createOnlinePopup()
{
	GtkAllocation *al;
	if (blist)
		gtk_widget_show(blist);
	al = get_applet_pos(TRUE);
	if (blist_options & OPT_BLIST_NEAR_APPLET)
		gtk_widget_set_uposition(blist, al->x, al->y);
	else if (blist_options & OPT_BLIST_SAVED_WINDOWS)
		gtk_widget_set_uposition(blist, blist_pos.x - blist_pos.xoff,
					 blist_pos.y - blist_pos.yoff);
	g_free(al);
}

void AppletClicked(GtkWidget *sender, GdkEventButton *ev, gpointer data)
{
	if (!ev || ev->button != 1 || ev->type != GDK_BUTTON_PRESS)
		return;

	if (applet_buddy_show) {
		applet_buddy_show = FALSE;
		if (!connections && mainwindow)
			gtk_widget_hide(mainwindow);
		else
			gtk_widget_hide(blist);
	} else {
		applet_buddy_show = TRUE;
		if (!connections)
			applet_show_login(APPLET_WIDGET(applet), NULL);
		else
			createOnlinePopup();
	}
}


/***************************************************************
**
** Initialize GNOME stuff
**
****************************************************************/

gint init_applet_mgr(int argc, char *argv[])
{
	GdkPixmap *pm;

	applet_widget_init("Gaim", VERSION, argc, argv, NULL, 0, NULL);

	applet = applet_widget_new("gaim_applet");
	if (!applet)
		g_error(_("Can't create Gaim applet!"));
	gtk_signal_connect(GTK_OBJECT(applet), "back_change", GTK_SIGNAL_FUNC(back_changed), NULL);
	gtk_widget_set_events(applet, gtk_widget_get_events(applet) | GDK_BUTTON_PRESS_MASK);
	gtk_widget_realize(applet);

	pm = get_applet_icon(GAIM_GNOME_OFFLINE_ICON);
	if (!pm)
		pm = gdk_pixmap_create_from_xpm_d(applet->window, NULL,
				&applet->style->bg[GTK_WIDGET_STATE(applet)], aimicon_xpm);
	icon = gtk_pixmap_new(pm, NULL);
#ifdef HAVE_PANEL_PIXEL_SIZE
	gtk_widget_set_usize(icon, 5, 5);
#else
	gtk_widget_set_usize(icon, 48, 48);
#endif
	gdk_pixmap_unref(pm);
	applet_widget_add(APPLET_WIDGET(applet), icon);

	applet_widget_register_stock_callback(APPLET_WIDGET(applet),
					      "about",
					      GNOME_STOCK_MENU_ABOUT,
					      _("About..."), (AppletCallbackFunc)show_about, NULL);

	gtk_signal_connect(GTK_OBJECT(applet), "button_press_event", GTK_SIGNAL_FUNC(AppletClicked),
			   NULL);

	gtk_signal_connect(GTK_OBJECT(applet), "destroy", GTK_SIGNAL_FUNC(do_quit), NULL);

#ifdef HAVE_PANEL_PIXEL_SIZE
	gtk_signal_connect(GTK_OBJECT(applet), "change_pixel_size",
			   GTK_SIGNAL_FUNC(applet_change_pixel_size), NULL);
#endif

	gtk_widget_show(icon);
	gtk_widget_show(applet);
	return 0;
}

void set_user_state(enum gaim_user_states state)
{
	if (state == signing_on)
		connecting++;
	else if ((state == away || state == online) && connecting > 0)
		connecting--;
	update_applet();
}

void applet_set_tooltips(char *msg)
{
	if (!applet)
		return;
	applet_widget_set_tooltip(APPLET_WIDGET(applet), msg);
}

#endif /*USE_APPLET */