summary refs log blame commit diff stats
path: root/plugins/mpcinfo/mp3Info.c
blob: b7112a5d3e7f6b6fe8e282081b4595a6e0d6fc53 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                        
                                                                             




































































                                                                                                                                              
                                                                                



                                                         
                                                    















































                                                                                                     
                                  


























                                                                                                         
                                                                     









                                                                           
                                                                                            





                                    
                                                                                    








                                           
                                                          



                                                   
                                                           
     

                                                             













                                                    
                                                  
















                                                          
                                             

                    
                                                                     













                                                                          
                                                     





                                                                                 

                                            

                                                       
                                                 

                                                                        
                                                 
                                                                                                 
                                             
                                                     
                                             
                                                     
                                             
                                                      
                                               




















                                                                   
                                                                          































































                                                                                                                                                                          
/*
 *  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

//#include <stdio.h>
#include <sys/stat.h>
//#include "functions.c"

struct tagInfo{
	int mode;
	int cbr;
	int bitrate;
	unsigned int freq;
	char *artist;
	char *title;
	char *album;
	char *comment;
	char *genre;
	//int genre;
	//int track;
};

static int RATES[2][3][15]={
				{//mpeg2
                    {-1,8,16,24,32,64,80,56,64,128,160,112,128,256,320},//layer3 (V2)    
					{-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},//layer2 (V2)
					{-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448},//layer1 (V2)
                },
                {//mpeg1
					{-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320},//layer3 (V1)
					{-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},//layer2 (V1)
                    {-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448},//layer1 (V1)
        }};
static int FREQS[2][4]={{22050,24000,16000,-1},{44100,48000,32000,-1}};
//static double FRATES[]={38.5,32.5,27.8,0.0};

static char GENRES[][50]={"Blues","Classic Rock","Country","Dance","Disco","Funk","Grunge","Hip-Hop","Jazz","Metal",
"New Age","Oldies","Other","Pop","R&B","Rap","Reggae","Rock","Techno","Industrial",
"Alternative","Ska","Death Metal","Pranks","Soundtrack","Euro-Techno","Ambient","Trip-Hop","Vocal","Jazz+Funk",
"Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound Clip","Gospel","Noise",
"AlternRock","Bass","Soul","Punk","Space","Meditative","Instrumental Pop","Instrumental Rock","Ethnic","Gothic",
"Darkwave","Techno-Industrial","Electronic","Pop-Folk","Eurodance","Dream","Southern Rock","Comedy","Cult","Gangsta",
"Top 40","Christian Rap","Pop/Funk","Jungle","Native American","Cabaret","New Wave","Psychadelic","Rave","Showtunes",
"Trailer","Lo-Fi","Tribal","Acid Punk","Acid Jazz","Polka","Retro","Musical","Rock & Roll","Hard Rock",

//################## END OF OFFICIAL ID3 TAGS, WINAMP TAGS BELOW ########################################

"Folk","Folk/Rock","National Folk","Swing","Fast Fusion","Bebob","Latin","Revival","Celtic","Bluegrass",
"Avantgarde","Gothic Rock","Progressive Rock","Psychedelic Rock","Symphonic Rock","Slow Rock","Big Band","Chorus","Easy Listening","Acoustic",
"Humour","Speech","Chanson","Opera","Chamber Music","Sonata","Symphony","Booty Bass","Primus","Porn Groove",
"Satire","Slow Jam","Club","Tango","Samba","Folklore","Ballad","Poweer Ballad","Rhytmic Soul","Freestyle",
"Duet","Punk Rock","Drum Solo","A Capela","Euro-House","Dance Hall",

//################## FOUND AT http://en.wikipedia.org/wiki/ID3 ###########################################

"Goa","Drum & Bass","Club-House","Hardcore",
"Terror","Indie","BritPop","Negerpunk","Polsk Punk","Beat","Christian Gangsta Rap","Heavy Metal","Black Metal","Crossover",
"Contemporary Christian","Christian Rock","Merengue","Salsa","Thrash Metal","Anime","JPop","Synthpop"

};

static char MODES [][13]={"Stereo","Joint-Stereo","Dual-Channel","Mono"};

int iPow(int x, int y){return (int)(pow((double)x,(double) y));}

int str2int(char *text){
    //if (DEBUG==1) putlog("converting string to int");
    int i;
    int ret=0;
    for (i=1;i<=strlen(text);i++){
        if ((text[strlen(text)-i]>57)||(text[strlen(text)-i]<48)){
           hexchat_printf(ph,"invalid char in string: %i",text[strlen(text)-i]);
           return 255;
        }
        ret+=((int)text[strlen(text)-i]-48)*iPow(10,i-1);
    }
    //hexchat_printf(ph, "str2int(%s)=%i",text,ret);
    //if (DEBUG==1) putlog("int converted");
    return ret;
}
/*
static int getSize(char *file){
    //if (DEBUG==1) putlog("reading filesize");
	struct stat info;
	if (stat(file,&info)!=0) return -1;
	return info.st_size;
}*/
/*
int inStr(char *s1, int sl1, char *s2){
    //if (DEBUG==1) putlog("checking instr");
	int i;int j;
	for(i=0;i<sl1-strlen(s2);i++){
		for (j=0;j<strlen(s2);j++){
			if (s1[i+j]!=s2[j]) j=strlen(s2)+2;
		}
		if (j==strlen(s2)) return i;
	}
	return -1;
}

static char *subString(char *text, int first, int length, int spcKill){
//if (DEBUG==1) putlog("creating substring");
	char *ret=(char*) calloc (length+1,sizeof(char)); //malloc(sizeof(char)*(length+1));
	ret[length]=0;int i;
	for (i=0;i<length;i++){
		ret[i]=text[i+first];
		//if (ret[i]==0) ret[i]='0';
	}
	if (spcKill==1){
	   for (i=length-1;i>=0;i--){
           if (ret[i]==32) ret[i]=0;
           else i=-1;
       }
    }
    //if (DEBUG==1) putlog("substring created");
	return ret;
}

static char *substring(char *text, int first, int length){return subString(text,first,length,0);} //1
*/

static char *tagExtract(char *tag, int tagLen, char* info){
//if (DEBUG==1) putlog("extracting tag");
	int pos, len, i;
	pos=inStr(tag,tagLen,info);
//hexchat_printf(ph,"pos=%i",pos);
	if (pos==-1) return "";//NULL;
	//printf("position of %s = %i\n",info,pos);
	len=0;
	//for (i=pos;i<pos+10;i++)printf("tag[%i]=%i \n",i,tag[i]);
	for (i=0;i<4;i++) {
		len+=tag[pos+strlen(info)+i]*iPow(255,3-i);
	}
	//printf("Tag-Length: %i\n",len);
	if (strcmp("COMM",info)!=0) return substring(tag,pos+7+strlen(info),len-1);//11
	return substring(tag,pos+7+strlen(info),len-1);//11
	//char *ct=substring(tag,pos+7+strlen(info),len-1);//11
	//return substring(ct,strlen(ct)+1,len-1-strlen(ct)); //<-- do not understand, what i did here :(
	
}

struct tagInfo readID3V1(char *file){
//if (DEBUG==1) putlog("reading ID3V1");
	FILE *f;
	struct tagInfo ret;
	int res, i, c, val;
	char *tag;
	char *id;
	char *tmp;
	tag = (char*) malloc(sizeof(char)*129);
	ret.artist=NULL;
	f=fopen(file,"rb");
	if (f==NULL){
       hexchat_print(ph,"file not found while trying to read id3v1");
       //if (DEBUG==1) putlog("file not found while trying to read id3v1");
       return ret;
    }
	//int offset=getSize(file)-128;
	res=fseek(f,-128,SEEK_END);
	if (res!=0) {printf("seek failed\n");fclose(f);return ret;}
	//long int pos=ftell(f);
	//printf("position= %li\n",pos);
	for (i=0;i<128;i++) {
		c=fgetc(f);
		if (c==EOF) {hexchat_printf(ph,"read ID3V1 failed\n");fclose(f);return ret;}
		tag[i]=(char)c;
	}
	fclose(f);
	//printf("tag readed: \n");
	id=substring(tag,0,3);
	//printf("header: %s\n",id);
	if (strcmp(id,"TAG")!=0){hexchat_printf(ph,"no id3 v1 found\n");return ret;}
	ret.title=subString(tag,3,30,1);
	ret.artist=subString(tag,33,30,1);
	ret.album=subString(tag,63,30,1);
	ret.comment=subString(tag,97,30,1);
	tmp=substring(tag,127,1);
	//ret.genre=substring(tag,127,1);
	
