all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Philipp Stephani <p.stephani2@gmail.com>
To: martin rudalics <rudalics@gmx.at>, 28189@debbugs.gnu.org
Subject: bug#28189: 26.0.50; Emacs uses deprecated function gtk_window_parse_geometry
Date: Fri, 25 Aug 2017 09:28:35 +0000	[thread overview]
Message-ID: <CAArVCkS793xfAwajWDaDsfYy=i9Bghzk_OW_57TVUwAvcTH9gQ@mail.gmail.com> (raw)
In-Reply-To: <CAArVCkQMp=BYh7-26UKOOD9Jo2Jj2pPPzt8XR_MEZfCBFynMew@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 428 bytes --]

Philipp Stephani <p.stephani2@gmail.com> schrieb am Do., 24. Aug. 2017 um
01:26 Uhr:

>
> I've attached the compilation log including all GTK-related error messages.
>

I've attached a patch that fixes all deprecation warnings. It's not
intended to be installed as-is, more as a baseline for discussion. Some of
the functions have straightforward replacements, others are harder to
replace, yet others have vanished altogether.

[-- Attachment #1.2: Type: text/html, Size: 849 bytes --]

[-- Attachment #2: 0001-Fix-all-GDK-GTK-warnings.txt --]
[-- Type: text/plain, Size: 16514 bytes --]

From 71874784ddd654dae24d6fce9303832c2ee17da2 Mon Sep 17 00:00:00 2001
From: Philipp Stephani <phst@google.com>
Date: Fri, 25 Aug 2017 11:08:25 +0200
Subject: [PATCH] Fix all GDK/GTK warnings

---
 src/gtkutil.c | 41 +++++++++++++++++++++++++++++++++++++++++
 src/xfns.c    | 36 +++++++++++++++++++++++++++++++++---
 src/xmenu.c   | 49 +++++++++++++++++++++++++++++++++++++++++++++----
 src/xterm.c   | 11 +++++++++++
 src/xterm.h   | 18 +++++++++++-------
 5 files changed, 141 insertions(+), 14 deletions(-)

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 0c8395efe9..648fc808c3 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -566,6 +566,11 @@ xg_check_special_colors (struct frame *f,
   if (! FRAME_GTK_WIDGET (f) || ! (get_bg || get_fg))
     return success_p;
 
+#if GTK_CHECK_VERSION (3, 16, 0)
+  if (get_bg)
+    return success_p;
+#endif
+
   block_input ();
   {
 #ifdef HAVE_GTK3
@@ -577,7 +582,11 @@ xg_check_special_colors (struct frame *f,
     if (get_fg)
       gtk_style_context_get_color (gsty, state, &col);
     else
+#if GTK_CHECK_VERSION (3, 16, 0)
+      emacs_abort ();
+#else
       gtk_style_context_get_background_color (gsty, state, &col);
+#endif
 
     unsigned short
       r = col.red * 65535,
@@ -792,6 +801,7 @@ xg_hide_tooltip (struct frame *f)
     General functions for creating widgets, resizing, events, e.t.c.
  ***********************************************************************/
 
+#if ! GTK_CHECK_VERSION (3, 22, 0)
 static void
 my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
 		const gchar *msg, gpointer user_data)
@@ -799,6 +809,7 @@ my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
   if (!strstr (msg, "visible children"))
     fprintf (stderr, "XX %s-WARNING **: %s\n", log_domain, msg);
 }
+#endif
 
 /* Make a geometry string and pass that to GTK.  It seems this is the
    only way to get geometry position right if the user explicitly
@@ -810,8 +821,10 @@ xg_set_geometry (struct frame *f)
 {
   if (f->size_hint_flags & (USPosition | PPosition))
     {
+#if ! GTK_CHECK_VERSION (3, 22, 0)
       if (x_gtk_use_window_move)
 	{
+#endif
 	  /* Handle negative positions without consulting
 	     gtk_window_parse_geometry (Bug#25851).  The position will
 	     be off by scrollbar width + window manager decorations.  */
@@ -828,6 +841,7 @@ xg_set_geometry (struct frame *f)
 
 	  /* Reset size hint flags.  */
 	  f->size_hint_flags &= ~ (XNegative | YNegative);
+# if ! GTK_CHECK_VERSION (3, 22, 0)
 	}
       else
 	{
@@ -859,6 +873,7 @@ xg_set_geometry (struct frame *f)
 
 	  g_log_remove_handler ("Gtk", id);
 	}
+#endif
     }
 }
 
