Webdialog position/size and pref_key on Mac OS X

195 views
Skip to first unread message

Jonathan Winterflood

unread,
Jan 13, 2011, 2:15:01 PM1/13/11
to sketch...@googlegroups.com
Hi all,

WebDialog seems not to save/restore it's size and position on Mac OS X.
I seem to remember reading about it somewhere, but I can't find where now....

Is there a fix/workaround?

Thanks,
--
Jonathan

Todd Burch

unread,
Jan 13, 2011, 2:28:57 PM1/13/11
to sketch...@googlegroups.com
Post some code.

Jonathan Winterflood

unread,
Jan 13, 2011, 3:57:20 PM1/13/11
to sketch...@googlegroups.com
Sure...

* In the console: UI::WebDialog.new("foo", true, "testkey").show()

* Then move, resize, close the dialog

* Then same code again.

Note the dialog has the default size/position again.

Works fine in Windows and Ubuntu+Wine

Cheers,
--
Jonathan


On Thu, Jan 13, 2011 at 20:28, Todd Burch <mr.tod...@gmail.com> wrote:
Post some code.

--
You received this message because you are subscribed to the Google Groups "SketchUp Ruby API" group.
To post to this group, send email to sketch...@googlegroups.com.
To unsubscribe from this group, send email to sketchupruby...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sketchupruby?hl=en.

Dan Rathbun

unread,
Jan 13, 2011, 7:35:21 PM1/13/11
to Google SketchUp Developers - SketchUp Ruby API
what about using x,y,width, height arguments?

or:

what about making calls to set_size() and set_postion() before you
call show() ?

also when you instance a WebDialog object, they may not get GC'd
during the session. I remember TIG or AdamB writing about this.

What happens if you close SU, reopen it, and open a new "foo" dialog ?

The proper thing to do in Ruby is to hold a reference to the
fooDialog, and when the user clicks the menu (or toolbar button,) the
second time, your code should check if the instance has already been
created.
I use a @@instance class var in the WebDialog subclass, if I'm
subclassing; if not @@instance is a module var in the module that
creates the dialog.
Initially, inside the module or class definition, @@instance is set
false.
When the user clicks a menu item, or toolbar button, a use() class (or
module) method is called:

def self.use()
#
@@instance=self.new() if @@instance==false
#
if @@validation==MF_CHECKED
@@instance.close
else
if @@instance.visible?
@@instance.bring_to_front
else
@@instance.show
end
# be sure menu item and toolbar buttons are still checked
@@validation=MF_CHECKED
end
#
end # method

@@validation is initially set to MF_ENABLED at the top of the module
or class definition.

the set_on_close() callback (of the dialog instance,) would have the
statement:
@@validation=MF_UNCHECKED

the block for menu item (or UI::Command object,) should call the
class' or module's use() method, instead of calling a new()
constructor. (Otherwise you end up with numerous instances created
each time the user clicks a button.)

the item or button's set_validation_proc block is simply
{ @@validation }
* I prefer not to have conditionals being run on each redraw of the
UI, inside validation procs, if I can do them elsewhere. Meaning if
the validation integer will not change until the user does something,
then change the value then by changing the value of a class or module
var, and Sketchup will pick up the change on the next UI redraw.

~

Todd Burch

unread,
Jan 13, 2011, 7:37:07 PM1/13/11
to sketch...@googlegroups.com
Coding it right, it works for me just fine.  

Recognize what you are doing.  Each time you issue 

UI::WebDialog.new("foo", true, "testkey").show() 


you are creating a new instance of a web dialog, which wipes out the old one.  


However, if you code this: 



u = UI::WebDialog.new("foo", true, "testkey")

u.show() 

move the dialog 

close the dialog 

u.show()  


it will show up where you left it.  




Dan Rathbun

unread,
Jan 13, 2011, 7:41:55 PM1/13/11
to Google SketchUp Developers - SketchUp Ruby API
"WebDialog's - The Lost Manual"
by Thomas Thomassen
http://forums.sketchucation.com/download/file.php?id=36664

Jonathan Winterflood

