Ticket #11679: lxappearance-obconf-gtk3_preview.patch

File lxappearance-obconf-gtk3_preview.patch, 23.2 KB (added by Joe Locash, 2 years ago)
  • src/preview.c

    From ccede6fe71312498f7e85a231e6a0678e375cdf6 Mon Sep 17 00:00:00 2001
    From: bill-auger <mr.j.spam.me@gmail.com>
    Date: Mon, 2 Nov 2020 19:04:46 -0500
    Subject: complete GTK3 preview implementation (closes #768)
    
    the GTK3 preview did not render properly, because it attempted to mimic the GTK2
    code too closely - the function which draws to the gdk-pixbuf (the return value
    of the drawing functions), and its GDK2 counterpart which it replaced, did not
    have feature-parity - i could not find a replacement which does - some of the
    features of gdk-pixbuf2 appear to be incompatible with GTK3
    
    the GTK2-compatible function recycled the target gdk-pixbuf, composing the final
    graphic, layer upon layer, with each call - however, each call to the replacement
    function for GTK3, clobbered the previous gdk-pixbuf; such that the final graphic
    represented only the work done in the last call; and so the returned graphic was
    much smaller than expected
    
    instead, this change does the compositing with cairo using cairo drawing surfaces,
    then finally copying at once onto the GDK pixbuf used by the GTK2 implementation
    (per the function contract), just before returning it
    ---
     src/preview.c | 363 ++++++++++++++++++++++------------------------------------
     1 file changed, 135 insertions(+), 228 deletions(-)
    
    diff --git a/src/preview.c b/src/preview.c
    index a2fc63d..75005f5 100644
    a b  
    1717   See the COPYING file for a copy of the GNU General Public License.
    1818*/
    1919
     20/*
     21 * This file was taken from ObConf; and some modifications were done
     22 * to make it a loadable module of LXAppearance.
     23 * Later, it was modified to support GTK3, in addition to GTK2.
     24 */
     25
    2026#ifdef HAVE_CONFIG_H
    2127#include <config.h>
    2228#endif
    GdkPixbuf *preview_theme(const gchar *name, const gchar *titlelayout,  
    4753                         RrFont *osd_active_font,
    4854                         RrFont *osd_inactive_font);
    4955
     56typedef struct _CairoComposeParams {
     57    Display *display;             /* xLib Display */
     58    cairo_t *context;             /* cairo context for compositing surface */
     59    Visual *visual;               /* xLib display Visual */
     60    cairo_surface_t *surface_src; /* RrAppearance.Pixmap conversion surface */
     61
     62} CairoComposeParams;
     63
    5064/* End forwarded */
    5165
    5266static void theme_pixmap_paint(RrAppearance *a, gint w, gint h)
    static guint32 rr_color_pixel(const RrColor *c)  
    6175                     + (RrColorBlue(c) << 8) + 0xff);
    6276}
    6377
     78/*! Initialize a Cairo context and surface
     79    to be used for compositing various Openbox themed window decoration
     80    for the "Window Border" preview pane.
     81    These will presumably be destroyed in finalize_composition()
     82    after any number of rendering passes through compose_surface()
     83    @param params  pointer to a CairoComposeParams struct
     84                   which is to describe/hold the destination Cairo context
     85    @param w       the desired width of the composite image
     86    @param h       the desired height of the composite image
     87    @return        returns a new Cairo sufrace */
     88static cairo_surface_t* initialize_composite(CairoComposeParams *params,
     89                                             gint w, gint h)
     90{
     91  cairo_surface_t* surface;
     92
     93  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
     94  params->display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
     95  params->context = cairo_create(surface);
     96  params->visual = DefaultVisual(params->display, 0);
     97
     98  return surface;
     99}
     100
     101/*! Compose a pre-rendered preview of an Openbox themed window decoration
     102    as a layer onto a composite Cairo surface,
     103    as created in initialize_composite().
     104    @param params     pointer to a CairoComposeParams struct
     105                      describing/holding the destination Cairo context
     106    @param appearance pointer to an RrAppearance struct, belonging to an RrTheme
     107                      to be used as the layer source
     108    @param x          the destination x coordinate, for source pixel 0,0
     109    @param y          the destination y coordinate, for source pixel 0,0
     110    @param w          the width of the source RrAppearance Pixmap
     111    @param h          the height of the source RrAppearance Pixmap
     112    @return           returns void */
     113static void compose_surface(CairoComposeParams *params, RrAppearance *appearance,
     114                            gint x, gint y, gint w, gint h)
     115{
     116    params->surface_src = cairo_xlib_surface_create(params->display,
     117                                                    appearance->pixmap,
     118                                                    params->visual,
     119                                                    w, h);
     120
     121    cairo_set_source_surface(params->context, params->surface_src, x, y);
     122    cairo_paint(params->context);
     123
     124    cairo_surface_destroy(params->surface_src);
     125}
     126
     127/*! Copy composed Cairo surface onto a new GdkPixbuf;
     128    then destroy the source Cairo context and underlying composite surface.
     129    These were presumably created in initialize_composite().
     130    @param params  pointer to a CairoComposeParams struct
     131                   describeing/holding the Cairo context to be destroyed
     132    @param surface pointer to a cairo_surface_t
     133                   to be used as the source for the GdkPixbuf,
     134                   then destroyed
     135    @param w       the width of the composite image
     136    @param h       the height of the composite image
     137    @return        returns a new GdkPixbuf */
     138static GdkPixbuf* finalize_composition(CairoComposeParams *params,
     139                                       cairo_surface_t *surface,
     140                                       gint w, gint h)
     141{
     142  GdkPixbuf *pixbuf;
     143
     144  pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, w, h);
     145
     146  cairo_surface_destroy(surface);
     147  cairo_destroy(params->context);
     148
     149  return pixbuf;
     150}
     151
    64152/* XXX: Make this more general */
    65153static GdkPixbuf* preview_menu(RrTheme *theme)
    66154{
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    75163    RrAppearance *selected;
    76164    RrAppearance *bullet; /* for submenu */
    77165#if GTK_CHECK_VERSION(3, 0, 0)
    78     cairo_surface_t *surface;
    79     Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
     166    cairo_surface_t *surface; /* compositing destination, source for pixbuf */
     167    CairoComposeParams compose_params; /* composite surface context */
    80168#else
    81169    GdkPixmap *pixmap;
    82170#endif
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    130218
    131219    //height += 3*th + 3*theme->mbwidth + 5*PADDING;
    132220
     221#if GTK_CHECK_VERSION(3, 0, 0)
     222    /* initialize cairo context and composite destination surface */
     223    surface = initialize_composite(&compose_params, width, height);
     224#endif
     225
    133226    /* set border */
    134227    pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
    135228    gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_border_color));
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    145238    theme_pixmap_paint(title_text, bw, title_h);
    146239
    147240#if GTK_CHECK_VERSION(3, 0, 0)
    148     surface = cairo_xlib_surface_create(dpy,
    149                                                    title_text->pixmap,
    150                                                    DefaultVisual(dpy, 0),
    151                                                    x,
    152                                                    y);
    153 
    154     pixbuf = gdk_pixbuf_get_from_surface(surface,
    155                                         0,
    156                                         0,
    157                                         bw,
    158                                         title_h);
    159 
    160    cairo_surface_destroy(surface);
    161 
     241    compose_surface(&compose_params, title_text, x, y, bw, title_h);
    162242#else
    163243    pixmap = gdk_pixmap_foreign_new(title_text->pixmap);
    164244    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    174254    theme_pixmap_paint(menu, bw, th);
    175255
    176256#if GTK_CHECK_VERSION(3, 0, 0)
    177     surface = cairo_xlib_surface_create(dpy,
    178                                                    menu->pixmap,
    179                                                    DefaultVisual(dpy, 0),
    180                                                    x,
    181                                                    y);
    182 
    183     pixbuf = gdk_pixbuf_get_from_surface(surface,
    184                                         0,
    185                                         0,
    186                                         bw,
    187                                         th);
    188 
    189    cairo_surface_destroy(surface);
    190 
     257    compose_surface(&compose_params, menu, x, y, bw, th);
    191258#else
    192259    pixmap = gdk_pixmap_foreign_new(menu->pixmap);
    193260    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    204271    /* draw background for normal entry */
    205272    theme_pixmap_paint(background, bw, bh);
    206273#if GTK_CHECK_VERSION(3, 0, 0)
    207     surface = cairo_xlib_surface_create(dpy,
    208                                                    background->pixmap,
    209                                                    DefaultVisual(dpy, 0),
    210                                                    x,
    211                                                    y);
    212 
    213     pixbuf = gdk_pixbuf_get_from_surface(surface,
    214                                         0,
    215                                         0,
    216                                         bw,
    217                                         bh);
    218 
    219    cairo_surface_destroy(surface);
    220 
     274    compose_surface(&compose_params, background, x, y, bw, bh);
    221275#else
    222276    pixmap = gdk_pixmap_foreign_new(background->pixmap);
    223277    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    234288    RrMinSize(normal, &tw, &th);
    235289    theme_pixmap_paint(normal, tw, th);
    236290#if GTK_CHECK_VERSION(3, 0, 0)
    237     surface = cairo_xlib_surface_create(dpy,
    238                                                    normal->pixmap,
    239                                                    DefaultVisual(dpy, 0),
    240                                                    x,
    241                                                    y);
    242 
    243     pixbuf = gdk_pixbuf_get_from_surface(surface,
    244                                         0,
    245                                         0,
    246                                         tw,
    247                                         th);
    248 
    249    cairo_surface_destroy(surface);
    250 
     291    compose_surface(&compose_params, normal, x, y, tw, th);
    251292#else
    252293    pixmap = gdk_pixmap_foreign_new(normal->pixmap);
    253294    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    262303    bullet->surface.parenty = PADDING;
    263304    theme_pixmap_paint(bullet, th, th);
    264305#if GTK_CHECK_VERSION(3, 0, 0)
    265     surface = cairo_xlib_surface_create(dpy,
    266                                                    bullet->pixmap,
    267                                                    DefaultVisual(dpy, 0),
    268                                                    width - theme->mbwidth - th,
    269                                                    y);
    270 
    271     pixbuf = gdk_pixbuf_get_from_surface(surface,
    272                                         0,
    273                                         0,
    274                                         th,
    275                                         th);
    276 
    277    cairo_surface_destroy(surface);
    278 
     306    compose_surface(&compose_params, bullet, width - theme->mbwidth - th, y, th, th);
    279307#else
    280308    pixmap = gdk_pixmap_foreign_new(bullet->pixmap);
    281309    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    289317    background->surface.parenty = bh;
    290318    theme_pixmap_paint(background, bw, bh);
    291319#if GTK_CHECK_VERSION(3, 0, 0)
    292     surface = cairo_xlib_surface_create(dpy,
    293                                                    background->pixmap,
    294                                                    DefaultVisual(dpy, 0),
    295                                                    x - PADDING,
    296                                                    y - PADDING);
    297 
    298     pixbuf = gdk_pixbuf_get_from_surface(surface,
    299                                         0,
    300                                         0,
    301                                         bw,
    302                                         bh);
    303 
    304    cairo_surface_destroy(surface);
    305 
     320    compose_surface(&compose_params, background,
     321                    x - PADDING, y - PADDING, bw, bh);
    306322#else
    307323    pixmap = gdk_pixmap_foreign_new(background->pixmap);
    308324    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    317333    disabled->surface.parenty = PADDING;
    318334    theme_pixmap_paint(disabled, tw, th);
    319335#if GTK_CHECK_VERSION(3, 0, 0)
    320     surface = cairo_xlib_surface_create(dpy,
    321                                                    disabled->pixmap,
    322                                                    DefaultVisual(dpy, 0),
    323                                                    x,
    324                                                    y);
    325 
    326     pixbuf = gdk_pixbuf_get_from_surface(surface,
    327                                         0,
    328                                         0,
    329                                         tw,
    330                                         th);
    331 
    332    cairo_surface_destroy(surface);
    333 
     336    compose_surface(&compose_params, disabled, x, y, tw, th);
    334337#else
    335338    pixmap = gdk_pixmap_foreign_new(disabled->pixmap);
    336339    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    346349
    347350    theme_pixmap_paint(background, bw, bh);
    348351#if GTK_CHECK_VERSION(3, 0, 0)
    349     surface = cairo_xlib_surface_create(dpy,
    350                                                    background->pixmap,
    351                                                    DefaultVisual(dpy, 0),
    352                                                    x - PADDING,
    353                                                    y - PADDING);
    354 
    355     pixbuf = gdk_pixbuf_get_from_surface(surface,
    356                                         0,
    357                                         0,
    358                                         bw,
    359                                         bh);
    360 
    361    cairo_surface_destroy(surface);
    362 
     352    compose_surface(&compose_params, background,
     353                    x - PADDING, y - PADDING, bw, bh);
    363354#else
    364355    pixmap = gdk_pixmap_foreign_new(background->pixmap);
    365356    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_menu(RrTheme *theme)  
    375366    selected->surface.parenty = PADDING;
    376367    theme_pixmap_paint(selected, tw, th);
    377368#if GTK_CHECK_VERSION(3, 0, 0)
    378     surface = cairo_xlib_surface_create(dpy,
    379                                                    selected->pixmap,
    380                                                    DefaultVisual(dpy, 0),
    381                                                    x,
    382                                                    y);
    383 
    384     pixbuf = gdk_pixbuf_get_from_surface(surface,
    385                                         0,
    386                                         0,
    387                                         tw,
    388                                         th);
    389 
    390    cairo_surface_destroy(surface);
    391 
     369    compose_surface(&compose_params, selected, x, y, tw, th);
    392370#else
    393371    pixmap = gdk_pixmap_foreign_new(selected->pixmap);
    394372    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    395373                                          gdk_colormap_get_system(),
    396374                                          0, 0, x, y, tw, th);
    397375#endif
     376
     377#if GTK_CHECK_VERSION(3, 0, 0)
     378    // copy composed cairo surface to GDK pixbuf
     379    pixbuf = finalize_composition(&compose_params, surface, width, height);
     380#else
     381    ; // the GTK2 paths have composed onto the GDK pixbuf directly
     382#endif
     383
    398384    return pixbuf;
    399385}
    400386
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    405391    RrAppearance *handle;
    406392    RrAppearance *a;
    407393#if GTK_CHECK_VERSION(3, 0, 0)
    408     cairo_surface_t *surface;
    409     Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
     394    cairo_surface_t *surface; /* compositing destination, source for pixbuf */
     395    CairoComposeParams compose_params; /* composite surface context */
    410396#else
    411397    GdkPixmap *pixmap;
    412398#endif
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    417403
    418404    const gchar *layout;
    419405
     406#if GTK_CHECK_VERSION(3, 0, 0)
     407    /* initialize cairo context and composite destination surface */
     408    surface = initialize_composite(&compose_params, width, height);
     409#endif
     410
    420411    title = focus ? theme->a_focused_title : theme->a_unfocused_title;
    421412
    422413    /* set border */
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    433424
    434425    x = y = theme->fbwidth;
    435426#if GTK_CHECK_VERSION(3, 0, 0)
    436     surface = cairo_xlib_surface_create(dpy,
    437                                                    title->pixmap,
    438                                                    DefaultVisual(dpy, 0),
    439                                                    x,
    440                                                    y);
    441 
    442     pixbuf = gdk_pixbuf_get_from_surface(surface,
    443                                         0,
    444                                         0,
    445                                         w,
    446                                         h);
    447 
    448    cairo_surface_destroy(surface);
    449 
     427    compose_surface(&compose_params, title, x, y, w, h);
    450428#else
    451429    pixmap = gdk_pixmap_foreign_new(title->pixmap);
    452430    pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    494472
    495473            theme_pixmap_paint(a, w, h);
    496474#if GTK_CHECK_VERSION(3, 0, 0)
    497     surface = cairo_xlib_surface_create(dpy,
    498                                                    a->pixmap,
    499                                                    DefaultVisual(dpy, 0),
    500                                                    x,
    501                                                    y);
    502 
    503     pixbuf = gdk_pixbuf_get_from_surface(surface,
    504                                         0,
    505                                         0,
    506                                         w,
    507                                         h);
    508 
    509    cairo_surface_destroy(surface);
    510 
     475            compose_surface(&compose_params, a, x, y, w, h);
    511476#else
    512477            pixmap = gdk_pixmap_foreign_new(a->pixmap);
    513478            pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    528493
    529494            theme_pixmap_paint(a, w, h);
    530495#if GTK_CHECK_VERSION(3, 0, 0)
    531     surface = cairo_xlib_surface_create(dpy,
    532                                                    a->pixmap,
    533                                                    DefaultVisual(dpy, 0),
    534                                                    x,
    535                                                    y);
    536 
    537     pixbuf = gdk_pixbuf_get_from_surface(surface,
    538                                         0,
    539                                         0,
    540                                         w,
    541                                         h);
    542 
    543    cairo_surface_destroy(surface);
    544 
     496            compose_surface(&compose_params, a, x, y, w, h);
    545497#else
    546498            pixmap = gdk_pixmap_foreign_new(a->pixmap);
    547499            pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    616568
    617569            theme_pixmap_paint(a, w, h);
    618570#if GTK_CHECK_VERSION(3, 0, 0)
    619     surface = cairo_xlib_surface_create(dpy,
    620                                                    a->pixmap,
    621                                                    DefaultVisual(dpy, 0),
    622                                                    x,
    623                                                    y + 1);
    624 
    625     pixbuf = gdk_pixbuf_get_from_surface(surface,
    626                                         0,
    627                                         0,
    628                                         w,
    629                                         h);
    630 
    631    cairo_surface_destroy(surface);
    632 
     571            compose_surface(&compose_params, a, x, y + 1, w, h);
    633572#else
    634573            pixmap = gdk_pixmap_foreign_new(a->pixmap);
    635574            /* use y + 1 because these buttons should be centered wrt the label
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    653592
    654593        theme_pixmap_paint(handle, w, h);
    655594#if GTK_CHECK_VERSION(3, 0, 0)
    656     surface = cairo_xlib_surface_create(dpy,
    657                                                    handle->pixmap,
    658                                                    DefaultVisual(dpy, 0),
    659                                                    x,
    660                                                    y);
    661 
    662     pixbuf = gdk_pixbuf_get_from_surface(surface,
    663                                         0,
    664                                         0,
    665                                         w,
    666                                         h);
    667 
    668    cairo_surface_destroy(surface);
    669 
     595        compose_surface(&compose_params, handle, x, y, w, h);
    670596#else
    671597        pixmap = gdk_pixmap_foreign_new(handle->pixmap);
    672598        pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    691617
    692618        theme_pixmap_paint(a, w, h);
    693619#if GTK_CHECK_VERSION(3, 0, 0)
    694     surface = cairo_xlib_surface_create(dpy,
    695                                                    a->pixmap,
    696                                                    DefaultVisual(dpy, 0),
    697                                                    x,
    698                                                    y);
    699 
    700     pixbuf = gdk_pixbuf_get_from_surface(surface,
    701                                         0,
    702                                         0,
    703                                         w,
    704                                         h);
    705 
    706    cairo_surface_destroy(surface);
    707 
     620        compose_surface(&compose_params, a, x, y, w, h);
    708621#else
    709622        pixmap = gdk_pixmap_foreign_new(a->pixmap);
    710623        pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    715628        /* right grip */
    716629        x = width - theme->fbwidth - theme->grip_width;
    717630#if GTK_CHECK_VERSION(3, 0, 0)
    718     surface = cairo_xlib_surface_create(dpy,
    719                                                    a->pixmap,
    720                                                    DefaultVisual(dpy, 0),
    721                                                    x,
    722                                                    y);
    723 
    724     pixbuf = gdk_pixbuf_get_from_surface(surface,
    725                                         0,
    726                                         0,
    727                                         w,
    728                                         h);
    729 
    730    cairo_surface_destroy(surface);
    731 
     631        compose_surface(&compose_params, a, x, y, w, h);
    732632#else
    733633        pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap,
    734634                                              gdk_colormap_get_system(),
    static GdkPixbuf* preview_window(RrTheme *theme, const gchar *titlelayout,  
    736636#endif
    737637    }
    738638
     639#if GTK_CHECK_VERSION(3, 0, 0)
     640    // copy composed cairo surface into GDK pixbuf
     641    pixbuf = finalize_composition(&compose_params, surface, width, height);
     642#else
     643    ; // the GTK2 paths have composed onto the GDK pixbuf directly
     644#endif
     645
    739646    /* title separator colour */
    740647    x = theme->fbwidth;
    741648    y = theme->fbwidth + theme->title_height;