@@ -1044,6 +1059,7 @@ static void
 xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel)
 {
 #ifdef HAVE_GTK3
+#if ! GTK_CHECK_VERSION (3, 22, 0)
   GdkRGBA bg;
   XColor xbg;
   xbg.pixel = pixel;
@@ -1055,6 +1071,7 @@ xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel)
       bg.alpha = 1.0;
       gtk_widget_override_background_color (w, GTK_STATE_FLAG_NORMAL, &bg);
     }
+#endif
 #else
   GdkColor bg;
   GdkColormap *map = gtk_widget_get_colormap (w);
@@ -1207,16 +1224,20 @@ xg_create_frame_widgets (struct frame *f)
   if (FRAME_EXTERNAL_TOOL_BAR (f))
     update_frame_tool_bar (f);
 
+#if ! GTK_CHECK_VERSION (3, 14, 0)
   /* We don't want this widget double buffered, because we draw on it
      with regular X drawing primitives, so from a GTK/GDK point of
      view, the widget is totally blank.  When an expose comes, this
      will make the widget blank, and then Emacs redraws it.  This flickers
      a lot, so we turn off double buffering.  */
   gtk_widget_set_double_buffered (wfixed, FALSE);
+#endif
 
+#if ! GTK_CHECK_VERSION (3, 22, 0)
   gtk_window_set_wmclass (GTK_WINDOW (wtop),
                           SSDATA (Vx_resource_name),
                           SSDATA (Vx_resource_class));
+#endif
 
   /* Add callback to do nothing on WM_DELETE_WINDOW.  The default in
      GTK is to destroy the widget.  We want Emacs to do that instead.  */
@@ -4079,8 +4100,10 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar,
 
         if (int_gtk_range_get_value (GTK_RANGE (wscroll)) != value)
           gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
+#if ! GTK_CHECK_VERSION (3, 18, 0)
         else if (changed)
           gtk_adjustment_changed (adj);
+#endif
 
         xg_ignore_gtk_scrollbar = 0;
 
@@ -4117,7 +4140,9 @@ xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
       gtk_adjustment_configure (adj, (gdouble) value, (gdouble) lower,
 				(gdouble) upper, (gdouble) step_increment,
 				(gdouble) page_increment, (gdouble) pagesize);
+#if ! GTK_CHECK_VERSION (3, 18, 0)
       gtk_adjustment_changed (adj);
+#endif
       unblock_input ();
     }
 }
@@ -4138,8 +4163,13 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
       GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
       GdkWindow *gwin;
 #ifdef HAVE_GTK3
+#if GTK_CHECK_VERSION (3, 20, 0)
+      GdkDevice *gdev
+        = gdk_seat_get_pointer (gdk_display_get_default_seat (gdpy));
+#else
       GdkDevice *gdev = gdk_device_manager_get_client_pointer
         (gdk_display_get_device_manager (gdpy));
+#endif
       gwin = gdk_device_get_window_at_position (gdev, NULL, NULL);
 #else
       gwin = gdk_display_get_window_at_pointer (gdpy, NULL, NULL);
@@ -4612,7 +4642,11 @@ xg_make_tool_item (struct frame *f,
   if (wimage && text_image)
     gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
 
+#if GTK_CHECK_VERSION (3, 20, 0)
+  gtk_widget_set_focus_on_click (wb, FALSE);
+#else
   gtk_button_set_focus_on_click (GTK_BUTTON (wb), FALSE);
+#endif
   gtk_button_set_relief (GTK_BUTTON (wb), GTK_RELIEF_NONE);
   gtk_container_add (GTK_CONTAINER (wb), vb);
   gtk_container_add (GTK_CONTAINER (weventbox), wb);
@@ -5229,6 +5263,12 @@ xg_initialize (void)
 
   settings = gtk_settings_get_for_screen (gdk_display_get_default_screen
                                           (gdk_display_get_default ()));
+#if GTK_CHECK_VERSION (3, 16, 0)
+  g_object_set (settings,
+                "gtk-menu-bar-accel", EMACS_CLASS,
+                "gtk-key-theme-name", "Emacs",
+                NULL);
+#else
   /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
      bindings.  It doesn't seem to be any way to remove properties,
      so we set it to "" which in means "no key".  */
@@ -5243,6 +5283,7 @@ xg_initialize (void)
                                     "gtk-key-theme-name",
                                     "Emacs",
                                     EMACS_CLASS);
