Bug 713168: Add support for different screen/input-device resolutions and virtual buttons. Temporary. rs=mwu
authorChris Jones <jones.chris.g@gmail.com>
Thu, 29 Dec 2011 14:39:25 -0800
changeset 83543 87d4fca7a8e276c52657f2eec5ff51164876fa4a
parent 83542 fb2a16bf3c2d5c40d303f2f3b7022d2c4679d09b
child 83544 6d050439f6872e36c31f2c01ec1e84b23758a5f2
push id21767
push userkhuey@mozilla.com
push dateFri, 30 Dec 2011 12:07:47 +0000
treeherdermozilla-central@9fdaea5d67e2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu
bugs713168
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 713168: Add support for different screen/input-device resolutions and virtual buttons. Temporary. rs=mwu
widget/src/gonk/nsAppShell.cpp
widget/src/gonk/nsAppShell.h
--- a/widget/src/gonk/nsAppShell.cpp
+++ b/widget/src/gonk/nsAppShell.cpp
@@ -35,27 +35,29 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #define _GNU_SOURCE
 
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <linux/input.h>
 #include <signal.h>
 #include <sys/epoll.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "mozilla/Hal.h"
+#include "nscore.h"
+#include "mozilla/FileUtils.h"
 #include "mozilla/Services.h"
 #include "nsAppShell.h"
 #include "nsGkAtoms.h"
 #include "nsGUIEvent.h"
 #include "nsIObserverService.h"
 #include "nsWindow.h"
 
 #include "android/log.h"
@@ -75,17 +77,25 @@
 #define ABS_MT_POSITION_Y       0x36    /* Center Y ellipse position */
 #define ABS_MT_TOOL_TYPE        0x37    /* Type of touching device */
 #define ABS_MT_BLOB_ID          0x38    /* Group a set of packets as a blob */
 #define ABS_MT_TRACKING_ID      0x39    /* Unique ID of initiated contact */
 #define ABS_MT_PRESSURE         0x3a    /* Pressure on contact area */
 #define SYN_MT_REPORT           2
 #endif
 
-#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
+#define LOG(args...)                                            \
+    __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
+#ifdef VERBOSE_LOG_ENABLED
+# define VERBOSE_LOG(args...)                           \
+    __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
+#else
+# define VERBOSE_LOG(args...)                   \
+    (void)0
+#endif
 
 using namespace mozilla;
 
 bool gDrawRequest = false;
 static nsAppShell *gAppShell = NULL;
 static int epollfd = 0;
 static int signalfds[2] = {0};
 
@@ -115,34 +125,33 @@ pipeHandler(int fd, FdHandler *data)
 
 static
 PRUint64 timevalToMS(const struct timeval &time)
 {
     return time.tv_sec * 1000 + time.tv_usec / 1000;
 }
 
 static void