	val=(int)tmp[0];
	if (val<0)val+=256;
	//hexchat_printf(ph, "tmp[0]=%i (%i)",val,tmp[0]);
	if ((val<148)&&(val>=0)) 
       ret.genre=GENRES[val];//#############changed
	else {
         ret.genre="unknown";
         //hexchat_printf(ph, "tmp[0]=%i (%i)",val,tmp[0]);
    }
	//hexchat_printf(ph, "tmp: \"%s\" -> %i",tmp,tmp[0]);
	//hexchat_printf(ph,"genre \"%s\"",ret.genre);
	//if (DEBUG==1) putlog("id3v1 extracted");
	return ret;
}

char *extractID3Genre(char *tag){
     //if (DEBUG==1) putlog("extracting id3 genre");
     if (tag[strlen(tag)-1]==')'){
        tag[strlen(tag)-1]=0;
        tag=&tag[1];
        return GENRES[str2int(tag)];
        //return tag;
     }
     else{
          int i;
          //hexchat_print(ph, "Using 2 criteria");
          for (i=0;i<strlen(tag);i++){
              if (tag[i]==')'){ tag=&tag[i]+1;return tag;}
          //return tag;
          }
     }
     return "[152] failed";
}

struct tagInfo readID3V2(char *file){
//if (DEBUG==1) putlog("reading id3v2");
	FILE *f;
	int i, c, len;
	char header[10];
	char *tag;
	struct tagInfo ret;

	f = fopen(file,"rb");
	//hexchat_printf(ph,"file :%s",file);
	if (f==NULL)
	{
       hexchat_print(ph,"file not found whilt trying to read ID3V2");
       //if (DEBUG==1)putlog("file not found while trying to read ID3V2");
       return ret;
    }

	ret.artist=NULL;
	for (i=0;i<10;i++){
        c=fgetc(f);
        if (c==EOF){
           //putlog("found eof while reading id3v2");
           return ret;
        }
        header[i]=(char)c;
    }
	if (strstr(header,"ID3")==header){
		//hexchat_printf(ph,"found id3v2\n");
		len=0;
		for (i=6;i<10;i++) len+=(int)header[i]*iPow(256,9-i);
		
		//char *tag=(char*)malloc(sizeof(char)*len);
		tag=(char*) calloc(len,sizeof(char)); //malloc(sizeof(char)*len);
		for (i=0;i<len;i++){c=fgetc(f);tag[i]=(char)c;}
//hexchat_printf(ph,"tag length: %i\n",len);
//hexchat_printf(ph,"tag: %s\n",tag);
		fclose(f);
		ret.comment=tagExtract(tag,len,"COMM");
//hexchat_printf(ph,"Comment: %s\n",ret.comment);
		ret.genre=tagExtract(tag,len,"TCON");
		//if (strcmp(ret.genre,"(127)")==0) ret.genre="unknown";
//hexchat_printf(ph, "ret.genre = %s",ret.genre);
		if ((ret.genre!=NULL)&&(ret.genre[0]=='(')) ret.genre=extractID3Genre(ret.genre);
//hexchat_printf(ph,"genre: %s\n",ret.genre);
		ret.title=tagExtract(tag,len,"TIT2");
//hexchat_printf(ph,"Title: %s\n",ret.title);
		ret.album=tagExtract(tag,len,"TALB");
//hexchat_printf(ph,"Album: %s\n",ret.album);
		ret.artist=tagExtract(tag,len,"TPE1");
//hexchat_printf(ph,"Artist: %s\n",ret.artist);
	}
	else{fclose(f);printf("no id3v2 tag found\n"); return ret;}
	//printf("id2v2 done\n");
	//if (DEBUG==1) putlog("id3v2 readed");
	return ret;
}

struct tagInfo readHeader(char *file){
//if (DEBUG==1) putlog("reading header");
	FILE *f;
	//int buffer[5120];
	int versionB, layerB, bitrateB, freqB, modeB;
	int header[4];
	int count=0;
	int cc=0;
	struct tagInfo info;
	info.artist=NULL;

	f = fopen(file,"rb");
	if (f==NULL)
	{
       hexchat_print(ph,"file not found while trying to read mp3 header");
       //if (DEBUG==1) putlog("file not found while trying to read mp3 header");
       return info;
    }
	//struct tagInfo tagv2
	
