-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make a haskell-gi based version of the cairo library #148
Comments
Thanks a lot for the feedback! This is very valuable. I was aware of these things, but having confirmation that they are a pain in practice helps me prioritize them. Some replies:
There should be, certainly! It's just that nobody has written it yet. Ideally,
What is there right now is sensible, in that this is what the introspection data says the type should be. And the introspection data is right, since the C API allows for any
Converting
I am not sure that it can be sensible autogenerated, but adding some
I see that you filed #147, I will add some comments there. Thanks again for the comments! |
Actually, this was wrong! In my my system at least In fact I have some vague recollection that at some point I did do the |
So how would you proceed with 1.? Perhaps I can help with that? Would it be better to create a separate repository, or to work inside the Haskell-gi repository? I guess it is very easy to:
Then GTK would need to be adapted that instead of GI.Cairo.Context a Cairo.Render instance is created at the appropriate places. But more importantly, GI.Pango and GI.PangoCairo need to be adjusted that they work inside the Render monad (for the few functions, that do). This seems like there is more to do inside GTK / Pango / PangoCairo than in Cairo itself. Is that correct? Of course, there are functions like -- Sorry for my collection of incoherent thoughts about integer types in the next section: Regarding the Integer types: you really have to decide how low level you want Haskell GI to be. Do the users of your library have to deal with the conversions and the corresponding errors, or does the library deal with it? For the users, it is more easy if they don't have to care and their programs are easier to maintain. Idiomatic Haskell would certainly be to take Int or Integer and handle the conversions internally by throwing exceptions if the number gets to large. I had all these integer conversions going on for many Pango functions, e.g. It is not really a problem though. Just dozens of But take for example The more I think about it, all these points are weaknesses from the GTK API, coming from weaknesses in the C type system. |
That would be fantastic, thanks! Here is what I think we should do. (@hamishmack Please let me know if you have a better idea for how to do things.) We should fork the A hard requirement is that the API exported from the new And we add So, in practice, as an example, this would mean that the widgetDraw :: Cairo.Context -> IO Bool
widgetDraw cr = renderWithContext cr $ do (stuff in the render monad) Does this sound reasonable? This seems to me convenient enough, while still staying close enough to the C API so that maintenance is not much of a pain. If you agree, and feel like giving it a try, I would be happy to help. |
My current guiding principle is making the bindings as high level as possible, while being correct in the sense that, assuming that the C API has no bugs, no bugs are introduced by the bindings themselves. So stuff like the overloaded labels ( But silently translating f :: Int -> Int
f x = ...
i32 <- get #intProp widget
set widget [#intProp := f i32] and even if So I think I am reasonably satisfied with the current tradeoff. We are binding a C library which uses a type
Indeed! This is #128, and I agree that it should be fixed (but the fix is not straightforward, and would require a small extension of the introspection spec).
Very nice suggestion! I had not thought of this before, good idea. There is unfortunately currently nothing in the introspection API that specifies this information, though, so in the same way as #128, one would need some upstream work first. Maybe worth it!
Indeed! We should strive to make the Along these lines, and since you asked about the general design philosophy :) One thing that should be possible, and may be an interesting experiment, is to build a much more high-level GUI toolkit based on Doing the same thing for reflex, or perhaps other approaches to GUI programming in Haskell should be quite nice. |
Ok, I will give it a try. Regarding the project structureFor me it is not quite clear, if it really should live inside the bindings folder. The logic is quite special there and it would be the first non-generated source file in there. And we should make non-equal stuff separate. Perhaps we could create an extra repository inside haskell-gi? Also from the dependency chain, the gi-cairo-render package (working name, okay?) will be dependent on Haskell GI but not the other way around, right? Regarding the GI.PangoCairo invocation inside CairoWe still need the reverse of the "trick" you mentioned above, e.g. a function with the signature: getContext :: Cairo.Render GI.Cairo.Context We can assume safely, that the Cairo.Render context is created via your first "trick". |
Excellent, thanks!
Sure, it could easily live anywhere else in the repo.
I did this originally with
Right.
I am not sure that such a function can be constructed ( |
Perhaps I understand something wrong. Assume, if we have the "trick 2" function, then haskell-gi, including gi-gtk will be completely independent of gi-cairo-render (as if it where a complete different library). Actually one could even take the old cairo library, if there wouldn't be the dependency to To be more precise: As you wrote, the user can use
This even works, 5 level of function calls down. This would be an acceptable API for my taste. I has the advantage, that haskell-gi can be completely unchanged. Letting the Haskell type yoga aside, both |
Oh, I misread the type signature! getContext :: Cairo.Render GI.Cairo.Context should be trivial to construct, of course. I misread it as getContext :: Cairo.Render -> GI.Cairo.Context which is impossible to construct. I completely agree with the rest of your comment, and I also had this kind of "decoupled" design in mind. |
Thinking more about the example you gave, we probably also want something like toRender :: (Cairo.Context -> IO a) -> Render a to be able to embed something like |
Ok, I will then:
What I would really like to know, if this is okay for the developers of |
This sounds like an excellent plan, thanks! |
I still have to learn I still don't get why the did it this way and didn't try to get their changes upstream.
I thought I get rid of it altogether and prefer using
From what I see, this "marshaller" is defined in Do you have a clue? The code is here. |
The problem is with the following minimal code:
This is valid code for So:
I can't understand the behaviour of |
I am afraid that I don't know the answer, but as an ugly workaround (until we figure out something better), perhaps you could just copy and paste by hand the code |
Ok, after looking at the generated code, you have to write:
instead of
This syntax is just awesome. I now fixed all |
Hi @garetxe I now made everything compile and added three magic functions.
where
Can you adopt me inside Haskell GI namespace or inside the Haskell GI project and still keep me as a co-maintainer? What still needs to be done:
|
Thanks a lot!
I think that Otherwise everything looks good, I think. |
Perhaps I would architect things slightly differently. We could have a The overall decision to split off the base library is sound, I think, but calling it
Sure! |
I totally agree. If I understand correctly:
We have to still find a suitable namespace. How about
From what I understand, most of this can only be done by you. Especially most of 1 (e.g. creating a project, renaming namespaces can be done by me) and for 3. you would also be the ideal candidate. I always wanted to upload a package to hackage though ;-). If you don't want to have |
I don't see how to make it work for both while we keep the libraries separate (unless we use a typeclass or something, which I'd rather not, since it will make type inference worse). One possibility is to make the What do you think? One advantage of this approach, in addition to having a single type, is that if we depend on |
This depends a bit on how we decide to go. If
Same here. If we go the route of adding a dependency on
Sounds good :) As soon as we agree on the design I can spend some time on this.
Sure :) |
Ok. Let's proceed with the idea, that we rewrite
Then, lets look how to rewrite Sorry, I don't get it anymore this evening (it's 23.00 in germany), but I wrote the compiling version:
This is translated by
So I need to define the magic function, which must be something with |
Something like the following should work, I believe: foreign import ccall "cairo_gobject_context_get_type" c_cairo_gobject_context_get_type ::
IO GType
instance BoxedObject Cairo where
boxedType _ = c_cairo_gobject_context_get_type
magicFunction = wrapBoxed Cairo |
I rewrote all of the I don't understand it completely. The memory management of The original
So we execute some function, while before we call I guess, calling So I did the following:
So I guess, that freeBoxed destroys the pointer with other means, e.g. this fancy C call you gave me? But I feel, there must be simpler way. Couldn't I just call But I don't see that the pointer is really destroyed in You can find my changes in my |
The rule is that renderWith surface (Render m) = liftIO $
bracket (do context <- Internal.create surface
wrapBoxed Cairo context)
(\context -> do status <- Internal.status context
-- freeBoxed context
unless (status == StatusSuccess) $
fail =<< Internal.statusToString status)
(\context -> runReaderT m context) the One could indeed also write a version with renderWith surface (Render m) = liftIO $
bracket (do context <- Internal.create surface)
(\context -> do status <- Internal.status context
Internal.destroy context
unless (status == StatusSuccess) $
fail =<< Internal.statusToString status)
(\context -> withTransient Context context $ runReaderT m) Note that in either case there will be an object of type Calling a destructor when an object is being collected by the GC is very small overhead, pretty much the same as calling |
Ok, now everything compiles. I rewrote the three magic functions and the Clock and SDL examples are running (so both I now wanted (first in a fork of haskell-gi/haskell-gi, to not destroy anything):
What I would like most, if What would be even better (much!), if Haskell GI would do:
I guess the last one is impossible without massive development in Haskell GI, right? I also ported my labyrinth game to the new infrastructure. It is in the examples folder and uses all magic functions. |
Great, thanks for doing this!
So in a hand-written version of
I completely agree. To avoid special casing
No, I think this would be fairly easy to implement (although the interesting case is callbacks, not ordinary functions, right?). But making this automatically makes me uneasy: it is very easy now to slap a
Great! The memory management in the new functions seems OK to me, so if they work in a non-trivial example they are probably correct. |
Perfect! Just merge it! What about automatic tests? I didn't think about how to tests it, but actually we should have some automatic test which verify that we leak no memory. What about the demos? Shall we translate the other too and put them into the examples folder or in gi-gtk-examples? Best regards, |
Great. I will import everything from your
Any ideas on how to do this? I have used
I think putting things in the examples folder is best, let's do that. |
Thank you! I will wait until you commit and then port the examples and think about tests. I also think about porting |
Hi, I did not come very far the last days, due to time constraints. I had a few minutes today and tried to further evolve my branch I now got compile errors in GI/Gdk/Objects/Screen.hs:971:21
This instance should have come out of the generated source, right? Do you have a clue, why it isn't there? Best regards, P.S.: I understand it now. There are two conflicting declarations for FontOptions. I will fix it! |
Hi Inaki, can you comment on this? I do not understand it at all. It does also not work with the plain generated cairo bindings, if I generate the bindings from hand (e.g. with haskell-gi). It does work when using cabal on the whole of haskell-gi (e.g. cabal new-build). This is why your standalone version of Here are the details: In GI.Gdk/Objects/Screen.hs there is a function
This seems wrong to me and probably leaks memory. When I generate the bindings from hand via You can test it, by checking out my branch and typing |
Thanks for the analysis! I am a little bit puzzled why |
What is even worse is, that when building via |
Here is what screenGetFontOptions ::
(B.CallStack.HasCallStack, MonadIO m, IsScreen a) =>
a
{- ^ /@screen@/: a 'GI.Gdk.Objects.Screen.Screen' -}
-> m (Maybe Cairo.FontOptions.FontOptions)
{- ^ __Returns:__ the current font options, or 'Nothing' if no
default font options have been set. -}
screenGetFontOptions screen = liftIO $ do
screen' <- unsafeManagedPtrCastPtr screen
result <- gdk_screen_get_font_options screen'
maybeResult <- convertIfNonNull result $ \result' -> do
result'' <- (newBoxed Cairo.FontOptions.FontOptions) result'
return result''
touchManagedPtr screen
return maybeResult You see that it assumes that <record name="FontOptions" c:type="cairo_font_options_t" foreign="1"
glib:type-name="CairoFontOptions"
glib:get-type="cairo_gobject_font_options_get_type"/> What does it say on your system? (In my system this is at |
I just did this, and |
In my system it shows:
I have libgirepository-1.0.dev, 1.50.0-1+b1 in Debian 9. |
OK, that explains the difference between what I see and what you see. I just need to figure out how to patch things up so |
Ouch, I was just making a silly typo. An override works just fine, try adding the following to
|
My comment in the pull request was concerned with the following. I did:
This is, at least, surprising. |
Oh, I see! This is indeed badly documented. The issue is that you need to generate the appropriate
Then |
Oh, thanks! Of course you need to have already What is really missing for me to develop
The steps in The more I use Do you have any clue or am I simply too stupid to use cabal ;-) ? P.S.: Can you push your new version of |
No, it should not be necessary (I just checked just in case :) ).
I think the following should work as you want:
The The build is not entirely reproducible, in that it will depend on the latest versions of hackage packages (if you want to avoid this locally, you can use If you forget to run
Thanks for the reminder, done! |
I just changed some things around that should make the experience of using Definitely not perfect, but at least less misleading. With this in place, and once you generate the |
Works like a charm. Of course, |
I guess before releasing the new version of I now have a problem with Path.hs. This is still generated with If I look in If I look in cairo-gobject.h, there is a function So two questions:
|
The more I understand about this Path in the C source code, the more I think it should be disabled in Haskell GI. You can get the Path (i.e. first move from a to b, then circle to c, then line to d, etc.) from a There is no gobject data, because the memory management is obscure. 1st possibility:
The corresponding code to actually use Paths was commented out in the gtk2hs library. The author thought about a nice abstraction, but this would not be that easy to write. But there is nearly no use for all this functionality, because a path can be directly constructed inside a And if we write an abstraction, this should not come out of the generated code, which is useless. |
I agree completely. It sounds reasonable to me to omit If someone decides to implement a nicer Haskell abstraction on top of that that would be great, of course, but I don't think that should be a priority right now. |
In my Debian 9 installation the
Upstream it equals:
is there an override for that? It even changes from structure to enumeration. Why is Debians |
It can be fixed with overrides (since xml nodes can be arbitrarily added/removed), but it would be a mess... Perhaps the best thing would be to just include the Fedora version of the We don't do that generally, since the API of libraries do change, but in this case it may be OK. Here is the copy in my system says: <?xml version="1.0"?>
<repository version="1.2"
xmlns="http://www.gtk.org/introspection/core/1.0"
xmlns:c="http://www.gtk.org/introspection/c/1.0"
xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
<package name="cairo-gobject"/>
<namespace name="cairo" version="1.0"
shared-library="libcairo-gobject.so.2"
c:identifier-prefixes="cairo"
c:symbol-prefixes="cairo">
<record name="Context" c:type="cairo_t" foreign="1"
glib:type-name="CairoContext"
glib:get-type="cairo_gobject_context_get_type"/>
<record name="Device" c:type="cairo_device_t" foreign="1"
glib:type-name="CairoDevice"
glib:get-type="cairo_gobject_device_get_type"/>
<record name="Surface" c:type="cairo_surface_t" foreign="1"
glib:type-name="CairoSurface"
glib:get-type="cairo_gobject_surface_get_type"/>
<record name="Matrix" c:type="cairo_matrix_t" foreign="1"/>
<record name="Pattern" c:type="cairo_pattern_t" foreign="1"
glib:type-name="CairoPattern"
glib:get-type="cairo_gobject_pattern_get_type"/>
<record name="Region" c:type="cairo_region_t" foreign="1"
glib:type-name="CairoRegion"
glib:get-type="cairo_gobject_region_get_type"/>
<enumeration name="Status" c:type="cairo_status_t"
glib:type-name="cairo_status_t"
glib:get-type="cairo_gobject_status_get_type">
<member name="success"
value="0"
c:identifier="CAIRO_STATUS_SUCCESS"/>
<member name="no_memory"
value="1"
c:identifier="CAIRO_STATUS_NO_MEMORY"/>
<member name="invalid_restore"
value="2"
c:identifier="CAIRO_STATUS_INVALID_RESTORE"/>
<member name="invalid_pop_group"
value="3"
c:identifier="CAIRO_STATUS_INVALID_POP_GROUP"/>
<member name="no_current_point"
value="4"
c:identifier="CAIRO_STATUS_NO_CURRENT_POINT"/>
<member name="invalid_matrix"
value="5"
c:identifier="CAIRO_STATUS_INVALID_MATRIX"/>
<member name="invalid_status"
value="6"
c:identifier="CAIRO_STATUS_INVALID_STATUS"/>
<member name="null_pointer"
value="7"
c:identifier="CAIRO_STATUS_NULL_POINTER"/>
<member name="invalid_string"
value="8"
c:identifier="CAIRO_STATUS_INVALID_STRING"/>
<member name="invalid_path_data"
value="9"
c:identifier="CAIRO_STATUS_INVALID_PATH_DATA"/>
<member name="read_error"
value="10"
c:identifier="CAIRO_STATUS_READ_ERROR"/>
<member name="write_error"
value="11"
c:identifier="CAIRO_STATUS_WRITE_ERROR"/>
<member name="surface_finished"
value="12"
c:identifier="CAIRO_STATUS_SURFACE_FINISHED"/>
<member name="surface_type_mismatch"
value="13"
c:identifier="CAIRO_STATUS_SURFACE_TYPE_MISMATCH"/>
<member name="pattern_type_mismatch"
value="14"
c:identifier="CAIRO_STATUS_PATTERN_TYPE_MISMATCH"/>
<member name="invalid_content"
value="15"
c:identifier="CAIRO_STATUS_INVALID_CONTENT"/>
<member name="invalid_format"
value="16"
c:identifier="CAIRO_STATUS_INVALID_FORMAT"/>
<member name="invalid_visual"
value="17"
c:identifier="CAIRO_STATUS_INVALID_VISUAL"/>
<member name="file_not_found"
value="18"
c:identifier="CAIRO_STATUS_FILE_NOT_FOUND"/>
<member name="invalid_dash"
value="19"
c:identifier="CAIRO_STATUS_INVALID_DASH"/>
<member name="invalid_dsc_comment"
value="20"
c:identifier="CAIRO_STATUS_INVALID_DSC_COMMENT"/>
<member name="invalid_index"
value="21"
c:identifier="CAIRO_STATUS_INVALID_INDEX"/>
<member name="clip_not_representable"
value="22"
c:identifier="CAIRO_STATUS_CLIP_NOT_REPRESENTABLE"/>
<member name="temp_file_error"
value="23"
c:identifier="CAIRO_STATUS_TEMP_FILE_ERROR"/>
<member name="invalid_stride"
value="24"
c:identifier="CAIRO_STATUS_INVALID_STRIDE"/>
<member name="font_type_mismatch"
value="25"
c:identifier="CAIRO_STATUS_FONT_TYPE_MISMATCH"/>
<member name="user_font_immutable"
value="26"
c:identifier="CAIRO_STATUS_USER_FONT_IMMUTABLE"/>
<member name="user_font_error"
value="27"
c:identifier="CAIRO_STATUS_USER_FONT_ERROR"/>
<member name="negative_count"
value="28"
c:identifier="CAIRO_STATUS_NEGATIVE_COUNT"/>
<member name="invalid_clusters"
value="29"
c:identifier="CAIRO_STATUS_INVALID_CLUSTERS"/>
<member name="invalid_slant"
value="30"
c:identifier="CAIRO_STATUS_INVALID_SLANT"/>
<member name="invalid_weight"
value="31"
c:identifier="CAIRO_STATUS_INVALID_WEIGHT"/>
<member name="invalid_size"
value="32"
c:identifier="CAIRO_STATUS_INVALID_SIZE"/>
<member name="user_font_not_implemented"
value="33"
c:identifier="CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED"/>
<member name="device_type_mismatch"
value="34"
c:identifier="CAIRO_STATUS_DEVICE_TYPE_MISMATCH"/>
<member name="device_error"
value="35"
c:identifier="CAIRO_STATUS_DEVICE_ERROR"/>
<member name="invalid_mesh_construction"
value="36"
c:identifier="CAIRO_STATUS_INVALID_MESH_CONSTRUCTION"/>
<member name="device_finished"
value="37"
c:identifier="CAIRO_STATUS_DEVICE_FINISHED"/>
<member name="jbig2_global_missing"
value="38"
c:identifier="CAIRO_STATUS_JBIG2_GLOBAL_MISSING"/>
</enumeration>
<enumeration name="Content" c:type="cairo_content_t"
glib:type-name="cairo_content_t"
glib:get-type="cairo_gobject_content_get_type">
<member name="color"
value="4096"
c:identifier="CAIRO_CONTENT_COLOR"/>
<member name="alpha"
value="8192"
c:identifier="CAIRO_CONTENT_ALPHA"/>
<member name="color_alpha"
value="12288"
c:identifier="CAIRO_CONTENT_COLOR_ALPHA"/>
</enumeration>
<enumeration name="Operator" c:type="cairo_operator_t"
glib:type-name="cairo_operator_t"
glib:get-type="cairo_gobject_operator_get_type">
<member name="clear"
value="0"
c:identifier="CAIRO_OPERATOR_CLEAR"/>
<member name="source"
value="1"
c:identifier="CAIRO_OPERATOR_SOURCE"/>
<member name="over"
value="2"
c:identifier="CAIRO_OPERATOR_OVER"/>
<member name="in"
value="3"
c:identifier="CAIRO_OPERATOR_IN"/>
<member name="out"
value="4"
c:identifier="CAIRO_OPERATOR_OUT"/>
<member name="atop"
value="5"
c:identifier="CAIRO_OPERATOR_ATOP"/>
<member name="dest"
value="6"
c:identifier="CAIRO_OPERATOR_DEST"/>
<member name="dest_over"
value="7"
c:identifier="CAIRO_OPERATOR_DEST_OVER"/>
<member name="dest_in"
value="8"
c:identifier="CAIRO_OPERATOR_DEST_IN"/>
<member name="dest_out"
value="9"
c:identifier="CAIRO_OPERATOR_DEST_OUT"/>
<member name="dest_atop"
value="10"
c:identifier="CAIRO_OPERATOR_DEST_ATOP"/>
<member name="xor"
value="11"
c:identifier="CAIRO_OPERATOR_XOR"/>
<member name="add"
value="12"
c:identifier="CAIRO_OPERATOR_ADD"/>
<member name="saturate"
value="13"
c:identifier="CAIRO_OPERATOR_SATURATE"/>
<member name="multiply"
value="14"
c:identifier="CAIRO_OPERATOR_MULTIPLY"/>
<member name="screen"
value="15"
c:identifier="CAIRO_OPERATOR_SCREEN"/>
<member name="overlay"
value="16"
c:identifier="CAIRO_OPERATOR_OVERLAY"/>
<member name="darken"
value="17"
c:identifier="CAIRO_OPERATOR_DARKEN"/>
<member name="lighten"
value="18"
c:identifier="CAIRO_OPERATOR_LIGHTEN"/>
<member name="color_dodge"
value="19"
c:identifier="CAIRO_OPERATOR_COLOR_DODGE"/>
<member name="color_burn"
value="20"
c:identifier="CAIRO_OPERATOR_COLOR_BURN"/>
<member name="hard_light"
value="21"
c:identifier="CAIRO_OPERATOR_HARD_LIGHT"/>
<member name="soft_light"
value="22"
c:identifier="CAIRO_OPERATOR_SOFT_LIGHT"/>
<member name="difference"
value="23"
c:identifier="CAIRO_OPERATOR_DIFFERENCE"/>
<member name="exclusion"
value="24"
c:identifier="CAIRO_OPERATOR_EXCLUSION"/>
<member name="hsl_hue"
value="25"
c:identifier="CAIRO_OPERATOR_HSL_HUE"/>
<member name="hsl_saturation"
value="26"
c:identifier="CAIRO_OPERATOR_HSL_SATURATION"/>
<member name="hsl_color"
value="27"
c:identifier="CAIRO_OPERATOR_HSL_COLOR"/>
<member name="hsl_luminosity"
value="28"
c:identifier="CAIRO_OPERATOR_HSL_LUMINOSITY"/>
</enumeration>
<enumeration name="Antialias" c:type="cairo_antialias_t"
glib:type-name="cairo_antialias_t"
glib:get-type="cairo_gobject_antialias_get_type">
<member name="default"
value="0"
c:identifier="CAIRO_ANTIALIAS_DEFAULT"/>
<member name="none"
value="1"
c:identifier="CAIRO_ANTIALIAS_NONE"/>
<member name="gray"
value="2"
c:identifier="CAIRO_ANTIALIAS_GRAY"/>
<member name="subpixel"
value="3"
c:identifier="CAIRO_ANTIALIAS_SUBPIXEL"/>
<member name="fast"
value="4"
c:identifier="CAIRO_ANTIALIAS_FAST"/>
<member name="good"
value="5"
c:identifier="CAIRO_ANTIALIAS_GOOD"/>
<member name="best"
value="6"
c:identifier="CAIRO_ANTIALIAS_BEST"/>
</enumeration>
<enumeration name="FillRule" c:type="cairo_fill_rule_t"
glib:type-name="cairo_fill_rule_t"
glib:get-type="cairo_gobject_fill_rule_get_type">
<member name="winding"
value="0"
c:identifier="CAIRO_FILL_RULE_WINDING"/>
<member name="even_odd"
value="1"
c:identifier="CAIRO_FILL_RULE_EVEN_ODD"/>
</enumeration>
<enumeration name="LineCap" c:type="cairo_line_cap_t"
glib:type-name="cairo_line_cap_t"
glib:get-type="cairo_gobject_line_cap_get_type">
<member name="butt"
value="0"
c:identifier="CAIRO_LINE_CAP_BUTT"/>
<member name="round"
value="1"
c:identifier="CAIRO_LINE_CAP_ROUND"/>
<member name="square"
value="2"
c:identifier="CAIRO_LINE_CAP_SQUARE"/>
</enumeration>
<enumeration name="LineJoin" c:type="cairo_line_join_t"
glib:type-name="cairo_line_join_t"
glib:get-type="cairo_gobject_line_join_get_type">
<member name="miter"
value="0"
c:identifier="CAIRO_LINE_JOIN_MITER"/>
<member name="round"
value="1"
c:identifier="CAIRO_LINE_JOIN_ROUND"/>
<member name="bevel"
value="2"
c:identifier="CAIRO_LINE_JOIN_BEVEL"/>
</enumeration>
<enumeration name="TextClusterFlags" c:type="cairo_text_cluster_flags_t"
glib:type-name="cairo_text_cluster_flags_t"
glib:get-type="cairo_gobject_text_cluster_flags_get_type">
<member name="backward"
value="1"
c:identifier="CAIRO_TEXT_CLUSTER_FLAG_BACKWARD"/>
</enumeration>
<enumeration name="FontSlant" c:type="cairo_font_slant_t"
glib:type-name="cairo_font_slant_t"
glib:get-type="cairo_gobject_font_slant_get_type">
<member name="normal"
value="0"
c:identifier="CAIRO_FONT_SLANT_NORMAL"/>
<member name="italic"
value="1"
c:identifier="CAIRO_FONT_SLANT_ITALIC"/>
<member name="oblique"
value="2"
c:identifier="CAIRO_FONT_SLANT_OBLIQUE"/>
</enumeration>
<enumeration name="FontWeight" c:type="cairo_font_weight_t"
glib:type-name="cairo_font_weight_t"
glib:get-type="cairo_gobject_font_weight_get_type">
<member name="normal"
value="0"
c:identifier="CAIRO_FONT_WEIGHT_NORMAL"/>
<member name="bold"
value="1"
c:identifier="CAIRO_FONT_WEIGHT_BOLD"/>
</enumeration>
<enumeration name="SubpixelOrder" c:type="cairo_subpixel_order_t"
glib:type-name="cairo_subpixel_order_t"
glib:get-type="cairo_gobject_subpixel_order_get_type">
<member name="default"
value="0"
c:identifier="CAIRO_SUBPIXEL_ORDER_DEFAULT"/>
<member name="rgb"
value="1"
c:identifier="CAIRO_SUBPIXEL_ORDER_RGB"/>
<member name="bgr"
value="2"
c:identifier="CAIRO_SUBPIXEL_ORDER_BGR"/>
<member name="vrgb"
value="3"
c:identifier="CAIRO_SUBPIXEL_ORDER_VRGB"/>
<member name="vbgr"
value="4"
c:identifier="CAIRO_SUBPIXEL_ORDER_VBGR"/>
</enumeration>
<enumeration name="HintStyle" c:type="cairo_hint_style_t"
glib:type-name="cairo_hint_style_t"
glib:get-type="cairo_gobject_hint_style_get_type">
<member name="default"
value="0"
c:identifier="CAIRO_HINT_STYLE_DEFAULT"/>
<member name="none"
value="1"
c:identifier="CAIRO_HINT_STYLE_NONE"/>
<member name="slight"
value="2"
c:identifier="CAIRO_HINT_STYLE_SLIGHT"/>
<member name="medium"
value="3"
c:identifier="CAIRO_HINT_STYLE_MEDIUM"/>
<member name="full"
value="4"
c:identifier="CAIRO_HINT_STYLE_FULL"/>
</enumeration>
<enumeration name="HintMetrics" c:type="cairo_hint_metrics_t"
glib:type-name="cairo_hint_metrics_t"
glib:get-type="cairo_gobject_hint_metrics_get_type">
<member name="default"
value="0"
c:identifier="CAIRO_HINT_METRICS_DEFAULT"/>
<member name="off"
value="1"
c:identifier="CAIRO_HINT_METRICS_OFF"/>
<member name="on"
value="2"
c:identifier="CAIRO_HINT_METRICS_ON"/>
</enumeration>
<record name="FontOptions" c:type="cairo_font_options_t" foreign="1"
glib:type-name="CairoFontOptions"
glib:get-type="cairo_gobject_font_options_get_type"/>
<enumeration name="FontType" c:type="cairo_font_type_t"
glib:type-name="cairo_font_type_t"
glib:get-type="cairo_gobject_font_type_get_type">
<member name="toy"
value="0"
c:identifier="CAIRO_FONT_TYPE_TOY"/>
<member name="ft"
value="1"
c:identifier="CAIRO_FONT_TYPE_FT"/>
<member name="win32"
value="2"
c:identifier="CAIRO_FONT_TYPE_WIN32"/>
<member name="quartz"
value="3"
c:identifier="CAIRO_FONT_TYPE_QUARTZ"/>
<member name="user"
value="4"
c:identifier="CAIRO_FONT_TYPE_USER"/>
</enumeration>
<enumeration name="PathDataType" c:type="cairo_path_data_type_t"
glib:type-name="cairo_path_data_type_t"
glib:get-type="cairo_gobject_path_data_type_get_type">
<member name="move_to"
value="0"
c:identifier="CAIRO_PATH_MOVE_TO"/>
<member name="line_to"
value="1"
c:identifier="CAIRO_PATH_LINE_TO"/>
<member name="curve_to"
value="2"
c:identifier="CAIRO_PATH_CURVE_TO"/>
<member name="close_path"
value="3"
c:identifier="CAIRO_PATH_CLOSE_PATH"/>
</enumeration>
<enumeration name="DeviceType" c:type="cairo_device_type_t"
glib:type-name="cairo_device_type_t"
glib:get-type="cairo_gobject_device_type_get_type">
<member name="drm"
value="0"
c:identifier="CAIRO_DEVICE_TYPE_DRM"/>
<member name="gl"
value="1"
c:identifier="CAIRO_DEVICE_TYPE_GL"/>
<member name="script"
value="2"
c:identifier="CAIRO_DEVICE_TYPE_SCRIPT"/>
<member name="xcb"
value="3"
c:identifier="CAIRO_DEVICE_TYPE_XCB"/>
<member name="xlib"
value="4"
c:identifier="CAIRO_DEVICE_TYPE_XLIB"/>
<member name="xml"
value="5"
c:identifier="CAIRO_DEVICE_TYPE_XML"/>
<member name="cogl"
value="6"
c:identifier="CAIRO_DEVICE_TYPE_COGL"/>
<member name="win32"
value="7"
c:identifier="CAIRO_DEVICE_TYPE_WIN32"/>
<member name="invalid"
value="-1"
c:identifier="CAIRO_DEVICE_TYPE_INVALID"/>
</enumeration>
<enumeration name="SurfaceType" c:type="cairo_surface_type_t"
glib:type-name="cairo_surface_type_t"
glib:get-type="cairo_gobject_surface_type_get_type">
<member name="image"
value="0"
c:identifier="CAIRO_SURFACE_TYPE_IMAGE"/>
<member name="pdf"
value="1"
c:identifier="CAIRO_SURFACE_TYPE_PDF"/>
<member name="ps"
value="2"
c:identifier="CAIRO_SURFACE_TYPE_PS"/>
<member name="xlib"
value="3"
c:identifier="CAIRO_SURFACE_TYPE_XLIB"/>
<member name="xcb"
value="4"
c:identifier="CAIRO_SURFACE_TYPE_XCB"/>
<member name="glitz"
value="5"
c:identifier="CAIRO_SURFACE_TYPE_GLITZ"/>
<member name="quartz"
value="6"
c:identifier="CAIRO_SURFACE_TYPE_QUARTZ"/>
<member name="win32"
value="7"
c:identifier="CAIRO_SURFACE_TYPE_WIN32"/>
<member name="beos"
value="8"
c:identifier="CAIRO_SURFACE_TYPE_BEOS"/>
<member name="directfb"
value="9"
c:identifier="CAIRO_SURFACE_TYPE_DIRECTFB"/>
<member name="svg"
value="10"
c:identifier="CAIRO_SURFACE_TYPE_SVG"/>
<member name="os2"
value="11"
c:identifier="CAIRO_SURFACE_TYPE_OS2"/>
<member name="win32_printing"
value="12"
c:identifier="CAIRO_SURFACE_TYPE_WIN32_PRINTING"/>
<member name="quartz_image"
value="13"
c:identifier="CAIRO_SURFACE_TYPE_QUARTZ_IMAGE"/>
<member name="script"
value="14"
c:identifier="CAIRO_SURFACE_TYPE_SCRIPT"/>
<member name="qt"
value="15"
c:identifier="CAIRO_SURFACE_TYPE_QT"/>
<member name="recording"
value="16"
c:identifier="CAIRO_SURFACE_TYPE_RECORDING"/>
<member name="vg"
value="17"
c:identifier="CAIRO_SURFACE_TYPE_VG"/>
<member name="gl"
value="18"
c:identifier="CAIRO_SURFACE_TYPE_GL"/>
<member name="drm"
value="19"
c:identifier="CAIRO_SURFACE_TYPE_DRM"/>
<member name="tee"
value="20"
c:identifier="CAIRO_SURFACE_TYPE_TEE"/>
<member name="xml"
value="21"
c:identifier="CAIRO_SURFACE_TYPE_XML"/>
<member name="skia"
value="22"
c:identifier="CAIRO_SURFACE_TYPE_SKIA"/>
<member name="subsurface"
value="23"
c:identifier="CAIRO_SURFACE_TYPE_SUBSURFACE"/>
<member name="cogl"
value="24"
c:identifier="CAIRO_SURFACE_TYPE_COGL"/>
</enumeration>
<enumeration name="Format" c:type="cairo_format_t"
glib:type-name="cairo_format_t"
glib:get-type="cairo_gobject_format_get_type">
<member name="invalid"
value="-1"
c:identifier="CAIRO_FORMAT_INVALID"/>
<member name="argb32"
value="0"
c:identifier="CAIRO_FORMAT_ARGB32"/>
<member name="rgb24"
value="1"
c:identifier="CAIRO_FORMAT_RGB24"/>
<member name="a8"
value="2"
c:identifier="CAIRO_FORMAT_A8"/>
<member name="a1"
value="3"
c:identifier="CAIRO_FORMAT_A1"/>
<member name="rgb16_565"
value="4"
c:identifier="CAIRO_FORMAT_RGB16_565"/>
<member name="rgb30"
value="5"
c:identifier="CAIRO_FORMAT_RGB30"/>
</enumeration>
<enumeration name="PatternType" c:type="cairo_pattern_type_t"
glib:type-name="cairo_pattern_type_t"
glib:get-type="cairo_gobject_pattern_type_get_type">
<member name="solid"
value="0"
c:identifier="CAIRO_PATTERN_TYPE_SOLID"/>
<member name="surface"
value="1"
c:identifier="CAIRO_PATTERN_TYPE_SURFACE"/>
<member name="linear"
value="2"
c:identifier="CAIRO_PATTERN_TYPE_LINEAR"/>
<member name="radial"
value="3"
c:identifier="CAIRO_PATTERN_TYPE_RADIAL"/>
<member name="mesh"
value="4"
c:identifier="CAIRO_PATTERN_TYPE_MESH"/>
<member name="raster_source"
value="5"
c:identifier="CAIRO_PATTERN_TYPE_RASTER_SOURCE"/>
</enumeration>
<enumeration name="Extend" c:type="cairo_extend_t"
glib:type-name="cairo_extend_t"
glib:get-type="cairo_gobject_extend_get_type">
<member name="none"
value="0"
c:identifier="CAIRO_EXTEND_NONE"/>
<member name="repeat"
value="1"
c:identifier="CAIRO_EXTEND_REPEAT"/>
<member name="reflect"
value="2"
c:identifier="CAIRO_EXTEND_REFLECT"/>
<member name="pad"
value="3"
c:identifier="CAIRO_EXTEND_PAD"/>
</enumeration>
<enumeration name="Filter" c:type="cairo_filter_t"
glib:type-name="cairo_filter_t"
glib:get-type="cairo_gobject_filter_get_type">
<member name="fast"
value="0"
c:identifier="CAIRO_FILTER_FAST"/>
<member name="good"
value="1"
c:identifier="CAIRO_FILTER_GOOD"/>
<member name="best"
value="2"
c:identifier="CAIRO_FILTER_BEST"/>
<member name="nearest"
value="3"
c:identifier="CAIRO_FILTER_NEAREST"/>
<member name="bilinear"
value="4"
c:identifier="CAIRO_FILTER_BILINEAR"/>
<member name="gaussian"
value="5"
c:identifier="CAIRO_FILTER_GAUSSIAN"/>
</enumeration>
<enumeration name="RegionOverlap" c:type="cairo_region_overlap_t"
glib:type-name="cairo_region_overlap_t"
glib:get-type="cairo_gobject_region_overlap_get_type">
<member name="in"
value="0"
c:identifier="CAIRO_REGION_OVERLAP_IN"/>
<member name="out"
value="1"
c:identifier="CAIRO_REGION_OVERLAP_OUT"/>
<member name="part"
value="2"
c:identifier="CAIRO_REGION_OVERLAP_PART"/>
</enumeration>
<record name="FontFace" c:type="cairo_font_face_t" foreign="1"
glib:type-name="CairoFontFace"
glib:get-type="cairo_gobject_font_face_get_type"/>
<record name="ScaledFont" c:type="cairo_scaled_font_t" foreign="1"
glib:type-name="CairoScaledFont"
glib:get-type="cairo_gobject_scaled_font_get_type"/>
<record name="Path" c:type="cairo_path_t" foreign="1"/>
<record name="RectangleInt" c:type="cairo_rectangle_int_t"
glib:type-name="CairoRectangleInt"
glib:get-type="cairo_gobject_rectangle_int_get_type">
<field name="x" writable="1">
<type name="gint" c:type="gint"/>
</field>
<field name="y" writable="1">
<type name="gint" c:type="gint"/>
</field>
<field name="width" writable="1">
<type name="gint" c:type="gint"/>
</field>
<field name="height" writable="1">
<type name="gint" c:type="gint"/>
</field>
</record>
<function name="image_surface_create" c:identifier="cairo_image_surface_create">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
</parameters>
</function>
</namespace>
</repository> |
I am a Haskell newbie, but I managed to write a non-trivial program with
gtk2hs
and converted it completely toHaskell GI
yesterday. I wanted to share some pain points of the conversion.One main pain point is the Cairo integration. There should be something (in Haskell GI, external library?), which abstracts this ForeignPtr stuff. Also, I used Pango Layouts deep inside the Render monad. Thus I needed to pass the
GI.Cairo.Context
inside the Render monad and switch between both of them. I found this very uggly. Generally I like the monadic interface ofgtk2hs
. Couldn't there be a special version of the Cairo library, which works with GI out of the box? Alsogtk2hs
seems to be unmaintained and the set of stackage resolvers where both GI and gtk2hs compile is nearly empty. So beeing dependent on both of them will be a pain in the long run.There are quite a few functions which should take enumerations, but take
Int32
instead, for exampledialogRun
anddialogAddButton
. In the Leksah source code, there are functionsdialogRun'
anddialogAddButton'
which takeGTK.ResponseType
instead. I also would like to have an enumeration for the mouse buttons ingetEventButtonButton
, likegtk2hs
had, maybe wrapping inside Maybe, if anybody has a mouse with more than 20 buttons and there will ever be a Haskell GI program taking advantage of it.I originally switched from Rust to Haskell, because in
gtk-rs
there was a mess of types used. Some functions usedf64
, somei32
and someu32
. Sometimes similar sounding functions used another data type for the same kind of parameter. This was better withgtk2hs
which usedInt
throughout. I now know that this mess comes from the introspection data itself, but couldHaskell GI
just also useInt
? I do not likeInt32
very much, as all conversions can go wrong and I'd rather love the library handle it, in a high level language like Haskell.I actually liked the monadic nature of
gtk2hs
, e.g. for Events. Couldn't something like this be autogenerated, too?I found it hard to find the correct pieces in the documentation. But after 1 day of digging, I am much better know. My first try was to grep in the generated binaries ;-). Nowadays I grep inside Leksah's source code, which, although I was not able to compile it on any platform, is a great source of inspiration.
Thanks in advance for some thoughts on the above points.
The text was updated successfully, but these errors were encountered: