Square area in top left of desktop slow to load when launching Firefox

Bug #1107850 reported by Tony Pursell on 2013-01-28
This bug affects 5 people
Affects Status Importance Assigned to Milestone
Mozilla Firefox
Fix Released
firefox (Ubuntu)

Bug Description

When launching Firefox (18.0.1 Mozilla Firefox for Ubuntu canonical 1.0) an area of the desktop in the top left of the screen is slow to load.

See attached file.

Although I am using 12.04 (fully updated, including proposed) I know this also affect people with 12.10.

ProblemType: Bug
DistroRelease: Ubuntu 12.04
Package: compiz 1:
ProcVersionSignature: Ubuntu 3.2.0-36.57-generic-pae 3.2.35
Uname: Linux 3.2.0-36-generic-pae i686

ApportVersion: 2.0.1-0ubuntu17.1
Architecture: i386
CompizPlugins: [core,composite,opengl,compiztoolbox,decor,vpswitch,snap,mousepoll,resize,place,move,wall,grid,regex,imgpng,session,gnomecompat,animation,fade,unitymtgrabhandles,workarounds,scale,expo,ezoom,unityshell]
CompositorRunning: compiz
Date: Mon Jan 28 12:32:18 2013
DistUpgraded: 2012-04-29 16:10:31,037 DEBUG failed to SystemUnLock() (E:Not locked)
DistroCodename: precise
DistroVariant: ubuntu
 Advanced Micro Devices [AMD] nee ATI RC410 [Radeon Xpress 200] [1002:5a61] (prog-if 00 [VGA controller])
   Subsystem: Hewlett-Packard Company Device [103c:2a3d]
InstallationMedia: Ubuntu 10.04 LTS "Lucid Lynx" - Release i386 (20100429)
 Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
 Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
 Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
 Bus 003 Device 002: ID 058f:9360 Alcor Micro Corp. 8-in-1 Media Card Reader
MachineType: HP Pavilion 061 RA918AA-ABU t3510.uk
MarkForUpload: True
PackageArchitecture: all
ProcKernelCmdLine: BOOT_IMAGE=/boot/vmlinuz-3.2.0-36-generic-pae root=UUID=95627c5a-4942-4b2a-81f0-b937540facaf ro radeon.modeset=1 resume=UUID=cc873305-f512-4d29-9d31-46311cd5e830 quiet splash vt.handoff=7
SourcePackage: compiz
UpgradeStatus: Upgraded to precise on 2012-04-29 (273 days ago)
dmi.bios.date: 04/10/2006
dmi.bios.vendor: American Megatrends Inc.
dmi.bios.version: 3.11
dmi.board.name: Asterope
dmi.board.vendor: Hewleet-Packard
dmi.board.version: 1.0
dmi.chassis.type: 3
dmi.modalias: dmi:bvnAmericanMegatrendsInc.:bvr3.11:bd04/10/2006:svnHPPavilion061:pnRA918AA-ABUt3510.uk:pvr00E0211RE101ASTE200:rvnHewleet-Packard:rnAsterope:rvr1.0:cvn:ct3:cvr:
dmi.product.name: RA918AA-ABU t3510.uk
dmi.product.version: 00E0211RE101ASTE200
dmi.sys.vendor: HP Pavilion 061
version.compiz: compiz 1:
version.libdrm2: libdrm2 2.4.39-0ubuntu0.1
version.libgl1-mesa-dri: libgl1-mesa-dri 8.0.4-0ubuntu0.3
version.libgl1-mesa-dri-experimental: libgl1-mesa-dri-experimental N/A
version.libgl1-mesa-glx: libgl1-mesa-glx 8.0.4-0ubuntu0.3
version.xserver-xorg-core: xserver-xorg-core 2:1.11.4-0ubuntu10.11
version.xserver-xorg-input-evdev: xserver-xorg-input-evdev 1:2.7.0-0ubuntu1.2
version.xserver-xorg-video-ati: xserver-xorg-video-ati 1:6.14.99~git20111219.aacbd629-0ubuntu2
version.xserver-xorg-video-intel: xserver-xorg-video-intel 2:2.17.0-1ubuntu4.2
version.xserver-xorg-video-nouveau: xserver-xorg-video-nouveau 1:0.0.16+git20111201+b5534a1-1build2

Created attachment 663821