-sendMouseEvent(PRUint32 msg, struct timeval *time, int x, int y)
+sendMouseEvent(PRUint32 msg, struct timeval& time, int x, int y)
 {
     nsMouseEvent event(true, msg, NULL,
                        nsMouseEvent::eReal, nsMouseEvent::eNormal);
 
     event.refPoint.x = x;
     event.refPoint.y = y;
-    event.time = timevalToMS(*time);
+    event.time = timevalToMS(time);
     event.isShift = false;
     event.isControl = false;
     event.isMeta = false;
     event.isAlt = false;
     event.button = nsMouseEvent::eLeftButton;
     if (msg != NS_MOUSE_MOVE)
         event.clickCount = 1;
 
     nsWindow::DispatchInputEvent(event);
-    //LOG("Dispatched type %d at %dx%d", msg, x, y);
 }
 
 static nsEventStatus
 sendKeyEventWithMsg(PRUint32 keyCode,
                     PRUint32 msg,
                     const timeval &time,
                     PRUint32 flags)
 {
@@ -169,66 +178,184 @@ static void
 sendSpecialKeyEvent(nsIAtom *command, const timeval &time)
 {
     nsCommandEvent event(true, nsGkAtoms::onAppCommand, command, NULL);
     event.time = timevalToMS(time);
     nsWindow::DispatchInputEvent(event);
 }
 
 static void
+maybeSendKeyEvent(int keyCode, bool pressed, const timeval& time)
+{
+    switch (keyCode) {
+    case KEY_BACK:
+        sendKeyEvent(NS_VK_ESCAPE, pressed, time);
+        break;
+    case KEY_MENU:
+        if (!pressed)
+            sendSpecialKeyEvent(nsGkAtoms::Menu, time);
+        break;
+    case KEY_SEARCH:
+        if (pressed)
+            sendSpecialKeyEvent(nsGkAtoms::Search, time);
+        break;
+    case KEY_HOME:
+        sendKeyEvent(NS_VK_HOME, pressed, time);
+        break;
+    case KEY_POWER:
+        sendKeyEvent(NS_VK_SLEEP, pressed, time);
+        break;
+    case KEY_VOLUMEUP:
+        if (pressed)
+            sendSpecialKeyEvent(nsGkAtoms::VolumeUp, time);
+        break;
+    case KEY_VOLUMEDOWN:
+        if (pressed)
+            sendSpecialKeyEvent(nsGkAtoms::VolumeDown, time);
+        break;
+    default:
+        VERBOSE_LOG("Got unknown key event code. type 0x%04x code 0x%04x value %d",
+                    keyCode, pressed);
+    }
+}
+
+static void
 maybeSendKeyEvent(const input_event& e)
 {
     if (e.type != EV_KEY) {
-        LOG("Got unknown key event type. type 0x%04x code 0x%04x value %d",
+        VERBOSE_LOG("Got unknown key event type. type 0x%04x code 0x%04x value %d",
             e.type, e.code, e.value);
         return;
     }
 
     if (e.value != 0 && e.value != 1) {
-        LOG("Got unknown key event value. type 0x%04x code 0x%04x value %d",
+        VERBOSE_LOG("Got unknown key event value. type 0x%04x code 0x%04x value %d",
             e.type, e.code, e.value);
         return;
     }
 
     bool pressed = e.value == 1;
-    switch (e.code) {
-    case KEY_BACK:
-        sendKeyEvent(NS_VK_ESCAPE, pressed, e.time);
-        break;
-    case KEY_MENU:
-        if (!pressed)
-            sendSpecialKeyEvent(nsGkAtoms::Menu, e.time);
-        break;
-    case KEY_SEARCH:
-        if (pressed)
-            sendSpecialKeyEvent(nsGkAtoms::Search, e.time);
-        break;
-    case KEY_HOME:
-        sendKeyEvent(NS_VK_HOME, pressed, e.time);
-        break;
-    case KEY_POWER:
-        sendKeyEvent(NS_VK_SLEEP, pressed, e.time);
-        break;
-    case KEY_VOLUMEUP:
-        if (pressed)
-            sendSpecialKeyEvent(nsGkAtoms::VolumeUp, e.time);
-        break;
-    case KEY_VOLUMEDOWN:
-        if (pressed)
-            sendSpecialKeyEvent(nsGkAtoms::VolumeDown, e.time);
-        break;
-    default:
-        LOG("Got unknown key event code. type 0x%04x code 0x%04x value %d",
-            e.type, e.code, e.value);
+    maybeSendKeyEvent(e.code, pressed, e.time);
+}
+
+static void
+configureVButtons(FdHandler& data)
+{
+    char vbuttonsPath[PATH_MAX];
+    snprintf(vbuttonsPath, sizeof(vbuttonsPath),
+             "/sys/board_properties/virtualkeys.%s",
+             data.name);
+    ScopedClose fd(open(vbuttonsPath, O_RDONLY));
+    if (0 > fd.mFd) {
+        LOG("No vbuttons for mt device %s", data.name);
+        return;
+    }
+
+    // This device has vbuttons.  Process the configuration.
+    char config[1024];
+    ssize_t nread;
+    do {
+        nread = read(fd.mFd, config, sizeof(config));
+    } while (-1 == nread && EINTR == errno);
+
+    if (0 > nread) {
+        LOG("Error reading virtualkey configuration");
+        return;
     }
+
+    config[nread] = '\0';
+
+    LOG("Device %s has vbutton config '%s'", data.name, config);
+
+    char* startStr = config;
+    for (size_t i = 0; i < FdHandler::kMaxVButtons; ++i) {
+        FdHandler::VButton& vbutton = data.vbuttons[i];
+        char* token;
+        char* state;
+                
+        // XXX not clear what "0x01" is ... maybe a version
+        // number?  See InputManager.java.
+        if (!(token = strtok_r(startStr, ":", &state)) ||
+            strcmp(token, "0x01")) {
+            LOG("  magic 0x01 tag missing");
+            break;
+        }
+        startStr = NULL;
+
+        if (!(token = strtok_r(NULL, ":", &state))) {
+            LOG("  failed to read keycode");
+            break;
+        }
+        vbutton.keyCode = atoi(token);
+
+        const char *centerX, *centerY, *width, *height;
+        if (!((centerX = strtok_r(NULL, ":", &state)) &&
+              (centerY = strtok_r(NULL, ":", &state)) &&
+              (width = strtok_r(NULL, ":", &state)) &&
+              (height = strtok_r(NULL, ":", &state)))) {
+            LOG("  failed to read bound params");
+            break;
+        }
+
+        // NB: these coordinates are in *screen* space, not input
+        // space.  That means the values in /sys/board_config make
+        // assumptions about how the raw input events are mapped
+        // ... le sigh.
+        nsIntRect rect;
+        rect.width = atoi(width);
+        rect.height = atoi(height);
+        rect.x = atoi(centerX) - rect.width / 2;
+        rect.y = atoi(centerY) - rect.height / 2;
+        vbutton.buttonRect = rect;
+
+        LOG("  configured vbutton code=%d at <x=%d,y=%d,w=%d,h=%d>",
+            vbutton.keyCode, rect.x, rect.y, rect.width, rect.height);
+    }
+}
+
+static bool
+calibrateMultitouchDevice(FdHandler& data)
+{
+    if (data.calibrated)
+        return true;
+    if (gScreenBounds.IsEmpty()) {
+        // The framebuffer hasn't been initialized yet.  We *could*
+        // force it to be initialized here, but that's another patch.
+        LOG("Deferring multitouch calibrate, fb not ready");
+        return false;
+    }
+
+    struct input_absinfo xInfo, yInfo;
+    if (0 > ioctl(data.fd, EVIOCGABS(ABS_MT_POSITION_X), &xInfo) ||
+        0 > ioctl(data.fd, EVIOCGABS(ABS_MT_POSITION_Y), &yInfo)) {
+        LOG("Couldn't get absinfo for multitouch axes");
+        return false;
+    }
+    LOG("Input coordinate bounds: xmin=%d, xmax=%d, ymin=%d, ymax=%d",
+        xInfo.minimum, xInfo.maximum, yInfo.minimum, yInfo.maximum);
+
+    data.inputMinX = xInfo.minimum;
+    data.inputMinY = yInfo.minimum;
+    data.inputToScreenScaleX =
+        float(gScreenBounds.width) / float(xInfo.maximum - xInfo.minimum);
+    data.inputToScreenScaleY =
+        float(gScreenBounds.height) / float(yInfo.maximum - yInfo.minimum);
+
+    configureVButtons(data);
+
+    data.calibrated = true;
+    return true;
 }
 
 static void
 multitouchHandler(int fd, FdHandler *data)
 {
+    if (!calibrateMultitouchDevice(*data))
+        return;
+
     // The Linux's input documentation (Documentation/input/input.txt)
     // says that we'll always read a multiple of sizeof(input_event) bytes here.
     input_event events[16];
     int event_count = read(fd, events, sizeof(events));
     if (event_count < 0) {
         LOG("Error reading in multitouchHandler");
         return;
     }
@@ -254,56 +381,87 @@ multitouchHandler(int fd, FdHandler *dat
             case ABS_MT_WIDTH_MINOR:
             case ABS_MT_ORIENTATION:
             case ABS_MT_TOOL_TYPE:
             case ABS_MT_BLOB_ID:
             case ABS_MT_TRACKING_ID:
             case ABS_MT_PRESSURE:
                 break;
             case ABS_MT_POSITION_X:
-                data->mtX = event->value;
+                data->mtX = data->inputXToScreenX(event->value);
                 break;
             case ABS_MT_POSITION_Y:
-                data->mtY = event->value;
+                data->mtY = data->inputYToScreenY(event->value);
                 break;
             default:
-                LOG("Got unknown event type 0x%04x with code 0x%04x and value %d",
-                    event->type, event->code, event->value);
+                VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
+                            event->type, event->code, event->value);
+                break;
             }
         } else if (event->type == EV_SYN) {
             switch (event->code) {
             case SYN_MT_REPORT:
                 if (data->mtState == FdHandler::MT_COLLECT)
                     data->mtState = FdHandler::MT_IGNORE;
                 break;
             case SYN_REPORT:
-                if ((!data->mtMajor || data->mtState == FdHandler::MT_START)) {
-                    sendMouseEvent(NS_MOUSE_BUTTON_UP, &event->time,
-                                   data->mtX, data->mtY);
+                if (!data->mtMajor || data->mtState == FdHandler::MT_START) {
                     data->mtDown = false;
-                    //LOG("Up mouse event");
+                    if (data->keyCode) {
+                        maybeSendKeyEvent(data->keyCode, data->mtDown,
+                                          event->time);
+                        data->keyCode = 0;
+                    } else {
+                        sendMouseEvent(NS_MOUSE_BUTTON_UP, event->time,
+                                       data->mtX, data->mtY);
+                    }
                 } else if (!data->mtDown) {
-                    sendMouseEvent(NS_MOUSE_BUTTON_DOWN, &event->time,
-                                   data->mtX, data->mtY);
+                    int x = data->mtX, y = data->mtY;
+
+                    bool isKeyEvent = false;
+                    if (!gScreenBounds.Contains(x, y)) {
+                        // Off-screen mt down.  Should be a vbutton.
+                        for (size_t i = 0; i < FdHandler::kMaxVButtons; ++i) {
+                            const FdHandler::VButton& vbutton = data->vbuttons[i];
+                            if (vbutton.buttonRect.IsEmpty())
+                                break;
+
+                            if (vbutton.buttonRect.Contains(x, y)) {
+                                isKeyEvent = true;
+                                data->keyCode = vbutton.keyCode;
+                                break;
+                            }
+                        }
+                    }
                     data->mtDown = true;
-                    //LOG("Down mouse event");
-                } else {
-                    sendMouseEvent(NS_MOUSE_MOVE, &event->time,
+
+                    if (isKeyEvent) {
+                        maybeSendKeyEvent(data->keyCode, data->mtDown,
+                                          event->time);
+                    } else {
+                        sendMouseEvent(NS_MOUSE_BUTTON_DOWN, event->time,
+                                       data->mtX, data->mtY);
+                    }
+                } else if (!data->keyCode) {
+                    sendMouseEvent(NS_MOUSE_MOVE, event->time,
                                    data->mtX, data->mtY);
                     data->mtDown = true;
                 }
+
                 data->mtState = FdHandler::MT_START;
+
                 break;
             default:
-                LOG("Got unknown event type 0x%04x with code 0x%04x and value %d",
-                    event->type, event->code, event->value);
+                VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
+                            event->type, event->code, event->value);
+
             }
         } else
-            LOG("Got unknown event type 0x%04x with code 0x%04x and value %d",
-                event->type, event->code, event->value);
+            VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
+                        event->type, event->code, event->value);
     }
 }
 
 static void
 singleTouchHandler(int fd, FdHandler *data)
 {
     // The Linux's input documentation (Documentation/input/input.txt)
     // says that we'll always read a multiple of sizeof(input_event) bytes here.
@@ -338,26 +496,26 @@ singleTouchHandler(int fd, FdHandler *da
                 break;
             default:
                 LOG("Got unknown st abs event type 0x%04x with code 0x%04x and value %d",
                     event->type, event->code, event->value);
             }
         } else if (event->type == EV_SYN) {
             if (data->mtState == FdHandler::MT_START) {
                 MOZ_ASSERT(data->mtDown);
-                sendMouseEvent(NS_MOUSE_BUTTON_DOWN, &event->time,
+                sendMouseEvent(NS_MOUSE_BUTTON_DOWN, event->time,
                                data->mtX, data->mtY);
                 data->mtState = FdHandler::MT_COLLECT;
             } else if (data->mtDown) {
                 MOZ_ASSERT(data->mtDown);
-                sendMouseEvent(NS_MOUSE_MOVE, &event->time,
+                sendMouseEvent(NS_MOUSE_MOVE, event->time,
                                data->mtX, data->mtY);
             } else {
                 MOZ_ASSERT(!data->mtDown);
-                sendMouseEvent(NS_MOUSE_BUTTON_UP, &event->time,
+                sendMouseEvent(NS_MOUSE_BUTTON_UP, event->time,
                                    data->mtX, data->mtY);
                 data->mtDown = false;
                 data->mtState = FdHandler::MT_START;
             }
         }
     }
 }
 
@@ -403,23 +561,23 @@ nsAppShell::Init()
     NS_ENSURE_SUCCESS(rv, rv);
 
     epollfd = epoll_create(16);
     NS_ENSURE_TRUE(epollfd >= 0, NS_ERROR_UNEXPECTED);
 
     int ret = pipe2(signalfds, O_NONBLOCK);
     NS_ENSURE_FALSE(ret, NS_ERROR_UNEXPECTED);
 
-    rv = AddFdHandler(signalfds[0], pipeHandler);
+    rv = AddFdHandler(signalfds[0], pipeHandler, "");
     NS_ENSURE_SUCCESS(rv, rv);
 
     DIR *dir = opendir("/dev/input");
     NS_ENSURE_TRUE(dir, NS_ERROR_UNEXPECTED);
 
-#define BITSET(bit, flags) (flags[bit >> 3] & (1 << (bit & 0x7)))
+#define IS_BIT_SET(bit, flags) (flags[bit >> 3] & (1 << (bit & 0x7)))
 
     struct dirent *entry;
     while ((entry = readdir(dir))) {
         char entryName[64];
         char entryPath[MAXPATHLEN];
         if (snprintf(entryPath, sizeof(entryPath),
                      "/dev/input/%s", entry->d_name) < 0) {
             LOG("Couldn't generate path while enumerating input devices!");
@@ -430,51 +588,53 @@ nsAppShell::Init()
             LOG("Found device %s - %s", entry->d_name, entryName);
         else
             continue;
 
         FdHandlerCallback handlerFunc = NULL;
 
         char flags[(NS_MAX(ABS_MAX, KEY_MAX) + 1) / 8];
         if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(flags)), flags) >= 0 &&
-            BITSET(ABS_MT_POSITION_X, flags)) {
+            IS_BIT_SET(ABS_MT_POSITION_X, flags)) {
 
             LOG("Found multitouch input device");
             handlerFunc = multitouchHandler;
         } else if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(flags)), flags) >= 0 &&