	info=readID3V2(file);
	//struct tagInfo tagv1;//=readID3V1(file);
	//if 	(tagv2.artist!=NULL){info=tagv2;}
	//else {
	if (info.artist==NULL){
		//printf("searching for id3v1\n");
		//tagv1=readID3V1(file);
		info=readID3V1(file); //#####################
	}
	/*
	if (tagv1.artist!=NULL){
		//printf("Artist: %s\nTitle: %s\nAlbum: %s\nComment: %s\nGenre: %s\n",tagv1.artist,tagv1.title,tagv1.album,tagv1.comment,tagv1.genre);
		info=tagv1;
	}
	*/
	while ((count<5120)&&(cc!=EOF)&&(cc!=255)) {cc=fgetc(f);count++;}
	if ((cc==EOF)||(count==5119)) printf("no header found\n");
	else {
		//printf("located header at %i\n",count);
		header[0]=255;
		for (count=1;count<4;count++){
			header[count]=fgetc(f);
			//printf("header[%i]=%i\n",count,header[count]);
		}
		versionB=(header[1]&8)>>3;
		layerB=(header[1]&6)>>1;
		bitrateB=(header[2]&240)>>4; //4
		freqB=(header[2]&12)>>2;//2
		modeB=(header[3]&192)>>6;//6
		//printf("Mpeg: %i\nLayer: %i\nBitrate: %i\nFreq: %i\nMode: %i\n",versionB, layerB, bitrateB, freqB, modeB);
		//int Bitrate=RATES[versionB][layerB-1][bitrateB];
		//int Freq=FREQS[versionB][freqB];
		info.bitrate=RATES[versionB][layerB-1][bitrateB];
		info.freq=FREQS[versionB][freqB];
		info.mode=modeB;	
	}
	fclose(f);
	//if (DEBUG==1) putlog("header readed");
	return info;
}
/*
static void printMp3Info(char *file){
	//printf("\nScanning Mp3-File for Informations: %s\n",file);
	//printf("size:\t%10d byte\n",getSize(file));
	struct tagInfo info =readHeader(file);
	printf("%s | %10d",file,getSize(file));
	if  (info.bitrate>0){
		//printf("Bitrate: %i\nFreq: %i\nMode: %s\n",info.bitrate,info.freq,MODES[info.mode]);
		printf(" | %i kbps | %i kHz | %s",info.bitrate,info.freq,MODES[info.mode]);
		//if (info.artist!=NULL) printf("\nArtist: %s\nTitle: %s\nAlbum: %s\nComment: %s\nGenre: %s\n",info.artist,info.title,info.album,info.comment,info.genre);
		if (info.artist!=NULL) {
			printf("| %s | %s | %s | %s | %s",info.artist,info.title,info.album,info.comment,info.genre);
			//printf("| %s ",info.title);//,info.title,info.album,info.comment,info.genre
		}
	}
	printf("\n");
	
}
*/
lass="p">, nick, nick); else nick_command_parse (current_sess, cmd, nick, nick); } GtkWidget * menu_toggle_item (char *label, GtkWidget *menu, void *callback, void *userdata, int state) { GtkWidget *item; item = gtk_check_menu_item_new_with_mnemonic (label); gtk_check_menu_item_set_active ((GtkCheckMenuItem*)item, state); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback), userdata); gtk_widget_show (item); return item; } GtkWidget * menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, gpointer userdata, char *icon) { GtkWidget *img, *item; char *path; if (!label) item = gtk_menu_item_new (); else { if (icon) { /*if (flags & XCMENU_MARKUP) item = gtk_image_menu_item_new_with_markup (label); else*/ item = gtk_image_menu_item_new_with_mnemonic (label); img = NULL; if (access (icon, R_OK) == 0) /* try fullpath */ img = gtk_image_new_from_file (icon); else { /* try relative to ~/.xchat2 */ path = g_strdup_printf ("%s/%s", get_xdir_fs (), icon); if (access (path, R_OK) == 0) img = gtk_image_new_from_file (path); else img = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); g_free (path); } if (img) gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img); } else { if (flags & XCMENU_MARKUP) { item = gtk_menu_item_new_with_label (""); if (flags & XCMENU_MNEMONIC) gtk_label_set_markup_with_mnemonic (GTK_LABEL (GTK_BIN (item)->child), label); else gtk_label_set_markup (GTK_LABEL (GTK_BIN (item)->child), label); } else { if (flags & XCMENU_MNEMONIC) item = gtk_menu_item_new_with_mnemonic (label); else item = gtk_menu_item_new_with_label (label); } } } gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_object_set_data (G_OBJECT (item), "u", userdata); if (cmd) g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (popup_menu_cb), cmd); if (flags & XCMENU_SHADED) gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); gtk_widget_show_all (item); return item; } static void menu_quick_item_with_callback (void *callback, char *label, GtkWidget * menu, void *arg) { GtkWidget *item; item = gtk_menu_item_new_with_label (label); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback), arg); gtk_widget_show (item); } GtkWidget * menu_quick_sub (char *name, GtkWidget *menu, GtkWidget **sub_item_ret, int flags, int pos) { GtkWidget *sub_menu; GtkWidget *sub_item; if (!name) return menu; /* Code to add a submenu */ sub_menu = gtk_menu_new (); if (flags & XCMENU_MARKUP) { sub_item = gtk_menu_item_new_with_label (""); gtk_label_set_markup (GTK_LABEL (GTK_BIN (sub_item)->child), name); } else { if (flags & XCMENU_MNEMONIC) sub_item = gtk_menu_item_new_with_mnemonic (name); else sub_item = gtk_menu_item_new_with_label (name); } gtk_menu_shell_insert (GTK_MENU_SHELL (menu), sub_item, pos); gtk_widget_show (sub_item); gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub_item), sub_menu); if (sub_item_ret) *sub_item_ret = sub_item; if (flags & XCMENU_DOLIST) /* We create a new element in the list */ submenu_list = g_slist_prepend (submenu_list, sub_menu); return sub_menu; } static GtkWidget * menu_quick_endsub () { /* Just delete the first element in the linked list pointed to by first */ if (submenu_list) submenu_list = g_slist_remove (submenu_list, submenu_list->data); if (submenu_list) return (submenu_list->data); else return NULL; } static void toggle_cb (GtkWidget *item, char *pref_name) { char buf[256]; if (GTK_CHECK_MENU_ITEM (item)->active) snprintf (buf, sizeof (buf), "set %s 1", pref_name); else snprintf (buf, sizeof (buf), "set %s 0", pref_name); handle_command (current_sess, buf, FALSE); } static int is_in_path (char *cmd) { char *prog = strdup (cmd + 1); /* 1st char is "!" */ char *space, *path, *orig; orig = prog; /* save for free()ing */ /* special-case these default entries. */ /* 123456789012345678 */ if (strncmp (prog, "gnome-terminal -x ", 18) == 0) /* don't check for gnome-terminal, but the thing it's executing! */ prog += 18; space = strchr (prog, ' '); /* this isn't 100% but good enuf */ if (space) *space = 0; path = g_find_program_in_path (prog); if (path) { g_free (path); g_free (orig); return 1; } g_free (orig); return 0; } /* syntax: "LABEL~ICON~STUFF~ADDED~LATER~" */ static void menu_extract_icon (char *name, char **label, char **icon) { char *p = name; char *start = NULL; char *end = NULL; while (*p) { if (*p == '~') { /* escape \~ */ if (p == name || p[-1] != '\\') { if (!start) start = p + 1; else if (!end) end = p + 1; } } p++; } if (!end) end = p; if (start && start != end) { *label = g_strndup (name, (start - name) - 1); *icon = g_strndup (start, (end - start) - 1); } else { *label = g_strdup (name); *icon = NULL; } } /* append items to "menu" using the (struct popup*) list provided */ void menu_create (GtkWidget *menu, GSList *list, char *target, int check_path) { struct popup *pop; GtkWidget *tempmenu = menu, *subitem = NULL; int childcount = 0; submenu_list = g_slist_prepend (0, menu); while (list) { pop = (struct popup *) list->data; if (!g_ascii_strncasecmp (pop->name, "SUB", 3)) { childcount = 0; tempmenu = menu_quick_sub (pop->cmd, tempmenu, &subitem, XCMENU_DOLIST|XCMENU_MNEMONIC, -1); } else if (!g_ascii_strncasecmp (pop->name, "TOGGLE", 6)) { childcount++; menu_toggle_item (pop->name + 7, tempmenu, toggle_cb, pop->cmd, cfg_get_bool (pop->cmd)); } else if (!g_ascii_strncasecmp (pop->name, "ENDSUB", 6)) { /* empty sub menu due to no programs in PATH? */ if (check_path && childcount < 1) gtk_widget_destroy (subitem); subitem = NULL; if (tempmenu != menu) tempmenu = menu_quick_endsub (); /* If we get here and tempmenu equals menu that means we havent got any submenus to exit from */ } else if (!g_ascii_strncasecmp (pop->name, "SEP", 3)) { menu_quick_item (0, 0, tempmenu, XCMENU_SHADED, 0, 0); } else { char *icon, *label; /* default command in hexchat.c */ if (pop->cmd[0] == 'n' && !strcmp (pop->cmd, "notify -n ASK %s")) { /* don't create this item if already in notify list */ if (!target || notify_is_in_list (current_sess->server, target)) { list = list->next; continue; } } menu_extract_icon (pop->name, &label, &icon); if (!check_path || pop->cmd[0] != '!') { menu_quick_item (pop->cmd, label, tempmenu, 0, target, icon); /* check if the program is in path, if not, leave it out! */ } else if (is_in_path (pop->cmd)) { childcount++; menu_quick_item (pop->cmd, label, tempmenu, 0, target, icon); } g_free (label); g_free (icon); } list = list->next; } /* Let's clean up the linked list from mem */ while (submenu_list) submenu_list = g_slist_remove (submenu_list, submenu_list->data); } static char *str_copy = NULL; /* for all pop-up menus */ static GtkWidget *nick_submenu = NULL; /* user info submenu */ static void menu_destroy (GtkWidget *menu, gpointer objtounref) { gtk_widget_destroy (menu); g_object_unref (menu); if (objtounref) g_object_unref (G_OBJECT (objtounref)); nick_submenu = NULL; } static void menu_popup (GtkWidget *menu, GdkEventButton *event, gpointer objtounref) { if (event && event->window) gtk_menu_set_screen (GTK_MENU (menu), gdk_drawable_get_screen (event->window)); g_object_ref (menu); g_object_ref_sink (menu); g_object_unref (menu); g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (menu_destroy), objtounref); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, event ? event->time : 0); } static void menu_nickinfo_cb (GtkWidget *menu, session *sess) { char buf[512]; if (!is_session (sess)) return; /* issue a /WHOIS */ snprintf (buf, sizeof (buf), "WHOIS %s %s", str_copy, str_copy); handle_command (sess, buf, FALSE); /* and hide the output */ sess->server->skip_next_whois = 1; } static void copy_to_clipboard_cb (GtkWidget *item, char *url) { gtkutil_copy_to_clipboard (item, NULL, url); } /* returns boolean: Some data is missing */ static gboolean menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu) { char buf[512]; char unknown[96]; char *real, *fmt; struct away_msg *away; gboolean missing = FALSE; GtkWidget *item; /* let the translators tweak this if need be */ fmt = _("<tt><b>%-11s</b></tt> %s"); snprintf (unknown, sizeof (unknown), "<i>%s</i>", _("Unknown")); if (user->realname) { real = strip_color (user->realname, -1, STRIP_ALL|STRIP_ESCMARKUP); snprintf (buf, sizeof (buf), fmt, _("Real Name:"), real); g_free (real); } else { snprintf (buf, sizeof (buf), fmt, _("Real Name:"), unknown); } item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), user->realname ? user->realname : unknown); snprintf (buf, sizeof (buf), fmt, _("User:"), user->hostname ? user->hostname : unknown); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), user->hostname ? user->hostname : unknown); snprintf (buf, sizeof (buf), fmt, _("Country:"), user->hostname ? country(user->hostname) : unknown); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), user->hostname ? country(user->hostname) : unknown); snprintf (buf, sizeof (buf), fmt, _("Server:"), user->servername ? user->servername : unknown); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), user->servername ? user->servername : unknown); if (user->lasttalk) { char min[96]; snprintf (min, sizeof (min), _("%u minutes ago"), (unsigned int) ((time (0) - user->lasttalk) / 60)); snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), min); } else { snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), unknown); } menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); if (user->away) { away = server_away_find_message (current_sess->server, user->nick); if (away) { char *msg = strip_color (away->message ? away->message : unknown, -1, STRIP_ALL|STRIP_ESCMARKUP); snprintf (buf, sizeof (buf), fmt, _("Away Msg:"), msg); g_free (msg); item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (copy_to_clipboard_cb), away->message ? away->message : unknown); } else missing = TRUE; } return missing; } void fe_userlist_update (session *sess, struct User *user) { GList *items, *next; if (!nick_submenu || !str_copy) return; /* not the same nick as the menu? */ if (sess->server->p_cmp (user->nick, str_copy)) return; /* get rid of the "show" signal */ g_signal_handlers_disconnect_by_func (nick_submenu, menu_nickinfo_cb, sess); /* destroy all the old items */ items = ((GtkMenuShell *) nick_submenu)->children; while (items) { next = items->next; gtk_widget_destroy (items->data); items = next; } /* and re-create them with new info */ menu_create_nickinfo_menu (user, nick_submenu); } void menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel) { char buf[512]; struct User *user; GtkWidget *submenu, *menu = gtk_menu_new (); if (str_copy) free (str_copy); str_copy = strdup (nick); submenu_list = 0; /* first time through, might not be 0 */ /* more than 1 nick selected? */ if (num_sel > 1) { snprintf (buf, sizeof (buf), _("%d nicks selected."), num_sel); menu_quick_item (0, buf, menu, 0, 0, 0); menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0); } else { user = userlist_find (sess, nick); /* lasttalk is channel specific */ if (!user) user = userlist_find_global (current_sess->server, nick); if (user) { nick_submenu = submenu = menu_quick_sub (nick, menu, NULL, XCMENU_DOLIST, -1); if (menu_create_nickinfo_menu (user, submenu) || !user->hostname || !user->realname || !user->servername) { g_signal_connect (G_OBJECT (submenu), "show", G_CALLBACK (menu_nickinfo_cb), sess); } menu_quick_endsub (); menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0); } } if (num_sel > 1) menu_create (menu, popup_list, NULL, FALSE); else menu_create (menu, popup_list, str_copy, FALSE); if (num_sel == 0) /* xtext click */ menu_add_plugin_items (menu, "\x5$NICK", str_copy); else /* userlist treeview click */ menu_add_plugin_items (menu, "\x5$NICK", NULL); menu_popup (menu, event, NULL); } /* stuff for the View menu */ static void menu_showhide_cb (session *sess) { if (prefs.hex_gui_hide_menu) gtk_widget_hide (sess->gui->menu); else gtk_widget_show (sess->gui->menu); } static void menu_topic_showhide_cb (session *sess) { if (prefs.hex_gui_topicbar) gtk_widget_show (sess->gui->topic_bar); else gtk_widget_hide (sess->gui->topic_bar); } static void menu_userlist_showhide_cb (session *sess) { mg_decide_userlist (sess, TRUE); } static void menu_ulbuttons_showhide_cb (session *sess) { if (prefs.hex_gui_ulist_buttons) gtk_widget_show (sess->gui->button_box); else gtk_widget_hide (sess->gui->button_box); } static void menu_cmbuttons_showhide_cb (session *sess) { switch (sess->type) { case SESS_CHANNEL: if (prefs.hex_gui_mode_buttons) gtk_widget_show (sess->gui->topicbutton_box); else gtk_widget_hide (sess->gui->topicbutton_box); break; default: gtk_widget_hide (sess->gui->topicbutton_box); } } static void menu_setting_foreach (void (*callback) (session *), int id, guint state) { session *sess; GSList *list; int maindone = FALSE; /* do it only once for EVERY tab */ list = sess_list; while (list) { sess = list->data; if (!sess->gui->is_tab || !maindone) { if (sess->gui->is_tab) maindone = TRUE; if (id != -1) GTK_CHECK_MENU_ITEM (sess->gui->menu_item[id])->active = state; if (callback) callback (sess); } list = list->next; } } void menu_bar_toggle (void) { prefs.hex_gui_hide_menu = !prefs.hex_gui_hide_menu; menu_setting_foreach (menu_showhide_cb, MENU_ID_MENUBAR, !prefs.hex_gui_hide_menu); } static void menu_bar_toggle_cb (void) { menu_bar_toggle (); if (prefs.hex_gui_hide_menu) fe_message (_("The Menubar is now hidden. You can show it again" " by pressing F9 or right-clicking in a blank part of" " the main text area."), FE_MSG_INFO); } static void menu_topicbar_toggle (GtkWidget *wid, gpointer ud) { prefs.hex_gui_topicbar = !prefs.hex_gui_topicbar; menu_setting_foreach (menu_topic_showhide_cb, MENU_ID_TOPICBAR, prefs.hex_gui_topicbar); } static void menu_userlist_toggle (GtkWidget *wid, gpointer ud) { prefs.hex_gui_ulist_hide = !prefs.hex_gui_ulist_hide; menu_setting_foreach (menu_userlist_showhide_cb, MENU_ID_USERLIST, !prefs.hex_gui_ulist_hide); } static void menu_ulbuttons_toggle (GtkWidget *wid, gpointer ud) { prefs.hex_gui_ulist_buttons = !prefs.hex_gui_ulist_buttons; menu_setting_foreach (menu_ulbuttons_showhide_cb, MENU_ID_ULBUTTONS, prefs.hex_gui_ulist_buttons); } static void menu_cmbuttons_toggle (GtkWidget *wid, gpointer ud) { prefs.hex_gui_mode_buttons = !prefs.hex_gui_mode_buttons; menu_setting_foreach (menu_cmbuttons_showhide_cb, MENU_ID_MODEBUTTONS, prefs.hex_gui_mode_buttons); } void menu_middlemenu (session *sess, GdkEventButton *event) { GtkWidget *menu; GtkAccelGroup *accel_group; accel_group = gtk_accel_group_new (); menu = menu_create_main (accel_group, FALSE, sess->server->is_away, !sess->gui->is_tab, NULL); menu_popup (menu, event, accel_group); } static void open_url_cb (GtkWidget *item, char *url) { char buf[512]; /* pass this to /URL so it can handle irc:// */ snprintf (buf, sizeof (buf), "URL %s", url); handle_command (current_sess, buf, FALSE); } void menu_urlmenu (GdkEventButton *event, char *url) { GtkWidget *menu; char *tmp, *chop; if (str_copy) free (str_copy); str_copy = strdup (url); menu = gtk_menu_new (); /* more than 51 chars? Chop it */ if (g_utf8_strlen (str_copy, -1) >= 52) { tmp = strdup (str_copy); chop = g_utf8_offset_to_pointer (tmp, 48); chop[0] = chop[1] = chop[2] = '.'; chop[3] = 0; menu_quick_item (0, tmp, menu, XCMENU_SHADED, 0, 0); free (tmp); } else { menu_quick_item (0, str_copy, menu, XCMENU_SHADED, 0, 0); } menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0); /* Two hardcoded entries */ if (strncmp (str_copy, "irc://", 6) == 0 || strncmp (str_copy, "ircs://",7) == 0) menu_quick_item_with_callback (open_url_cb, _("Connect"), menu, str_copy); else menu_quick_item_with_callback (open_url_cb, _("Open Link in Browser"), menu, str_copy); menu_quick_item_with_callback (copy_to_clipboard_cb, _("Copy Selected Link"), menu, str_copy); /* custom ones from urlhandlers.conf */ menu_create (menu, urlhandler_list, str_copy, TRUE); menu_add_plugin_items (menu, "\x4$URL", str_copy); menu_popup (menu, event, NULL); } static void menu_chan_cycle (GtkWidget * menu, char *chan) { char tbuf[256]; if (current_sess) { snprintf (tbuf, sizeof tbuf, "CYCLE %s", chan); handle_command (current_sess, tbuf, FALSE); } } static void menu_chan_part (GtkWidget * menu, char *chan) { char tbuf[256]; if (current_sess) { snprintf (tbuf, sizeof tbuf, "part %s", chan); handle_command (current_sess, tbuf, FALSE); } } static void menu_chan_join (GtkWidget * menu, char *chan) { char tbuf[256]; if (current_sess) { snprintf (tbuf, sizeof tbuf, "join %s", chan); handle_command (current_sess, tbuf, FALSE); } } void menu_chanmenu (struct session *sess, GdkEventButton * event, char *chan) { GtkWidget *menu; int is_joined = FALSE; if (find_channel (sess->server, chan)) is_joined = TRUE; if (str_copy) free (str_copy); str_copy = strdup (chan); menu = gtk_menu_new (); menu_quick_item (0, chan, menu, XCMENU_SHADED, str_copy, 0); menu_quick_item (0, 0, menu, XCMENU_SHADED, str_copy, 0); if (!is_joined) menu_quick_item_with_callback (menu_chan_join, _("Join Channel"), menu, str_copy); else { menu_quick_item_with_callback (menu_chan_part, _("Part Channel"), menu, str_copy); menu_quick_item_with_callback (menu_chan_cycle, _("Cycle Channel"), menu, str_copy); } menu_addfavoritemenu (sess->server, menu, str_copy); menu_add_plugin_items (menu, "\x5$CHAN", str_copy); menu_popup (menu, event, NULL); } static void menu_delfav_cb (GtkWidget *item, server *serv) { servlist_autojoinedit (serv->network, str_copy, FALSE); } static void menu_addfav_cb (GtkWidget *item, server *serv) { servlist_autojoinedit (serv->network, str_copy, TRUE); } void menu_addfavoritemenu (server *serv, GtkWidget *menu, char *channel) { if (!serv->network) return; if (channel != str_copy) { if (str_copy) free (str_copy); str_copy = strdup (channel); } if (joinlist_is_in_list (serv, channel)) mg_create_icon_item (_("_Remove from Favorites"), GTK_STOCK_REMOVE, menu, menu_delfav_cb, serv); else mg_create_icon_item (_("_Add to Favorites"), GTK_STOCK_ADD, menu, menu_addfav_cb, serv); } static void menu_open_server_list (GtkWidget *wid, gpointer none) { fe_serverlist_open (current_sess); } static void menu_settings (GtkWidget * wid, gpointer none) { extern void setup_open (void); setup_open (); } static void menu_usermenu (void) { editlist_gui_open (NULL, NULL, usermenu_list, _(DISPLAY_NAME": User menu"), "usermenu", "usermenu.conf", 0); } static void usermenu_create (GtkWidget *menu) { menu_create (menu, usermenu_list, "", FALSE); menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0); /* sep */ menu_quick_item_with_callback (menu_usermenu, _("Edit This Menu..."), menu, 0); } static void usermenu_destroy (GtkWidget * menu) { GList *items = ((GtkMenuShell *) menu)->children; GList *next; while (items) { next = items->next; gtk_widget_destroy (items->data); items = next; } } void usermenu_update (void) { int done_main = FALSE; GSList *list = sess_list; session *sess; GtkWidget *menu; while (list) { sess = list->data; menu = sess->gui->menu_item[MENU_ID_USERMENU]; if (sess->gui->is_tab) { if (!done_main && menu) { usermenu_destroy (menu); usermenu_create (menu); done_main = TRUE; } } else if (menu) { usermenu_destroy (menu); usermenu_create (menu); } list = list->next; } } static void menu_newserver_window (GtkWidget * wid, gpointer none) { int old = prefs.hex_gui_tab_chans; prefs.hex_gui_tab_chans = 0; new_ircwindow (NULL, NULL, SESS_SERVER, 0); prefs.hex_gui_tab_chans = old; } static void menu_newchannel_window (GtkWidget * wid, gpointer none) { int old = prefs.hex_gui_tab_chans; prefs.hex_gui_tab_chans = 0; new_ircwindow (current_sess->server, NULL, SESS_CHANNEL, 0); prefs.hex_gui_tab_chans = old; } static void menu_newserver_tab (GtkWidget * wid, gpointer none) { int old = prefs.hex_gui_tab_chans; int oldf = prefs.hex_gui_tab_newtofront; prefs.hex_gui_tab_chans = 1; /* force focus if setting is "only requested tabs" */ if (prefs.hex_gui_tab_newtofront == 2) prefs.hex_gui_tab_newtofront = 1; new_ircwindow (NULL, NULL, SESS_SERVER, 0); prefs.hex_gui_tab_chans = old; prefs.hex_gui_tab_newtofront = oldf; } static void menu_newchannel_tab (GtkWidget * wid, gpointer none) { int old = prefs.hex_gui_tab_chans; prefs.hex_gui_tab_chans = 1; new_ircwindow (current_sess->server, NULL, SESS_CHANNEL, 0); prefs.hex_gui_tab_chans = old; } static void menu_rawlog (GtkWidget * wid, gpointer none) { open_rawlog (current_sess->server); } static void menu_detach (GtkWidget * wid, gpointer none) { mg_detach (current_sess, 0); } static void menu_close (GtkWidget * wid, gpointer none) { mg_close_sess (current_sess); } static void menu_quit (GtkWidget * wid, gpointer none) { mg_open_quit_dialog (FALSE); } static void menu_search () { search_open (current_sess); } static void menu_search_next () { GtkXText *xtext = GTK_XTEXT (current_sess->gui->xtext); xtext_buffer *buf = xtext->buffer; if (!gtk_xtext_search (xtext, buf->search_text, (buf->search_flags & (case_match | follow | regexp)), NULL)) { fe_message (_("Search hit end, not found."), FE_MSG_ERROR); } } static void menu_search_prev () { GtkXText *xtext = GTK_XTEXT (current_sess->gui->xtext); xtext_buffer *buf = xtext->buffer; if (!gtk_xtext_search(xtext, buf->search_text, (buf->search_flags & (case_match | follow | regexp)) | backward, NULL)) { fe_message (_("Search hit end, not found."), FE_MSG_ERROR); } } static void menu_search_reset () { GtkXText *xtext = GTK_XTEXT (current_sess->gui->xtext); xtext_buffer *buf = xtext->buffer; gtk_xtext_search (xtext, "", 0, NULL); } static void menu_resetmarker (GtkWidget * wid, gpointer none) { gtk_xtext_reset_marker_pos (GTK_XTEXT (current_sess->gui->xtext)); } static void menu_copy_selection (GtkWidget * wid, gpointer none) { gtk_xtext_copy_selection (GTK_XTEXT (current_sess->gui->xtext)); } static void menu_flushbuffer (GtkWidget * wid, gpointer none) { fe_text_clear (current_sess, 0); } static void savebuffer_req_done (session *sess, char *file) { int fh; if (!file) return; fh = open (file, O_TRUNC | O_WRONLY | O_CREAT, 0600); if (fh != -1) { gtk_xtext_save (GTK_XTEXT (sess->gui->xtext), fh); close (fh); } } static void menu_savebuffer (GtkWidget * wid, gpointer none) { gtkutil_file_req (_("Select an output filename"), savebuffer_req_done, current_sess, NULL, NULL, FRF_WRITE); } static void menu_disconnect (GtkWidget * wid, gpointer none) { handle_command (current_sess, "DISCON", FALSE); } static void menu_reconnect (GtkWidget * wid, gpointer none) { if (current_sess->server->hostname[0]) handle_command (current_sess, "RECONNECT", FALSE); else fe_serverlist_open (current_sess); } static void menu_join_cb (GtkWidget *dialog, gint response, GtkEntry *entry) { switch (response) { case GTK_RESPONSE_ACCEPT: menu_chan_join (NULL, entry->text); break; case GTK_RESPONSE_HELP: chanlist_opengui (current_sess->server, TRUE); break; } gtk_widget_destroy (dialog); } static void menu_join_entry_cb (GtkWidget *entry, GtkDialog *dialog) { gtk_dialog_response (dialog, GTK_RESPONSE_ACCEPT); } static void menu_join (GtkWidget * wid, gpointer none) { GtkWidget *hbox, *dialog, *entry, *label; dialog = gtk_dialog_new_with_buttons (_("Join Channel"), GTK_WINDOW (parent_window), 0, _("Retrieve channel list..."), GTK_RESPONSE_HELP, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (dialog)->vbox), TRUE); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); hbox = gtk_hbox_new (TRUE, 0); entry = gtk_entry_new (); GTK_ENTRY (entry)->editable = 0; /* avoid auto-selection */ gtk_entry_set_text (GTK_ENTRY (entry), "#"); g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (menu_join_entry_cb), dialog); gtk_box_pack_end (GTK_BOX (hbox), entry, 0, 0, 0); label = gtk_label_new (_("Enter Channel to Join:")); gtk_box_pack_end (GTK_BOX (hbox), label, 0, 0, 0); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (menu_join_cb), entry); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); gtk_widget_show_all (dialog); gtk_editable_set_editable (GTK_EDITABLE (entry), TRUE); gtk_editable_set_position (GTK_EDITABLE (entry), 1); } static void menu_away (GtkCheckMenuItem *item, gpointer none) { handle_command (current_sess, item->active ? "away" : "back", FALSE); } static void menu_chanlist (GtkWidget * wid, gpointer none) { chanlist_opengui (current_sess->server, FALSE); } static void menu_banlist (GtkWidget * wid, gpointer none) { banlist_opengui (current_sess); } #ifdef USE_PLUGIN static void menu_loadplugin (void) { plugingui_load (); } static void menu_pluginlist (void) { plugingui_open (); } #else #define menu_pluginlist 0 #define menu_loadplugin 0 #endif #define usercommands_help _("User Commands - Special codes:\n\n"\ "%c = current channel\n"\ "%e = current network name\n"\ "%m = machine info\n"\ "%n = your nick\n"\ "%t = time/date\n"\ "%v = HexChat version\n"\ "%2 = word 2\n"\ "%3 = word 3\n"\ "&2 = word 2 to the end of line\n"\ "&3 = word 3 to the end of line\n\n"\ "eg:\n"\ "/cmd john hello\n\n"\ "%2 would be \042john\042\n"\ "&2 would be \042john hello\042.") #define ulbutton_help _("Userlist Buttons - Special codes:\n\n"\ "%a = all selected nicks\n"\ "%c = current channel\n"\ "%e = current network name\n"\ "%h = selected nick's hostname\n"\ "%m = machine info\n"\ "%n = your nick\n"\ "%s = selected nick\n"\ "%t = time/date\n") #define dlgbutton_help _("Dialog Buttons - Special codes:\n\n"\ "%a = all selected nicks\n"\ "%c = current channel\n"\ "%e = current network name\n"\ "%h = selected nick's hostname\n"\ "%m = machine info\n"\ "%n = your nick\n"\ "%s = selected nick\n"\ "%t = time/date\n") #define ctcp_help _("CTCP Replies - Special codes:\n\n"\ "%d = data (the whole ctcp)\n"\ "%e = current network name\n"\ "%m = machine info\n"\ "%s = nick who sent the ctcp\n"\ "%t = time/date\n"\ "%2 = word 2\n"\ "%3 = word 3\n"\ "&2 = word 2 to the end of line\n"\ "&3 = word 3 to the end of line\n\n") #define url_help _("URL Handlers - Special codes:\n\n"\ "%s = the URL string\n\n"\ "Putting a ! in front of the command\n"\ "indicates it should be sent to a\n"\ "shell instead of HexChat") static void menu_usercommands (void) { editlist_gui_open (NULL, NULL, command_list, _(DISPLAY_NAME": User Defined Commands"), "commands", "commands.conf", usercommands_help); } static void menu_ulpopup (void) { editlist_gui_open (NULL, NULL, popup_list, _(DISPLAY_NAME": Userlist Popup menu"), "popup", "popup.conf", ulbutton_help); } static void menu_rpopup (void) { editlist_gui_open (_("Text"), _("Replace with"), replace_list, _(DISPLAY_NAME": Replace"), "replace", "replace.conf", 0); } static void menu_urlhandlers (void) { editlist_gui_open (NULL, NULL, urlhandler_list, _(DISPLAY_NAME": URL Handlers"), "urlhandlers", "urlhandlers.conf", url_help); } static void menu_evtpopup (void) { pevent_dialog_show (); } static void menu_keypopup (void) { key_dialog_show (); } static void menu_ulbuttons (void) { editlist_gui_open (NULL, NULL, button_list, _(DISPLAY_NAME": Userlist buttons"), "buttons", "buttons.conf", ulbutton_help); } static void menu_dlgbuttons (void) { editlist_gui_open (NULL, NULL, dlgbutton_list, _(DISPLAY_NAME": Dialog buttons"), "dlgbuttons", "dlgbuttons.conf", dlgbutton_help); } static void menu_ctcpguiopen (void) { editlist_gui_open (NULL, NULL, ctcp_list, _(DISPLAY_NAME": CTCP Replies"), "ctcpreply", "ctcpreply.conf", ctcp_help); } static void menu_docs (GtkWidget *wid, gpointer none) { fe_open_url ("http://www.hexchat.org/"); } /*static void menu_webpage (GtkWidget *wid, gpointer none) { fe_open_url ("http://xchat.org"); }*/ static void menu_dcc_win (GtkWidget *wid, gpointer none) { fe_dcc_open_recv_win (FALSE); fe_dcc_open_send_win (FALSE); } static void menu_dcc_chat_win (GtkWidget *wid, gpointer none) { fe_dcc_open_chat_win (FALSE); } void menu_change_layout (void) { if (prefs.hex_gui_tab_layout == 0) { menu_setting_foreach (NULL, MENU_ID_LAYOUT_TABS, 1); menu_setting_foreach (NULL, MENU_ID_LAYOUT_TREE, 0); mg_change_layout (0); } else { menu_setting_foreach (NULL, MENU_ID_LAYOUT_TABS, 0); menu_setting_foreach (NULL, MENU_ID_LAYOUT_TREE, 1); mg_change_layout (2); } } static void menu_layout_cb (GtkWidget *item, gpointer none) { prefs.hex_gui_tab_layout = 2; if (GTK_CHECK_MENU_ITEM (item)->active) prefs.hex_gui_tab_layout = 0; menu_change_layout (); } static void menu_apply_metres_cb (session *sess) { mg_update_meters (sess->gui); } static void menu_metres_off (GtkWidget *item, gpointer none) { if (GTK_CHECK_MENU_ITEM (item)->active) { prefs.hex_gui_lagometer = 0; prefs.hex_gui_throttlemeter = 0; menu_setting_foreach (menu_apply_metres_cb, -1, 0); } } static void menu_metres_text (GtkWidget *item, gpointer none) { if (GTK_CHECK_MENU_ITEM (item)->active) { prefs.hex_gui_lagometer = 2; prefs.hex_gui_throttlemeter = 2; menu_setting_foreach (menu_apply_metres_cb, -1, 0); } } static void menu_metres_graph (GtkWidget *item, gpointer none) { if (GTK_CHECK_MENU_ITEM (item)->active) { prefs.hex_gui_lagometer = 1; prefs.hex_gui_throttlemeter = 1; menu_setting_foreach (menu_apply_metres_cb, -1, 0); } } static void menu_metres_both (GtkWidget *item, gpointer none) { if (GTK_CHECK_MENU_ITEM (item)->active) { prefs.hex_gui_lagometer = 3; prefs.hex_gui_throttlemeter = 3; menu_setting_foreach (menu_apply_metres_cb, -1, 0); } } static struct mymenu mymenu[] = { {N_("He_xChat"), 0, 0, M_NEWMENU, 0, 0, 1}, {N_("Network Li_st..."), menu_open_server_list, (char *)&pix_book, M_MENUPIX, 0, 0, 1, GDK_s}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("_New"), 0, GTK_STOCK_NEW, M_MENUSUB, 0, 0, 1}, {N_("Server Tab..."), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1, GDK_t}, {N_("Channel Tab..."), menu_newchannel_tab, 0, M_MENUITEM, 0, 0, 1}, {N_("Server Window..."), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1}, {N_("Channel Window..."), menu_newchannel_window, 0, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, {0, 0, 0, M_SEP, 0, 0, 0}, #ifdef USE_PLUGIN {N_("_Load Plugin or Script..."), menu_loadplugin, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 0, 1}, #else {N_("_Load Plugin or Script..."), 0, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 0, 0}, #endif {0, 0, 0, M_SEP, 0, 0, 0}, /* 11 */ #define DETACH_OFFSET (12) {0, menu_detach, GTK_STOCK_REDO, M_MENUSTOCK, 0, 0, 1, GDK_i}, /* 12 */ #define CLOSE_OFFSET (13) {0, menu_close, GTK_STOCK_CLOSE, M_MENUSTOCK, 0, 0, 1, GDK_w}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("_Quit"), menu_quit, GTK_STOCK_QUIT, M_MENUSTOCK, 0, 0, 1, GDK_q}, /* 15 */ {N_("_View"), 0, 0, M_NEWMENU, 0, 0, 1}, #define MENUBAR_OFFSET (17) {N_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1, GDK_F9}, {N_("_Topic Bar"), menu_topicbar_toggle, 0, M_MENUTOG, MENU_ID_TOPICBAR, 0, 1}, {N_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1, GDK_F7}, {N_("U_serlist Buttons"), menu_ulbuttons_toggle, 0, M_MENUTOG, MENU_ID_ULBUTTONS, 0, 1}, {N_("M_ode Buttons"), menu_cmbuttons_toggle, 0, M_MENUTOG, MENU_ID_MODEBUTTONS, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("_Channel Switcher"), 0, 0, M_MENUSUB, 0, 0, 1}, /* 23 */ #define TABS_OFFSET (24) {N_("_Tabs"), menu_layout_cb, 0, M_MENURADIO, MENU_ID_LAYOUT_TABS, 0, 1}, {N_("T_ree"), 0, 0, M_MENURADIO, MENU_ID_LAYOUT_TREE, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, {N_("_Network Meters"), 0, 0, M_MENUSUB, 0, 0, 1}, /* 27 */ #define METRE_OFFSET (28) {N_("Off"), menu_metres_off, 0, M_MENURADIO, 0, 0, 1}, {N_("Graph"), menu_metres_graph, 0, M_MENURADIO, 0, 0, 1}, {N_("Text"), menu_metres_text, 0, M_MENURADIO, 0, 0, 1}, {N_("Both"), menu_metres_both, 0, M_MENURADIO, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, /* 32 */ {N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1}, {N_("_Disconnect"), menu_disconnect, GTK_STOCK_DISCONNECT, M_MENUSTOCK, MENU_ID_DISCONNECT, 0, 1}, {N_("_Reconnect"), menu_reconnect, GTK_STOCK_CONNECT, M_MENUSTOCK, MENU_ID_RECONNECT, 0, 1}, {N_("Join a Channel..."), menu_join, GTK_STOCK_JUMP_TO, M_MENUSTOCK, MENU_ID_JOIN, 0, 1}, {N_("List of Channels..."), menu_chanlist, GTK_STOCK_INDEX, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, #define AWAY_OFFSET (39) {N_("Marked Away"), menu_away, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_a}, {N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 40 */ {N_("S_ettings"), 0, 0, M_NEWMENU, 0, 0, 1}, {N_("_Preferences"), menu_settings, GTK_STOCK_PREFERENCES, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("Auto Replace..."), menu_rpopup, 0, M_MENUITEM, 0, 0, 1}, {N_("CTCP Replies..."), menu_ctcpguiopen, 0, M_MENUITEM, 0, 0, 1}, {N_("Dialog Buttons..."), menu_dlgbuttons, 0, M_MENUITEM, 0, 0, 1}, {N_("Keyboard Shortcuts..."), menu_keypopup, 0, M_MENUITEM, 0, 0, 1}, {N_("Text Events..."), menu_evtpopup, 0, M_MENUITEM, 0, 0, 1}, {N_("URL Handlers..."), menu_urlhandlers, 0, M_MENUITEM, 0, 0, 1}, {N_("User Commands..."), menu_usercommands, 0, M_MENUITEM, 0, 0, 1}, {N_("Userlist Buttons..."), menu_ulbuttons, 0, M_MENUITEM, 0, 0, 1}, {N_("Userlist Popup..."), menu_ulpopup, 0, M_MENUITEM, 0, 0, 1}, /* 52 */ {N_("_Window"), 0, 0, M_NEWMENU, 0, 0, 1}, {N_("Ban List..."), menu_banlist, 0, M_MENUITEM, 0, 0, 1}, {N_("Character Chart..."), ascii_open, 0, M_MENUITEM, 0, 0, 1}, {N_("Direct Chat..."), menu_dcc_chat_win, 0, M_MENUITEM, 0, 0, 1}, {N_("File Transfers..."), menu_dcc_win, 0, M_MENUITEM, 0, 0, 1}, {N_("Friends List..."), notify_opengui, 0, M_MENUITEM, 0, 0, 1}, {N_("Ignore List..."), ignore_gui_open, 0, M_MENUITEM, 0, 0, 1}, {N_("Plugins and Scripts..."), menu_pluginlist, 0, M_MENUITEM, 0, 0, 1}, {N_("Raw Log..."), menu_rawlog, 0, M_MENUITEM, 0, 0, 1}, /* 61 */ {N_("URL Grabber..."), url_opengui, 0, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_m}, {N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1, GDK_C}, {N_("C_lear Text"), menu_flushbuffer, GTK_STOCK_CLEAR, M_MENUSTOCK, 0, 0, 1, GDK_l}, {N_("Save Text..."), menu_savebuffer, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 0, 1}, #define SEARCH_OFFSET 68 {N_("Search"), 0, GTK_STOCK_JUSTIFY_LEFT, M_MENUSUB, 0, 0, 1}, {N_("Search Text..."), menu_search, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_f}, {N_("Reset Search"), menu_search_reset, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_F}, {N_("Search Next" ), menu_search_next, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_g}, {N_("Search Previous" ), menu_search_prev, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_G}, {0, 0, 0, M_END, 0, 0, 0}, {N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */ {N_("_Contents"), menu_docs, GTK_STOCK_HELP, M_MENUSTOCK, 0, 0, 1, GDK_F1}, #if 0 {N_("Check for updates"), menu_update, 0, M_MENUITEM, 0, 1}, #endif {N_("_About"), menu_about, GTK_STOCK_ABOUT, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, }; GtkWidget * create_icon_menu (char *labeltext, void *stock_name, int is_stock) { GtkWidget *item, *img; if (is_stock) img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); else img = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name)); item = gtk_image_menu_item_new_with_mnemonic (labeltext); gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img); gtk_widget_show (img); return item; } /* Override the default GTK2.4 handler, which would make menu bindings not work when the menu-bar is hidden. */ static gboolean menu_canacaccel (GtkWidget *widget, guint signal_id, gpointer user_data) { /* GTK2.2 behaviour */ #if GTK_CHECK_VERSION(2,20,0) return gtk_widget_is_sensitive (widget); #else return GTK_WIDGET_IS_SENSITIVE (widget); #endif } /* === STUFF FOR /MENU === */ static GtkMenuItem * menu_find_item (GtkWidget *menu, char *name) { GList *items = ((GtkMenuShell *) menu)->children; GtkMenuItem *item; GtkWidget *child; const char *labeltext; while (items) { item = items->data; child = GTK_BIN (item)->child; if (child) /* separators arn't labels, skip them */ { labeltext = g_object_get_data (G_OBJECT (item), "name"); if (!labeltext) labeltext = gtk_label_get_text (GTK_LABEL (child)); if (!menu_streq (labeltext, name, 1)) return item; } else if (name == NULL) { return item; } items = items->next; } return NULL; } static GtkWidget * menu_find_path (GtkWidget *menu, char *path) { GtkMenuItem *item; char *s; char name[128]; int len; /* grab the next part of the path */ s = strchr (path, '/'); len = s - path; if (!s) len = strlen (path); len = MIN (len, sizeof (name) - 1); memcpy (name, path, len); name[len] = 0; item = menu_find_item (menu, name); if (!item) return NULL; menu = gtk_menu_item_get_submenu (item); if (!menu) return NULL; path += len; if (*path == 0) return menu; return menu_find_path (menu, path + 1); } static GtkWidget * menu_find (GtkWidget *menu, char *path, char *label) { GtkWidget *item = NULL; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) item = (GtkWidget *)menu_find_item (menu, label); return item; } static void menu_foreach_gui (menu_entry *me, void (*callback) (GtkWidget *, menu_entry *, char *)) { GSList *list = sess_list; int tabdone = FALSE; session *sess; if (!me->is_main) return; /* not main menu */ while (list) { sess = list->data; /* do it only once for tab sessions, since they share a GUI */ if (!sess->gui->is_tab || !tabdone) { callback (sess->gui->menu, me, NULL); if (sess->gui->is_tab) tabdone = TRUE; } list = list->next; } } static void menu_update_cb (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item; item = menu_find (menu, me->path, me->label); if (item) { gtk_widget_set_sensitive (item, me->enable); /* must do it without triggering the callback */ if (GTK_IS_CHECK_MENU_ITEM (item)) GTK_CHECK_MENU_ITEM (item)->active = me->state; } } /* radio state changed via mouse click */ static void menu_radio_cb (GtkCheckMenuItem *item, menu_entry *me) { me->state = 0; if (item->active) me->state = 1; /* update the state, incase this was changed via right-click. */ /* This will update all other windows and menu bars */ menu_foreach_gui (me, menu_update_cb); if (me->state && me->cmd) handle_command (current_sess, me->cmd, FALSE); } /* toggle state changed via mouse click */ static void menu_toggle_cb (GtkCheckMenuItem *item, menu_entry *me) { me->state = 0; if (item->active) me->state = 1; /* update the state, incase this was changed via right-click. */ /* This will update all other windows and menu bars */ menu_foreach_gui (me, menu_update_cb); if (me->state) handle_command (current_sess, me->cmd, FALSE); else handle_command (current_sess, me->ucmd, FALSE); } static GtkWidget * menu_radio_item (char *label, GtkWidget *menu, void *callback, void *userdata, int state, char *groupname) { GtkWidget *item; GtkMenuItem *parent; GSList *grouplist = NULL; parent = menu_find_item (menu, groupname); if (parent) grouplist = gtk_radio_menu_item_get_group ((GtkRadioMenuItem *)parent); item = gtk_radio_menu_item_new_with_label (grouplist, label); gtk_check_menu_item_set_active ((GtkCheckMenuItem*)item, state); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback), userdata); gtk_widget_show (item); return item; } static void menu_reorder (GtkMenu *menu, GtkWidget *item, int pos) { if (pos == 0xffff) /* outbound.c uses this default */ return; if (pos < 0) /* position offset from end/bottom */ gtk_menu_reorder_child (menu, item, (g_list_length (GTK_MENU_SHELL (menu)->children) + pos) - 1); else gtk_menu_reorder_child (menu, item, pos); } static GtkWidget * menu_add_radio (GtkWidget *menu, menu_entry *me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { item = menu_radio_item (me->label, menu, menu_radio_cb, me, me->state, me->group); menu_reorder (GTK_MENU (menu), item, me->pos); } return item; } static GtkWidget * menu_add_toggle (GtkWidget *menu, menu_entry *me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { item = menu_toggle_item (me->label, menu, menu_toggle_cb, me, me->state); menu_reorder (GTK_MENU (menu), item, me->pos); } return item; } static GtkWidget * menu_add_item (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { item = menu_quick_item (me->cmd, me->label, menu, me->markup ? XCMENU_MARKUP|XCMENU_MNEMONIC : XCMENU_MNEMONIC, target, me->icon); menu_reorder (GTK_MENU (menu), item, me->pos); } return item; } static GtkWidget * menu_add_sub (GtkWidget *menu, menu_entry *me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; int pos; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { pos = me->pos; if (pos < 0) /* position offset from end/bottom */ pos = g_list_length (GTK_MENU_SHELL (menu)->children) + pos; menu_quick_sub (me->label, menu, &item, me->markup ? XCMENU_MARKUP|XCMENU_MNEMONIC : XCMENU_MNEMONIC, pos); } return item; } static void menu_del_cb (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item = menu_find (menu, me->path + me->root_offset, me->label); if (item) gtk_widget_destroy (item); } static void menu_add_cb (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item; GtkAccelGroup *accel_group; if (me->group) /* have a group name? Must be a radio item */ item = menu_add_radio (menu, me); else if (me->ucmd) /* have unselect-cmd? Must be a toggle item */ item = menu_add_toggle (menu, me); else if (me->cmd || !me->label) /* label=NULL for separators */ item = menu_add_item (menu, me, target); else item = menu_add_sub (menu, me); if (item) { gtk_widget_set_sensitive (item, me->enable); if (me->key) { accel_group = g_object_get_data (G_OBJECT (menu), "accel"); if (accel_group) /* popup menus don't have them */ gtk_widget_add_accelerator (item, "activate", accel_group, me->key, me->modifier, GTK_ACCEL_VISIBLE); } } } char * fe_menu_add (menu_entry *me) { char *text; menu_foreach_gui (me, menu_add_cb); if (!me->markup) return NULL; if (!pango_parse_markup (me->label, -1, 0, NULL, &text, NULL, NULL)) return NULL; /* return the label with markup stripped */ return text; } void fe_menu_del (menu_entry *me) { menu_foreach_gui (me, menu_del_cb); } void fe_menu_update (menu_entry *me) { menu_foreach_gui (me, menu_update_cb); } /* used to add custom menus to the right-click menu */ static void menu_add_plugin_mainmenu_items (GtkWidget *menu) { GSList *list; menu_entry *me; list = menu_list; /* outbound.c */ while (list) { me = list->data; if (me->is_main) menu_add_cb (menu, me, NULL); list = list->next; } } void menu_add_plugin_items (GtkWidget *menu, char *root, char *target) { GSList *list; menu_entry *me; list = menu_list; /* outbound.c */ while (list) { me = list->data; if (!me->is_main && !strncmp (me->path, root + 1, root[0])) menu_add_cb (menu, me, target); list = list->next; } } /* === END STUFF FOR /MENU === */ GtkWidget * menu_create_main (void *accel_group, int bar, int away, int toplevel, GtkWidget **menu_widgets) { int i = 0; GtkWidget *item; GtkWidget *menu = 0; GtkWidget *menu_item = 0; GtkWidget *menu_bar; GtkWidget *usermenu = 0; GtkWidget *submenu = 0; int close_mask = STATE_CTRL; int away_mask = STATE_ALT; char *key_theme = NULL; GtkSettings *settings; GSList *group = NULL; if (bar) menu_bar = gtk_menu_bar_new (); else menu_bar = gtk_menu_new (); /* /MENU needs to know this later */ g_object_set_data (G_OBJECT (menu_bar), "accel", accel_group); g_signal_connect (G_OBJECT (menu_bar), "can-activate-accel", G_CALLBACK (menu_canacaccel), 0); /* set the initial state of toggles */ mymenu[MENUBAR_OFFSET].state = !prefs.hex_gui_hide_menu; mymenu[MENUBAR_OFFSET+1].state = prefs.hex_gui_topicbar; mymenu[MENUBAR_OFFSET+2].state = !prefs.hex_gui_ulist_hide; mymenu[MENUBAR_OFFSET+3].state = prefs.hex_gui_ulist_buttons; mymenu[MENUBAR_OFFSET+4].state = prefs.hex_gui_mode_buttons; mymenu[AWAY_OFFSET].state = away; switch (prefs.hex_gui_tab_layout) { case 0: mymenu[TABS_OFFSET].state = 1; mymenu[TABS_OFFSET+1].state = 0; break; default: mymenu[TABS_OFFSET].state = 0; mymenu[TABS_OFFSET+1].state = 1; } mymenu[METRE_OFFSET].state = 0; mymenu[METRE_OFFSET+1].state = 0; mymenu[METRE_OFFSET+2].state = 0; mymenu[METRE_OFFSET+3].state = 0; switch (prefs.hex_gui_lagometer) { case 0: mymenu[METRE_OFFSET].state = 1; break; case 1: mymenu[METRE_OFFSET+1].state = 1; break; case 2: mymenu[METRE_OFFSET+2].state = 1; break; default: mymenu[METRE_OFFSET+3].state = 1; } /* change Close binding to ctrl-shift-w when using emacs keys */ settings = gtk_widget_get_settings (menu_bar); if (settings) { g_object_get (settings, "gtk-key-theme-name", &key_theme, NULL); if (key_theme) { if (!g_ascii_strcasecmp (key_theme, "Emacs")) { close_mask = STATE_SHIFT | STATE_CTRL; mymenu[SEARCH_OFFSET].key = 0; } g_free (key_theme); } } /* Away binding to ctrl-alt-a if the _Help menu conflicts (FR/PT/IT) */ { char *help = _("_Help"); char *under = strchr (help, '_'); if (under && (under[1] == 'a' || under[1] == 'A')) away_mask = STATE_ALT | STATE_CTRL; } if (!toplevel) { mymenu[DETACH_OFFSET].text = N_("_Detach"); mymenu[CLOSE_OFFSET].text = N_("_Close"); } else { mymenu[DETACH_OFFSET].text = N_("_Attach"); mymenu[CLOSE_OFFSET].text = N_("_Close"); } while (1) { item = NULL; if (mymenu[i].id == MENU_ID_USERMENU && !prefs.hex_gui_usermenu) { i++; continue; } switch (mymenu[i].type) { case M_NEWMENU: if (menu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu); item = menu = gtk_menu_new (); if (mymenu[i].id == MENU_ID_USERMENU) usermenu = menu; menu_item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text)); /* record the English name for /menu */ g_object_set_data (G_OBJECT (menu_item), "name", mymenu[i].text); gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), menu_item); gtk_widget_show (menu_item); break; case M_MENUPIX: item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, FALSE); goto normalitem; case M_MENUSTOCK: item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE); goto normalitem; case M_MENUITEM: item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text)); normalitem: if (mymenu[i].key != 0) gtk_widget_add_accelerator (item, "activate", accel_group, mymenu[i].key, mymenu[i].key == GDK_F1 ? 0 : mymenu[i].key == GDK_w ? close_mask : (g_ascii_isupper (mymenu[i].key)) ? STATE_SHIFT | STATE_CTRL : STATE_CTRL, GTK_ACCEL_VISIBLE); if (mymenu[i].callback) g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (mymenu[i].callback), 0); if (submenu) gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item); else gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); break; case M_MENUTOG: item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text)); togitem: /* must avoid callback for Radio buttons */ GTK_CHECK_MENU_ITEM (item)->active = mymenu[i].state; /*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state);*/ if (mymenu[i].key != 0) gtk_widget_add_accelerator (item, "activate", accel_group, mymenu[i].key, mymenu[i].id == MENU_ID_AWAY ? away_mask : STATE_CTRL, GTK_ACCEL_VISIBLE); if (mymenu[i].callback) g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (mymenu[i].callback), 0); if (submenu) gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item); else gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); gtk_widget_set_sensitive (item, mymenu[i].sensitive); break; case M_MENURADIO: item = gtk_radio_menu_item_new_with_mnemonic (group, _(mymenu[i].text)); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); goto togitem; case M_SEP: item = gtk_menu_item_new (); gtk_widget_set_sensitive (item, FALSE); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); break; case M_MENUSUB: group = NULL; submenu = gtk_menu_new (); item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE); /* record the English name for /menu */ g_object_set_data (G_OBJECT (item), "name", mymenu[i].text); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); break; /*case M_END:*/ default: if (!submenu) { if (menu) { gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu); menu_add_plugin_mainmenu_items (menu_bar); } if (usermenu) usermenu_create (usermenu); return (menu_bar); } submenu = NULL; } /* record this GtkWidget * so it's state might be changed later */ if (mymenu[i].id != 0 && menu_widgets) /* this ends up in sess->gui->menu_item[MENU_ID_XXX] */ menu_widgets[mymenu[i].id] = item; i++; } }