Build Identifier:
Mozilla/5.0 (X11; Linux i686; rv:18.0) Gecko/18 Firefox/18.0a1 ID:20120921030601

Ubuntu 12.04.1
At the time of a start of the browser window, a desktop is seen in the top left corner temporarily

This problem happens regardless with HWA on/off
I can reproduce only in Nightly18.0a1.

Regression window
Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/17 Firefox/17.0a1 ID:20120813030532
Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/17 Firefox/17.0a1 ID:20120814030521

In local build,
Last Good: ed614ea130c0
First Bad: 13d19788ad1d

  Adapter Description : VMware, Inc. -- Gallium 0.4 on SVGA3D; build: RELEASE;
  Device ID : Gallium 0.4 on SVGA3D; build: RELEASE;
  Driver Version : 2.1 Mesa 8.0.2
  GPU Accelerated Windows : 0/1 Basic no information
  Vendor ID : VMware, Inc.
  WebGL Renderer : VMware, Inc. -- Gallium 0.4 on SVGA3D; build: RELEASE; -- 2.1 Mesa 8.0.2
  AzureCanvasBackend : cairo
  AzureContentBackend : none
  AzureFallbackCanvasBackend : none

Much more obvious without a compositing window manager.
viewmanager.refresh-driver-painting.enabled false restores the old behavior.

I don't know if this is useful information, but I don't see this problem when omtc is enabled. (For whatever reason.)

This seems to be some interaction with GDK applying shapes to child windows.

Before GTK maps the toplevel window, it issues a ConfigureRequest to resize the window. Probably because this request may be redirected to and modified by the window manager, though I'm not sure it would be for an unmapped window, GDK does not record the new size on the window until it receives the ConfigureNotify reply.

Immediately after the toplevel is mapped, GDK sets a shape on the child window. This is based on parent window sizes - probably some client-side window code that doesn't really make much sense for the server-side toplevel window size. GDK still considers the toplevel to have the size it had before the ConfigureRequest, which happens to be the default GtkWindow size of 200x200.

The child window has a back pixmap of None, meaning it shows nothing until it is drawn, and so the background remains. The toplevel window has a back pixmap or background color based on the theme and so looks inconsistent.

Some options I'm thinking about:

1) Change the default size of the window. This needs to be done before realizing the window, but the desired size is not provided at that point. A small size could be selected to limit the effect to 1 pixel.

2) Try sizing the window as soon as possible instead of waiting until Show.
The event loop would need to run to process the ConfigureNotify, so this may not be helpful.

3) Look into setting the back pixmap of the toplevel window to None.

4) Don't set the back pixmap of child windows to None.

5) Find out why dlbi changes made this show up.

