Bug 541015 - Support rotating between portrait and landscape on N900 [r=karlt]

This commit is contained in:
Mark Finkle 2010-04-01 09:58:42 -04:00
Родитель 75db30109e
Коммит d0fffdb53f
2 изменённых файлов: 174 добавлений и 10 удалений

Просмотреть файл

@ -53,18 +53,36 @@
#include "nsICommandLineRunner.h"
#include "nsIWindowMediator.h"
#include "nsIDOMWindowInternal.h"
#include "nsPIDOMWindow.h"
#include "nsIDocShell.h"
#include "nsIBaseWindow.h"
#include "nsIWidget.h"
#include "nsIWritablePropertyBag2.h"
#include <stdlib.h>
#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#ifdef MOZ_X11
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
#endif
#ifdef MOZ_PLATFORM_MAEMO
struct DBusMessage; /* libosso.h references internals of dbus */
#include <dbus/dbus.h>
#include <dbus/dbus-protocol.h>
#include <libosso.h>
// These come from <mce/dbus-names.h> (maemo sdk 5+)
#define MCE_SERVICE "com.nokia.mce"
#define MCE_REQUEST_IF "com.nokia.mce.request"
#define MCE_REQUEST_PATH "/com/nokia/mce/request"
#define MCE_SIGNAL_IF "com.nokia.mce.signal"
#define MCE_DEVICE_ORIENTATION_SIG "sig_device_orientation_ind"
#define MCE_MATCH_RULE "type='signal',interface='" MCE_SIGNAL_IF "',member='" MCE_DEVICE_ORIENTATION_SIG "'"
#endif
#define MIN_GTK_MAJOR_VERSION 2
@ -155,6 +173,7 @@ class nsNativeAppSupportUnix : public nsNativeAppSupportBase
public:
NS_IMETHOD Start(PRBool* aRetVal);
NS_IMETHOD Stop(PRBool *aResult);
NS_IMETHOD Enable();
private:
#ifdef MOZ_PLATFORM_MAEMO
@ -169,17 +188,118 @@ private:
};
#ifdef MOZ_PLATFORM_MAEMO
static nsresult
GetMostRecentWindow(const PRUnichar* aType, nsIDOMWindowInternal** aWindow)
{
nsCOMPtr<nsIWindowMediator> wm = do_GetService("@mozilla.org/appshell/window-mediator;1");
if (wm)
return wm->GetMostRecentWindow(aType, aWindow);
return NS_ERROR_FAILURE;
}
static GtkWidget*
WidgetForDOMWindow(nsISupports *aWindow)
{
nsCOMPtr<nsPIDOMWindow> domWindow(do_QueryInterface(aWindow));
if (!domWindow)
return NULL;
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(domWindow->GetDocShell());
if (!baseWindow)
return NULL;
nsCOMPtr<nsIWidget> widget;
baseWindow->GetMainWidget(getter_AddRefs(widget));
if (!widget)
return NULL;
return (GtkWidget*)(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
}
static void
OssoSetWindowOrientation(PRBool aPortrait)
{
// Tell Hildon desktop to force our window to be either portrait or landscape,
// depending on the current rotation
// NOTE: We only update the most recent top-level window so this is only
// suitable for apps with only one window.
nsCOMPtr<nsIDOMWindowInternal> window;
GetMostRecentWindow(NS_LITERAL_STRING("").get(), getter_AddRefs(window));
GtkWidget* widget = WidgetForDOMWindow(window);
if (widget && widget->window) {
GdkWindow *gdk = widget->window;
GdkAtom request = gdk_atom_intern("_HILDON_PORTRAIT_MODE_REQUEST", FALSE);
if (aPortrait) {
gulong portrait_set = 1;
gdk_property_change(gdk, request, gdk_x11_xatom_to_atom(XA_CARDINAL),
32, GDK_PROP_MODE_REPLACE, (const guchar *) &portrait_set, 1);
}
else {
gdk_property_delete(gdk, request);
}
}
// Update the system info property
nsCOMPtr<nsIWritablePropertyBag2> info = do_GetService("@mozilla.org/system-info;1");
if (info) {
info->SetPropertyAsAString(NS_LITERAL_STRING("screen-orientation"),
aPortrait ? NS_LITERAL_STRING("portrait") : NS_LITERAL_STRING("landscape"));
}
}
static PRBool OssoIsScreenOn(osso_context_t* ctx)
{
osso_return_t rv;
osso_rpc_t ret;
PRBool result = PR_FALSE;
rv = osso_rpc_run_system(ctx, MCE_SERVICE, MCE_REQUEST_PATH, MCE_REQUEST_IF,
"get_display_status", &ret, DBUS_TYPE_INVALID);
if (rv == OSSO_OK) {
if (strcmp(ret.value.s, "on") == 0)
result = PR_TRUE;
osso_rpc_free_val(&ret);
}
return result;
}
static void OssoRequestAccelerometer(osso_context_t *ctx, PRBool aEnabled)
{
osso_return_t rv;
osso_rpc_t ret;
rv = osso_rpc_run_system(ctx,
MCE_SERVICE,
MCE_REQUEST_PATH, MCE_REQUEST_IF,
aEnabled ? "req_accelerometer_enable" : "req_accelerometer_disable",
aEnabled ? &ret : NULL,
DBUS_TYPE_INVALID);
// Orientation might changed while the accelerometer was off, so let's update
// the window's orientation
if (rv == OSSO_OK && aEnabled) {
OssoSetWindowOrientation(strcmp(ret.value.s, "portrait") == 0);
osso_rpc_free_val(&ret);
}
}
static void OssoDisplayCallback(osso_display_state_t state, gpointer data)
{
nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
if (!os)
return;
if (state == OSSO_DISPLAY_ON)
osso_context_t* context = (osso_context_t*) data;
if (state == OSSO_DISPLAY_ON) {
os->NotifyObservers(nsnull, "system-display-on", nsnull);
else
OssoRequestAccelerometer(context, PR_TRUE);
} else {
os->NotifyObservers(nsnull, "system-display-dimmed-or-off", nsnull);
OssoRequestAccelerometer(context, PR_FALSE);
}
}
static void OssoHardwareCallback(osso_hw_state_t *state, gpointer data)
@ -226,13 +346,11 @@ OssoDbusCallback(const gchar *interface, const gchar *method,
// The "top_application" method just wants us to focus the top-most window.
if (!strcmp("top_application", method)) {
nsCOMPtr<nsIWindowMediator> wm = do_GetService("@mozilla.org/appshell/window-mediator;1");
nsCOMPtr<nsIDOMWindowInternal> window;
wm->GetMostRecentWindow(NS_LITERAL_STRING("").get(), getter_AddRefs(window));
if (window) {
GetMostRecentWindow(NS_LITERAL_STRING("").get(), getter_AddRefs(window));
if (window)
window->Focus();
}
return OSSO_OK;
}
@ -285,6 +403,21 @@ OssoDbusCallback(const gchar *interface, const gchar *method,
return OSSO_OK;
}
static DBusHandlerResult
OssoModeControlCallback(DBusConnection *con, DBusMessage *msg, gpointer data)
{
if (dbus_message_is_signal(msg, MCE_SIGNAL_IF, MCE_DEVICE_ORIENTATION_SIG)) {
DBusMessageIter iter;
if (dbus_message_iter_init(msg, &iter)) {
const gchar *mode = NULL;
dbus_message_iter_get_basic(&iter, &mode);
OssoSetWindowOrientation(strcmp(mode, "portrait") == 0);
}
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif
NS_IMETHODIMP
@ -323,7 +456,7 @@ nsNativeAppSupportUnix::Start(PRBool *aRetVal)
system will happily kill your process.
*/
nsCAutoString applicationName;
if(gAppData->vendor) {
if (gAppData->vendor) {
applicationName.Append(gAppData->vendor);
applicationName.Append(".");
}
@ -341,8 +474,13 @@ nsNativeAppSupportUnix::Start(PRBool *aRetVal)
}
osso_hw_set_event_cb(m_osso_context, nsnull, OssoHardwareCallback, &m_hw_state);
osso_hw_set_display_event_cb(m_osso_context, OssoDisplayCallback, nsnull);
osso_hw_set_display_event_cb(m_osso_context, OssoDisplayCallback, m_osso_context);
osso_rpc_set_default_cb_f(m_osso_context, OssoDbusCallback, nsnull);
// Setup an MCE callback to monitor orientation
DBusConnection *connnection = (DBusConnection*)osso_get_sys_dbus_connection(m_osso_context);
dbus_bus_add_match(connnection, MCE_MATCH_RULE, nsnull);
dbus_connection_add_filter(connnection, OssoModeControlCallback, nsnull, nsnull);
#endif
*aRetVal = PR_TRUE;
@ -455,6 +593,13 @@ nsNativeAppSupportUnix::Stop(PRBool *aResult)
#ifdef MOZ_PLATFORM_MAEMO
if (m_osso_context) {
// Disable the accelerometer when closing
OssoRequestAccelerometer(m_osso_context, PR_FALSE);
// Remove the MCE callback filter
DBusConnection *connnection = (DBusConnection*)osso_get_sys_dbus_connection(m_osso_context);
dbus_connection_remove_filter(connnection, OssoModeControlCallback, nsnull);
osso_hw_unset_event_cb(m_osso_context, nsnull);
osso_rpc_unset_default_cb_f(m_osso_context, OssoDbusCallback, nsnull);
osso_deinitialize(m_osso_context);
@ -464,6 +609,17 @@ nsNativeAppSupportUnix::Stop(PRBool *aResult)
return NS_OK;
}
NS_IMETHODIMP
nsNativeAppSupportUnix::Enable()
{
#ifdef MOZ_PLATFORM_MAEMO
// Enable the accelerometer for orientation support
if (OssoIsScreenOn(m_osso_context))
OssoRequestAccelerometer(m_osso_context, PR_TRUE);
#endif
return NS_OK;
}
nsresult
NS_CreateNativeAppSupport(nsINativeAppSupport **aResult)
{

Просмотреть файл

@ -91,6 +91,7 @@
#include "nsIObserverService.h"
#include "nsIdleService.h"
#include "nsIPropertyBag2.h"
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
@ -4265,6 +4266,13 @@ nsWindow::Create(nsIWidget *aParent,
if (mWindowType == eWindowType_toplevel) {
GdkWindow *gdkwin = mShell->window;
// Tell the Hildon desktop that we support being rotated
gulong portrait_set = 1;
GdkAtom support = gdk_atom_intern("_HILDON_PORTRAIT_MODE_SUPPORT", FALSE);
gdk_property_change(gdkwin, support, gdk_x11_xatom_to_atom(XA_CARDINAL),
32, GDK_PROP_MODE_REPLACE,
(const guchar *) &portrait_set, 1);
// Tell maemo-status-volume daemon to ungrab keys
gulong volume_set = 1;
GdkAtom keys = gdk_atom_intern("_HILDON_ZOOM_KEY_ATOM", FALSE);