gecko-dev/widget/gtk/TaskbarProgress.cpp
Michael Webster 1a8239407b Bug 1418749 - Add a TaskbarProgress implementation for gtk3/x11. r=paolo,karlt
This adds support for download progress reporting via the XApp
method currently used in the Cinnamon desktop, by establishing a new
X11 window property to be supported/read by the window manager.

See https://github.com/linuxmint/xapps/blob/master/libxapp/xapp-gtk-window.c,
as well as https://github.com/linuxmint/muffin/commit/39045da0ea06f
for more details.

The property-setting code lives in nsWindow - it's a small and stable
enough chunk that it made more sense to do this than actually depend on
another external library.  As nsWindow is already using x11 calls, this
seemed the safest place for it, without affecting the build.

The TaskbarProgress instance is initialized via the DownloadsTaskbar
js module, and is handed a pointer to the current main window to call
SetProgress on.  Most of the javascript side of this is in line with
how the other platforms are handled.

Without a supporting window manager/desktop environment (currently just
Cinnamon/Muffin 3.6,) the simplest way to observe working behavior is
by calling 'xprop -spy' on the browser window being testing and watching
for updates during a download.

--HG--
extra : rebase_source : 0606f6c87116204ec290c19276072d0c1c35691e
2018-03-08 18:43:00 +02:00

112 lines
3.4 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "mozilla/Logging.h"
#include "TaskbarProgress.h"
#include "nsWindow.h"
#include "WidgetUtils.h"
#include "nsPIDOMWindow.h"
using mozilla::LogLevel;
static mozilla::LazyLogModule gGtkTaskbarProgressLog("nsIGtkTaskbarProgress");
/******************************************************************************
* TaskbarProgress
******************************************************************************/
NS_IMPL_ISUPPORTS(TaskbarProgress, nsIGtkTaskbarProgress, nsITaskbarProgress)
TaskbarProgress::TaskbarProgress()
: mPrimaryWindow(nullptr)
{
MOZ_LOG(gGtkTaskbarProgressLog, LogLevel::Info,
("%p TaskbarProgress()", this));
}
TaskbarProgress::~TaskbarProgress()
{
MOZ_LOG(gGtkTaskbarProgressLog, LogLevel::Info,
("%p ~TaskbarProgress()", this));
}
NS_IMETHODIMP
TaskbarProgress::SetProgressState(nsTaskbarProgressState aState,
uint64_t aCurrentValue,
uint64_t aMaxValue)
{
#ifdef MOZ_X11
NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED);
if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) {
NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(aMaxValue == 0, NS_ERROR_INVALID_ARG);
}
NS_ENSURE_TRUE((aCurrentValue <= aMaxValue), NS_ERROR_ILLEGAL_VALUE);
// See TaskbarProgress::SetPrimaryWindow: if we're running in headless
// mode, mPrimaryWindow will be null.
if (!mPrimaryWindow) {
return NS_OK;
}
gulong progress;
if (aMaxValue == 0) {
progress = 0;
} else {
// Rounding down to ensure we don't set to 'full' until the operation
// is completely finished.
progress = (gulong) (((double)aCurrentValue / aMaxValue) * 100.0);
}
// Check if the resultant value is the same as the previous call, and
// ignore this update if it is.
if (progress == mCurrentProgress) {
return NS_OK;
}
mCurrentProgress = progress;
MOZ_LOG(gGtkTaskbarProgressLog, LogLevel::Debug,
("GtkTaskbarProgress::SetProgressState progress: %lu", progress));
mPrimaryWindow->SetProgress(progress);
#endif
return NS_OK;
}
NS_IMETHODIMP
TaskbarProgress::SetPrimaryWindow(mozIDOMWindowProxy* aWindow)
{
NS_ENSURE_TRUE(aWindow != nullptr, NS_ERROR_ILLEGAL_VALUE);
auto* parent = nsPIDOMWindowOuter::From(aWindow);
RefPtr<nsIWidget> widget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent);
// Only nsWindows have a native window, HeadlessWidgets do not. Stop here if the
// window does not have one.
if (!widget->GetNativeData(NS_NATIVE_WINDOW)) {
return NS_OK;
}
mPrimaryWindow = static_cast<nsWindow*>(widget.get());
// Clear our current progress. We get a forced update from the DownloadsTaskbar
// after returning from this function - zeroing out our progress will make sure the
// new window gets the property set on it immediately, rather than waiting for the
// progress value to change (which could be a while depending on size.)
mCurrentProgress = 0;
MOZ_LOG(gGtkTaskbarProgressLog, LogLevel::Debug,
("GtkTaskbarProgress::SetPrimaryWindow window: %p", mPrimaryWindow.get()));
return NS_OK;
}