(In reply to Karl Tomlinson (:karlt) from comment #3)
> Immediately after the toplevel is mapped, GDK sets a shape on the child
> window.

Immediately before, actually.

The reason this didn't happen before refresh-driver-painting was that GDK
didn't create a native X Window for the child window until we requested it,
and that didn't happen until the expose event, at which point I assume GDK knew
the size of the toplevel window.

What is different with refresh driver painting is that it calls
GetThebesSurface() off the refresh driver to select a buffer format for the
BasicThebesLayer buffer. This can result in the X Window for the child window
being created before GDK receives the ConfigureNotify event.

Perhaps we could come up with a different reference surface (the toplevel
window surface would be fine in our controlled situation) but the problem
would be harder to solve with GL layers where the GLContext is created
for the native X window into which we'll draw.

I don't think we can Show/Map the window, and then paint immediately because
the Map request is redirected to the window manager and may not have been
effected before we paint. And the child window will still have the incorrect
shape, masking out drawing until the ConfigureNotify is received.

It looks like _NET_WM_SYNC_REQUEST with background None would be a way to postpone client and window manager drawing until the ConfigureNotify has been received.
However, the support doesn't seem to be there in GTK or in window managers.
It seems it is used mostly for window-manager-initiated resize drags, possibly because most apps don't have background None.

gtk_window_show() does not increment configure_request_count when it resizes the
window, and so gtk_window_configure_event() bails out early, replying to the
_NET_WM_SYNC_REQUEST before the drawing has taken place.

kwin 4.8.5 does not wait (any significant time at least) for the
_NET_WM_SYNC_REQUEST reply before drawing the frame. It only sends the
message for the resize before show when compositing is enabled.

metacity 2.30.3 and 2.34.8 do not send a _NET_WM_SYNC_REQUEST for the resize
before show, with or without compositing enabled. They do send these when
dragging the frame border to resize.

I haven't tested compiz or mutter which I would expect to use
_NET_WM_SYNC_REQUEST at least for resize drags. Bug 378293 seems to suggest compiz
is using _NET_WM_SYNC_REQUEST as an indicator of when it expects to have all Damage events for a window show.

Created attachment 673078
use ParentRelative background pixmap to avoid effects from shapes GDK applies to child windows during Show

Given the window manager is drawing the frame before we respond to the
ConfigureNotify event, we might as well give in and let the background be
drawn on Show.

This would be quite the wrong thing for translucent windows, as the shape
would be wrong until we paint. However, we only make override-redirect
windows transparent and GDK handles override-redirect windows differently,
resizing synchronously and temporarily setting the background to None during
show to suppress display of the background.

This patch is perhaps a simple quick fix, but we can do a better fix.

Using ParentRelative makes child Windows look just like their parent Window's
background until they are drawn. This seems to look a little better than
setting background None on the toplevel, which leads to the window manager
frame painting while there still seems to be a big gap in the middle.

ParentRelative has the additional requirement that the parent window needs to
have matching depth. Usually our child windows inherit the colormap/visual
from the parent and so that is satisfied. That inheritance doesn't guarantee
the same depth when windows are reparented. The only toplevel windows that we
give different depths are popup windows, so that would only be a problem if we
had windowed plugins in a popup. However, I'm not sure that styles/themes can't set different visuals on different widgets, which would be a problem to solve when reparenting to the GtkInvisible widget.

I started looking into drawing directly to the toplevel X Window and never
doing anything to trigger creation of X Windows for child windows, but that
seems to be relying too much on the implementation of GdkWindows.

The best strategy would be to redesign MozContainer to be a GTK_NO_WINDOW widget and stop creating child nsWindows for each toplevel window. I'll upload patches for that.

Created attachment 673082
set gFocusWindow on fallback instead of early

This was interfering with focus change detection in SetFocus() when the nsWindow of the container receives focus, and so mIMModule->OnFocusWindow() was not getting called. (Currently the child window is the one receiving focus in SetFocus().)

Created attachment 673083
don't resize toplevel window in response to resized notification

When the widget calls WindowResized() on either of the listeners,
nsDocShell::SetPositionAndSize() and DocumentViewerImpl::SetBounds() get
called. This is a notification that the window has changed. When the
viewer is not mAttachedToParent, it makes sense to resize the child window in
response to toplevel change. Resizing the toplevel again doesn't make sense
in this situation, and would lead to infinite recursion (unless broken in some
way). When !mAttachedToParent the Resize() here would not resize
the toplevel, so some other mechanism should be used if the intention is to resize the toplevel.


Created attachment 673084
remove unused event handler parameters

The following patch will change widget signal handlers somewhat.
Removing the unused GtkWidget parameters makes it clear where the particular widget provided by the signal is not important.

Comment on attachment 673083
don't resize toplevel window in response to resized notification

r=me if this is all tested in the cases when mAttachedToParent is true (Windows?)

Created attachment 673088
don't use a separate GdkWindow for MozContainer (unless necessary)

Gtk has the concept of GTK_NO_WINDOW widgets. For these
gtk_widget_get_window() returns the parent (or ancestor) widget's window.
These widgets should not modify the parent widget's window, expect to draw.
gdk_window_get_user_data(gdk_widget_get_window(widget), &data) will not return widget for these windows.

Created attachment 673091
don't log child window XIDs as this has the side effect of creating X Windows early

When logging was enabled, the gdk_x11_window_get_xid here for the child window
was slightly concealing what has changed with dlbi because it caused GDK to generate a native X Window for the GdkWindow earlier.

The child window XIDs are available from xwininfo anyway, so I've just included the parent window for child window logs to help tie things together.

This also now output the single mGdkWindow as it is shared by both widgets.

Created attachment 673098
invalidate new regions of even toplevel resized windows

This addresses a noticable difference in painting the new area of a window
being resized by the window manager (through dragging the frame).

With child windows, the resize notification here of parent window change
caused a client request to resize the child window (through WindowResized).
GDK invalidated the new part of the child window while doing this.

Immediately after dispatching this size-allocate signal, GTK does a
synchronous paint of invalid regions.

Without a child window, the client-side invalidate doesn't happen and the X
Expose event hasn't been received yet and so the repaint lags behind, leaving
the background quite visible.

The ForcedRepaint() code in the view system doesn't work as well as we might
like. It invalidates the whole window, but with basic layers only the region
in the native expose event is repainted. The whole invalidated rect is
repainted later, but by that time it seems the window manager has already
started compositing the new portion that was painted and includes the
background of the new part of the window as well. I guess we could change
this process to repaint freshly invalidated regions as well as the region of
the expose signal, but I'll save that for a later date.

This patch is essentially keeping the behavior that we have on child windows.
I guess we could invalidate the whole window here, but we don't seem to need
to. The key is to prevent the background flickering by painting the new part
as fast as possible. It doesn't seem to matter that the painting of resized
existing content lags a little.

While modifying this code, I'm skipping the WindowResized if there is no
change. If mBounds was changed in the Resize() methods, then WindowResized
would have been called there.

Created attachment 673117
attach DocumentViewer to top GTK widget

One X window, without GDK black magic.

Comment on attachment 673088
don't use a separate GdkWindow for MozContainer (unless necessary)

Review of attachment 673088:

::: widget/gtk2/mozcontainer.c
@@ +196,5 @@
> tmp_list = tmp_list->next;
> }
> + if (gtk_widget_get_has_window (widget))
> + gdk_window_show (gtk_widget_get_window(widget));