-                   BITSET(ABS_X, flags)) {
+                   IS_BIT_SET(ABS_X, flags)) {
             LOG("Found single touch input device");
             handlerFunc = singleTouchHandler;
         } else if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(flags)), flags) >= 0) {
             LOG("Found key input device");
             handlerFunc = keyHandler;
         }
 
         // Register the handler, if we have one.
         if (!handlerFunc)
             continue;
 
-        rv = AddFdHandler(fd, handlerFunc);
+        rv = AddFdHandler(fd, handlerFunc, entryName);
         if (NS_FAILED(rv))
             LOG("Failed to add fd to epoll fd");
     }
 
     return rv;
 }
 
 nsresult
-nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc)
+nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc,
+                         const char* deviceName)
 {
     epoll_event event = {
         EPOLLIN,
         { 0 }
     };
 
     FdHandler *handler = mHandlers.AppendElement();
     handler->fd = fd;
+    strncpy(handler->name, deviceName, sizeof(handler->name) - 1);
     handler->func = handlerFunc;
     event.data.u32 = mHandlers.Length() - 1;
     return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) ?
            NS_ERROR_UNEXPECTED : NS_OK;
 }
 
 void
 nsAppShell::ScheduleNativeEventCallback()
--- a/widget/src/gonk/nsAppShell.h
+++ b/widget/src/gonk/nsAppShell.h
@@ -34,47 +34,92 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsAppShell_h
 #define nsAppShell_h
 
 #include "nsBaseAppShell.h"
