/* mpv_gtk.c GTK (X Window) Interface (Linux/Unix) mp - Programmer Text Editor Copyright (C) 1991/2005 Angel Ortega 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. http://www.triptico.com */ #include "config.h" #include #include "mp_core.h" #include "mp_video.h" #ifdef CONFOPT_GTK #include #include #include #include #include #include #include #include #include "mp_func.h" #include "mp_iface.h" #include "mp_lang.h" #include "mp_synhi.h" #include "mp_conf.h" /******************* Data ********************/ GtkWidget * window=NULL; GtkWidget * menu=NULL; GtkWidget * menu_bar=NULL; GtkWidget * file_tabs=NULL; GtkWidget * entry=NULL; GtkWidget * list=NULL; GtkWidget * area=NULL; GtkWidget * scrollbar=NULL; GtkWidget * status=NULL; GdkGC * gc=NULL; #if GTK_MAJOR_VERSION < 2 GdkIC * ic=NULL; #else GtkIMContext * im=NULL; #endif GdkPixmap * pixmap=NULL; GdkFont * _font_normal=NULL; GdkFont * _font_italic=NULL; /* last directory */ char _mpv_last_directory[1024]; /* readline buffer */ static char _mpv_readline_buf[1024]; /* confirmation value for gtk dialogs */ static int _mpv_confirm_value=-1; /* selected element from the list */ static int _mpv_selected_item=0; /* font information */ char _mpv_font_face[80]=""; #if GTK_MAJOR_VERSION >= 2 float _mpv_font_size = 12; #else float _mpv_font_size = 14; #endif int _mpv_font_width=0; int _mpv_font_height=0; char _mpv_font_weight[80]="medium"; char _mpv_font_encoding[32]="iso8859"; /* frame buffer with chars in document window */ static int * _mpv_fb=NULL; static int * _mpv_fbo=NULL; static int _mpv_fb_size=0; /* cursor position */ static int _mpv_x_cursor; static int _mpv_y_cursor; /* temporal buffer */ static char _mpv_buffer[1024]; /* flag to use of italic fonts */ int _use_italics=0; /* set if selection is ours */ int _mpv_selection=0; /* colors */ static GdkColor _inks[MP_COLOR_PRIVATE]; static GdkColor _papers[MP_COLOR_PRIVATE]; #include "mp.xpm" static int _use_double_buffer=1; /* window geometry */ int _mpv_gtk_xpos=-1; int _mpv_gtk_ypos=-1; int _mpv_gtk_width=600; int _mpv_gtk_height=400; /* the X11 font in use */ char _x11_font_spec[1024]; /* input context */ static char _mpv_im_char='\0'; /* use pango for painting */ int _mpv_use_pango=1; #if GTK_MAJOR_VERSION >= 2 /* pango stuff */ PangoFontDescription * _pango_font_desc=NULL; #endif /* if the expose is generated by a keypress, this is set, meaning 'try to be clever about what needs to be redrawn'. Otherwise, full text buffer is redrawn by clearing _mpv_fbo */ static int _mpv_expose_by_key=0; /* maximize main window */ static int mpv_gtk_maximize=0; /******************* Code *******************/ /* from mpv_unix_common.c */ extern int _unix_strcasecmp(char *, char *); extern FILE * _unix_fopen(char * file, char * mode); extern mp_txt * _unix_glob(char * spec); extern int _unix_help(char * term, int synhi); extern void _mpv_strip_cwd(char * buf, int size); extern int _unix_popen(mp_txt *txt,char *cmd,char *mode); #if GTK_MAJOR_VERSION >= 2 char * _(const char * str) { static char tmp[1024]; char * ptr; if((ptr=g_locale_to_utf8(str, -1, NULL, NULL, NULL)) != NULL) { strncpy(tmp, ptr, sizeof(tmp)); free(ptr); } else tmp[0]='\0'; return(tmp); } char * __(const char * str) { static char tmp[1024]; char * ptr; if((ptr=g_locale_from_utf8(str, -1, NULL, NULL, NULL)) != NULL) { strncpy(tmp, ptr, sizeof(tmp)); free(ptr); } else tmp[0]='\0'; return(tmp); } #else #define _(x) (x) #define __(x) (x) #endif static void _goto(int x, int y) { /* just store the coords */ _mpv_x_cursor=x; _mpv_y_cursor=y; } static void _char(int c, int color) { if(_mpv_y_cursor >= _mpv_y_size || _mpv_x_cursor >= _mpv_x_size) return; /* fill the frame buffer */ _mpv_fb[(_mpv_y_cursor * _mpv_x_size) + _mpv_x_cursor]= (color << 8)|((unsigned char)c); _mpv_x_cursor++; } static void _str(char * str, int color) { int * fb; fb=&_mpv_fb[(_mpv_y_cursor * _mpv_x_size) + _mpv_x_cursor]; while(*str) { *fb=(color << 8)|(*str); fb++; _mpv_x_cursor++; str++; } } static void _cursor(int x, int y) { /* dummy! */ } static void _refresh(void) { GdkRectangle r; r.x=0; r.y=0; #if GTK_MAJOR_VERSION < 2 r.width=0; r.height=0; #else r.width=area->allocation.width; r.height=area->allocation.height; #endif gtk_widget_draw(area, &r); } static void _title(char * str) { char tmp[2048]; static char _prev[2048]=""; strncpy(tmp,"mp " VERSION, sizeof(tmp)); if(str==NULL && _mp_active != NULL) str=_mp_active->name; if(str!=NULL && *str!='\0') { strcat(tmp," - "); strcat(tmp,str); } /* redraw title only if it's different from the previously set one */ if(strcmp(_prev, tmp) != 0) { gtk_window_set_title(GTK_WINDOW(window), tmp); strncpy(_prev, tmp, sizeof(_prev)); } } static void _status_line(char * str) { gtk_label_set_text(GTK_LABEL(status), _(str)); } static char * _mpv_filter_menu_label(char * label) { static char tmp[1024]; int n; for(n=0;*label && *label!='\t';label++) { #if GTK_MAJOR_VERSION < 2 if(*label!='&') tmp[n++]=*label; #else if(*label == '&') tmp[n++] = '_'; else if (*label == '_') { tmp[n++] = '_'; tmp[n++] = '_'; } else tmp[n++] = *label; #endif } tmp[n]='\0'; return(_(tmp)); } static void _add_menu(char * label) { GtkWidget * menu_item; label=L(label); if(menu_bar==NULL) menu_bar=gtk_menu_bar_new(); menu=gtk_menu_new(); label=_mpv_filter_menu_label(label); #if GTK_MAJOR_VERSION < 2 menu_item=gtk_menu_item_new_with_label(label); #else menu_item=gtk_menu_item_new_with_mnemonic(label); #endif gtk_widget_show(menu_item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu); gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), menu_item); } static void _mpv_menu_item_callback(char * funcname) /* menu click callback */ { mpi_process('\0', NULL, funcname); if(_mpi_exit_requested) gtk_main_quit(); } static void _add_menu_item(char * funcname) { GtkWidget * menu_item; char tmp[1024]; char * keyname; char * label; char * signal="activate"; int * i; if((label=mpf_get_desc_by_funcname(funcname)) == NULL) return; label=_(L(_mpv_filter_menu_label(label))); if((keyname=mpf_get_keyname_by_funcname(funcname))!=NULL) { keyname=L(keyname); snprintf(tmp,sizeof(tmp),"%s - [%s]",label,keyname); label=tmp; } if(*label=='-') menu_item=gtk_menu_item_new(); else { i=mpf_toggle_function_value(funcname); if(i!=NULL) { menu_item=gtk_check_menu_item_new_with_label(label); signal="toggled"; gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(menu_item), *i); } else menu_item=gtk_menu_item_new_with_label(label); } gtk_menu_append(GTK_MENU(menu), menu_item); gtk_signal_connect_object(GTK_OBJECT(menu_item), signal, GTK_SIGNAL_FUNC(_mpv_menu_item_callback), (gpointer) funcname); gtk_widget_show(menu_item); } static void _check_menu(char * funcname, int toggle) { /* dummy! */ } static int _menu(void) { /* dummy! */ return(0); } static void _gtk_really_modal(void) { _mpv_confirm_value=-1; while(_mpv_confirm_value==-1) gtk_main_iteration(); _mpv_expose_by_key=0; } static void _mpv_confirm_yes_callback(GtkWidget * widget, gpointer data) { _mpv_confirm_value=1; gtk_widget_destroy(GTK_WIDGET(widget)); } static void _mpv_confirm_no_callback(GtkWidget * widget, gpointer data) { _mpv_confirm_value=0; gtk_widget_destroy(GTK_WIDGET(widget)); } static void _mpv_confirm_yes_file_callback(GtkWidget * widget, gpointer data) { const char * ptr; ptr=gtk_file_selection_get_filename(GTK_FILE_SELECTION(widget)); strncpy(_mpv_readline_buf,__(ptr),sizeof(_mpv_readline_buf)); _mpv_confirm_value=1; gtk_widget_destroy(GTK_WIDGET(widget)); } static void _mpv_confirm_yes_entry_callback(GtkWidget * widget, gpointer data) { char * ptr; ptr=gtk_editable_get_chars(GTK_EDITABLE(entry),0,-1); strncpy(_mpv_readline_buf,__(ptr),sizeof(_mpv_readline_buf)); g_free(ptr); entry=NULL; _mpv_confirm_value=1; gtk_widget_destroy(GTK_WIDGET(widget)); } static int _mpv_confirm_key_callback(GtkWidget * widget, GdkEventKey * event) { if(event->string[0] == '\r') { _mpv_confirm_yes_callback(widget, NULL); return(1); } else if(event->string[0] == '\e') { _mpv_confirm_no_callback(widget, NULL); return(1); } return(0); } static gint _mpv_confirm_key_yes_no_callback(GtkWidget * widget, GdkEventKey * event) { char * yes; char * no; yes=L("Y"); no=L("N"); if(tolower(event->string[0]) == tolower(*yes)) { _mpv_confirm_yes_callback(widget, NULL); return(1); } else if(tolower(event->string[0]) == tolower(*no)) { _mpv_confirm_no_callback(widget, NULL); return(1); } return(0); } static gint _mpv_confirm_key_entry_callback(GtkWidget * widget, GdkEventKey * event) { if(event->string[0] == '\r') { _mpv_confirm_yes_entry_callback(widget, NULL); return(1); } else if(event->string[0] == '\e') { _mpv_confirm_no_callback(widget, NULL); return(1); } return(0); } static gint _mpv_confirm_key_file_callback(GtkWidget * widget, GdkEventKey * event) { if(event->string[0] == '\e') { _mpv_confirm_no_callback(widget, NULL); return(1); } return(0); } static int _sys_to_clip(void) { if(_mpv_selection) return(1); gtk_selection_convert(area, GDK_SELECTION_PRIMARY, gdk_atom_intern("STRING", FALSE), GDK_CURRENT_TIME); return(0); } static void _clip_to_sys(void) { _mpv_selection=gtk_selection_owner_set(area, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); } static void _alert(char * msg, char * msg2) { char tmp[8192]; GtkWidget * dlg; GtkWidget * label; GtkWidget * button; if(msg2==NULL) strncpy(tmp,msg,sizeof(tmp)); else sprintf(tmp,msg,msg2); dlg=gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dlg),"mp " VERSION); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),5); label=gtk_label_new(_(tmp)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),label,TRUE,TRUE,0); gtk_widget_show(label); button=gtk_button_new_with_label("OK"); gtk_signal_connect_object(GTK_OBJECT(button),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_yes_callback),GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),button,TRUE,TRUE,0); gtk_widget_show(button); gtk_signal_connect(GTK_OBJECT(dlg),"key_press_event", (GtkSignalFunc) _mpv_confirm_key_callback, NULL); gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(dlg),TRUE); gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(window)); gtk_widget_show(dlg); _gtk_really_modal(); } static int _confirm(char * prompt) { GtkWidget * dlg; GtkWidget * label; GtkWidget * ybutton; GtkWidget * nbutton; dlg=gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dlg),"mp " VERSION); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),5); label=gtk_label_new(_(prompt)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),label,TRUE,TRUE,0); gtk_widget_show(label); ybutton=gtk_button_new_with_label(_(L("Yes"))); gtk_signal_connect_object(GTK_OBJECT(ybutton),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_yes_callback),GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),ybutton,TRUE,TRUE,0); gtk_widget_show(ybutton); nbutton=gtk_button_new_with_label(_(L("No"))); gtk_signal_connect_object(GTK_OBJECT(nbutton),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_no_callback),GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),nbutton,TRUE,TRUE,0); gtk_widget_show(nbutton); gtk_signal_connect(GTK_OBJECT(dlg),"key_press_event", (GtkSignalFunc) _mpv_confirm_key_yes_no_callback, NULL); gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(dlg),TRUE); gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(window)); gtk_widget_show(dlg); _gtk_really_modal(); return(_mpv_confirm_value); } static char * _readline(int type, char * prompt, char * def) { GtkWidget * dlg; GtkWidget * label; GtkWidget * ybutton; GtkWidget * nbutton; GtkWidget * combo; GList * combo_items=NULL; char * hist[100]; int n; if(type==MPR_OPEN || type==MPR_SAVE) { dlg=gtk_file_selection_new(prompt); if(def != NULL) gtk_file_selection_set_filename(GTK_FILE_SELECTION(dlg),def); else if (strlen(_mpv_last_directory) > 0) gtk_file_selection_set_filename(GTK_FILE_SELECTION(dlg), _mpv_last_directory); gtk_signal_connect_object( GTK_OBJECT(GTK_FILE_SELECTION(dlg)->ok_button),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_yes_file_callback),GTK_OBJECT(dlg)); gtk_signal_connect_object( GTK_OBJECT(GTK_FILE_SELECTION(dlg)->cancel_button),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_no_callback),GTK_OBJECT(dlg)); gtk_signal_connect(GTK_OBJECT(dlg),"key_press_event", (GtkSignalFunc) _mpv_confirm_key_file_callback, NULL); gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(dlg),TRUE); gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(window)); gtk_widget_show(dlg); _gtk_really_modal(); if(_mpv_confirm_value) { struct stat s; char *p; /* simulate abort if user types ENTER without writing nothing or opens a directory */ if(stat(_mpv_readline_buf,&s)!=-1 && s.st_mode & S_IFDIR) return(NULL); strcpy(_mpv_last_directory, _mpv_readline_buf); if ((p=strrchr(_mpv_last_directory, '/')) != NULL) { *p++; *p = '\0'; } _mpv_strip_cwd(_mpv_readline_buf, sizeof(_mpv_readline_buf)); return(_mpv_readline_buf); } } else { dlg=gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dlg),"mp " VERSION); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),5); label=gtk_label_new(_(prompt)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),label,TRUE,TRUE,0); gtk_widget_show(label); combo=gtk_combo_new(); entry=GTK_COMBO(combo)->entry; gtk_widget_set_usize(combo, 300, -1); gtk_combo_set_use_arrows_always(GTK_COMBO(combo), TRUE); gtk_combo_set_case_sensitive(GTK_COMBO(combo), TRUE); /* store the history into combo_items */ for(n=0;n < 100;n++) { char tmp[512]; if(! mpi_history_get(type, mpi_history_size(type) - n, tmp, sizeof(tmp))) break; if(tmp[0]=='\0') hist[n]=NULL; else { hist[n]=(char *)malloc(sizeof(tmp)+1); strcpy(hist[n],_(tmp)); } combo_items=g_list_append(combo_items, hist[n]); } for(;n < 10;n++) hist[n]=NULL; if(def != NULL && *def != '\0') { gtk_entry_set_text(GTK_ENTRY(entry),def); combo_items=g_list_prepend(combo_items, def); } if(type == MPR_PASSWORD) gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); gtk_combo_set_popdown_strings(GTK_COMBO(combo), combo_items); g_list_free(combo_items); gtk_editable_select_region(GTK_EDITABLE(entry),0,1000); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),combo,TRUE,TRUE,0); gtk_widget_show(combo); ybutton=gtk_button_new_with_label(_(L("OK"))); gtk_signal_connect_object(GTK_OBJECT(ybutton),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_yes_entry_callback), GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), ybutton,TRUE,TRUE,0); gtk_widget_show(ybutton); nbutton=gtk_button_new_with_label(_(L("Cancel"))); gtk_signal_connect_object(GTK_OBJECT(nbutton),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_no_callback),GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), nbutton,TRUE,TRUE,0); gtk_widget_show(nbutton); gtk_signal_connect(GTK_OBJECT(dlg),"key_press_event", (GtkSignalFunc) _mpv_confirm_key_entry_callback, NULL); gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(dlg),TRUE); gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(window)); gtk_widget_show(dlg); gtk_widget_grab_focus(entry); _gtk_really_modal(); for(n=0;n < 10;n++) { if(hist[n]!=NULL) free(hist[n]); } if(_mpv_confirm_value) { mpi_history_add(type, _mpv_readline_buf); return(_mpv_readline_buf); } } return(NULL); } static void _mpv_select_row_callback(GtkCList * list, gint row, gint column, GdkEventButton * event, gpointer data) { _mpv_selected_item=row; } #define LIST_MAX_COLS 4 static int _list(char * title, mp_txt * txt, int pos) { GtkWidget * dlg; GtkWidget * label; GtkWidget * ybutton; GtkWidget * nbutton; GtkWidget * scrolled; char line[1024]; int n, ncols; mp_move_bof(txt); if(txt->lasty == 0) { /* no lines or just one line: exit */ return(0); } /* calculate number of columns based on the number of \t (tabs) found on the first line */ mp_get_str(txt,line,sizeof(line),'\n'); mp_move_bof(txt); for(ncols=1,n=0;line[n];n++) if(line[n] == '\t') ncols++; /* avoid too much columns */ if(ncols > LIST_MAX_COLS) ncols=LIST_MAX_COLS; dlg=gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dlg),"mp " VERSION); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),5); label=gtk_label_new(_(title)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),label,TRUE,TRUE,0); gtk_widget_show(label); scrolled=gtk_scrolled_window_new(NULL, NULL); gtk_widget_set_usize(scrolled, _mpv_gtk_width / 2, _mpv_gtk_height / 2); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),scrolled,TRUE,TRUE,0); gtk_widget_show(scrolled); list=gtk_clist_new(ncols); gtk_clist_set_selection_mode(GTK_CLIST(list), GTK_SELECTION_BROWSE); gtk_clist_column_titles_hide(GTK_CLIST(list)); gtk_container_add(GTK_CONTAINER(scrolled),list); for(n=0;n < ncols;n++) { /* no title for the column */ gtk_clist_set_column_title(GTK_CLIST(list), n, ""); /* set width to an optimal one */ gtk_clist_set_column_auto_resize(GTK_CLIST(list), n, 1); } gtk_widget_show(list); /* traverse the list, adding the elements */ _mpv_selected_item=0; while(mp_peek_char(txt)!='\0') { char * args[LIST_MAX_COLS]; char * ptr; mp_get_str(txt,line,sizeof(line),'\n'); ptr=strtok(line, "\t"); for(n=0;n < ncols && ptr != NULL;n++) { args[n]=strdup(_(ptr)); ptr=strtok(NULL, "\t"); } for(;n < ncols;n++) args[n]=strdup(""); gtk_clist_append(GTK_CLIST(list), args); for(n=0;n < ncols;n++) free(args[n]); } /* set desired element as active */ gtk_clist_select_row(GTK_CLIST(list), pos, 0); /* move also the black outline (cursor) Is there a better way to do this? */ GTK_CLIST(list)->focus_row = pos; gtk_signal_connect(GTK_OBJECT(list), "select-row", GTK_SIGNAL_FUNC(_mpv_select_row_callback), NULL); ybutton=gtk_button_new_with_label(_(L("OK"))); gtk_signal_connect_object(GTK_OBJECT(ybutton),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_yes_callback), GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), ybutton,TRUE,TRUE,0); gtk_widget_show(ybutton); nbutton=gtk_button_new_with_label(_(L("Cancel"))); gtk_signal_connect_object(GTK_OBJECT(nbutton),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_no_callback),GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), nbutton,TRUE,TRUE,0); gtk_widget_show(nbutton); gtk_signal_connect(GTK_OBJECT(dlg),"key_press_event", (GtkSignalFunc) _mpv_confirm_key_callback, NULL); /* gtk_signal_connect_object(GTK_OBJECT(dlg),"key_press_event", GTK_SIGNAL_FUNC(_mpv_confirm_key_callback),GTK_OBJECT(dlg)); */ gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(dlg),TRUE); gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(window)); gtk_widget_show(dlg); gtk_widget_grab_focus(list); _gtk_really_modal(); if(_mpv_confirm_value) return(_mpv_selected_item); return(-1); } static GdkFont * _mpv_get_font(char * fontface, char * slant, int size) { if(fontface==NULL) strncpy(_x11_font_spec, "fixed", sizeof(_x11_font_spec)); else { /* adds a -* if no sub-encoding is set */ if(strchr(_mpv_font_encoding, '-') == NULL) strcat(_mpv_font_encoding, "-*"); snprintf(_x11_font_spec,sizeof(_x11_font_spec), "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s", fontface, _mpv_font_weight, slant, size, _mpv_font_encoding); } return(gdk_font_load(_x11_font_spec)); } static void _mpv_calc_font_width_and_height(void) { #if GTK_MAJOR_VERSION >= 2 if(_mpv_use_pango) { PangoLayout * pa; if(_pango_font_desc == NULL) return; /* From http://developer.gnome.org/doc/API/2.0/ gtk/gtk-question-index.html (1.13) */ pa = gtk_widget_create_pango_layout(area, "m"); pango_layout_set_font_description(pa, _pango_font_desc); pango_layout_get_pixel_size(pa, &_mpv_font_width, &_mpv_font_height); g_object_unref(pa); } else #endif /* GTK_MAJOR_VERSION >= 2 */ { if(_font_normal == NULL) return; _mpv_font_width=gdk_char_width(_font_normal,'m'); _mpv_font_height=gdk_string_height(_font_normal,"lg,_|'"); _mpv_font_height += (_mpv_font_height / 3); } _mpv_x_size=(area->allocation.width / _mpv_font_width) + 1; _mpv_y_size=(area->allocation.height / _mpv_font_height) + 1; /* rebuild framebuffer */ if(_mpv_fb != NULL) { free(_mpv_fb); free(_mpv_fbo); } _mpv_fb_size=_mpv_x_size * _mpv_y_size * sizeof(int); _mpv_fb=(int *) malloc(_mpv_fb_size); _mpv_fbo=(int *) malloc(_mpv_fb_size); memset(_mpv_fb, '\0', _mpv_fb_size); memset(_mpv_fbo, '\0', _mpv_fb_size); /* (re)build pixmap */ if(pixmap != NULL) gdk_pixmap_unref(pixmap); pixmap=gdk_pixmap_new(area->window, area->allocation.width, _mpv_font_height,-1); } static int _zoom(int inc) { static int _min_size=6; static int _max_size=128; GdkFont * fn=NULL; GdkFont * fi=NULL; int s=0; #if GTK_MAJOR_VERSION >= 2 if(_mpv_use_pango) { char tmp[128]; PangoFontDescription * p; char * prev_locale; /* default font */ if(_mpv_font_face[0] == '\0') strcpy(_mpv_font_face, "Mono"); /* set locale to C float numbers */ prev_locale = setlocale(LC_NUMERIC, "C"); snprintf(tmp, sizeof(tmp) - 1, "%s %.1f", _mpv_font_face, _mpv_font_size + (float) inc); tmp[sizeof(tmp) - 1]='\0'; /* restore locale */ setlocale(LC_NUMERIC, prev_locale); if((p=pango_font_description_from_string(tmp)) != NULL) { _pango_font_desc=p; _mpv_font_size += (float) inc; _mpv_calc_font_width_and_height(); mp_log("Using Pango font '%s'\n", tmp); } } else #else /* Pango does not exist on GTK 1.x */ _mpv_use_pango=0; #endif /* GTK_MAJOR_VERSION >= 2 */ { /* default font */ if(_mpv_font_face[0] == '\0') strcpy(_mpv_font_face, "lucidatypewriter"); if(_use_italics) { for(s=(int)_mpv_font_size + inc;s >= _min_size && s <= _max_size;) { fn=_mpv_get_font(_mpv_font_face, "r", s); if(fn == NULL) continue; fi=_mpv_get_font(_mpv_font_face, "i", s); if(fi == NULL) { gdk_font_unref(fn); fn=NULL; } else break; s += inc; } } if(fi == NULL) { _use_italics=0; /* no fonts? may be the selected one cannot be set to italic; retry */ for(s=(int)_mpv_font_size + inc;fn == NULL && s >= _min_size && s <= _max_size;) { if((fn=_mpv_get_font(_mpv_font_face, "r", s)) != NULL) break; s += inc; } } /* if the font could not be set, try a default fallback font ('fixed') */ if(fn == NULL) fn=_mpv_get_font(NULL, "r", s); /* if the font could not be set and there is no previous one, we have a serious problem */ if(fn==NULL) { if(_font_normal==NULL) { printf("Error: font '%s' could not be set\n", _mpv_font_face); exit(0); } else { if(inc == -1) _min_size=(int)_mpv_font_size; else _max_size=(int)_mpv_font_size; } } else { _mpv_font_size=(float)s; if(_font_normal!=NULL) gdk_font_unref(_font_normal); if(_font_italic!=NULL) gdk_font_unref(_font_italic); _font_normal=fn; _font_italic=fi; _mpv_calc_font_width_and_height(); mp_log("Using X11 font '%s'\n", _x11_font_spec); } } return(0); } static void _mpv_value_changed_callback(GtkAdjustment * adj, gpointer * data) { int i=(int) adj->value; if(i >= 0 && i < _mp_active->lasty && i != _mp_active->y) { mp_move_xy(_mp_active, 0, i); _mp_active->vy=_mp_active->y; mpi_draw_all(_mp_active); } } static void _scrollbar(int pos, int size, int max) { GtkAdjustment * adjustment; adjustment=gtk_range_get_adjustment(GTK_RANGE(scrollbar)); if((int)adjustment->upper==max && (int)adjustment->page_size==size && (int)adjustment->page_increment==size && (int)adjustment->value==pos) return; gtk_signal_disconnect_by_func(GTK_OBJECT(adjustment), (GtkSignalFunc) _mpv_value_changed_callback, NULL); adjustment->step_increment = (gfloat)1; adjustment->upper=(gfloat)max - 1; adjustment->page_size=(gfloat)size; adjustment->page_increment=(gfloat)size; adjustment->value=(gfloat)pos - 1; gtk_range_set_adjustment(GTK_RANGE(scrollbar),adjustment); gtk_adjustment_changed(adjustment); gtk_adjustment_value_changed(adjustment); gtk_signal_connect( GTK_OBJECT(gtk_range_get_adjustment(GTK_RANGE(scrollbar))), "value_changed", (GtkSignalFunc) _mpv_value_changed_callback, NULL); } static void _about(void) { GtkWidget * dlg; GtkWidget * icon; GtkWidget * label; GtkWidget * button; GdkPixmap * pixmap; GdkPixmap * mask; dlg=gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dlg),"mp " VERSION); gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox),5); pixmap=gdk_pixmap_create_from_xpm_d(window->window, &mask, NULL, mp_xpm); icon=gtk_pixmap_new(pixmap, mask); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),icon,TRUE,TRUE,0); gtk_widget_show(icon); label=gtk_label_new(_(MP_LICENSE)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),label,TRUE,TRUE,0); gtk_widget_show(label); button=gtk_button_new_with_label("OK"); gtk_signal_connect_object(GTK_OBJECT(button),"clicked", GTK_SIGNAL_FUNC(_mpv_confirm_yes_callback),GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),button,TRUE,TRUE,0); gtk_widget_show(button); gtk_signal_connect(GTK_OBJECT(dlg),"key_press_event", (GtkSignalFunc) _mpv_confirm_key_callback, NULL); gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(dlg),TRUE); gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(window)); gtk_widget_show(dlg); _gtk_really_modal(); } #if GTK_MAJOR_VERSION >= 2 #define _t_poke(c) _pango_line[p++]=c static char _pango_line[1024]; static void _mpv_pango_paint(void) { PangoLayout * pl; GdkRectangle gr; PangoAttrList * pal; PangoAttribute * pa; int * fb; int y, n, m, i, p, c, u, color; gr.x=0; gr.y=0; gr.width=area->allocation.width; gr.height=_mpv_font_height; for(n=y=0;n < _mpv_y_size;n++, y+= _mpv_font_height) { i=n * _mpv_x_size; fb=&_mpv_fb[i]; /* avoid drawing a line that didn't change */ if(memcmp((char *)fb, (char *)&_mpv_fbo[i], _mpv_x_size * sizeof(int)) == 0) continue; pl=gtk_widget_create_pango_layout(area, NULL); pango_layout_set_font_description(pl, _pango_font_desc); pal=pango_attr_list_new(); for(m=p=0;m < _mpv_x_size;) { /* get first color */ color=*fb & 0xff00; /* writes into _mpv_buffer while color is the same */ for(i=u=0;m < _mpv_x_size && color == (*fb & 0xff00); i++,m++,fb++) { c=*fb & 0xff; _mpv_buffer[i]=c; /* count non-ASCII chars */ if(c >= 128) u++; } _mpv_buffer[i]='\0'; color >>= 8; /* if word includes non-ASCII chars, convert to utf-8 */ if(u) { char * u8=g_locale_to_utf8(_mpv_buffer, i, NULL, NULL, NULL); /* if successful, copy onto _mpv_buffer */ if(u8 != NULL) { strncpy(_mpv_buffer, u8, sizeof(_mpv_buffer)); free(u8); } else { /* word doesn't match locale or something weirder; just substitute non-ASCIIs with '?' */ for(i=0;_mpv_buffer[i] != '\0';i++) { c=_mpv_buffer[i]; if(c < 0 || c > 127) _mpv_buffer[i]='?'; } } } /* store start of attribute */ u=p; /* move into main text */ for(i=0;_mpv_buffer[i] != '\0';i++) _t_poke(_mpv_buffer[i]); /* creates Pango attributes */ /* add the background attribute *only* if it's different from the NORMAL color, as background attributes seem to be painfully slow */ if(_papers[color].red != _papers[MP_COLOR_NORMAL].red || _papers[color].green != _papers[MP_COLOR_NORMAL].green || _papers[color].blue != _papers[MP_COLOR_NORMAL].blue) { pa=pango_attr_background_new(_papers[color].red, _papers[color].green, _papers[color].blue); pa->start_index=u; pa->end_index=p; pango_attr_list_insert(pal, pa); } /* underline? */ if(mpc_color_desc[color].underline) { pa=pango_attr_underline_new(TRUE); pa->start_index=u; pa->end_index=p; pango_attr_list_insert(pal, pa); } /* foreground color */ pa=pango_attr_foreground_new(_inks[color].red, _inks[color].green, _inks[color].blue); pa->start_index=u; pa->end_index=p; pango_attr_list_insert(pal, pa); } _t_poke('\0'); pango_layout_set_attributes(pl, pal); pango_attr_list_unref(pal); pango_layout_set_text(pl, _pango_line, p); gdk_gc_set_foreground(gc, &_papers[MP_COLOR_NORMAL]); if(!_use_double_buffer) { /* draw background */ gdk_draw_rectangle(area->window, gc, TRUE, 0, y, gr.width, gr.height); /* draw text */ gr.y=y; gtk_paint_layout(area->style, area->window, GTK_STATE_NORMAL, TRUE, &gr, area, "", 2, y, pl); } else { /* draw background */ gdk_draw_rectangle(pixmap, gc, TRUE, 0, 0, gr.width, gr.height); /* draw text */ gtk_paint_layout(area->style, pixmap, GTK_STATE_NORMAL, TRUE, &gr, area, "", 2, 0, pl); /* finally draw */ gdk_draw_pixmap(area->window, gc, pixmap, 0, 0, 0, y, gr.width, gr.height); } g_object_unref(pl); } /* copy this framebuffer into old */ memcpy(_mpv_fbo, _mpv_fb, _mpv_fb_size); } #endif /* GTK_MAJOR_VERSION >= 2 */ static void _mpv_gdk_paint(void) { int n,m,i; int * fb; int c,color,x; GdkFont * font; int yp,sw,sp; for(n=0;n < _mpv_y_size;n++) { i=n * _mpv_x_size; fb=&_mpv_fb[i]; /* avoid drawing a line that didn't change */ if(memcmp((char *)fb, (char *)&_mpv_fbo[i], _mpv_x_size * sizeof(int)) == 0) continue; yp=n * _mpv_font_height; for(x=m=0;m < _mpv_x_size;) { /* get first color */ color=*fb & 0xff00; /* writes into _mpv_buffer while color is the same */ for(i=0,sp=1;m<_mpv_x_size && color == (*fb & 0xff00); i++,m++,fb++) { c=*fb & 0xff; _mpv_buffer[i]=c; if(c!=' ') sp=0; } _mpv_buffer[i]='\0'; color>>=8; if(mpc_color_desc[color].italic && _font_italic != NULL) font=_font_italic; else font=_font_normal; sw=gdk_string_width(font,_mpv_buffer); gdk_gc_set_foreground(gc, &_papers[color]); if(! _use_double_buffer) { gdk_draw_rectangle(area->window, gc, TRUE, x, yp, sw, _mpv_font_height); if(!sp) { gdk_gc_set_foreground(gc, &_inks[color]); gdk_draw_string(area->window, font, gc, x, yp + _mpv_font_height - (_mpv_font_height / 3), _mpv_buffer); if(mpc_color_desc[color].underline) gdk_draw_line(area->window, gc, x, yp + _mpv_font_height - 4, x + sw, yp + _mpv_font_height - 4); } } else { if(sp) { gdk_draw_rectangle(area->window, gc, TRUE, x, yp, sw, _mpv_font_height); } else { gdk_draw_rectangle(pixmap, gc, TRUE, 0, 0, sw, _mpv_font_height); gdk_gc_set_foreground(gc, &_inks[color]); gdk_draw_string(pixmap, font, gc, 0, _mpv_font_height - (_mpv_font_height / 3), _mpv_buffer); if(mpc_color_desc[color].underline) gdk_draw_line(pixmap, gc, 0, _mpv_font_height - 4, sw, _mpv_font_height - 4); /* finally transfer */ gdk_draw_pixmap(area->window, gc, pixmap, 0, 0, x, yp, sw, _mpv_font_height); } } x+=sw; } } /* copy this framebuffer into old */ memcpy(_mpv_fbo, _mpv_fb, _mpv_fb_size); } static void _mpv_paint(void) { #if GTK_MAJOR_VERSION >= 2 if(_mpv_use_pango) _mpv_pango_paint(); else #endif _mpv_gdk_paint(); } static gint _mpv_key_callback(GtkWidget * widget, GdkEventKey * event, gpointer data) { char * ptr=NULL; int c='\0'; #if GTK_MAJOR_VERSION >= 2 gtk_im_context_filter_keypress(im, event); #endif if(event->keyval < 10000) c=event->keyval; mpi_move_selecting=event->state & GDK_SHIFT_MASK; if (GDK_MOD1_MASK & event->state) return 0; /* Reserve ALT for Menu Mnemonics */ if(event->state & (GDK_CONTROL_MASK)) { switch(event->keyval) { case GDK_Up: ptr="ctrl-cursor-up"; break; case GDK_Down: ptr="ctrl-cursor-down"; break; case GDK_Left: ptr="ctrl-cursor-left"; break; case GDK_Right: ptr="ctrl-cursor-right"; break; case GDK_Prior: ptr="ctrl-page-up"; break; case GDK_Next: ptr="ctrl-page-down"; break; case GDK_Home: ptr="ctrl-home"; break; case GDK_End: ptr="ctrl-end"; break; case GDK_space: ptr="ctrl-space"; break; case GDK_KP_Add: ptr="ctrl-kp-plus"; break; case GDK_KP_Subtract: ptr="ctrl-kp-minus"; break; case GDK_KP_Multiply: ptr="ctrl-kp-multiply"; break; case GDK_KP_Divide: ptr="ctrl-kp-divide"; break; case GDK_F1: ptr="ctrl-f1"; break; case GDK_F2: ptr="ctrl-f2"; break; case GDK_F3: ptr="ctrl-f3"; break; case GDK_F4: ptr="ctrl-f4"; break; case GDK_F5: ptr="ctrl-f5"; break; case GDK_F6: ptr="ctrl-f6"; break; case GDK_F7: ptr="ctrl-f7"; break; case GDK_F8: ptr="ctrl-f8"; break; case GDK_F9: ptr="ctrl-f9"; break; case GDK_F10: ptr="ctrl-f10"; break; case GDK_F11: ptr="ctrl-f11"; break; case GDK_F12: ptr="ctrl-f12"; break; case GDK_KP_Enter: case GDK_Return: ptr="ctrl-enter"; break; case 'a': ptr="ctrl-a"; break; case 'b': ptr="ctrl-b"; break; case 'c': ptr="ctrl-c"; break; case 'd': ptr="ctrl-d"; break; case 'e': ptr="ctrl-e"; break; case 'f': ptr="ctrl-f"; break; case 'g': ptr="ctrl-g"; break; case 'h': ptr="ctrl-h"; break; case 'i': ptr="ctrl-i"; break; case 'j': ptr="ctrl-j"; break; case 'k': ptr="ctrl-k"; break; case 'l': ptr="ctrl-l"; break; case 'm': ptr="ctrl-m"; break; case 'n': ptr="ctrl-n"; break; case 'o': ptr="ctrl-o"; break; case 'p': ptr="ctrl-p"; break; case 'q': ptr="ctrl-q"; break; case 'r': ptr="ctrl-r"; break; case 's': ptr="ctrl-s"; break; case 't': ptr="ctrl-t"; break; case 'u': ptr="ctrl-u"; break; case 'v': ptr="ctrl-v"; break; case 'w': ptr="ctrl-w"; break; case 'x': ptr="ctrl-x"; break; case 'y': ptr="ctrl-y"; break; case 'z': ptr="ctrl-z"; break; } } else if(event->keyval > 256) { switch(event->keyval) { case GDK_Up: ptr="cursor-up"; break; case GDK_Down: ptr="cursor-down"; break; case GDK_Left: ptr="cursor-left"; break; case GDK_Right: ptr="cursor-right"; break; case GDK_Prior: ptr="page-up"; break; case GDK_Next: ptr="page-down"; break; case GDK_Home: ptr="home"; break; case GDK_End: ptr="end"; break; case GDK_KP_Add: ptr="kp-plus"; break; case GDK_KP_Subtract: ptr="kp-minus"; break; case GDK_KP_Multiply: ptr="kp-multiply"; break; case GDK_KP_Divide: ptr="kp-divide"; break; case GDK_F1: ptr="f1"; break; case GDK_F2: ptr="f2"; break; case GDK_F3: ptr="f3"; break; case GDK_F4: ptr="f4"; break; case GDK_F5: ptr="f5"; break; case GDK_F6: ptr="f6"; break; case GDK_F7: ptr="f7"; break; case GDK_F8: ptr="f8"; break; case GDK_F9: ptr="f9"; break; case GDK_F10: ptr="f10"; break; case GDK_F11: ptr="f11"; break; case GDK_F12: ptr="f12"; break; case GDK_Insert: ptr="insert"; break; case GDK_BackSpace: ptr="backspace"; break; case GDK_Delete: ptr="delete"; break; case GDK_KP_Enter: case GDK_Return: ptr="enter"; break; case GDK_Tab: ptr="tab"; break; case GDK_Escape: ptr="escape"; break; } } else { if(c < 32 || c > 255 || c==127) c='\0'; } if(_mpv_im_char != '\0') { c=_mpv_im_char; _mpv_im_char='\0'; } if(c!='\0' || ptr!=NULL) { /* tell next expose we've call it */ _mpv_expose_by_key=1; mpi_process(c, ptr, NULL); _mpv_expose_by_key=0; } if(_mpi_exit_requested) gtk_main_quit(); return(0); } static gint _mpv_mouse_callback(GtkWidget * widget, GdkEventButton * event, gpointer data) { int x,y; char * keyname=NULL; /* mouse instant positioning */ x=((int)event->x) / _mpv_font_width; y=((int)event->y) / _mpv_font_height; mp_move_xy(_mp_active,x,y+_mp_active->vy); mp_move_bol(_mp_active); mp_move_to_visual_column(_mp_active,x); switch(event->button) { case 1: keyname="mouse-left-button"; break; case 2: keyname="mouse-middle-button"; break; case 3: keyname="mouse-right-button"; break; case 4: keyname="mouse-wheel-up"; break; case 5: keyname="mouse-wheel-down"; break; } if(keyname != NULL) mpi_process('\0', keyname, NULL); mpi_draw_all(_mp_active); return(0); } static gint _mpv_configure_event_callback(GtkWidget * widget, GdkEventConfigure * event) { static GdkEventConfigure o; if(memcmp(&o,event,sizeof(o))==0) return(TRUE); memcpy(&o,event,sizeof(o)); _mpv_calc_font_width_and_height(); if(_mp_active) mpi_draw_all(_mp_active); return(TRUE); } static gint _mpv_expose_event_callback(GtkWidget * widget, GdkEventExpose * event) { /* printf("expose: %d, %d, %d, %d [%d]\n", event->area.x, event->area.y, event->area.width, event->area.height, _mpv_expose_by_key);*/ /* if the expose event has not been generated by refresh(), force a complete redraw */ if(!_mpv_expose_by_key) memset(_mpv_fbo, '\0', _mpv_fb_size); else _mpv_expose_by_key=0; _mpv_paint(); #if GTK_MAJOR_VERSION < 2 /* get back the processing of dead keys */ if(ic!=NULL) gdk_im_begin(ic, widget->window); #endif return(FALSE); } #if GTK_MAJOR_VERSION >= 2 static void _mpv_commit_callback(GtkIMContext * i, char * str, gpointer u) { str=__(str); _mpv_im_char=*str; } #endif static void _mpv_realize_callback(GtkWidget * widget) { #if GTK_MAJOR_VERSION < 2 /* I don't undestand this stupid load of crap */ /* borrowed (more or less) from the gtk_entry code */ /* all this shit is just to receive dead key composed characters correctly */ GdkICAttr * attr; GdkEventMask mask; GdkIMStyle s_style=GDK_IM_PREEDIT_NONE | GDK_IM_PREEDIT_NOTHING | GDK_IM_STATUS_NONE | GDK_IM_STATUS_NOTHING; if(gdk_im_ready() && (attr=gdk_ic_attr_new())!=NULL) { attr->style=gdk_im_decide_style(s_style); attr->client_window=widget->window; ic=gdk_ic_new(attr, (GdkICAttributesType)GDK_IC_ALL_REQ); mask=gdk_window_get_events(widget->window); mask |= gdk_ic_get_events(ic); gdk_window_set_events(widget->window, mask); gdk_im_begin(ic, widget->window); } #else /* GTK > 2 */ im=gtk_im_multicontext_new(); g_signal_connect(im, "commit", G_CALLBACK(_mpv_commit_callback), NULL); gtk_im_context_set_client_window(im, widget->window); #endif } static void _mpv_filetabs_callback(GtkNotebook * notebook, GtkNotebookPage * page, gint pg_num, gpointer data) { int n; mp_txt * txt; for(n=0,txt=_mp_txts;txt!=NULL && n < 100;n++,txt=txt->next) { if(n==pg_num) { if(_mp_active != txt) _mp_active=txt; } } gtk_widget_grab_focus(area); mpi_draw_all(_mp_active); } static void _filetabs(int rebuild) { int n; mp_txt * t; GtkWidget * l; char * ptr; gtk_signal_disconnect_by_func(GTK_OBJECT(file_tabs), (GtkSignalFunc) _mpv_filetabs_callback, NULL); if(rebuild) { /* delete possible previous tabs */ for(n=0;n < 100;n++) gtk_notebook_remove_page(GTK_NOTEBOOK(file_tabs),0); } for(t=_mp_txts,n=0;t!=NULL && n < 100;t=t->next,n++) { if(rebuild) { GtkWidget * f; if((ptr=strrchr(t->name,'/'))==NULL) ptr=t->name; else ptr++; l=gtk_label_new(_(ptr)); gtk_widget_show(l); f=gtk_frame_new(NULL); gtk_widget_show(f); gtk_notebook_append_page(GTK_NOTEBOOK(file_tabs), f,l); } if(_mp_active == t) gtk_notebook_set_page(GTK_NOTEBOOK(file_tabs), n); } gtk_signal_connect(GTK_OBJECT(file_tabs),"switch_page", (GtkSignalFunc) _mpv_filetabs_callback, NULL); gtk_widget_grab_focus(area); } static gint _mpv_selection_clear_callback(GtkWidget * widget, GdkEventSelection * event, gpointer data) { _mpv_selection=0; return(TRUE); } static void _mpv_selection_get_callback(GtkWidget * widget, GtkSelectionData * sel, guint info, guint tm, gpointer data) { char * ptr; int n,c; if(!_mpv_selection) return; if(_mp_clipboard == NULL) return; /* counts first the number of bytes in the clipboard */ mp_move_bof(_mp_clipboard); for(n=0;(c=mp_get_char(_mp_clipboard))!='\0';n++); /* get buffer */ if((ptr=(char *)malloc(n))==NULL) return; /* transfer */ mp_move_bof(_mp_clipboard); for(n=0;(c=mp_get_char(_mp_clipboard))!='\0';n++) ptr[n]=c; /* pastes into primary selection */ gtk_selection_data_set(sel, GDK_SELECTION_TYPE_STRING, 8, (unsigned char *) ptr, n); free(ptr); } static void _mpv_selection_received_callback(GtkWidget * widget, GtkSelectionData * sel, guint tm, gpointer data) { int n; mp_lock_clipboard(1); for(n=0;n < sel->length;n++) { mp_put_char(_mp_clipboard,sel->data[n],1); mp_put_char(_mp_active,sel->data[n],1); } mp_lock_clipboard(0); mpi_draw_all(_mp_active); } #if GTK_MAJOR_VERSION >= 2 static gint _mpv_scroll_callback(GtkWidget * widget, GdkEventScroll * event) { char * keyname=NULL; switch(event->direction) { case GDK_SCROLL_UP: keyname="mouse-wheel-up"; break; case GDK_SCROLL_DOWN: keyname="mouse-wheel-down"; break; case GDK_SCROLL_LEFT: keyname="mouse-wheel-left"; break; case GDK_SCROLL_RIGHT: keyname="mouse-wheel-right"; break; default: keyname=NULL; } if(keyname != NULL) mpi_process('\0', keyname, NULL); mpi_draw_all(_mp_active); return(0); } #endif static gint _mpv_delete_event(GtkWidget * w, GdkEvent * e, gpointer data) { mpi_shutdown(); return(FALSE); } static void _mpv_destroy(GtkWidget * w, gpointer data) { gtk_main_quit(); } /** * _mpv_create_colors - Creates the colors defined in the color database * * Creates the colors defined in the color database, probably * set from the configuration file. */ static void _mpv_create_colors(void) { int n; int ink,paper; for(n=0;n < MP_COLOR_PRIVATE;n++) { if(mpi_monochrome) { ink=0x00000000; paper=0x00ffffff; if(n == MP_COLOR_SELECTED || n == MP_COLOR_CURSOR) mpc_color_desc[n].reverse=1; } else { ink=mpc_color_desc[n].ink_rgb; paper=mpc_color_desc[n].paper_rgb; if(ink==0xffffffff) ink=mpc_color_desc[0].ink_rgb; if(paper==0xffffffff) paper=mpc_color_desc[0].paper_rgb; } if(mpc_color_desc[n].reverse) { int i=paper; paper=ink; ink=i; } _inks[n].pixel=0; _inks[n].blue=(ink & 0x000000ff) << 8; _inks[n].green=(ink & 0x0000ff00); _inks[n].red=(ink & 0x00ff0000) >> 8; gdk_color_alloc(gdk_colormap_get_system(), &_inks[n]); _papers[n].pixel=0; _papers[n].blue=(paper & 0x00000000ff) << 8; _papers[n].green=(paper & 0x0000ff00); _papers[n].red=(paper & 0x00ff00ff) >> 8; gdk_color_alloc(gdk_colormap_get_system(), &_papers[n]); } } static void _main_loop(void) { gtk_main(); } static int _startup_1(void) { int argc=1; return(gtk_init_check(&argc, &_mpv_argv)); } static void _startup_2(void) { GtkWidget * vbox; GtkWidget * hbox; GdkPixmap * pixmap; GdkPixmap * mask; mp_log("Using GTK+ driver (%d.%d.%d)\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(_mpv_delete_event), NULL); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(_mpv_destroy), NULL); /* file tabs */ file_tabs=gtk_notebook_new(); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(file_tabs), GTK_POS_TOP); GTK_WIDGET_UNSET_FLAGS(file_tabs,GTK_CAN_FOCUS); gtk_notebook_set_scrollable(GTK_NOTEBOOK(file_tabs),1); vbox=gtk_vbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(window), vbox); gtk_box_pack_start(GTK_BOX(vbox),menu_bar,FALSE,FALSE,0); gtk_box_pack_start(GTK_BOX(vbox),file_tabs,FALSE,FALSE,0); /* horizontal box holding the text and the scrollbar */ hbox=gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox),hbox,TRUE,TRUE,0); /* the Minimum Profit area */ area=gtk_drawing_area_new(); gtk_box_pack_start(GTK_BOX(hbox),area,TRUE,TRUE,0); gtk_widget_set_usize(GTK_WIDGET(area), 600, 400); gtk_widget_set_events(GTK_WIDGET(area),GDK_BUTTON_PRESS_MASK); #if GTK_MAJOR_VERSION >= 2 gtk_widget_set_double_buffered(area, FALSE); #endif gtk_signal_connect(GTK_OBJECT(area),"configure_event", (GtkSignalFunc) _mpv_configure_event_callback, NULL); gtk_signal_connect(GTK_OBJECT(area),"expose_event", (GtkSignalFunc) _mpv_expose_event_callback, NULL); gtk_signal_connect(GTK_OBJECT(area), "realize", (GtkSignalFunc) _mpv_realize_callback, NULL); gtk_signal_connect(GTK_OBJECT(window),"key_press_event", (GtkSignalFunc) _mpv_key_callback, NULL); gtk_signal_connect(GTK_OBJECT(area),"button_press_event", (GtkSignalFunc) _mpv_mouse_callback, NULL); gtk_signal_connect(GTK_OBJECT(file_tabs),"switch_page", (GtkSignalFunc) _mpv_filetabs_callback, NULL); gtk_signal_connect(GTK_OBJECT(area), "selection_clear_event", GTK_SIGNAL_FUNC(_mpv_selection_clear_callback), NULL); gtk_signal_connect(GTK_OBJECT(area), "selection_get", GTK_SIGNAL_FUNC(_mpv_selection_get_callback), NULL); gtk_signal_connect(GTK_OBJECT(area), "selection_received", GTK_SIGNAL_FUNC(_mpv_selection_received_callback), NULL); #if GTK_MAJOR_VERSION >= 2 gtk_signal_connect(GTK_OBJECT(area), "scroll_event", GTK_SIGNAL_FUNC(_mpv_scroll_callback), NULL); #endif gtk_selection_add_target(area, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 1); /* the scrollbar */ scrollbar=gtk_vscrollbar_new(NULL); gtk_box_pack_start(GTK_BOX(hbox),scrollbar,FALSE,FALSE,0); gtk_signal_connect( GTK_OBJECT(gtk_range_get_adjustment(GTK_RANGE(scrollbar))), "value_changed", (GtkSignalFunc) _mpv_value_changed_callback, NULL); /* the status bar */ status=gtk_label_new("mp " VERSION); gtk_box_pack_start(GTK_BOX(vbox), status, FALSE, FALSE, 0); gtk_misc_set_alignment(GTK_MISC(status), 0, 0.5); gtk_label_set_justify(GTK_LABEL(status), GTK_JUSTIFY_LEFT); gtk_widget_show_all(window); gc=gdk_gc_new(area->window); _mpv_font_size--; mpv_zoom(1); #if GTK_MAJOR_VERSION >= 2 if (mpv_gtk_maximize) gtk_window_maximize(GTK_WINDOW(window)); #else /* unsupported in GTK 1.x */ mpv_gtk_maximize=0; #endif /* set size */ if(!mpv_gtk_maximize) { if(_mpv_gtk_xpos >= 0 && _mpv_gtk_ypos >= 0) gdk_window_move(GTK_WIDGET(window)->window, _mpv_gtk_xpos, _mpv_gtk_ypos); if(_mpv_gtk_width > 0 && _mpv_gtk_height > 0) { /* fix ridiculously small values */ if(_mpv_gtk_width < 150) _mpv_gtk_width=150; if(_mpv_gtk_height < 150) _mpv_gtk_height=150; gtk_window_set_default_size(GTK_WINDOW(window), _mpv_gtk_width, _mpv_gtk_height); gdk_window_resize(GTK_WIDGET(window)->window, _mpv_gtk_width, _mpv_gtk_height); } } /* colors */ _mpv_create_colors(); fclose(stderr); mp_log("X11 geometry set to %dx%d+%d+%d\n", _mpv_gtk_width, _mpv_gtk_height, _mpv_gtk_xpos, _mpv_gtk_ypos); /* set application icon */ pixmap=gdk_pixmap_create_from_xpm_d(window->window, &mask, NULL, mp_xpm); gdk_window_set_icon(window->window, NULL, pixmap, mask); } static void _shutdown(void) { /* dummy */ } static void _suspend(void) { #if GTK_MAJOR_VERSION >= 2 if (window) gtk_window_iconify(GTK_WINDOW(window)); #endif } static int _syscmd(mp_txt *txt,char *cmd,char *mode) { if (txt && mode) { return _unix_popen(txt,cmd,mode); } else { int ret; mp_log("Executing %s\n",cmd); ret = system(cmd); mp_log("Execution returned %d\n",ret); return ret; } } static void _usage(void) { printf("Minimum Profit " VERSION " - Programmer Text Editor\n"); printf("Copyright (C) 1991-2005 Angel Ortega \n"); printf("%s\n", __DATE__ " " __TIME__); printf("This software is covered by the GPL license. NO WARRANTY.\n\n"); printf("%s\n", L("\ Usage: mp [options] [file [file ...]]\n\ \n\ Options:\n\ \n\ -t|--tag [tag] Edits the file where tag is defined\n\ -w|--word-wrap [col] Sets wordwrapping in column col\n\ -ts|--tab-size [size] Sets tab size\n\ -ai|--autoindent Sets automatic indentation mode\n\ -l|--lang [lang] Language selection\n\ -m|--mode [mode] Syntax-hilight mode\n\ --col80 Marks column # 80\n\ -bw|--monochrome Monochrome\n\ -tx|--text Use text mode (instead of GUI)\n\ -sp|--spellcheck Active spellchecking\n\ -h|--help This help screen\n\ \n\ -hw|--hardware-cursor Activates the use of hardware cursor\n\ --mouse Activate mouse usage for cursor positioning\n\ -nt|--no-transparent Disable transparent mode (eterm, aterm, etc.)\n\ ")); printf("--mode: %s\n",mps_enumerate_modes()); printf("\nConfig file: %s\n",_mpc_config_file); } static void _set_var(char * var, char * value) { if(strcmp(var,"gtk_font_face") == 0) strncpy(_mpv_font_face, value, sizeof(_mpv_font_face)); else if(strcmp(var,"gtk_font_size") == 0) { char * prev_locale = setlocale(LC_NUMERIC, "C"); _mpv_font_size = atof(value); setlocale(LC_NUMERIC, prev_locale); } else if(strcmp(var,"gtk_font_weight") == 0) strncpy(_mpv_font_weight, value, sizeof(_mpv_font_weight)); else if(strcmp(var,"gtk_font_encoding") == 0) strncpy(_mpv_font_encoding, value, sizeof(_mpv_font_encoding)); else if(strcmp(var,"gtk_use_italics") == 0) _use_italics=atoi(value); else if(strcmp(var,"gtk_use_double_buffer") == 0) _use_double_buffer=atoi(value); else if(strcmp(var,"gtk_width") == 0) _mpv_gtk_width=atoi(value); else if(strcmp(var,"gtk_height") == 0) _mpv_gtk_height=atoi(value); else if(strcmp(var,"gtk_xpos") == 0) _mpv_gtk_xpos=atoi(value); else if(strcmp(var,"gtk_ypos") == 0) _mpv_gtk_ypos=atoi(value); else if(strcmp(var, "use_pango") == 0 || strcmp(var, "gtk_use_pango") == 0) _mpv_use_pango=atoi(value); else if(strcmp(var, "gtk_maximize") == 0) mpv_gtk_maximize=atoi(value); } static int _args(int argc, char * argv[]) { int n; for(n=1;n < argc;n++) { if(argv[n] == NULL) continue; if(strcmp(argv[n],"-geometry")==0 || strcmp(argv[n],"--geometry")==0) { int x,y,tx,ty; if(n >= argc - 1) break; argv[n]=NULL; n++; x=y=tx=ty=-1; if(sscanf(argv[n],"%dx%d+%d+%d",&tx,&ty,&x,&y) == 4) { _mpv_gtk_width=tx; _mpv_gtk_height=ty; _mpv_gtk_xpos=x; _mpv_gtk_ypos=y; } else if(sscanf(argv[n],"%dx%d",&tx,&ty) == 2) { _mpv_gtk_width=tx; _mpv_gtk_height=ty; } else if(sscanf(argv[n],"+%d+%d",&x,&y)==2) { _mpv_gtk_xpos=x; _mpv_gtk_ypos=y; } } else continue; argv[n]=NULL; } return(0); } struct _mpv_driver _mpv_driver_gtk= { "gtk", 0, _unix_strcasecmp, _unix_fopen, _unix_glob, _goto, _char, _str, _cursor, _refresh, _title, _status_line, _add_menu, _add_menu_item, _check_menu, _menu, _alert, _confirm, _list, _readline, _sys_to_clip, _clip_to_sys, _about, _unix_help, _zoom, _scrollbar, _filetabs, _set_var, _args, _usage, _main_loop, _startup_1, _startup_2, _shutdown, _suspend, _syscmd }; #else /* CONFOPT_GTK */ struct _mpv_driver _mpv_driver_gtk= { "gtk", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #endif /* CONFOPT_GTK */