view plugins/crazychat/cc_features.c @ 12116:e75ef7aa913e

[gaim-migrate @ 14416] " This patch implements a replacement for the queuing system from 1.x. It also obsoletes a previous patch [#1338873] I submitted to prioritize the unseen states in gtk conversations. The attached envelope.png is ripped from the msgunread.png already included in gaim. It should be dropped in the pixmaps directory (Makefile.am is updated accordingly in this patch). The two separate queuing preferences from 1.x, queuing messages while away and queuing all new messages (from docklet), are replaced with a single 3-way preference for conversations. The new preference is "Hide new IM conversations". This preference can be set to never, away and always. When a gtk conversation is created, it may be placed in a hidden conversation window instead of being placed normally. This decision is based upon the preference and possibly the away state of the account the conversation is being created for. This *will* effect conversations the user explicitly requests to be created, so in these cases the caller must be sure to present the conversation to the user, using gaim_gtkconv_present_conversation(). This is done already in gtkdialogs.c which handles creating conversations requested by the user from gaim proper (menus, double-clicking on budy in blist, etc.). The main advantage to not queuing messages is that the conversations exist, the message is written to the conversation (and logged if appropriate) and the unseen state is set on the conversation. This means no additional features are needed to track whether there are queued messages or not, just use the unseen state on conversations. Since conversations may not be visible (messages "queued"), gaim proper needs some notification that there are messages waiting. I opted for a menutray icon that shows up when an im conversation has an unseen message. Clicking this icon will focus (and show if hidden) the first conversation with an unseen message. This is essentially the same behavior of the docklet in cvs right now, except that the icon is only visible when there is a conversation with an unread message. The api that is added is flexible enough to allow either the docklet or the new blist menutray icon to be visible for conversations of any/all types and for unseen messages >= any state. Currently they are set to only IM conversations and only unseen states >= TEXT (system messages and no log messages will not trigger blinking the docklet or showing the blist tray icon), but these could be made preferences relatively easily in the future. Other plugins could probably benefit as well: gaim_gtk_conversations_get_first_unseen(). There is probably some limit to comment size, so I'll stop rambling now. If anyone has more questions/comments, catch me in #gaim, here or on gaim-devel." committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Wed, 16 Nov 2005 18:17:01 +0000
parents 8bcd4d4ccef6
children
line wrap: on
line source

#include <assert.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "cc_interface.h"
#include "crazychat.h"

#include "Utilities.h"
#include "QTUtilities.h"
#include "camdata.h"
#include "camproc.h"
#include "util.h"
#include <unistd.h>


#ifdef __APPLE_CC__
#include <Carbon/Carbon.h>
#else
#include <Carbon.h>
#endif

/* temporarily including for development testing */
#include "cc_gtk_gl.h"

/* hard coding the webcam dimensions: BAD, but we're not probing hardware yet */

#define WEBCAM_X		644	/* webcam's x dim */
#define WEBCAM_Y		480	/* webcam's y dim */

/* default webcam timer callback delay */
#define WEBCAM_CALLBACK_DELAY	40	/* in ms */

int x_click, y_click;
int mode_change=0;

struct input_instance input_data;

/* move this to input_instance eventually */
/*
UInt32 colorBuf[WEBCAM_Y][WEBCAM_X];
*/
unsigned int (*colorBuf)[640];
int detection_mode=0;
int draw_mode=0; //0=pixels, 1=face
int easter_count;
static void *kickstart(void *data);
static void *facefind(void *data);

/**
 * Resets the OpenGL viewport stuff on widget reconfiguration (resize,
 * reposition)
 * @param widget	widget that got reconfigured
 * @param event		the configuration event
 * @param data		unused
 * @return		TRUE ( i don't know what FALSE would do )
 */
static gboolean config_wrapper(GtkWidget *widget, GdkEventConfigure *event,
		void *data);

