From ad9e12076b4806a195a8f37d502d02fc81c3ac14 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 13 Nov 2012 14:51:41 +0100
Subject: [PATCH] console: fix displaychangelisteners interface

Split callbacks into separate Ops struct.  Pass DisplayChangeListener
pointer as first argument to all callbacks.  Uninline a bunch of
display functions and move them from console.h to console.c

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 7c20b4a374d0016e3fce005690fb428354a56621)
[BR: BSC#1026612 CVE-2017-2633 (infrastructure patch)]
Signed-off-by: Bruce Rogers <brogers@suse.com>
---
 hw/qxl.c                   |  18 +++--
 include/ui/console.h       | 185 ++++++++++++---------------------------------
 include/ui/spice-display.h |   1 +
 trace-events               |   2 +
 ui/cocoa.m                 |  26 ++++---
 ui/console.c               | 131 ++++++++++++++++++++++++++++++++
 ui/curses.c                |  32 +++++---
 ui/sdl.c                   |  44 +++++++----
 ui/spice-display.c         |  19 +++--
 ui/vnc.c                   |  37 ++++++---
 vl.c                       |   6 +-
 11 files changed, 302 insertions(+), 199 deletions(-)

diff --git a/hw/qxl.c b/hw/qxl.c
index 0767f5c099..77bb3706c7 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1866,21 +1866,25 @@ static void qxl_vm_change_state_handler(void *opaque, int running,
 
 /* display change listener */
 
-static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
+static void display_update(DisplayChangeListener *dcl,
+                           struct DisplayState *ds,
+                           int x, int y, int w, int h)
 {
     if (qxl0->mode == QXL_MODE_VGA) {
         qemu_spice_display_update(&qxl0->ssd, x, y, w, h);
     }
 }
 
-static void display_resize(struct DisplayState *ds)
+static void display_resize(DisplayChangeListener *dcl,
+                           struct DisplayState *ds)
 {
     if (qxl0->mode == QXL_MODE_VGA) {
         qemu_spice_display_resize(&qxl0->ssd);
     }
 }
 
-static void display_refresh(struct DisplayState *ds)
+static void display_refresh(DisplayChangeListener *dcl,
+                            struct DisplayState *ds)
 {
     if (qxl0->mode == QXL_MODE_VGA) {
         qemu_spice_display_refresh(&qxl0->ssd);
@@ -1891,10 +1895,11 @@ static void display_refresh(struct DisplayState *ds)
     }
 }
 
-static DisplayChangeListener display_listener = {
+static DisplayChangeListenerOps display_listener_ops = {
+    .dpy_name        = "spice/qxl",
     .dpy_gfx_update  = display_update,
     .dpy_gfx_resize  = display_resize,
-    .dpy_refresh = display_refresh,
+    .dpy_refresh     = display_refresh,
 };
 
 static void qxl_init_ramsize(PCIQXLDevice *qxl)
@@ -2077,7 +2082,8 @@ static int qxl_init_primary(PCIDevice *dev)
         return rc;
     }
 
-    register_displaychangelistener(vga->ds, &display_listener);
+    qxl->ssd.dcl.ops = &display_listener_ops;
+    register_displaychangelistener(vga->ds, &qxl->ssd.dcl);
     return rc;
 }
 
diff --git a/include/ui/console.h b/include/ui/console.h
index d78b098199..058c96bad8 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -147,21 +147,42 @@ void cursor_set_mono(QEMUCursor *c,
 void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
 void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
 
+typedef struct DisplayChangeListenerOps {
+    const char *dpy_name;
+
+    void (*dpy_refresh)(DisplayChangeListener *dcl,
+                        struct DisplayState *s);
+
+    void (*dpy_gfx_update)(DisplayChangeListener *dcl,
+                           struct DisplayState *s,
+                           int x, int y, int w, int h);
+    void (*dpy_gfx_resize)(DisplayChangeListener *dcl,
+                           struct DisplayState *s);
+    void (*dpy_gfx_setdata)(DisplayChangeListener *dcl,
+                            struct DisplayState *s);
+    void (*dpy_text_cursor)(DisplayChangeListener *dcl,
+                            struct DisplayState *s,
+                            int x, int y);
+    void (*dpy_text_resize)(DisplayChangeListener *dcl,
+                            struct DisplayState *s,
+                            int w, int h);
+    void (*dpy_text_update)(DisplayChangeListener *dcl,
+                            struct DisplayState *s,
+                            int x, int y, int w, int h);
+
+    void (*dpy_mouse_set)(DisplayChangeListener *dcl,
+                          struct DisplayState *s,
+                          int x, int y, int on);
+    void (*dpy_cursor_define)(DisplayChangeListener *dcl,
+                              struct DisplayState *s,
+                              QEMUCursor *cursor);
+} DisplayChangeListenerOps;
+
 struct DisplayChangeListener {
     int idle;
     uint64_t gui_timer_interval;
-
-    void (*dpy_refresh)(struct DisplayState *s);
-
-    void (*dpy_gfx_update)(struct DisplayState *s, int x, int y, int w, int h);
-    void (*dpy_gfx_resize)(struct DisplayState *s);
-    void (*dpy_gfx_setdata)(struct DisplayState *s);
-    void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
-    void (*dpy_text_resize)(struct DisplayState *s, int w, int h);
-    void (*dpy_text_update)(struct DisplayState *s, int x, int y, int w, int h);
-
-    void (*dpy_mouse_set)(struct DisplayState *s, int x, int y, int on);
-    void (*dpy_cursor_define)(struct DisplayState *s, QEMUCursor *cursor);
+    const DisplayChangeListenerOps *ops;
+    DisplayState *ds;
 
     QLIST_ENTRY(DisplayChangeListener) next;
 };
@@ -207,132 +228,20 @@ static inline int is_buffer_shared(DisplaySurface *surface)
 
 void gui_setup_refresh(DisplayState *ds);
 
-static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
-{
-    QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
-    gui_setup_refresh(ds);
-    if (dcl->dpy_gfx_resize) {
-        dcl->dpy_gfx_resize(ds);
-    }
-}
-
-static inline void unregister_displaychangelistener(DisplayState *ds,
-                                                    DisplayChangeListener *dcl)
-{
-    QLIST_REMOVE(dcl, next);
-    gui_setup_refresh(ds);
-}
-
-static inline void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h)
-{
-    struct DisplayChangeListener *dcl;
-    int width = pixman_image_get_width(s->surface->image);
-    int height = pixman_image_get_height(s->surface->image);
-
-    x = MAX(x, 0);
-    y = MAX(y, 0);
-    x = MIN(x, width);
-    y = MIN(y, height);
-    w = MIN(w, width - x);
-    h = MIN(h, height - y);
-
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_gfx_update) {
-            dcl->dpy_gfx_update(s, x, y, w, h);
-        }
-    }
-}
-
-static inline void dpy_gfx_resize(DisplayState *s)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_gfx_resize) {
-            dcl->dpy_gfx_resize(s);
-        }
-    }
-}
-
-static inline void dpy_gfx_setdata(DisplayState *s)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_gfx_setdata) {
-            dcl->dpy_gfx_setdata(s);
-        }
-    }
-}
-
-static inline void dpy_refresh(DisplayState *s)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_refresh) {
-            dcl->dpy_refresh(s);
-        }
-    }
-}
-
-static inline void dpy_text_cursor(struct DisplayState *s, int x, int y)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_text_cursor) {
-            dcl->dpy_text_cursor(s, x, y);
-        }
-    }
-}
-
-static inline void dpy_text_update(DisplayState *s, int x, int y, int w, int h)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_text_update) {
-            dcl->dpy_text_update(s, x, y, w, h);
-        }
-    }
-}
-
-static inline void dpy_text_resize(DisplayState *s, int w, int h)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_text_resize) {
-            dcl->dpy_text_resize(s, w, h);
-        }
-    }
-}
-
-static inline void dpy_mouse_set(struct DisplayState *s, int x, int y, int on)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_mouse_set) {
-            dcl->dpy_mouse_set(s, x, y, on);
-        }
-    }
-}
-
-static inline void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_cursor_define) {
-            dcl->dpy_cursor_define(s, cursor);
-        }
-    }
-}
-
-static inline bool dpy_cursor_define_supported(struct DisplayState *s)
-{
-    struct DisplayChangeListener *dcl;
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->dpy_cursor_define) {
-            return true;
-        }
-    }
-    return false;
-}
+void register_displaychangelistener(DisplayState *ds,
+                                    DisplayChangeListener *dcl);
+void unregister_displaychangelistener(DisplayChangeListener *dcl);
+
+void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h);
+void dpy_gfx_resize(DisplayState *s);
+void dpy_gfx_setdata(DisplayState *s);
+void dpy_refresh(DisplayState *s);
+void dpy_text_cursor(struct DisplayState *s, int x, int y);
+void dpy_text_update(DisplayState *s, int x, int y, int w, int h);
+void dpy_text_resize(DisplayState *s, int w, int h);
+void dpy_mouse_set(struct DisplayState *s, int x, int y, int on);
+void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor);
+bool dpy_cursor_define_supported(struct DisplayState *s);
 
 static inline int ds_get_linesize(DisplayState *ds)
 {
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h
index 46f9530fe3..f2752aa25a 100644
--- a/include/ui/spice-display.h
+++ b/include/ui/spice-display.h
@@ -72,6 +72,7 @@ typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
 
 struct SimpleSpiceDisplay {
     DisplayState *ds;
+    DisplayChangeListener dcl;
     void *buf;
     int bufsize;
     QXLWorker *worker;
diff --git a/trace-events b/trace-events
index b3f57b7d74..23fe27c04a 100644
--- a/trace-events
+++ b/trace-events
@@ -960,6 +960,8 @@ dma_map_wait(void *dbs) "dbs=%p"
 # console.h
 displaysurface_free(void *display_state, void *display_surface) "state=%p surface=%p"
 displaysurface_resize(void *display_state, void *display_surface, int width, int height) "state=%p surface=%p %dx%d"
+displaychangelistener_register(void *dcl, const char *name) "%p [ %s ]"
+displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]"
 
 # vga.c
 ppm_save(const char *filename, void *display_surface) "%s surface=%p"
diff --git a/ui/cocoa.m b/ui/cocoa.m
index ca42413b34..b1fb30e7f9 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -969,7 +969,9 @@ int main (int argc, const char * argv[]) {
 
 
 #pragma mark qemu
-static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
+static void cocoa_update(DisplayChangeListener *dcl,
+                         DisplayState *ds,
+                         int x, int y, int w, int h)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
 
@@ -986,14 +988,16 @@ static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
     [cocoaView setNeedsDisplayInRect:rect];
 }
 
-static void cocoa_resize(DisplayState *ds)
+static void cocoa_resize(DisplayChangeListener *dcl,
+                         DisplayState *ds)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");
 
     [cocoaView resizeContentToWidth:(int)(ds_get_width(ds)) height:(int)(ds_get_height(ds)) displayState:ds];
 }
 
