@@ -5297,6 +5297,9 @@ typedef struct
52975297 GtkWidget * mcase ; // Match case check
52985298 GtkWidget * up ; // Direction up radio
52995299 GtkWidget * down ; // Direction down radio
5300+ GtkWidget * find ; // 'Find Next' action button
5301+ GtkWidget * replace ; // 'Replace With' action button
5302+ GtkWidget * all ; // 'Replace All' action button
53005303} SharedFindReplace ;
53015304
53025305static SharedFindReplace find_widgets = {0 };
@@ -5347,6 +5350,61 @@ dialog_destroyed_cb(GtkWidget *widget UNUSED, gpointer data)
53475350 * (GtkWidget * * )data = NULL ;
53485351}
53495352
5353+ static void
5354+ entry_changed_cb (GtkWidget * entry , GtkWidget * dialog )
5355+ {
5356+ const gchar * entry_text ;
5357+ gboolean nonempty ;
5358+
5359+ entry_text = gtk_editable_get_text (GTK_EDITABLE (entry ));
5360+
5361+ if (!entry_text )
5362+ return ; // Shouldn't happen
5363+
5364+ nonempty = (entry_text [0 ] != '\0' );
5365+
5366+ if (dialog == find_widgets .dialog )
5367+ gtk_widget_set_sensitive (find_widgets .find , nonempty );
5368+
5369+ if (dialog == repl_widgets .dialog )
5370+ {
5371+ gtk_widget_set_sensitive (repl_widgets .find , nonempty );
5372+ gtk_widget_set_sensitive (repl_widgets .replace , nonempty );
5373+ gtk_widget_set_sensitive (repl_widgets .all , nonempty );
5374+ }
5375+ }
5376+
5377+ static gboolean
5378+ find_key_pressed_cb (
5379+ GtkEventControllerKey * controller ,
5380+ guint keyval ,
5381+ guint keycode ,
5382+ GdkModifierType state ,
5383+ SharedFindReplace * frdp )
5384+ {
5385+ // If the user is holding one of the key modifiers we will just bail out,
5386+ // thus preserving the possibility of normal focus traversal.
5387+ if (state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK ))
5388+ return FALSE;
5389+
5390+ // the Escape key synthesizes a cancellation action
5391+ if (keyval == GDK_KEY_Escape )
5392+ {
5393+ // Destroy rather than hide the dialog: reusing a hidden toplevel loses
5394+ // window decorations on Wayland
5395+ gtk_window_destroy (GTK_WINDOW (frdp -> dialog ));
5396+ return TRUE;
5397+ }
5398+
5399+ return FALSE;
5400+ }
5401+
5402+ static void
5403+ entry_activate_cb (GtkWidget * widget UNUSED , void * udata )
5404+ {
5405+ gtk_widget_grab_focus (GTK_WIDGET (udata ));
5406+ }
5407+
53505408 static void
53515409find_replace_dialog_create (char_u * arg , int do_replace )
53525410{
@@ -5356,6 +5414,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53565414 int mcase = !p_ic ;
53575415 GtkWidget * vertbox , * grid , * hbox , * tmp , * btn ;
53585416 gboolean sensitive ;
5417+ GtkEventController * key_controller ;
53595418
53605419 frdp = do_replace ? & repl_widgets : & find_widgets ;
53615420 entry_text = get_find_dialog_text (arg , & wword , & mcase );
@@ -5368,7 +5427,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53685427 }
53695428
53705429 // If the dialog already exists, just raise it.
5371- if (frdp -> dialog )
5430+ if (frdp -> dialog != NULL )
53725431 {
53735432 if (entry_text != NULL )
53745433 {
@@ -5380,7 +5439,15 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53805439 (gboolean )mcase );
53815440 }
53825441 gtk_window_present (GTK_WINDOW (frdp -> dialog ));
5442+
5443+ // For :promptfind dialog, always give keyboard focus to 'what' entry.
5444+ // For :promptrepl dialog, give it to 'with' entry if 'what' has a
5445+ // non-empty entry; otherwise, to 'what' entry.
53835446 gtk_widget_grab_focus (frdp -> what );
5447+ if (do_replace && g_utf8_strlen (
5448+ gtk_editable_get_text (GTK_EDITABLE (frdp -> what )), -1 ) > 0 )
5449+ gtk_widget_grab_focus (frdp -> with );
5450+
53845451 vim_free (entry_text );
53855452 return ;
53865453 }
@@ -5392,7 +5459,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53925459 gtk_window_set_destroy_with_parent (GTK_WINDOW (frdp -> dialog ), TRUE);
53935460 gtk_window_set_title (GTK_WINDOW (frdp -> dialog ),
53945461 do_replace ? _ ("VIM - Search and Replace..." )
5395- : _ ("VIM - Search..." ));
5462+ : _ ("VIM - Search..." ));
53965463 gtk_window_set_resizable (GTK_WINDOW (frdp -> dialog ), FALSE);
53975464
53985465 g_signal_connect (frdp -> dialog , "destroy" ,
@@ -5433,7 +5500,17 @@ find_replace_dialog_create(char_u *arg, int do_replace)
54335500 frdp -> with = gtk_entry_new ();
54345501 gtk_widget_set_hexpand (frdp -> with , TRUE);
54355502 gtk_grid_attach (GTK_GRID (grid ), frdp -> with , 1 , 1 , 1 , 1 );
5503+ gtk_entry_set_activates_default (GTK_ENTRY (frdp -> with ), TRUE);
5504+
5505+ // Make the entry activation only change the input focus onto the
5506+ // with item.
5507+ gtk_entry_set_activates_default (GTK_ENTRY (frdp -> what ), FALSE);
5508+ g_signal_connect (G_OBJECT (frdp -> what ), "activate" ,
5509+ G_CALLBACK (entry_activate_cb ), frdp -> with );
54365510 }
5511+ else
5512+ // Make the entry activation do the search.
5513+ gtk_entry_set_activates_default (GTK_ENTRY (frdp -> what ), TRUE);
54375514
54385515 // Checkboxes
54395516 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL , 12 );
@@ -5472,20 +5549,36 @@ find_replace_dialog_create(char_u *arg, int do_replace)
54725549
54735550 btn = gtk_button_new_with_label (_ ("Find Next" ));
54745551 gtk_widget_set_sensitive (btn , sensitive );
5552+ frdp -> find = btn ;
5553+
5554+ key_controller = gtk_event_controller_key_new ();
5555+ g_signal_connect (key_controller , "key-pressed" ,
5556+ G_CALLBACK (find_key_pressed_cb ), frdp );
5557+ gtk_widget_add_controller (GTK_WIDGET (frdp -> dialog ), key_controller );
5558+
5559+ g_signal_connect (G_OBJECT (frdp -> what ), "changed" ,
5560+ G_CALLBACK (entry_changed_cb ), frdp -> dialog );
5561+
5562+ // Make it so that when entry is activated, this button will be activated.
5563+ gtk_window_set_default_widget (GTK_WINDOW (frdp -> dialog ), btn );
54755564 g_signal_connect (btn , "clicked" , G_CALLBACK (find_replace_cb ),
54765565 GINT_TO_POINTER (do_replace ? FRD_R_FINDNEXT : FRD_FINDNEXT ));
54775566 gtk_box_append (GTK_BOX (hbox ), btn );
54785567
54795568 if (do_replace )
54805569 {
54815570 btn = gtk_button_new_with_label (_ ("Replace" ));
5571+ gtk_widget_set_sensitive (btn , sensitive );
54825572 g_signal_connect (btn , "clicked" , G_CALLBACK (find_replace_cb ),
54835573 GINT_TO_POINTER (FRD_REPLACE ));
5574+ frdp -> replace = btn ;
54845575 gtk_box_append (GTK_BOX (hbox ), btn );
54855576
54865577 btn = gtk_button_new_with_label (_ ("Replace All" ));
5578+ gtk_widget_set_sensitive (btn , sensitive );
54875579 g_signal_connect (btn , "clicked" , G_CALLBACK (find_replace_cb ),
54885580 GINT_TO_POINTER (FRD_REPLACEALL ));
5581+ frdp -> all = btn ;
54895582 gtk_box_append (GTK_BOX (hbox ), btn );
54905583 }
54915584
@@ -5494,11 +5587,6 @@ find_replace_dialog_create(char_u *arg, int do_replace)
54945587 G_CALLBACK (gtk_window_destroy ), frdp -> dialog );
54955588 gtk_box_append (GTK_BOX (hbox ), btn );
54965589
5497- // Connect Enter key in entry to Find Next
5498- g_signal_connect_swapped (frdp -> what , "activate" ,
5499- G_CALLBACK (find_replace_cb ),
5500- GINT_TO_POINTER (do_replace ? FRD_R_FINDNEXT : FRD_FINDNEXT ));
5501-
55025590 gtk_window_present (GTK_WINDOW (frdp -> dialog ));
55035591 gtk_widget_grab_focus (frdp -> what );
55045592 if (do_replace && entry_text != NULL && entry_text [0 ] != NUL )
0 commit comments