@@ +207,5 @@
> gtk_widget_set_mapped(widget, FALSE);
> + if (gtk_widget_get_has_window (widget))
> + gdk_window_hide (gtk_widget_get_window(widget));


::: widget/gtk2/nsWindow.cpp
@@ +3718,5 @@
> g_signal_connect(mContainer, "drag_data_received",
> G_CALLBACK(drag_data_received_event_cb), NULL);
> + GtkWidget *widgets[] = { GTK_WIDGET(mContainer), mShell, nullptr };
> + for (int i = 0; widgets[i]; ++i) {

Slightly better to just use for (int i = 0; i < ArrayLength(widgets); ++i)

Comment on attachment 673117
attach DocumentViewer to top GTK widget

Review of attachment 673117:


On Windows this caused all kinds of breakage with third-party apps that try to monkey with Firefox's HWNDs. Hopefully we won't have that sort of trouble on X.

::: widget/gtk2/nsWindow.cpp
@@ +458,5 @@
> + nsIWidgetListener *listeners[] =
> + { mWidgetListener, mAttachedWidgetListener };
> + for (size_t i = 0; i < ArrayLength(listeners); ++i) {
> + if (listeners[i])
> + listeners[i]->WindowResized(this, aWidth, aHeight);


@@ +474,5 @@
> aStatus = nsEventStatus_eIgnore;
> + nsIWidgetListener* listener =
> + mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
> + if (listener)
> + aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);


Thanks for the reviews.

(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #17)
> > + GtkWidget *widgets[] = { GTK_WIDGET(mContainer), mShell, nullptr };
> > + for (int i = 0; widgets[i]; ++i) {
> Slightly better to just use for (int i = 0; i < ArrayLength(widgets); ++i)

mShell may be null, so we'd also need if ( widgets[i] ) {
but maybe that's not so bad because it would be a little clearer.

Tony Pursell (ajpursell) wrote :
Tony Pursell (ajpursell) wrote :
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in compiz (Ubuntu):
status: New → Confirmed
Tony Pursell (ajpursell) wrote :

Also reported on the Mozilla bug tracker


*** Bug 835331 has been marked as a duplicate of this bug. ***

madbiologist (me-again) wrote :

The bug mentioned in comment #4 has been marked as a duplicate of https://bugzilla.mozilla.org/show_bug.cgi?id=793501

A Mozilla developer has written a set of patches to correct the bug. They are currently undergoing testing.

affects: compiz (Ubuntu) → firefox (Ubuntu)
Changed in firefox:
importance: Unknown → Low
status: Unknown → Fix Released
madbiologist (me-again) on 2016-09-28
Changed in firefox (Ubuntu):
status: Confirmed → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.