-static void cocoa_refresh(DisplayState *ds)
+static void cocoa_refresh(DisplayChangeListener *dcl,
+                          DisplayState *ds)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
 
@@ -1030,6 +1034,14 @@ static void cocoa_cleanup(void)
     g_free(dcl);
 }
 
+static const DisplayChangeListenerOps dcl_ops = {
+    .dpy_name          = "cocoa",
+    .dpy_gfx_update = cocoa_update;
+    .dpy_gfx_resize = cocoa_resize;
+    .dpy_gfx_setdata = cocoa_setdata;
+    .dpy_refresh = cocoa_refresh;
+};
+
 void cocoa_display_init(DisplayState *ds, int full_screen)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
@@ -1037,12 +1049,8 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
     dcl = g_malloc0(sizeof(DisplayChangeListener));
 
     // register vga output callbacks
-    dcl->dpy_gfx_update = cocoa_update;
-    dcl->dpy_gfx_resize = cocoa_resize;
-    dcl->dpy_refresh = cocoa_refresh;
-    dcl->dpy_gfx_setdata = cocoa_setdata;
-
-	register_displaychangelistener(ds, dcl);
+    dcl->ops = &dcl_ops;
+    register_displaychangelistener(ds, dcl);
 
     // register cleanup function
     atexit(cocoa_cleanup);