/**
 * Debug features test.  Draws pixels directly to the frame buffer.
 * @param widget	widget that we're drawing
 * @param event		the draw event
 * @param data		array of pixels
 * @return		DUNNO
 */
static gboolean mydraw(GtkWidget *widget, GdkEventExpose *event,
			      void *data);

/**
 * Periodically querys the webcam for more data.
 * @param instance	webcam input instance data
 * @return 		TRUE to stop other handler, FALSE to continue
 */
static gboolean webcam_cb(struct input_instance *instance);

/**
 * Init window code, adding our click callback.
 * @param widget	the window we clicked in
 * @param instance	webcam input instance data
 */
static void init_cb(GtkWidget *widget, struct input_instance *instance);

/**
 * Click callback
 * @param widget	the window we clicked in
 * @param event		the button click event structure
 * @param instance	input instance data
 * @return 		TRUE to stop other handler, FALSE to continue
 */
static gboolean click_cb(GtkWidget *widget, GdkEventButton *event,
		struct input_instance *instance);

/**
 * Button callback
 * @param button	the button we clicked on
 * @param instance	input instance data
 */
static void button_cb(GtkWidget *button, struct input_instance *instance);

/**
 * Destroy callback.  Called when the input processing window is destroyed.
 * @param widget	the window we clicked in
 * @param cc		crazychat global data structure
 */
static void destroy_cb(GtkWidget *widget, struct crazychat *cc);

/**
 * Set feature material.
 * @param entry		model selector combo box entry
 * @param material	pointer to material we're setting
 */
static void material_set(GtkWidget *entry, guint8 *material);

struct input_instance *init_input(struct crazychat *cc)
{

