2017-10-20 20 views
1

J'ai écrit une petite classe pour créer une image circulaire à partir d'un bytearray JPEG encodé en base64, mais il semble constamment provoquer des segavires. C'était le moyen le plus simple que je pouvais trouver pour créer une surface de cairo dans GJS, bien que je ne sois pas opposé à Clutter, si cela résout mon problème.Pourquoi ma classe Gdk/cairo provoque-t-elle une erreur de segmentation?

var CircularImage = new Lang.Class({ 
    Name: "CircularImage", 
    Extends: Gtk.DrawingArea, 

    _init: function (bytearray, win, size) { 
     this.parent({ 
      height_request: size, 
      width_request: size 
     }); 

     this.size = size; 

     let image_stream = Gio.MemoryInputStream.new_from_data(
      GLib.base64_decode(bytearray), 
      GLib.free 
     ); 

     let pixbuf = GdkPixbuf.Pixbuf.new_from_stream(
      image_stream, 
      null 
     ) 

     pixbuf.scale_simple(this.size, this.size, GdkPixbuf.InterpType.HYPER); 

     this._surface = Gdk.cairo_surface_create_from_pixbuf(
      pixbuf, 
      0, 
      win.get_window() 
     ); 

     this.connect("draw", (widget, cr) => { 
      this._draw(widget, cr); 
      return false; 
     }); 
    }, 

    _draw: function (widget, cr) { 
     cr.setSourceSurface(this._surface, 0, 0); 
     cr.arc(this.size/2, this.size/2, this.size/2, 0, 2*Math.PI); 
     cr.clip(); 
     cr.paint(); 
    } 
}); 

Il ne semble pas être une Détruisons fonction ou signal pour CairoImageSurface et je l'ai essayé unreffing le pixbuf pour voir si cela a aidé, mais cela se traduit par une erreur:

GLib-GObject-WARNING **: g_object_remove_toggle_ref: couldn't find toggle ref 0x7f45456b19e0((nil))

I Je l'ai utilisé dans une simple fenêtre Gtk et cela fonctionne, mais il semble causer des erreurs de segment environ la moitié du temps. Je ne connais pas grand-chose à la gestion de la mémoire, puisque j'utilise habituellement des langages récupérés par les ordures, donc je suppose que cela a quelque chose à voir avec la mémoire que je ne libère pas.

Y at-il quelque chose d'évident que je fais mal, un moyen plus facile de faire cela avec Clutter ou de façon simple, je peux traquer les segcatults arbitraires?

Répondre

2

Vous ne devriez pas avoir à gérer la gestion de la mémoire dans GJS même si la bibliothèque sous-jacente l'exige. Si vous le faites, c'est un bug. Essayer de le faire de toute façon causera certainement un accident. (Donc, si vous voyez des instructions pour appeler GLib.free() ou GObject.unref() même dans les GJS docs -. Ils sont générées automatiquement à partir de la documentation C et ne devraient pas être là)

Malheureusement, ces bugs qui vous obligent à prendre soin de la gestion de la mémoire font encore existent, et deux d'entre eux sont pertinents pour votre extrait de code.

Le bug vous frapper est en ce moment celui-ci: https://bugzilla.gnome.org/show_bug.cgi?id=747431 Au lieu de cela, faire quelque chose comme ceci:

let image_stream = Gio.MemoryInputStream.new_from_bytes(
    GLib.base64_decode(bytearray).toGBytes()); 

Un autre bug GJS qui pourrait devenir pertinent est plus tard que lorsque vous vous connectez à un signal draw vous devez actuellement appeler cr.$dispose() sur le contexte du Caire ou la mémoire sera divulguée.

+0

Merci beaucoup, je suis heureux de pouvoir l'utiliser maintenant. Une question, je suppose que je devrais appeler 'cr. $ Dispose()' dans le rappel draw après 'cr.paint()'? –

+1

C'est vrai, ça devrait être la dernière chose avant de revenir. – ptomato

+0

J'ai testé un peu plus avec ceci et semble toujours éprouver une fuite de mémoire. Y at-il des appels spéciaux que je devrais faire sur ':: destroy' pour que tout soit libéré? –