GA_ROOT vs GA_ROOTOWNER

1,607 views
Skip to first unread message

Marshall Greenblatt

unread,
Feb 15, 2010, 6:39:55 PM2/15/10
to chromi...@chromium.org
Hi All,

I'm a bit confused about the use of GA_ROOT and GA_ROOTOWNER as an argument to GetAncestor() in Chromium (Windows) sources.  In most places we're currently using GA_ROOT but in a few cases we're using GA_ROOTOWNER instead.  My understanding of the difference is that GA_ROOTOWNER guarantees that the returned value is a top-level window since only top-level windows can be owners.  However, it's unclear to me how a root window could be something other than a top-level window.  Also, in a number of places we're using GA_ROOT with the expectation that the returned value will be the top-level Chromium window (e.g. to retrieve the FocusManager instance).  Should we be using GA_ROOTOWNER instead in those places? Can any of the Windows gurus comment on the proper usage of these sparsely documented arguments?

Thanks,
Marshall

Peter Kasting

unread,
Feb 15, 2010, 9:01:33 PM2/15/10
to magree...@gmail.com, chromi...@chromium.org
I can't comment on _proper_ usage, but I can comment that in all code I've written and read I've used GA_ROOT, and I never even knew GA_ROOTOWNER existed.

I bet this is a case of copy and pasting (on both sides) without understanding.  A close reading of MSDN plus fixing all our code to do the right thing everywhere might be good.

PK

Marshall Greenblatt

unread,
Feb 15, 2010, 10:01:16 PM2/15/10
to Peter Kasting, chromi...@chromium.org
MSDN isn't very helpful on this issue, unfortunately:

http://msdn.microsoft.com/en-us/library/ms633502%28VS.85%29.aspx

--- begin snip ---

GA_ROOT
    Retrieves the root window by walking the chain of parent windows.
GA_ROOTOWNER
    Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.

--- end snip ---

Googling it doesn't offer much in the way of guidance either -- hence my posting here :-)

Hironori Bono (坊野 博典)

unread,
Feb 16, 2010, 1:08:38 AM2/16/10
to magree...@gmail.com, Peter Kasting, chromi...@chromium.org
Greetings Marshall,

To read this description, it seems GetAncestor(hwnd, GA_ROOT) just
calls GetParent(hwnd) to retrieve the parent window. On the other
hand, GetAncestor(hwnd, GA_ROOTOWNER) calls GetParent(hwnd) and calls
GetWindow(hwnd, GW_OWNER) if GetParent(hwnd) returns NULL. To read
through the MSDN document (*1) which writes differences between an
owned window and a child window, a dialog created with CreateDialog()
is usually an owned window but it is not a child window. So, we need
to use GetAncestor(hwnd, GA_ROOTOWNER) when we need to get the
top-level window from a dialog? (I'm not so confident of my opinion,
though.)

(*1) <http://msdn.microsoft.com/en-us/library/ms632599(VS.85).aspx>.

Best regards,

Hironori Bono
E-mail: hb...@chromium.org

> --
> Chromium Developers mailing list: chromi...@chromium.org
> View archives, change email options, or unsubscribe:
> http://groups.google.com/a/chromium.org/group/chromium-dev
>

Marshall Greenblatt

unread,
Feb 16, 2010, 10:41:06 AM2/16/10
to Hironori Bono (坊野 博典), Peter Kasting, chromi...@chromium.org
2010/2/16 Hironori Bono (坊野 博典) <hb...@chromium.org>
Greetings Marshall,

To read this description, it seems GetAncestor(hwnd, GA_ROOT) just
calls GetParent(hwnd) to retrieve the parent window. On the other
hand, GetAncestor(hwnd, GA_ROOTOWNER) calls GetParent(hwnd) and calls
GetWindow(hwnd, GW_OWNER) if GetParent(hwnd) returns NULL. To read
through the MSDN document (*1) which writes differences between an
owned window and a child window, a dialog created with CreateDialog()
is usually an owned window but it is not a child window. So, we need
to use GetAncestor(hwnd, GA_ROOTOWNER) when we need to get the
top-level window from a dialog? (I'm not so confident of my opinion,
though.)

I've performed an experiment to test the behavior on Windows 7.  DialogA creates DialogB which then creates DialogC.

DialogA = 60f3e
GetParent(DialogA) = 0
GetAncestor(DialogA, GA_ROOT) = 60f3e
GetAncestor(DialogA, GA_ROOTOWNER) = 60f3e
DialogB = 30fde
GetParent(DialogB) =60f3e
GetAncestor(DialogB, GA_ROOT) = 30fde
GetAncestor(DialogB, GA_ROOTOWNER) = 60f3e
DialogC = 30fea
GetParent(DialogC) =30fde
GetAncestor(DialogC, GA_ROOT) = 30fea
GetAncestor(DialogC, GA_ROOTOWNER) = 60f3e

I also checked the Wine implementation of GetAncestor() and GetParent():
http://source.winehq.org/source/dlls/user32/win.c#L2609
http://source.winehq.org/source/dlls/user32/win.c#L2568

If the window passed to GetParent() has the WS_POPUP flag it returns the window's owner and if it has the WS_CHILD flag it returns the window's parent.  This matches with the experimental results.

All of this indicates the following:

