-
Notifications
You must be signed in to change notification settings - Fork 19
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
Shoes.app contents unavailable outside its scope #44
Comments
As currently written, there is no way in Shoes to reliably manage other Apps/Wiindows. It is confounded by the other (mostly unwritten about) url/visit style which does allow modal dialog like control . My sample ytm.rb at http://walkabout.mvmanila.com/public/share/ytm.rb shows this style of Shoes programming (you'll need http://walkabout.mvmanila.com/public/share/ytmsec.csv An IRB facility does need that kind of modal control and inspection into Shoes.apps (kind of like gdb has to control its apps and threads and set values in the target. Perhaps your irb could be written in that style and if you need some api's into Shoes internals we can write them. Just a suggestion. |
The code seems to be accommodating on the surface but clearly not working to manage multiple Shoes apps. One oddities in https://github.com/Shoes3/shoes3/blob/master/shoes/app.c#L80 is the usage of rb_ary_dup in shoes_apps_get, which seems like a very bad idea. Also, shoes_app_new indeed pushes the app into the array. It might be necessary to gdb this one because even though the object is listed, some of its methods are not available. It is possible to add slots and elements to a window but not read it without previously defining local variables (such as in my IRB turtorial). I did test without rb_ary_dup on Loose Shoes but without success. Accessing contents of Shoes.APPS[0] from a second window still generates an undefined method:
You very well understand what I ought to do with IRB. Adding a special API will certainly work but it doesn't fix the core problem. Proper support within Shoes would most certainly make IRB an amazingly useful tool but also it would allow multiple windows applications to exist, such as what once was Gimp. |
Investigation reveals that Shoes should properly support multiple apps. The reason the contents is not available outside its scope is that Shoes::Types::App is not related to Shoes::Types::Canvas in any way. It is however unclear why the following code snippet will display the contents. Canvas may be mixin in some way. Using Shoes IRB will not display the contents (directly, using put or info). Also, Shoes.app {
para "Check Shoes console (alt-/)"
info self.class
info contents
info (self.class.instance_methods - Object.class.instance_methods).sort
} REFERENCES |
The clues are in ruby.c lines:4364 through 4394. |
Funny enough, on line 4392 there is I did try earlier to set the parent class of cApp to cCanvas but Shoes crashed (segfault, shoes.rb:152) before displaying the splash screen. The two following wouldn't work. cApp = rb_define_class_under(cTypes, "App", cCanvas); cApp = rb_define_class("App", cCanvas);
rb_include_module(cApp, cTypes);
rb_define_alloc_func(cApp, shoes_app_alloc); |
For a maintenance release, I wouldn't fix it ;^) This code and the manipulation of self is what makes Shoes unique (and confusing). As you've discovered, modifying stuff here almost always results in unintended behavior. |
Come on, we have already triumphed over a few "couldn't, wouldn't fix". :) |
compares the lists produced by Shoes.app {
info Shoes::included_modules
info Shoes::instance_methods
info Shoes::Types::included_modules
info Shoes::Types::instance_methods
info Shoes::Types::App::instance_methods
info self.class
} |
Updated your code for clarity in the output: Shoes.app {
info Shoes::included_modules
info (Shoes::instance_methods - Object.instance_methods).sort
info Shoes::Types::included_modules
info (Shoes::Types::instance_methods - Object.instance_methods).sort
info (Shoes::Types::App::instance_methods - Object.instance_methods).sort
info self.class
} |
I can guess _why rb_ary_dup was used. If Window-1 gets a list of APPS[] there is no current way that Windows-1 knows that Windows-2 spawned a half dozen windows and closed 3 of them. Or that Windows-3 (IRB for example) is poking inside Windows-1 and closed a fourth windows from there. APPS is only an [array] of Apps/Windows/Alerts it knows about at the time it is queried. For introspection we really need a dynamic tree structure of windows at that level in the tree and ways to move up, down, left and right in the tree node. Not so simple for anyone and very not backwards compatible but that's OK, IMO. We have a data structure problem with APPS[] and we will need some hashes or nested arrays or both. For example APPS[] could return the( flat) array of all the windows it knows about at the time. as it does now for backwards compatibility. Shoes.AppTree (.e.g) could return a dynamic list of list or list of hashes or .... Window titles cannot be use as a hash key since a scrip(s)t can change those. A global C var may already exist for counting windows that can be use to create keys or we can create one. I'm only exploring the idea. Might be a hell of lot of 'C' code to modify and app issues will bite you in the ass. Thoughts? |
Before I start modifying anything, it's good to explore how this corner of Shoes works and since I'm not particularly knowledgeable with meta programming and the Shoes core class arrangement I wrote a program to explore it. https://gist.github.com/ccoupe/95e095cbb749ba7c5006 It's Shoes so all the windows stack on top so you have to spread them out manually. Ugly. It demonstrates that one can manipulate other Shoes windows from Shoes. Not easily because you have to instance_eval to get the binding correct and string escaping can be horrendous. However for this bug report, you can do it. To use eval(string, TOPLEVEL_BiNDING) as IRB (and others) like to do is a problem unless Shoes/irb can switch (+save/restore) the binding. It could do that I think but it would be ugly, hackish, and prone to breakage. But I'm not very clever so perhaps someone else can do better. |
Turns out there is an existing App.slot method documented (by @passenger94 ?) " as I would prefer the name to be 'slots' but for compatibility reasons I will dup the tiny bit of code and rename it to slots and document slots. And I may have found a good test case for when Shoes doesn't alway default to flow layout - a bug that has bothered me forever. @backorder' original test script has been modified to add a start block because not everything is realized at the instantly and use slot.contents. @app = Shoes.app {
s = stack { para "stack paragraph" }
para "paragraph"
info "contents: #{contents}"
info "Shoes.APPS[0].contents: #{Shoes.APPS[0].slot.contents}"
info "stack contents #{s.contents}"
Shoes.app {
info "Shoes.app(2)>>Shoes.APPS: #{Shoes.APPS}"
begin
info "Shoes.app(2)>>Shoes.APPS[0].contents: #{Shoes.APPS[0].slot.contents}"
rescue Exception => e
msg = e.backtrace.join("\n")
error "Shoes.app(2)>>Shoes.APPS[0]:\n#{e.message}\n#{msg}"
end
}
}
Shoes.app {
flow { para "flow paragraph" }
info "Shoes.app(3)>>Shoes.APPS[1].contents: #{Shoes.APPS[1].slot.contents}"
start do
begin
info "Shoes.app(3)>>Shoes.APPS: #{Shoes.APPS.inspect}"
rescue Exception => e
msg = e.backtrace.join("\n")
error "Shoes.app(2)>>Shoes.APPS:\n#{e.message}\n#{msg}"
end
begin
info "Shoes.app(3)>>Shoes.APPS[0].contents: #{Shoes.APPS[0].slot.contents}"
rescue Exception => e
msg = e.backtrace.join("\n")
error "Shoes.app(2)>>Shoes.APPS[0]:\n#{e.message}\n#{msg}"
end
end
}
Shoes.show_log Also you guys should join the new mailing list even if you just want to lurk. |
Seems like it is working as it should. It does feel a bit overkill to have to used a slot method rather than just APPS. Changing APPS to reflect slot behaviour might need much work. This technique using slot on APPS should be documented in the manual if no other steps are taken on this issue here. Excellent work, @ccoupe! |
It's definitely requires a long wiki article about how to poke around inside the DSL. The start() method was also critical in the above example because that's how things work. The manual has been updated for 3.2.25 |
Folks might be interested in the wiki article: https://github.com/Shoes3/shoes3/wiki/Poking-in-Shoes.app which adds a button in another window using the methods discovered above. |
This is a very good wiki article. Shoes is getting gradually demystified. |
The contents of any given Shoes.app is unavailable outside its scope, regardless of the manner it is referenced (variable, Shoes.APPS, etc). For example, on Windows, Shoes.app(3) can refer to its own contents using Shoes.APPS[1] but not access contents to other app listed in Shoes.APPS. On MacOS X, Shoes.app(2) can access to contents of Shoes.app(1) whereas Shoes.app(3) cannot. Other tests have proven that it is possible to add slots and elements to an existing Shoes app.
This issue seriously limits the ability to interact amongst Shoes.APPS but also when using IRB for fast prototyping or modifying a running Shoes app. _BE AWARE_ The Shoes Console output is different on Windows than MacOS X (and likely Linux too); platform specific implementation may cause the slight differences.
The Shoes script is available below after the console outputs.
SHOES CONSOLE ON WINDOWS
SHOES CONSOLE ON MACOS X
SHOES SCRIPT
The text was updated successfully, but these errors were encountered: