To: vim-dev@vim.org Subject: Patch 5.6a.018 Fcc: outbox From: Bram Moolenaar ------------ Note: I received a number of fixes for the GTK version from Marcin Dalecki. I found these important enough to include. But since this is more than a small change, I'll give this another week before releasing 5.6. A few functions were moved, which made patch quite big, even though not that much really changed. Patch 5.6a.018 Problem: GTK GUI: submenu priority doesn't work. Help dialog could be destroyed too soon. When closing a dialog window (e.g. the "ATTENTION" one), Vim would just hang. When GTK theme is changed, Vim doesn't adjust to the new colors. Argument for ":promptfind" isn't used. Solution: Fixed the mentioned problems. Made the dialogs look&feel nicer. Moved functions to avoid the need for a forward declaration. Fixed reentrancy of the file browser dialog. Added drag&drop support for GNOME. Init the text for the Find/replace dialog from the last used search string. Set "match whole word" toggle button correctly. Made repeat rate for drag outside of window depend on the distance from the window. (Marcin Dalecki) Made the drag in Visual mode actually work. Removed recursiveness protection from gui_mch_get_rgb(), it might cause more trouble than it solves. Files: src/ex_docmd.c, src/gui_gtk.c, src/gui_gtk_x11.c, src/ui.c, src/proto/ui.pro, src/misc2.c *** ../vim-5.6a.17/src/ex_docmd.c Wed Dec 29 12:11:01 1999 --- src/ex_docmd.c Sat Jan 8 13:45:47 2000 *************** *** 5941,5947 **** } } ! #if defined(USE_GUI_MSWIN) || defined(USE_GUI_BEOS) || defined(macintosh) || defined(PROTO) /* * Handle a file drop. The code is here because a drop is *nearly* like an * :args command, but not quite (we have a list of exact filenames, so we --- 5941,5948 ---- } } ! #if defined(USE_GUI_MSWIN) || defined(USE_GUI_BEOS) || defined(macintosh) \ ! || defined(USE_GUI_GTK) || defined(PROTO) /* * Handle a file drop. The code is here because a drop is *nearly* like an * :args command, but not quite (we have a list of exact filenames, so we *************** *** 5949,5958 **** * code is very similar to :args and hence needs access to a lot of the static * functions in this file. * - * Arguments: - * FILEC => the number of files dropped - * FILEV => the list of files dropped - * * The list should be allocated using vim_alloc(), as should each item in the * list. This function takes over responsibility for freeing the list. * --- 5950,5955 ---- *************** *** 5966,5973 **** void handle_drop(filec, filev, split) ! int filec; ! char_u **filev; int split; /* force splitting the window */ { EXARG ea; --- 5963,5970 ---- void handle_drop(filec, filev, split) ! int filec; /* the number of files dropped */ ! char_u **filev; /* the list of files dropped */ int split; /* force splitting the window */ { EXARG ea; *** ../vim-5.6a.17/src/gui_gtk.c Mon Dec 20 09:59:10 1999 --- src/gui_gtk.c Sat Jan 8 21:11:02 2000 *************** *** 19,24 **** --- 19,29 ---- * :-) (My native language is polish and I speak * native grade german too. I'm living in Göttingen.de.) * --mdcki" + * + * + * Although some #ifdefs suggest that GTK 1.0 is supported, it isn't. The + * code requires GTK version 1.1.16 or later. Stuff for older versions will + * be removed some time. */ #include "gui_gtk_f.h" *************** *** 92,115 **** #define FR_REPLACE 4 #define FR_REPLACEALL 5 - - #if defined(USE_BROWSE) || defined(PROTO) - static void browse_ok_cb(GtkWidget * widget, gpointer cbdata); - static void browse_cancel_cb(GtkWidget * widget, gpointer cbdata); - static gboolean browse_destroy_cb(GtkWidget * widget); - #endif - - #ifdef GUI_DIALOG - static void butproc(GtkWidget * widget, gpointer data); - #endif - static void entry_activate_cb(GtkWidget *widget, GtkWidget *with); static void entry_changed_cb(GtkWidget *entry, GtkWidget *dialog); static void find_direction_cb(GtkWidget *widget, gpointer data); ! static void find_replace_cb(GtkWidget *widget, gint flags); static void exact_match_cb(GtkWidget *widget, gpointer data); static void repl_dir_cb(GtkWidget * widget, gpointer data); - static void find_replace_dialog_create(int do_replace); #ifdef USE_TOOLBAR static void get_pixmap(char *menuname, GdkPixmap **pixmap, GdkBitmap **mask); --- 97,108 ---- #define FR_REPLACE 4 #define FR_REPLACEALL 5 static void entry_activate_cb(GtkWidget *widget, GtkWidget *with); static void entry_changed_cb(GtkWidget *entry, GtkWidget *dialog); static void find_direction_cb(GtkWidget *widget, gpointer data); ! static void find_replace_cb(GtkWidget *widget, unsigned int flags); static void exact_match_cb(GtkWidget *widget, gpointer data); static void repl_dir_cb(GtkWidget * widget, gpointer data); #ifdef USE_TOOLBAR static void get_pixmap(char *menuname, GdkPixmap **pixmap, GdkBitmap **mask); *************** *** 120,127 **** #endif #if defined(WANT_MENU) || defined(PROTO) - static void gui_mch_recurse_tearoffs(VimMenu *menu, int val); - static void menu_item_cb(GtkWidget *widget, gpointer data); /* * Only use accelerators when gtk_menu_ensure_uline_accel_group() is --- 113,118 ---- *************** *** 133,138 **** --- 124,130 ---- # define GTK_USE_ACCEL # endif #endif + /* * Create a highly customized menu item by hand instead of by using: * *************** *** 192,198 **** * additional underscores. */ name = g_new(char, strlen((char *)menu->name) + num + 1); ! for (num = 0, tmp = (char *)menu->name; *tmp; tmp++) { /* actext has been added above, stop at the TAB */ if (*tmp == TAB) break; --- 184,190 ---- * additional underscores. */ name = g_new(char, strlen((char *)menu->name) + num + 1); ! for (num = 0, tmp = (char *)menu->name; *tmp; ++tmp) { /* actext has been added above, stop at the TAB */ if (*tmp == TAB) break; *************** *** 285,294 **** if (parent == NULL) gtk_menu_bar_insert(GTK_MENU_BAR(gui.menubar), menu->id, idx); else { - #ifdef GTK_HAVE_FEATURES_1_1_0 /* since the tearoff should always appear first, increment idx */ ++idx; - #endif gtk_menu_insert(GTK_MENU(parent->submenu_id), menu->id, idx); } --- 277,284 ---- *************** *** 314,319 **** --- 304,319 ---- #endif } + /*ARGSUSED*/ + static void + menu_item_activate(GtkWidget * widget, gpointer data) + { + gui_menu_cb((VimMenu *) data); + + /* make sure the menu action is taken immediately */ + if (gtk_main_level() > 0) + gtk_main_quit(); + } /*ARGSUSED*/ void *************** *** 337,343 **** (char *)(menu->strings[MENU_INDEX_TIP]), (char *)(menu->dname), gtk_pixmap_new(pixmap, mask), ! GTK_SIGNAL_FUNC(menu_item_cb), (gpointer)menu, idx); } --- 337,343 ---- (char *)(menu->strings[MENU_INDEX_TIP]), (char *)(menu->dname), gtk_pixmap_new(pixmap, mask), ! GTK_SIGNAL_FUNC(menu_item_activate), (gpointer)menu, idx); } *************** *** 351,372 **** if (parent->submenu_id == 0) return; if (is_menu_separator(menu->name)) { ! /* just add it */ menu->id = gtk_menu_item_new(); gtk_widget_show(menu->id); ! gtk_menu_append(GTK_MENU(parent->submenu_id), menu->id); ! return; /* that's all */ } menu_item_new(menu, parent->submenu_id, FALSE); gtk_widget_show(menu->id); ! gtk_menu_append(GTK_MENU(parent->submenu_id), menu->id); if (menu->id != 0) gtk_signal_connect(GTK_OBJECT(menu->id), "activate", ! GTK_SIGNAL_FUNC(menu_item_cb), (gpointer) menu); } #endif --- 351,375 ---- if (parent->submenu_id == 0) return; + /* make place for the possible tearoff handle item */ + ++idx; if (is_menu_separator(menu->name)) { ! /* Separator: Just add it */ menu->id = gtk_menu_item_new(); gtk_widget_show(menu->id); ! gtk_menu_insert(GTK_MENU(parent->submenu_id), menu->id, idx); ! return; } + /* Add textual menu item. */ menu_item_new(menu, parent->submenu_id, FALSE); gtk_widget_show(menu->id); ! gtk_menu_insert(GTK_MENU(parent->submenu_id), menu->id, idx); if (menu->id != 0) gtk_signal_connect(GTK_OBJECT(menu->id), "activate", ! GTK_SIGNAL_FUNC(menu_item_activate), (gpointer) menu); } #endif *************** *** 426,432 **** *pixmap = NULL; *mask = NULL; ! if (strncmp(menuname, "BuiltIn", 7) == 0) { if (isdigit((int)menuname[7]) && isdigit((int)menuname[8])) { builtin_num = atoi(menuname + 7); pixmap_create_by_num(builtin_num, pixmap, mask); --- 429,435 ---- *pixmap = NULL; *mask = NULL; ! if (strncmp(menuname, "BuiltIn", (size_t)7) == 0) { if (isdigit((int)menuname[7]) && isdigit((int)menuname[8])) { builtin_num = atoi(menuname + 7); pixmap_create_by_num(builtin_num, pixmap, mask); *************** *** 549,565 **** gtk_form_move_resize(GTK_FORM(gui.formwin), gui.drawarea, x, y, w, h); } - #if 0 - /* - * Nothing to be done here, since we have started to manage our windows with - * abstract management widgets, which is much better in fact. - */ - /*ARGSUSED*/ - void - gui_mch_set_menu_pos(int x, int y, int w, int h) - { - } - #endif #if defined(WANT_MENU) || defined(PROTO) /* --- 552,557 ---- *************** *** 571,577 **** { #if 0 VimMenu *menu; ! /* FIXME: imeplemnt this later */ for (menu = root_menu; menu != NULL; menu = menu->next) if (menu->id != 0) XtVaSetValues(menu->id, --- 563,569 ---- { #if 0 VimMenu *menu; ! /* FIXME: implement this later */ for (menu = root_menu; menu != NULL; menu = menu->next) if (menu->id != 0) XtVaSetValues(menu->id, *************** *** 580,600 **** #endif } void gui_mch_toggle_tearoffs(int enable) { ! gui_mch_recurse_tearoffs(root_menu, enable); } #endif #ifdef USE_TOOLBAR /* ! * seems like there's a hole in the GTK Toolbar API: there's no provision for ! * removing an item from the toolbar! */ static void ! gui_gtk_toolbar_remove_item_by_text(GtkToolbar *tb, const char *text) { GtkContainer *container; GList *childl; --- 572,615 ---- #endif } + + static void + recurse_tearoffs(VimMenu * menu, int val) + { + #ifdef GTK_HAVE_FEATURES_1_1_0 + while (menu != NULL) { + if (!popup_menu(menu->name)) { + if (menu->submenu_id != 0) { + if (val) + gtk_widget_show(menu->tearoff_handle); + else + gtk_widget_hide(menu->tearoff_handle); + } + recurse_tearoffs(menu->children, val); + } + menu = menu->next; + } + #endif + } + + void gui_mch_toggle_tearoffs(int enable) { ! recurse_tearoffs(root_menu, enable); } #endif #ifdef USE_TOOLBAR + /* ! * Seems like there's a hole in the GTK Toolbar API: there's no provision for ! * removing an item from the toolbar. Therefore I need to resort to going ! * really deeply into the internal widget structures. */ static void ! toolbar_remove_item_by_text(GtkToolbar *tb, const char *text) { GtkContainer *container; GList *childl; *************** *** 637,648 **** { #ifdef USE_TOOLBAR if (menu->parent && toolbar_menu(menu->parent->name)) { ! #if 0 ! /* FIXME: this isn't in GTK yet, but will be. for now, use the alternative */ ! gtk_toolbar_remove_item(GTK_TOOLBAR(gui.toolbar), ! GTK_TOOLBAR_DATA_TEXT, menu->dname); ! #endif ! gui_gtk_toolbar_remove_item_by_text(GTK_TOOLBAR(gui.toolbar), (const char *)menu->dname); return; } --- 652,658 ---- { #ifdef USE_TOOLBAR if (menu->parent && toolbar_menu(menu->parent->name)) { ! toolbar_remove_item_by_text(GTK_TOOLBAR(gui.toolbar), (const char *)menu->dname); return; } *************** *** 716,724 **** value = adjustment->value; /* ! * We just ignore the dragging argument, since otherwise ! * the scrollbar size will not be adjusted properly in ! * synthetic scrolls. */ gui_drag_scrollbar(sb, value, FALSE); if (gtk_main_level() > 0) --- 726,733 ---- value = adjustment->value; /* ! * We just ignore the dragging argument, since otherwise the scrollbar ! * size will not be adjusted properly in synthetic scrolls. */ gui_drag_scrollbar(sb, value, FALSE); if (gtk_main_level() > 0) *************** *** 768,773 **** --- 777,831 ---- * Implementation of the file selector related stuff */ + /*ARGSUSED*/ + static void + browse_ok_cb(GtkWidget *widget, gpointer cbdata) + { + Gui *vw = (Gui *)cbdata; + + if (vw->browse_fname != NULL) + g_free(vw->browse_fname); + + vw->browse_fname = (char_u *)g_strdup(gtk_file_selection_get_filename( + GTK_FILE_SELECTION(vw->filedlg))); + gtk_widget_hide(vw->filedlg); + if (gtk_main_level() > 0) + gtk_main_quit(); + } + + /*ARGSUSED*/ + static void + browse_cancel_cb(GtkWidget *widget, gpointer cbdata) + { + Gui *vw = (Gui *)cbdata; + + if (vw->browse_fname != NULL) + { + g_free(vw->browse_fname); + vw->browse_fname = NULL; + } + gtk_widget_hide(vw->filedlg); + if (gtk_main_level() > 0) + gtk_main_quit(); + } + + /*ARGSUSED*/ + static gboolean + browse_destroy_cb(GtkWidget * widget) + { + if (gui.browse_fname != NULL) + { + g_free(gui.browse_fname); + gui.browse_fname = NULL; + } + gui.filedlg = NULL; + + if (gtk_main_level() > 0) + gtk_main_quit(); + + return FALSE; + } + /* * Put up a file requester. * Returns the selected name in allocated memory, or NULL for Cancel. *************** *** 793,804 **** if (!gui.filedlg) { gui.filedlg = gtk_file_selection_new((const gchar *)title); - fs = GTK_FILE_SELECTION(gui.filedlg); #ifdef GTK_HAVE_FEATURES_1_1_4 gtk_window_set_modal(GTK_WINDOW(gui.filedlg), TRUE); gtk_window_set_transient_for(GTK_WINDOW(gui.filedlg), GTK_WINDOW(gui.mainwin)); #endif gtk_container_border_width(GTK_CONTAINER(fs), 4); gtk_file_selection_hide_fileop_buttons(fs); --- 851,863 ---- if (!gui.filedlg) { gui.filedlg = gtk_file_selection_new((const gchar *)title); #ifdef GTK_HAVE_FEATURES_1_1_4 gtk_window_set_modal(GTK_WINDOW(gui.filedlg), TRUE); gtk_window_set_transient_for(GTK_WINDOW(gui.filedlg), GTK_WINDOW(gui.mainwin)); #endif + fs = GTK_FILE_SELECTION(gui.filedlg); + gtk_container_border_width(GTK_CONTAINER(fs), 4); gtk_file_selection_hide_fileop_buttons(fs); *************** *** 834,926 **** if (gui.browse_fname == NULL) return NULL; return vim_strsave(gui.browse_fname); ! } /* gui_mch_browse */ ! /*ARGSUSED*/ ! static void ! browse_ok_cb(GtkWidget *widget, gpointer cbdata) ! { ! Gui *vw = (Gui *)cbdata; ! if (vw->browse_fname != NULL) ! g_free(vw->browse_fname); ! vw->browse_fname = (char_u *)g_strdup(gtk_file_selection_get_filename( ! GTK_FILE_SELECTION(vw->filedlg))); ! gtk_widget_hide(vw->filedlg); ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! } ! /*ARGSUSED*/ static void ! browse_cancel_cb(GtkWidget *widget, gpointer cbdata) { ! Gui *vw = (Gui *)cbdata; ! ! if (vw->browse_fname != NULL) ! { ! g_free(vw->browse_fname); ! vw->browse_fname = NULL; ! } ! gtk_widget_hide(vw->filedlg); ! if (gtk_main_level() > 0) ! gtk_main_quit(); } /*ARGSUSED*/ ! static gboolean ! browse_destroy_cb(GtkWidget * widget) { ! if (gui.browse_fname != NULL) ! { ! g_free(gui.browse_fname); ! gui.browse_fname = NULL; ! } ! gui.filedlg = NULL; ! /* This is needed to get out of gtk_main? */ ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! return FALSE; } - #endif /* USE_BROWSE */ - - #ifdef GUI_DIALOG - - static int dialogStatus; - static GtkWidget *dialogbb = NULL; - /* ARGSUSED */ int ! gui_mch_dialog(int type, ! char_u * title, ! char_u * message, ! char_u * buttons, ! int dfltbutton) { ! char_u *buts; ! char_u *p, *next; int butcount; ! GtkWidget *vbox = NULL; ! GtkWidget *table = NULL; GtkWidget *pixmap; ! GtkWidget *dialogmessage = NULL; ! GtkWidget *action_area = NULL; ! GtkWidget *separator = NULL; GdkPixmap *icon = NULL; GdkBitmap *mask = NULL; char **icon_data = NULL; #define MAXBUT 10 ! GtkWidget *dialogButton[MAXBUT]; if (title == NULL) ! title = (char_u *) "Vim dialog"; if ((type < 0) || (type > VIM_LAST_TYPE)) type = VIM_GENERIC; --- 893,975 ---- if (gui.browse_fname == NULL) return NULL; return vim_strsave(gui.browse_fname); ! } ! #endif /* USE_BROWSE */ ! #ifdef GUI_DIALOG ! typedef struct _ButtonData { ! int *status; ! int index; ! GtkWidget *dialog; ! } ButtonData; ! ! typedef struct _CancelData { ! int *status; ! GtkWidget *dialog; ! } CancelData; ! /* ARGSUSED */ static void ! dlg_button_clicked(GtkWidget * widget, ButtonData *data) { ! *(data->status) = data->index + 1; ! gtk_widget_destroy(data->dialog); } + /* + * This makes the Escape key equivalent to the cancel button. + */ + /*ARGSUSED*/ ! static int ! dlg_key_press_event(GtkWidget * widget, GdkEventKey * event, CancelData *data) { ! if (event->keyval != GDK_Escape) ! return FALSE; ! /* The result value of 0 from a dialog is signaling cancelation. */ ! *(data->status) = 0; ! gtk_widget_destroy(data->dialog); ! return TRUE; } /* ARGSUSED */ int ! gui_mch_dialog(int type, /* type of dialog */ ! char_u * title, /* title of dialog */ ! char_u * message, /* message text */ ! char_u * buttons, /* names of buttons */ ! int def_but) /* default button */ { ! char_u *names; ! char_u *p; int butcount; + int dialog_status = -1; ! GtkWidget *dialog; ! GtkWidget *frame; ! GtkWidget *vbox; ! GtkWidget *table; GtkWidget *pixmap; ! GtkWidget *dialogmessage; ! GtkWidget *action_area; ! GtkWidget *sub_area; ! GtkWidget *separator; GdkPixmap *icon = NULL; GdkBitmap *mask = NULL; char **icon_data = NULL; #define MAXBUT 10 ! GtkWidget *button[MAXBUT]; ! ButtonData data[MAXBUT]; ! CancelData cancel_data; if (title == NULL) ! title = (char_u *) "Vim dialog..."; if ((type < 0) || (type > VIM_LAST_TYPE)) type = VIM_GENERIC; *************** *** 928,943 **** /* if our pointer is currently hidden, then we should show it. */ gui_mch_mousehide(FALSE); ! dialogbb = gtk_window_new(GTK_WINDOW_DIALOG); ! gtk_window_set_title(GTK_WINDOW(dialogbb), (const gchar *)title); ! gtk_window_position(GTK_WINDOW(dialogbb), GTK_WIN_POS_MOUSE); #ifdef GTK_HAVE_FEATURES_1_1_4 ! gtk_window_set_transient_for(GTK_WINDOW(dialogbb), GTK_WINDOW(gui.mainwin)); #endif ! gtk_grab_add(dialogbb); vbox = gtk_vbox_new(FALSE, 0); ! gtk_container_add(GTK_CONTAINER(dialogbb), vbox); gtk_widget_show(vbox); table = gtk_table_new(1, 3, FALSE); --- 977,1007 ---- /* if our pointer is currently hidden, then we should show it. */ gui_mch_mousehide(FALSE); ! dialog = gtk_window_new(GTK_WINDOW_DIALOG); ! gtk_window_set_title(GTK_WINDOW(dialog), (const gchar *)title); ! gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE); #ifdef GTK_HAVE_FEATURES_1_1_4 ! gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gui.mainwin)); #endif ! gtk_widget_realize(dialog); ! gdk_window_set_decorations(dialog->window, GDK_DECOR_BORDER); ! gdk_window_set_functions(dialog->window, GDK_FUNC_MOVE); ! ! cancel_data.status = &dialog_status; ! cancel_data.dialog = dialog; ! gtk_signal_connect_after(GTK_OBJECT(dialog), "key_press_event", ! GTK_SIGNAL_FUNC(dlg_key_press_event), ! (gpointer) &cancel_data); ! ! gtk_grab_add(dialog); ! ! /* this makes it look beter on Motif style window managers */ ! frame = gtk_frame_new(NULL); ! gtk_container_add(GTK_CONTAINER(dialog), frame); ! gtk_widget_show(frame); vbox = gtk_vbox_new(FALSE, 0); ! gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); table = gtk_table_new(1, 3, FALSE); *************** *** 968,974 **** icon_data = generic_xpm; }; icon = gdk_pixmap_colormap_create_from_xpm_d(NULL, ! gtk_widget_get_colormap(dialogbb), &mask, NULL, icon_data); if (icon) { pixmap = gtk_pixmap_new(icon, mask); --- 1032,1038 ---- icon_data = generic_xpm; }; icon = gdk_pixmap_colormap_create_from_xpm_d(NULL, ! gtk_widget_get_colormap(dialog), &mask, NULL, icon_data); if (icon) { pixmap = gtk_pixmap_new(icon, mask); *************** *** 976,1006 **** gtk_table_attach_defaults(GTK_TABLE(table), pixmap, 0, 1, 0, 1); gtk_widget_show(pixmap); } /* Add label */ dialogmessage = gtk_label_new((const gchar *)message); gtk_table_attach_defaults(GTK_TABLE(table), dialogmessage, 1, 2, 0, 1); gtk_widget_show(dialogmessage); - /* for some reason this doesn't work properly under kwm */ - /* gdk_window_set_decorations(dialogbb->window, GDK_DECOR_BORDER); - * gdk_window_set_functions(dialogbb->window, 0); - */ - action_area = gtk_hbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(action_area), 4); gtk_box_pack_end(GTK_BOX(vbox), action_area, FALSE, TRUE, 0); gtk_widget_show(action_area); /* make a copy, so that we can insert NULs */ ! buts = vim_strsave(buttons); ! if (buts == NULL) return -1; /* * Create the buttons. */ ! p = buts; for (butcount = 0; butcount < MAXBUT; ++butcount) { for (next = p; *next; ++next) { if (*next == DLG_HOTKEY_CHAR) mch_memmove(next, next + 1, STRLEN(next)); --- 1040,1073 ---- gtk_table_attach_defaults(GTK_TABLE(table), pixmap, 0, 1, 0, 1); gtk_widget_show(pixmap); } + /* Add label */ dialogmessage = gtk_label_new((const gchar *)message); gtk_table_attach_defaults(GTK_TABLE(table), dialogmessage, 1, 2, 0, 1); gtk_widget_show(dialogmessage); action_area = gtk_hbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(action_area), 4); gtk_box_pack_end(GTK_BOX(vbox), action_area, FALSE, TRUE, 0); gtk_widget_show(action_area); + sub_area = gtk_hbox_new(TRUE, 0); + gtk_container_set_border_width(GTK_CONTAINER(sub_area), 0); + gtk_box_pack_start(GTK_BOX(action_area), sub_area, FALSE, TRUE, 0); + gtk_widget_show(sub_area); + /* make a copy, so that we can insert NULs */ ! names = vim_strsave(buttons); ! if (names == NULL) return -1; /* * Create the buttons. */ ! p = names; for (butcount = 0; butcount < MAXBUT; ++butcount) { + char_u *next; + for (next = p; *next; ++next) { if (*next == DLG_HOTKEY_CHAR) mch_memmove(next, next + 1, STRLEN(next)); *************** *** 1010,1066 **** } } ! dialogButton[butcount] = gtk_button_new_with_label((const gchar *)p); ! GTK_WIDGET_SET_FLAGS(dialogButton[butcount], GTK_CAN_DEFAULT); ! gtk_widget_show(dialogButton[butcount]); ! gtk_signal_connect(GTK_OBJECT(dialogButton[butcount]), (const char *)"clicked", ! GTK_SIGNAL_FUNC(butproc), GINT_TO_POINTER(butcount)); if (*next == NUL) { ! gtk_box_pack_end(GTK_BOX(action_area), dialogButton[butcount], ! FALSE, FALSE, 0); break; } else { ! gtk_box_pack_start(GTK_BOX(action_area), dialogButton[butcount], ! FALSE, FALSE, 0); } p = next; } ! ++butcount; ! vim_free(buts); ! if (dfltbutton < 1) ! dfltbutton = 1; ! if (dfltbutton > butcount) ! dfltbutton = butcount; ! /* XtVaSetValues(dialogbb, XmNdefaultButton, dialogButton[dfltbutton - 1], NULL); */ ! gtk_widget_grab_focus(dialogButton[dfltbutton - 1]); ! gtk_widget_grab_default(dialogButton[dfltbutton - 1]); separator = gtk_hseparator_new(); gtk_box_pack_end(GTK_BOX(vbox), separator, FALSE, TRUE, 0); gtk_widget_show(separator); ! dialogStatus = -1; ! gtk_widget_show(dialogbb); ! while (dialogbb) /* stay here until dialog goes away */ gtk_main_iteration_do(TRUE); ! return dialogStatus; } - /* ARGSUSED */ - static void - butproc(GtkWidget * widget, gpointer data) - { - dialogStatus = (GPOINTER_TO_INT(data)) + 1; - - gtk_widget_destroy(dialogbb); - dialogbb = NULL; - if (gtk_main_level() > 0) - gtk_main_quit(); - } #endif /* GUI_DIALOG */ --- 1077,1131 ---- } } ! button[butcount] = gtk_button_new_with_label((const gchar *)p); ! GTK_WIDGET_SET_FLAGS(button[butcount], GTK_CAN_DEFAULT); ! gtk_widget_show(button[butcount]); ! ! data[butcount].status = &dialog_status; ! data[butcount].index = butcount; ! data[butcount].dialog = dialog; ! gtk_signal_connect(GTK_OBJECT(button[butcount]), (const char *)"clicked", ! GTK_SIGNAL_FUNC(dlg_button_clicked), ! (gpointer) &data[butcount]); if (*next == NUL) { ! gtk_box_pack_end(GTK_BOX(action_area), button[butcount], ! FALSE, TRUE, 0); break; } else { ! gtk_box_pack_start(GTK_BOX(sub_area), button[butcount], ! TRUE, TRUE, 0); } p = next; } ! vim_free(names); ! ! --def_but; /* 1 is first button */ ! if (def_but < 0) ! def_but = 0; ! if (def_but > butcount) ! def_but = butcount; ! gtk_widget_grab_focus(button[def_but]); ! gtk_widget_grab_default(button[def_but]); separator = gtk_hseparator_new(); gtk_box_pack_end(GTK_BOX(vbox), separator, FALSE, TRUE, 0); gtk_widget_show(separator); ! dialog_status = -1; ! gtk_widget_show(dialog); ! ! /* loop here until the dialog goes away */ ! while (dialog_status == -1 && GTK_WIDGET_VISIBLE(dialog)) gtk_main_iteration_do(TRUE); ! if (dialog_status < 0) ! dialog_status = 0; ! return dialog_status; } #endif /* GUI_DIALOG */ *************** *** 1069,1081 **** gui_mch_show_popupmenu(VimMenu * menu) { gtk_menu_popup(GTK_MENU(menu->submenu_id), ! NULL, NULL, NULL, NULL, 3, GDK_CURRENT_TIME); } #endif /* ! * Don't create it twice! */ typedef struct _SharedFindReplace { --- 1134,1146 ---- gui_mch_show_popupmenu(VimMenu * menu) { gtk_menu_popup(GTK_MENU(menu->submenu_id), ! NULL, NULL, NULL, NULL, 3, (guint32)GDK_CURRENT_TIME); } #endif /* ! * We don't create it twice. */ typedef struct _SharedFindReplace { *************** *** 1090,1165 **** GtkWidget *all; /* 'Replace All' action button */ } SharedFindReplace; ! static SharedFindReplace find_widgets; ! static SharedFindReplace repl_widgets; ! ! /*ARGSUSED*/ ! void ! gui_mch_find_dialog(char_u * arg) { ! find_replace_dialog_create(FALSE); ! } ! ! /*ARGSUSED*/ ! void ! gui_mch_replace_dialog(char_u * arg) ! { ! find_replace_dialog_create(TRUE); ! } ! /* ! * Synchronize all gui elements, which are dependant upon the ! * main text font used. Those are in esp. the find/replace dialogs. ! * If You don't understand why this should be needed, please try to ! * search for "pięść" in iso8859-2. ! */ ! void gui_gtk_synch_fonts(void) ! { ! SharedFindReplace *frdp; ! int do_replace; ! /* OK this loop is a bit tricky... */ ! for (do_replace = 0; do_replace <= 1; ++do_replace) { ! frdp = (do_replace) ? (&repl_widgets) : (&find_widgets); ! if (frdp->dialog) { ! GtkStyle *style; ! /* synch the font with whats used by the text itself */ ! style = gtk_style_copy(gtk_widget_get_style(frdp->what)); ! gdk_font_unref(style->font); ! style->font = gui.norm_font; ! gdk_font_ref(style->font); ! gtk_widget_set_style(frdp->what, style); ! gtk_style_unref(style); ! if (do_replace) { ! style = gtk_style_copy(gtk_widget_get_style(frdp->with)); ! gdk_font_unref(style->font); ! style->font = gui.norm_font; ! gdk_font_ref(style->font); ! gtk_widget_set_style(frdp->with, style); ! gtk_style_unref(style); ! } ! } ! } } static void ! find_replace_dialog_create(int do_replace) { ! GtkWidget *hbox; /* main top down box */ ! GtkWidget *actionarea; ! GtkWidget *table; ! GtkWidget *tmp; ! GtkWidget *vbox; ! gboolean sensitive; SharedFindReplace *frdp; ! char *entry_text; frdp = (do_replace) ? (&repl_widgets) : (&find_widgets); if (frdp->dialog) { gui_gtk_synch_fonts(); if (!GTK_WIDGET_VISIBLE(frdp->dialog)) { --- 1155,1238 ---- GtkWidget *all; /* 'Replace All' action button */ } SharedFindReplace; ! static SharedFindReplace find_widgets = { NULL }; ! static SharedFindReplace repl_widgets = { NULL }; ! /* ARGSUSED */ ! static int ! find_key_press_event(GtkWidget * widget, ! GdkEventKey * event, ! SharedFindReplace * frdp) { ! /* If the user is holding one of the key modifiers we will just bail out, ! * thus preserving the possibility of normal focus traversal. ! */ ! if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) ! return FALSE; ! /* the scape key synthesizes a cancellation action */ ! if (event->keyval == GDK_Escape) { ! find_replace_cb(widget, FR_DIALOGTERM); ! gtk_widget_hide(frdp->dialog); + return TRUE; + } ! /* block traversal resulting from those keys */ ! if (event->keyval == GDK_Left || event->keyval == GDK_Right) ! return TRUE; ! /* It would be delightfull if it where possible to do search history ! * operations on the K_UP and K_DOWN keys here. ! */ ! return FALSE; } static void ! find_replace_dialog_create(char_u *arg, int do_replace) { ! GtkWidget *frame; ! GtkWidget *hbox; /* main top down box */ ! GtkWidget *actionarea; ! GtkWidget *table; ! GtkWidget *tmp; ! GtkWidget *vbox; ! gboolean sensitive; SharedFindReplace *frdp; ! char_u *entry_text = arg; ! gboolean exact_word = FALSE; frdp = (do_replace) ? (&repl_widgets) : (&find_widgets); + /* + * If the argument is emtpy, get the last used search pattern. If it is + * surrounded by "\<..\>" remove that and set the "exact_word" toggle + * button. + */ + if (*entry_text == NUL) + entry_text = last_search_pat(); + if (entry_text != NULL) + { + entry_text = vim_strsave(entry_text); + if (entry_text != NULL) + { + int len = STRLEN(entry_text); + + if (len >= 4 + && STRNCMP(entry_text, "\\<", 2) == 0 + && STRNCMP(entry_text + len - 2, "\\>", 2) == 0) + { + exact_word = TRUE; + mch_memmove(entry_text, entry_text + 2, (size_t)(len - 4)); + entry_text[len - 4] = NUL; + } + } + } + + /* + * If the dialog already exists, just raise it. + */ if (frdp->dialog) { gui_gtk_synch_fonts(); if (!GTK_WIDGET_VISIBLE(frdp->dialog)) { *************** *** 1167,1174 **** --- 1240,1254 ---- gtk_widget_show(frdp->dialog); } + if (entry_text != NULL) + { + gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->exact), + exact_word); + } gdk_window_raise(frdp->dialog->window); + vim_free(entry_text); return; } *************** *** 1182,1190 **** } gtk_window_position(GTK_WINDOW(frdp->dialog), GTK_WIN_POS_MOUSE); hbox = gtk_hbox_new(FALSE, 0); ! gtk_container_add(GTK_CONTAINER(frdp->dialog), hbox); if (do_replace) table = gtk_table_new(1024, 4, FALSE); --- 1262,1279 ---- } gtk_window_position(GTK_WINDOW(frdp->dialog), GTK_WIN_POS_MOUSE); + gtk_widget_realize(frdp->dialog); + gdk_window_set_decorations(frdp->dialog->window, + GDK_DECOR_TITLE | GDK_DECOR_BORDER | GDK_DECOR_RESIZEH); + gdk_window_set_functions(frdp->dialog->window, + GDK_FUNC_RESIZE | GDK_FUNC_MOVE); + + /* this makes it look beter on Motif style window managers */ + frame = gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(frdp->dialog), frame); hbox = gtk_hbox_new(FALSE, 0); ! gtk_container_add(GTK_CONTAINER(frame), hbox); if (do_replace) table = gtk_table_new(1024, 4, FALSE); *************** *** 1198,1208 **** gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 0, 1, GTK_FILL, GTK_EXPAND, 2, 2); frdp->what = gtk_entry_new(); ! entry_text = gtk_entry_get_text(GTK_ENTRY(frdp->what)); ! sensitive = (strlen(entry_text) != 0); ! gtk_entry_set_text(GTK_ENTRY(frdp->what), entry_text); gtk_signal_connect(GTK_OBJECT(frdp->what), "changed", GTK_SIGNAL_FUNC(entry_changed_cb), frdp->dialog); gtk_table_attach(GTK_TABLE(table), frdp->what, 1, 1024, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2); --- 1287,1300 ---- gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 0, 1, GTK_FILL, GTK_EXPAND, 2, 2); frdp->what = gtk_entry_new(); ! sensitive = (entry_text != NULL && STRLEN(entry_text) != 0); ! if (entry_text != NULL) ! gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text); gtk_signal_connect(GTK_OBJECT(frdp->what), "changed", GTK_SIGNAL_FUNC(entry_changed_cb), frdp->dialog); + gtk_signal_connect_after(GTK_OBJECT(frdp->what), "key_press_event", + GTK_SIGNAL_FUNC(find_key_press_event), + (gpointer) frdp); gtk_table_attach(GTK_TABLE(table), frdp->what, 1, 1024, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2); *************** *** 1215,1220 **** --- 1307,1315 ---- gtk_signal_connect(GTK_OBJECT(frdp->with), "activate", GTK_SIGNAL_FUNC(find_replace_cb), (gpointer) FR_R_FINDNEXT); + gtk_signal_connect_after(GTK_OBJECT(frdp->with), "key_press_event", + GTK_SIGNAL_FUNC(find_key_press_event), + (gpointer) frdp); gtk_table_attach(GTK_TABLE(table), frdp->with, 1, 1024, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2); *************** *** 1235,1241 **** /* exact match only button */ frdp->exact = gtk_check_button_new_with_label("Match exact word only"); ! gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->exact), FALSE); gtk_signal_connect(GTK_OBJECT(frdp->exact), "clicked", GTK_SIGNAL_FUNC(exact_match_cb), NULL); if (do_replace) --- 1330,1336 ---- /* exact match only button */ frdp->exact = gtk_check_button_new_with_label("Match exact word only"); ! gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->exact), exact_word); gtk_signal_connect(GTK_OBJECT(frdp->exact), "clicked", GTK_SIGNAL_FUNC(exact_match_cb), NULL); if (do_replace) *************** *** 1256,1262 **** gtk_container_border_width(GTK_CONTAINER(vbox), 0); gtk_container_add(GTK_CONTAINER(tmp), vbox); ! /* 'up' and 'down' buttons */ frdp->up = gtk_radio_button_new_with_label(NULL, "Up"); gtk_box_pack_start(GTK_BOX(vbox), frdp->up, TRUE, TRUE, 0); frdp->down = gtk_radio_button_new_with_label( --- 1351,1357 ---- gtk_container_border_width(GTK_CONTAINER(vbox), 0); gtk_container_add(GTK_CONTAINER(tmp), vbox); ! /* 'Up' and 'Down' buttons */ frdp->up = gtk_radio_button_new_with_label(NULL, "Up"); gtk_box_pack_start(GTK_BOX(vbox), frdp->up, TRUE, TRUE, 0); frdp->down = gtk_radio_button_new_with_label( *************** *** 1281,1287 **** } gtk_box_pack_end(GTK_BOX(hbox), actionarea, FALSE, FALSE, 0); ! /* 'find next' button */ frdp->find = gtk_button_new_with_label("Find Next"); gtk_widget_set_sensitive(frdp->find, sensitive); if (do_replace) --- 1376,1382 ---- } gtk_box_pack_end(GTK_BOX(hbox), actionarea, FALSE, FALSE, 0); ! /* 'Find Next' button */ frdp->find = gtk_button_new_with_label("Find Next"); gtk_widget_set_sensitive(frdp->find, sensitive); if (do_replace) *************** *** 1297,1303 **** gtk_widget_grab_default(frdp->find); if (do_replace) { ! /* 'replace' button */ frdp->replace = gtk_button_new_with_label("Replace"); gtk_widget_set_sensitive(frdp->replace, sensitive); GTK_WIDGET_SET_FLAGS(frdp->replace, GTK_CAN_DEFAULT); --- 1392,1398 ---- gtk_widget_grab_default(frdp->find); if (do_replace) { ! /* 'Replace' button */ frdp->replace = gtk_button_new_with_label("Replace"); gtk_widget_set_sensitive(frdp->replace, sensitive); GTK_WIDGET_SET_FLAGS(frdp->replace, GTK_CAN_DEFAULT); *************** *** 1306,1312 **** GTK_SIGNAL_FUNC(find_replace_cb), (gpointer) FR_REPLACE); ! /* 'replace all' button */ frdp->all = gtk_button_new_with_label("Replace All"); gtk_widget_set_sensitive(frdp->all, sensitive); GTK_WIDGET_SET_FLAGS(frdp->all, GTK_CAN_DEFAULT); --- 1401,1407 ---- GTK_SIGNAL_FUNC(find_replace_cb), (gpointer) FR_REPLACE); ! /* 'Replace All' button */ frdp->all = gtk_button_new_with_label("Replace All"); gtk_widget_set_sensitive(frdp->all, sensitive); GTK_WIDGET_SET_FLAGS(frdp->all, GTK_CAN_DEFAULT); *************** *** 1316,1322 **** (gpointer) FR_REPLACEALL); } ! /* 'cancel' button */ tmp = gtk_button_new_with_label("Cancel"); GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT); gtk_box_pack_end(GTK_BOX(actionarea), tmp, FALSE, FALSE, 0); --- 1411,1417 ---- (gpointer) FR_REPLACEALL); } ! /* 'Cancel' button */ tmp = gtk_button_new_with_label("Cancel"); GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT); gtk_box_pack_end(GTK_BOX(actionarea), tmp, FALSE, FALSE, 0); *************** *** 1340,1350 **** gui_gtk_synch_fonts(); gtk_widget_show_all(frdp->dialog); } /* * Convenience function. ! * creates a button with a label, and packs it into the box specified by the * parameter 'parent'. */ GtkWidget * --- 1435,1499 ---- gui_gtk_synch_fonts(); gtk_widget_show_all(frdp->dialog); + + vim_free(entry_text); + } + + void + gui_mch_find_dialog(char_u * arg) + { + find_replace_dialog_create(arg, FALSE); + } + + + void + gui_mch_replace_dialog(char_u * arg) + { + find_replace_dialog_create(arg, TRUE); + } + + + /* + * Synchronize all gui elements, which are dependant upon the + * main text font used. Those are in esp. the find/replace dialogs. + * If You don't understand why this should be needed, please try to + * search for "pięść" in iso8859-2. + */ + void + gui_gtk_synch_fonts(void) + { + SharedFindReplace *frdp; + int do_replace; + + /* OK this loop is a bit tricky... */ + for (do_replace = 0; do_replace <= 1; ++do_replace) { + frdp = (do_replace) ? (&repl_widgets) : (&find_widgets); + if (frdp->dialog) { + GtkStyle *style; + + /* synch the font with whats used by the text itself */ + style = gtk_style_copy(gtk_widget_get_style(frdp->what)); + gdk_font_unref(style->font); + style->font = gui.norm_font; + gdk_font_ref(style->font); + gtk_widget_set_style(frdp->what, style); + gtk_style_unref(style); + if (do_replace) { + style = gtk_style_copy(gtk_widget_get_style(frdp->with)); + gdk_font_unref(style->font); + style->font = gui.norm_font; + gdk_font_ref(style->font); + gtk_widget_set_style(frdp->with, style); + gtk_style_unref(style); + } + } + } } + /* * Convenience function. ! * Creates a button with a label, and packs it into the box specified by the * parameter 'parent'. */ GtkWidget * *************** *** 1355,1362 **** GtkWidget *parent, int connect_object, gboolean expand, ! gboolean fill ! ) { GtkWidget *tmp; --- 1504,1510 ---- GtkWidget *parent, int connect_object, gboolean expand, ! gboolean fill) { GtkWidget *tmp; *************** *** 1374,1418 **** /*** private function definitions ***/ - #ifdef WANT_MENU - static void - gui_mch_recurse_tearoffs(VimMenu * menu, int val) - { - #ifdef GTK_HAVE_FEATURES_1_1_0 - while (menu != NULL) { - if (!popup_menu(menu->name)) { - if (menu->submenu_id != 0) { - if (val) - gtk_widget_show(menu->tearoff_handle); - else - gtk_widget_hide(menu->tearoff_handle); - } - gui_mch_recurse_tearoffs(menu->children, val); - } - menu = menu->next; - } - #endif - } - - /*ARGSUSED*/ - static void - menu_item_cb(GtkWidget * widget, gpointer data) - { - gui_menu_cb((VimMenu *) data); - - /* make sure the menu action is taken immediately */ - if (gtk_main_level() > 0) - gtk_main_quit(); - } - #endif - - /* * Callback for actions of the find and replace dialogs */ /*ARGSUSED*/ static void ! find_replace_cb(GtkWidget * widget, gint flags) { char *find_text, *repl_text, *cmd; gboolean direction_down = TRUE; --- 1522,1533 ---- /*** private function definitions ***/ /* * Callback for actions of the find and replace dialogs */ /*ARGSUSED*/ static void ! find_replace_cb(GtkWidget * widget, unsigned int flags) { char *find_text, *repl_text, *cmd; gboolean direction_down = TRUE; *************** *** 1519,1525 **** } g_free(cmd); ! } /* find_replace_cb */ /* our usual callback function */ /*ARGSUSED*/ --- 1634,1640 ---- } g_free(cmd); ! } /* our usual callback function */ /*ARGSUSED*/ *************** *** 1615,1631 **** } } ! ! static void helpfind_ok(GtkWidget *wgt, gpointer cbdata); ! static void helpfind_entry_changed(GtkWidget *entry, gpointer cbdata); static GtkWidget *helpfind = NULL; static GtkWidget *help_entry = NULL; ! void ! do_helpfind() { ! GtkWidget *vbox, *hbox, *tmp; if (!gui.in_use) { --- 1730,1808 ---- } } ! /* ! * Handling of the nice additional asynchronous little help topic requester. ! */ static GtkWidget *helpfind = NULL; static GtkWidget *help_entry = NULL; + static int help_ok_sensitive = FALSE; ! static void ! helpfind_entry_changed(GtkWidget *entry, gpointer cbdata) { ! GtkWidget *ok = (GtkWidget *)cbdata; ! char *txt = gtk_entry_get_text(GTK_ENTRY(entry)); ! ! if (txt == NULL || *txt == NUL) ! return; ! ! gtk_widget_set_sensitive(ok, strlen(txt)); ! gtk_widget_grab_default(ok); ! help_ok_sensitive = TRUE; ! } ! ! /*ARGSUSED*/ ! static void ! helpfind_ok(GtkWidget *wgt, gpointer cbdata) ! { ! char *txt, *cmd; ! GtkEntry *entry = GTK_ENTRY(cbdata); ! ! if ((txt = gtk_entry_get_text(entry)) == NULL) ! return; ! ! /* When the OK button isn't sensitive, hitting CR means cancel. */ ! if (help_ok_sensitive) ! { ! if ((cmd = (char *)alloc(strlen(txt) + 8)) == NULL) ! return; ! ! /* use CTRL-\ CTRL-N to get Vim into Normal mode first */ ! g_snprintf(cmd, (gulong)(strlen(txt) + 7), "\034\016:h %s\r", txt); ! add_to_input_buf((char_u *)cmd, STRLEN(cmd)); ! vim_free(cmd); ! } ! ! /* Don't destroy this dialogue just hide it from the users view. ! * Reuse it later */ ! gtk_widget_hide(helpfind); ! ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! } ! ! /*ARGSUSED*/ ! static void ! helpfind_cancel(GtkWidget *wgt, gpointer cbdata) ! { ! /* Don't destroy this dialogue just hide it from the users view. ! * Reuse it later */ ! gtk_widget_hide(helpfind); ! ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! } ! ! void ! do_helpfind(void) ! { ! GtkWidget *frame; ! GtkWidget *vbox; ! GtkWidget *hbox; ! GtkWidget *tmp; ! GtkWidget *action_area; ! GtkWidget *sub_area; if (!gui.in_use) { *************** *** 1650,1735 **** gtk_window_set_transient_for(GTK_WINDOW(helpfind), GTK_WINDOW(gui.mainwin)); #endif gtk_window_position(GTK_WINDOW(helpfind), GTK_WIN_POS_MOUSE); ! gtk_window_set_title(GTK_WINDOW(helpfind), "VIM - Help on what?"); gtk_signal_connect(GTK_OBJECT(helpfind), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &helpfind); ! vbox = gtk_vbox_new(FALSE, 6); ! gtk_container_add(GTK_CONTAINER(helpfind), vbox); ! gtk_container_border_width(GTK_CONTAINER(helpfind), 6); hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); ! tmp = gtk_label_new("Topic: "); gtk_box_pack_start(GTK_BOX(hbox), tmp, TRUE, TRUE, 0); help_entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), help_entry, TRUE, TRUE, 0); ! tmp = gtk_hseparator_new(); ! gtk_box_pack_start(GTK_BOX(vbox), tmp, FALSE, TRUE, 0); ! hbox = gtk_hbutton_box_new(); ! gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_EDGE); ! gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbox), 0); ! gtk_container_border_width(GTK_CONTAINER(hbox), 0); ! gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); ! ! tmp = gui_gtk_button_new_with_label("Ok", ! GTK_SIGNAL_FUNC(helpfind_ok), ! help_entry, hbox, FALSE, FALSE, FALSE); gtk_signal_connect(GTK_OBJECT(help_entry), "changed", GTK_SIGNAL_FUNC(helpfind_entry_changed), tmp); gtk_signal_connect(GTK_OBJECT(help_entry), "activate", GTK_SIGNAL_FUNC(helpfind_ok), help_entry); gtk_widget_set_sensitive(tmp, FALSE); GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT); ! tmp = gui_gtk_button_new_with_label("Cancel", ! GTK_SIGNAL_FUNC(gtk_widget_destroy), ! helpfind, hbox, TRUE, FALSE, FALSE); ! GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT); ! gtk_widget_grab_default(tmp); gtk_widget_grab_focus(help_entry); gtk_widget_show_all(helpfind); - } - - - static void - helpfind_entry_changed(GtkWidget *entry, gpointer cbdata) - { - GtkWidget *ok = (GtkWidget *)cbdata; - char *txt = gtk_entry_get_text(GTK_ENTRY(entry)); - - if (txt == NULL) - return; - - gtk_widget_set_sensitive(ok, strlen(txt)); - } - - - /*ARGSUSED*/ - static void - helpfind_ok(GtkWidget *wgt, gpointer cbdata) - { - char *txt, *cmd; - GtkEntry *entry = GTK_ENTRY(cbdata); - - if ((txt = gtk_entry_get_text(entry)) == NULL) - return; - - if ((cmd = (char *)alloc(strlen(txt) + 8)) == NULL) - return; - - /* use CTRL-\ CTRL-N to get Vim into Normal mode first */ - g_snprintf(cmd, (gulong)(strlen(txt) + 7), "\034\016:h %s\r", txt); - add_to_input_buf((char_u *)cmd, STRLEN(cmd)); - - gtk_widget_destroy(helpfind); - vim_free(cmd); - - if (gtk_main_level() > 0) - gtk_main_quit(); } --- 1827,1888 ---- gtk_window_set_transient_for(GTK_WINDOW(helpfind), GTK_WINDOW(gui.mainwin)); #endif gtk_window_position(GTK_WINDOW(helpfind), GTK_WIN_POS_MOUSE); ! gtk_window_set_title(GTK_WINDOW(helpfind), "VIM - Help on..."); ! ! gtk_widget_realize(helpfind); ! gdk_window_set_decorations(helpfind->window, ! GDK_DECOR_BORDER | GDK_DECOR_TITLE); ! gdk_window_set_functions(helpfind->window, GDK_FUNC_MOVE); ! gtk_signal_connect(GTK_OBJECT(helpfind), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &helpfind); ! /* this makes it look beter on Motif style window managers */ ! frame = gtk_frame_new(NULL); ! gtk_container_add(GTK_CONTAINER(helpfind), frame); ! gtk_widget_show(frame); ! ! vbox = gtk_vbox_new(FALSE, 0); ! gtk_container_add(GTK_CONTAINER(frame), vbox); hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + gtk_container_border_width(GTK_CONTAINER(hbox), 6); ! tmp = gtk_label_new("Topic:"); gtk_box_pack_start(GTK_BOX(hbox), tmp, TRUE, TRUE, 0); help_entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), help_entry, TRUE, TRUE, 0); ! action_area = gtk_hbox_new(FALSE, 0); ! gtk_container_set_border_width(GTK_CONTAINER(action_area), 4); ! gtk_box_pack_end(GTK_BOX(vbox), action_area, FALSE, TRUE, 0); ! sub_area = gtk_hbox_new(TRUE, 0); ! gtk_container_set_border_width(GTK_CONTAINER(sub_area), 0); ! gtk_box_pack_end(GTK_BOX(action_area), sub_area, FALSE, TRUE, 0); ! ! tmp = gui_gtk_button_new_with_label("Cancel", ! GTK_SIGNAL_FUNC(helpfind_cancel), ! help_entry, sub_area, TRUE, TRUE, TRUE); ! GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT); ! gtk_widget_grab_default(tmp); ! ! tmp = gui_gtk_button_new_with_label("OK", ! GTK_SIGNAL_FUNC(helpfind_ok), ! help_entry, sub_area, FALSE, TRUE, TRUE); gtk_signal_connect(GTK_OBJECT(help_entry), "changed", GTK_SIGNAL_FUNC(helpfind_entry_changed), tmp); gtk_signal_connect(GTK_OBJECT(help_entry), "activate", GTK_SIGNAL_FUNC(helpfind_ok), help_entry); gtk_widget_set_sensitive(tmp, FALSE); + help_ok_sensitive = FALSE; GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT); ! tmp = gtk_hseparator_new(); ! gtk_box_pack_end(GTK_BOX(vbox), tmp, FALSE, TRUE, 0); gtk_widget_grab_focus(help_entry); gtk_widget_show_all(helpfind); } *** ../vim-5.6a.17/src/gui_gtk_x11.c Wed Dec 29 12:11:01 1999 --- src/gui_gtk_x11.c Sat Jan 8 21:15:25 2000 *************** *** 19,24 **** --- 19,29 ---- * :-) (My native language is polish and I speak * native grade german too. I'm living in Göttingen.de.) * --mdcki" + * + * + * Although some #ifdefs suggest that GTK 1.0 is supported, it isn't. The + * code requires GTK version 1.1.16 or later. Stuff for older versions will + * be removed some time. */ #include "vim.h" *************** *** 36,46 **** /* slection distinguishers */ enum { ! SEL_TYPE_NONE, SELECTION_STRING, SELECTION_CLIPBOARD }; /* This is the single only fixed width font in X11, which seems to be present * on all servers and available in all the variants we need. * --- 41,69 ---- /* slection distinguishers */ enum { ! SELECTION_TYPE_NONE, SELECTION_STRING, SELECTION_CLIPBOARD }; + /* + * Enable DND feature. Disable this if it causes problems. + */ + #define GTK_DND + + #ifdef GTK_DND + /* DND specification constants. */ + enum { + TARGET_STRING + }; + + static GtkTargetEntry target_table[] = { + { "STRING", 0, TARGET_STRING }, + { "text/plain", 0, TARGET_STRING } + }; + static guint n_targets = sizeof(target_table) / sizeof(target_table[0]); + #endif + /* This is the single only fixed width font in X11, which seems to be present * on all servers and available in all the variants we need. * *************** *** 50,78 **** #define DFLT_FONT "-adobe-courier-medium-r-normal-*-14-*-*-*-m-*-*-*" ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! static void font_sel_ok(GtkWidget *wgt, gpointer cbdata); ! static void font_sel_cancel(GtkWidget *wgt, gpointer cbdata); ! static void font_sel_destroy(GtkWidget *wgt, gpointer cbdata); ! #endif ! ! static gint expose_event(GtkWidget * widget, GdkEventExpose * event); ! static gint button_press_event(GtkWidget * widget, GdkEventButton * event); ! static gint button_release_event(GtkWidget * widget, GdkEventButton * event); ! static gint motion_notify_event(GtkWidget * widget, GdkEventMotion * event); ! static void destroy_callback(void); ! static int delete_event_cb(GtkWidget *wgt, gpointer cbdata); /* ! * If of the atom used to communicate save yourself from the X11 session ! * manager. There is no need to move this into the GUI struct, since this ! * should be always constant. */ ! GdkAtom save_yourself_atom = GDK_NONE; /* * Keycodes recognized by vim. - * we will be using the techniques described here later for real work. */ static struct special_key { guint key_sym; --- 73,93 ---- #define DFLT_FONT "-adobe-courier-medium-r-normal-*-14-*-*-*-m-*-*-*" ! /* ! * Atom used to communicate save yourself from the X11 session manager. There ! * is no need to move this into the GUI struct, since this should be always ! * constant. ! */ ! static GdkAtom save_yourself_atom = GDK_NONE; /* ! * Atom used to recognize requests for on the fly GTK+ style configuration ! * changes. */ ! static GdkAtom reread_rcfiles_atom = GDK_NONE; /* * Keycodes recognized by vim. */ static struct special_key { guint key_sym; *************** *** 306,311 **** --- 321,357 ---- #endif /* + * Redraw the corresponding portions of the screen. + */ + /*ARGSUSED*/ + static gint + expose_event(GtkWidget * widget, GdkEventExpose * event) + { + out_flush(); /* make sure all output has been processed */ + gui_redraw(event->area.x, event->area.y, + event->area.width, event->area.height); + + /* Clear the border areas if needed */ + if (event->area.x < FILL_X(0)) + gdk_window_clear_area(gui.drawarea->window, 0, 0, FILL_X(0), 0); + if (event->area.y < FILL_Y(0)) + gdk_window_clear_area(gui.drawarea->window, 0, 0, 0, FILL_Y(0)); + if (event->area.x > FILL_X(Columns)) + gdk_window_clear_area(gui.drawarea->window, + FILL_X((int)Columns), 0, 0, 0); + if (event->area.y > FILL_Y(Rows)) + gdk_window_clear_area(gui.drawarea->window, 0, FILL_Y((int)Rows), 0, 0); + + return FALSE; + } + + + /**************************************************************************** + * Focus handlers: + */ + + + /* * This is a simple state machine: * BLINK_NONE not blinking at all * BLINK_OFF blinking, cursor is not shown *************** *** 347,364 **** /*ARGSUSED*/ static gint ! gui_gtk_blink_cb(gpointer data) { if (blink_state == BLINK_ON) { gui_undraw_cursor(); blink_state = BLINK_OFF; ! blink_timer = gtk_timeout_add(blink_offtime, ! (GtkFunction) gui_gtk_blink_cb, NULL); } else { gui_update_cursor(TRUE, FALSE); blink_state = BLINK_ON; ! blink_timer = gtk_timeout_add(blink_ontime, ! (GtkFunction) gui_gtk_blink_cb, NULL); } return FALSE; /* don't happen again */ --- 393,410 ---- /*ARGSUSED*/ static gint ! blink_cb(gpointer data) { if (blink_state == BLINK_ON) { gui_undraw_cursor(); blink_state = BLINK_OFF; ! blink_timer = gtk_timeout_add((guint32)blink_offtime, ! (GtkFunction) blink_cb, NULL); } else { gui_update_cursor(TRUE, FALSE); blink_state = BLINK_ON; ! blink_timer = gtk_timeout_add((guint32)blink_ontime, ! (GtkFunction) blink_cb, NULL); } return FALSE; /* don't happen again */ *************** *** 375,382 **** gtk_timeout_remove(blink_timer); /* Only switch blinking on if none of the times is zero */ if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) { ! blink_timer = gtk_timeout_add(blink_waittime, ! (GtkFunction) gui_gtk_blink_cb, NULL); blink_state = BLINK_ON; gui_update_cursor(TRUE, FALSE); } --- 421,428 ---- gtk_timeout_remove(blink_timer); /* Only switch blinking on if none of the times is zero */ if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) { ! blink_timer = gtk_timeout_add((guint32)blink_waittime, ! (GtkFunction) blink_cb, NULL); blink_state = BLINK_ON; gui_update_cursor(TRUE, FALSE); } *************** *** 437,451 **** } /*ARGSUSED*/ static gint key_press_event(GtkWidget * widget, GdkEventKey * event, gpointer data) { - #ifdef USE_XIM char_u string[256], string2[256]; - #else - char_u string[3], string2[3]; - #endif guint key_sym; int len; int i; --- 483,497 ---- } + /**************************************************************************** + * Main keyboard handler: + */ + /*ARGSUSED*/ static gint key_press_event(GtkWidget * widget, GdkEventKey * event, gpointer data) { char_u string[256], string2[256]; guint key_sym; int len; int i; *************** *** 571,576 **** --- 617,628 ---- return TRUE; } + + /**************************************************************************** + * Selection handlers: + */ + + /*ARGSUSED*/ static gint selection_clear_event(GtkWidget * widget, GdkEventSelection * event) *************** *** 647,653 **** clip_get_selection(); /* get the selection from the * register */ ! motion_type = clip_convert_selection(&string, (long_u *)&length); if (motion_type < 0) return; --- 699,705 ---- clip_get_selection(); /* get the selection from the * register */ ! motion_type = clip_convert_selection(&string, &length); if (motion_type < 0) return; *************** *** 655,661 **** if (info == SELECTION_CLIPBOARD) length++; ! result = (char_u *)malloc(2 * length); if (result == NULL) { vim_free(string); --- 707,713 ---- if (info == SELECTION_CLIPBOARD) length++; ! result = lalloc((long_u)(2 * length), FALSE); if (result == NULL) { vim_free(string); *************** *** 676,682 **** selection_data->type = selection_data->target; selection_data->format = 8; /* 8 bits per char */ ! gtk_selection_data_set(selection_data, type, 8, result, length); vim_free(string); vim_free(result); } --- 728,734 ---- selection_data->type = selection_data->target; selection_data->format = 8; /* 8 bits per char */ ! gtk_selection_data_set(selection_data, type, 8, result, (gint)length); vim_free(string); vim_free(result); } *************** *** 771,2916 **** return OK; } /* ! * Setup the window icon after the main window has bee realized. */ ! /*ARGSUSED*/ ! static void ! mainwin_realize(GtkWidget *widget) { ! /* If you get an error message here, you still need to unpack the runtime ! * archive! */ ! #include "../runtime/vim32x32.xpm" ! static GdkPixmap *icon = NULL; ! static GdkBitmap *icon_mask = NULL; ! if (!icon) ! icon = gdk_pixmap_create_from_xpm_d(gui.mainwin->window, ! &icon_mask, NULL, magick); ! gdk_window_set_icon(gui.mainwin->window, NULL, icon, icon_mask); } /* ! * After the drawing area comes up, we calculate all colors and create the ! * dummy blank cursor. ! * ! * Don't try to set any VIM scrollbar sizes anywhere here. I'm relying on the ! * fact that the main VIM engine doesn't take them into account anywhere. */ ! static void ! drawarea_realize_cb(GtkWidget *widget) { ! char blank_data[] = {0x0}; ! GdkPixmap *blank_mask; ! GdkColor color; ! GtkWidget *sbar; ! #ifdef USE_XIM ! xim_init(); ! #endif ! gui_mch_new_colors(); ! blank_mask = gdk_bitmap_create_from_data(NULL, blank_data, 1, 1); ! gdk_color_white(gdk_colormap_get_system(), &color); ! gui.blank_pointer = gdk_cursor_new_from_pixmap(blank_mask, blank_mask, ! &color, &color, 0, 0); ! gdk_bitmap_unref(blank_mask); ! if (gui.pointer_hidden) ! gdk_window_set_cursor(widget->window, gui.blank_pointer); ! /* get the actual size of the scrollbars, if they are realized */ ! sbar = firstwin->w_scrollbars[SBAR_LEFT].id; ! if (!sbar || (!gui.which_scrollbars[SBAR_LEFT] ! && firstwin->w_scrollbars[SBAR_RIGHT].id)) ! sbar = firstwin->w_scrollbars[SBAR_RIGHT].id; ! if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.width) ! gui.scrollbar_width = sbar->allocation.width; ! sbar = gui.bottom_sbar.id; ! if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.height) ! gui.scrollbar_height = sbar->allocation.height; } ! /* ! * Initialise the X GUI. Create all the windows, set up all the call-backs etc. ! * Returns OK for success, FAIL when the GUI can't be started. ! */ ! int ! gui_mch_init() { ! GtkWidget *vbox; ! /* Uncomment this to enable synchronous mode for debugging */ ! /* XSynchronize(gui.dpy, True); */ ! /* Initialize values */ ! gui.rev_video = FALSE; ! gui.border_width = 2; ! gui.scrollbar_width = SB_DEFAULT_WIDTH; ! gui.scrollbar_height = SB_DEFAULT_WIDTH; ! gui.fgcolor = g_new0(GdkColor, 1); ! gui.bgcolor = g_new0(GdkColor, 1); ! #ifdef WANT_MENU ! /* Don't change the menu height values used in gui.c at runtime */ ! gui.menu_height_fixed = TRUE; ! #endif ! /* Set default foreground and background colours. */ ! gui.norm_pixel = gui.def_norm_pixel; ! gui.back_pixel = gui.def_back_pixel; ! gui.mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); ! gtk_window_set_policy(GTK_WINDOW(gui.mainwin), TRUE, TRUE, TRUE); ! gtk_container_border_width(GTK_CONTAINER(gui.mainwin), 0); ! gtk_widget_set_events(gui.mainwin, GDK_VISIBILITY_NOTIFY_MASK); ! (void)gtk_signal_connect(GTK_OBJECT(gui.mainwin), "delete_event", ! GTK_SIGNAL_FUNC(delete_event_cb), NULL); ! /* Add an icon to the main window. For fun and convenience of the user. */ ! if (vim_strchr(p_go, GO_ICON) != NULL) ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "realize", ! GTK_SIGNAL_FUNC(mainwin_realize), NULL); ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! /* FIXME: this should eventually get the accelgroup of the gui.mainwin */ ! gui.accel_group = gtk_accel_group_get_default(); ! #endif ! vbox = gtk_vbox_new(FALSE, 0); ! gtk_container_add(GTK_CONTAINER(gui.mainwin), vbox); ! gtk_widget_show(vbox); ! #ifdef WANT_MENU ! /* create the menubar and handle */ ! gui.menubar = gtk_menu_bar_new(); ! gtk_widget_show(gui.menubar); ! gtk_box_pack_start(GTK_BOX(vbox), gui.menubar, FALSE, TRUE, 0); ! #endif ! #ifdef USE_TOOLBAR ! /* create the toolbar */ ! if (p_toolbar) { ! if (strstr((const char *)p_toolbar, "text") ! && strstr((const char *)p_toolbar, "icons")) ! gui.toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, ! GTK_TOOLBAR_BOTH); ! else if (strstr((const char *)p_toolbar, "text")) ! gui.toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, ! GTK_TOOLBAR_TEXT); ! else ! gui.toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, ! GTK_TOOLBAR_ICONS); ! } else ! gui.toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, ! GTK_TOOLBAR_ICONS); ! gtk_widget_show(gui.toolbar); ! # ifdef GTK_HAVE_FEATURES_1_1_0 ! /* some aesthetics on the toolbar */ ! gtk_toolbar_set_button_relief(GTK_TOOLBAR(gui.toolbar), GTK_RELIEF_NONE); ! # endif ! gtk_container_border_width(GTK_CONTAINER(gui.toolbar), 1); ! gtk_box_pack_start(GTK_BOX(vbox), gui.toolbar, FALSE, TRUE, 0); ! #endif ! gui.formwin = gtk_form_new(); ! gtk_container_border_width(GTK_CONTAINER(gui.formwin), 0); ! gtk_widget_set_events(gui.formwin, GDK_EXPOSURE_MASK); - gui.drawarea = gtk_drawing_area_new(); - - /* Determine which events we will filter. */ - gtk_widget_set_events(gui.drawarea, - GDK_EXPOSURE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - gtk_widget_show(gui.drawarea); - gtk_form_put(GTK_FORM(gui.formwin), gui.drawarea, 0, 0); - gtk_widget_show(gui.formwin); - gtk_box_pack_start(GTK_BOX(vbox), gui.formwin, TRUE, TRUE, 0); - - gtk_signal_connect(GTK_OBJECT(gui.mainwin), "key_press_event", - (GtkSignalFunc) key_press_event, NULL); - gtk_signal_connect(GTK_OBJECT(gui.drawarea), "realize", - GTK_SIGNAL_FUNC(drawarea_realize_cb), NULL); ! /* Check if reverse video needs to be applied (on Sun it's done by X) */ ! if (gui.rev_video && gui_mch_get_lightness(gui.back_pixel) ! > gui_mch_get_lightness(gui.norm_pixel)) { ! gui.norm_pixel = gui.def_back_pixel; ! gui.back_pixel = gui.def_norm_pixel; ! gui.def_norm_pixel = gui.norm_pixel; ! gui.def_back_pixel = gui.back_pixel; ! } ! gui.visibility = GDK_VISIBILITY_UNOBSCURED; ! clipboard.atom = gdk_atom_intern("_VIM_TEXT", FALSE); ! save_yourself_atom = gdk_atom_intern("WM_SAVE_YOURSELF", FALSE); /* ! * Start out by adding the configured border width into the border offset. */ ! gui.border_offset = gui.border_width; ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "visibility_notify_event", ! GTK_SIGNAL_FUNC(visibility_event), NULL); ! #endif ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "expose_event", ! GTK_SIGNAL_FUNC(expose_event), NULL); ! /* ! * Only install these enter/leave callbacks when 'p' in 'guioptions'. ! * Only needed for some window managers. ! */ ! if (vim_strchr(p_go, GO_POINTER) != NULL) { ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "leave_notify_event", ! GTK_SIGNAL_FUNC(leave_notify_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "enter_notify_event", ! GTK_SIGNAL_FUNC(enter_notify_event), NULL); } ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_out_event", ! GTK_SIGNAL_FUNC(focus_out_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_in_event", ! GTK_SIGNAL_FUNC(focus_in_event), NULL); ! ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "motion_notify_event", ! GTK_SIGNAL_FUNC(motion_notify_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "button_press_event", ! GTK_SIGNAL_FUNC(button_press_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "button_release_event", ! GTK_SIGNAL_FUNC(button_release_event), NULL); ! /* ! * Add selection handler functions. ! */ ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_clear_event", ! GTK_SIGNAL_FUNC(selection_clear_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_received", ! GTK_SIGNAL_FUNC(selection_received_event), NULL); ! /* gtk_selection_add_target() is not in GTK 1.1.2 */ ! #ifdef GTK_HAVE_FEATURES_1_1_4 ! gtk_selection_add_target(gui.drawarea, GDK_SELECTION_PRIMARY, ! GDK_TARGET_STRING, SELECTION_STRING); ! gtk_selection_add_target(gui.drawarea, GDK_SELECTION_PRIMARY, ! clipboard.atom, SELECTION_CLIPBOARD); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_get", ! GTK_SIGNAL_FUNC(selection_get_event), NULL); ! #else ! gtk_selection_add_handler(gui.drawarea, GDK_SELECTION_PRIMARY, ! GDK_TARGET_STRING, selection_handler, NULL); ! gtk_selection_add_handler(gui.drawarea, GDK_SELECTION_PRIMARY, ! clipboard.atom, selection_handler, NULL); ! #endif ! /* Pretend we don't have input focus, we will get an event if we do. */ ! gui.in_focus = FALSE; ! return OK; } ! ! /* ! * Called when the foreground or background color has been changed. ! */ ! void ! gui_mch_new_colors() { ! /* This used to change the graphics contexts directly but we are currently ! * manipulating them where desired. ! */ ! if (gui.drawarea && gui.drawarea->window) { ! GdkColor color; ! color.pixel = gui.back_pixel; ! gdk_window_set_background(gui.drawarea->window, &color); } } - #ifdef GTK_HAVE_FEATURES_1_1_6 - # define USE_GEOMETRY_FOR_HINTS 1 - #endif static void ! update_window_manager_hints(void) ! { ! int width; ! int height; ! #ifdef USE_GEOMETRY_FOR_HINTS ! GdkGeometry geometry; ! GdkWindowHints geometry_mask; ! /* This also needs to be done when the main window isn't there yet, ! * otherwise the hints don't work. */ ! width = gui_get_base_width(); ! height = gui_get_base_height(); ! geometry_mask = GDK_HINT_BASE_SIZE|GDK_HINT_RESIZE_INC|GDK_HINT_MIN_SIZE; ! geometry.width_inc = gui.char_width; ! geometry.height_inc = gui.char_height; ! geometry.base_width = width; ! geometry.base_height = height; ! geometry.min_width = width + MIN_COLUMNS * gui.char_width; ! geometry.min_height = height + MIN_LINES * gui.char_height; ! gtk_window_set_geometry_hints(GTK_WINDOW(gui.mainwin), gui.formwin, ! &geometry, geometry_mask); ! #else ! XSizeHints size_hints; ! /* Don't set the size until the main window is really there */ ! if (!GTK_WIDGET_REALIZED(gui.mainwin)) ! return; ! width = gui_get_base_width(); ! height = gui_get_base_height(); ! /* The hints don't automatically take the menubar and toolbar into ! * account. Need to add their height here, if they are visible. */ ! # ifdef USE_TOOLBAR ! if (gui.toolbar && GTK_WIDGET_REALIZED(gui.toolbar) ! && GTK_WIDGET_VISIBLE(gui.toolbar)) ! height += gui.toolbar->allocation.height; ! # endif ! # ifdef WANT_MENU ! if (gui.menubar && GTK_WIDGET_REALIZED(gui.menubar) ! && GTK_WIDGET_VISIBLE(gui.menubar)) ! height += gui.menubar->allocation.height; ! # endif /* ! * Argh!!! Once again we need to deal with an ommission in GTK+ by ! * resorting to direct Xlib calls. Fortunatly I know how to do it :-). */ ! size_hints.flags = (PResizeInc | PBaseSize | PMinSize | PSize); ! size_hints.width_inc = gui.char_width; ! size_hints.height_inc = gui.char_height; ! size_hints.base_width = width; ! size_hints.base_height = height; ! size_hints.min_width = width + MIN_COLUMNS * gui.char_width; ! size_hints.min_height = height + MIN_LINES * gui.char_height; ! /* This is only needed for "older" window managers. See a corresposning ! * comment in the X11 headers. */ ! size_hints.width = width + Columns * gui.char_width; ! size_hints.height = height + Rows * gui.char_height; ! XSetWMNormalHints(GDK_DISPLAY(), ! GDK_WINDOW_XWINDOW(gui.mainwin->window), ! &size_hints); ! #endif /* USE_GEOMETRY_FOR_HINTS */ } /* ! * This signal informs us about the need to rearrange our subwidgets. */ /*ARGSUSED*/ ! static gint ! form_configure_event(GtkWidget * widget, GdkEventConfigure * event) { ! gtk_form_freeze(GTK_FORM(gui.formwin)); ! gui_resize_window(event->width, event->height); ! gtk_form_thaw(GTK_FORM(gui.formwin)); ! ! return TRUE; ! } ! /*ARGSUSED*/ ! static gint ! client_event_cb(GtkWidget *widget, GdkEventClient *event) ! { ! if (event->message_type == save_yourself_atom ) { ! out_flush(); ! ml_sync_all(FALSE, FALSE); /* preserve all swap files */ ! return TRUE; ! } ! return FALSE; } /* ! * Open the GUI window which was created by a call to gui_mch_init(). */ ! int ! gui_mch_open() { ! int x = -1, y = -1; ! ! /* Determine user specified geometry, if present. */ ! if (gui.geom) { ! int mask; ! unsigned w, h; ! ! mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h); ! if (mask & WidthValue) ! Columns = w; ! if (mask & HeightValue) ! Rows = h; ! if (mask & (XValue | YValue)) ! gtk_widget_set_uposition(gui.mainwin, x, y); ! g_free(gui.geom); ! gui.geom = NULL; ! } ! ! gtk_form_set_size(GTK_FORM(gui.formwin), ! gui_get_base_width() + Columns * gui.char_width, ! gui_get_base_height() + Rows * gui.char_height); ! update_window_manager_hints(); ! ! if (found_reverse_arg ) ! { ! gui.def_norm_pixel = gui_mch_get_color("White"); ! gui.def_back_pixel = gui_mch_get_color("Black"); ! } ! else ! { ! gui.def_norm_pixel = gui_mch_get_color("Black"); ! gui.def_back_pixel = gui_mch_get_color("White"); ! } ! ! /* Get the colors from the "Normal" and "Menu" group (set in syntax.c or ! * in a vimrc file) ! */ ! set_normal_colors(); ! ! /* Check that none of the colors are the same as the background color */ ! gui_check_colors(); ! ! /* Get the colors for the highlight groups (gui_check_colors() might have ! * changed them). ! */ ! highlight_gui_started(); /* re-init colors and fonts */ ! ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "destroy", ! GTK_SIGNAL_FUNC(destroy_callback), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "client_event", ! GTK_SIGNAL_FUNC(client_event_cb), NULL); ! #ifdef HANGUL_INPUT ! hangul_keyboard_set(); #endif ! /* ! * Notify the fixed area about the need to resize the contents of the ! * gui.formwin, which we use for random positioning of the included ! * components. ! * ! * We connect this signal deferred finally after anything is in place, ! * since this is intended to handle resizements coming from the window ! * manager upon us and should not interfere with what VIM is requesting ! * upon startup. ! */ ! gtk_signal_connect(GTK_OBJECT(gui.formwin), "configure_event", ! GTK_SIGNAL_FUNC(form_configure_event), NULL); ! gtk_widget_show(gui.mainwin); ! return OK; } ! /*ARGSUSED*/ ! void ! gui_mch_exit(int rc) { ! gtk_exit(0); } /* ! * Get the position of the top left corner of the window. */ int ! gui_mch_get_winpos(int *x, int *y) { ! /* For some people this must be gdk_window_get_origin() for a correct ! * result. Where is the documentation! */ ! #ifdef GTK_HAVE_FEATURES_1_1_4 ! gdk_window_get_root_origin(gui.mainwin->window, x, y); ! #else ! gdk_window_get_origin(gui.mainwin->window, x, y); ! #endif ! return OK; ! } ! /* ! * Set the position of the top left corner of the window to the given ! * coordinates. ! */ ! void ! gui_mch_set_winpos(int x, int y) ! { ! gdk_window_move(gui.mainwin->window, x, y); ! } ! /* ! * Set the windows size. ! */ ! /*ARGSUSED*/ ! void ! gui_mch_set_winsize(int width, int height, ! int min_width, int min_height, ! int base_width, int base_height) ! { ! gtk_form_set_size(GTK_FORM(gui.formwin), width, height); ! /* give GTK+ a chance to put all widget's into place */ ! gui_mch_update(); ! /* this will cause the proper resizement to happen too */ ! update_window_manager_hints(); ! } - /* - * The screen size is used to make sure the initial window doesn't get bigger - * then the screen. This subtracts some room for menubar, toolbar and window - * decoreations. - */ - void - gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) - { - *screen_w = gdk_screen_width(); - /* Subtract 'guihearroom' from the height to allow some room for the - * window manager (task list and window title bar). */ - *screen_h = gdk_screen_height() - p_ghr; ! /* ! * FIXME: dirty trick: Because the gui_get_base_height() doesn't include ! * the toolbar and menubar for GTK, we subtract them from the screen ! * hight, so that the window size can be made to fit on the screen. ! * This should be completely changed later. ! */ ! #ifdef USE_TOOLBAR ! if (gui.toolbar && GTK_WIDGET_REALIZED(gui.toolbar) ! && GTK_WIDGET_VISIBLE(gui.toolbar)) ! *screen_h -= gui.toolbar->allocation.height; ! #endif ! #ifdef WANT_MENU ! if (gui.menubar && GTK_WIDGET_REALIZED(gui.menubar) ! && GTK_WIDGET_VISIBLE(gui.menubar)) ! *screen_h -= gui.menubar->allocation.height; #endif - } ! #if defined(WANT_MENU) || defined(PROTO) ! void ! gui_mch_enable_menu(int flag) ! { ! if (flag) ! gtk_widget_show(gui.menubar); ! else ! gtk_widget_hide(gui.menubar); ! update_window_manager_hints(); ! } #endif ! ! #if defined(USE_TOOLBAR) || defined(PROTO) ! void ! gui_mch_show_toolbar(int showit) ! { ! if (gui.toolbar == NULL) ! return; ! ! if (!showit) { ! if (GTK_WIDGET_VISIBLE(gui.toolbar)) { ! gtk_widget_hide(gui.toolbar); ! /* wait util this gets done on the server side. */ ! update_window_manager_hints(); ! } ! } else { ! g_assert(p_toolbar != NULL); if (strstr((const char *)p_toolbar, "text") ! && strstr((const char *)p_toolbar, "icons")) { ! gtk_toolbar_set_style(GTK_TOOLBAR(gui.toolbar), GTK_TOOLBAR_BOTH); ! } else if (strstr((const char *)p_toolbar, "text")) { ! gtk_toolbar_set_style(GTK_TOOLBAR(gui.toolbar), GTK_TOOLBAR_TEXT); ! } else if (strstr((const char *)p_toolbar, "icons")) { ! gtk_toolbar_set_style(GTK_TOOLBAR(gui.toolbar), GTK_TOOLBAR_ICONS); ! } ! ! if (strstr((const char *)p_toolbar, "tooltips")) ! gtk_toolbar_set_tooltips(GTK_TOOLBAR(gui.toolbar), TRUE); else ! gtk_toolbar_set_tooltips(GTK_TOOLBAR(gui.toolbar), FALSE); ! /* ! * Black on white will catch the attention of the user more likely then ! * black on grey. However due to errors / omissions in GTK+-1.1.5 this ! * ceased to work properly. I had been looking after it and there seems ! * to be no easy fix for it there. (--mdcki) ! * ! * This problem still applies for GTK+-1.2.3. (--mdcki) ! * And I didn't find any current example where the tooltip colors ! * would have need changed correctly. ! */ ! gtk_tooltips_set_colors(GTK_TOOLBAR(gui.toolbar)->tooltips, ! &gui.toolbar->style->white, ! &gui.toolbar->style->black); ! if (!GTK_WIDGET_VISIBLE(gui.toolbar)) { ! gtk_widget_show(gui.toolbar); ! update_window_manager_hints(); ! } ! } ! } #endif ! #ifdef USE_FONTSET ! static GuiFont ! gui_mch_get_fontset(char_u * name, int report_error) ! { ! GdkFont *font; ! if (!gui.in_use || name == NULL) ! return (GuiFont) 0; ! font = gdk_fontset_load((gchar *) name); ! if (font == NULL) { ! if (report_error) ! EMSG2("Unknown fontset: %s", name); ! return (GuiFont) 0; } ! /* reference this font as beeing in use */ ! gdk_font_ref(font); ! return (GuiFont) font; ! } #endif ! /* ! * Initialise vim to use the font with the given name. ! * Return FAIL if the font could not be loaded, OK otherwise. ! */ ! int ! gui_mch_init_font(char_u * font_name) ! { ! GdkFont *font = NULL; ! char *chunk[28], *sdup, *tmp; ! int len, i; ! ! #ifdef USE_FONTSET ! { ! static char_u *dflt_fontset = NULL; ! ! if (gui.fontset) ! { ! /* If fontset is active, VIM treat all the font as a fontset. */ ! if (font_name == NULL || vim_strchr(font_name, ',') == NULL) ! font_name = dflt_fontset; ! font = gui_mch_get_fontset(font_name, FALSE); ! if (font == NULL) ! return FAIL; ! } ! else if (font_name == NULL && *p_guifontset) ! { ! font = gui_mch_get_fontset(p_guifontset, FALSE); ! if (font) ! { ! font_name = p_guifontset; ! dflt_fontset = alloc(STRLEN(p_guifontset) + 1); ! STRCPY(dflt_fontset, p_guifontset); ! } ! } } ! if (font == NULL) ! #endif ! { ! /* ! * If none of the fonts in 'font' could be loaded, try the default, ! * which should be present on all X11 servers. ! */ ! if (font_name == NULL) ! font_name = (char_u *) DFLT_FONT; ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! if (STRCMP(font_name, "*") == 0) { ! /* ! * Request for a font handling dialog. ! * Not quite sure we should handle this here... ! */ ! /* ! * NOTE about font selection widget: this can easily be backported ! * to gtk-1.0.x. ! */ ! if (!gui.fontdlg) ! { ! GtkFontSelectionDialog *fsd = NULL; ! gui.fontdlg = gtk_font_selection_dialog_new("Font Selection"); ! fsd = GTK_FONT_SELECTION_DIALOG(gui.fontdlg); ! if (p_guifont != NULL) ! gtk_font_selection_dialog_set_font_name(fsd, ! (char *)p_guifont); ! # ifdef GTK_HAVE_FEATURES_1_1_4 ! gtk_window_set_modal(GTK_WINDOW(gui.fontdlg), TRUE); ! gtk_window_set_transient_for(GTK_WINDOW(gui.fontdlg), ! GTK_WINDOW(gui.mainwin)); ! # endif ! gtk_signal_connect(GTK_OBJECT(gui.fontdlg), "destroy", ! GTK_SIGNAL_FUNC(font_sel_destroy), &gui); ! gtk_signal_connect(GTK_OBJECT(fsd->ok_button), "clicked", ! GTK_SIGNAL_FUNC(font_sel_ok), &gui); ! gtk_signal_connect(GTK_OBJECT(fsd->cancel_button), "clicked", ! GTK_SIGNAL_FUNC(font_sel_cancel), &gui); ! } ! if (gui.fontname) ! { ! g_free(gui.fontname); ! gui.fontname = NULL; ! } ! gtk_window_position(GTK_WINDOW(gui.fontdlg), GTK_WIN_POS_MOUSE); ! gtk_widget_show(gui.fontdlg); ! # ifdef GTK_HAVE_FEATURES_1_1_4 ! { ! static gchar *spacings[] = {"c", "m", NULL}; ! /* In GTK 1.2.3 this must be after the gtk_widget_show() call, ! * otherwise everything is blocked for ten seconds. */ ! gtk_font_selection_dialog_set_filter( ! GTK_FONT_SELECTION_DIALOG(gui.fontdlg), ! GTK_FONT_FILTER_BASE, ! GTK_FONT_ALL, NULL, NULL, ! NULL, NULL, spacings, NULL); ! } ! # endif ! while (gui.fontdlg && GTK_WIDGET_VISIBLE(gui.fontdlg)) ! gtk_main_iteration_do(TRUE); ! if (gui.fontname == NULL) ! return FAIL; ! vim_free(p_guifont); ! p_guifont = vim_strsave(gui.fontname); ! font_name = p_guifont; ! } ! #endif ! if (font == NULL) ! font = gui_mch_get_font(font_name, FALSE); - if (font == NULL) - return FAIL; - } ! if (gui.norm_font != 0) ! gdk_font_unref(font); ! gui.norm_font = font; ! #ifdef USE_FONTSET ! if (font->type == GDK_FONT_FONTSET) ! { ! gui.fontset = (GuiFont) font; ! gui.char_width = gdk_string_width(font, " "); } ! else #endif - { - gui.char_width = ((XFontStruct *) - GDK_FONT_XFONT(font))->max_bounds.width; - } ! gui.char_height = font->ascent + font->descent; ! gui.char_ascent = font->ascent; ! /* Set the fontname, which will be used for information purposes */ ! hl_set_font_name(font_name); ! if (font->type != GDK_FONT_FONTSET) ! { ! /* There is only one excuse I can give for the following attempt ! * to manage font styles: ! * ! * I HATE THE BRAIN DEAD WAY X11 IS HANDLING FONTS (--mdcki) ! */ ! if ((sdup = g_strdup((const char *)font_name)) == NULL) ! return FAIL; ! /* slipt up the whole */ ! i = 0; ! for (tmp = sdup; *tmp != '\0'; ++tmp) ! if (*tmp == '-') ! { ! *tmp = '\0'; ! chunk[i] = tmp + 1; ! ++i; ! } ! g_free(sdup); ! if (i == 14) ! { ! char *bold_name = NULL; ! char *ital_name = NULL; ! char *italbold_name = NULL; ! /* font name was compleate */ ! len = strlen((const char *)font_name) + 32; ! bold_name = (char *)alloc(len); ! ital_name = (char *)alloc(len); ! italbold_name = (char *)alloc(len); ! if (bold_name == NULL || ital_name == NULL || italbold_name == NULL) ! { ! vim_free(bold_name); ! vim_free(ital_name); ! vim_free(italbold_name); ! return FAIL; ! } ! *bold_name = '\0'; ! *ital_name = '\0'; ! *italbold_name = '\0'; ! for (i = 0; i < 14; ++i) ! { ! strcat(bold_name, "-"); ! strcat(ital_name, "-"); ! strcat(italbold_name, "-"); ! strcat(bold_name, (i != 2) ? chunk[i] : "bold"); ! strcat(ital_name, (i != 3) ? chunk[i] : "o"); ! if (i != 2 && i != 3) ! strcat(italbold_name, chunk[i]); ! else ! { ! if (i == 2) ! strcat(italbold_name, "bold"); ! else if (i == 3) ! strcat(italbold_name, "o"); ! } ! } ! font = gui_mch_get_font((char_u *)bold_name, FALSE); ! if (font != NULL) ! gui.bold_font = font; ! else if (gui.bold_font) ! { ! gdk_font_unref(gui.bold_font); ! gui.bold_font = NULL; ! } ! font = gui_mch_get_font((char_u *)ital_name, FALSE); ! if (font != NULL) ! gui.ital_font = font; ! else if (gui.ital_font) ! { ! gdk_font_unref(gui.ital_font); ! gui.ital_font = NULL; ! } ! font = gui_mch_get_font((char_u *)italbold_name, FALSE); ! if (font != NULL) ! gui.boldital_font = font; ! else if (gui.boldital_font) ! { ! gdk_font_unref(gui.boldital_font); ! gui.boldital_font = NULL; ! } - vim_free(bold_name); - vim_free(ital_name); - vim_free(italbold_name); - } - } ! /* Synchronize the fonts used in user input dialogs, since otherwise ! * search/replace will be esp annoyig in case of international font usage. ! */ ! gui_gtk_synch_fonts(); ! #ifdef USE_XIM ! /* Adjust input management behaviour to the capabilities of the new ! * fontset */ ! xim_decide_input_style(); ! if (xim_get_status_area_height()) ! { ! /* Status area is required. Just create the empty label so that ! * mainwin will allocate the extra space for status area. */ ! GtkWidget *label = gtk_label_new(" "); ! gtk_widget_set_usize(label, 20, gui.char_height + 2); ! gtk_box_pack_end(GTK_BOX(GTK_BIN(gui.mainwin)->child), label, ! FALSE, FALSE, 0); ! gtk_widget_show(label); } - #endif ! /* Preserve the logical dimensions of the screen. */ update_window_manager_hints(); ! return OK; ! } ! GuiFont ! gui_mch_get_font(char_u * name, int report_error) ! { ! GdkFont *font; ! if (!gui.in_use || name == NULL) /* can't do this when GUI not running */ ! return (GuiFont) 0; ! #ifdef USE_FONTSET ! if (gui.fontset) ! /* If fontset is active, VIM treat all the font as a fontset */ ! return gui_mch_get_fontset(name, report_error); ! else if (vim_strchr(name, ',')) ! return (GuiFont)0; #endif ! font = gdk_font_load((const gchar *) name); ! if (font == NULL) { ! if (report_error) ! EMSG2("Unknown font: %s", name); ! return (GuiFont) 0; ! } ! /* reference this font as beeing in use */ ! gdk_font_ref(font); ! if (((XFontStruct *) GDK_FONT_XFONT(font))->max_bounds.width ! != ((XFontStruct *) GDK_FONT_XFONT(font))->min_bounds.width) { ! EMSG2("Font \"%s\" is not fixed-width", name); ! gdk_font_unref(font); ! return (GuiFont) 0; ! } ! return (GuiFont) font; } ! /* ! * Set the current text font. ! * Since we create all GC on demand, we use just gui.current_font to ! * indicate the desired current font. ! */ void ! gui_mch_set_font(GuiFont font) { ! gui.current_font = font; } - #if 0 /* not used */ /* ! * Return TRUE if the two fonts given are equivalent. */ int ! gui_mch_same_font(GuiFont f1, GuiFont f2) { ! return gdk_font_equal((GdkFont *) f1, (GdkFont *) f2); ! } #endif /* ! * If a font is not going to be used, free its structure. */ void ! gui_mch_free_font(GuiFont font) { ! if (font) ! gdk_font_unref((GdkFont *) font); } - /* ! * Return the Pixel value (color) for the given color name. This routine was ! * pretty much taken from example code in the Silicon Graphics OSF/Motif ! * Programmer's Guide. ! * Return -1 for error. */ ! GuiColor ! gui_mch_get_color(char_u * name) { ! int i; ! static char *(vimnames[][2]) = ! { ! /* A number of colors that some X11 systems don't have */ ! {"LightRed", "#FFA0A0"}, ! {"LightGreen", "#80FF80"}, ! {"LightMagenta", "#FFA0FF"}, ! {"DarkCyan", "#008080"}, ! {"DarkBlue", "#0000C0"}, ! {"DarkRed", "#C00000"}, ! {"DarkMagenta", "#C000C0"}, ! {"DarkGrey", "#C0C0C0"}, ! {NULL, NULL} ! }; ! ! if (!gui.in_use) /* can't do this when GUI not running */ ! return (GuiColor)(-1); ! ! while (name != NULL) { ! GdkColor color; ! ! if (gdk_color_parse((const gchar *)name, &color)) { ! GdkColormap *colormap; ! colormap = gtk_widget_get_colormap(gui.drawarea); ! gdk_color_alloc(colormap, &color); ! return (GuiColor) color.pixel; ! } ! /* add a few builtin names */ ! for (i = 0;; ++i) { ! if (vimnames[i][0] == NULL) { ! name = NULL; ! break; ! } ! if (STRICMP(name, vimnames[i][0]) == 0) { ! name = (char_u *) vimnames[i][1]; ! break; ! } ! } ! } ! return (GuiColor)(-1); } - /* - * Set the current text foreground color. - */ - void - gui_mch_set_fg_color(GuiColor color) - { - gui.fgcolor->pixel = (Pixel) color; - } /* ! * Set the current text background color. */ void ! gui_mch_set_bg_color(GuiColor color) { ! gui.bgcolor->pixel = (Pixel) color; } ! /* ! * Use the blank mouse pointer or not. ! * ! * hide: TRUE = use blank ptr, FALSE = use parent ptr ! */ void ! gui_mch_mousehide(int hide) { ! if (gui.pointer_hidden != hide) { ! if (gui.drawarea->window && gui.blank_pointer) { ! if (hide) ! gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer); ! else ! gdk_window_set_cursor(gui.drawarea->window, NULL); ! } ! gui.pointer_hidden = hide; ! } } void ! gui_mch_draw_string(int row, int col, char_u * s, int len, int flags) { ! GdkGC *gc; ! ! if (gui.current_font == NULL || gui.drawarea->window == NULL) return; ! #if defined(USE_FONTSET) && defined(MULTI_BYTE) ! if (gui.fontset) ! { ! if (col > 0 && mb_isbyte1(LinePointers[row], col - 1)) ! { ! col++; ! len--; ! s++; } - if (len == 1 && IsLeadByte(*s)) - len = 2; - } - #endif ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! ! if (flags & DRAW_TRANSP) { ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_draw_text(gui.drawarea->window, ! gui.current_font, ! gc, ! TEXT_X(col), TEXT_Y(row), ! (const gchar *)s, len); ! } else { ! int width; ! int height; ! width = gdk_text_width(gui.current_font, (const gchar *)s, len); ! height = gui.char_height; ! ! gdk_gc_set_foreground(gc, gui.bgcolor); ! gdk_draw_rectangle(gui.drawarea->window, ! gc, ! TRUE, ! FILL_X(col), FILL_Y(row), width, height); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_draw_text(gui.drawarea->window, ! gui.current_font, ! gc, ! TEXT_X(col), TEXT_Y(row), ! (const gchar *)s, len); ! } ! ! /* redraw the contents with an offset of 1 to emulate bold */ ! if (flags & DRAW_BOLD) { ! gdk_draw_text(gui.drawarea->window, ! gui.current_font, ! gc, ! TEXT_X(col) + 1, TEXT_Y(row), ! (const gchar *)s, len); ! } ! ! if (flags & DRAW_UNDERL) { ! gdk_draw_line(gui.drawarea->window, ! gc, FILL_X(col), ! FILL_Y(row + 1) - 1, FILL_X(col + len) - 1, FILL_Y(row + 1) - 1); ! } ! gdk_gc_destroy(gc); ! } ! ! /* ! * Return OK if the key with the termcap name "name" is supported. ! */ ! int ! gui_mch_haskey(char_u * name) ! { ! int i; ! ! for (i = 0; special_keys[i].key_sym != 0; i++) ! if (name[0] == special_keys[i].code0 && ! name[1] == special_keys[i].code1) ! return OK; ! return FAIL; ! } ! #if defined(WANT_TITLE) || defined(PROTO) ! /* ! * Return the text window-id and display. Only required for X-based GUI's ! */ ! int ! gui_get_x11_windis(Window * win, Display ** dis) ! { ! /* ! * This is currently only used by the code which is handling the ! * window manager title of this program. ! */ ! *dis = GDK_DISPLAY(); ! if (gui.mainwin->window) { ! *win = GDK_WINDOW_XWINDOW(gui.mainwin->window); ! return OK; } - *win = 0; - return FAIL; } #endif - void - gui_mch_beep() - { - gdk_beep(); - } ! void ! gui_mch_flash() { ! GdkGCValues values; ! GdkGC *invert_gc; ! GdkColor foreground; ! GdkColor background; ! ! if (gui.drawarea->window == NULL) ! return; ! foreground.pixel = gui.norm_pixel ^ gui.back_pixel; ! background.pixel = gui.norm_pixel ^ gui.back_pixel; ! values.foreground = foreground; ! values.background = background; ! values.function = GDK_XOR; ! invert_gc = gdk_gc_new_with_values(gui.drawarea->window, ! &values, ! GDK_GC_FOREGROUND | ! GDK_GC_BACKGROUND | ! GDK_GC_FUNCTION); ! gdk_gc_set_exposures(invert_gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! /* Do a visual beep by changing back and forth in some undetermined way, ! * the foreground and background colors. This is due to the fact that ! * there can't be really any prediction about the effects of XOR on ! * arbitrary X11 servers. However this seems to be enought for what we ! * intend it to do. ! */ ! gdk_draw_rectangle(gui.drawarea->window, invert_gc, ! TRUE, ! 0, 0, ! FILL_X((int) Columns) + gui.border_offset, ! FILL_Y((int) Rows) + gui.border_offset); ! gdk_flush(); ! ui_delay(20L, TRUE); /* wait 1/50 of a second */ ! gdk_draw_rectangle(gui.drawarea->window, invert_gc, ! TRUE, ! 0, 0, ! FILL_X((int) Columns) + gui.border_offset, ! FILL_Y((int) Rows) + gui.border_offset); ! gdk_gc_destroy(invert_gc); } /* ! * Invert a rectangle from row r, column c, for nr rows and nc columns. */ ! void ! gui_mch_invert_rectangle(int r, int c, int nr, int nc) { ! GdkGCValues values; ! GdkGC *invert_gc; ! GdkColor foreground; ! GdkColor background; ! if (gui.drawarea->window == NULL) ! return; ! foreground.pixel = gui.norm_pixel ^ gui.back_pixel; ! background.pixel = gui.norm_pixel ^ gui.back_pixel; ! values.foreground = foreground; ! values.background = background; ! values.function = GDK_XOR; ! invert_gc = gdk_gc_new_with_values(gui.drawarea->window, ! &values, ! GDK_GC_FOREGROUND | ! GDK_GC_BACKGROUND | ! GDK_GC_FUNCTION); ! gdk_gc_set_exposures(invert_gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_draw_rectangle(gui.drawarea->window, invert_gc, ! TRUE, ! FILL_X(c), FILL_Y(r), ! (nc) * gui.char_width, (nr) * gui.char_height); ! gdk_gc_destroy(invert_gc); } ! /* ! * Iconify the GUI window. ! */ ! void ! gui_mch_iconify() { ! XIconifyWindow(GDK_DISPLAY(), ! GDK_WINDOW_XWINDOW(gui.mainwin->window), ! DefaultScreen(GDK_DISPLAY())); } /* ! * Draw a cursor without focus. */ ! void ! gui_mch_draw_hollow_cursor(GuiColor color) { ! GdkGC *gc; ! if (gui.drawarea->window == NULL) ! return; ! gui_mch_set_fg_color(color); ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! #if defined(USE_FONTSET) && defined(MULTI_BYTE) ! if (gui.fontset) { ! if (IsLeadByte(LinePointers[gui.row][gui.col]) ! # ifdef HANGUL_INPUT ! || composing_hangul # endif ! ) ! gdk_draw_rectangle(gui.drawarea->window, gc, ! FALSE, ! FILL_X(gui.col), FILL_Y(gui.row), ! 2*gui.char_width - 1, gui.char_height - 1); ! else ! gdk_draw_rectangle(gui.drawarea->window, gc, ! FALSE, ! FILL_X(gui.col), FILL_Y(gui.row), ! gui.char_width - 1, gui.char_height - 1); } else #endif ! gdk_draw_rectangle(gui.drawarea->window, gc, ! FALSE, ! FILL_X(gui.col), FILL_Y(gui.row), ! gui.char_width - 1, gui.char_height - 1); ! gdk_gc_destroy(gc); ! } ! /* ! * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using ! * color "color". ! */ ! void ! gui_mch_draw_part_cursor(int w, int h, GuiColor color) ! { ! GdkGC *gc; ! if (gui.drawarea->window == NULL) ! return; ! gui_mch_set_fg_color(color); ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_draw_rectangle(gui.drawarea->window, gc, ! TRUE, ! #ifdef RIGHTLEFT ! /* vertical line should be on the right of current point */ ! State != CMDLINE && curwin->w_p_rl ? FILL_X(gui.col + 1) - w : ! #endif ! FILL_X(gui.col), ! FILL_Y(gui.row) + gui.char_height - h, ! w, h); ! gdk_gc_destroy(gc); ! } ! #ifndef GTK_HAVE_FEATURES_1_1_0 ! static gint ! idle_function(GtkWidget * label) ! { ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! return FALSE; } - #endif ! /* ! * Catch up with any queued X11 events. This may put keyboard input into the ! * input buffer, call resize call-backs, trigger timers etc. If there is ! * nothing in the X11 event queue (& no timers pending), then we return ! * immediately. ! */ ! void ! gui_mch_update() { ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! while (gtk_events_pending() && !vim_is_input_buf_full()) ! gtk_main_iteration_do(FALSE); ! #else ! int pending; ! /* Somehow the above loop hangs on GTK 1.0.6. Use the idle_function() to ! * work around this weird problem. */ ! while (((pending = gtk_events_pending()) > 1) && !vim_is_input_buf_full()) ! gtk_main_iteration(); ! if ((pending == 1) && !vim_is_input_buf_full()) { ! gtk_idle_add((GtkFunction)idle_function, gui.mainwin); ! gtk_main_iteration_do(FALSE); ! } #endif - } ! static gint ! input_timer_cb(gpointer data) ! { ! int *timed_out = (int *) data; ! /* Just inform the caller about the accurence of it */ ! *timed_out = TRUE; ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! return FALSE; /* don't happen again */ } /* ! * GUI input routine called by gui_wait_for_chars(). Waits for a character ! * from the keyboard. ! * wtime == -1 Wait forever. ! * wtime == 0 This should never happen. ! * wtime > 0 Wait wtime milliseconds for a character. ! * Returns OK if a character was found to be available within the given time, ! * or FAIL otherwise. */ ! int ! gui_mch_wait_for_chars(long wtime) { ! int focus; ! guint timer; ! ! static int timed_out; ! ! timed_out = FALSE; ! ! /* this timeout makes sure that we will return if no characters arrived in ! * time */ ! ! if (wtime > 0) ! timer = gtk_timeout_add(wtime, input_timer_cb, &timed_out); ! else ! timer = 0; ! ! focus = gui.in_focus; ! ! do { ! /* Stop or start blinking when focus changes */ ! if (gui.in_focus != focus) { ! if (gui.in_focus) ! gui_mch_start_blink(); ! else ! gui_mch_stop_blink(); ! focus = gui.in_focus; ! } ! ! /* ! * Loop in GTK+ processing until a timeout or input occurs. ! */ ! gtk_main(); ! ! /* Got char, return immediately */ ! if (!vim_is_input_buf_empty()) { ! if (timer != 0 && !timed_out) ! gtk_timeout_remove(timer); ! return OK; ! } ! } while (wtime < 0 || !timed_out); ! ! /* ! * Flush all eventually pending (drawing) events. ! */ ! gui_mch_update(); ! ! return FAIL; } ! ! /**************************************************************************** ! * Output drawing routines. ! ****************************************************************************/ ! ! ! /* Flush any output to the screen */ ! void ! gui_mch_flush() { ! gdk_flush(); } /* ! * Clear a rectangular region of the screen from text pos (row1, col1) to ! * (row2, col2) inclusive. */ void ! gui_mch_clear_block(int row1, int col1, int row2, int col2) { ! GdkGC *gc; ! GdkColor color; - if (gui.drawarea->window == NULL) - return; ! color.pixel = gui.back_pixel; ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, &color); ! /* ! * Clear one extra pixel at the right, for when bold characters have ! * spilled over to the next column. This can erase part of the next ! * character however in the usage context of this function it will be ! * overriden immediately by the correct character again. ! */ ! gdk_draw_rectangle(gui.drawarea->window, gc, TRUE, ! FILL_X(col1), FILL_Y(row1), ! (col2 - col1 + 1) * gui.char_width + 1, ! (row2 - row1 + 1) * gui.char_height); ! gdk_gc_destroy(gc); ! } ! void ! gui_mch_clear_all(void) ! { ! if (gui.drawarea->window == NULL) ! return; ! gdk_window_clear(gui.drawarea->window); } /* ! * Scroll the text between gui.scroll_region_top & gui.scroll_region_bot by the ! * number of lines given. Positive scrolls down (text goes up) and negative ! * scrolls up (text goes down). */ ! static void check_copy_area(void) { ! XEvent event; ! XGraphicsExposeEvent *gevent; ! ! if (gui.visibility != GDK_VISIBILITY_PARTIAL) ! return; ! ! gdk_flush(); ! ! /* Wait to check whether the scroll worked or not */ ! for (;;) { ! if (XCheckTypedEvent(GDK_DISPLAY(), NoExpose, &event)) ! return; /* The scroll worked. */ ! if (XCheckTypedEvent(GDK_DISPLAY(), GraphicsExpose, &event)) { ! gevent = (XGraphicsExposeEvent *) & event; ! gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height); ! if (gevent->count == 0) ! return; /* This was the last expose event */ ! } ! gdk_flush(); ! } } /* ! * Delete the given number of lines from the given row, scrolling up any ! * text further down within the scroll region. */ void ! gui_mch_delete_lines(int row, int num_lines) { ! if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED) ! return; /* Can't see the window */ ! ! if (num_lines <= 0) ! return; ! ! if (row + num_lines > gui.scroll_region_bot) { ! /* Scrolled out of region, just blank the lines out */ ! gui_clear_block(row, 0, gui.scroll_region_bot, (int) Columns - 1); ! } else { ! GdkGC *gc; ! ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_gc_set_background(gc, gui.bgcolor); ! ! /* copy one extra pixel, for when bold has spilled over */ ! gdk_window_copy_area(gui.drawarea->window, gc, ! FILL_X(0), FILL_Y(row), ! gui.drawarea->window, ! FILL_X(0), FILL_Y(row + num_lines), ! gui.char_width * (int) Columns + 1, ! gui.char_height * ! (gui.scroll_region_bot - row - num_lines + 1)); ! gdk_gc_destroy(gc); ! ! /* Update gui.cursor_row if the cursor scrolled or copied over */ ! if (gui.cursor_row >= row) { ! if (gui.cursor_row < row + num_lines) ! gui.cursor_is_valid = FALSE; ! else if (gui.cursor_row <= gui.scroll_region_bot) ! gui.cursor_row -= num_lines; } ! gui_clear_block(gui.scroll_region_bot - num_lines + 1, 0, ! gui.scroll_region_bot, (int) Columns - 1); ! check_copy_area(); } } - /* - * Insert the given number of lines before the given row, scrolling down any - * following text within the scroll region. - */ void ! gui_mch_insert_lines(int row, int num_lines) { ! if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED) ! return; /* Can't see the window */ ! if (num_lines <= 0) return; ! if (row + num_lines > gui.scroll_region_bot) { ! /* Scrolled out of region, just blank the lines out */ ! gui_clear_block(row, 0, gui.scroll_region_bot, (int) Columns - 1); } else { ! GdkGC *gc; ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_gc_set_background(gc, gui.bgcolor); ! /* copy one extra pixel, for when bold has spilled over */ ! gdk_window_copy_area(gui.drawarea->window, gc, ! FILL_X(0), FILL_Y(row + num_lines), ! gui.drawarea->window, ! FILL_X(0), FILL_Y(row), ! gui.char_width * (int) Columns + 1, ! gui.char_height * ! (gui.scroll_region_bot - row - num_lines + 1)); ! gdk_gc_destroy(gc); ! /* Update gui.cursor_row if the cursor scrolled or copied over */ ! if (gui.cursor_row >= gui.row) { ! if (gui.cursor_row <= gui.scroll_region_bot - num_lines) ! gui.cursor_row += num_lines; ! else if (gui.cursor_row <= gui.scroll_region_bot) ! gui.cursor_is_valid = FALSE; ! } ! gui_clear_block(row, 0, row + num_lines - 1, (int) Columns - 1); ! check_copy_area(); } } /* ! * X Selection stuff, for cutting and pasting text to other windows. */ ! void ! clip_mch_request_selection() { ! /* First try to get the content of our own special clipboard. */ ! received_selection = RS_NONE; ! (void)gtk_selection_convert(gui.drawarea, ! GDK_SELECTION_PRIMARY, clipboard.atom, ! GDK_CURRENT_TIME); ! while (received_selection == RS_NONE) ! gtk_main(); /* wait for selection_received_event */ ! if (received_selection == RS_FAIL) ! { ! /* Now try to get it out of the usual string selection. */ ! received_selection = RS_NONE; ! (void)gtk_selection_convert(gui.drawarea, GDK_SELECTION_PRIMARY, ! GDK_TARGET_STRING, ! GDK_CURRENT_TIME); ! while (received_selection == RS_NONE) ! gtk_main(); /* wait for selection_received_event */ } } void ! clip_mch_lose_selection() { ! gtk_selection_owner_set(gui.drawarea, ! GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); ! gui_mch_update(); } /* ! * Check whatever we allready own the selection */ ! int ! clip_mch_own_selection() { ! #if 0 ! return gdk_selection_owner_get( ! GDK_SELECTION_PRIMARY) == gui.drawarea->window; ! #else ! /* At this point we always already own the clipboard */ ! return OK; ! #endif } /* ! * Send the current selection to the clipboard. */ void ! clip_mch_set_selection() { ! gtk_selection_owner_set(gui.drawarea, ! GDK_SELECTION_PRIMARY, ! GDK_CURRENT_TIME); ! gui_mch_update(); } - - #if defined(WANT_MENU) || defined(PROTO) /* ! * Make a menu item appear either active or not active (grey or not grey). */ void ! gui_mch_menu_grey(VimMenu * menu, int grey) { ! if (menu->id == 0) return; ! gui_mch_menu_hidden(menu, FALSE); ! gtk_widget_set_sensitive(menu->id, !grey); ! gui_mch_update(); } /* ! * Make menu item hidden or not hidden. */ void ! gui_mch_menu_hidden(VimMenu * menu, int hidden) { ! if (menu->id == 0) return; ! if (hidden) { ! if (GTK_WIDGET_VISIBLE(menu->id)) ! gtk_widget_hide(menu->id); ! } else { ! if (!GTK_WIDGET_VISIBLE(menu->id)) ! gtk_widget_show(menu->id); ! } ! gui_mch_update(); } ! /* ! * This is called after setting all the menus to grey/hidden or not. ! */ ! void ! gui_mch_draw_menubar() { ! /* just make sure that the visual changes get effect immediately */ ! gui_mch_update(); } #endif /* ! * Scrollbar stuff. */ void ! gui_mch_enable_scrollbar(GuiScrollbar * sb, int flag) { ! if (sb->id == 0) ! return; ! if (flag) ! gtk_widget_show(sb->id); ! else ! gtk_widget_hide(sb->id); ! update_window_manager_hints(); } /* ! * Return the lightness of a pixel. White is 255. ! * ! * FIXME: port it compleatly to GDK. */ int ! gui_mch_get_lightness(GuiColor pixel) { ! XColor xc; ! GdkColormap *colormap; ! colormap = gtk_widget_get_colormap(gui.mainwin); ! xc.pixel = pixel; ! XQueryColor(GDK_DISPLAY(), GDK_COLORMAP_XCOLORMAP(colormap), &xc); ! return (int) (xc.red * 3 + xc.green * 6 + xc.blue) / (10 * 256); } - #if (defined(SYNTAX_HL) && defined(WANT_EVAL)) || defined(PROTO) /* ! * Return the RGB value of a pixel as "#RRGGBB". ! * ! * FIXME: It should be possible to avoid any direct usage of Xlib. Use gdk ! * instead! */ ! char_u * ! gui_mch_get_rgb(GuiColor pixel) { ! XColor xc; ! GdkColormap *colormap; ! static char_u retval[10]; ! static int prevent_congestion = 0; /* Reduce the race! */ ! while (prevent_congestion) ! /* shouldn't we do something here? */; ! ++prevent_congestion; ! colormap = gtk_widget_get_colormap(gui.mainwin); ! xc.pixel = pixel; ! XQueryColor(GDK_DISPLAY(), GDK_COLORMAP_XCOLORMAP(colormap), &xc); ! sprintf((char *) retval, "#%02x%02x%02x", ! (unsigned) xc.red >> 8, ! (unsigned) xc.green >> 8, ! (unsigned) xc.blue >> 8); ! /* hope the following is atomic enought (99.999%) */ ! --prevent_congestion; ! /* WOAH!!! Returning pointer to static string! */ ! return retval; } - #endif /* ! * Get current y mouse coordinate in text window. ! * Return -1 when unknown. */ ! int ! gui_mch_get_mouse_x(void) { ! int winx, winy; ! GdkModifierType mask; ! if (gdk_window_get_pointer(gui.drawarea->window, &winx, &winy, &mask)) { ! if (gui.which_scrollbars[SBAR_LEFT]) ! return winx; ! return winx; ! } ! return -1; ! } ! int ! gui_mch_get_mouse_y(void) ! { ! int winx, winy; ! GdkModifierType mask; ! if (gdk_window_get_pointer(gui.drawarea->window, &winx, &winy, &mask)) ! return winy; ! return -1; } void ! gui_mch_setmouse(int x, int y) { ! /* Sorry for that, but we can't avoid it, since there seems to be ! no internal GDK mechanism present to accomplish this */ ! XWarpPointer(GDK_DISPLAY(), (Window) 0, ! GDK_WINDOW_XWINDOW(gui.drawarea->window), 0, 0, 0, 0, x, y); ! } ! /*** private function defintions ***/ ! /* redraw the corresponding portions of the screen */ ! /*ARGSUSED*/ ! static gint ! expose_event(GtkWidget * widget, GdkEventExpose * event) ! { ! out_flush(); /* make sure all output has been processed */ ! gui_redraw(event->area.x, event->area.y, ! event->area.width, event->area.height); ! /* Clear the border areas if needed */ ! if (event->area.x < FILL_X(0)) ! gdk_window_clear_area(gui.drawarea->window, 0, 0, FILL_X(0), 0); ! if (event->area.y < FILL_Y(0)) ! gdk_window_clear_area(gui.drawarea->window, 0, 0, 0, FILL_Y(0)); ! if (event->area.x > FILL_X(Columns)) ! gdk_window_clear_area(gui.drawarea->window, ! FILL_X((int)Columns), 0, 0, 0); ! if (event->area.y > FILL_Y(Rows)) ! gdk_window_clear_area(gui.drawarea->window, 0, FILL_Y((int)Rows), 0, 0); ! return FALSE; } - static guint mouse_click_timer = 0; - static int mouse_timed_out = TRUE; - /* ! * Timer used to recognize multiple clicks of the mouse button */ ! static gint ! mouse_click_timer_cb(gpointer data) { ! /* we don't use this information currently */ ! int *timed_out = (int *) data; ! ! *timed_out = TRUE; ! return FALSE; /* don't happen again */ ! } ! /* ! * Mouse button handling. Note please that we are capturing multiple click's by ! * our own timeout mechanis instead of the one provided by GTK+ istelf. This is ! * due to the way the generic VIM code is recognizing multiple clicks. ! */ ! /*ARGSUSED*/ ! static gint ! button_press_event(GtkWidget * widget, GdkEventButton * event) ! { ! int button; ! int repeated_click = FALSE; ! int x, y; ! int_u vim_modifiers; ! /* ! * Don't let additional events about multiple clicks send by GTK to us ! * after the inital button press event confuse us. ! */ ! if (event->type != GDK_BUTTON_PRESS) ! return FALSE; ! x = event->x; ! y = event->y; ! /* Handle multiple clicks */ ! if (!mouse_timed_out && mouse_click_timer) { ! gtk_timeout_remove(mouse_click_timer); ! mouse_click_timer = 0; ! repeated_click = TRUE; } ! mouse_timed_out = FALSE; ! mouse_click_timer = gtk_timeout_add(p_mouset, ! mouse_click_timer_cb, &mouse_timed_out); ! switch (event->button) { ! case 1: ! button = MOUSE_LEFT; ! break; ! case 2: ! button = MOUSE_MIDDLE; ! break; ! case 3: ! button = MOUSE_RIGHT; ! break; ! case 4: ! button = MOUSE_4; ! break; ! case 5: ! button = MOUSE_5; ! break; ! default: ! return FALSE; /* Unknown button */ } ! vim_modifiers = 0x0; ! if (event->state & GDK_SHIFT_MASK) ! vim_modifiers |= MOUSE_SHIFT; ! if (event->state & GDK_CONTROL_MASK) ! vim_modifiers |= MOUSE_CTRL; ! if (event->state & GDK_MOD1_MASK) ! vim_modifiers |= MOUSE_ALT; ! gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers); ! if (gtk_main_level() > 0) ! gtk_main_quit(); /* make sure the above will be handled immediately */ ! return TRUE; } - static guint motion_repeat_timer = 0; - /* ! * Timer used to recognize multiple clicks of the mouse button */ ! /*ARGSUSED*/ ! static gint ! motion_repeat_timer_cb(gpointer data) { ! gint x, y; ! GdkModifierType state; ! GdkEventMotion event; ! ! gdk_window_get_pointer(gui.drawarea->window, &x, &y, &state); ! ! if (!(state & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK))) ! return FALSE; ! ! /* Fake a motion event. */ ! event.is_hint = 0; ! event.x = x; ! event.y = y; ! event.state = state; - /* FIXME: argh! for some unknown reason this doesn't lead to nice - * autoscrolling and automatic extension of the selection area. However - * the autorepeating works nice already. We need certainly to investigate - * this further. - * - * BTW: It doesn't work properly in the motif version too. So maybe we need - * to look at how it's done in the Windows version again... - * - * I'm assuming that this is somehow related to the gui_mouse_moved - * stuff... - */ ! motion_notify_event(gui.drawarea, &event); ! /* Don't happen again. We will get reinstalled in the synthetic ! * event if needed - thus repeating should still work. ! */ ! return FALSE; } ! /*ARGSUSED*/ ! static gint ! button_release_event(GtkWidget * widget, GdkEventButton * event) { ! int x, y; ! int_u vim_modifiers; ! /* Remove any motion "mashine gun" timers used for automatic further ! extension of allocation areas if outside of the applications window ! area .*/ ! if (motion_repeat_timer) { ! gtk_timeout_remove(motion_repeat_timer); ! motion_repeat_timer = 0; } ! x = event->x; ! y = event->y; ! ! vim_modifiers = 0x0; ! if (event->state & GDK_SHIFT_MASK) ! vim_modifiers |= MOUSE_SHIFT; ! if (event->state & GDK_CONTROL_MASK) ! vim_modifiers |= MOUSE_CTRL; ! if (event->state & GDK_MOD1_MASK) ! vim_modifiers |= MOUSE_ALT; ! ! gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, vim_modifiers); ! if (gtk_main_level() > 0) ! gtk_main_quit(); /* make sure it will be handled immediately */ ! ! return TRUE; } ! ! /*ARGSUSED*/ ! static gint ! motion_notify_event(GtkWidget * widget, GdkEventMotion * event) { ! gint x, y; ! GdkModifierType state; ! int_u vim_modifiers; ! int button; ! ! if (event->is_hint) ! gdk_window_get_pointer(event->window, &x, &y, &state); ! else { ! x = event->x; ! y = event->y; ! state = event->state; ! } ! button = (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | ! GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | ! GDK_BUTTON5_MASK)) ! ? MOUSE_DRAG : ' '; ! ! /* If our pointer is currently hidden, then we should show it. */ ! gui_mch_mousehide(FALSE); ! ! /* Just moving the rodent above the drawing area without ! any button beeing pressed. */ ! if (button != MOUSE_DRAG) { ! gui_mouse_moved(y); ! return TRUE; ! } ! ! vim_modifiers = 0x0; ! if (state & GDK_SHIFT_MASK) ! vim_modifiers |= MOUSE_SHIFT; ! if (state & GDK_CONTROL_MASK) ! vim_modifiers |= MOUSE_CTRL; ! if (state & GDK_MOD1_MASK) ! vim_modifiers |= MOUSE_ALT; ! ! /* inform the editor egine about the occurence of this event */ ! gui_send_mouse_event(button, x, y, FALSE, vim_modifiers); ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! ! /* ! * Auto repeat timer handling. ! */ ! if (x < 0 || y < 0 ! || x >= gui.drawarea->allocation.width ! || y >= gui.drawarea->allocation.height) { ! ! /* just in case remove stale timers */ ! if (motion_repeat_timer) ! gtk_timeout_remove(motion_repeat_timer); ! /* shoot again */ ! motion_repeat_timer = gtk_timeout_add(100, ! motion_repeat_timer_cb, NULL); ! } ! ! return TRUE; /* handled */ } /* ! * Callback routine for the "delete_event" signal on the toplevel window. ! * Tries to vim gracefully, or refuses to exit with changed buffers. */ ! /*ARGSUSED*/ ! static int ! delete_event_cb(GtkWidget *wgt, gpointer cbdata) { ! gui_window_closed(); ! return TRUE; } /* ! * Function called when window already closed. ! * We can't do much more here than to trying to preserve what had been done, ! * since the window is already inevitably going away. */ ! static void ! destroy_callback(void) { ! /* preserve files and exit */ ! preserve_exit(); ! if (gtk_main_level() > 0) ! gtk_main_quit(); } ! #ifdef GTK_HAVE_FEATURES_1_1_0 /* ! * Get a font structure for highlighting. ! * "cbdata" is a pointer to the global gui structure. */ ! /*ARGSUSED*/ ! static void ! font_sel_ok(GtkWidget *wgt, gpointer cbdata) { ! Gui *vw = (Gui *)cbdata; ! GtkFontSelectionDialog *fs = (GtkFontSelectionDialog *)vw->fontdlg; ! if (vw->fontname) ! g_free(vw->fontname); ! vw->fontname = (char_u *)g_strdup( ! gtk_font_selection_dialog_get_font_name(fs)); ! gtk_widget_hide(vw->fontdlg); ! if (gtk_main_level() > 0) ! gtk_main_quit(); } ! /*ARGSUSED*/ ! static void ! font_sel_cancel(GtkWidget *wgt, gpointer cbdata) { ! Gui *vw = (Gui *)cbdata; ! gtk_widget_hide(vw->fontdlg); ! if (gtk_main_level() > 0) ! gtk_main_quit(); } ! /*ARGSUSED*/ ! static void ! font_sel_destroy(GtkWidget *wgt, gpointer cbdata) { ! Gui *vw = (Gui *)cbdata; ! vw->fontdlg = NULL; ! if (gtk_main_level() > 0) ! gtk_main_quit(); } - #endif --- 823,3120 ---- return OK; } + + /**************************************************************************** + * Mouse handling callbacks + */ + + + static guint mouse_click_timer = 0; + static int mouse_timed_out = TRUE; + /* ! * Timer used to recognize multiple clicks of the mouse button */ ! static gint ! mouse_click_timer_cb(gpointer data) { ! /* we don't use this information currently */ ! int *timed_out = (int *) data; ! *timed_out = TRUE; ! return FALSE; /* don't happen again */ } + static guint motion_repeat_timer = 0; + static int motion_repeat_offset = FALSE; + + static gint motion_notify_event(GtkWidget *, GdkEventMotion *); + /* ! * Timer used to recognize multiple clicks of the mouse button. */ ! /*ARGSUSED*/ ! static gint ! motion_repeat_timer_cb(gpointer data) { ! gint x, y; ! GdkModifierType state; ! GdkEventMotion event; ! gdk_window_get_pointer(gui.drawarea->window, &x, &y, &state); ! if (!(state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | ! GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | ! GDK_BUTTON5_MASK))) ! { ! motion_repeat_timer = 0; ! return FALSE; ! } ! /* If there already is a mouse click in the input buffer, wait another ! * time (otherwise we would create a backlog of clicks) */ ! if (vim_used_in_input_buf() > 10) ! return TRUE; ! motion_repeat_timer = 0; ! ! /* Fake a motion event. ! * Trick: Pretend the mouse moved to the next character on every other ! * event, otherwise drag events will be discarded, because they are still ! * in the same character. */ ! event.is_hint = FALSE; ! if (motion_repeat_offset) ! { ! event.x = x + gui.char_width; ! motion_repeat_offset = FALSE; ! } ! else ! { ! event.x = x; ! motion_repeat_offset = TRUE; ! } ! event.y = y; ! event.state = state; ! motion_notify_event(gui.drawarea, &event); ! ! /* Don't happen again. We will get reinstalled in the synthetic event if ! * needed - thus repeating should still work. ! */ ! return FALSE; } ! /*ARGSUSED*/ ! static gint ! motion_notify_event(GtkWidget * widget, GdkEventMotion * event) { ! gint x, y; ! GdkModifierType state; ! int_u vim_modifiers; ! int button; ! if (event->is_hint) ! gdk_window_get_pointer(event->window, &x, &y, &state); ! else { ! x = event->x; ! y = event->y; ! state = event->state; ! } ! button = (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | ! GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | ! GDK_BUTTON5_MASK)) ! ? MOUSE_DRAG : ' '; ! /* If our pointer is currently hidden, then we should show it. */ ! gui_mch_mousehide(FALSE); ! /* Just moving the rodent above the drawing area without any button beeing ! * pressed. */ ! if (button != MOUSE_DRAG) { ! gui_mouse_moved(y); ! return TRUE; ! } ! /* translate modifier coding between the main engine and GTK */ ! vim_modifiers = 0x0; ! if (state & GDK_SHIFT_MASK) ! vim_modifiers |= MOUSE_SHIFT; ! if (state & GDK_CONTROL_MASK) ! vim_modifiers |= MOUSE_CTRL; ! if (state & GDK_MOD1_MASK) ! vim_modifiers |= MOUSE_ALT; ! /* inform the editor egine about the occurence of this event */ ! gui_send_mouse_event(button, x, y, FALSE, vim_modifiers); ! if (gtk_main_level() > 0) ! gtk_main_quit(); + /* + * Auto repeat timer handling. + */ + if (x < 0 || y < 0 + || x >= gui.drawarea->allocation.width + || y >= gui.drawarea->allocation.height) { ! int dx; ! int dy; ! int offshoot; ! int delay = 10; ! /* Calculate the maximal distance of the cursor from the drawing area. ! * (offshoot can't become negative here!). ! */ ! dx = x < 0 ? -x : x - gui.drawarea->allocation.width; ! dy = y < 0 ? -y : y - gui.drawarea->allocation.height; ! offshoot = dx > dy ? dx : dy; ! /* Make a linearly declaying timer delay with a threshold of 5 at a ! * distance of 127 pixels from the main window. ! * ! * One could think endlessly about the most ergonomic variant here. ! * For example it could make sense to calculate the distance from the ! * drags start instead... ! * ! * Maybe a parabolic interpolation would suite us better here too... ! */ ! if (offshoot > 127) { ! /* 5 appears to be somehow near to my perceptual limits :-). */ ! delay = 5; ! } else { ! delay = (130 * (127 - offshoot)) / 127 + 5; ! } ! /* shoot again */ ! if (!motion_repeat_timer) ! motion_repeat_timer = gtk_timeout_add((guint32)delay, ! motion_repeat_timer_cb, NULL); ! } ! return TRUE; /* handled */ ! } ! /* ! * Mouse button handling. Note please that we are capturing multiple click's ! * by our own timeout mechanism instead of the one provided by GTK+ istelf. ! * This is due to the way the generic VIM code is recognizing multiple clicks. ! */ ! /*ARGSUSED*/ ! static gint ! button_press_event(GtkWidget * widget, GdkEventButton * event) ! { ! int button; ! int repeated_click = FALSE; ! int x, y; ! int_u vim_modifiers; /* ! * Don't let additional events about multiple clicks send by GTK to us ! * after the inital button press event confuse us. */ ! if (event->type != GDK_BUTTON_PRESS) ! return FALSE; ! x = event->x; ! y = event->y; ! /* Handle multiple clicks */ ! if (!mouse_timed_out && mouse_click_timer) { ! gtk_timeout_remove(mouse_click_timer); ! mouse_click_timer = 0; ! repeated_click = TRUE; } ! mouse_timed_out = FALSE; ! mouse_click_timer = gtk_timeout_add((guint32)p_mouset, ! mouse_click_timer_cb, &mouse_timed_out); ! switch (event->button) { ! case 1: ! button = MOUSE_LEFT; ! break; ! case 2: ! button = MOUSE_MIDDLE; ! break; ! case 3: ! button = MOUSE_RIGHT; ! break; ! case 4: ! button = MOUSE_4; ! break; ! case 5: ! button = MOUSE_5; ! break; ! default: ! return FALSE; /* Unknown button */ ! } ! vim_modifiers = 0x0; ! if (event->state & GDK_SHIFT_MASK) ! vim_modifiers |= MOUSE_SHIFT; ! if (event->state & GDK_CONTROL_MASK) ! vim_modifiers |= MOUSE_CTRL; ! if (event->state & GDK_MOD1_MASK) ! vim_modifiers |= MOUSE_ALT; ! gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers); ! if (gtk_main_level() > 0) ! gtk_main_quit(); /* make sure the above will be handled immediately */ ! return TRUE; } ! /*ARGSUSED*/ ! static gint ! button_release_event(GtkWidget * widget, GdkEventButton * event) { ! int x, y; ! int_u vim_modifiers; ! ! /* Remove any motion "mashine gun" timers used for automatic further ! extension of allocation areas if outside of the applications window ! area .*/ ! if (motion_repeat_timer) { ! gtk_timeout_remove(motion_repeat_timer); ! motion_repeat_timer = 0; } + + x = event->x; + y = event->y; + + vim_modifiers = 0x0; + if (event->state & GDK_SHIFT_MASK) + vim_modifiers |= MOUSE_SHIFT; + if (event->state & GDK_CONTROL_MASK) + vim_modifiers |= MOUSE_CTRL; + if (event->state & GDK_MOD1_MASK) + vim_modifiers |= MOUSE_ALT; + + gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, vim_modifiers); + if (gtk_main_level() > 0) + gtk_main_quit(); /* make sure it will be handled immediately */ + + return TRUE; } + #ifdef GTK_DND + /**************************************************************************** + * Drag aNd Drop support handlers. + */ + + /* + * DND receiver. + */ + /*ARGSUSED*/ static void ! drag_data_received(GtkWidget *widget, GdkDragContext *context, ! gint x, gint y, ! GtkSelectionData *data, ! guint info, guint time) ! { ! char_u **fnames; ! int redo_dirs = FALSE; ! int i; ! int n; ! char *start; ! char *stop; ! char *copy; ! int nfiles; ! GdkModifierType current_modifiers; ! ! /* Get the current modifier state for proper distinguishment between ! * different operations later. */ ! current_modifiers = 0; ! gdk_window_get_pointer(NULL, NULL, NULL, ¤t_modifiers); ! ! /* guard against trash */ ! if (((data->length <= 0) && (data->format != 8)) ! || (((char *)data->data)[data->length] != '\0')) { ! gtk_drag_finish(context, FALSE, FALSE, time); ! return; ! } ! /* Count how meny items there may be there and normalize ! * delimiters. ! */ ! n = 1; ! copy = strdup((char *)data->data); ! for (i = 0; i < data->length; ++i) { ! if (copy[i] == '\n') ! ++n; ! else if(copy[i] == '\r') { ! copy[i] = '\n'; ! ++n; ! } ! } ! fnames = (char_u **) alloc((n + 1) * sizeof(char_u *)); ! start = copy; ! stop = copy; ! nfiles = 0; ! for (i = 0; i < n; ++i) { ! stop = strchr(start, '\n'); ! if (stop) ! *stop = '\0'; ! ! if (!strlen(start)) ! continue; ! ! if (strncmp(start, "file:", 5)) { ! int j; ! ! free(copy); ! for (j = 0; j < nfiles; ++j) ! free(fnames[j]); ! gtk_drag_finish(context, FALSE, FALSE, time); ! return; ! } ! ! if (!strncmp(start, "file://localhost", 16)) { ! fnames[nfiles] = (char_u *)strdup(start + 16); ! ++nfiles; ! } else { ! fnames[nfiles] = (char_u *)strdup(start + 5); ! ++nfiles; ! } ! start = stop + 2; ! } ! free(copy); ! ! /* accept */ ! gtk_drag_finish (context, TRUE, FALSE, time); /* ! * Handle dropping a directory on Vim. */ ! if (nfiles == 1) { ! if (mch_isdir(fnames[0])) { ! if (mch_chdir((char *)fnames[0]) == 0) { ! free(fnames[0]); ! fnames[0] = NULL; ! redo_dirs = TRUE; ! } ! } ! } else { ! /* Ignore any directories */ ! for (i = 0; i < nfiles; ++i) { ! if (mch_isdir(fnames[i])) { ! free(fnames[i]); ! fnames[i] = NULL; ! } ! } ! } ! if (current_modifiers & GDK_SHIFT_MASK) { ! /* Shift held down, change to first file's directory */ ! if (fnames[0] != NULL && vim_chdirfile(fnames[0]) == 0) ! redo_dirs = TRUE; ! } ! /* Handle the drop, :edit or :split to get to the file */ ! handle_drop(nfiles, fnames, current_modifiers & GDK_CONTROL_MASK); ! ! if (redo_dirs) ! shorten_fnames(TRUE); ! ! /* Update the screen display */ ! update_screen(NOT_VALID); ! setcursor(); ! out_flush(); } + #endif /* GTK_DND */ /* ! * Setup the window icon after the main window has bee realized. */ /*ARGSUSED*/ ! static void ! mainwin_realize(GtkWidget *widget) { ! /* If you get an error message here, you still need to unpack the runtime ! * archive! */ ! #include "../runtime/vim32x32.xpm" ! static GdkPixmap *icon = NULL; ! static GdkBitmap *icon_mask = NULL; ! if (!icon) ! icon = gdk_pixmap_create_from_xpm_d(gui.mainwin->window, ! &icon_mask, NULL, magick); ! gdk_window_set_icon(gui.mainwin->window, NULL, icon, icon_mask); } /* ! * After the drawing area comes up, we calculate all colors and create the ! * dummy blank cursor. ! * ! * Don't try to set any VIM scrollbar sizes anywhere here. I'm relying on the ! * fact that the main VIM engine doesn't take them into account anywhere. */ ! static void ! drawarea_realize_cb(GtkWidget *widget) { ! char blank_data[] = {0x0}; ! GdkPixmap *blank_mask; ! GdkColor color; ! GtkWidget *sbar; ! #ifdef USE_XIM ! xim_init(); #endif + gui_mch_new_colors(); ! blank_mask = gdk_bitmap_create_from_data(NULL, blank_data, 1, 1); ! gdk_color_white(gdk_colormap_get_system(), &color); ! gui.blank_pointer = gdk_cursor_new_from_pixmap(blank_mask, blank_mask, ! &color, &color, 0, 0); ! gdk_bitmap_unref(blank_mask); ! if (gui.pointer_hidden) ! gdk_window_set_cursor(widget->window, gui.blank_pointer); ! /* get the actual size of the scrollbars, if they are realized */ ! sbar = firstwin->w_scrollbars[SBAR_LEFT].id; ! if (!sbar || (!gui.which_scrollbars[SBAR_LEFT] ! && firstwin->w_scrollbars[SBAR_RIGHT].id)) ! sbar = firstwin->w_scrollbars[SBAR_RIGHT].id; ! if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.width) ! gui.scrollbar_width = sbar->allocation.width; ! sbar = gui.bottom_sbar.id; ! if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.height) ! gui.scrollbar_height = sbar->allocation.height; } ! /* ! * Callback routine for the "delete_event" signal on the toplevel window. ! * Tries to vim gracefully, or refuses to exit with changed buffers. ! */ /*ARGSUSED*/ ! static int ! delete_event_cb(GtkWidget *wgt, gpointer cbdata) { ! gui_window_closed(); ! return TRUE; } /* ! * Initialise the X GUI. Create all the windows, set up all the call-backs etc. ! * Returns OK for success, FAIL when the GUI can't be started. */ int ! gui_mch_init() { ! GtkWidget *vbox; ! /* Initialize values */ ! gui.rev_video = FALSE; ! gui.border_width = 2; ! gui.scrollbar_width = SB_DEFAULT_WIDTH; ! gui.scrollbar_height = SB_DEFAULT_WIDTH; ! gui.fgcolor = g_new0(GdkColor, 1); ! gui.bgcolor = g_new0(GdkColor, 1); ! #ifdef WANT_MENU ! /* Don't change the menu height values used in gui.c at runtime */ ! gui.menu_height_fixed = TRUE; ! #endif ! /* Set default foreground and background colours. */ ! gui.norm_pixel = gui.def_norm_pixel; ! gui.back_pixel = gui.def_back_pixel; ! gui.mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); ! gtk_window_set_policy(GTK_WINDOW(gui.mainwin), TRUE, TRUE, TRUE); ! gtk_container_border_width(GTK_CONTAINER(gui.mainwin), 0); ! gtk_widget_set_events(gui.mainwin, GDK_VISIBILITY_NOTIFY_MASK); ! (void)gtk_signal_connect(GTK_OBJECT(gui.mainwin), "delete_event", ! GTK_SIGNAL_FUNC(delete_event_cb), NULL); + /* Add an icon to the main window. For fun and convenience of the user. */ + if (vim_strchr(p_go, GO_ICON) != NULL) + gtk_signal_connect(GTK_OBJECT(gui.mainwin), "realize", + GTK_SIGNAL_FUNC(mainwin_realize), NULL); ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! /* FIXME: this should eventually get the accelgroup of the gui.mainwin */ ! gui.accel_group = gtk_accel_group_get_default(); #endif ! vbox = gtk_vbox_new(FALSE, 0); ! gtk_container_add(GTK_CONTAINER(gui.mainwin), vbox); ! gtk_widget_show(vbox); ! #ifdef WANT_MENU ! /* create the menubar and handle */ ! gui.menubar = gtk_menu_bar_new(); ! gtk_widget_show(gui.menubar); ! gtk_box_pack_start(GTK_BOX(vbox), gui.menubar, FALSE, TRUE, 0); #endif ! #ifdef USE_TOOLBAR ! /* create the toolbar */ ! if (p_toolbar) { if (strstr((const char *)p_toolbar, "text") ! && strstr((const char *)p_toolbar, "icons")) ! gui.toolbar = ! gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH); ! else if (strstr((const char *)p_toolbar, "text")) ! gui.toolbar = ! gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_TEXT); else ! gui.toolbar = ! gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS); ! } else ! gui.toolbar = ! gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS); ! gtk_widget_show(gui.toolbar); ! # ifdef GTK_HAVE_FEATURES_1_1_0 ! /* some aesthetics on the toolbar */ ! gtk_toolbar_set_button_relief(GTK_TOOLBAR(gui.toolbar), GTK_RELIEF_NONE); ! # endif ! gtk_container_border_width(GTK_CONTAINER(gui.toolbar), 1); ! gtk_box_pack_start(GTK_BOX(vbox), gui.toolbar, FALSE, TRUE, 0); #endif + gui.formwin = gtk_form_new(); + gtk_container_border_width(GTK_CONTAINER(gui.formwin), 0); + gtk_widget_set_events(gui.formwin, GDK_EXPOSURE_MASK); ! gui.drawarea = gtk_drawing_area_new(); ! /* Determine which events we will filter. */ ! gtk_widget_set_events(gui.drawarea, ! GDK_EXPOSURE_MASK | ! GDK_ENTER_NOTIFY_MASK | ! GDK_LEAVE_NOTIFY_MASK | ! GDK_BUTTON_PRESS_MASK | ! GDK_BUTTON_RELEASE_MASK | ! GDK_POINTER_MOTION_MASK | ! GDK_POINTER_MOTION_HINT_MASK); ! gtk_widget_show(gui.drawarea); ! gtk_form_put(GTK_FORM(gui.formwin), gui.drawarea, 0, 0); ! gtk_widget_show(gui.formwin); ! gtk_box_pack_start(GTK_BOX(vbox), gui.formwin, TRUE, TRUE, 0); ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "key_press_event", ! (GtkSignalFunc) key_press_event, NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "realize", ! GTK_SIGNAL_FUNC(drawarea_realize_cb), NULL); ! ! /* Check if reverse video needs to be applied (on Sun it's done by X) */ ! if (gui.rev_video && gui_mch_get_lightness(gui.back_pixel) ! > gui_mch_get_lightness(gui.norm_pixel)) { ! gui.norm_pixel = gui.def_back_pixel; ! gui.back_pixel = gui.def_norm_pixel; ! gui.def_norm_pixel = gui.norm_pixel; ! gui.def_back_pixel = gui.back_pixel; } + gui.visibility = GDK_VISIBILITY_UNOBSCURED; + clipboard.atom = gdk_atom_intern("_VIM_TEXT", FALSE); + save_yourself_atom = gdk_atom_intern("WM_SAVE_YOURSELF", FALSE); + reread_rcfiles_atom = gdk_atom_intern("_GTK_READ_RCFILES", FALSE); ! /* ! * Start out by adding the configured border width into the border offset. ! */ ! gui.border_offset = gui.border_width; ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "visibility_notify_event", ! GTK_SIGNAL_FUNC(visibility_event), NULL); #endif + gtk_signal_connect(GTK_OBJECT(gui.drawarea), "expose_event", + GTK_SIGNAL_FUNC(expose_event), NULL); ! /* ! * Only install these enter/leave callbacks when 'p' in 'guioptions'. ! * Only needed for some window managers. ! */ ! if (vim_strchr(p_go, GO_POINTER) != NULL) { ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "leave_notify_event", ! GTK_SIGNAL_FUNC(leave_notify_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "enter_notify_event", ! GTK_SIGNAL_FUNC(enter_notify_event), NULL); } ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_out_event", ! GTK_SIGNAL_FUNC(focus_out_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_in_event", ! GTK_SIGNAL_FUNC(focus_in_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "motion_notify_event", ! GTK_SIGNAL_FUNC(motion_notify_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "button_press_event", ! GTK_SIGNAL_FUNC(button_press_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "button_release_event", ! GTK_SIGNAL_FUNC(button_release_event), NULL); ! /* ! * Add selection handler functions. ! */ ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_clear_event", ! GTK_SIGNAL_FUNC(selection_clear_event), NULL); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_received", ! GTK_SIGNAL_FUNC(selection_received_event), NULL); ! /* gtk_selection_add_target() is not in GTK 1.1.2 */ ! #ifdef GTK_HAVE_FEATURES_1_1_4 ! gtk_selection_add_target(gui.drawarea, GDK_SELECTION_PRIMARY, ! GDK_TARGET_STRING, SELECTION_STRING); ! gtk_selection_add_target(gui.drawarea, GDK_SELECTION_PRIMARY, ! clipboard.atom, SELECTION_CLIPBOARD); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_get", ! GTK_SIGNAL_FUNC(selection_get_event), NULL); ! #else ! gtk_selection_add_handler(gui.drawarea, GDK_SELECTION_PRIMARY, ! GDK_TARGET_STRING, selection_handler, NULL); ! gtk_selection_add_handler(gui.drawarea, GDK_SELECTION_PRIMARY, ! clipboard.atom, selection_handler, NULL); ! #endif ! /* Pretend we don't have input focus, we will get an event if we do. */ ! gui.in_focus = FALSE; ! return OK; ! } ! /* ! * Called when the foreground or background color has been changed. ! */ ! void ! gui_mch_new_colors() ! { ! /* This used to change the graphics contexts directly but we are currently ! * manipulating them where desired. ! */ ! if (gui.drawarea && gui.drawarea->window) { ! GdkColor color; ! color.pixel = gui.back_pixel; ! gdk_window_set_background(gui.drawarea->window, &color); } ! } ! ! #ifdef GTK_HAVE_FEATURES_1_1_6 ! # define USE_GEOMETRY_FOR_HINTS 1 #endif ! static void ! update_window_manager_hints(void) ! { ! int width; ! int height; ! #ifdef USE_GEOMETRY_FOR_HINTS ! GdkGeometry geometry; ! GdkWindowHints geometry_mask; ! /* This also needs to be done when the main window isn't there yet, ! * otherwise the hints don't work. */ ! width = gui_get_base_width(); ! height = gui_get_base_height(); ! geometry_mask = GDK_HINT_BASE_SIZE|GDK_HINT_RESIZE_INC|GDK_HINT_MIN_SIZE; ! geometry.width_inc = gui.char_width; ! geometry.height_inc = gui.char_height; ! geometry.base_width = width; ! geometry.base_height = height; ! geometry.min_width = width + MIN_COLUMNS * gui.char_width; ! geometry.min_height = height + MIN_LINES * gui.char_height; ! gtk_window_set_geometry_hints(GTK_WINDOW(gui.mainwin), gui.formwin, ! &geometry, geometry_mask); ! #else ! XSizeHints size_hints; ! /* Don't set the size until the main window is really there */ ! if (!GTK_WIDGET_REALIZED(gui.mainwin)) ! return; ! width = gui_get_base_width(); ! height = gui_get_base_height(); ! /* The hints don't automatically take the menubar and toolbar into ! * account. Need to add their height here, if they are visible. */ ! # ifdef USE_TOOLBAR ! if (gui.toolbar && GTK_WIDGET_REALIZED(gui.toolbar) ! && GTK_WIDGET_VISIBLE(gui.toolbar)) ! height += gui.toolbar->allocation.height; ! # endif ! # ifdef WANT_MENU ! if (gui.menubar && GTK_WIDGET_REALIZED(gui.menubar) ! && GTK_WIDGET_VISIBLE(gui.menubar)) ! height += gui.menubar->allocation.height; ! # endif ! /* ! * Argh!!! Once again we need to deal with an ommission in GTK+ by ! * resorting to direct Xlib calls. Fortunatly I know how to do it :-). ! */ ! size_hints.flags = (PResizeInc | PBaseSize | PMinSize | PSize); ! size_hints.width_inc = gui.char_width; ! size_hints.height_inc = gui.char_height; ! size_hints.base_width = width; ! size_hints.base_height = height; ! size_hints.min_width = width + MIN_COLUMNS * gui.char_width; ! size_hints.min_height = height + MIN_LINES * gui.char_height; ! /* This is only needed for "older" window managers. See a corresposning ! * comment in the X11 headers. */ ! size_hints.width = width + Columns * gui.char_width; ! size_hints.height = height + Rows * gui.char_height; ! XSetWMNormalHints(GDK_DISPLAY(), ! GDK_WINDOW_XWINDOW(gui.mainwin->window), ! &size_hints); ! #endif /* USE_GEOMETRY_FOR_HINTS */ ! } ! /* ! * This signal informs us about the need to rearrange our subwidgets. ! */ ! /*ARGSUSED*/ ! static gint ! form_configure_event(GtkWidget * widget, GdkEventConfigure * event) ! { ! gtk_form_freeze(GTK_FORM(gui.formwin)); ! gui_resize_window(event->width, event->height); ! gtk_form_thaw(GTK_FORM(gui.formwin)); ! return TRUE; ! } ! /* ! * X11 based inter client communication handler. ! */ ! /*ARGSUSED*/ ! static gint ! client_event_cb(GtkWidget *widget, GdkEventClient *event) ! { ! if (event->message_type == save_yourself_atom ) { ! out_flush(); ! ml_sync_all(FALSE, FALSE); /* preserve all swap files */ ! return TRUE; ! } else if (event->message_type == reread_rcfiles_atom) { ! gui_mch_new_colors(); ! return TRUE; ! } ! return FALSE; ! } ! /* ! * Function called when window already closed. ! * We can't do much more here than to trying to preserve what had been done, ! * since the window is already inevitably going away. ! */ ! static void ! destroy_callback(void) ! { ! /* preserve files and exit */ ! preserve_exit(); ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! } ! /* ! * Open the GUI window which was created by a call to gui_mch_init(). ! */ ! int ! gui_mch_open() ! { ! int x = -1, y = -1; ! /* Determine user specified geometry, if present. */ ! if (gui.geom) { ! int mask; ! unsigned w, h; ! mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h); ! if (mask & WidthValue) ! Columns = w; ! if (mask & HeightValue) ! Rows = h; ! if (mask & (XValue | YValue)) ! gtk_widget_set_uposition(gui.mainwin, x, y); ! g_free(gui.geom); ! gui.geom = NULL; } ! gtk_form_set_size(GTK_FORM(gui.formwin), ! (guint)(gui_get_base_width() + Columns * gui.char_width), ! (guint)(gui_get_base_height() + Rows * gui.char_height)); update_window_manager_hints(); ! if (found_reverse_arg ) ! { ! gui.def_norm_pixel = gui_mch_get_color((char_u *)"White"); ! gui.def_back_pixel = gui_mch_get_color((char_u *)"Black"); ! } ! else ! { ! gui.def_norm_pixel = gui_mch_get_color((char_u *)"Black"); ! gui.def_back_pixel = gui_mch_get_color((char_u *)"White"); ! } + /* Get the colors from the "Normal" and "Menu" group (set in syntax.c or + * in a vimrc file) + */ + set_normal_colors(); ! /* Check that none of the colors are the same as the background color */ ! gui_check_colors(); ! /* Get the colors for the highlight groups (gui_check_colors() might have ! * changed them). ! */ ! highlight_gui_started(); /* re-init colors and fonts */ ! gtk_signal_connect(GTK_OBJECT(gui.mainwin), "destroy", ! GTK_SIGNAL_FUNC(destroy_callback), NULL); ! ! /* Make this run after any internal handling of the client event happaned ! * to make sure that all changes implicated by it are already in place and ! * we thus can make our own adjustments. ! */ ! gtk_signal_connect_after(GTK_OBJECT(gui.mainwin), "client_event", ! GTK_SIGNAL_FUNC(client_event_cb), NULL); ! #ifdef HANGUL_INPUT ! hangul_keyboard_set(); #endif ! /* ! * Notify the fixed area about the need to resize the contents of the ! * gui.formwin, which we use for random positioning of the included ! * components. ! * ! * We connect this signal deferred finally after anything is in place, ! * since this is intended to handle resizements coming from the window ! * manager upon us and should not interfere with what VIM is requesting ! * upon startup. ! */ ! gtk_signal_connect(GTK_OBJECT(gui.formwin), "configure_event", ! GTK_SIGNAL_FUNC(form_configure_event), NULL); ! #ifdef GTK_DND ! /* ! * Set up for receiving DND items. ! */ ! gtk_drag_dest_set(gui.drawarea, ! GTK_DEST_DEFAULT_ALL, ! target_table, n_targets, ! GDK_ACTION_COPY | GDK_ACTION_MOVE); ! gtk_signal_connect(GTK_OBJECT(gui.drawarea), "drag_data_received", ! GTK_SIGNAL_FUNC(drag_data_received), NULL); ! #endif ! gtk_widget_show(gui.mainwin); ! ! return OK; } ! ! /*ARGSUSED*/ void ! gui_mch_exit(int rc) { ! gtk_exit(0); } /* ! * Get the position of the top left corner of the window. */ int ! gui_mch_get_winpos(int *x, int *y) { ! /* For some people this must be gdk_window_get_origin() for a correct ! * result. Where is the documentation! */ ! #ifdef GTK_HAVE_FEATURES_1_1_4 ! gdk_window_get_root_origin(gui.mainwin->window, x, y); ! #else ! gdk_window_get_origin(gui.mainwin->window, x, y); #endif + return OK; + } /* ! * Set the position of the top left corner of the window to the given ! * coordinates. */ void ! gui_mch_set_winpos(int x, int y) { ! gdk_window_move(gui.mainwin->window, x, y); } /* ! * Set the windows size. */ ! /*ARGSUSED*/ ! void ! gui_mch_set_winsize(int width, int height, ! int min_width, int min_height, ! int base_width, int base_height) { ! gtk_form_set_size(GTK_FORM(gui.formwin), width, height); ! /* give GTK+ a chance to put all widget's into place */ ! gui_mch_update(); ! /* this will cause the proper resizement to happen too */ ! update_window_manager_hints(); } /* ! * The screen size is used to make sure the initial window doesn't get bigger ! * then the screen. This subtracts some room for menubar, toolbar and window ! * decoreations. */ void ! gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) { ! *screen_w = gdk_screen_width(); ! /* Subtract 'guihearroom' from the height to allow some room for the ! * window manager (task list and window title bar). */ ! *screen_h = gdk_screen_height() - p_ghr; ! ! /* ! * FIXME: dirty trick: Because the gui_get_base_height() doesn't include ! * the toolbar and menubar for GTK, we subtract them from the screen ! * hight, so that the window size can be made to fit on the screen. ! * This should be completely changed later. ! */ ! #ifdef USE_TOOLBAR ! if (gui.toolbar && GTK_WIDGET_REALIZED(gui.toolbar) ! && GTK_WIDGET_VISIBLE(gui.toolbar)) ! *screen_h -= gui.toolbar->allocation.height; ! #endif ! #ifdef WANT_MENU ! if (gui.menubar && GTK_WIDGET_REALIZED(gui.menubar) ! && GTK_WIDGET_VISIBLE(gui.menubar)) ! *screen_h -= gui.menubar->allocation.height; ! #endif } ! #if defined(WANT_MENU) || defined(PROTO) void ! gui_mch_enable_menu(int flag) { ! if (flag) ! gtk_widget_show(gui.menubar); ! else ! gtk_widget_hide(gui.menubar); ! ! update_window_manager_hints(); } + #endif + + #if defined(USE_TOOLBAR) || defined(PROTO) void ! gui_mch_show_toolbar(int showit) { ! if (gui.toolbar == NULL) return; ! if (!showit) { ! if (GTK_WIDGET_VISIBLE(gui.toolbar)) { ! gtk_widget_hide(gui.toolbar); ! /* wait util this gets done on the server side. */ ! update_window_manager_hints(); ! } ! } else { ! g_assert(p_toolbar != NULL); ! if (strstr((const char *)p_toolbar, "text") ! && strstr((const char *)p_toolbar, "icons")) { ! gtk_toolbar_set_style(GTK_TOOLBAR(gui.toolbar), GTK_TOOLBAR_BOTH); ! } else if (strstr((const char *)p_toolbar, "text")) { ! gtk_toolbar_set_style(GTK_TOOLBAR(gui.toolbar), GTK_TOOLBAR_TEXT); ! } else if (strstr((const char *)p_toolbar, "icons")) { ! gtk_toolbar_set_style(GTK_TOOLBAR(gui.toolbar), GTK_TOOLBAR_ICONS); } ! if (!GTK_WIDGET_VISIBLE(gui.toolbar)) { ! gtk_widget_show(gui.toolbar); ! update_window_manager_hints(); ! } ! if (strstr((const char *)p_toolbar, "tooltips")) ! gtk_toolbar_set_tooltips(GTK_TOOLBAR(gui.toolbar), TRUE); ! else ! gtk_toolbar_set_tooltips(GTK_TOOLBAR(gui.toolbar), FALSE); } } #endif ! #ifdef USE_FONTSET ! static GuiFont ! gui_mch_get_fontset(char_u * name, int report_error) { ! GdkFont *font; ! if (!gui.in_use || name == NULL) ! return (GuiFont) 0; ! font = gdk_fontset_load((gchar *) name); ! if (font == NULL) { ! if (report_error) ! EMSG2("Unknown fontset: %s", name); ! return (GuiFont) 0; ! } ! /* reference this font as beeing in use */ ! gdk_font_ref(font); ! return (GuiFont) font; } + #endif + #ifdef GTK_HAVE_FEATURES_1_1_0 /* ! * Get a font structure for highlighting. ! * "cbdata" is a pointer to the global gui structure. */ ! /*ARGSUSED*/ ! static void ! font_sel_ok(GtkWidget *wgt, gpointer cbdata) { ! Gui *vw = (Gui *)cbdata; ! GtkFontSelectionDialog *fs = (GtkFontSelectionDialog *)vw->fontdlg; ! if (vw->fontname) ! g_free(vw->fontname); ! vw->fontname = (char_u *)g_strdup( ! gtk_font_selection_dialog_get_font_name(fs)); ! gtk_widget_hide(vw->fontdlg); ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! } ! /*ARGSUSED*/ ! static void ! font_sel_cancel(GtkWidget *wgt, gpointer cbdata) ! { ! Gui *vw = (Gui *)cbdata; ! ! gtk_widget_hide(vw->fontdlg); ! if (gtk_main_level() > 0) ! gtk_main_quit(); } ! /*ARGSUSED*/ ! static void ! font_sel_destroy(GtkWidget *wgt, gpointer cbdata) { ! Gui *vw = (Gui *)cbdata; ! ! vw->fontdlg = NULL; ! if (gtk_main_level() > 0) ! gtk_main_quit(); } + #endif /* ! * Initialise vim to use the font with the given name. ! * Return FAIL if the font could not be loaded, OK otherwise. */ ! int ! gui_mch_init_font(char_u * font_name) { ! GdkFont *font = NULL; ! char *chunk[28], *sdup, *tmp; ! int len, i; ! #ifdef USE_FONTSET ! { ! static char_u *dflt_fontset = NULL; ! if (gui.fontset) ! { ! /* If fontset is active, VIM treat all the font as a fontset. */ ! if (font_name == NULL || vim_strchr(font_name, ',') == NULL) ! font_name = dflt_fontset; ! font = gui_mch_get_fontset(font_name, FALSE); ! if (font == NULL) ! return FAIL; ! } ! else if (font_name == NULL && *p_guifontset) ! { ! font = gui_mch_get_fontset(p_guifontset, FALSE); ! if (font) ! { ! font_name = p_guifontset; ! dflt_fontset = alloc(STRLEN(p_guifontset) + 1); ! STRCPY(dflt_fontset, p_guifontset); ! } ! } ! } ! if (font == NULL) ! #endif { ! /* ! * If none of the fonts in 'font' could be loaded, try the default, ! * which should be present on all X11 servers. ! */ ! if (font_name == NULL) ! font_name = (char_u *) DFLT_FONT; ! ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! if (STRCMP(font_name, "*") == 0) { ! /* ! * Request for a font handling dialog. ! * Not quite sure we should handle this here... ! */ ! /* ! * NOTE about font selection widget: this can easily be backported ! * to gtk-1.0.x. ! */ ! if (!gui.fontdlg) ! { ! GtkFontSelectionDialog *fsd = NULL; ! ! gui.fontdlg = gtk_font_selection_dialog_new("Font Selection"); ! fsd = GTK_FONT_SELECTION_DIALOG(gui.fontdlg); ! if (p_guifont != NULL) ! gtk_font_selection_dialog_set_font_name(fsd, ! (char *)p_guifont); ! # ifdef GTK_HAVE_FEATURES_1_1_4 ! gtk_window_set_modal(GTK_WINDOW(gui.fontdlg), TRUE); ! gtk_window_set_transient_for(GTK_WINDOW(gui.fontdlg), ! GTK_WINDOW(gui.mainwin)); # endif ! gtk_signal_connect(GTK_OBJECT(gui.fontdlg), "destroy", ! GTK_SIGNAL_FUNC(font_sel_destroy), &gui); ! gtk_signal_connect(GTK_OBJECT(fsd->ok_button), "clicked", ! GTK_SIGNAL_FUNC(font_sel_ok), &gui); ! gtk_signal_connect(GTK_OBJECT(fsd->cancel_button), "clicked", ! GTK_SIGNAL_FUNC(font_sel_cancel), &gui); ! } ! if (gui.fontname) ! { ! g_free(gui.fontname); ! gui.fontname = NULL; ! } ! gtk_window_position(GTK_WINDOW(gui.fontdlg), GTK_WIN_POS_MOUSE); ! gtk_widget_show(gui.fontdlg); ! # ifdef GTK_HAVE_FEATURES_1_1_4 ! { ! static gchar *spacings[] = {"c", "m", NULL}; ! ! /* In GTK 1.2.3 this must be after the gtk_widget_show() call, ! * otherwise everything is blocked for ten seconds. */ ! gtk_font_selection_dialog_set_filter( ! GTK_FONT_SELECTION_DIALOG(gui.fontdlg), ! GTK_FONT_FILTER_BASE, ! GTK_FONT_ALL, NULL, NULL, ! NULL, NULL, spacings, NULL); ! } ! # endif ! ! while (gui.fontdlg && GTK_WIDGET_VISIBLE(gui.fontdlg)) ! gtk_main_iteration_do(TRUE); ! ! if (gui.fontname == NULL) ! return FAIL; ! vim_free(p_guifont); ! p_guifont = vim_strsave(gui.fontname); ! font_name = p_guifont; ! } ! #endif ! if (font == NULL) ! font = gui_mch_get_font(font_name, FALSE); ! ! if (font == NULL) ! return FAIL; ! } ! ! if (gui.norm_font != 0) ! gdk_font_unref(font); ! gui.norm_font = font; ! #ifdef USE_FONTSET ! if (font->type == GDK_FONT_FONTSET) ! { ! gui.fontset = (GuiFont) font; ! gui.char_width = gdk_string_width(font, " "); } else #endif ! { ! gui.char_width = ((XFontStruct *) ! GDK_FONT_XFONT(font))->max_bounds.width; ! } ! gui.char_height = font->ascent + font->descent; ! gui.char_ascent = font->ascent; ! /* Set the fontname, which will be used for information purposes */ ! hl_set_font_name(font_name); ! if (font->type != GDK_FONT_FONTSET) ! { ! /* There is only one excuse I can give for the following attempt ! * to manage font styles: ! * ! * I HATE THE BRAIN DEAD WAY X11 IS HANDLING FONTS (--mdcki) ! */ ! if ((sdup = g_strdup((const char *)font_name)) == NULL) ! return FAIL; ! /* slipt up the whole */ ! i = 0; ! for (tmp = sdup; *tmp != '\0'; ++tmp) ! if (*tmp == '-') ! { ! *tmp = '\0'; ! chunk[i] = tmp + 1; ! ++i; ! } ! ! g_free(sdup); ! ! if (i == 14) ! { ! char *bold_name = NULL; ! char *ital_name = NULL; ! char *italbold_name = NULL; ! ! /* font name was compleate */ ! len = strlen((const char *)font_name) + 32; ! bold_name = (char *)alloc(len); ! ital_name = (char *)alloc(len); ! italbold_name = (char *)alloc(len); ! if (bold_name == NULL || ital_name == NULL || italbold_name == NULL) ! { ! vim_free(bold_name); ! vim_free(ital_name); ! vim_free(italbold_name); ! return FAIL; ! } ! ! *bold_name = '\0'; ! *ital_name = '\0'; ! *italbold_name = '\0'; ! ! for (i = 0; i < 14; ++i) ! { ! strcat(bold_name, "-"); ! strcat(ital_name, "-"); ! strcat(italbold_name, "-"); ! strcat(bold_name, (i != 2) ? chunk[i] : "bold"); ! strcat(ital_name, (i != 3) ? chunk[i] : "o"); ! ! if (i != 2 && i != 3) ! strcat(italbold_name, chunk[i]); ! else ! { ! if (i == 2) ! strcat(italbold_name, "bold"); ! else if (i == 3) ! strcat(italbold_name, "o"); ! } ! } ! ! font = gui_mch_get_font((char_u *)bold_name, FALSE); ! if (font != NULL) ! gui.bold_font = font; ! else if (gui.bold_font) ! { ! gdk_font_unref(gui.bold_font); ! gui.bold_font = NULL; ! } ! ! font = gui_mch_get_font((char_u *)ital_name, FALSE); ! if (font != NULL) ! gui.ital_font = font; ! else if (gui.ital_font) ! { ! gdk_font_unref(gui.ital_font); ! gui.ital_font = NULL; ! } ! ! font = gui_mch_get_font((char_u *)italbold_name, FALSE); ! if (font != NULL) ! gui.boldital_font = font; ! else if (gui.boldital_font) ! { ! gdk_font_unref(gui.boldital_font); ! gui.boldital_font = NULL; ! } ! ! vim_free(bold_name); ! vim_free(ital_name); ! vim_free(italbold_name); ! } ! } ! ! /* Synchronize the fonts used in user input dialogs, since otherwise ! * search/replace will be esp annoyig in case of international font usage. ! */ ! gui_gtk_synch_fonts(); ! ! #ifdef USE_XIM ! /* Adjust input management behaviour to the capabilities of the new ! * fontset */ ! xim_decide_input_style(); ! if (xim_get_status_area_height()) ! { ! /* Status area is required. Just create the empty label so that ! * mainwin will allocate the extra space for status area. */ ! GtkWidget *label = gtk_label_new(" "); ! ! gtk_widget_set_usize(label, 20, gui.char_height + 2); ! gtk_box_pack_end(GTK_BOX(GTK_BIN(gui.mainwin)->child), label, ! FALSE, FALSE, 0); ! gtk_widget_show(label); ! } ! #endif ! /* Preserve the logical dimensions of the screen. */ ! update_window_manager_hints(); ! return OK; } ! GuiFont ! gui_mch_get_font(char_u * name, int report_error) { ! GdkFont *font; ! if (!gui.in_use || name == NULL) /* can't do this when GUI not running */ ! return (GuiFont) 0; ! #ifdef USE_FONTSET ! if (gui.fontset) ! /* If fontset is active, VIM treat all the font as a fontset */ ! return gui_mch_get_fontset(name, report_error); ! else if (vim_strchr(name, ',')) ! return (GuiFont)0; #endif ! font = gdk_font_load((const gchar *) name); ! if (font == NULL) { ! if (report_error) ! EMSG2("Unknown font: %s", name); ! return (GuiFont) 0; ! } ! /* reference this font as beeing in use */ ! gdk_font_ref(font); ! if (((XFontStruct *) GDK_FONT_XFONT(font))->max_bounds.width ! != ((XFontStruct *) GDK_FONT_XFONT(font))->min_bounds.width) { ! EMSG2("Font \"%s\" is not fixed-width", name); ! gdk_font_unref(font); ! return (GuiFont) 0; ! } ! return (GuiFont) font; } /* ! * Set the current text font. ! * Since we create all GC on demand, we use just gui.current_font to ! * indicate the desired current font. */ ! void ! gui_mch_set_font(GuiFont font) { ! gui.current_font = font; } ! #if 0 /* not used */ ! /* ! * Return TRUE if the two fonts given are equivalent. ! */ ! int ! gui_mch_same_font(GuiFont f1, GuiFont f2) { ! return gdk_font_equal((GdkFont *) f1, (GdkFont *) f2); } + #endif /* ! * If a font is not going to be used, free its structure. */ void ! gui_mch_free_font(GuiFont font) { ! if (font) ! gdk_font_unref((GdkFont *) font); ! } ! /* ! * Return the Pixel value (color) for the given color name. This routine was ! * pretty much taken from example code in the Silicon Graphics OSF/Motif ! * Programmer's Guide. ! * Return -1 for error. ! */ ! GuiColor ! gui_mch_get_color(char_u * name) ! { ! int i; ! static char *(vimnames[][2]) = ! { ! /* A number of colors that some X11 systems don't have */ ! {"LightRed", "#FFA0A0"}, ! {"LightGreen", "#80FF80"}, ! {"LightMagenta", "#FFA0FF"}, ! {"DarkCyan", "#008080"}, ! {"DarkBlue", "#0000C0"}, ! {"DarkRed", "#C00000"}, ! {"DarkMagenta", "#C000C0"}, ! {"DarkGrey", "#C0C0C0"}, ! {NULL, NULL} ! }; ! if (!gui.in_use) /* can't do this when GUI not running */ ! return (GuiColor)(-1); ! while (name != NULL) { ! GdkColor color; ! if (gdk_color_parse((const gchar *)name, &color)) { ! GdkColormap *colormap; ! colormap = gtk_widget_get_colormap(gui.drawarea); ! gdk_color_alloc(colormap, &color); ! return (GuiColor) color.pixel; ! } ! /* add a few builtin names */ ! for (i = 0;; ++i) { ! if (vimnames[i][0] == NULL) { ! name = NULL; ! break; ! } ! if (STRICMP(name, vimnames[i][0]) == 0) { ! name = (char_u *) vimnames[i][1]; ! break; ! } ! } ! } ! return (GuiColor)(-1); } /* ! * Set the current text foreground color. */ ! void ! gui_mch_set_fg_color(GuiColor color) { ! gui.fgcolor->pixel = (Pixel) color; ! } ! /* ! * Set the current text background color. ! */ ! void ! gui_mch_set_bg_color(GuiColor color) ! { ! gui.bgcolor->pixel = (Pixel) color; } /* ! * Use the blank mouse pointer or not. ! * ! * hide: TRUE = use blank ptr, FALSE = use parent ptr */ void ! gui_mch_mousehide(int hide) { ! if (gui.pointer_hidden != hide) { ! if (gui.drawarea->window && gui.blank_pointer) { ! if (hide) ! gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer); ! else ! gdk_window_set_cursor(gui.drawarea->window, NULL); } ! gui.pointer_hidden = hide; } } void ! gui_mch_draw_string(int row, int col, char_u * s, int len, int flags) { ! GdkGC *gc; ! if (gui.current_font == NULL || gui.drawarea->window == NULL) return; ! #if defined(USE_FONTSET) && defined(MULTI_BYTE) ! if (gui.fontset) ! { ! if (col > 0 && mb_isbyte1(LinePointers[row], col - 1)) ! { ! col++; ! len--; ! s++; ! } ! if (len == 1 && IsLeadByte(*s)) ! len = 2; ! } ! #endif ! ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! ! if (flags & DRAW_TRANSP) { ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_draw_text(gui.drawarea->window, ! gui.current_font, ! gc, ! TEXT_X(col), TEXT_Y(row), ! (const gchar *)s, len); } else { ! int width; ! int height; ! width = gdk_text_width(gui.current_font, (const gchar *)s, len); ! height = gui.char_height; ! gdk_gc_set_foreground(gc, gui.bgcolor); ! gdk_draw_rectangle(gui.drawarea->window, ! gc, ! TRUE, ! FILL_X(col), FILL_Y(row), width, height); gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_draw_text(gui.drawarea->window, ! gui.current_font, ! gc, ! TEXT_X(col), TEXT_Y(row), ! (const gchar *)s, len); ! } ! /* redraw the contents with an offset of 1 to emulate bold */ ! if (flags & DRAW_BOLD) { ! gdk_draw_text(gui.drawarea->window, ! gui.current_font, ! gc, ! TEXT_X(col) + 1, TEXT_Y(row), ! (const gchar *)s, len); ! } ! if (flags & DRAW_UNDERL) { ! gdk_draw_line(gui.drawarea->window, ! gc, FILL_X(col), ! FILL_Y(row + 1) - 1, FILL_X(col + len) - 1, FILL_Y(row + 1) - 1); } + gdk_gc_destroy(gc); } /* ! * Return OK if the key with the termcap name "name" is supported. */ ! int ! gui_mch_haskey(char_u * name) { ! int i; ! for (i = 0; special_keys[i].key_sym != 0; i++) ! if (name[0] == special_keys[i].code0 && ! name[1] == special_keys[i].code1) ! return OK; ! return FAIL; ! } ! ! #if defined(WANT_TITLE) || defined(PROTO) ! /* ! * Return the text window-id and display. Only required for X-based GUI's ! */ ! int ! gui_get_x11_windis(Window * win, Display ** dis) ! { ! /* ! * This is currently only used by the code which is handling the ! * window manager title of this program. ! */ ! *dis = GDK_DISPLAY(); ! if (gui.mainwin->window) { ! *win = GDK_WINDOW_XWINDOW(gui.mainwin->window); ! return OK; } + *win = 0; + return FAIL; } + #endif void ! gui_mch_beep() { ! gdk_beep(); ! } ! ! void ! gui_mch_flash() ! { ! GdkGCValues values; ! GdkGC *invert_gc; ! GdkColor foreground; ! GdkColor background; ! ! if (gui.drawarea->window == NULL) ! return; ! ! foreground.pixel = gui.norm_pixel ^ gui.back_pixel; ! background.pixel = gui.norm_pixel ^ gui.back_pixel; ! ! values.foreground = foreground; ! values.background = background; ! values.function = GDK_XOR; ! invert_gc = gdk_gc_new_with_values(gui.drawarea->window, ! &values, ! GDK_GC_FOREGROUND | ! GDK_GC_BACKGROUND | ! GDK_GC_FUNCTION); ! gdk_gc_set_exposures(invert_gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! ! /* Do a visual beep by changing back and forth in some undetermined way, ! * the foreground and background colors. This is due to the fact that ! * there can't be really any prediction about the effects of XOR on ! * arbitrary X11 servers. However this seems to be enought for what we ! * intend it to do. ! */ ! gdk_draw_rectangle(gui.drawarea->window, invert_gc, ! TRUE, ! 0, 0, ! FILL_X((int) Columns) + gui.border_offset, ! FILL_Y((int) Rows) + gui.border_offset); ! ! gdk_flush(); ! ui_delay(20L, TRUE); /* wait 1/50 of a second */ ! gdk_draw_rectangle(gui.drawarea->window, invert_gc, ! TRUE, ! 0, 0, ! FILL_X((int) Columns) + gui.border_offset, ! FILL_Y((int) Rows) + gui.border_offset); ! ! gdk_gc_destroy(invert_gc); } /* ! * Invert a rectangle from row r, column c, for nr rows and nc columns. */ ! void ! gui_mch_invert_rectangle(int r, int c, int nr, int nc) { ! GdkGCValues values; ! GdkGC *invert_gc; ! GdkColor foreground; ! GdkColor background; ! if (gui.drawarea->window == NULL) ! return; ! ! foreground.pixel = gui.norm_pixel ^ gui.back_pixel; ! background.pixel = gui.norm_pixel ^ gui.back_pixel; ! ! values.foreground = foreground; ! values.background = background; ! values.function = GDK_XOR; ! invert_gc = gdk_gc_new_with_values(gui.drawarea->window, ! &values, ! GDK_GC_FOREGROUND | ! GDK_GC_BACKGROUND | ! GDK_GC_FUNCTION); ! gdk_gc_set_exposures(invert_gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_draw_rectangle(gui.drawarea->window, invert_gc, ! TRUE, ! FILL_X(c), FILL_Y(r), ! (nc) * gui.char_width, (nr) * gui.char_height); ! gdk_gc_destroy(invert_gc); } /* ! * Iconify the GUI window. */ void ! gui_mch_iconify() { ! XIconifyWindow(GDK_DISPLAY(), ! GDK_WINDOW_XWINDOW(gui.mainwin->window), ! DefaultScreen(GDK_DISPLAY())); } /* ! * Draw a cursor without focus. */ void ! gui_mch_draw_hollow_cursor(GuiColor color) { ! GdkGC *gc; ! ! if (gui.drawarea->window == NULL) return; ! gui_mch_set_fg_color(color); ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! #if defined(USE_FONTSET) && defined(MULTI_BYTE) ! if (gui.fontset) ! { ! if (IsLeadByte(LinePointers[gui.row][gui.col]) ! # ifdef HANGUL_INPUT ! || composing_hangul ! # endif ! ) ! gdk_draw_rectangle(gui.drawarea->window, gc, ! FALSE, ! FILL_X(gui.col), FILL_Y(gui.row), ! 2*gui.char_width - 1, gui.char_height - 1); ! else ! gdk_draw_rectangle(gui.drawarea->window, gc, ! FALSE, ! FILL_X(gui.col), FILL_Y(gui.row), ! gui.char_width - 1, gui.char_height - 1); ! } ! else ! #endif ! gdk_draw_rectangle(gui.drawarea->window, gc, ! FALSE, ! FILL_X(gui.col), FILL_Y(gui.row), ! gui.char_width - 1, gui.char_height - 1); ! gdk_gc_destroy(gc); } /* ! * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using ! * color "color". */ void ! gui_mch_draw_part_cursor(int w, int h, GuiColor color) { ! GdkGC *gc; ! ! if (gui.drawarea->window == NULL) return; ! gui_mch_set_fg_color(color); ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_draw_rectangle(gui.drawarea->window, gc, ! TRUE, ! #ifdef RIGHTLEFT ! /* vertical line should be on the right of current point */ ! State != CMDLINE && curwin->w_p_rl ? FILL_X(gui.col + 1) - w : ! #endif ! FILL_X(gui.col), ! FILL_Y(gui.row) + gui.char_height - h, ! w, h); ! gdk_gc_destroy(gc); } ! #ifndef GTK_HAVE_FEATURES_1_1_0 ! static gint ! idle_function(GtkWidget * label) { ! if (gtk_main_level() > 0) ! gtk_main_quit(); ! ! return FALSE; } #endif + /* ! * Catch up with any queued X11 events. This may put keyboard input into the ! * input buffer, call resize call-backs, trigger timers etc. If there is ! * nothing in the X11 event queue (& no timers pending), then we return ! * immediately. */ void ! gui_mch_update() { ! #ifdef GTK_HAVE_FEATURES_1_1_0 ! while (gtk_events_pending() && !vim_is_input_buf_full()) ! gtk_main_iteration_do(FALSE); ! #else ! int pending; ! ! /* Somehow the above loop hangs on GTK 1.0.6. Use the idle_function() to ! * work around this weird problem. */ ! while (((pending = gtk_events_pending()) > 1) && !vim_is_input_buf_full()) ! gtk_main_iteration(); ! ! if ((pending == 1) && !vim_is_input_buf_full()) { ! gtk_idle_add((GtkFunction)idle_function, gui.mainwin); ! gtk_main_iteration_do(FALSE); ! } ! #endif } + static gint + input_timer_cb(gpointer data) + { + int *timed_out = (int *) data; + + /* Just inform the caller about the accurence of it */ + *timed_out = TRUE; + + if (gtk_main_level() > 0) + gtk_main_quit(); + + return FALSE; /* don't happen again */ + } /* ! * GUI input routine called by gui_wait_for_chars(). Waits for a character ! * from the keyboard. ! * wtime == -1 Wait forever. ! * wtime == 0 This should never happen. ! * wtime > 0 Wait wtime milliseconds for a character. ! * Returns OK if a character was found to be available within the given time, ! * or FAIL otherwise. */ int ! gui_mch_wait_for_chars(long wtime) { ! int focus; ! guint timer; ! static int timed_out; ! timed_out = FALSE; ! ! /* this timeout makes sure that we will return if no characters arrived in ! * time */ ! ! if (wtime > 0) ! timer = gtk_timeout_add((guint32)wtime, input_timer_cb, &timed_out); ! else ! timer = 0; ! ! focus = gui.in_focus; ! ! do { ! /* Stop or start blinking when focus changes */ ! if (gui.in_focus != focus) { ! if (gui.in_focus) ! gui_mch_start_blink(); ! else ! gui_mch_stop_blink(); ! focus = gui.in_focus; ! } ! ! /* ! * Loop in GTK+ processing until a timeout or input occurs. ! */ ! gtk_main(); ! ! /* Got char, return immediately */ ! if (!vim_is_input_buf_empty()) { ! if (timer != 0 && !timed_out) ! gtk_timeout_remove(timer); ! return OK; ! } ! } while (wtime < 0 || !timed_out); ! ! /* ! * Flush all eventually pending (drawing) events. ! */ ! gui_mch_update(); ! ! return FAIL; ! } ! ! ! /**************************************************************************** ! * Output drawing routines. ! ****************************************************************************/ ! ! ! /* Flush any output to the screen */ ! void ! gui_mch_flush() ! { ! gdk_flush(); } /* ! * Clear a rectangular region of the screen from text pos (row1, col1) to ! * (row2, col2) inclusive. */ ! void ! gui_mch_clear_block(int row1, int col1, int row2, int col2) { ! GdkGC *gc; ! GdkColor color; ! ! if (gui.drawarea->window == NULL) ! return; ! ! color.pixel = gui.back_pixel; ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, &color); ! /* ! * Clear one extra pixel at the right, for when bold characters have ! * spilled over to the next column. This can erase part of the next ! * character however in the usage context of this function it will be ! * overriden immediately by the correct character again. ! */ ! gdk_draw_rectangle(gui.drawarea->window, gc, TRUE, ! FILL_X(col1), FILL_Y(row1), ! (col2 - col1 + 1) * gui.char_width + 1, ! (row2 - row1 + 1) * gui.char_height); ! gdk_gc_destroy(gc); ! } ! void ! gui_mch_clear_all(void) ! { ! if (gui.drawarea->window == NULL) ! return; ! gdk_window_clear(gui.drawarea->window); } /* ! * Scroll the text between gui.scroll_region_top & gui.scroll_region_bot by the ! * number of lines given. Positive scrolls down (text goes up) and negative ! * scrolls up (text goes down). */ ! static void check_copy_area(void) { ! XEvent event; ! XGraphicsExposeEvent *gevent; ! if (gui.visibility != GDK_VISIBILITY_PARTIAL) ! return; ! gdk_flush(); ! ! /* Wait to check whether the scroll worked or not. */ ! for (;;) { ! if (XCheckTypedEvent(GDK_DISPLAY(), NoExpose, &event)) ! return; /* The scroll worked. */ ! if (XCheckTypedEvent(GDK_DISPLAY(), GraphicsExpose, &event)) { ! gevent = (XGraphicsExposeEvent *) & event; ! gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height); ! if (gevent->count == 0) ! return; /* This was the last expose event */ ! } ! gdk_flush(); ! } } + /* + * Delete the given number of lines from the given row, scrolling up any + * text further down within the scroll region. + */ void ! gui_mch_delete_lines(int row, int num_lines) { ! if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED) ! return; /* Can't see the window */ + if (num_lines <= 0) + return; ! if (row + num_lines > gui.scroll_region_bot) { ! /* Scrolled out of region, just blank the lines out */ ! gui_clear_block(row, 0, gui.scroll_region_bot, (int) Columns - 1); ! } else { ! GdkGC *gc; ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_gc_set_background(gc, gui.bgcolor); ! /* copy one extra pixel, for when bold has spilled over */ ! gdk_window_copy_area(gui.drawarea->window, gc, ! FILL_X(0), FILL_Y(row), ! gui.drawarea->window, ! FILL_X(0), FILL_Y(row + num_lines), ! gui.char_width * (int) Columns + 1, ! gui.char_height * ! (gui.scroll_region_bot - row - num_lines + 1)); ! gdk_gc_destroy(gc); ! /* Update gui.cursor_row if the cursor scrolled or copied over */ ! if (gui.cursor_row >= row) { ! if (gui.cursor_row < row + num_lines) ! gui.cursor_is_valid = FALSE; ! else if (gui.cursor_row <= gui.scroll_region_bot) ! gui.cursor_row -= num_lines; ! } ! gui_clear_block(gui.scroll_region_bot - num_lines + 1, 0, ! gui.scroll_region_bot, (int) Columns - 1); ! check_copy_area(); ! } } /* ! * Insert the given number of lines before the given row, scrolling down any ! * following text within the scroll region. */ ! void ! gui_mch_insert_lines(int row, int num_lines) { ! if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED) ! return; /* Can't see the window */ ! if (num_lines <= 0) ! return; ! if (row + num_lines > gui.scroll_region_bot) { ! /* Scrolled out of region, just blank the lines out */ ! gui_clear_block(row, 0, gui.scroll_region_bot, (int) Columns - 1); ! } else { ! GdkGC *gc; ! gc = gdk_gc_new(gui.drawarea->window); ! gdk_gc_set_exposures(gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED); ! gdk_gc_set_foreground(gc, gui.fgcolor); ! gdk_gc_set_background(gc, gui.bgcolor); + /* copy one extra pixel, for when bold has spilled over */ + gdk_window_copy_area(gui.drawarea->window, gc, + FILL_X(0), FILL_Y(row + num_lines), + gui.drawarea->window, + FILL_X(0), FILL_Y(row), + gui.char_width * (int) Columns + 1, + gui.char_height * + (gui.scroll_region_bot - row - num_lines + 1)); + gdk_gc_destroy(gc); ! /* Update gui.cursor_row if the cursor scrolled or copied over */ ! if (gui.cursor_row >= gui.row) { ! if (gui.cursor_row <= gui.scroll_region_bot - num_lines) ! gui.cursor_row += num_lines; ! else if (gui.cursor_row <= gui.scroll_region_bot) ! gui.cursor_is_valid = FALSE; ! } ! gui_clear_block(row, 0, row + num_lines - 1, (int) Columns - 1); ! check_copy_area(); } + } ! /* ! * X Selection stuff, for cutting and pasting text to other windows. ! */ ! void ! clip_mch_request_selection() ! { ! /* First try to get the content of our own special clipboard. */ ! received_selection = RS_NONE; ! (void)gtk_selection_convert(gui.drawarea, ! GDK_SELECTION_PRIMARY, clipboard.atom, ! (guint32)GDK_CURRENT_TIME); ! while (received_selection == RS_NONE) ! gtk_main(); /* wait for selection_received_event */ ! if (received_selection == RS_FAIL) { ! /* Now try to get it out of the usual string selection. */ ! received_selection = RS_NONE; ! (void)gtk_selection_convert(gui.drawarea, GDK_SELECTION_PRIMARY, ! GDK_TARGET_STRING, ! (guint32)GDK_CURRENT_TIME); ! while (received_selection == RS_NONE) ! gtk_main(); /* wait for selection_received_event */ } + } ! void ! clip_mch_lose_selection() ! { ! gtk_selection_owner_set(gui.drawarea, ! GDK_SELECTION_PRIMARY, (guint32)GDK_CURRENT_TIME); ! gui_mch_update(); ! } ! /* ! * Check whatever we allready own the selection. ! */ ! int ! clip_mch_own_selection() ! { ! #if 0 ! return gdk_selection_owner_get( ! GDK_SELECTION_PRIMARY) == gui.drawarea->window; ! #else ! /* At this point we always already own the clipboard */ ! return OK; ! #endif } /* ! * Send the current selection to the clipboard. */ ! void ! clip_mch_set_selection() { ! gtk_selection_owner_set(gui.drawarea, ! GDK_SELECTION_PRIMARY, ! (guint32)GDK_CURRENT_TIME); ! gui_mch_update(); ! } ! #if defined(WANT_MENU) || defined(PROTO) ! /* ! * Make a menu item appear either active or not active (grey or not grey). ! */ ! void ! gui_mch_menu_grey(VimMenu * menu, int grey) ! { ! if (menu->id == 0) ! return; ! gui_mch_menu_hidden(menu, FALSE); ! gtk_widget_set_sensitive(menu->id, !grey); ! gui_mch_update(); } ! /* ! * Make menu item hidden or not hidden. ! */ ! void ! gui_mch_menu_hidden(VimMenu * menu, int hidden) { ! if (menu->id == 0) ! return; ! if (hidden) { ! if (GTK_WIDGET_VISIBLE(menu->id)) ! gtk_widget_hide(menu->id); ! } else { ! if (!GTK_WIDGET_VISIBLE(menu->id)) ! gtk_widget_show(menu->id); } ! gui_mch_update(); } ! /* ! * This is called after setting all the menus to grey/hidden or not. ! */ ! void ! gui_mch_draw_menubar() { ! /* just make sure that the visual changes get effect immediately */ ! gui_mch_update(); } + #endif /* ! * Scrollbar stuff. */ ! void ! gui_mch_enable_scrollbar(GuiScrollbar * sb, int flag) { ! if (sb->id == 0) ! return; ! if (flag) ! gtk_widget_show(sb->id); ! else ! gtk_widget_hide(sb->id); ! update_window_manager_hints(); } + /* ! * Return the lightness of a pixel. White is 255. */ ! int ! gui_mch_get_lightness(GuiColor pixel) { ! XColor xc; ! GdkColormap *colormap; ! ! colormap = gtk_widget_get_colormap(gui.mainwin); ! xc.pixel = pixel; ! ! /* FIXME: this is crap in terms of actual accuracy */ ! XQueryColor(GDK_DISPLAY(), GDK_COLORMAP_XCOLORMAP(colormap), &xc); ! ! return (int) (xc.red * 3 + xc.green * 6 + xc.blue) / (10 * 256); } ! #if (defined(SYNTAX_HL) && defined(WANT_EVAL)) || defined(PROTO) ! /* ! * Return the RGB value of a pixel as "#RRGGBB". ! * ! * Unfortunately there appears to be no way to accomplish this entierly ! * without resorting to native X11 functions. */ ! char_u * ! gui_mch_get_rgb(GuiColor pixel) { ! XColor xc; ! GdkColormap *colormap; ! static char_u retval[10]; ! colormap = gtk_widget_get_colormap(gui.mainwin); ! xc.pixel = pixel; ! XQueryColor(GDK_DISPLAY(), GDK_COLORMAP_XCOLORMAP(colormap), &xc); ! ! sprintf((char *) retval, "#%02x%02x%02x", ! (unsigned) xc.red >> 8, ! (unsigned) xc.green >> 8, ! (unsigned) xc.blue >> 8); ! ! /* WOAH!!! Returning pointer to static string! Could be overwritten when ! * this function is called recursively (e.g., when some event occurs). */ ! return retval; } + #endif ! /* ! * Get current y mouse coordinate in text window. ! * Return -1 when unknown. ! */ ! int ! gui_mch_get_mouse_x(void) { ! int winx, winy; ! GdkModifierType mask; ! gdk_window_get_pointer(gui.drawarea->window, &winx, &winy, &mask); ! return winx; } ! int ! gui_mch_get_mouse_y(void) { ! int winx, winy; ! GdkModifierType mask; ! gdk_window_get_pointer(gui.drawarea->window, &winx, &winy, &mask); ! return winy; ! } ! ! void ! gui_mch_setmouse(int x, int y) ! { ! /* Sorry for the Xlib call, but we can't avoid it, since there is no ! * internal GDK mechanism present to accomplish this. ! */ ! XWarpPointer(GDK_DISPLAY(), (Window) 0, ! GDK_WINDOW_XWINDOW(gui.drawarea->window), 0, 0, 0, 0, x, y); } *** ../vim-5.6a.17/src/ui.c Mon Dec 20 09:59:15 1999 --- src/ui.c Sat Jan 8 20:56:28 2000 *************** *** 1156,1161 **** --- 1156,1169 ---- } #endif + #if defined(USE_GUI_GTK) || defined(PROTO) + int + vim_used_in_input_buf() + { + return inbufcount; + } + #endif + /* Add the given bytes to the input buffer */ void add_to_input_buf(s, len) *** ../vim-5.6a.17/src/proto/ui.pro Mon Dec 20 09:58:55 1999 --- src/proto/ui.pro Sat Jan 8 20:56:32 2000 *************** *** 30,35 **** --- 30,36 ---- int vim_is_input_buf_full __ARGS((void)); int vim_is_input_buf_empty __ARGS((void)); int vim_free_in_input_buf __ARGS((void)); + int vim_used_in_input_buf __ARGS((void)); void add_to_input_buf __ARGS((char_u *s, int len)); void push_raw_key __ARGS((char_u *s, int len)); void trash_input_buf __ARGS((void)); *** ../vim-5.6a.17/src/misc2.c Thu Dec 23 11:13:43 1999 --- src/misc2.c Sat Jan 8 21:27:11 2000 *************** *** 2031,2037 **** return State; } ! #if defined(MKSESSION) || defined(MSWIN) || defined(PROTO) /* * Change to a file's directory. */ --- 2031,2037 ---- return State; } ! #if defined(MKSESSION) || defined(MSWIN) || defined(USE_GUI_GTK) || defined(PROTO) /* * Change to a file's directory. */ *** ../vim-5.6a.17/src/version.c Sat Jan 8 22:58:58 2000 --- src/version.c Sat Jan 8 22:58:33 2000 *************** *** 420,421 **** --- 420,423 ---- { /* Add new patch number below this line */ + /**/ + 18, /**/ -- hundred-and-one symptoms of being an internet addict: 79. All of your most erotic dreams have a scrollbar at the right side. --/-/---- Bram Moolenaar ---- Bram@moolenaar.net ---- Bram@vim.org ---\-\-- \ \ www.vim.org/iccf www.moolenaar.net www.vim.org / /