+#endif
 
   /* Make dialogs close on C-g.  Since file dialog inherits from
      dialog, this works for them also.  */
diff --git a/src/xfns.c b/src/xfns.c
index 2f8c9c2541..9bea7a0228 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4884,7 +4884,9 @@ Internal use only, use `display-monitor-attributes-list' instead.  */)
 #ifdef USE_GTK
   double mm_width_per_pixel, mm_height_per_pixel;
   GdkDisplay *gdpy;
+#if ! GTK_CHECK_VERSION (3, 22, 0)
   GdkScreen *gscreen;
+#endif
   gint primary_monitor = 0, n_monitors, i;
   Lisp_Object monitor_frames, rest, frame;
   static const char *source = "Gdk";
@@ -4896,11 +4898,18 @@ Internal use only, use `display-monitor-attributes-list' instead.  */)
   mm_height_per_pixel = ((double) HeightMMOfScreen (dpyinfo->screen)
 			 / x_display_pixel_height (dpyinfo));
   gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+#if GTK_CHECK_VERSION (3, 22, 0)
+  /* FIXME: This function assumes that GdkMonitor objects are never
+   * destroyed, even if the monitor is unplugged.  That’s probably the
+   * case, but should be verified.  */
+  n_monitors = gdk_display_get_n_monitors (gdpy);
+#else
   gscreen = gdk_display_get_default_screen (gdpy);
 #if GTK_CHECK_VERSION (2, 20, 0)
   primary_monitor = gdk_screen_get_primary_monitor (gscreen);
 #endif
   n_monitors = gdk_screen_get_n_monitors (gscreen);
+#endif
   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
   monitors = xzalloc (n_monitors * sizeof *monitors);
 
@@ -4913,7 +4922,14 @@ Internal use only, use `display-monitor-attributes-list' instead.  */)
 	{
 	  GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
 
+#if GTK_CHECK_VERSION (3, 22, 0)
+          for (i = 0; i < n_monitors; i++)
+            if (gdk_display_get_monitor_at_window (gdpy, gwin)
+                == gdk_display_get_monitor (gdpy, i))
+              break;
+#else
 	  i = gdk_screen_get_monitor_at_window (gscreen, gwin);
+#endif
 	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
 	}
     }
@@ -4924,9 +4940,19 @@ Internal use only, use `display-monitor-attributes-list' instead.  */)
       GdkRectangle rec, work;
       struct MonitorInfo *mi = &monitors[i];
 
+#if GTK_CHECK_VERSION (3, 22, 0)
+      GdkMonitor *monitor = gdk_display_get_monitor (gdpy, i);
+      if (gdk_monitor_is_primary (monitor))
+        primary_monitor = i;
+      gdk_monitor_get_geometry (monitor, &rec);
+#else
       gdk_screen_get_monitor_geometry (gscreen, i, &rec);
+#endif
 
-#if GTK_CHECK_VERSION (2, 14, 0)
+#if GTK_CHECK_VERSION (3, 22, 0)
+      width_mm = gdk_monitor_get_width_mm (monitor);
+      height_mm = gdk_monitor_get_height_mm (monitor);
+#elif GTK_CHECK_VERSION (2, 14, 0)
       width_mm = gdk_screen_get_monitor_width_mm (gscreen, i);
       height_mm = gdk_screen_get_monitor_height_mm (gscreen, i);
 #endif
@@ -4935,7 +4961,9 @@ Internal use only, use `display-monitor-attributes-list' instead.  */)
       if (height_mm < 0)
 	height_mm = rec.height * mm_height_per_pixel + 0.5;
 
-#if GTK_CHECK_VERSION (3, 4, 0)
+#if GTK_CHECK_VERSION (3, 22, 0)
+      gdk_monitor_get_workarea (monitor, &work);
+#elif GTK_CHECK_VERSION (3, 4, 0)
       gdk_screen_get_monitor_workarea (gscreen, i, &work);
 #else
       /* Emulate the behavior of GTK+ 3.4.  */
@@ -4968,7 +4996,9 @@ Internal use only, use `display-monitor-attributes-list' instead.  */)
       mi->mm_width = width_mm;
       mi->mm_height = height_mm;
 
