<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<span>Hi!<br>
</span>
<div><br>
</div>
<div><span style="">I have a question regarding how can i use the pimpl idiom in the kbd navigation case.</span><br>
</div>
<div>The editor private members will be defined in g_editor.c.<br>
</div>
<div>But since i'm moving the core kbd navigation stuff to it's own file (g_kbdnav.c) i must have a way of accessing this t_kbdnav struct on that file. </div>
<div><br>
</div>
<div>Currently i've used the solution (example below) of implementing a canvas_getkbdnav(t_canvas *x) function on g_editor.c that returns a pointer to it's t_kbdnav struct.
<br>
</div>
<div><br>
</div>
<div>Is this okay/good? Why?<br>
</div>
<div><br>
</div>
<div></div>
<div><span style="">Note: </span><br>
</div>
<div><span style="">
<div></div>
</span><span style="">I could make canvas_getkbdnav(t_canvas *x) static and pass a t_kbdnav pointer as a parameter from g_editor to the kbdnav stuff. The problem is that i also i need to call some kbdnav function from the iemgui files (g_toggle.c, g_hslider.c,
 etc) because they have custom drawing functions that need to call some kbdnav logic to draw the in/outlet selection. </span></div>
<div><span style=""><br>
</span></div>
<div><span style="">____________________________________________________________________________________</span></div>
<div><br>
</div>
<div><b>----------g_canvas.h----------</b><br>
</div>
<div><br>
</div>
<div>typedef struct _editor {<br>
</div>
<div>    ...<br>
</div>
<div>    void *e_privatedata;<br>
</div>
<div>} t_editor;<br>
</div>
<div><br>
</div>
<div><b>----------g_editor.c----------</b><br>
</div>
<div><br>
</div>
<div>typedef struct _editor_private {<br>
</div>
<div>#ifdef HAVE_KEYBOARDNAV<br>
</div>
<div>    t_kbdnav kbdnav;<br>
</div>
<div>#endif<br>
</div>
<div>} t_editor_private;<br>
</div>
<div><br>
</div>
<div>t_kbdnav* canvas_getkbdnav(t_canvas *x)<br>
</div>
<div>{<br>
</div>
<div>    ...<br>
</div>
<div>}<br>
</div>
<div><br>
</div>
<div><b>----------g_kbdnav.h----------</b><br>
</div>
<div><br>
</div>
<div>EXTERN t_kbdnav* canvas_getkbdnav(t_canvas *x);<br>
</div>
<div><br>
</div>
<div><b>----------g_kbdnav.c----------</b><br>
</div>
<div><br>
</div>
<div>void kbdnav_somefunction(t_canvas *x)<br>
</div>
<div>{<br>
</div>
<div>    t_kbdnav *kbdnav = canvas_getkbdnav(x);<br>
</div>
<div>    ...<br>
</div>
<span>}</span>
<div><br>
</div>
<div><br>
</div>
<div>
<div>Cheers,<br>
</div>
<div><span>Henri.</span></div>
</div>
<div><span><br>
</span></div>
<div><span><br>
</span></div>
<div><br>
</div>
<div>
<div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size: 11pt;" data-ogsc=""><b>De:</b> Christof Ressi <christof.ressi@gmx.at><br>
<b>Enviado:</b> terça-feira, 16 de julho de 2019 14:32<br>
<b>Para:</b> Henri Augusto Bisognini <msndohenri@hotmail.com><br>
<b>Cc:</b> pd-dev@lists.iem.at <pd-dev@lists.iem.at><br>
<b>Assunto:</b> Aw: Re: [PD-dev] First complete keyboard navigation prototype</font>
<div> </div>
</div>
<div>
<div style="font-family:Verdana; font-size:12.0px">
<div>
<div>Hi,</div>
<div> </div>
<div>> But it appears that actually the size of the struct is deduced <span style="font-family: Calibri, Helvetica, sans-serif; display: inline; background-color: rgb(255, 255, 255);">
while compiling.<span> S</span></span>o if you write an external it is going to think the canvas struct is the same size as it was in the pd header files that were used during compilation.</div>
<div> </div>
<div>exactly.</div>
<div>
<div> </div>
<div>> <span>When using the pointer to implementation idiom, wouldn't the pointer itself change the size of the struct?
</span></div>
<div> </div>
<div><span>yes, it will</span></div>
<div> </div>
<div><span>> You've said something about that not being a problem when you add it as the last member of the struct but i don't understand why and how that would work.</span></div>
<div> </div>
<div><span>usually, externals shouldn't care about the *size* the t_editor struct (at least I can't think of any use case), so you can get away with adding new fields at the end (although it's certainly not recommended). Note that those headers aren't really
 public anyway!</span></div>
<div> </div>
<div>However, appending fields conditionally can lead to problems:</div>
<div> </div>
<div><span>struct Foo {</span></div>
<div><span>    int a;</span></div>
<div><span>#ifdef FOO_EX</span></div>
<div>    int c;</div>
<div><span>#endif</span></div>
<div>};</div>
<div> </div>
<div>Now let's say we need to add another member:</div>
<div> </div>
<div>
<div><span>struct Foo {</span></div>
<div><span>    int a;</span></div>
<div><span>#ifdef FOO_EX</span></div>
<div>    int c;</div>
<div><span>#endif</span></div>
</div>
<div>
<div><span>    in b;</span></div>
<div><span>};</span></div>
</div>
<div> </div>
<div>If the host compiles with FOO_EX defined and the client doesn't, the latter will assume a wrong offset for 'b'.</div>
<div> </div>
<div>The solution is to add a field for private data *once*. The advantage is that a) we can hide the private data and b) we can extend it without worrying about compatibility:</div>
<div> </div>
<div>struct Foo {</div>
<div>   int a;</div>
<div>   PrivateFoo *p;</div>
<div>};</div>
<div> </div>
<div>We can still add public members if needed:</div>
<div> </div>
<div>struct Foo {</div>
<div>    int a;</div>
<div>    void *private;</div>
<div>    int b;</div>
<div>};</div>
<div> </div>
<div>'private' points to a private data structure that is not be visible to clients. There you can conditionally enable members without problems:</div>
<div> </div>
<div>struct PrivateFoo {</div>
<div>#ifdef USE_BAR</div>
<div>    struct MyFeature feature;</div>
<div>#endif</div>
<div>};</div>
<div> </div>
<div>MyFeature could be in a seperate source file together with your methods and it only gets compiled when needed.</div>
<div> </div>
<div>Again, have a look at the "t_canvas_private" struct and the "gl_privatedata" member of "_glist" (aka "t_canvas") and do the same for "_editor", e.g.:</div>
<div> </div>
<div>in g_canvas.h:</div>
<div> </div>
<div>typedef struct _editor {</div>
<div>    ...</div>
<div>    void *e_privatedata;</div>
<div>} t_editor;</div>
<div> </div>
<div>in g_editor.c:</div>
<div> </div>
<div>#ifdef HAVE_KEYBOARDNAV</div>
<div>#include "g_keyboardnav.h"</div>
<div>#endif</div>
<div> </div>
<div>typedef struct _editor_private {</div>
<div>#ifdef HAVE_KEYBOARDNAV</div>
<div>    t_keyboardnav keyboardnav;</div>
<div>#endif</div>
<div>} t_editor_private;</div>
<div> </div>
<div>the "t_keyboardnav" struct is defined in "g_keyboardnav.h" and its methods implemented in "g_keyboardnav.c". Both only get compiled when needed.</div>
<div> </div>
<div>Hope this makes sense.</div>
<div> </div>
<div>Christof</div>
<div> </div>
<div name="x_quote" style="margin:10px 5px 5px 10px; padding:10px 0 10px 10px; border-left:2px solid #C3D9E5; word-wrap:break-word">
<div style="margin:0 0 10px 0"><b>Gesendet:</b> Dienstag, 16. Juli 2019 um 16:51 Uhr<br>
<b>Von:</b> "Henri Augusto Bisognini" <msndohenri@hotmail.com><br>
<b>An:</b> "pd-dev@lists.iem.at" <pd-dev@lists.iem.at><br>
<b>Betreff:</b> Re: [PD-dev] First complete keyboard navigation prototype</div>
<div name="x_quoted-content">
<div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<span>Okay, just help me check if i got it right.</span>
<div> </div>
<div>At first i was thinking that when externals, for any reason, used the size of the canvas struct <span style="font-family: Calibri, Helvetica, sans-serif; display: inline; background-color: rgb(255, 255, 255);">(or any other)</span> it would do so in real
 time. Like calling sizeof() and stuff.</div>