diff --git a/ui/console.c b/ui/console.c
index fb148a488a..e41a9f4729 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1374,6 +1374,137 @@ void qemu_free_displaysurface(DisplayState *ds)
     g_free(ds->surface);
 }
 
+void register_displaychangelistener(DisplayState *ds,
+                                    DisplayChangeListener *dcl)
+{
+    trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
+    dcl->ds = ds;
+    QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
+    gui_setup_refresh(ds);
+    if (dcl->ops->dpy_gfx_resize) {
+        dcl->ops->dpy_gfx_resize(dcl, ds);
+    }
+}
+
+void unregister_displaychangelistener(DisplayChangeListener *dcl)
+{
+    DisplayState *ds = dcl->ds;
+    trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
+    QLIST_REMOVE(dcl, next);
+    gui_setup_refresh(ds);
+}
+
+void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h)
+{
+    struct DisplayChangeListener *dcl;
+    int width = pixman_image_get_width(s->surface->image);
+    int height = pixman_image_get_height(s->surface->image);
+
+    x = MAX(x, 0);
+    y = MAX(y, 0);
+    x = MIN(x, width);
+    y = MIN(y, height);
+    w = MIN(w, width - x);
+    h = MIN(h, height - y);
+
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_gfx_update) {
+            dcl->ops->dpy_gfx_update(dcl, s, x, y, w, h);
+        }
+    }
+}
+
+void dpy_gfx_resize(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_gfx_resize) {
+            dcl->ops->dpy_gfx_resize(dcl, s);
+        }
+    }
+}
+
+void dpy_gfx_setdata(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_gfx_setdata) {
+            dcl->ops->dpy_gfx_setdata(dcl, s);
+        }
+    }
+}
+
+void dpy_refresh(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_refresh) {
+            dcl->ops->dpy_refresh(dcl, s);
+        }
+    }
+}
+
+void dpy_text_cursor(struct DisplayState *s, int x, int y)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_text_cursor) {
+            dcl->ops->dpy_text_cursor(dcl, s, x, y);
+        }
+    }
+}
+
+void dpy_text_update(DisplayState *s, int x, int y, int w, int h)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_text_update) {
+            dcl->ops->dpy_text_update(dcl, s, x, y, w, h);
+        }
+    }
+}
+
+void dpy_text_resize(DisplayState *s, int w, int h)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_text_resize) {
+            dcl->ops->dpy_text_resize(dcl, s, w, h);
+        }
+    }
+}
+
+void dpy_mouse_set(struct DisplayState *s, int x, int y, int on)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_mouse_set) {
+            dcl->ops->dpy_mouse_set(dcl, s, x, y, on);
+        }
+    }
+}
+
+void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_cursor_define) {
+            dcl->ops->dpy_cursor_define(dcl, s, cursor);
+        }
+    }
+}
+
+bool dpy_cursor_define_supported(struct DisplayState *s)
+{
+    struct DisplayChangeListener *dcl;
+    QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (dcl->ops->dpy_cursor_define) {
+            return true;
+        }
+    }
+    return false;
+}
+
 static void dumb_display_init(void)
 {
     DisplayState *ds = g_malloc0(sizeof(DisplayState));
diff --git a/ui/curses.c b/ui/curses.c
index d78e378440..ca9856ccef 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -35,12 +35,15 @@
 #define FONT_HEIGHT 16
 #define FONT_WIDTH 8
 
+static DisplayChangeListener *dcl;
 static console_ch_t screen[160 * 100];
 static WINDOW *screenpad = NULL;
 static int width, height, gwidth, gheight, invalidate;
 static int px, py, sminx, sminy, smaxx, smaxy;
 
-static void curses_update(DisplayState *ds, int x, int y, int w, int h)
+static void curses_update(DisplayChangeListener *dcl,
+                          DisplayState *ds,
+                          int x, int y, int w, int h)
 {
     chtype *line;
 
@@ -91,7 +94,9 @@ static void curses_calc_pad(void)
     }
 }
 