-#if GTK_CHECK_VERSION (2, 14, 0)
+#if GTK_CHECK_VERSION (3, 22, 0)
+      mi->name = g_strdup (gdk_monitor_get_model (monitor));
+#elif GTK_CHECK_VERSION (2, 14, 0)
       mi->name = gdk_screen_get_monitor_plug_name (gscreen, i);
 #endif
     }
diff --git a/src/xmenu.c b/src/xmenu.c
index 64df151b28..2b1ef4a29d 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1145,6 +1145,7 @@ struct next_popup_x_y
   int y;
 };
 
+#if ! GTK_CHECK_VERSION (3, 22, 0)
 /* The menu position function to use if we are not putting a popup
    menu where the pointer is.
    MENU is the menu to pop up.
@@ -1203,6 +1204,7 @@ menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer
   if (data->y + req.height > max_y)
     *y -= data->y + req.height - max_y;
 }
+#endif
 
 static void
 popup_selection_callback (GtkWidget *widget, gpointer client_data)
@@ -1231,12 +1233,14 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
 {
   int i;
   GtkWidget *menu;
+#if ! GTK_CHECK_VERSION (3, 22, 0)
   GtkMenuPositionFunc pos_func = 0;  /* Pop up at pointer.  */
   struct next_popup_x_y popup_x_y;
+#endif
   ptrdiff_t specpdl_count = SPECPDL_INDEX ();
   bool use_pos_func = ! for_click;
 
-#ifdef HAVE_GTK3
+#if defined HAVE_GTK3 && ! GTK_CHECK_VERSION (3, 22, 0)
   /* Always use position function for Gtk3.  Otherwise menus may become
      too small to show anything.  */
   use_pos_func = true;
@@ -1253,13 +1257,16 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
 
   if (use_pos_func)
     {
-      Window dummy_window;
-
+#if ! GTK_CHECK_VERSION (3, 22, 0)
       /* Not invoked by a click.  pop up at x/y.  */
       pos_func = menu_position_func;
+#endif
 
-      /* Adjust coordinates to be root-window-relative.  */
+      /* Adjust coordinates to be root-window-relative, but not for
+       * GTK+ 3.22, where the menu position is frame-relative.  */
       block_input ();
+#if ! GTK_CHECK_VERSION (3, 22, 0)
+      Window dummy_window;
       XTranslateCoordinates (FRAME_X_DISPLAY (f),
 
                              /* From-window, to-window.  */
@@ -1271,15 +1278,18 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
 
                              /* Child of win.  */
                              &dummy_window);
+#endif
 #ifdef HAVE_GTK3
       /* Use window scaling factor to adjust position for hidpi screens. */
       x /= xg_get_scale (f);
       y /= xg_get_scale (f);
 #endif
       unblock_input ();
+#if ! GTK_CHECK_VERSION (3, 22, 0)
       popup_x_y.x = x;
       popup_x_y.y = y;
       popup_x_y.f = f;
+#endif
 
       i = 0;  /* gtk_menu_popup needs this to be 0 for a non-button popup.  */
     }
@@ -1296,8 +1306,39 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
   /* Display the menu.  */
   gtk_widget_show_all (menu);
 
+#if GTK_CHECK_VERSION (3, 22, 0)
+  /* FIXME: We should pass the GDK event to this function instead of
+   * synthesizing it.  */
+  GdkWindow *window = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkEvent *event = gdk_event_new (GDK_BUTTON_PRESS);
+  event->button.window = window;
+  event->button.time = FRAME_DISPLAY_INFO (f)->last_user_time;
+  event->button.button = i;
+  event->button.device
+    = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
+  if (for_click)
+    gtk_menu_popup_at_pointer (GTK_MENU (menu), event);
+  else
+    {
+      GtkRequisition req;
+      gtk_widget_get_preferred_size (menu, NULL, &req);
+      GdkRectangle rect = {
+        .x = x,
+        .y = y,
+        .width = req.width,
+        .height = req.height,
+      };
+      /* FIXME: Check whether the adjustments in menu_position_func
+       * are still needed.  */
+      gtk_menu_popup_at_rect (GTK_MENU (menu), window, &rect,
+                              GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_NORTH_WEST,
+                              event);
+    }
+#else
   gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
 		  FRAME_DISPLAY_INFO (f)->last_user_time);
