/******************************************************************** Copyright (C) 2000 Bassoukos Tassos 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., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "connection.h" #include "main.h" #include "protocol.h" #include "userlist.h" #include "hldat.h" #include "guiprefs.h" #include "guiutils.h" #include "userwidget.h" #include "pixmap.h" #include "privs.h" #include "users.h" #include "privchat.h" #define UWE_HEIGHT 17 #define UWE_WIDTH 232 static void uwe_destroy(UserWidgetEntry *uwe){ if(uwe->group!=NULL) gtk_object_destroy(GTK_OBJECT(uwe->group)); } static int uw_sort(const void *a,const void *b){ int i=0; if(userlist_group_by_status==TRUE){ i=(((*(UserWidgetEntry **)b)->ule->u.status^1)&3)- (((*(UserWidgetEntry **)a)->ule->u.status^1)&3); if(i!=0) return i; } if(userlist_sort_name==TRUE) return strcmp((*(UserWidgetEntry **)a)->ule->name, (*(UserWidgetEntry **)b)->ule->name); return 0; } static void userwidget_sort(UserWidget *u){ UserWidgetEntry **ue; int i; if(u->numusers==0 || u->frozen) return; ue=(UserWidgetEntry **)malloc(sizeof(UserWidgetEntry *)*u->numusers); for(i=0;inumusers;i++){ ue[i]=&(u->users[i]); ue[i]->oldpos=ue[i]->pos; ue[i]->pos=i; } qsort(ue,u->numusers,sizeof(UserWidgetEntry *),uw_sort); for(i=0;inumusers;i++) ue[i]->pos=i; for(i=0;inumusers;i++) if(ue[i]->group!=NULL && (ue[i]->pos!=ue[i]->oldpos)){ if(ue[i]->oldpos==-1) gnome_canvas_item_set(ue[i]->group, "y",(double)(ue[i]->pos*(UWE_HEIGHT+1)),NULL); else gnome_canvas_item_move(ue[i]->group,0,(ue[i]->pos-ue[i]->oldpos)*(UWE_HEIGHT+1)); } free(ue); } static void userwidget_set_bounds(UserWidget *uw){ double x1,x2,y1,y2; if(uw->frozen) return; gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(uw->root), &x1,&y1,&x2,&y2); if(x1>0.0) x1=0.0; if(y1>0.0) y1=0.0; if(x2width) x2=uw->width; if(x2widget->allocation.height) y2=uw->widget->allocation.height-1.0; gnome_canvas_set_scroll_region(GNOME_CANVAS(uw->widget), x1,y1,x2,y2); } static void userwidget_set_selection(UserWidget *uw,int seluser){ if(seluser>=uw->numusers || seluser<-1) seluser=-1; if(uw->seluser==seluser) return; if(uw->seluser!=-1) gnome_canvas_item_hide(uw->users[uw->seluser].rect); if(seluser!=-1) gnome_canvas_item_show(uw->users[seluser].rect); uw->seluser=seluser; if(uw->select!=NULL){ if(uw->seluser!=-1) uw->select(uw,uw->users[uw->seluser].ule->u.socket, FALSE,uw->select_data); else uw->select(uw,-1,FALSE,uw->select_data); } } static void userwidget_set_selection_by_mouse(UserWidget *uw,GdkEventButton *b){ double x,y; int cx,cy,seluser,i; if(b->type!=GDK_BUTTON_PRESS && b->type!=GDK_2BUTTON_PRESS) return; gnome_canvas_window_to_world(GNOME_CANVAS(uw->widget),b->x,b->y,&x,&y); gnome_canvas_w2c(GNOME_CANVAS(uw->widget),x,y,&cx,&cy); seluser=cy/(UWE_HEIGHT+1); for(i=0;inumusers;i++){ if(uw->users[i].pos==seluser){ userwidget_set_selection(uw,i); return; } } userwidget_set_selection(uw,-1); } struct { int status; int icon; } uwe_status_icons[UWE_STATUS_ICONS]={ {ULE_STATUS_ADMIN,192}, {ULE_STATUS_NOMSG,226}, {ULE_STATUS_NOPRIVCHAT,227} }; static void uwe_update(UserWidget *uw,int i){ UserWidgetEntry *uwe=uw->users+i; GnomeCanvasGroup *it; Icon *ic; GtkStyle *style=gtk_widget_get_style(uw->widget); int created=FALSE; int last_xpos; GnomeCanvasPoints *pts; GdkImlibImage *imc; if(uw->frozen>0) return; if(uwe->group==NULL){ int rgba; created=TRUE; uwe->group=gnome_canvas_item_new(uw->root, gnome_canvas_group_get_type(), "y",(double)(uwe->pos*(UWE_HEIGHT+1)), "x",(double)0.0, NULL); gnome_canvas_item_raise_to_top(uwe->group); gnome_canvas_item_show(uwe->group); rgba=(userlist_highlight_color_alpha&0xff00)>>8| (userlist_highlight_color.red &0xff00)<<16| (userlist_highlight_color.green&0xff00)<<8| (userlist_highlight_color.blue &0xff00); uwe->rect=gnome_canvas_item_new(GNOME_CANVAS_GROUP(uwe->group), gnome_canvas_rect_get_type(), "x1",(double)0.0, "y1",(double)0.0, "x2",(double)UWE_WIDTH-1, "y2",(double)UWE_HEIGHT, "fill_color_rgba",rgba, /* "outline_color_rgba",0x0, BUG: locks up deep in libart_lgpl version 1.1.12 */ NULL); if(userlist_aa_canvas==FALSE){ GdkBitmap *stbm; pixmap_get("stipple",NULL,&stbm); gnome_canvas_item_set(uwe->rect,"fill_stipple",stbm,NULL); } pts=gnome_canvas_points_new(2); pts->coords[0]=2.0;pts->coords[1]=2.0; pts->coords[2]=(double)uw->width-2;pts->coords[3]=UWE_HEIGHT-2; uwe->line1=gnome_canvas_item_new(GNOME_CANVAS_GROUP(uwe->group), gnome_canvas_line_get_type(), "points",pts, "width_units",(double)3.0, "fill_color_rgba",0xff0000ff, NULL); pts->coords[0]=2.0;pts->coords[3]=2.0; pts->coords[2]=(double)uw->width-2;pts->coords[1]=UWE_HEIGHT-2; uwe->line2=gnome_canvas_item_new(GNOME_CANVAS_GROUP(uwe->group), gnome_canvas_line_get_type(), "points",pts, "width_units",(double)3.0, "fill_color_rgba",0xff0000ff, NULL); gnome_canvas_item_hide(uwe->group); gnome_canvas_item_hide(uwe->rect); gnome_canvas_item_hide(uwe->line1); gnome_canvas_item_hide(uwe->line2); gnome_canvas_points_free(pts); } it=GNOME_CANVAS_GROUP(uwe->group); ic=get_icon(uwe->ule->u.icon); if(uwe->icon==NULL && ic!=NULL){ uwe->icon=gnome_canvas_item_new(it,gnome_canvas_image_get_type(), "x",(double)0.0,"y",(double)UWE_HEIGHT/2.0+0.5, "anchor",GTK_ANCHOR_W, "image",ic->image, "width",(double)ic->image->rgb_width, "height",(double)ic->image->rgb_height, NULL); } else if(uwe->icon!=NULL && ic==NULL){ gtk_object_destroy(GTK_OBJECT(uwe->icon)); uwe->icon=NULL; } else if(uwe->icon!=NULL && ic!=NULL){ gnome_canvas_item_set(uwe->icon, "image",ic->image, "width",(double)ic->image->rgb_width, "height",(double)ic->image->rgb_height, NULL); } last_xpos=uw->width-23; if(userlist_use_status_icons==TRUE) for(i=0;istatus_icon[i]!=NULL){ if((uwe->ule->u.status & uwe_status_icons[i].status)==0){ gtk_object_destroy(GTK_OBJECT(uwe->status_icon[i])); uwe->status_icon[i]=0; } else { gnome_canvas_item_set(uwe->status_icon[i], "x",(double)last_xpos, "y",(double)0.0,NULL); last_xpos-=24; } } else if(uwe->status_icon[i]==NULL && (uwe->ule->u.status & uwe_status_icons[i].status)){ imc=get_image_icon(uwe_status_icons[i].icon,0,0,TRUE); if(imc!=NULL){ uwe->status_icon[i]=gnome_canvas_item_new(it,gnome_canvas_image_get_type(), "x",(double)last_xpos, "y",(double)0.0, "anchor",GTK_ANCHOR_NW, "image",imc, "width",(double)imc->rgb_width, "height",(double)imc->rgb_height,NULL); last_xpos-=24; } } } if(uwe->name==NULL && uwe->ule->name!=NULL){ uwe->name=gnome_canvas_item_new(it,gnome_canvas_text_get_type(), "text","a","x",(double)34.0,"y",(double)8.0, "anchor",GTK_ANCHOR_W,NULL); if(userlist_font.use_custom_font==TRUE && userlist_font.font!=NULL) gnome_canvas_item_set(uwe->name,"font_gdk",userlist_font.font,NULL); else gnome_canvas_item_set(uwe->name,"font_gdk",style->font,NULL); } else if(uwe->name!=NULL && uwe->ule->name==NULL){ gtk_object_destroy(GTK_OBJECT(uwe->name)); uwe->name=NULL; } if(uwe->name!=NULL){ gnome_canvas_item_set(uwe->name,"text",uwe->ule->name, "fill_color_gdk",&userlist_colors[uwe->ule->u.status&3], NULL); } if((uwe->ule->u.status&ULE_FIDELIO_IGNORED)==0){ gnome_canvas_item_hide(uwe->line1); gnome_canvas_item_hide(uwe->line2); } else { gnome_canvas_item_show(uwe->line1); gnome_canvas_item_show(uwe->line2); } gnome_canvas_item_lower_to_bottom(uwe->rect); if(uwe->icon!=NULL) gnome_canvas_item_lower_to_bottom(uwe->icon); if(uwe->name!=NULL) gnome_canvas_item_raise_to_top(uwe->name); if(created==TRUE) gnome_canvas_item_show(uwe->group); } static void userwidget_handle_button(GtkWidget *w,GdkEvent *ev,UserWidget *uw){ GdkEventButton *b; if(ev->type!=GDK_BUTTON_PRESS && ev->type!=GDK_2BUTTON_PRESS) return; b=(GdkEventButton *)ev; if(b->type==GDK_2BUTTON_PRESS && uw->seluser!=-1){ user_start_message(uw->c,userwidget_get_seluser(uw)); /*if(uw->select!=NULL) uw->select(uw,uw->users[uw->seluser].ule->u.socket,TRUE,uw->select_data); */ } else if(b->type==GDK_BUTTON_PRESS){ gboolean f; userwidget_set_selection_by_mouse(uw,b); f=(uw->seluser!=-1)?TRUE:FALSE; if(uw->menu!=NULL){ gtk_widget_set_sensitive(uw->menu[0].widget,f); gtk_widget_set_sensitive(uw->menu[1].widget,f); gtk_widget_set_sensitive(uw->menu[2].widget,f && privs_check(uw->c,PRIV_GET_USER_INFO)); gtk_widget_set_sensitive(uw->menu[4].widget,f); gtk_widget_set_sensitive(uw->menu[5].widget,f && privs_check(uw->c,PRIV_DISCON_USER)); } if(uw->menu!=NULL && b->button==3){ privchat_make_invite_menu(uw,GTK_MENU(uw->popup_menu)); // gnome_popup_menu_do_popup(uw->popup_menu,NULL,NULL,b,uw->popup_data); } } } void userwidget_set_select(UserWidget *uw, void (*select)(UserWidget *,int,gboolean,gpointer), gpointer data){ uw->select=select; uw->select_data=data; } void userwidget_remove(UserWidget *uw,int socket){ int i; for(i=0;inumusers;i++) if(uw->users[i].ule->u.socket==socket){ uwe_destroy(&uw->users[i]); uw->numusers--; for(;inumusers;i++) uw->users[i]=uw->users[i+1]; if(i==uw->seluser) userwidget_set_selection(uw,-1); else if(uw->seluser>i) userwidget_set_selection(uw,uw->seluser-1); userwidget_sort(uw); userwidget_set_bounds(uw); return; } } void userwidget_add(UserWidget *uw,int socket){ UserWidgetEntry *uwe; UserlistEntry *ule=get_user_by_socket(uw->c,socket); int i; if(ule==NULL) { printf("Internal warning 0x52f7: %d\n",socket); return; } for(i=0;inumusers;i++){ if(uw->users[i].ule->u.socket==socket){ printf("Internal warning 0x6641\n"); return; } } uw->numusers++; uw->users=realloc(uw->users,uw->numusers*sizeof(UserWidgetEntry)); uwe=&uw->users[uw->numusers-1]; uwe->ule=ule; uwe->pos=uw->numusers-1; uwe->oldpos=-1; uwe->group=NULL; uwe->icon=NULL; uwe->name=NULL; uwe->rect=NULL; for(i=0;istatus_icon[i]=NULL; if(uw->frozen>0) return; userwidget_sort(uw); uwe_update(uw,uw->numusers-1); userwidget_set_bounds(uw); } void userwidget_update(UserWidget *uw,int socket){ int i; for(i=0;inumusers;i++){ if(uw->users[i].ule->u.socket==socket){ uwe_update(uw,i); userwidget_sort(uw); userwidget_set_bounds(uw); return; } } printf("Internal warning 0x72dc\n"); } void userwidget_clear(UserWidget *uw){ int i; userwidget_set_selection(uw,-1); for(i=0;inumusers;i++) uwe_destroy(&uw->users[i]); uw->numusers=0; userwidget_set_bounds(uw); } static void uw_change_size(GtkWidget *widget, GtkAllocation *allocation, gpointer data){ UserWidget *uw=(UserWidget *)data; int i,last_xpos,j; GnomeCanvasPoints *pts=gnome_canvas_points_new(2); uw->width=allocation->width; pts->coords[0]=2.0; pts->coords[2]=(double)uw->width-2; for(i=0;inumusers;i++){ gnome_canvas_item_set(uw->users[i].rect,"x2",(double)uw->width,NULL); pts->coords[1]=2.0;pts->coords[3]=UWE_HEIGHT-2; gnome_canvas_item_set(uw->users[i].line1,"points",pts,NULL); pts->coords[3]=2.0;pts->coords[1]=UWE_HEIGHT-2; gnome_canvas_item_set(uw->users[i].line2,"points",pts,NULL); last_xpos=(uw->width-23); for(j=0;jusers[i].status_icon[j]!=NULL){ gnome_canvas_item_set(uw->users[i].status_icon[j],"x",(double)last_xpos,NULL); last_xpos-=24; } /* FIXME: somehow if this isn't here, the no_*_icon's won't be redrawn... (gnome-libs 1.0.53)*/ gnome_canvas_item_move(uw->users[i].group,0,0); } gnome_canvas_points_free(pts); userwidget_set_bounds(uw); } static void uw_ignore_user(GtkButton *b,UserWidget *uw){ if(uw->seluser!=-1){ gboolean i; i=userlist_get_ignored(uw->c,userwidget_get_seluser(uw)); i=(i==TRUE)?FALSE:TRUE; userlist_set_ignored(uw->c,userwidget_get_seluser(uw),i); } } static void uw_kick(GtkButton *b,UserWidget *uw){ if(uw->seluser!=-1) user_start_kick(uw->c,userwidget_get_seluser(uw)); } static void uw_send_message(GtkButton *b,UserWidget *uw){ if(uw->seluser!=-1) user_start_message(uw->c,userwidget_get_seluser(uw)); } static void uw_query_user(GtkButton *b,UserWidget *uw){ if(uw->seluser!=-1) user_query_info(uw->c,userwidget_get_seluser(uw)); } static GnomeUIInfo uw_privchat_menu[]={ GNOMEUIINFO_END }; static GnomeUIInfo uw_menu_uiinfo[]={ GNOMEUIINFO_ITEM_STOCK(N_("Message"),N_("Send this user a message"), uw_send_message, HL_MENU HL_STOCK_PIXMAP_USERS_SENDMESG), GNOMEUIINFO_SUBTREE_STOCK(N_("Invite to..."),uw_privchat_menu, HL_MENU HL_STOCK_PIXMAP_PRIVCHAT), GNOMEUIINFO_ITEM_STOCK(N_("Info"),N_("Get info of a user"), uw_query_user, HL_MENU HL_STOCK_PIXMAP_USERS_INFO), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_STOCK("Ignore",N_("(Un)Ignore this user"), uw_ignore_user, GNOME_STOCK_PIXMAP_CLOSE), GNOMEUIINFO_ITEM_STOCK("Kick/Ban",N_("Kick or Ban this user"), uw_kick, HL_MENU HL_STOCK_PIXMAP_USERS_KICK), GNOMEUIINFO_END }; UserWidget *userwidget_new(Connection *c){ UserWidget *uw=(UserWidget *)malloc(sizeof(UserWidget)); uw->users=NULL; uw->numusers=0; uw->c=c; uw->seluser=-1; uw->select=NULL; uw->menu=NULL; uw->popup_menu=NULL; uw->frozen=0; uw->ops=NULL; uw->width=UWE_WIDTH-1; if(userlist_aa_canvas==TRUE) uw->widget=gnome_canvas_new_aa(); else uw->widget=gnome_canvas_new(); gtk_widget_add_events(uw->widget,GDK_BUTTON_PRESS_MASK | GDK_BUTTON1_MASK | GDK_BUTTON3_MASK | GDK_EXPOSURE_MASK); gtk_widget_set_usize(uw->widget,UWE_WIDTH,UWE_HEIGHT*10); gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(uw->widget),1.0); uw->root=GNOME_CANVAS_GROUP(gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(uw->widget)), gnome_canvas_group_get_type(),NULL)); { GtkStyle *style=gtk_style_copy(gtk_widget_get_style(main_app)); style->bg[GTK_STATE_NORMAL]=style->base[GTK_STATE_NORMAL]; gtk_widget_set_style(uw->widget,style); gtk_container_set_border_width(GTK_CONTAINER(uw->widget),2); } gtk_signal_connect(GTK_OBJECT(uw->widget),"button-press-event", GTK_SIGNAL_FUNC(userwidget_handle_button),uw); gtk_signal_connect(GTK_OBJECT(uw->widget),"size-allocate", GTK_SIGNAL_FUNC(uw_change_size),uw); uw->menu=gutils_dup_gnomeuiinfo_with_data(uw_menu_uiinfo,uw); uw->popup_data=uw; uw->popup_menu=gnome_popup_menu_new(uw->menu); gnome_popup_menu_attach(uw->popup_menu,uw->widget,uw); privchat_attach_to_menu(uw->c,GTK_MENU(uw->popup_menu),uw->menu[1].widget); return uw; } void userwidget_destroy(UserWidget *uw){ userwidget_set_select(uw,NULL,NULL); if(uw->menu!=NULL) free(uw->menu); userwidget_clear(uw); if(uw->ops!=NULL) userlist_rm_ops(uw->c,uw->ops); if(uw->users!=NULL) free(uw->users); free(uw); } void userwidget_freeze(UserWidget *uw){ uw->frozen++; } void userwidget_thaw(UserWidget *uw){ int i; if(--uw->frozen>0) return; if(uw->frozen<0) printf("Internal warning 0xdf41\n"); userwidget_sort(uw); for(i=0;inumusers;i++) uwe_update(uw,i); userwidget_set_selection(uw,uw->seluser); userwidget_set_bounds(uw); } int userwidget_get_seluser(UserWidget *uw){ if(uw->seluser==-1) return -1; return uw->users[uw->seluser].ule->u.socket; } /* ====================================================== */ static void uw_upd_sock(Connection *c,int sock,gpointer data){ userwidget_update((UserWidget *)data,sock); } static void uw_add_sock(Connection *c,int sock,gpointer data){ userwidget_add((UserWidget *)data,sock); } static void uw_rm_sock(Connection *c,int sock,gpointer data){ userwidget_remove((UserWidget *)data,sock); } static void uw_refresh_all(Connection *c,int numusers, int *sock,gpointer data){ UserWidget *uw=(UserWidget *)data; int oldsel=uw->seluser; int i; if(oldsel!=-1) oldsel=uw->users[oldsel].ule->u.socket; userwidget_freeze(uw); userwidget_clear(uw); for(i=0;iops=up; userlist_add_ops(uw->c,up,uw); } /* ====================================================== */