1. GetAncestor(hwnd, GA_ROOTOWNER) walks the child hierarchy using GetParent() to reach the top-level window.
2. GetAncestor(hwnd, GA_ROOT) returns the current dialog window.

So, in conclusion, if the intent is to retrieve the top-level window we should be using GetAncestor(hwnd, GA_ROOTOWNER) and if the intent is to return the current dialog window we should be using GetAncestor(hwnd, GA_ROOT).
 

Marshall Greenblatt

unread,
Feb 16, 2010, 11:46:17 AM2/16/10
to Hironori Bono (坊野 博典), Peter Kasting, chromi...@chromium.org
2010/2/16 Marshall Greenblatt <magree...@gmail.com>

All of this indicates the following:

1. GetAncestor(hwnd, GA_ROOTOWNER) walks the child hierarchy using GetParent() to reach the top-level window.
2. GetAncestor(hwnd, GA_ROOT) returns the current dialog window.

So, in conclusion, if the intent is to retrieve the top-level window we should be using GetAncestor(hwnd, GA_ROOTOWNER) and if the intent is to return the current dialog window we should be using GetAncestor(hwnd, GA_ROOT).



 My use of the term "top-level" above is incorrect.  From http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx

--- begin snip ---

An active window is the top-level window of the application with which the user is currently working. To allow the user to easily identify the active window, the system places it at the top of the z-order and changes the color of its title bar and border to the system-defined active window colors. Only a top-level window can be an active window. When the user is working with a child window, the system activates the top-level parent window associated with the child window.

--- end snip ---

Also from the above document, a window can have styles WS_POPUP or WS_OVERLAPPED and qualify as an owner.  So it would be more accurate to say that GetAncestor(hwnd, GA_ROOTOWNER) returns the root-most window with WS_POPUP or WS_OVERLAPPED styles.


Marshall Greenblatt

unread,
Feb 16, 2010, 1:11:58 PM2/16/10
to Peter Kasting, chromi...@chromium.org
On Mon, Feb 15, 2010 at 9:01 PM, Peter Kasting <pkas...@google.com> wrote:
I can't comment on _proper_ usage, but I can comment that in all code I've written and read I've used GA_ROOT, and I never even knew GA_ROOTOWNER existed.

I bet this is a case of copy and pasting (on both sides) without understanding.  A close reading of MSDN plus fixing all our code to do the right thing everywhere might be good.

I've gone through our current usage of GetAncestor() in Chromium and all uses appear to be correct. To make the usage clearer for the future what do you think about adding new functions to win_util and using those functions instead of calling GetAncestor() directly?

/* Returns the root ancestor window closest to |hwnd|. Root windows have style
   WS_OVERLAPPED or WS_POPUP.  If |hwnd| is a root window then |hwnd| will
   be returned. If |hwnd| has style WS_CHILD then the closest root ancestor window
   will usually be the top-level dialog that contains |hwnd|. */
HWND GetClosestRootAncestor(HWND hwnd) {
  return ::GetAncestor(hwnd, GA_ROOT);
}

/* Returns the root ancestor window furthest from |hwnd|. Root windows have style
   WS_OVERLAPPED or WS_POPUP.  The furthest root ancestor window will
   usually be the main application window. */
HWND GetFurthestRootAncestor(HWND hwnd) {
  return ::GetAncestor(hwnd, GA_ROOTOWNER);
}
 

PK

Peter Kasting

unread,
Feb 16, 2010, 2:26:13 PM2/16/10
to Marshall Greenblatt, chromi...@chromium.org
On Tue, Feb 16, 2010 at 10:11 AM, Marshall Greenblatt <magree...@gmail.com> wrote:
To make the usage clearer for the future what do you think about adding new functions to win_util and using those functions instead of calling GetAncestor() directly?

/* Returns the root ancestor window closest to |hwnd|. Root windows have style
   WS_OVERLAPPED or WS_POPUP.  If |hwnd| is a root window then |hwnd| will
   be returned. If |hwnd| has style WS_CHILD then the closest root ancestor window
   will usually be the top-level dialog that contains |hwnd|. */
HWND GetClosestRootAncestor(HWND hwnd) {
  return ::GetAncestor(hwnd, GA_ROOT);
}

/* Returns the root ancestor window furthest from |hwnd|. Root windows have style
   WS_OVERLAPPED or WS_POPUP.  The furthest root ancestor window will
   usually be the main application window. */
HWND GetFurthestRootAncestor(HWND hwnd) {
  return ::GetAncestor(hwnd, GA_ROOTOWNER);
}

Ambivalent.  I like that there are comments, but I'm not a huge fan of functions that merely rename an existing Windows function, and because the difference is still subtle, I worry that this doesn't really make it less likely that someone will copy and paste the wrong thing.

So I probably wouldn't do anything.

PK

Marshall Greenblatt

unread,
Feb 16, 2010, 2:35:07 PM2/16/10
to Peter Kasting, chromi...@chromium.org

OK, that works :-).
 

PK

Hironori Bono (坊野 博典)

unread,
Feb 17, 2010, 11:03:50 PM2/17/10
to Marshall Greenblatt, Peter Kasting, chromi...@chromium.org
Greetings Marshall,

Thank you for your experiment. It's awesome.

Best regards,

Hironori Bono
E-mail: hb...@chromium.org

2010/2/17 Marshall Greenblatt <magree...@gmail.com>:

Reply all
Reply to author
Forward
0 new messages