+#endif
 
   record_unwind_protect_ptr (pop_down_menu, menu);
 
diff --git a/src/xterm.c b/src/xterm.c
index 77daa22ae0..4038c78c9c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -4018,7 +4018,13 @@ XTflash (struct frame *f)
        when the scroll bars and the edit widget share the same X window.  */
     GdkWindow *window = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
 #ifdef HAVE_GTK3
+#if GTK_CHECK_VERSION (3, 22, 0)
+    cairo_region_t *region = gdk_window_get_visible_region (window);
+    GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
+    cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
+#else
     cairo_t *cr = gdk_cairo_create (window);
+#endif
     cairo_set_source_rgb (cr, 1, 1, 1);
     cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
 #define XFillRectangle(d, win, gc, x, y, w, h) \
@@ -4132,7 +4138,12 @@ XTflash (struct frame *f)
 
 #ifdef USE_GTK
 #ifdef HAVE_GTK3
+#if GTK_CHECK_VERSION (3, 22, 0)
+      gdk_window_end_draw_frame (window, context);
+      cairo_region_destroy (region);
+#else
       cairo_destroy (cr);
+#endif
 #else
       g_object_unref (G_OBJECT (gc));
 #endif
diff --git a/src/xterm.h b/src/xterm.h
index 803feda99f..b40ed960b7 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -49,13 +49,6 @@ typedef Widget xt_or_gtk_widget;
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 
-/* Some definitions to reduce conditionals.  */
-typedef GtkWidget *xt_or_gtk_widget;
-#undef XSync
-#define XSync(d, b) do { gdk_window_process_all_updates (); \
-                         XSync (d, b);  } while (false)
-#endif /* USE_GTK */
-
 /* True iff GTK's version is at least I.J.K.  */
 #ifndef GTK_CHECK_VERSION
 # ifdef USE_GTK
@@ -69,6 +62,17 @@ typedef GtkWidget *xt_or_gtk_widget;
 # endif
 #endif
 
+/* Some definitions to reduce conditionals.  */
+typedef GtkWidget *xt_or_gtk_widget;
+#undef XSync
+#if GTK_CHECK_VERSION (3, 22, 0)
+#define XSync(d, b) do { XSync ((d), (b)); } while (false)
+#else
+#define XSync(d, b) do { gdk_window_process_all_updates (); \
+                         XSync (d, b);  } while (false)
+#endif
+#endif /* USE_GTK */
+
 /* The GtkTooltip API came in 2.12, but gtk-enable-tooltips in 2.14. */
 #if GTK_CHECK_VERSION (2, 14, 0)
 #define USE_GTK_TOOLTIP
-- 
2.14.1.342.g6490525c54-goog


  parent reply	other threads:[~2017-08-25  9:28 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-22 20:22 bug#28189: 26.0.50; Emacs uses deprecated function gtk_window_parse_geometry Philipp
2017-08-23  8:46 ` martin rudalics
2017-08-23 10:38   ` Philipp Stephani
2017-08-23 13:19     ` martin rudalics
2017-08-23 23:26       ` Philipp Stephani
2017-08-24  9:37         ` martin rudalics
2017-08-25  9:28         ` Philipp Stephani [this message]
2017-08-26  9:29           ` martin rudalics
2017-08-27 13:34             ` Philipp Stephani
2017-09-03 11:49               ` martin rudalics
2017-09-19 15:35                 ` Philipp Stephani
2017-09-19 16:38                   ` Philipp Stephani
2017-09-23 11:22               ` Philipp Stephani
2017-09-23 13:21                 ` martin rudalics
2017-09-23 13:28                   ` Eli Zaretskii
2017-09-23 16:32                     ` Philipp Stephani
2017-09-23 16:48                       ` Eli Zaretskii
2017-09-23 18:28                     ` martin rudalics
2017-09-23 18:31                       ` Eli Zaretskii
2017-09-23 16:36                   ` Philipp Stephani
2017-09-23 18:29                     ` martin rudalics

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAArVCkS793xfAwajWDaDsfYy=i9Bghzk_OW_57TVUwAvcTH9gQ@mail.gmail.com' \
    --to=p.stephani2@gmail.com \
    --cc=28189@debbugs.gnu.org \
    --cc=rudalics@gmx.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.