<div> </div>
<div>But it appears that actually the size of the struct is deduced <span style="font-family: Calibri, Helvetica, sans-serif; display: inline; background-color: rgb(255, 255, 255);">
while compiling.<span> S</span></span>o if you write an external it is going to think the canvas struct is the same size as it was in the pd header files that were used during compilation.</div>
<div> </div>
<div>Is that it?</div>
<div> </div>
<span>I don't think i quite get something. When using the pointer to implementation idiom, wouldn't the pointer itself change the size of the struct? You've said something about that not being a problem when you add it as the last member of the struct but i
 don't understand why and how that would work.</span></div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
 </div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<span>(I don't have a formal background on programming so forgive me if thats obvious or something.)</span></div>
<div>
<div id="x_appendonsend"> </div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
 </div>
<hr style="display:inline-block; width:98.0%">
<div id="x_divRplyFwdMsg"><font color="#000000" face="Calibri, sans-serif" style="font-size: 11pt;" data-ogsc=""><b>De:</b> Christof Ressi <christof.ressi@gmx.at><br>
<b>Enviado:</b> sábado, 15 de junho de 2019 17:11<br>
<b>Para:</b> Henri Augusto Bisognini<br>
<b>Cc:</b> pd-dev@lists.iem.at<br>
<b>Assunto:</b> Aw: Re: [PD-dev] First complete keyboard navigation prototype</font>
<div> </div>
</div>
<div>
<div style="font-family:Verdana; font-size:12.0px">
<div>
<div>Hi, as IOhannes said, "g_canvas.h" is semi-public in a sense that some externals use it (e.g. iemguts). So unless it is absolutely necessary, we should avoid breaking binary compatibility.</div>
<div> </div>
<div> </div>
<div>
<div>If the e_kbdnav member is only conditionally enabled with an #ifdef, existing externals (or those not compiled with key-nav-support) will see a different size of t_editor. This is not much of a problem as long as e_kbdnav is the last member of t_editor,
 but as soon as we add another member, we might run into problems, since this last field will be at a different offset.</div>
<div> </div>
<div>I think the solution is simple: just add a "void *e_private" member which points to some private data where we can put all stuff which we don't want to expose the header. (This is called the "PIMPL idiom"). e_kbdnav would be the first member of such private
 data.</div>
<div> </div>
<div>IOhannes actually did this with the "gl_privatedata" member in t_canvas to hide the undo queue implemention.  The "t_canvas_private" struct currently only has a "t_undo" member but it's possible to add/remove/rearrange members at will without having to
 think about binary compatibility issues because it's not in a header file.</div>
<div> </div>
<div>Christof</div>
<div style="margin:10.0px 5.0px 5.0px 10.0px; padding:10.0px 0 10.0px 10.0px; border-left:2.0px solid rgb(195,217,229)">
<div style="margin:0 0 10.0px 0"><b>Gesendet:</b> Samstag, 15. Juni 2019 um 19:58 Uhr<br>
<b>Von:</b> "Henri Augusto Bisognini" <msndohenri@hotmail.com><br>
<b>An:</b> "pd-dev@lists.iem.at" <pd-dev@lists.iem.at><br>
<b>Betreff:</b> Re: [PD-dev] First complete keyboard navigation prototype</div>
<div>
<div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Please excuse my ignorance on that matter but could you give me a brief explanation of the problem at hand?</div>
<div>
<div id="x_x_appendonsend"> </div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
 </div>
<hr style="display:inline-block; width:98.0%">
<div id="x_x_divRplyFwdMsg"><font color="#000000" face="Calibri, sans-serif" style="font-size: 11pt;" data-ogsc=""><b>De:</b> Pd-dev <pd-dev-bounces@lists.iem.at> em nome de IOhannes m zmölnig <zmoelnig@iem.at><br>
<b>Enviado:</b> sexta-feira, 14 de junho de 2019 04:37<br>
<b>Para:</b> pd-dev@lists.iem.at<br>
<b>Assunto:</b> Re: [PD-dev] First complete keyboard navigation prototype</font>
<div> </div>
</div>
<div class="x_x_BodyFragment">
<div class="x_x_PlainText"><font size="2"><span style="font-size:11.0pt">On 6/13/19 7:34 PM, Henri Augusto Bisognini wrote:<br>
> Also, in g_canvas.h, inside the "struct _editor" there is a "struct _kbdnav" member. This is the struct that contains the data used in the keyboard navigation.<br>
><br>
<br>
i haven't looked at the actual code, but what you describe here, is that<br>
you are actually changing the size of a quasi-public struct and thus the<br>
memory layout as presented to externals.<br>
<br>
which means that a version of Pd that has the keyboard-navigation<br>
enabled is (partly) *binary-incompatible* with a version of Pd that does<br>
not have the keyboard-navigation enabled.<br>
<br>
bummer :-(<br>
<br>
gfmadr<br>
IOhannes</span></font><br>
 </div>
</div>
</div>
_______________________________________________ Pd-dev mailing list Pd-dev@lists.iem.at
<a href="https://lists.puredata.info/listinfo/pd-dev" target="_blank" style="">https://lists.puredata.info/listinfo/pd-dev</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
_______________________________________________ Pd-dev mailing list Pd-dev@lists.iem.at
<a href="https://lists.puredata.info/listinfo/pd-dev" target="_blank" style="">https://lists.puredata.info/listinfo/pd-dev</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>