-static void curses_resize(DisplayState *ds, int width, int height)
+static void curses_resize(DisplayChangeListener *dcl,
+                          DisplayState *ds,
+                          int width, int height)
 {
     if (width == gwidth && height == gheight) {
         return;
@@ -128,7 +133,9 @@ static void curses_winch_handler(int signum)
 #endif
 #endif
 
-static void curses_cursor_position(DisplayState *ds, int x, int y)
+static void curses_cursor_position(DisplayChangeListener *dcl,
+                                   DisplayState *ds,
+                                   int x, int y)
 {
     if (x >= 0) {
         x = sminx + x - px;
@@ -154,7 +161,8 @@ static void curses_cursor_position(DisplayState *ds, int x, int y)
 
 static kbd_layout_t *kbd_layout = NULL;
 
-static void curses_refresh(DisplayState *ds)
+static void curses_refresh(DisplayChangeListener *dcl,
+                           DisplayState *ds)
 {
     int chr, nextchr, keysym, keycode, keycode_alt;
 
@@ -187,7 +195,7 @@ static void curses_refresh(DisplayState *ds)
             clear();
             refresh();
             curses_calc_pad();
-            curses_update(ds, 0, 0, width, height);
+            curses_update(dcl, ds, 0, 0, width, height);
             continue;
         }
 #endif
@@ -323,9 +331,16 @@ static void curses_keyboard_setup(void)
     }
 }
 
+static const DisplayChangeListenerOps dcl_ops = {
+    .dpy_name        = "curses",
+    .dpy_text_update = curses_update,
+    .dpy_text_resize = curses_resize,
+    .dpy_refresh     = curses_refresh,
+    .dpy_text_cursor = curses_cursor_position,
+};
+
 void curses_display_init(DisplayState *ds, int full_screen)
 {
-    DisplayChangeListener *dcl;
 #ifndef _WIN32
     if (!isatty(1)) {
         fprintf(stderr, "We need a terminal output\n");
@@ -346,10 +361,7 @@ void curses_display_init(DisplayState *ds, int full_screen)
 #endif
 
     dcl = (DisplayChangeListener *) g_malloc0(sizeof(DisplayChangeListener));
-    dcl->dpy_text_update = curses_update;
-    dcl->dpy_text_resize = curses_resize;
-    dcl->dpy_refresh = curses_refresh;
-    dcl->dpy_text_cursor = curses_cursor_position;
+    dcl->ops = &dcl_ops;
     register_displaychangelistener(ds, dcl);
 
     invalidate = 1;
diff --git a/ui/sdl.c b/ui/sdl.c
index 1657848e9f..5baffa0094 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -59,7 +59,9 @@ static SDL_PixelFormat host_format;
 static int scaling_active = 0;
 static Notifier mouse_mode_notifier;
 
-static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
+static void sdl_update(DisplayChangeListener *dcl,
+                       DisplayState *ds,
+                       int x, int y, int w, int h)
 {
     //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
     SDL_Rect rec;
@@ -81,7 +83,8 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
     SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
 }
 
-static void sdl_setdata(DisplayState *ds)
+static void sdl_setdata(DisplayChangeListener *dcl,
+                        DisplayState *ds)
 {
     if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
 
@@ -114,7 +117,8 @@ static void do_sdl_resize(int width, int height, int bpp)
     }
 }
 
-static void sdl_resize(DisplayState *ds)
+static void sdl_resize(DisplayChangeListener *dcl,
+                       DisplayState *ds)
 {
     if (!scaling_active) {
         do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
@@ -122,7 +126,7 @@ static void sdl_resize(DisplayState *ds)
         do_sdl_resize(real_screen->w, real_screen->h,
                       ds_get_bits_per_pixel(ds));
     }
-    sdl_setdata(ds);
+    sdl_setdata(dcl, ds);
 }
 
 /* generic keyboard conversion */
@@ -514,7 +518,7 @@ static void handle_keydown(DisplayState *ds, SDL_Event *ev)
         case 0x16: /* 'u' key on US keyboard */
             if (scaling_active) {
                 scaling_active = 0;
-                sdl_resize(ds);
+                sdl_resize(dcl, ds);
                 vga_hw_invalidate();
                 vga_hw_update();
             }
@@ -753,7 +757,8 @@ static void handle_activation(DisplayState *ds, SDL_Event *ev)
     }
 }
 
-static void sdl_refresh(DisplayState *ds)
+static void sdl_refresh(DisplayChangeListener *dcl,
+                        DisplayState *ds)
 {
     SDL_Event ev1, *ev = &ev1;
 
@@ -768,7 +773,7 @@ static void sdl_refresh(DisplayState *ds)
     while (SDL_PollEvent(ev)) {
         switch (ev->type) {
         case SDL_VIDEOEXPOSE:
-            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
+            sdl_update(dcl, ds, 0, 0, real_screen->w, real_screen->h);
             break;
         case SDL_KEYDOWN:
             handle_keydown(ds, ev);
@@ -803,7 +808,9 @@ static void sdl_refresh(DisplayState *ds)
     }
 }
 
-static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on)
+static void sdl_mouse_warp(DisplayChangeListener *dcl,
+                           DisplayState *ds,
+                           int x, int y, int on)
 {
     if (on) {
         if (!guest_cursor)
@@ -819,7 +826,9 @@ static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on)
     guest_x = x, guest_y = y;
 }
 
-static void sdl_mouse_define(DisplayState *ds, QEMUCursor *c)
+static void sdl_mouse_define(DisplayChangeListener *dcl,
+                             DisplayState *ds,
+                             QEMUCursor *c)
 {
     uint8_t *image, *mask;
     int bpl;
@@ -849,6 +858,16 @@ static void sdl_cleanup(void)
     SDL_QuitSubSystem(SDL_INIT_VIDEO);
 }
 
+static const DisplayChangeListenerOps dcl_ops = {
+    .dpy_name          = "sdl",
+    .dpy_gfx_update    = sdl_update,
+    .dpy_gfx_resize    = sdl_resize,
+    .dpy_refresh       = sdl_refresh,
+    .dpy_gfx_setdata   = sdl_setdata,
+    .dpy_mouse_set     = sdl_mouse_warp,
+    .dpy_cursor_define = sdl_mouse_define,
+};
+
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
 {
     int flags;
@@ -917,12 +936,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     }
 
     dcl = g_malloc0(sizeof(DisplayChangeListener));
-    dcl->dpy_gfx_update = sdl_update;
-    dcl->dpy_gfx_resize = sdl_resize;
-    dcl->dpy_refresh = sdl_refresh;
-    dcl->dpy_gfx_setdata = sdl_setdata;
-    dcl->dpy_mouse_set = sdl_mouse_warp;
-    dcl->dpy_cursor_define = sdl_mouse_define;
+    dcl->ops = &dcl_ops;
     register_displaychangelistener(ds, dcl);
 
     mouse_mode_notifier.notify = sdl_mouse_mode_change;
diff --git a/ui/spice-display.c b/ui/spice-display.c
index dc7e58d0ed..b6528fae78 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -583,25 +583,30 @@ static const QXLInterface dpy_interface = {
 
 static SimpleSpiceDisplay sdpy;
 
-static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
+static void display_update(DisplayChangeListener *dcl,
+                           struct DisplayState *ds,
+                           int x, int y, int w, int h)
 {
     qemu_spice_display_update(&sdpy, x, y, w, h);
 }
 
-static void display_resize(struct DisplayState *ds)
+static void display_resize(DisplayChangeListener *dcl,
+                           struct DisplayState *ds)
 {
     qemu_spice_display_resize(&sdpy);
 }
 
-static void display_refresh(struct DisplayState *ds)
+static void display_refresh(DisplayChangeListener *dcl,
+                            struct DisplayState *ds)
 {
     qemu_spice_display_refresh(&sdpy);
 }
 
-static DisplayChangeListener display_listener = {
+static const DisplayChangeListenerOps display_listener_ops = {
+    .dpy_name        = "spice",
     .dpy_gfx_update  = display_update,
     .dpy_gfx_resize  = display_resize,
-    .dpy_refresh = display_refresh,
+    .dpy_refresh     = display_refresh,
 };
 
 void qemu_spice_display_init(DisplayState *ds)
@@ -615,5 +620,7 @@ void qemu_spice_display_init(DisplayState *ds)
 
     qemu_spice_create_host_memslot(&sdpy);
     qemu_spice_create_host_primary(&sdpy);
-    register_displaychangelistener(ds, &display_listener);
+
+    sdpy.dcl.ops = &display_listener_ops;
+    register_displaychangelistener(ds, &sdpy.dcl);
 }
diff --git a/ui/vnc.c b/ui/vnc.c
index f26bc6d9d2..2a43535526 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -430,7 +430,9 @@ static void framebuffer_update_request(VncState *vs, int incremental,
 static void vnc_refresh(void *opaque);
 static int vnc_refresh_server_surface(VncDisplay *vd);
 
-static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+static void vnc_dpy_update(DisplayChangeListener *dcl,
+                           DisplayState *ds,
+                           int x, int y, int w, int h)
 {
     int i;
     VncDisplay *vd = ds->opaque;
@@ -573,7 +575,8 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
     return ptr;
 }
 
-static void vnc_dpy_resize(DisplayState *ds)
+static void vnc_dpy_resize(DisplayChangeListener *dcl,
+                           DisplayState *ds)
 {
     VncDisplay *vd = ds->opaque;
     VncState *vs;
@@ -721,7 +724,9 @@ int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
     return n;
 }
 
-static void vnc_mouse_set(DisplayState *ds, int x, int y, int visible)
+static void vnc_mouse_set(DisplayChangeListener *dcl,
+                          DisplayState *ds,
+                          int x, int y, int visible)
 {
     /* can we ask the client(s) to move the pointer ??? */
 }
@@ -747,7 +752,9 @@ static int vnc_cursor_define(VncState *vs)
     return -1;
 }
 
-static void vnc_dpy_cursor_define(DisplayState *ds, QEMUCursor *c)
+static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
+                                  DisplayState *ds,
+                                  QEMUCursor *c)
 {
     VncDisplay *vd = vnc_display;
     VncState *vs;
@@ -1966,14 +1973,15 @@ static void pixel_format_message (VncState *vs) {
     vs->write_pixels = vnc_write_pixels_copy;
 }
 
-static void vnc_dpy_setdata(DisplayState *ds)
+static void vnc_dpy_setdata(DisplayChangeListener *dcl,
+                            DisplayState *ds)
 {
     VncDisplay *vd = ds->opaque;
 
     qemu_pixman_image_unref(vd->guest.fb);
     vd->guest.fb = pixman_image_ref(ds->surface->image);
     vd->guest.format = ds->surface->format;
-    vnc_dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
+    vnc_dpy_update(dcl, ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
 }
 
 static void vnc_colordepth(VncState *vs)
@@ -2687,7 +2695,7 @@ static void vnc_init_timer(VncDisplay *vd)
     vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
     if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) {
         vd->timer = qemu_new_timer_ms(rt_clock, vnc_refresh, vd);
-        vnc_dpy_resize(vd->ds);
+        vnc_dpy_resize(dcl, vd->ds);
         vnc_refresh(vd);
     }
 }
@@ -2832,6 +2840,15 @@ static void vnc_listen_websocket_read(void *opaque)
 }
 #endif /* CONFIG_VNC_WS */
 
+static const DisplayChangeListenerOps dcl_ops = {
+    .dpy_name          = "vnc",
+    .dpy_gfx_update    = vnc_dpy_update,
+    .dpy_gfx_resize    = vnc_dpy_resize,
+    .dpy_gfx_setdata   = vnc_dpy_setdata,
+    .dpy_mouse_set     = vnc_mouse_set,
+    .dpy_cursor_define = vnc_dpy_cursor_define,
+};
+
 void vnc_display_init(DisplayState *ds)
 {
     VncDisplay *vs = g_malloc0(sizeof(*vs));
@@ -2862,11 +2879,7 @@ void vnc_display_init(DisplayState *ds)
     qemu_mutex_init(&vs->mutex);
     vnc_start_worker_thread();
 
-    dcl->dpy_gfx_update = vnc_dpy_update;
-    dcl->dpy_gfx_resize = vnc_dpy_resize;
-    dcl->dpy_gfx_setdata = vnc_dpy_setdata;
-    dcl->dpy_mouse_set = vnc_mouse_set;
-    dcl->dpy_cursor_define = vnc_dpy_cursor_define;
+    dcl->ops = &dcl_ops;
     register_displaychangelistener(ds, dcl);
 }
 
diff --git a/vl.c b/vl.c
index bf504a40c9..316210e6cc 100644
--- a/vl.c
+++ b/vl.c
@@ -1641,13 +1641,13 @@ void gui_setup_refresh(DisplayState *ds)
     bool have_text = false;
 
     QLIST_FOREACH(dcl, &ds->listeners, next) {
-        if (dcl->dpy_refresh != NULL) {
+        if (dcl->ops->dpy_refresh != NULL) {
             need_timer = true;
         }
-        if (dcl->dpy_gfx_update != NULL) {
+        if (dcl->ops->dpy_gfx_update != NULL) {
             have_gfx = true;
         }
-        if (dcl->dpy_text_update != NULL) {
+        if (dcl->ops->dpy_text_update != NULL) {
             have_text = true;
         }
     }
