Mercurial > pidgin
changeset 11475:7fab28c991f3
[gaim-migrate @ 13717]
merging gaim-doodle/whiteboard/whatever you like to call it.
Needs some cleanups and doxygen comments, but has basic functionality
committer: Tailor Script <tailor@pidgin.im>
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Fri, 09 Sep 2005 04:40:21 +0000 |
parents | 7e9635b73ed6 |
children | 5d3f8d9e8f92 |
files | src/Makefile.am src/gtkmain.c src/gtkwhiteboard.c src/gtkwhiteboard.h src/protocols/yahoo/Makefile.am src/protocols/yahoo/yahoo.c src/protocols/yahoo/yahoo_doodle.c src/protocols/yahoo/yahoo_doodle.h src/protocols/yahoo/yahoo_filexfer.c src/protocols/yahoo/yahoo_filexfer.h src/prpl.h src/whiteboard.c src/whiteboard.h |
diffstat | 13 files changed, 2195 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/src/Makefile.am Fri Sep 09 04:00:35 2005 +0000 +++ b/src/Makefile.am Fri Sep 09 04:40:21 2005 +0000 @@ -101,7 +101,8 @@ upnp.c \ util.c \ value.c \ - xmlnode.c + xmlnode.c \ + whiteboard.c gaim_coreheaders = \ account.h \ @@ -146,7 +147,8 @@ util.h \ value.h \ version.h \ - xmlnode.h + xmlnode.h \ + whiteboard.h @@ -271,7 +273,8 @@ gtkthemes.c \ gtkutils.c \ idle.c \ - session.c + session.c \ + gtkwhiteboard.c gaim_headers = \ $(dbus_headers) \ @@ -311,7 +314,8 @@ gtkstatusbox.h \ gtkstock.h \ gtkutils.h \ - internal.h + internal.h \ + gtkwhiteboard.h gaimincludedir=$(includedir)/gaim gaiminclude_HEADERS = \
--- a/src/gtkmain.c Fri Sep 09 04:00:35 2005 +0000 +++ b/src/gtkmain.c Fri Sep 09 04:40:21 2005 +0000 @@ -38,6 +38,7 @@ #include "sound.h" #include "status.h" #include "util.h" +#include "whiteboard.h" #include "gtkaccount.h" #include "gtkblist.h" @@ -58,6 +59,7 @@ #include "gtksound.h" #include "gtkutils.h" #include "gtkstock.h" +#include "gtkwhiteboard.h" #if HAVE_SIGNAL_H # include <signal.h> @@ -256,6 +258,7 @@ gaim_request_set_ui_ops(gaim_gtk_request_get_ui_ops()); gaim_sound_set_ui_ops(gaim_gtk_sound_get_ui_ops()); gaim_connections_set_ui_ops(gaim_gtk_connections_get_ui_ops()); + gaim_whiteboard_set_ui_ops(gaim_gtk_whiteboard_get_ui_ops()); gaim_gtk_stock_init(); gaim_gtk_prefs_init();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gtkwhiteboard.c Fri Sep 09 04:40:21 2005 +0000 @@ -0,0 +1,818 @@ +/* + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + * + */ + +// INCLUDES ============================================================================================ + +#include <stdlib.h> + +#include "blist.h" + +#include "gtkwhiteboard.h" + +// GLOBALS ============================================================================================= + +//GList *buttonList = NULL; + +//GdkColor DefaultColor[PALETTE_NUM_COLORS]; + +static gboolean LocalShutdownRequest; + +static int LastX; // Tracks last position of the mouse when drawing +static int LastY; +static int MotionCount; // Tracks how many brush motions made +static int BrushState = BRUSH_STATE_UP; + +static GaimWhiteboardUiOps ui_ops = +{ + gaim_gtk_whiteboard_create, + gaim_gtk_whiteboard_destroy, + gaim_gtk_whiteboard_set_dimensions, + gaim_gtk_whiteboard_draw_brush_point, + gaim_gtk_whiteboard_draw_brush_line, + gaim_gtk_whiteboard_clear +}; + +// FUNCTIONS ============================================================================================ + +GaimWhiteboardUiOps *gaim_gtk_whiteboard_get_ui_ops( void ) +{ + return( &ui_ops ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_create( GaimWhiteboard *wb ) +{ + //g_print( "gaim_gtk_whiteboard_create()\n" ); + + int i; + + GtkWidget *window; + GtkWidget *drawing_area; + + GtkWidget *hbox_palette; + GtkWidget *vbox_palette_above_canvas_and_controls; + GtkWidget *hbox_canvas_and_controls; + GtkWidget *vbox_controls; + + // -------------------------- + // |[][][][palette[][][][][]| + // |------------------------| + // | canvas | con | + // | | trol| + // | | s | + // | | | + // | | | + // -------------------------- + + GtkWidget *clear_button; + GtkWidget *save_button; + + GtkWidget *palette_color_box[PALETTE_NUM_COLORS]; + GdkPixbuf *palette_color_area[PALETTE_NUM_COLORS]; + + GaimGtkWhiteboard *gtkwb = g_new0( GaimGtkWhiteboard, 1 ); + gtkwb->wb = wb; + wb->ui_data = gtkwb; + + // Get dimensions (default?) for the whiteboard canvas + if( wb->prpl_ops && wb->prpl_ops->get_dimensions ) + wb->prpl_ops->get_dimensions( wb, >kwb->width, >kwb->height ); + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtkwb->window = window; + gtk_widget_set_name( window, wb->who ); + + // Try and set window title as the name of the buddy, else just use their username + const char *window_title = gaim_contact_get_alias( gaim_buddy_get_contact( gaim_find_buddy( wb->account, wb->who ) ) ); + if( window_title ) + gtk_window_set_title( ( GtkWindow* )( window ), window_title ); + else + gtk_window_set_title( ( GtkWindow* )( window ), wb->who ); + + gtk_window_set_resizable( ( GtkWindow* )( window ), FALSE ); + + g_signal_connect( G_OBJECT( window ), "destroy", + G_CALLBACK( gaim_gtk_whiteboard_exit ), ( gpointer )( gtkwb ) ); + + // Create vertical box to place palette above the canvas and controls + vbox_palette_above_canvas_and_controls = gtk_vbox_new( FALSE, 0 ); + gtk_container_add( GTK_CONTAINER( window ), vbox_palette_above_canvas_and_controls ); + gtk_widget_show( vbox_palette_above_canvas_and_controls ); + + // Create horizontal box for the palette and all its entries + hbox_palette = gtk_hbox_new( FALSE, 0 ); + gtk_container_add( GTK_CONTAINER( vbox_palette_above_canvas_and_controls ), hbox_palette ); + gtk_widget_show( hbox_palette ); + + // Create horizontal box to seperate the canvas from the controls + hbox_canvas_and_controls = gtk_hbox_new( FALSE, 0 ); + gtk_container_add( GTK_CONTAINER( vbox_palette_above_canvas_and_controls ), hbox_canvas_and_controls ); + gtk_widget_show( hbox_canvas_and_controls ); + + for( i = 0; i < PALETTE_NUM_COLORS; i++ ) + { + //palette_color_area[i] = + + palette_color_box[i] = gtk_image_new_from_pixbuf( NULL ); + gtk_widget_set_size_request( palette_color_box[i], gtkwb->width / PALETTE_NUM_COLORS ,32 ); + gtk_container_add( GTK_CONTAINER( hbox_palette ), palette_color_box[i] ); + + + + gtk_widget_show( palette_color_box[i] ); + } + + // Create the drawing area + drawing_area = gtk_drawing_area_new(); + gtkwb->drawing_area = drawing_area; + gtk_widget_set_size_request( GTK_WIDGET( drawing_area ), gtkwb->width, gtkwb->height ); + gtk_box_pack_start( GTK_BOX( hbox_canvas_and_controls ), drawing_area, TRUE, TRUE, 8 ); + + gtk_widget_show( drawing_area ); + + // Signals used to handle backing pixmap + g_signal_connect( G_OBJECT( drawing_area ), "expose_event", + G_CALLBACK( gaim_gtk_whiteboard_expose_event ), ( gpointer )( gtkwb ) ); + + g_signal_connect( G_OBJECT( drawing_area ), "configure_event", + G_CALLBACK( gaim_gtk_whiteboard_configure_event ), ( gpointer )( gtkwb ) ); + + // Event signals + g_signal_connect( G_OBJECT( drawing_area ), "button_press_event", + G_CALLBACK( gaim_gtk_whiteboard_brush_down ), ( gpointer )( gtkwb ) ); + + g_signal_connect( G_OBJECT( drawing_area ), "motion_notify_event", + G_CALLBACK( gaim_gtk_whiteboard_brush_motion ), ( gpointer )( gtkwb ) ); + + g_signal_connect( G_OBJECT( drawing_area ), "button_release_event", + G_CALLBACK( gaim_gtk_whiteboard_brush_up ), ( gpointer )( gtkwb ) ); + + gtk_widget_set_events( drawing_area, GDK_EXPOSURE_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_HINT_MASK ); + + // Create vertical box to contain the controls + vbox_controls = gtk_vbox_new( FALSE, 0 ); + gtk_container_add( GTK_CONTAINER( hbox_canvas_and_controls ), vbox_controls ); + gtk_widget_show( vbox_controls ); + + // Add a clear button + clear_button = gtk_button_new_with_label( "Clear" ); + gtk_widget_set_size_request( clear_button, 96 ,32 ); + gtk_box_pack_start( GTK_BOX( vbox_controls ), clear_button, FALSE, FALSE, 0 ); + gtk_widget_show( clear_button ); + + g_signal_connect( G_OBJECT( clear_button ), "clicked", + G_CALLBACK( gaim_gtk_whiteboard_button_clear_press ), ( gpointer )( gtkwb ) ); + + // Add a save button + save_button = gtk_button_new_with_label( "Save" ); + gtk_widget_set_size_request( save_button, 96 ,32 ); + gtk_box_pack_start( GTK_BOX( vbox_controls ), save_button, FALSE, FALSE, 8 ); + gtk_widget_show( save_button ); + + g_signal_connect( G_OBJECT( save_button ), "clicked", + G_CALLBACK( gaim_gtk_whiteboard_button_save_press ), ( gpointer )( gtkwb ) ); + + // Make all this (window) visible + gtk_widget_show( window ); + + gaim_gtk_whiteboard_set_canvas_as_icon( gtkwb ); + + // TODO Specific protocol/whiteboard assignment here? Needs a UI Op? + // Set default brush size and color + //ds->brush_size = DOODLE_BRUSH_MEDIUM; + //ds->brush_color = 0; // black +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_destroy( GaimWhiteboard *wb ) +{ + //g_print( "gaim_gtk_whiteboard_destroy()\n" ); + + GaimGtkWhiteboard *gtkwb = wb->ui_data; + + // TODO Ask if user wants to save picture before the session is closed + + // Clear graphical memory + if( gtkwb->pixmap ) + { + //g_print( "---gtkwb->pixmap = %p\n", gtkwb->pixmap ); + g_object_unref( gtkwb->pixmap ); + gtkwb->pixmap = NULL; + } + + if( gtkwb->window ) + { + //g_print( "---gtkwb->window = %p\n", gtkwb->window ); + gtk_widget_destroy( gtkwb->window ); + gtkwb->window = NULL; + } +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_exit( GtkWidget *widget, gpointer data ) +{ + //g_print( "gaim_gtk_whiteboard_exit()\n" ); + + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + GaimWhiteboard *wb = gtkwb->wb; + + if( gtkwb->window && gtkwb->pixmap ) + { + LocalShutdownRequest = TRUE; + + //g_print( "---gtkwb->window = %p\n", gtkwb->window ); + gaim_gtk_whiteboard_destroy( wb ); + } + else + LocalShutdownRequest = FALSE; + + if( gtkwb ) + { + //g_print( "---gtkwb = %p\n", gtkwb ); + g_free( gtkwb ); + + gtkwb = NULL; + wb->ui_data = NULL; + } + + // Destroy whiteboard core, if the local user exited the whiteboard window + if( wb && LocalShutdownRequest ) + { + //g_print( "---wb = %p\n", wb ); + gaim_whiteboard_destroy( wb ); + wb = NULL; + } +} + +// ------------------------------------------------------------------------------------------------------ +/* +// Whiteboard start button on conversation window (move this code to gtkconv? and use new prpl_info member?) +void gaim_gtkwhiteboard_button_start_press( GtkButton *button, gpointer data ) +{ + GaimConversation *conv = data; + GaimAccount *account = gaim_conversation_get_account( conv ); + GaimConnection *gc = gaim_account_get_connection( account ); + char *to = ( char* )( gaim_conversation_get_name( conv ) ); + + // Only handle this if local client requested Doodle session (else local client would have sent one) + GaimWhiteboard *wb = gaim_whiteboard_get( account, to ); + + // Write a local message to this conversation showing that + // a request for a Doodle session has been made + gaim_conv_im_write( GAIM_CONV_IM( conv ), "", _("Sent Doodle request."), + GAIM_MESSAGE_NICK | GAIM_MESSAGE_RECV, time( NULL ) ); + + yahoo_doodle_command_send_request( gc, to ); + yahoo_doodle_command_send_ready( gc, to ); + + // Insert this 'session' in the list. At this point, it's only a requested session. + wb = gaim_whiteboard_create( account, to, DOODLE_STATE_REQUESTING ); +} +*/ +// ------------------------------------------------------------------------------------------------------ + +gboolean gaim_gtk_whiteboard_configure_event( GtkWidget *widget, GdkEventConfigure *event, gpointer data ) +{ + //g_print( "gaim_gtk_whiteboard_configure_event | %s\n", ds->who ); + + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + + GdkPixmap *pixmap = gtkwb->pixmap; + + if( pixmap ) + g_object_unref( pixmap ); + + pixmap = gdk_pixmap_new( widget->window, + widget->allocation.width, + widget->allocation.height, + -1 ); + + gtkwb->pixmap = pixmap; + + gdk_draw_rectangle( pixmap, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height ); + + return( TRUE ); +} + +// ------------------------------------------------------------------------------------------------------ + +gboolean gaim_gtk_whiteboard_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer data ) +{ + //g_print( "gaim_gtk_whiteboard_expose_event | %s\n", ds->who ); + + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + GdkPixmap *pixmap = gtkwb->pixmap; + + gdk_draw_drawable( widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE( widget )], + pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height ); + + return( FALSE ); +} + +// ------------------------------------------------------------------------------------------------------ + +gboolean gaim_gtk_whiteboard_brush_down( GtkWidget *widget, GdkEventButton *event, gpointer data ) +{ + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + //g_print( "gaim_gtk_whiteboard_brush_down | %s\n", gtkwb->wb->who ); + GdkPixmap *pixmap = gtkwb->pixmap; + + GaimWhiteboard *wb = gtkwb->wb; + GList *draw_list = wb->draw_list; + + int *x0 = NULL; + int *y0 = NULL; + + if( BrushState != BRUSH_STATE_UP ) + { + // Potential double-click DOWN to DOWN? + + g_print( "***Bad brush state transition %d to DOWN\n", BrushState ); + + BrushState = BRUSH_STATE_DOWN; + + //return( FALSE ); + } + + BrushState = BRUSH_STATE_DOWN; + + if( event->button == 1 && pixmap != NULL ) + { + // Check if draw_list has contents; if so, clear it + if( draw_list ) + draw_list = gaim_whiteboard_draw_list_destroy( draw_list ); + + x0 = g_new0( int, 1 ); + y0 = g_new0( int, 1 ); + + *x0 = event->x; + *y0 = event->y; + + // Set tracking variables + LastX = *x0; + LastY = *y0; + + MotionCount = 0; + + draw_list = g_list_append( draw_list, ( gpointer )( x0 ) ); + draw_list = g_list_append( draw_list, ( gpointer )( y0 ) ); + + gaim_gtk_whiteboard_draw_brush_point( gtkwb->wb, + event->x, event->y, + 0,5 );//gtkwb->brush_color, gtkwb->brush_size ); NOTE temp const prot uiop + } + + wb->draw_list = draw_list; + + return( TRUE ); +} + +// ------------------------------------------------------------------------------------------------------ + +gboolean gaim_gtk_whiteboard_brush_motion( GtkWidget *widget, GdkEventMotion *event, gpointer data ) +{ + int x; + int y; + int *dx; + int *dy; + + GdkModifierType state; + + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + //g_print( "gaim_gtk_whiteboard_brush_motion | %s\n", gtkwb->wb->who ); + GdkPixmap *pixmap = gtkwb->pixmap; + + GaimWhiteboard *wb = gtkwb->wb; + GList *draw_list = wb->draw_list; + + if( event->is_hint ) + gdk_window_get_pointer( event->window, &x, &y, &state ); + else + { + x = event->x; + y = event->y; + state = event->state; + } + + if( state & GDK_BUTTON1_MASK && pixmap != NULL ) + { + if( ( BrushState != BRUSH_STATE_DOWN ) && ( BrushState != BRUSH_STATE_MOTION ) ) + { + g_print( "***Bad brush state transition %d to MOTION\n", BrushState ); + + BrushState = BRUSH_STATE_MOTION; + + return( FALSE ); + } + BrushState = BRUSH_STATE_MOTION; + + dx = g_new0( int, 1 ); + dy = g_new0( int, 1 ); + + *dx = x - LastX; + *dy = y - LastY; + + MotionCount++; + + // NOTE 100 is a temporary constant for how many deltas/motions in a stroke (needs UI Ops?) + if( MotionCount == 100 ) + { + draw_list = g_list_append( draw_list, ( gpointer )( dx ) ); + draw_list = g_list_append( draw_list, ( gpointer )( dy ) ); + + // Send draw list to prpl draw_list handler + if( gtkwb->wb->prpl_ops && gtkwb->wb->prpl_ops->send_draw_list ) + gtkwb->wb->prpl_ops->send_draw_list( gtkwb->wb, draw_list ); + + // The brush stroke is finished, clear the list for another one + if( draw_list ) + draw_list = gaim_whiteboard_draw_list_destroy( draw_list ); + + int *x0 = g_new0( int, 1 ); + int *y0 = g_new0( int, 1 ); + + *x0 = LastX; + *y0 = LastY; + + // Reset motion tracking + MotionCount = 0; + + draw_list = g_list_append( draw_list, ( gpointer )( x0 ) ); + draw_list = g_list_append( draw_list, ( gpointer )( y0 ) ); + + dx = g_new0( int, 1 ); + dy = g_new0( int, 1 ); + + *dx = x - LastX; + *dy = y - LastY; + } + + draw_list = g_list_append( draw_list, ( gpointer )( dx ) ); + draw_list = g_list_append( draw_list, ( gpointer )( dy ) ); + + gaim_gtk_whiteboard_draw_brush_line( gtkwb->wb, + LastX, LastY, + x, y, + 0, 5 );//gtkwb->brush_color, gtkwb->brush_size ); temp const proto ui ops? + + // Set tracking variables + LastX = x; + LastY = y; + } + + wb->draw_list = draw_list; + + return( TRUE ); +} + +// ------------------------------------------------------------------------------------------------------ + +gboolean gaim_gtk_whiteboard_brush_up( GtkWidget *widget, GdkEventButton *event, gpointer data ) +{ + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + //g_print( "gaim_gtk_whiteboard_brush_up | %s\n", gtkwb->wb->who ); + GdkPixmap *pixmap = gtkwb->pixmap; + + GaimWhiteboard *wb = gtkwb->wb; + GList *draw_list = wb->draw_list; + + if( ( BrushState != BRUSH_STATE_DOWN ) && ( BrushState != BRUSH_STATE_MOTION ) ) + { + g_print( "***Bad brush state transition %d to UP\n", BrushState ); + + BrushState = BRUSH_STATE_UP; + + return( FALSE ); + } + BrushState = BRUSH_STATE_UP; + + if( event->button == 1 && pixmap != NULL ) + { + // If the brush was never moved, express two sets of two deltas + // That's a 'point,' but not for Yahoo! + //if( ( event->x == LastX ) && ( event->y == LastY ) ) + if( MotionCount == 0 ) + { + int index; + + for( index = 0; index < 2; index++ ) // NOTE Yahoo Doodle specific! + { + int *x0 = NULL; + int *y0 = NULL; + + x0 = g_new0( int, 1 ); + y0 = g_new0( int, 1 ); + + draw_list = g_list_append( draw_list, ( gpointer )( x0 ) ); + draw_list = g_list_append( draw_list, ( gpointer )( y0 ) ); + } + } + //else + // MotionCount = 0; + + // Send draw list to prpl draw_list handler + if( gtkwb->wb->prpl_ops && gtkwb->wb->prpl_ops->send_draw_list ) + gtkwb->wb->prpl_ops->send_draw_list( gtkwb->wb, draw_list ); + + gaim_gtk_whiteboard_set_canvas_as_icon( gtkwb ); + + // The brush stroke is finished, clear the list for another one + if( draw_list ) + draw_list = gaim_whiteboard_draw_list_destroy( draw_list ); + + wb->draw_list = draw_list; + } + + return( TRUE ); +} + +// ------------------------------------------------------------------------------------------------------ + +// void gaim_gtk_whiteboard_draw_brush_point( GtkWidget *widget, GaimGtkWhiteboard *gtkwb, +// int x, int y, int color, int size ) +void gaim_gtk_whiteboard_draw_brush_point( GaimWhiteboard *wb, int x, int y, int color, int size ) +{ + //g_print( "goodle_doodle_session_draw_brush | %s\n", ds->who ); + + GaimGtkWhiteboard *gtkwb = wb->ui_data; + GtkWidget *widget = gtkwb->drawing_area; + GdkPixmap *pixmap = gtkwb->pixmap; + + GdkRectangle update_rect; + + update_rect.x = x - size / 2; + update_rect.y = y - size / 2; + update_rect.width = size; + update_rect.height = size; + + // Interpret and convert color + GdkGC *gfx_con = gdk_gc_new( pixmap ); + GdkColor col; + + gaim_gtk_whiteboard_rgb24_to_rgb48( color, &col ); + + gdk_gc_set_rgb_fg_color( gfx_con, &col ); + //gdk_gc_set_rgb_bg_color( gfx_con, &col ); + + // NOTE 5 is a size constant for now... this is because of how poorly the gdk_draw_arc draws small circles + if( size < 5 ) + { + // Draw a rectangle/square + gdk_draw_rectangle( pixmap, + gfx_con, + TRUE, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height ); + } + else + { + // Draw a circle + gdk_draw_arc( pixmap, + gfx_con, + TRUE, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height, + 0, FULL_CIRCLE_DEGREES ); + } + + gtk_widget_queue_draw_area( widget, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height ); + + gdk_gc_unref( gfx_con ); +} + +// ------------------------------------------------------------------------------------------------------ +// Uses Bresenham's algorithm (as provided by Wikipedia) +// void gaim_gtk_whiteboard_draw_brush_line( GtkWidget *widget, GaimGtkWhiteboard *gtkwb, +// int x0, int y0, int x1, int y1, int color, int size ) +void gaim_gtk_whiteboard_draw_brush_line( GaimWhiteboard *wb, int x0, int y0, int x1, int y1, int color, int size ) +{ + int temp; + + int xstep; + int ystep; + + gboolean steep = abs( y1 - y0 ) > abs( x1 - x0 ); + + if( steep ) + { + temp = x0; x0 = y0; y0 = temp; + temp = x1; x1 = y1; y1 = temp; + } + + int dx = abs( x1 - x0 ); + int dy = abs( y1 - y0 ); + + int error = 0; + int derror = dy; + + int x = x0; + int y = y0; + + if( x0 < x1 ) + xstep = 1; + else + xstep = -1; + + if( y0 < y1 ) + ystep = 1; + else + ystep = -1; + + if( steep ) + gaim_gtk_whiteboard_draw_brush_point( wb, y, x, color, size ); + else + gaim_gtk_whiteboard_draw_brush_point( wb, x, y, color, size ); + + while( x != x1 ) + { + x = x + xstep; + error = error + derror; + + if( ( error * 2 ) >= dx ) + { + y = y + ystep; + error = error - dx; + } + + if( steep ) + gaim_gtk_whiteboard_draw_brush_point( wb, y, x, color, size ); + else + gaim_gtk_whiteboard_draw_brush_point( wb, x, y, color, size ); + } +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_set_dimensions( GaimWhiteboard *wb, int width, int height ) +{ + GaimGtkWhiteboard *gtkwb = wb->ui_data; + + gtkwb->width = width; + gtkwb->height = height; +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_clear( GaimWhiteboard *wb ) +{ + GaimGtkWhiteboard *gtkwb = wb->ui_data; + GdkPixmap *pixmap = gtkwb->pixmap; + GtkWidget *drawing_area = gtkwb->drawing_area; + + gdk_draw_rectangle( pixmap, + drawing_area->style->white_gc, + TRUE, + 0, 0, + drawing_area->allocation.width, drawing_area->allocation.height ); + + gtk_widget_queue_draw_area( drawing_area, + 0, 0, + drawing_area->allocation.width, drawing_area->allocation.height ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_button_clear_press( GtkWidget *widget, gpointer data ) +{ + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + + gaim_gtk_whiteboard_clear( gtkwb->wb ); + + gaim_gtk_whiteboard_set_canvas_as_icon( gtkwb ); + + // Do protocol specific clearing procedures + if( gtkwb->wb->prpl_ops && gtkwb->wb->prpl_ops->clear ) + gtkwb->wb->prpl_ops->clear( gtkwb->wb ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_button_save_press( GtkWidget *widget, gpointer data ) +{ + GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); + GdkPixbuf *pixbuf; + + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new ("Save File", + GTK_WINDOW(gtkwb->window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL ); + + //gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER( dialog ), (gboolean)(TRUE) ); + +// if( user_edited_a_new_document ) + { +// gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( dialog ), default_folder_for_saving ); + gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER( dialog ), "whiteboard.jpg" ); + } +// else +// gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), filename_for_existing_document); + + int result = gtk_dialog_run( GTK_DIALOG( dialog ) ); + + if( result == GTK_RESPONSE_ACCEPT ) + { + char *filename; + + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER( dialog ) ); + + gtk_widget_destroy( dialog ); + + // Makes an icon from the whiteboard's canvas 'image' + pixbuf = gdk_pixbuf_get_from_drawable( NULL, + ( GdkDrawable* )( gtkwb->pixmap ), + gdk_drawable_get_colormap( gtkwb->pixmap ), + 0, 0, + 0, 0, + gtkwb->width, gtkwb->height ); + + if( gdk_pixbuf_save( pixbuf, + filename, + "jpeg", + NULL, + "quality", + "100", + NULL ) ) + g_print( "File Saved...\n" ); + else + g_print( "File not Saved... Error\n" ); + } + else + if( result == GTK_RESPONSE_CANCEL ) + { + gtk_widget_destroy( dialog ); + + g_print( "File not Saved... Canceled\n" ); + } +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_set_canvas_as_icon( GaimGtkWhiteboard *gtkwb ) +{ + GdkPixbuf *pixbuf; + + // Makes an icon from the whiteboard's canvas 'image' + pixbuf = gdk_pixbuf_get_from_drawable( NULL, + ( GdkDrawable* )( gtkwb->pixmap ), + gdk_drawable_get_colormap( gtkwb->pixmap ), + 0, 0, + 0, 0, + gtkwb->width, gtkwb->height ); + + gtk_window_set_icon( ( GtkWindow* )( gtkwb->window ), pixbuf ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_gtk_whiteboard_rgb24_to_rgb48( int color_rgb, GdkColor *color ) +{ + color->red = ( color_rgb >> 8 ) | 0xFF; + color->green = ( color_rgb & 0xFF00 ) | 0xFF; + color->blue = ( ( color_rgb & 0xFF ) << 8 ) | 0xFF; +} + +// ------------------------------------------------------------------------------------------------------ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gtkwhiteboard.h Fri Sep 09 04:40:21 2005 +0000 @@ -0,0 +1,89 @@ +/** + * @file gtkwhiteboard.h The GtkGaimWhiteboard frontend object + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + */ + +#ifndef _GAIM_GTKWHITEBOARD_H_ +#define _GAIM_GTKWHITEBOARD_H_ + +// INCLUDES ============================================================================================ +#include "gtkgaim.h" + +#include "whiteboard.h" + +// DEFINES ============================================================================================= + +#define FULL_CIRCLE_DEGREES 23040 + +#define BRUSH_STATE_UP 0 +#define BRUSH_STATE_DOWN 1 +#define BRUSH_STATE_MOTION 2 + +#define PALETTE_NUM_COLORS 7 + +// DATATYPES =========================================================================================== +typedef struct _GaimGtkWhiteboard +{ + GaimWhiteboard *wb; // backend data for this whiteboard + + GtkWidget *window; // Window for the Doodle session + GtkWidget *drawing_area; // Drawing area + + GdkPixmap *pixmap; // Memory for drawing area + + int width; // Canvas width + int height; // Canvas height +} GaimGtkWhiteboard; + +// PROTOTYPES ========================================================================================== + +GaimWhiteboardUiOps *gaim_gtk_whiteboard_get_ui_ops( void ); + +void gaim_gtk_whiteboard_create( GaimWhiteboard *wb ); +void gaim_gtk_whiteboard_destroy( GaimWhiteboard *wb ); +void gaim_gtk_whiteboard_exit( GtkWidget *widget, gpointer data ); + +//void gaim_gtkwhiteboard_button_start_press( GtkButton *button, gpointer data ); + +gboolean gaim_gtk_whiteboard_configure_event( GtkWidget *widget, GdkEventConfigure *event, gpointer data ); +gboolean gaim_gtk_whiteboard_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer data ); + +gboolean gaim_gtk_whiteboard_brush_down( GtkWidget *widget, GdkEventButton *event, gpointer data ); +gboolean gaim_gtk_whiteboard_brush_motion( GtkWidget *widget, GdkEventMotion *event, gpointer data ); +gboolean gaim_gtk_whiteboard_brush_up( GtkWidget *widget, GdkEventButton *event, gpointer data ); + +void gaim_gtk_whiteboard_draw_brush_point( GaimWhiteboard *wb, + int x, int y, int color, int size ); +void gaim_gtk_whiteboard_draw_brush_line( GaimWhiteboard *wb, + int x0, int y0, int x1, int y1, int color, int size ); + +void gaim_gtk_whiteboard_set_dimensions( GaimWhiteboard *wb, int width, int height ); +void gaim_gtk_whiteboard_clear( GaimWhiteboard *wb ); + +void gaim_gtk_whiteboard_button_clear_press( GtkWidget *widget, gpointer data ); +void gaim_gtk_whiteboard_button_save_press( GtkWidget *widget, gpointer data ); + +void gaim_gtk_whiteboard_set_canvas_as_icon( GaimGtkWhiteboard *gtkwb ); + +void gaim_gtk_whiteboard_rgb24_to_rgb48( int color_rgb, GdkColor *color ); + +#endif // _GAIM_GTKWHITEBOARD_H_
--- a/src/protocols/yahoo/Makefile.am Fri Sep 09 04:00:35 2005 +0000 +++ b/src/protocols/yahoo/Makefile.am Fri Sep 09 04:40:21 2005 +0000 @@ -18,6 +18,8 @@ yahoo_friend.c \ yahoo_packet.h \ yahoo_packet.c \ + yahoo_doodle.h \ + yahoo_doodle.c \ yahoo_picture.c \ yahoo_picture.h \ yahoo_profile.c \
--- a/src/protocols/yahoo/yahoo.c Fri Sep 09 04:00:35 2005 +0000 +++ b/src/protocols/yahoo/yahoo.c Fri Sep 09 04:40:21 2005 +0000 @@ -46,6 +46,7 @@ #include "yahoo_auth.h" #include "yahoo_filexfer.h" #include "yahoo_picture.h" +#include "yahoo_doodle.h" extern char *yahoo_crypt(const char *, const char *); @@ -664,6 +665,8 @@ GSList *l = pkt->hash; GSList *list = NULL; struct _yahoo_im *im = NULL; + + char imv[16]; if (pkt->status <= 1 || pkt->status == 5) { while (l) { @@ -687,12 +690,35 @@ if (im) im->msg = pair->value; } + // IMV key + if (pair->key == 63) + { + strcpy( imv, pair->value ); + } l = l->next; } } else if (pkt->status == 2) { gaim_notify_error(gc, NULL, _("Your Yahoo! message did not get sent."), NULL); } + + // Check for the Doodle IMV + if( !strcmp( imv, "doodle;11" ) ) + { + g_print( "'doodle;11' found in chat packet\n" ); + + GaimWhiteboard *wb = gaim_whiteboard_get_session( gc->account, im->from ); + + // If a Doodle session doesn't exist between this user + if( wb == NULL ) + { + g_print( "Creating new whiteboard for chat packet request\n" ); + wb = gaim_whiteboard_create( gc->account, im->from, DOODLE_STATE_REQUESTED ); + + yahoo_doodle_command_send_request( gc, im->from ); + yahoo_doodle_command_send_ready( gc, im->from ); + } + } for (l = list; l; l = l->next) { YahooFriend *f; @@ -2057,6 +2083,7 @@ yahoo_process_stealth(gc, pkt); break; case YAHOO_SERVICE_P2PFILEXFER: + yahoo_process_p2pfilexfer( gc, pkt ); // This case had no break and continued; thus keeping it this way. case YAHOO_SERVICE_FILETRANSFER: yahoo_process_filetransfer(gc, pkt); break; @@ -2964,7 +2991,14 @@ yahoo_packet_hash_str(pkt, 97, "1"); yahoo_packet_hash_str(pkt, 14, msg2); - yahoo_packet_hash_str(pkt, 63, ";0"); /* IMvironment */ + // If this message is to a user who is also Doodling with the local user, + // format the chat packet with the correct IMV information (thanks Yahoo!) + GaimWhiteboard *wb = gaim_whiteboard_get_session(gc->account, (char*)who); + if (wb) + yahoo_packet_hash_str(pkt, 63, "doodle;11"); + else + yahoo_packet_hash_str(pkt, 63, ";0"); // IMvironment + yahoo_packet_hash_str(pkt, 64, "0"); /* no idea */ yahoo_packet_hash_str(pkt, 1002, "1"); /* no idea, Yahoo 6 or later only it seems */ if (!yd->picture_url) @@ -3508,8 +3542,23 @@ GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_PRPL_ONLY, "prpl-yahoo", yahoogaim_cmd_buzz, _("buzz: Buzz a contact to get their attention"), NULL); + + gaim_cmd_register("doodle", "", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-yahoo", yahoo_doodle_gaim_cmd_start, + _("doodle: Request user to start a Doodle session"), NULL); } +static GaimWhiteboardPrplOps yahoo_whiteboard_prpl_ops = +{ + yahoo_doodle_start, + yahoo_doodle_end, + yahoo_doodle_get_dimensions, + NULL, + yahoo_doodle_send_draw_list, + yahoo_doodle_clear +}; + static GaimPluginProtocolInfo prpl_info = { OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC, @@ -3568,7 +3617,8 @@ yahoo_roomlist_cancel, yahoo_roomlist_expand_category, NULL, /* can_receive_file */ - yahoo_send_file + yahoo_send_file, + &yahoo_whiteboard_prpl_ops }; static GaimPluginInfo info =
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/yahoo/yahoo_doodle.c Fri Sep 09 04:40:21 2005 +0000 @@ -0,0 +1,728 @@ +/* + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + * + */ + +// INCLUDES ============================================================================================ + +#include "internal.h" + +#include "account.h" +#include "accountopt.h" +#include "blist.h" +#include "cipher.h" +#include "cmds.h" +#include "debug.h" +#include "notify.h" +#include "privacy.h" +#include "prpl.h" +#include "proxy.h" +#include "request.h" +#include "server.h" +#include "util.h" +#include "version.h" + +#include "yahoo.h" +#include "yahoo_packet.h" +#include "yahoo_friend.h" +#include "yahoochat.h" +#include "ycht.h" +#include "yahoo_auth.h" +#include "yahoo_filexfer.h" +#include "yahoo_picture.h" + +#include "whiteboard.h" +#include "yahoo_doodle.h" + +// GLOBALS ============================================================================================= + +const int DefaultColorRGB24[] = +{ + DOODLE_COLOR_RED, + DOODLE_COLOR_ORANGE, + DOODLE_COLOR_YELLOW, + DOODLE_COLOR_GREEN, + DOODLE_COLOR_CYAN, + DOODLE_COLOR_BLUE, + DOODLE_COLOR_VIOLET, + DOODLE_COLOR_PURPLE, + DOODLE_COLOR_TAN, + DOODLE_COLOR_BROWN, + DOODLE_COLOR_BLACK, + DOODLE_COLOR_GREY, + DOODLE_COLOR_WHITE +}; + +// FUNCTIONS ============================================================================================ + +GaimCmdRet yahoo_doodle_gaim_cmd_start( GaimConversation *conv, const char *cmd, char **args, char **error, void *data ) +{ + if( *args && args[0] ) + return( GAIM_CMD_RET_FAILED ); + + GaimAccount *account = gaim_conversation_get_account( conv ); + GaimConnection *gc = gaim_account_get_connection( account ); + char *to = ( char* )( gaim_conversation_get_name( conv ) ); + GaimWhiteboard *wb = gaim_whiteboard_get_session( account, to ); + + // NOTE Functionalize this code? + + if( wb == NULL ) + { + // Insert this 'session' in the list. At this point, it's only a requested session. + wb = gaim_whiteboard_create( account, to, DOODLE_STATE_REQUESTING ); + } + //else + // ; // NOTE Perhaps some careful handling of remote assumed established sessions + + yahoo_doodle_command_send_request( gc, to ); + yahoo_doodle_command_send_ready( gc, to ); + + // Write a local message to this conversation showing that + // a request for a Doodle session has been made + gaim_conv_im_write( GAIM_CONV_IM( conv ), "", _("Sent Doodle request."), + GAIM_MESSAGE_NICK | GAIM_MESSAGE_RECV, time( NULL ) ); + + return( GAIM_CMD_RET_OK ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_process( GaimConnection *gc, char *me, char *from, char *command, char *message ) +{ +// g_print( "-----------------------------------------------\n" ); +// g_print( "%s : %s : %s -> %s\n", from, imv, command, message ); + + // Now check to see what sort of Doodle message it is + int cmd = atoi( command ); + + switch( cmd ) + { + case DOODLE_CMD_REQUEST: + { + yahoo_doodle_command_got_request( gc, from ); + } break; + + case DOODLE_CMD_READY: + { + yahoo_doodle_command_got_ready( gc, from ); + } break; + + case DOODLE_CMD_CLEAR: + { + yahoo_doodle_command_got_clear( gc, from ); + } break; + + case DOODLE_CMD_DRAW: + { + yahoo_doodle_command_got_draw( gc, from, message ); + } break; + + case DOODLE_CMD_EXTRA: + { + yahoo_doodle_command_got_extra( gc, from, message ); + } break; + + case DOODLE_CMD_CONFIRM: + { + yahoo_doodle_command_got_confirm( gc, from ); + } break; + } +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_got_request( GaimConnection *gc, char *from ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Got REQUEST (%s)\n", from ); + + GaimAccount *account = gaim_connection_get_account( gc ); + + // Only handle this if local client requested Doodle session (else local client would have sent one) + GaimWhiteboard *wb = gaim_whiteboard_get_session( account, from ); + + // If a session with the remote user doesn't exist + if( wb == NULL ) + { + // Ask user if he/she wishes to accept the request for a doodle session + // TODO Ask local user to start Doodle session with remote user + // NOTE This if/else statement won't work right--must use dialog results + + /* char dialog_message[64]; + g_sprintf( dialog_message, "%s is requesting to start a Doodle session with you.", from ); + + gaim_notify_message( NULL, GAIM_NOTIFY_MSG_INFO, "Doodle", + dialog_message, NULL, NULL, NULL ); + */ + + wb = gaim_whiteboard_create( account, from, DOODLE_STATE_REQUESTED ); + + yahoo_doodle_command_send_request( gc, from ); + } + + // TODO Might be required to clear the canvas of an existing doodle session at this point +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_got_ready( GaimConnection *gc, char *from ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Got READY (%s)\n", from ); + + GaimAccount *account = gaim_connection_get_account( gc ); + + // Only handle this if local client requested Doodle session (else local client would have sent one) + GaimWhiteboard *wb = gaim_whiteboard_get_session( account, from ); + + if( wb == NULL ) + return; + + if( wb->state == DOODLE_STATE_REQUESTING ) + { + gaim_whiteboard_start( wb ); + + wb->state = DOODLE_STATE_ESTABLISHED; + + yahoo_doodle_command_send_confirm( gc, from ); + } + + if( wb->state == DOODLE_STATE_ESTABLISHED ) + { + // Ask whether to save picture too + + gaim_whiteboard_clear( wb ); + } + + // NOTE Not sure about this... I am trying to handle if the remote user already + // thinks we're in a session with them (when their chat message contains the doodle;11 imv key) + if( wb->state == DOODLE_STATE_REQUESTED ) + { + g_print( "Hmmmm\n" ); + + //gaim_whiteboard_start( wb ); + yahoo_doodle_command_send_request( gc, from ); + } +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_got_draw( GaimConnection *gc, char *from, char *message ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Got DRAW (%s)\n", from ); + + g_print( "Draw Message: %s\n", message ); + + GaimAccount *account = gaim_connection_get_account( gc ); + + // Only handle this if local client requested Doodle session (else local client would have sent one) + GaimWhiteboard *wb = gaim_whiteboard_get_session( account, from ); + + if( wb == NULL ) + return; + + // TODO Functionalize + // Convert drawing packet message to an integer list + + int *token = NULL; + int length = strlen( message ); + char *token_end; + + GList *d_list = NULL; // a local list of drawing info + + // Check to see if the message begans and ends with quotes + if( ( message[0] != '\"' ) || ( message[length - 1] != '\"' ) ) + return; + + // Truncate the quotations off of our message (why the hell did they add them anyways!?) + message[length - 1] = ','; + message = message + 1; + + // Traverse and extract all integers divided by commas + while( ( token_end = strchr( message, ',' ) ) ) + { + token_end[0] = 0; + + token = g_new0( int, 1 ); + + *token = atoi( message ); + + d_list = g_list_append( d_list, ( gpointer )( token ) ); + + message = token_end + 1; + } + + yahoo_doodle_draw_stroke( wb, d_list ); + + //goodle_doodle_session_set_canvas_as_icon( ds ); + + // Remove that shit + int *n = NULL; + GList *l = d_list; + while( l ) + { + n = l->data; + + g_free( n ); + + l = l->next; + } + + g_list_free( d_list ); + d_list = NULL; +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_got_clear( GaimConnection *gc, char *from ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Got CLEAR (%s)\n", from ); + + GaimAccount *account = gaim_connection_get_account( gc ); + + // Only handle this if local client requested Doodle session (else local client would have sent one) + GaimWhiteboard *wb = gaim_whiteboard_get_session( account, from ); + + if( wb == NULL ) + return; + + if( wb->state == DOODLE_STATE_ESTABLISHED ) + { + // TODO Ask user whether to save the image before clearing it + + gaim_whiteboard_clear( wb ); + } +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_got_extra( GaimConnection *gc, char *from, char *message ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Got EXTRA (%s)\n", from ); + + // I do not like these 'extra' features, so I'll only handle them in one way, + // which is returning them with the command/packet to turn them off + + yahoo_doodle_command_send_extra( gc, from, DOODLE_EXTRA_NONE ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_got_confirm( GaimConnection *gc, char *from ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Got CONFIRM (%s)\n", from ); + + // Get the doodle session + GaimAccount *account = gaim_connection_get_account( gc ); + + // Only handle this if local client requested Doodle session (else local client would have sent one) + GaimWhiteboard *wb = gaim_whiteboard_get_session( account, from ); + + if( wb == NULL ) + return; + + // TODO Combine the following IF's? + + // Check if we requested a doodle session + if( wb->state == DOODLE_STATE_REQUESTING ) + { + wb->state = DOODLE_STATE_ESTABLISHED; + + gaim_whiteboard_start( wb ); + + yahoo_doodle_command_send_confirm( gc, from ); + } + + // Check if we accepted a request for a doodle session + if( wb->state == DOODLE_STATE_REQUESTED ) + { + wb->state = DOODLE_STATE_ESTABLISHED; + + gaim_whiteboard_start( wb ); + } +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_got_shutdown( GaimConnection *gc, char *from ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Got SHUTDOWN (%s)\n", from ); + + GaimAccount *account = gaim_connection_get_account( gc ); + + // Only handle this if local client requested Doodle session (else local client would have sent one) + GaimWhiteboard *wb = gaim_whiteboard_get_session( account, from ); + + // TODO Ask if user wants to save picture before the session is closed + + // If this session doesn't exist, don't try and kill it + if( wb == NULL ) + return; + else + { + gaim_whiteboard_destroy( wb ); + + //yahoo_doodle_command_send_shutdown( gc, from ); + } +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_send_request( GaimConnection *gc, char *to ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Sent REQUEST (%s)\n", to ); + + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + // Make and send an acknowledge (ready) Doodle packet + pkt = yahoo_packet_new( YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, 0 ); + yahoo_packet_hash_str( pkt, 49, "IMVIRONMENT" ); + yahoo_packet_hash_str( pkt, 1, gaim_account_get_username( gc->account ) ); + yahoo_packet_hash_str( pkt, 14, "1" ); + yahoo_packet_hash_str( pkt, 13, "1" ); + yahoo_packet_hash_str( pkt, 5, to ); + yahoo_packet_hash_str( pkt, 63, "doodle;11" ); + yahoo_packet_hash_str( pkt, 64, "1" ); + yahoo_packet_hash_str( pkt, 1002, "1" ); + + yahoo_packet_send_and_free( pkt, yd ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_send_ready( GaimConnection *gc, char *to ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Sent READY (%s)\n", to ); + + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + // Make and send a request to start a Doodle session + pkt = yahoo_packet_new( YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, 0 ); + yahoo_packet_hash_str( pkt, 49, "IMVIRONMENT" ); + yahoo_packet_hash_str( pkt, 1, gaim_account_get_username( gc->account ) ); + yahoo_packet_hash_str( pkt, 14, "" ); + yahoo_packet_hash_str( pkt, 13, "0" ); + yahoo_packet_hash_str( pkt, 5, to ); + yahoo_packet_hash_str( pkt, 63, "doodle;11" ); + yahoo_packet_hash_str( pkt, 64, "0" ); + yahoo_packet_hash_str( pkt, 1002, "1" ); + + yahoo_packet_send_and_free( pkt, yd ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_send_draw( GaimConnection *gc, char *to, char *message ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Sent DRAW (%s)\n", to ); + + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + // Make and send a drawing packet + pkt = yahoo_packet_new( YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, 0 ); + yahoo_packet_hash_str( pkt, 49, "IMVIRONMENT" ); + yahoo_packet_hash_str( pkt, 1, gaim_account_get_username( gc->account ) ); + yahoo_packet_hash_str( pkt, 14, message ); + yahoo_packet_hash_str( pkt, 13, "3" ); + yahoo_packet_hash_str( pkt, 5, to ); + yahoo_packet_hash_str( pkt, 63, "doodle;11" ); + yahoo_packet_hash_str( pkt, 64, "1" ); + yahoo_packet_hash_str( pkt, 1002, "1" ); + + yahoo_packet_send_and_free( pkt, yd ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_send_clear( GaimConnection *gc, char *to ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Sent CLEAR (%s)\n", to ); + + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + // Make and send a request to clear packet + pkt = yahoo_packet_new( YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, 0 ); + yahoo_packet_hash_str( pkt, 49, "IMVIRONMENT" ); + yahoo_packet_hash_str( pkt, 1, gaim_account_get_username( gc->account ) ); + yahoo_packet_hash_str( pkt, 14, " " ); + yahoo_packet_hash_str( pkt, 13, "2" ); + yahoo_packet_hash_str( pkt, 5, to ); + yahoo_packet_hash_str( pkt, 63, "doodle;11" ); + yahoo_packet_hash_str( pkt, 64, "1" ); + yahoo_packet_hash_str( pkt, 1002, "1" ); + + yahoo_packet_send_and_free( pkt, yd ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_send_extra( GaimConnection *gc, char *to, char *message ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Sent EXTRA (%s)\n", to ); + + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + // Send out a request to use a specified 'extra' feature (message) + pkt = yahoo_packet_new( YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, 0 ); + yahoo_packet_hash_str( pkt, 49, "IMVIRONMENT" ); + yahoo_packet_hash_str( pkt, 1, gaim_account_get_username( gc->account ) ); + yahoo_packet_hash_str( pkt, 14, message ); + yahoo_packet_hash_str( pkt, 13, "4" ); + yahoo_packet_hash_str( pkt, 5, to ); + yahoo_packet_hash_str( pkt, 63, "doodle;11" ); + yahoo_packet_hash_str( pkt, 64, "1" ); + yahoo_packet_hash_str( pkt, 1002, "1" ); + + yahoo_packet_send_and_free( pkt, yd ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_send_confirm( GaimConnection *gc, char *to ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Sent CONFIRM (%s)\n", to ); + + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + // Send ready packet (that local client accepted and is ready) + pkt = yahoo_packet_new( YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, 0 ); + yahoo_packet_hash_str( pkt, 49, "IMVIRONMENT" ); + yahoo_packet_hash_str( pkt, 1, ( char* )( gaim_account_get_username( gc->account ) ) ); + yahoo_packet_hash_str( pkt, 14, "1" ); + yahoo_packet_hash_str( pkt, 13, "5" ); + yahoo_packet_hash_str( pkt, 5, to ); + yahoo_packet_hash_str( pkt, 63, "doodle;11" ); + yahoo_packet_hash_str( pkt, 64, "1" ); + yahoo_packet_hash_str( pkt, 1002, "1" ); + + yahoo_packet_send_and_free( pkt, yd ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_command_send_shutdown( GaimConnection *gc, char *to ) +{ + g_print( "-----------------------------------------------\n" ); + g_print( "Sent SHUTDOWN (%s)\n", to ); + + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + // Declare that you are ending the Doodle session + pkt = yahoo_packet_new( YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, 0 ); + yahoo_packet_hash_str( pkt, 49, "IMVIRONMENT" ); + yahoo_packet_hash_str( pkt, 1, gaim_account_get_username( gc->account ) ); + yahoo_packet_hash_str( pkt, 14, "" ); + yahoo_packet_hash_str( pkt, 13, "0" ); + yahoo_packet_hash_str( pkt, 5, to ); + yahoo_packet_hash_str( pkt, 63, ";0" ); + yahoo_packet_hash_str( pkt, 64, "0" ); + yahoo_packet_hash_str( pkt, 1002, "1" ); + + yahoo_packet_send_and_free( pkt, yd ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_start( GaimWhiteboard *wb ) +{ + //g_print( "yahoo_doodle_start()\n" ); + + doodle_session *ds = g_new0( doodle_session, 1 ); + + // Set default brush size and color + ds->brush_size = DOODLE_BRUSH_MEDIUM; + ds->brush_color = 0; // black + + wb->proto_data = ds; +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_end( GaimWhiteboard *wb ) +{ + //g_print( "yahoo_doodle_end()\n" ); + + GaimConnection *gc = gaim_account_get_connection( wb->account ); + + yahoo_doodle_command_send_shutdown( gc, wb->who ); + + doodle_session *ds = wb->proto_data; + if( ds ) + g_free( ds ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_get_dimensions( GaimWhiteboard *wb, int *width, int *height ) +{ + // Standard Doodle canvases are of one size: 368x256 + *width = DOODLE_CANVAS_WIDTH; + *height = DOODLE_CANVAS_HEIGHT; +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_send_draw_list( GaimWhiteboard *wb, GList *draw_list ) +{ + //g_print( "yahoo_doodle_send_draw_list()\n" ); + + doodle_session *ds = wb->proto_data; + char *message = yahoo_doodle_build_draw_string( ds, draw_list ); + + if( message ) + yahoo_doodle_command_send_draw( wb->account->gc, wb->who, message ); + +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_clear( GaimWhiteboard *wb ) +{ + yahoo_doodle_command_send_clear( wb->account->gc, wb->who ); +} + +// ------------------------------------------------------------------------------------------------------ + +void yahoo_doodle_draw_stroke( GaimWhiteboard *wb, GList *draw_list ) +{ + // Traverse through the list and draw the points and lines + + //g_print( "Drawing: color=%d, size=%d, (%d,%d)\n", brush_color, brush_size, x, y ); + + GList *l = draw_list; + + int *n = NULL; + + int brush_color; + int brush_size; + int x; + int y; + + int dx, dy; + + n = l->data; brush_color = *n; l = l->next; + n = l->data; brush_size = *n; l = l->next; + n = l->data; x = *n; l = l->next; + n = l->data; y = *n; l = l->next; + + int count = 0; + + // Pray this works and pray that the list has an even number of elements + while( l ) + { + count++; + + n = l->data; dx = *n; l = l->next; + n = l->data; dy = *n; l = l->next; + + gaim_whiteboard_draw_line( wb, + x, y, + x + dx, y + dy, + brush_color, brush_size ); + + x = x + dx; + y = y + dy; + } + + //g_print( "Counted %d deltas\n", count ); +} + +// ------------------------------------------------------------------------------------------------------ + +char *yahoo_doodle_build_draw_string( doodle_session *ds, GList *draw_list ) +{ + //g_print( "yahoo_doodle_build_draw_string()\n" ); + + if( draw_list == NULL ) + return( NULL ); + + GList *l = draw_list; + + int *n = NULL; + + static char message[1024]; // Hope that 1024 is enough + char token_string[16]; // Token string extracted from draw list + + strcpy( message, "\"" ); + + sprintf( token_string, "%d,%d,", ds->brush_color, ds->brush_size ); + strcat( message, token_string ); + + // Pray this works and pray that the list has an even number of elements + while( l ) + { + n = l->data; + + sprintf( token_string, "%d,", *n ); + + // This check prevents overflow + if( ( strlen( message ) + strlen( token_string ) ) < 1024 ) + strcat( message, token_string ); + else + break; + + l = l->next; + } + + message[strlen( message ) - 1] = '\"'; + //message[strlen( message )] = 0; + //message[511] = 0; + + //g_print( "Draw Message: %s\n", message ); + + return( message ); +} + +// ------------------------------------------------------------------------------------------------------ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/yahoo/yahoo_doodle.h Fri Sep 09 04:40:21 2005 +0000 @@ -0,0 +1,124 @@ +/** + * @file yahoo_doodle.h The Yahoo! protocol plugin Doodle IMVironment object + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + */ + +#ifndef _YAHOO_DOODLE_H_ +#define _YAHOO_DOODLE_H_ + +// INCLUDES ============================================================================================ +#include "whiteboard.h" +#include "cmds.h" + +// DEFINES ============================================================================================= + +// Doodle communication commands +#define DOODLE_CMD_REQUEST 0 +#define DOODLE_CMD_READY 1 +#define DOODLE_CMD_CLEAR 2 +#define DOODLE_CMD_DRAW 3 +#define DOODLE_CMD_EXTRA 4 +#define DOODLE_CMD_CONFIRM 5 + +// Doodle communication command for shutting down (also 0) +#define DOODLE_CMD_SHUTDOWN DOODLE_CMD_REQUEST + +#define DOODLE_EXTRA_NONE "\"1\"" +#define DOODLE_EXTRA_TICTACTOE "\"3\"" +#define DOODLE_EXTRA_DOTS "\"2\"" + +// Doodle session states +#define DOODLE_STATE_REQUESTING 0 +#define DOODLE_STATE_REQUESTED 1 +#define DOODLE_STATE_ESTABLISHED 2 + +// Doodle canvas dimensions +#define DOODLE_CANVAS_WIDTH 368 +#define DOODLE_CANVAS_HEIGHT 256 + +// Doodle color codes (most likely RGB) +#define DOODLE_COLOR_RED 13369344 +#define DOODLE_COLOR_ORANGE 16737792 +#define DOODLE_COLOR_YELLOW 15658496 +#define DOODLE_COLOR_GREEN 52224 +#define DOODLE_COLOR_CYAN 52428 +#define DOODLE_COLOR_BLUE 204 +#define DOODLE_COLOR_VIOLET 5381277 +#define DOODLE_COLOR_PURPLE 13369548 +#define DOODLE_COLOR_TAN 12093547 +#define DOODLE_COLOR_BROWN 5256485 +#define DOODLE_COLOR_BLACK 0 +#define DOODLE_COLOR_GREY 11184810 +#define DOODLE_COLOR_WHITE 16777215 + +#define PALETTE_NUM_OF_COLORS 12 + +// Doodle brush sizes (most likely variable) +#define DOODLE_BRUSH_SMALL 2 +#define DOODLE_BRUSH_MEDIUM 5 +#define DOODLE_BRUSH_LARGE 10 + +#define DOODLE_MAX_BRUSH_MOTIONS 100 + +// DATATYPES =========================================================================================== +typedef struct _doodle_session +{ + int brush_size; // Size of drawing brush + int brush_color; // Color of drawing brush +} doodle_session; + +// PROTOTYPES ========================================================================================== + +void dummy_func( void ); + +GaimCmdRet yahoo_doodle_gaim_cmd_start( GaimConversation *conv, const char *cmd, char **args, + char **error, void *data ); + +void yahoo_doodle_process( GaimConnection *gc, char *me, char *from, char *command, char *message ); + +void yahoo_doodle_command_got_request( GaimConnection *gc, char *from ); +void yahoo_doodle_command_got_ready( GaimConnection *gc, char *from ); +void yahoo_doodle_command_got_draw( GaimConnection *gc, char *from, char *message ); +void yahoo_doodle_command_got_clear( GaimConnection *gc, char *from ); +void yahoo_doodle_command_got_extra( GaimConnection *gc, char *from, char *message ); +void yahoo_doodle_command_got_confirm( GaimConnection *gc, char *from ); +void yahoo_doodle_command_got_shutdown( GaimConnection *gc, char *from ); + +void yahoo_doodle_command_send_request( GaimConnection *gc, char *to ); +void yahoo_doodle_command_send_ready( GaimConnection *gc, char *to ); +void yahoo_doodle_command_send_draw( GaimConnection *gc, char *to, char *message ); +void yahoo_doodle_command_send_clear( GaimConnection *gc, char *to ); +void yahoo_doodle_command_send_extra( GaimConnection *gc, char *to, char *message ); +void yahoo_doodle_command_send_confirm( GaimConnection *gc, char *to ); +void yahoo_doodle_command_send_shutdown( GaimConnection *gc, char *to ); + +void yahoo_doodle_start( GaimWhiteboard *wb ); +void yahoo_doodle_end( GaimWhiteboard *wb ); +void yahoo_doodle_get_dimensions( GaimWhiteboard *wb, int *width, int *height ); +void yahoo_doodle_send_draw_list( GaimWhiteboard *wb, GList *draw_list ); +void yahoo_doodle_clear( GaimWhiteboard *wb ); + +void yahoo_doodle_draw_stroke( GaimWhiteboard *wb, GList *draw_list ); +char *yahoo_doodle_build_draw_string( doodle_session *ds, GList *draw_list ); + + +#endif // _YAHOO_DOODLE_H_
--- a/src/protocols/yahoo/yahoo_filexfer.c Fri Sep 09 04:00:35 2005 +0000 +++ b/src/protocols/yahoo/yahoo_filexfer.c Fri Sep 09 04:40:21 2005 +0000 @@ -30,6 +30,7 @@ #include "yahoo.h" #include "yahoo_packet.h" #include "yahoo_filexfer.h" +#include "yahoo_doodle.h" @@ -351,6 +352,64 @@ xfer->data = NULL; } +void yahoo_process_p2pfilexfer( GaimConnection *gc, struct yahoo_packet *pkt ) +{ + GSList *l = pkt->hash; + + char *me = NULL; + char *from = NULL; + char *service = NULL; + char *message = NULL; + char *command = NULL; + char *imv = NULL; + char *unknown = NULL; + + // Get all the necessary values from this new packet + while( l ) + { + struct yahoo_pair *pair = l->data; + + if( pair->key == 5 ) // Get who the packet is for + me = pair->value; + + if( pair->key == 4 ) // Get who the packet is from + from = pair->value; + + if( pair->key == 49 ) // Get the type of service + service = pair->value; + + if( pair->key == 14 ) // Get the 'message' of the packet + message = pair->value; + + if( pair->key == 13 ) // Get the command associated with this packet + command = pair->value; + + if( pair->key == 63 ) // IMVironment name and version + imv = pair->value; + + if( pair->key == 64 ) // Not sure, but it does vary with initialization of Doodle + unknown = pair->value; // So, I'll keep it (for a little while atleast) + + l = l->next; + } + + // If this packet is an IMVIRONMENT, handle it accordingly + if( !strcmp( service, "IMVIRONMENT" ) ) + { + // Check for a Doodle packet and handle it accordingly + if( !strcmp( imv, "doodle;11" ) ) + yahoo_doodle_process( gc, me, from, command, message ); + + // If an IMVIRONMENT packet comes without a specific imviroment name + if( !strcmp( imv, ";0" ) ) + { + // It is unfortunately time to close all IMVironments with remote client + yahoo_doodle_command_got_shutdown( gc, from ); + } + + } +} + void yahoo_process_filetransfer(GaimConnection *gc, struct yahoo_packet *pkt) { char *from = NULL;
--- a/src/protocols/yahoo/yahoo_filexfer.h Fri Sep 09 04:00:35 2005 +0000 +++ b/src/protocols/yahoo/yahoo_filexfer.h Fri Sep 09 04:40:21 2005 +0000 @@ -21,6 +21,11 @@ */ /** + * Process ymsg events, particular IMViroments like Doodle + */ +void yahoo_process_p2pfilexfer( GaimConnection *gc, struct yahoo_packet *pkt ); + +/** * Process ymsg file receive invites. */ void yahoo_process_filetransfer(GaimConnection *gc, struct yahoo_packet *pkt);
--- a/src/prpl.h Fri Sep 09 04:00:35 2005 +0000 +++ b/src/prpl.h Fri Sep 09 04:40:21 2005 +0000 @@ -84,6 +84,7 @@ #include "plugin.h" #include "roomlist.h" #include "status.h" +#include "whiteboard.h" struct proto_chat_entry { char *label; @@ -304,6 +305,8 @@ /* file transfer callbacks */ gboolean (*can_receive_file)(GaimConnection *, const char *who); void (*send_file)(GaimConnection *, const char *who, const char *filename); + + GaimWhiteboardPrplOps *whiteboard_prpl_ops; }; #define GAIM_IS_PROTOCOL_PLUGIN(plugin) \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/whiteboard.c Fri Sep 09 04:40:21 2005 +0000 @@ -0,0 +1,216 @@ +/* + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + * + */ + +// INCLUDES ============================================================================================= + +#include <string.h> + +#include "whiteboard.h" +#include "prpl.h" + +// DATATYPES ============================================================================================ + +// GLOBALS ============================================================================================== + +static GaimWhiteboardUiOps *whiteboard_ui_ops = NULL; +//static GaimWhiteboardPrplOps *whiteboard_prpl_ops = NULL; + +static GList *wbList = NULL; + +//static gboolean auto_accept = TRUE; + +// FUNCTIONS ============================================================================================ + +void gaim_whiteboard_set_ui_ops( GaimWhiteboardUiOps *ops ) +{ + whiteboard_ui_ops = ops; +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_whiteboard_set_prpl_ops( GaimWhiteboard *wb, GaimWhiteboardPrplOps *ops ) +{ + wb->prpl_ops = ops; +} + +// ------------------------------------------------------------------------------------------------------ + +GaimWhiteboard *gaim_whiteboard_create( GaimAccount *account, char *who, int state ) +{ + //g_print( "gaim_whiteboard_create()\n" ); + + GaimWhiteboard *wb = g_new0( GaimWhiteboard, 1 ); + + wb->account = account; + wb->state = state; + wb->who = g_strdup( who ); + + GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO( account->gc->prpl ); + gaim_whiteboard_set_prpl_ops( wb, prpl_info->whiteboard_prpl_ops ); + + // Start up protocol specifics + if( wb->prpl_ops && wb->prpl_ops->start ) + wb->prpl_ops->start( wb ); + + wbList = g_list_append( wbList, ( gpointer )( wb ) ); + + return( wb ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_whiteboard_destroy( GaimWhiteboard *wb ) +{ + //g_print( "gaim_whiteboard_destroy()\n" ); + + if( wb->ui_data ) + { + //g_print( "---wb->ui_data = %p\n", wb->ui_data ); + + // Destroy frontend + if( whiteboard_ui_ops && whiteboard_ui_ops->destroy ) + whiteboard_ui_ops->destroy( wb ); + } + + // Do protocol specific session ending procedures + if( wb->prpl_ops && wb->prpl_ops->end ) + wb->prpl_ops->end( wb ); + + if( wb ) + { + //g_print( "---wb = %p\n", wb ); + + wb->account = NULL; + wb->state = 0; + + if( wb->who ) + g_free( wb->who ); + + wbList = g_list_remove( wbList, wb ); + + g_free( wb ); + wb = NULL; + } +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_whiteboard_start( GaimWhiteboard *wb ) +{ + //g_print( "gaim_whiteboard_start()\n" ); + + // Create frontend for whiteboard + if( whiteboard_ui_ops && whiteboard_ui_ops->create ) + whiteboard_ui_ops->create( wb ); +} + +// ------------------------------------------------------------------------------------------------------ + +// Looks through the list of whiteboard sessions for one that is between usernames 'me' and 'who' +// Returns a pointer to a matching whiteboard session; if none match, it returns NULL +GaimWhiteboard *gaim_whiteboard_get_session( GaimAccount *account, char *who ) +{ + //g_print( "gaim_whiteboard_get_session()\n" ); + + GaimWhiteboard *wb = NULL; + + GList *l = wbList; + + // Look for a whiteboard session between the local user and the remote user + while( l ) + { + wb = l->data; + + if( !strcmp( gaim_account_get_username( wb->account ), gaim_account_get_username( account ) ) && + !strcmp( wb->who, who ) ) + return( wb ); + + l = l->next; + } + + return( NULL ); +} + +// ------------------------------------------------------------------------------------------------------ + +GList *gaim_whiteboard_draw_list_destroy( GList *draw_list ) +{ + //g_print( "gaim_whiteboard_draw_list_destroy()\n" ); + + if( draw_list == NULL ) + return( NULL ); + else + { + // Destroy the contents of this list + int *n = NULL; + GList *l = draw_list; + while( l ) + { + n = l->data; + + if( n ) + g_free( n ); + + l = l->next; + } + + g_list_free( draw_list ); + draw_list = NULL; + } + + return( draw_list ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_whiteboard_set_dimensions( GaimWhiteboard *wb, int width, int height ) +{ + if( whiteboard_ui_ops && whiteboard_ui_ops->set_dimensions ) + whiteboard_ui_ops->set_dimensions( wb, width, height ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_whiteboard_draw_point( GaimWhiteboard *wb, int x, int y, int color, int size ) +{ + if( whiteboard_ui_ops && whiteboard_ui_ops->draw_point ) + whiteboard_ui_ops->draw_point( wb, x, y, color, size ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_whiteboard_draw_line( GaimWhiteboard *wb, int x1, int y1, int x2, int y2, int color, int size ) +{ + if( whiteboard_ui_ops && whiteboard_ui_ops->draw_line ) + whiteboard_ui_ops->draw_line( wb, x1, y1, x2, y2, color, size ); +} + +// ------------------------------------------------------------------------------------------------------ + +void gaim_whiteboard_clear( GaimWhiteboard *wb ) +{ + if( whiteboard_ui_ops && whiteboard_ui_ops->clear ) + whiteboard_ui_ops->clear( wb ); +} + +// ------------------------------------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/whiteboard.h Fri Sep 09 04:40:21 2005 +0000 @@ -0,0 +1,88 @@ +/** + * @file whiteboard.h The GaimWhiteboard core object + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + */ + +#ifndef _GAIM_WHITEBOARD_H_ +#define _GAIM_WHITEBOARD_H_ + +// DEFINES ============================================================================================= + +typedef struct _GaimWhiteboardPrplOps GaimWhiteboardPrplOps; // NOTE A nasty compiler dependency fix + +#include "account.h" + +// INCLUDES ============================================================================================ + +// DATATYPES =========================================================================================== +typedef struct _GaimWhiteboard +{ + int state; // State of whiteboard session + + GaimAccount *account; // Account associated with this session + char *who; // Name of the remote user + + void *ui_data; // Graphical user-interface data + void *proto_data; // Protocol specific data + GaimWhiteboardPrplOps *prpl_ops; // Protocol-plugin operations + + GList *draw_list; // List of drawing elements/deltas to send +} GaimWhiteboard; + +typedef struct _GaimWhiteboardUiOps +{ + void ( *create )( GaimWhiteboard *wb ); + void ( *destroy )( GaimWhiteboard *wb ); + void ( *set_dimensions)( GaimWhiteboard *wb, int width, int height ); + void ( *draw_point )( GaimWhiteboard *wb, int x, int y, int color, int size ); + void ( *draw_line )( GaimWhiteboard *wb, int x1, int y1, int x2, int y2, int color, int size ); + void ( *clear )( GaimWhiteboard *wb ); +} GaimWhiteboardUiOps; + +struct _GaimWhiteboardPrplOps +{ + void ( *start )( GaimWhiteboard *wb ); + void ( *end )( GaimWhiteboard *wb ); + void ( *get_dimensions )( GaimWhiteboard *wb, int *width, int *height ); + void ( *set_dimensions )( GaimWhiteboard *wb, int width, int height ); + void ( *send_draw_list )( GaimWhiteboard *wb, GList *draw_list ); + void ( *clear )( GaimWhiteboard *wb ); +}; + +// PROTOTYPES ========================================================================================== + +void gaim_whiteboard_set_ui_ops( GaimWhiteboardUiOps *ops ); + +GaimWhiteboard *gaim_whiteboard_create( GaimAccount *account, char *who, int state ); +void gaim_whiteboard_destroy( GaimWhiteboard *wb ); +void gaim_whiteboard_start( GaimWhiteboard *wb ); + +GaimWhiteboard *gaim_whiteboard_get_session( GaimAccount *account, char *who ); + +GList *gaim_whiteboard_draw_list_destroy( GList *draw_list ); + +void gaim_whiteboard_set_dimensions( GaimWhiteboard *wb, int width, int height ); +void gaim_whiteboard_draw_point( GaimWhiteboard *wb, int x, int y, int color, int size ); +void gaim_whiteboard_draw_line( GaimWhiteboard *wb, int x1, int y1, int x2, int y2, int color, int size ); +void gaim_whiteboard_clear( GaimWhiteboard *wb ); + +#endif // _GAIM_WHITEBOARD_H_