shoes / shoes3

a tiny graphical app kit for ruby
http://walkabout.mvmanila.com
Other
181 stars 19 forks source link

timer(o) { ...} #174

Closed passenger94 closed 8 years ago

passenger94 commented 8 years ago

I think i found the origin of the problem : -at least for Gtk - When drawing a canvas, Shoes call shoes_native_slot_paint which in turn calls Gtk's gtk_widget_queue_draw this has the effect of scheduling the drawing for when gtk main loop is idle, delaying the drawing for later in some circumstances.

We can fix this by forcing the immediate drawing with gdk_window_process_updates immediately after "queue_draw" It works nicely on good-svgview.rb !!

Do you remind of some good example of app having the problem to test ? I'm not sure about the implication on general performance though, as this will impact ALL drawings ....

IanTrudel commented 8 years ago

You rock! Seriously!

There were many examples we had to use timer(0) { }. You may have to dig into closed issues. Here's an easy one for you:

Shoes.app {
   e = edit_line

   timer(0) { e.focus }
}
ccoupe commented 8 years ago

I have no idea whether there is an OSX equivalent. I hope not.timer(0) is a hack some folks like to pull out. Is it time(1) on slow processors? The manual describes the start method to finish initializing gui objects (move focus, set checks and radios and otherwise wait for the gui framework/drawing queue to catch up. Does that not work?

The very existence of start {block} says that synchronous drawing was never intended and accommodated for years ago . Queue flushing runs counter to asynchronous drawing optimizations built into gtk and cocoa, optimizations that may even get a hardware assist now days . Reminds me of 1980's pre Carbon coding on the Mac and early X11 head scratching.

Putting aside the Negative Nancy feelings, I would like to say "Happy New Years" to you. Without your help, there would be no Shoes 3.2 (or 3.3).

IanTrudel commented 8 years ago

The hack has to do with the order of execution rather than timer itself. It is shielding the code enclosed in such way to allow access to runtime information that would not be otherwise available. timer(1) is unlikely to make any difference.

Happy New Year!

passenger94 commented 8 years ago

Happy new Year Folks !!! Wishing you truckloads of Fun and unacceptable insane amount of Love !

ccoupe commented 8 years ago

Whoa that was a big edit to the comment, @passenger94 ! You might remember that early versions of shoes_svg_new directly called the paint code before the first draw event was even possible. I took the code from what Image does.

passenger94 commented 8 years ago

Some of those comments had good instincts but some imprecisions too, i have a better grasp now of what's going on but not entirely ... Basically, at the moment, in some situation,start is not enough, and timer(0) is nothing else but a call to g_timeout_add, delaying code execution ...and the proposed solution works in some situation only.... Nothing rock solid ! btw i discoverd that #176 is happening right inside shoes_native_slot_paint, it is like Shoes is trying to repaint a last time but widget is already removed ...

passenger94 commented 8 years ago

I think i have something workable. (What follows is my understanding ... and gtk related)

First of all, use of start method (or style :start) is mandatory, direct drawing leads to ugly artefacts in drawing, noticeable in heavy drawings involving native widgets, so to have a smooth experience drawings have to be asynchronous (i mean in actual Shoes). I changed C's shoes_canvas_send_start method to also act after canvas creation (i found a mysterious, non used CANVAS_PAINT constant, maybe that was it's intended use), when clearing a slot for example, which was not the case before (hence the name), that was ONE of the reasons we needed timer(0) hack. An other reason has to do with the very very special case of slot having a height, there we end up having a slot with height surreptitiously nested inside another slot, in which case in C canvas and canvas->slot->owner are the same thing and we are good, but if the slot we are dealing with does not have a height, then we have two entities to manage and take care of, to make the send_start method working correctly ... A third reason is that no matter precise is the start method, sometimes if shoes is involved in heavy business inside the start method, it could bypass the drawing invoked just before, even if this one is, for Shoes, totally finished and everything is ready (.....) It's like Shoes, for some reason, doesn't have the chance to make the drawing visible, so i embedded a g_timeout_add_full with an interval of 1 millisecond (enough to trigger final drawing, gives a breath to Shoes)

So to make it short it's hopefully possible now to forget about timer(0) and cleanly use only start style/method If this is acceptable, we should make it more strongly visible in manual that drawings are asynchronous and the idiomatic Shoes way to deal with collateral effects is with the start method Sending a PR on a new branch "svg_start", waiting for heavy tests (create a new branch and let me know, so i can PR safely)

ccoupe commented 8 years ago

I'm going to merge the svg branch into master first and then we can create a branch from the updated master for your start/timer work which I don't think is svg releated, correct?

3.3.0 is feature complete (as they say), even with the OSX bug and the export method being unwritten. It's good enough for me and the idea was to get it out there and get feedback. You might want to create external copies of canvas.c , gtk.c etc that have you strt/timer changes so nothing gets lost.

passenger94 commented 8 years ago

yes it's not specific to svg, it just provided me with a good demo to check !

ccoupe commented 8 years ago

I finished the merge of svg into master and have created a timer-start branch.

ccoupe commented 8 years ago

Unsurprising to some, start doesn't fire on OSX. timer(0.1) works but we don't want. This is source of many confusions about video tests.

ccoupe commented 8 years ago

These start changes don't work on Windows either.

passenger94 commented 8 years ago

?? it works for me on windows7 ! (tested on latest master, well only on my system ...) But this branch (timer-start) is obsolete, should be deleted on osx there is a piece missing : see comment nbr 3 in #214, start is incorporated in master now , just need to finish the osx part

ccoupe commented 8 years ago

Yeah, start does work on Win7. It's a comedy of errors. I named the test scrip con.rb .. That turns out to be a very bad choice for windows since windows thinks it is the console device, not a filename.ext. Strange but true. Furthermore, Shoes.exe does not have $stdout or $stderr when run from msys but they are there if you use shoes.exe from dos console. Which makes Shoes.show_console pretty useless for anything particularly clever. cshoes.exe is fine in every shell but you don't need show_console at all in that case.

ccoupe commented 8 years ago

I'm working on the OSX side of this. I don't think glib timers are working on OSX. Canvas.c compiles and links but the start {} timer doesn't fire. We need a one shot NSTimer (and a NSInvocation and perhaps NSMethodSignature). My preference is to create a shoe_native_oneshot(msec, VALUE) - To be implemented in gtk.c and cocoa.m. but not exposed to Shoes scripts - they already have a one shot timer.

For OSX we have a ShoesTimer class - tied to Animate but a fine example to learn from. Of course we have the gtk code so that mostly just moving things around. For testing, I've created bugs/bug174.rb

# mix of problems with testing framework, cshoes, #174 & pull req #214
Shoes.app do
  @stk = stack do
    button "quit" do quit end
  end
  @stk.start do
  #timer(0.1) do
    para "In start blocks"
    #Shoes.show_console
    $stdout = $stderr
    $stdout.write "stdout printing\n"
    $stderr.puts "stderr printing"
    #if $stdout != $stderr
    #  $stdout = $stderr
      puts "Now on stdout?"
    #end
  end
end

Console issues aside that start code block is not executed on OSX.

ccoupe commented 8 years ago

1 msec seems overly hopeful for a timer setting (effectively 'start asap') compared to the older hack timer(0.1) which is 100 ms longer. FWIW, timer(0.1) doesn't match the manual. That says int seconds. Just something to ponder.

passenger94 commented 8 years ago

yes this is confusing it should be seconds and even when you give something less than 1 it should round it to 1 ! but from my experience it is totally not the case ...

From what i understand, the timing is not so important, except the shortest the best, the idea is to give Shoes some idle time so it can have opportunity to fire pending drawings (this is what is happening with the timer(o) {] trick) (but maybe 1ms is too optimistic)

!! Very surprising, the start event, per se (i mean the original one), should always start at slot creation time i.e. the first time the slot is drawn, the new start event/method helps when redrawing the slot, for example after a append, a clear etc ... it could also help in some edge case at creation time if there is intensive computing going on, but here, in your test app, it's dead simple it should work !!

Well....... gtk catches the drawing event (shoes_canvas_gtk_paint), then calls canvas.c drawing processings (shoes_canvas_paint -> shoes_canvas_paint_call), at the end of those, launches start method (shoes_canvas_send_start) is coca doing a similar thing ? only difference i can see is in the way cocoa is connected to the drawing event ... ? (which is kind of pure native Volapük slang to me) in drawRect: (NSRect)rect https://github.com/Shoes3/shoes3/blob/master/shoes/native/cocoa.m#L303

ccoupe commented 8 years ago

Obj->C and Cocoa are very OO - damn near everything is an object. You register to receive events mostly by defining the receiving method in your class. Obj->c dynamically looks to see if you have defined it and calls it. There are a LOT of Classes, methods and events. Apples documentation is pretty good. There is a lot to like but it's much different that gtk and C. There's alot to like about the Swift language too but the bridging to C appears to be immature and the linux & windows compilers don't have the gui classes.

ccoupe commented 8 years ago

Note that log.rb and help.rb both use timer(0.1). I'm not inclined to to fool with them.

FWIW, OSX time is a double and in seconds, so 1ms is 0.001. In gtk it's long int and counts milliseconds. That's another reason that I did not subclass ShoesTimer - although the obj->c is damn near identical. For shoe_native_oneshot() , which is not exposed to the users, I think the int ms arg is proper.

ccoupe commented 8 years ago

Now that the video test are partially working on OSX - they depend on start{} working -- I think this is done.