unread,
Jan 14, 2011, 5:45:05 AM1/14/11
to sketch...@googlegroups.com
Dan, Thanks for your long reply, and the Manual Link (that might be the document I was thinking of; no wonder Google couldn't find it behind the SketchUcation login-wall)

Note that:
The code I posted is a minimal testcase, not my plugin code.
Both my plugin and the testcase work as I want (and should, AFAICT) in Windows or Wine, but not in MacOS


On Fri, Jan 14, 2011 at 01:35, Dan Rathbun <dan...@earthlink.net> wrote:
what about using x,y,width, height arguments?

or:

what about making calls to set_size() and set_postion() before you
call show() ?

I do not want to set a default size, but I do want the size that the user chooses to persist over WebDialog close/reopens, and SketchUp close/reopen.
That is the whole purpose of the pref_key parameter:
""""Fixed window size
When you specify position and size Sketchup only uses those values the first time you create the dialog. After that it reads the last used values from the registry. That might be want to you want for resizable windows [...]"""
Webdialogs - The Lost Manual by Thomas Thomassen
 

also when you instance a WebDialog object, they may not get GC'd
during the session. I remember TIG or AdamB writing about this.
Fair enough, but I don't care in this case, I'm creating a new one from scratch that should grab it's position and size from the key.


What happens if you close SU, reopen it, and open a new "foo" dialog ?
Same thing
Thanks for the snippet.
Currently, my plugin holds a reference to the dialog, and kills+respawns one when the button is clicked again. Your method may well be better, I shall consider it.
However, It would still not solve the non-persistence of position over Sketchup restarts.

Cheers,
Jonathan

Jonathan Winterflood

unread,
Jan 14, 2011, 6:00:24 AM1/14/11
to sketch...@googlegroups.com
Todd, Thanks for your answer

On Fri, Jan 14, 2011 at 01:37, Todd Burch <mr.tod...@gmail.com> wrote:
Coding it right, it works for me just fine.  

Recognize what you are doing.  Each time you issue 

UI::WebDialog.new("foo", true, "testkey").show() 


you are creating a new instance of a web dialog, which wipes out the old one.  


True, but I intended to do that, although as Dan pointed out, it may be wiser to keep the dialog for the whole session.
Personally I'd rather destroy the dialog when it's not used, to save resources. (although my plugin does not actually do this, I meant it to... In the testcase, I believe the GC will eventually find and reap the dead Dialog once it's closed, right?)

The third parameter 'testkey' is used by SketchUp to save/restore dialog positions over WebDialog respawn and SketchUp reboots.
This code works fine on Windows/Wine
 

However, if you code this: 



u = UI::WebDialog.new("foo", true, "testkey")

u.show() 

move the dialog 

close the dialog 

u.show()  


it will show up where you left it.  


Indeed, this works on all OSes within a single SketchUp session.
On MacOS however, we're back to square one when we reboot SketchUP, whereas Windows/Wine stores the position against the key, and reopens the dialog in the correct place.


Cheers,
--
Jonathan

Dan Rathbun

unread,
Jan 14, 2011, 5:02:39 PM1/14/11
to Google SketchUp Developers - SketchUp Ruby API
On Jan 14, 6:00 am, Jonathan Winterflood wrote:
>
> On MacOS however, we're back to square one when we reboot SketchUP, whereas
> Windows/Wine stores the position against the key, and reopens the dialog in
> the correct place.

Do you see this behaviour with 7.x and 8.x, or is this a new bug ?

I will say that the UI::WebDialog.new() method is "cranky" when it
comes to processing arguments... if you put nil as the pref_key arg,
the method stops processing the remaining args. We discussed this in
the API topic over at SCF.
This is why I asked if you specified all arguments... the argument
processing for that method needs an overhaul !!

Your other option is to use the hash list as the argument, and try out
the 9th argument which has hashkey "mac_only_use_nswindow" (boolean
value.) Note that processing of a hash is also cranky... it doesn't
work correctly if string keys are used (at least on SU 7.x,) ... so
use symbol keys.

keys = {
:dialog_title => title,
:scrollable => false,
:preferences_key => 'MyDialog',
:height => 300,
:width => 400,
:left => 200,
:top => 200,
:resizable => true,
:mac_only_use_nswindow => true}

@dialog = UI::WebDialog.new(keys)

~

Jonathan Winterflood

unread,
Jan 15, 2011, 6:39:31 AM1/15/11
to sketch...@googlegroups.com
Dan,

On Fri, Jan 14, 2011 at 23:02, Dan Rathbun <dan...@earthlink.net> wrote:
On Jan 14, 6:00 am, Jonathan Winterflood wrote:
>
> On MacOS however, we're back to square one when we reboot SketchUP, whereas
> Windows/Wine stores the position against the key, and reopens the dialog in
> the correct place.

Do you see this behaviour with 7.x and 8.x, or is this a new bug ?
 
Installed 7 Pro trial, same results (including with all args or a hash)
 
I will say that the UI::WebDialog.new() method is "cranky" when it
comes to processing arguments... if you put nil as the pref_key arg,
the method stops processing the remaining args. We discussed this in
the API topic over at SCF.
This is why I asked if you specified all arguments... the argument
processing for that method needs an overhaul !!

Ah yes, I see

Setting the 4 last arguments (50, 50, 50, 50 was what I used) does not fail, but it always uses the arguments instead of the key.
 
Your other option is to use the hash list as the argument, and try out
the 9th argument which has hashkey "mac_only_use_nswindow" (boolean
value.) Note that processing of a hash is also cranky... it doesn't
work correctly if string keys are used (at least on SU 7.x,) ... so
use symbol keys.

keys = {
:dialog_title => title,
:scrollable => false,
:preferences_key => 'MyDialog',
:height => 300,
:width => 400,
:left => 200,
:top => 200,
:resizable => true,
:mac_only_use_nswindow => true}

@dialog = UI::WebDialog.new(keys)

Same here, uses the passed dimensions.
If dimensions are missing from the hash, still does not use the key
:mac_only_use_nswindow true or false has no visible effect

Thanks for the ideas
--
Jonathan

Dan Rathbun

unread,
Jan 15, 2011, 2:07:53 PM1/15/11
to Google SketchUp Developers - SketchUp Ruby API
ThomThom has started a topic at SCF to discuss this... seems we have
problems on PC as well, when using a hash (7.1 and 8.x,) but using
just args works.
http://forums.sketchucation.com/viewtopic.php?f=180&t=34216

By the way...

I think that there should only be one dialog instance using a specific
key.
On PC they are prepended with "WebDialog_" in the registry.
Dont know if it's the same on Mac for plist files.

Jonathan Winterflood

unread,
Jan 15, 2011, 3:49:32 PM1/15/11
to sketch...@googlegroups.com
Dan,

On Sat, Jan 15, 2011 at 20:07, Dan Rathbun <dan...@earthlink.net> wrote:
ThomThom has started a topic at SCF to discuss this... seems we have
problems on PC as well, when using a hash (7.1 and 8.x,) but using
just args works.
http://forums.sketchucation.com/viewtopic.php?f=180&t=34216

Great!
 
By the way...

I think that there should only be one dialog instance using a specific
key.
If one wants the size/position to be stored separately, one should obviously use separate keys.
If you do open several dialogs with the same key, the behaviour is probably undefined (or at least incompletely specified)
I wouldn't expect anything more dramatic than the last size/position change or dialog close winning the fight, though...

On PC they are prepended with "WebDialog_" in the registry.
Dont know if it's the same on Mac for plist files.
Looks like they are supposed to be in a "WebDialog" "section" on Mac, but mine do not show up so not sure.


My plist file does not mention the WebDialog key I use in my plugin or in the test code, I did do some investigation though:

# convert to xml from binary plist format
# output to stdout
plutil -convert xml1 -o - ~/Library/Preferences/com.google.sketchupfree8.plist

in the output:

# This seems to be my plugin's toolbar
    <key>ALToolPalette_my-toolbar-name_frame</key>
    <string>232 742 208 36 0 0 1280 778 </string>

# Entity info frame
    <key>Entity Info_frame</key>
    <string>1130 762 150 16 0 0 1280 778 </string>

# Palette/toolbar positions
    <key>NSWindow Frame GoogleToolPaletteLarge</key>
    <string>0 87 71 159 0 0 1280 778 </string>
    <key>NSWindow Frame NSColorPanel</key>
    <string>346 253 201 309 0 0 1280 778 </string>
    <key>NSWindow Frame NSFontPanel</key>
    <string>700 53 445 270 0 0 1280 778 </string>
    <key>NSWindow Frame RubyPanel</key>
    <string>530 61 752 316 0 0 1280 778 </string>
    <key>NSWindow Frame SketchUpDoc</key>
    <string>0 77 1024 701 0 0 1280 778 </string>
    <key>NSWindow Frame SolidModelToolPaletteLarge</key>
    <string>0 -14 71 126 0 0 1280 778 </string>
    <key>NSWindow Frame ToolPaletteLarge</key>
    <string>1187 153 71 598 0 0 1280 778 </string>

## data seems to be X Y Width Height ? ? Screen_width Screen_height (? ? is probably screen origin?)

# my plugin settings created with Sketchup.write_default
    <key>SketchUp.my_section.my_variable</key>
    <string>"my data here"</string>
## note the quote marks, these are added by SketchUp, ie: not present in the string I write or retrieve

# Main frame size/position
    <key>Sketchup.MainFrameSize</key>
    <string>{{1, 1}, {1024, 790}}</string>
## This doesn't seem correct though, max available screen size on this machine is 1280/800, minus the dock and the menu bar, so probably the 1280/778 mentioned above.
## Also, SketchUp Mac can have several main windows.
## However, new windows seem to try and use this size (and get their height clipped by the OS)

# Some web dialog obviously, not sure what it is though; Maybe the welcome screen?
    <key>WebDialog.ModelHere.Height</key>
    <integer>652</integer>
    <key>WebDialog.ModelHere.Width</key>
    <integer>925</integer>
# Strange that it uses a different format to the other windows, and there's no mention of the position...

# Talking of which...
    <key>displayWelcomeOnStartup</key>
    <false/>

So no mention of my WebDialog.
It may be that a section is created but pruned out because it is empty, or just that MacOS plists do not do sections, just foo.bar.baz.blah.whatever keys

Also, the file is only written (and read, probably) on Sketchup Quit, for those wanting to hack further.

Cheers,
Jonathan

Dan Rathbun

unread,
Jan 15, 2011, 8:32:06 PM1/15/11
to Google SketchUp Developers - SketchUp Ruby API
The DC Extension adds a few methods to the UI::WebDialog class. (**But
DCs must be enabled**)

last_height()
last_height()=
last_width()
last_width()=

So at least for size, you can use the getters within your
set_on_close() method to save the dialog size to your plugin's
defaults, and restore them thru the new() args, when the plugin is
used again.

For position... perhaps thru Javascript, maybe the window object have
a method / function to get position, then you could send it to ruby
via a calback, and again save to your plugins defaults.
x = window.screenLeft
y = window.screenTop
These may be IE only, as the bottom of the MSDN page says "There is no
public standard that applies to this property."

~

Myself.. I am 99% ready to abandon any interaction using
write_defaults() and read_defaults(), and just start using a settings
hash, then write it out to a file (in the plugin's subfolder,) using
hash.inspect(). To use the file, just read it into a String, and
eval() it back into a hash var:

# writes it out
sfile = File.new("subdir/mypluginsettings.txt",'w')
sfile.write( settings_hash.inspect )
sfile.close

# brings it in:
sfile = IO.readlines("subdir/mypluginsettings.txt")[0]
settings_hash = eval( sfile.chomp )

~

Jonathan Winterflood

unread,
Jan 15, 2011, 10:00:58 PM1/15/11
to sketch...@googlegroups.com
On Sun, Jan 16, 2011 at 02:32, Dan Rathbun <dan...@earthlink.net> wrote:
The DC Extension adds a few methods to the UI::WebDialog class. (**But
DCs must be enabled**)

Does this mean Pro only?
 
last_height()
last_height()=
last_width()
last_width()=

So at least for size, you can use the getters within your
set_on_close() method to save the dialog size to your plugin's
defaults, and restore them thru the new() args, when the plugin is
used again.

For position... perhaps thru Javascript, maybe the window object have
a method / function to get position, then you could send it to ruby
via a calback, and again save to your plugins defaults.
x = window.screenLeft
y = window.screenTop
These may be IE only, as the bottom of the MSDN page says "There is no
public standard that applies to this property."

Thanks for the idea.
I could maybe use JS for the window size also, not sure if there's an event for resize or move...
The onclose(if that's it's name) Javascript event could suffice, we don't need real-time updates

Not sure how many of all these are available in Safari

For the moment, I think I shall set some sane defaults and come back when the rest of the plugin works :)

~

Myself.. I am 99% ready to abandon any interaction using
write_defaults() and read_defaults(), and just start using a settings
hash, then write it out to a file (in the plugin's subfolder,) using
hash.inspect(). To use the file, just read it into a String, and
eval() it back into a hash var:

# writes it out
sfile = File.new("subdir/mypluginsettings.txt",'w')
sfile.write( settings_hash.inspect )
sfile.close

# brings it in:
sfile = IO.readlines("subdir/mypluginsettings.txt")[0]
settings_hash = eval( sfile.chomp )

Nice, and easier for any more than a few bits of data.
The downside is that it's not user-specific any more.
Not that's likely to be a problem very often, but a solution would be to store the inspected hash in a defaults variable (maybe base64 it first: [str].pack('m') / str64.unpack('m')[0])

In my case I only have one string to save (actually a legacy code that is a base64 of the data!)

Cheers,
Jonathan

Dan Rathbun

unread,
Jan 16, 2011, 6:19:53 PM1/16/11
to Google SketchUp Developers - SketchUp Ruby API
On Jan 15, 10:00 pm, Jonathan Winterflood wrote:
> On Sun, Jan 16, 2011 at 02:32, Dan Rathbun wrote:
>
> > Myself.. I am 99% ready to ... just start using a settings
> > hash, then write it out to a file ...
>
> Nice, and easier for any more than a few bits of data.
>
> The downside is that it's not user-specific any more.
> In my case I only have one string to save (actually a
> legacy code that is a base64 of the data!)

No problem on the User!
Mac : user = ENV['User']
Win : user = ENV['USERNAME']

The beauty of the inspect() method is that it properly walks complex
nested structures and outputs a string that can be re-eval'd back into
that same structure.

This means Arrays with nested arrays and /or hashes, or a Hash, with
nested arrays or hashes. It's similar to a JSON string.

Anyway... you can have a Settings hash, with User Keys pointing at a
single value (if you wish,) OR pointing at a nested array or nested
hash.

And BTW.. (offtopic,) this same feature can be used to easily store
and retrieve, complex data structures into/outof Attribute Dictionary
values.
~

Jonathan Winterflood

unread,
Jan 16, 2011, 6:39:48 PM1/16/11
to sketch...@googlegroups.com
Dan,
Yes I think we're really off-topic now...

On Mon, Jan 17, 2011 at 00:19, Dan Rathbun <dan...@earthlink.net> wrote:
On Jan 15, 10:00 pm, Jonathan Winterflood wrote:
> On Sun, Jan 16, 2011 at 02:32, Dan Rathbun wrote:
>
> > Myself.. I am 99% ready to ... just start using a settings
> > hash, then write it out to a file ...
>
> Nice, and easier for any more than a few bits of data.
>
> The downside is that it's not user-specific any more.
> In my case I only have one string to save (actually a
> legacy code that is a base64 of the data!)

No problem on the User!
Mac : user = ENV['User']
Win :  user = ENV['USERNAME']
True, but that means another thing to do that you could just let SketchUp deal with.
Files definitely mean you don't need to worry about size limits (if there are any in registry/plist?) for example.
Personal preference really, I'd say, unless we're really pushing the envelope.

The beauty of the inspect() method is that it properly walks complex
nested structures and outputs a string that can be re-eval'd back into
that same structure.
Nice
 
This means Arrays with nested arrays and /or hashes, or a Hash, with
nested arrays or hashes. It's similar to a JSON string.
I suppose our own classes can define an inspect method too?
As long as we have a tree structure not a graph, it should be ok (graphs==nightmare unless we use a factory setup with uids or something... which gets difficult fast...)
 
Anyway... you can have a Settings hash, with User Keys pointing at a
single value (if you wish,) OR pointing at a nested array or nested
hash.

And BTW.. (offtopic,) this same feature can be used to easily store
and retrieve, complex data structures into/outof Attribute Dictionary
values.
Indeed
~

Cheers,
Jonathan 

Dan Rathbun

unread,
Jan 16, 2011, 8:03:05 PM1/16/11
to Google SketchUp Developers - SketchUp Ruby API
On Jan 16, 6:39 pm, Jonathan Winterflood wrote:
> Dan,
> Yes I think we're really off-topic now...

But in your first post.. you asked if there was a workaround. :)

> I suppose our own classes can define an inspect method too?

Override actually. The inspect() method comes from Object, so is
inherited by ALL classes.
The Ruby API on Object.inspect() says:
"Returns a string containing a human-readable representation of obj.
If not overridden, uses the to_s method to generate the string."

In fact Geom::Point3d overrode both inspect() and to_s():
Console:
Geom::Point3d.instance_methods(false).include?('inspect')
true
Geom::Point3d.instance_methods(false).include?('to_s')
true

So YES.. you can, and you may have to_s() to fall back on when you do
override inspect()
You do need to be aware when subclassing a Class that has already
overidden one or both of these methods, that your subclass will
inherit the superclass' overrides rather than the originals from
Object.

Dan Rathbun

unread,
Jan 16, 2011, 8:45:12 PM1/16/11
to Google SketchUp Developers - SketchUp Ruby API
On Jan 16, 6:39 pm, Jonathan Winterflood wrote:

> On Mon, Jan 17, 2011 at 00:19, Dan Rathbun wrote:
> > On Jan 15, 10:00 pm, Jonathan Winterflood wrote:
> > > On Sun, Jan 16, 2011 at 02:32, Dan Rathbun wrote:
>
> > > > Myself.. I am 99% ready to ... just start using a settings
> > > > hash, then write it out to a file ...

> True, but that means another thing to do that you could just let
> SketchUp deal with.

But they cannot "get it right"... this feature of the API is
unreliable, in 3 areas:

> Files definitely mean you don't need to worry about size limits (if there
> are any in registry/plist?) for example.

On Win there is a registry size limit (for at least the system hive,)
but weirdly there is a registry attribute to hold the limit that can
be changed. The limit is set lower for "Home" and "CE" editions, than
"Pro" editions. I ran up against the limit on XP Home edition. The
Skethcup Settings are kept in the User Hive of the registry.

** Reliability:
The other problem we have on both platforms.. is the "all eggs in one
basket"
if a user is having App problems... they sometimes delete all the
plist files on Mac to reset the settings back to OEM default.
On PC, they may uninstall and reinstall (unless they are savy at using
the registry editor,) which wipes out the whole app settings
"attribute tree"

Anyway.. having them all in one place can be a detriment.
Further.. on Windows.. plugin keys are not automatically prepended
with a "Plugin_" substring. They are at the same level as Google's
application keys, and we can write extra attributes into their keys,
and I imagine possible overright attributes. The webdialog, on the
otherhand, always prepends "WebDialog_" to any pref_key (at least on
PC.)

** Maintenance:
The API defaults feature has no cleanup functions at all. We have
"write" and "read" but no "remove".
The registry (and I imagine plist,) become cluttered with old
abandoned keys and attributes.

** Portability:
On Windows, we can not make copies of the User hive (user.dat) as the
system puts a lock on it.
There may be users who want to take their plugins and settings with
them (say, on a thumbdrive,) and it would be easier if settings were
in files, either with the plugin, or in a "Sketchup/plugins" folder
heirarchy beneath the user's documents dir.
ie ~/documents/sketchup/plugins/
It's also likely the user would have folders there with skp files they
wish to "take along"

So now they can just copy the app/plugins foldertree (the rubies) and
their ~/documents/sketchup foldertree (settings, skps, skms, textures,
components, etc etc.)... and away they go ... off to another computer
that already has Sketchup on it.

There are people who are already keeping their plugin rubies in a
special place (and I am going to do that myself, as I got burned by
the latest M1 installer.)
I think Jim Foltz said he runs his plugins (for ALL his SU versions,)
from a single folder in the root of his C: drive.
Another guy told me his plugins folder is in his USER path somewhere.
I think I'll do the latter.

Anyway.. we discussed some of this at SCF:
"Where to Store User Settings?"
http://forums.sketchucation.com/viewtopic.php?f=180&t=33873
~

Jonathan Winterflood

unread,
Jan 18, 2011, 1:53:53 PM1/18/11
to sketch...@googlegroups.com
OK, I think you've won me over :D

For my plugin the data is not at all critical (last generated object parameters) so I won't bother, but if I have anything more interesting to keep then I'll definitely consider using a file.

Cheers,
--
Jonathan


~

Reply all
Reply to author
Forward
0 new messages