  /*pthread_t userinput_t; // should we put this in a nicer wrapper?*/
	struct draw_info *info;
	struct input_instance *instance; 
	info = (struct draw_info*)malloc(sizeof(*info));
	assert(info);
	memset(info, 0, sizeof(*info));
	info->timeout = TRUE;
	info->delay_ms = DEFAULT_FRAME_DELAY;
	info->data = &input_data;
	instance = (struct input_instance*)info->data;
	memset(instance, 0, sizeof(*instance));
	instance->output.features = &instance->face;
	EnterMovies();
	filter_bank *bank;
	bank = Filter_Initialize();
	assert(CamProc(instance, bank) == noErr); // change this prototype-> no windows
	instance->timer_id = g_timeout_add(WEBCAM_CALLBACK_DELAY,
		(GSourceFunc)webcam_cb, instance);
	/*	THREAD_CREATE(&userinput_t, facefind, instance); // is this being created correctly?*/
	struct window_box ret;
	cc_new_gl_window(init_cb, config_wrapper, mydraw,
			info, &ret);
	instance->widget = ret.window;
	gtk_window_set_title(GTK_WINDOW(ret.window), "Local User");
	instance->box = ret.vbox;
	GtkWidget *label = gtk_label_new("Click your face");
	instance->label = label;
	gtk_box_pack_start(GTK_BOX(ret.vbox), label, FALSE, FALSE, 0);
	gtk_box_reorder_child(GTK_BOX(ret.vbox), label, 0);
	gtk_widget_show(label);
	GtkWidget *button = gtk_button_new_with_label("Confirm");
	gtk_box_pack_start(GTK_BOX(ret.vbox), button, FALSE, FALSE, 0);
	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_cb),
			instance);
	instance->button = button;
	gtk_widget_show(button);

	GtkWidget *hbox = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(ret.vbox), hbox, FALSE, FALSE, 0);
	gtk_widget_show(hbox);

	GtkWidget *model_combo = gtk_combo_new();
	GList *glist = NULL;

	glist = g_list_append(glist, "Dog");
	glist = g_list_append(glist, "Shark");
	gtk_combo_set_popdown_strings(GTK_COMBO(model_combo), glist);
	g_list_free(glist);
	//gtk_combo_box_set_column_span_column(GTK_COMBO(model_combo),
	//		10);
	gtk_box_pack_start(GTK_BOX(hbox), model_combo, TRUE, TRUE, 0);
	gtk_widget_show(model_combo);
	instance->model = model_combo;

	GtkWidget *head_material_combo = gtk_combo_new();
	glist = NULL;
	glist = g_list_append(glist, "Red");
	glist = g_list_append(glist, "Dark Brown");
	glist = g_list_append(glist, "Light Brown");
	glist = g_list_append(glist, "White");
	glist = g_list_append(glist, "Green");
	glist = g_list_append(glist, "Black");
	gtk_combo_set_popdown_strings(GTK_COMBO(head_material_combo), glist);
	g_list_free(glist);
	//gtk_combo_box_set_column_span_column(GTK_COMBO(head_material_combo),
	//		10);
	gtk_box_pack_start(GTK_BOX(hbox), head_material_combo, TRUE, TRUE, 0);
	gtk_widget_show(head_material_combo);
	instance->head = head_material_combo;

	GtkWidget *appendage_material_combo = gtk_combo_new();
	glist = NULL;
	glist = g_list_append(glist, "Red");
	glist = g_list_append(glist, "Dark Brown");
	glist = g_list_append(glist, "Light Brown");
	glist = g_list_append(glist, "White");
	glist = g_list_append(glist, "Green");
	glist = g_list_append(glist, "Black");
	gtk_combo_set_popdown_strings(GTK_COMBO(appendage_material_combo),
			glist);
	g_list_free(glist);
	//gtk_combo_box_set_column_span_column(GTK_COMBO(appendage_material_combo), 10);
	gtk_box_pack_start(GTK_BOX(hbox), appendage_material_combo,
			TRUE, TRUE, 0);
	gtk_widget_show(appendage_material_combo);
	instance->appendage = appendage_material_combo;

	hbox = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(ret.vbox), hbox, FALSE, FALSE, 0);
	gtk_widget_show(hbox);
	
	GtkWidget *lids_material_combo = gtk_combo_new();
	glist = NULL;
	glist = g_list_append(glist, "Red");
	glist = g_list_append(glist, "Dark Brown");
	glist = g_list_append(glist, "Light Brown");
	glist = g_list_append(glist, "White");
	glist = g_list_append(glist, "Green");
	glist = g_list_append(glist, "Black");
	gtk_combo_set_popdown_strings(GTK_COMBO(lids_material_combo), glist);
	g_list_free(glist);
	//gtk_combo_box_set_column_span_column(GTK_COMBO(lids_material_combo), 10);
	gtk_box_pack_start(GTK_BOX(hbox), lids_material_combo, TRUE, TRUE, 0);
	gtk_widget_show(lids_material_combo);
	instance->lid = lids_material_combo;

	GtkWidget *left_iris_material_combo = gtk_combo_new();
	glist = NULL;
	glist = g_list_append(glist, "Red");
	glist = g_list_append(glist, "Dark Brown");
	glist = g_list_append(glist, "Light Brown");
	glist = g_list_append(glist, "White");
	glist = g_list_append(glist, "Green");
	glist = g_list_append(glist, "Black");
	gtk_combo_set_popdown_strings(GTK_COMBO(left_iris_material_combo),
			glist);
	g_list_free(glist);
	//gtk_combo_box_set_column_span_column(GTK_COMBO(left_iris_material_combo), 10);
	gtk_box_pack_start(GTK_BOX(hbox), left_iris_material_combo,
			TRUE, TRUE, 0);
	gtk_widget_show(left_iris_material_combo);
	instance->left_iris = left_iris_material_combo;

	/*
	GtkWidget *right_iris_material_combo = gtk_combo_new();
	glist = NULL;
	glist = g_list_append(glist, "Red");
	glist = g_list_append(glist, "Dark Brown");
	glist = g_list_append(glist, "Light Brown");
	glist = g_list_append(glist, "White");
	glist = g_list_append(glist, "Green");
	glist = g_list_append(glist, "Black");
	gtk_combo_set_popdown_strings(GTK_COMBO(right_iris_material_combo),
			glist);
	g_list_free(glist);
	//gtk_combo_box_set_column_span_column(GTK_COMBO(right_iris_material_combo), 10);
	gtk_box_pack_start(GTK_BOX(hbox), right_iris_material_combo,
			TRUE, TRUE, 0);
	gtk_widget_show(right_iris_material_combo);
	instance->right_iris = right_iris_material_combo;
*/
	gtk_widget_add_events(ret.draw_area, GDK_BUTTON_PRESS_MASK);
	g_signal_connect(G_OBJECT(ret.draw_area), "button_press_event",
			G_CALLBACK(click_cb), instance);
	g_signal_connect(G_OBJECT(ret.window), "destroy",
			G_CALLBACK(destroy_cb),	cc);
//	gtk_widget_set_size_request(window, 640, 480);
	gtk_window_set_default_size(GTK_WINDOW(ret.window),320,300);


	GdkGeometry hints;
        hints.max_width = 640;
        hints.max_height = 480;

        gtk_window_set_geometry_hints (GTK_WINDOW(ret.window),
                                       NULL,
                                      &hints,
                                       GDK_HINT_MAX_SIZE);
	gtk_widget_show(ret.window);
	return instance;
}

static gboolean webcam_cb(struct input_instance *instance)
{
	assert(instance);
	QueryCam();
	return TRUE;
}

static void *facefind(void *data)
{
	fprintf(stderr, "waiting\n");
	getchar();
	fprintf(stderr,"got you");
	detection_mode=1;
	return;
}

void destroy_input(struct input_instance *instance)
{
	extern filter_bank *bank;
	assert(instance);
	Filter_Destroy(bank);
	g_source_remove(instance->timer_id);
	Die();
	ExitMovies();
}

static gboolean config_wrapper(GtkWidget *widget, GdkEventConfigure *event,
		void *data)
{


	GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
	GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);

	GLfloat w = widget->allocation.width;
	GLfloat h = widget->allocation.height;
	GLfloat aspect;

//	fprintf(stderr,"Homicide  %f   %f  %d\n", w,h,draw_mode);

	if (draw_mode==1){
//		fprintf(stderr, "Bad place to be- actually not so bad\n");
		return configure(widget, event, data);
	}

	/*** OpenGL BEGIN ***/
	if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
		return FALSE;
	

/* Undo all of the Model lighting here*/

//	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
//	glDisable(GL_CULL_FACE);
//	glDisable(GL_LIGHT0);
//	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
/* */


	glViewport(0,-(h/14),w*2,h*2);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0,0,640,640);
	glRasterPos2i(0,0);
	glPixelZoom(-w/(1*640),(-h/(1*480)));
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();


	
	
	gdk_gl_drawable_gl_end(gldrawable);
	/*** OpenGL END ***/

	return TRUE;
}