+#include "nsRect.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 bool ProcessNextEvent();
 void NotifyEvent();
 }
 
 extern bool gDrawRequest;
 
 class FdHandler;
 typedef void(*FdHandlerCallback)(int, FdHandler *);
 
 class FdHandler {
 public:
-    FdHandler() : mtState(MT_START), mtDown(false) { }
+    FdHandler()
+        : mtState(MT_START)
+        , keyCode(0)
+        , mtDown(false)
+        , calibrated(false)
+    {
+        memset(name, 0, sizeof(name));
+    }
 
     int fd;
+    char name[64];
     FdHandlerCallback func;
     enum mtStates {
         MT_START,
         MT_COLLECT,
         MT_IGNORE
     } mtState;
     int mtX, mtY;
     int mtMajor;
+    int keyCode;
     bool mtDown;
+    // FIXME/bug 712973: we should be using libui here instead of
+    // recreating all that logic ourselves.  Please don't extend the
+    // hacks here further than what's below.
+    bool calibrated;
+    // Multitouch events are delivered to us in "input space", which
+    // is a coordinate space defined by the multitouch device driver.
+    // The coordinate space has top-left at P_min = <inputMinX,
+    // inputMinY> when in normal-portrait orientation.  The input
+    // device and the screen might have different resolutions.  The
+    // resolution difference is Scale = <inputToScreenScaleX,
+    // inputToScreenScaleY>.  So going from input to screen space
+    // (when in normal portrait orientation) is an affine transform
+    // defined by
+    //
+    //   P_screen = Scale * (P_input - P_min)
+    //
+    int inputMinX, inputMinY;
+    float inputToScreenScaleX, inputToScreenScaleY;
+    // Some touch devices use virtual buttons instead of hardware
+    // buttons.  When the device uses vbuttons, we convert touch
+    // events into key events of type |keyCode| when the start of the
+    // touch is within |buttonRect|.  |buttonRect| must be disjoint
+    // from the screen rect.
+    static const size_t kMaxVButtons = 4;
+    struct VButton {
+        nsIntRect buttonRect;   // in screen space
+        int keyCode;
+    } vbuttons[kMaxVButtons];
 
     void run()
     {
         func(fd, this);
     }
+
+    int inputXToScreenX(int inputX) {
+        return inputToScreenScaleX * (inputX - inputMinX);
+    }
+    int inputYToScreenY(int inputY) {
+        return inputToScreenScaleY * (inputY - inputMinY);
+    }
 };
 
 class nsAppShell : public nsBaseAppShell {
 public:
     nsAppShell();
 
     nsresult Init();
     virtual bool ProcessNextNativeEvent(bool maywait);
@@ -82,17 +127,18 @@ public:
     void NotifyNativeEvent();
 
 protected:
     virtual ~nsAppShell();
 
     virtual void ScheduleNativeEventCallback();
 
 private:
-    nsresult AddFdHandler(int fd, FdHandlerCallback handlerFunc);
+    nsresult AddFdHandler(int fd, FdHandlerCallback handlerFunc,
+                          const char* deviceName);
 
     // This is somewhat racy but is perfectly safe given how the callback works
     bool mNativeCallbackRequest;
     nsTArray<FdHandler> mHandlers;
 };
 
 #endif /* nsAppShell_h */