static gboolean mydraw(GtkWidget *widget, GdkEventExpose *event,
			      void *data)
{
	GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
	GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
	struct input_instance *instance = (struct input_instance*)data;
	unsigned int *boo;
	struct cc_features *features = &instance->face;

	char *string = gtk_entry_get_text(GTK_COMBO(instance->model)->entry);
	if (!strcmp(string, "Dog")) {
		features->kind = 0;
	} else if (!strcmp(string, "Shark")) {
		features->kind = 1;
	}
	
	material_set(GTK_ENTRY(GTK_COMBO(instance->head)->entry),
			&features->head_color);
	material_set(GTK_ENTRY(GTK_COMBO(instance->appendage)->entry),
			&features->appendage_color);
	material_set(GTK_ENTRY(GTK_COMBO(instance->lid)->entry),
			&features->lid_color);
	material_set(GTK_ENTRY(GTK_COMBO(instance->left_iris)->entry),
			&features->left_iris_color);
	material_set(GTK_ENTRY(GTK_COMBO(instance->left_iris)->entry),
			&features->right_iris_color);

	if (easter_count>0) {
		easter_count--;
	} else {
		instance->face.mode = 0;
	}
	
	if (mode_change>0){
		mode_change--;
		config_wrapper(widget, event, data);
	}

	if (draw_mode==1){
		instance->output.my_output=LOCAL;
		return draw(widget,event,&instance->output);
	}


	boo = (unsigned int*)colorBuf;

	assert(instance);
	assert(gtk_widget_is_gl_capable(widget));

	/*** OpenGL BEGIN ***/

	if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) {
	//	fprintf(stderr, "We're fucked this time.\n");
		return FALSE;
	}
	
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glDrawPixels(WEBCAM_X, WEBCAM_Y-70, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, boo);

	if (gdk_gl_drawable_is_double_buffered(gldrawable))
		gdk_gl_drawable_swap_buffers(gldrawable);
	else
		glFlush();
	
	gdk_gl_drawable_gl_end(gldrawable);
	
	/*** OpenGL END ***/
	
	return TRUE;
}

static void init_cb(GtkWidget *widget, struct input_instance *instance)
{
  //	setupDrawlists(LOCAL);
//	fprintf(stderr,"init_cb\n");
}

static gboolean click_cb(GtkWidget *widget, GdkEventButton *event,
		struct input_instance *instance)
{

	GLfloat w = widget->allocation.width;
	GLfloat h = widget->allocation.height;
	GLfloat aspect;

	if (draw_mode==1) {
		switch (event->button) {
			case 1:
				Debug("F U!\n");
				instance->face.mode = 1;
				easter_count = 5;
				break;
			case 3:
				Debug("should never get here\n");
				instance->face.mode = 2;
				easter_count = 5;
				break;
			default:
				instance->face.mode = 0;
				break;
		}
		return FALSE;
	}

	x_click=(event->x*(640/w));
	x_click=640-x_click;
	y_click=(event->y-(h/14))*(480/(h-(h/14)));
	detection_mode=1;
	//Debug("@@@ x:%d y:%d\n", x_click, y_click);

	gtk_label_set_text(instance->label,
			"Put on the box, then press confirm.");
	if (x_click <= 10) x_click=10;
	if (x_click >= WEBCAM_X-10) x_click=WEBCAM_X-60;
	if (y_click <= 10) y_click=10;
	if (y_click >= WEBCAM_Y-10) y_click=WEBCAM_Y-60;

	return FALSE;
}

static void button_cb(GtkWidget *button, struct input_instance *instance)
{
	if (!draw_mode) { /* transition to face mode */
		if (detection_mode == 0) { /* ignore confirm if no calibrate */
			return;
		}
		setupLighting(instance->widget);
		mode_change = 1;
		gtk_button_set_label(GTK_BUTTON(button), "Calibrate");
		gtk_label_set_label(instance->label,
				"If things get too crazy, click Calibrate.");
	} else { /* transition to calibration mode */
		gtk_label_set_label(instance->label, "Click your face");
		mode_change = 2;
		gtk_button_set_label(GTK_BUTTON(button), "Confirm");
	}
	draw_mode = !draw_mode;
}

static void destroy_cb(GtkWidget *widget, struct crazychat *cc)
{
	cc->features_state = 0;
	destroy_input(cc->input_data);
	cc->input_data = NULL;
}

static void material_set(GtkWidget *entry, guint8 *material)
{
	char *string = gtk_entry_get_text(GTK_ENTRY(entry));
	if (!strcmp(string, "Red")) {
		*material = 0;
	} else if (!strcmp(string, "Dark Brown")) {
		*material = 1;
	} else if (!strcmp(string, "Light Brown")) {
		*material = 2;
	} else if (!strcmp(string, "White")) {
		*material = 3;
	} else if (!strcmp(string, "Green")) {
		*material = 4;
	} else if (!strcmp(string, "Black")) {
		*material = 5;
	}
}