diff --git a/allmakefiles.sh b/allmakefiles.sh
index de08101962d..5975cc99519 100755
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -299,6 +299,7 @@ content/xbl/Makefile
content/xbl/public/Makefile
content/xbl/src/Makefile
content/xbl/builtin/Makefile
+content/xbl/builtin/gtk2/Makefile
content/xbl/builtin/unix/Makefile
content/xbl/builtin/win/Makefile
content/xsl/Makefile
diff --git a/content/xbl/builtin/Makefile.in b/content/xbl/builtin/Makefile.in
index 3146609842f..34af14eb842 100644
--- a/content/xbl/builtin/Makefile.in
+++ b/content/xbl/builtin/Makefile.in
@@ -48,9 +48,13 @@ else
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
DIRS = mac
else
+ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+DIRS = gtk2
+else
DIRS = unix
endif
endif
+endif
include $(topsrcdir)/config/rules.mk
diff --git a/content/xbl/builtin/gtk2/.cvsignore b/content/xbl/builtin/gtk2/.cvsignore
new file mode 100644
index 00000000000..f3c7a7c5da6
--- /dev/null
+++ b/content/xbl/builtin/gtk2/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/content/xbl/builtin/gtk2/Makefile.in b/content/xbl/builtin/gtk2/Makefile.in
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/content/xbl/builtin/gtk2/platformHTMLBindings.xml b/content/xbl/builtin/gtk2/platformHTMLBindings.xml
new file mode 100644
index 00000000000..6e51523e767
--- /dev/null
+++ b/content/xbl/builtin/gtk2/platformHTMLBindings.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp
index c81eae63dca..3e1de085ab8 100644
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -128,6 +128,7 @@
#include "nsStyleSet.h"
#include "nsImageFrame.h"
#include "nsILanguageAtomService.h"
+#include "nsTextControlFrame.h"
// view stuff
#include "nsViewsCID.h"
@@ -417,6 +418,7 @@ Shutdown()
GlobalWindowImpl::ShutDown();
nsDOMClassInfo::ShutDown();
+ nsTextControlFrame::ShutDown();
}
#ifdef NS_DEBUG
diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp
index 6817f6ee1cf..fbc482e60cd 100644
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -120,6 +120,10 @@
#include "nsIDOMText.h" //for multiline getselection
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
+#include "nsIDOMKeyListener.h"
+#include "nsIDOMEventGroup.h"
+#include "nsIDOM3EventTarget.h"
+#include "nsINativeKeyBindings.h"
#ifdef IBMBIDI
#include "nsIBidiKeyboard.h"
@@ -138,8 +142,12 @@ static const PRInt32 DEFAULT_COLS = 20;
static const PRInt32 DEFAULT_ROWS = 1;
static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
+static nsINativeKeyBindings *sNativeInputBindings = nsnull;
+static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
+
class nsTextInputListener : public nsISelectionListener,
public nsIDOMFocusListener,
+ public nsIDOMKeyListener,
public nsIEditorObserver,
public nsSupportsWeakReference
{
@@ -169,12 +177,19 @@ public:
NS_IMETHOD Blur (nsIDOMEvent* aEvent);
/* END interfaces from nsIDOMFocusListener*/
+ // nsIDOMKeyListener
+ NS_IMETHOD KeyDown(nsIDOMEvent *aKeyEvent);
+ NS_IMETHOD KeyPress(nsIDOMEvent *aKeyEvent);
+ NS_IMETHOD KeyUp(nsIDOMEvent *aKeyEvent);
+
NS_DECL_NSIEDITOROBSERVER
protected:
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
+ NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
+
protected:
nsTextControlFrame* mFrame; // weak reference
@@ -211,9 +226,18 @@ nsTextInputListener::~nsTextInputListener()
{
}
-NS_IMPL_ISUPPORTS5(nsTextInputListener, nsISelectionListener,
- nsIDOMEventListener, nsIDOMFocusListener,
- nsIEditorObserver, nsISupportsWeakReference)
+NS_IMPL_ADDREF(nsTextInputListener)
+NS_IMPL_RELEASE(nsTextInputListener)
+
+NS_INTERFACE_MAP_BEGIN(nsTextInputListener)
+ NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
+ NS_INTERFACE_MAP_ENTRY(nsIEditorObserver)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMFocusListener)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFocusListener)
+NS_INTERFACE_MAP_END
// BEGIN nsIDOMSelectionListener
@@ -313,6 +337,103 @@ nsTextInputListener::Blur(nsIDOMEvent* aEvent)
// END nsIFocusListener
+// BEGIN nsIDOMKeyListener
+
+static void
+DoCommandCallback(const char *aCommand, void *aData)
+{
+ nsTextControlFrame *frame = NS_STATIC_CAST(nsTextControlFrame*, aData);
+ nsIContent *content = frame->GetContent();
+
+ nsCOMPtr controllers;
+ nsCOMPtr input = do_QueryInterface(content);
+ if (input) {
+ input->GetControllers(getter_AddRefs(controllers));
+ } else {
+ nsCOMPtr textArea =
+ do_QueryInterface(content);
+
+ if (textArea) {
+ textArea->GetControllers(getter_AddRefs(controllers));
+ }
+ }
+
+ if (!controllers) {
+ NS_WARNING("Could not get controllers");
+ return;
+ }
+
+ nsCOMPtr controller;
+ controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
+ if (controller) {
+ controller->DoCommand(aCommand);
+ }
+}
+
+static PRBool
+DOMEventToNativeKeyEvent(nsIDOMEvent *aDOMEvent,
+ nsNativeKeyEvent *aNativeEvent)
+{
+ nsCOMPtr nsevent = do_QueryInterface(aDOMEvent);
+ PRBool defaultPrevented;
+ nsevent->GetPreventDefault(&defaultPrevented);
+ if (defaultPrevented)
+ return PR_FALSE;
+
+ nsCOMPtr keyEvent = do_QueryInterface(aDOMEvent);
+
+ keyEvent->GetCharCode(&aNativeEvent->charCode);
+ keyEvent->GetKeyCode(&aNativeEvent->keyCode);
+ keyEvent->GetAltKey(&aNativeEvent->altKey);
+ keyEvent->GetCtrlKey(&aNativeEvent->ctrlKey);
+ keyEvent->GetShiftKey(&aNativeEvent->shiftKey);
+ keyEvent->GetMetaKey(&aNativeEvent->metaKey);
+
+ return PR_TRUE;
+}
+
+NS_IMETHODIMP
+nsTextInputListener::KeyDown(nsIDOMEvent *aKeyEvent)
+{
+ nsNativeKeyEvent nativeEvent;
+ nsINativeKeyBindings *bindings = GetKeyBindings();
+ if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
+ if (bindings->KeyDown(nativeEvent, DoCommandCallback, mFrame)) {
+ aKeyEvent->PreventDefault();
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsTextInputListener::KeyPress(nsIDOMEvent *aKeyEvent)
+{
+ nsNativeKeyEvent nativeEvent;
+ nsINativeKeyBindings *bindings = GetKeyBindings();
+ if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
+ if (bindings->KeyPress(nativeEvent, DoCommandCallback, mFrame)) {
+ aKeyEvent->PreventDefault();
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsTextInputListener::KeyUp(nsIDOMEvent *aKeyEvent)
+{
+ nsNativeKeyEvent nativeEvent;
+ nsINativeKeyBindings *bindings = GetKeyBindings();
+ if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
+ if (bindings->KeyUp(nativeEvent, DoCommandCallback, mFrame)) {
+ aKeyEvent->PreventDefault();
+ }
+ }
+
+ return NS_OK;
+}
+// END nsIDOMKeyListener
// BEGIN nsIEditorObserver
@@ -371,6 +492,36 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
return domWindow->UpdateCommands(commandsToUpdate);
}
+nsINativeKeyBindings*
+nsTextInputListener::GetKeyBindings()
+{
+ if (mFrame->IsTextArea()) {
+ static PRBool sNoTextAreaBindings = PR_FALSE;
+
+ if (!sNativeTextAreaBindings && !sNoTextAreaBindings) {
+ CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea",
+ &sNativeTextAreaBindings);
+
+ if (!sNativeTextAreaBindings) {
+ sNoTextAreaBindings = PR_TRUE;
+ }
+ }
+
+ return sNativeTextAreaBindings;
+ }
+
+ static PRBool sNoInputBindings = PR_FALSE;
+ if (!sNativeInputBindings && !sNoInputBindings) {
+ CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input",
+ &sNativeInputBindings);
+
+ if (!sNativeInputBindings) {
+ sNoInputBindings = PR_TRUE;
+ }
+ }
+
+ return sNativeInputBindings;
+}
// END nsTextInputListener
@@ -1255,6 +1406,22 @@ nsTextControlFrame::PreDestroy(nsPresContext* aPresContext)
{
erP->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
}
+
+ nsCOMPtr systemGroup;
+ erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
+ nsCOMPtr dom3Targ = do_QueryInterface(mContent);
+ if (dom3Targ) {
+ // cast because of ambiguous base
+ nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
+ mTextListener);
+
+ dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keydown"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keyup"),
+ listener, PR_FALSE, systemGroup);
+ }
}
mDidPreDestroy = PR_TRUE;
@@ -3005,11 +3172,10 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE);
}
- //register keylistener
- nsCOMPtr erP;
- if (NS_SUCCEEDED(mContent->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP))) && erP)
- {
- // register the event listeners with the DOM event reveiver
+ //register focus and key listeners
+ nsCOMPtr erP = do_QueryInterface(mContent);
+ if (erP) {
+ // register the event listeners with the DOM event receiver
rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
// XXXbryner do we need to check for a null presshell here?
@@ -3017,6 +3183,22 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
return NS_ERROR_FAILURE;
}
+ nsCOMPtr systemGroup;
+ erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
+ nsCOMPtr dom3Targ = do_QueryInterface(mContent);
+ if (dom3Targ) {
+ // cast because of ambiguous base
+ nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
+ mTextListener);
+
+ dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keydown"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keyup"),
+ listener, PR_FALSE, systemGroup);
+ }
+
while(first)
{
nsIView *view = first->GetView();
@@ -3105,3 +3287,10 @@ nsTextControlFrame::HandleEvent(nsPresContext* aPresContext,
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
}
+
+/* static */ void
+nsTextControlFrame::ShutDown()
+{
+ NS_IF_RELEASE(sNativeTextAreaBindings);
+ NS_IF_RELEASE(sNativeInputBindings);
+}
diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h
index 237cfc9210f..517be789523 100644
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -212,6 +212,9 @@ public: //for methods who access nsTextControlFrame directly
nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
+ /* called to free up native keybinding services */
+ static NS_HIDDEN_(void) ShutDown();
+
protected:
/**
diff --git a/layout/html/forms/src/nsTextControlFrame.cpp b/layout/html/forms/src/nsTextControlFrame.cpp
index 6817f6ee1cf..fbc482e60cd 100644
--- a/layout/html/forms/src/nsTextControlFrame.cpp
+++ b/layout/html/forms/src/nsTextControlFrame.cpp
@@ -120,6 +120,10 @@
#include "nsIDOMText.h" //for multiline getselection
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
+#include "nsIDOMKeyListener.h"
+#include "nsIDOMEventGroup.h"
+#include "nsIDOM3EventTarget.h"
+#include "nsINativeKeyBindings.h"
#ifdef IBMBIDI
#include "nsIBidiKeyboard.h"
@@ -138,8 +142,12 @@ static const PRInt32 DEFAULT_COLS = 20;
static const PRInt32 DEFAULT_ROWS = 1;
static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
+static nsINativeKeyBindings *sNativeInputBindings = nsnull;
+static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
+
class nsTextInputListener : public nsISelectionListener,
public nsIDOMFocusListener,
+ public nsIDOMKeyListener,
public nsIEditorObserver,
public nsSupportsWeakReference
{
@@ -169,12 +177,19 @@ public:
NS_IMETHOD Blur (nsIDOMEvent* aEvent);
/* END interfaces from nsIDOMFocusListener*/
+ // nsIDOMKeyListener
+ NS_IMETHOD KeyDown(nsIDOMEvent *aKeyEvent);
+ NS_IMETHOD KeyPress(nsIDOMEvent *aKeyEvent);
+ NS_IMETHOD KeyUp(nsIDOMEvent *aKeyEvent);
+
NS_DECL_NSIEDITOROBSERVER
protected:
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
+ NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
+
protected:
nsTextControlFrame* mFrame; // weak reference
@@ -211,9 +226,18 @@ nsTextInputListener::~nsTextInputListener()
{
}
-NS_IMPL_ISUPPORTS5(nsTextInputListener, nsISelectionListener,
- nsIDOMEventListener, nsIDOMFocusListener,
- nsIEditorObserver, nsISupportsWeakReference)
+NS_IMPL_ADDREF(nsTextInputListener)
+NS_IMPL_RELEASE(nsTextInputListener)
+
+NS_INTERFACE_MAP_BEGIN(nsTextInputListener)
+ NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
+ NS_INTERFACE_MAP_ENTRY(nsIEditorObserver)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMFocusListener)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFocusListener)
+NS_INTERFACE_MAP_END
// BEGIN nsIDOMSelectionListener
@@ -313,6 +337,103 @@ nsTextInputListener::Blur(nsIDOMEvent* aEvent)
// END nsIFocusListener
+// BEGIN nsIDOMKeyListener
+
+static void
+DoCommandCallback(const char *aCommand, void *aData)
+{
+ nsTextControlFrame *frame = NS_STATIC_CAST(nsTextControlFrame*, aData);
+ nsIContent *content = frame->GetContent();
+
+ nsCOMPtr controllers;
+ nsCOMPtr input = do_QueryInterface(content);
+ if (input) {
+ input->GetControllers(getter_AddRefs(controllers));
+ } else {
+ nsCOMPtr textArea =
+ do_QueryInterface(content);
+
+ if (textArea) {
+ textArea->GetControllers(getter_AddRefs(controllers));
+ }
+ }
+
+ if (!controllers) {
+ NS_WARNING("Could not get controllers");
+ return;
+ }
+
+ nsCOMPtr controller;
+ controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
+ if (controller) {
+ controller->DoCommand(aCommand);
+ }
+}
+
+static PRBool
+DOMEventToNativeKeyEvent(nsIDOMEvent *aDOMEvent,
+ nsNativeKeyEvent *aNativeEvent)
+{
+ nsCOMPtr nsevent = do_QueryInterface(aDOMEvent);
+ PRBool defaultPrevented;
+ nsevent->GetPreventDefault(&defaultPrevented);
+ if (defaultPrevented)
+ return PR_FALSE;
+
+ nsCOMPtr keyEvent = do_QueryInterface(aDOMEvent);
+
+ keyEvent->GetCharCode(&aNativeEvent->charCode);
+ keyEvent->GetKeyCode(&aNativeEvent->keyCode);
+ keyEvent->GetAltKey(&aNativeEvent->altKey);
+ keyEvent->GetCtrlKey(&aNativeEvent->ctrlKey);
+ keyEvent->GetShiftKey(&aNativeEvent->shiftKey);
+ keyEvent->GetMetaKey(&aNativeEvent->metaKey);
+
+ return PR_TRUE;
+}
+
+NS_IMETHODIMP
+nsTextInputListener::KeyDown(nsIDOMEvent *aKeyEvent)
+{
+ nsNativeKeyEvent nativeEvent;
+ nsINativeKeyBindings *bindings = GetKeyBindings();
+ if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
+ if (bindings->KeyDown(nativeEvent, DoCommandCallback, mFrame)) {
+ aKeyEvent->PreventDefault();
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsTextInputListener::KeyPress(nsIDOMEvent *aKeyEvent)
+{
+ nsNativeKeyEvent nativeEvent;
+ nsINativeKeyBindings *bindings = GetKeyBindings();
+ if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
+ if (bindings->KeyPress(nativeEvent, DoCommandCallback, mFrame)) {
+ aKeyEvent->PreventDefault();
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsTextInputListener::KeyUp(nsIDOMEvent *aKeyEvent)
+{
+ nsNativeKeyEvent nativeEvent;
+ nsINativeKeyBindings *bindings = GetKeyBindings();
+ if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
+ if (bindings->KeyUp(nativeEvent, DoCommandCallback, mFrame)) {
+ aKeyEvent->PreventDefault();
+ }
+ }
+
+ return NS_OK;
+}
+// END nsIDOMKeyListener
// BEGIN nsIEditorObserver
@@ -371,6 +492,36 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
return domWindow->UpdateCommands(commandsToUpdate);
}
+nsINativeKeyBindings*
+nsTextInputListener::GetKeyBindings()
+{
+ if (mFrame->IsTextArea()) {
+ static PRBool sNoTextAreaBindings = PR_FALSE;
+
+ if (!sNativeTextAreaBindings && !sNoTextAreaBindings) {
+ CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea",
+ &sNativeTextAreaBindings);
+
+ if (!sNativeTextAreaBindings) {
+ sNoTextAreaBindings = PR_TRUE;
+ }
+ }
+
+ return sNativeTextAreaBindings;
+ }
+
+ static PRBool sNoInputBindings = PR_FALSE;
+ if (!sNativeInputBindings && !sNoInputBindings) {
+ CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input",
+ &sNativeInputBindings);
+
+ if (!sNativeInputBindings) {
+ sNoInputBindings = PR_TRUE;
+ }
+ }
+
+ return sNativeInputBindings;
+}
// END nsTextInputListener
@@ -1255,6 +1406,22 @@ nsTextControlFrame::PreDestroy(nsPresContext* aPresContext)
{
erP->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
}
+
+ nsCOMPtr systemGroup;
+ erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
+ nsCOMPtr dom3Targ = do_QueryInterface(mContent);
+ if (dom3Targ) {
+ // cast because of ambiguous base
+ nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
+ mTextListener);
+
+ dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keydown"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keyup"),
+ listener, PR_FALSE, systemGroup);
+ }
}
mDidPreDestroy = PR_TRUE;
@@ -3005,11 +3172,10 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE);
}
- //register keylistener
- nsCOMPtr erP;
- if (NS_SUCCEEDED(mContent->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP))) && erP)
- {
- // register the event listeners with the DOM event reveiver
+ //register focus and key listeners
+ nsCOMPtr erP = do_QueryInterface(mContent);
+ if (erP) {
+ // register the event listeners with the DOM event receiver
rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
// XXXbryner do we need to check for a null presshell here?
@@ -3017,6 +3183,22 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
return NS_ERROR_FAILURE;
}
+ nsCOMPtr systemGroup;
+ erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
+ nsCOMPtr dom3Targ = do_QueryInterface(mContent);
+ if (dom3Targ) {
+ // cast because of ambiguous base
+ nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
+ mTextListener);
+
+ dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keydown"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
+ listener, PR_FALSE, systemGroup);
+ dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keyup"),
+ listener, PR_FALSE, systemGroup);
+ }
+
while(first)
{
nsIView *view = first->GetView();
@@ -3105,3 +3287,10 @@ nsTextControlFrame::HandleEvent(nsPresContext* aPresContext,
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
}
+
+/* static */ void
+nsTextControlFrame::ShutDown()
+{
+ NS_IF_RELEASE(sNativeTextAreaBindings);
+ NS_IF_RELEASE(sNativeInputBindings);
+}
diff --git a/layout/html/forms/src/nsTextControlFrame.h b/layout/html/forms/src/nsTextControlFrame.h
index 237cfc9210f..517be789523 100644
--- a/layout/html/forms/src/nsTextControlFrame.h
+++ b/layout/html/forms/src/nsTextControlFrame.h
@@ -212,6 +212,9 @@ public: //for methods who access nsTextControlFrame directly
nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
+ /* called to free up native keybinding services */
+ static NS_HIDDEN_(void) ShutDown();
+
protected:
/**
diff --git a/widget/public/Makefile.in b/widget/public/Makefile.in
index 2b38cd31980..c243937db6c 100644
--- a/widget/public/Makefile.in
+++ b/widget/public/Makefile.in
@@ -71,6 +71,7 @@ EXPORTS = \
nsIDragSessionOS2.h \
nsIXRemoteWidgetHelper.h \
nsIPluginWidget.h \
+ nsINativeKeyBindings.h \
$(NULL)
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
diff --git a/widget/public/nsINativeKeyBindings.h b/widget/public/nsINativeKeyBindings.h
new file mode 100644
index 00000000000..f41151877f0
--- /dev/null
+++ b/widget/public/nsINativeKeyBindings.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+#ifndef nsINativeKeyBindings_h_
+#define nsINativeKeyBindings_h_
+
+#include "nsISupports.h"
+
+#define NS_INATIVEKEYBINDINGS_IID \
+{0x606c54e7, 0x0593, 0x4750, {0x99, 0xd9, 0x4e, 0x1b, 0xcc, 0xec, 0x98, 0xd9}}
+
+#define NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX \
+ "@mozilla.org/widget/native-key-bindings;1?type="
+
+struct nsNativeKeyEvent
+{
+ PRUint32 keyCode;
+ PRUint32 charCode;
+ PRBool altKey;
+ PRBool ctrlKey;
+ PRBool shiftKey;
+ PRBool metaKey;
+};
+
+class nsINativeKeyBindings : public nsISupports
+{
+ public:
+ typedef void (*DoCommandCallback)(const char *, void*);
+
+ NS_DEFINE_STATIC_IID_ACCESSOR(NS_INATIVEKEYBINDINGS_IID)
+
+ virtual NS_HIDDEN_(PRBool) KeyDown(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback,
+ void *aCallbackData) = 0;
+
+ virtual NS_HIDDEN_(PRBool) KeyPress(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback,
+ void *aCallbackData) = 0;
+
+ virtual NS_HIDDEN_(PRBool) KeyUp(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback,
+ void *aCallbackData) = 0;
+};
+
+#endif
diff --git a/widget/src/gtk2/Makefile.in b/widget/src/gtk2/Makefile.in
index 761f4c263e7..31f891a0dee 100644
--- a/widget/src/gtk2/Makefile.in
+++ b/widget/src/gtk2/Makefile.in
@@ -81,6 +81,7 @@ CPPSRCS = \
nsDragService.cpp \
nsFilePicker.cpp \
nsSound.cpp \
+ nsNativeKeyBindings.cpp \
$(NULL)
# build our subdirs, too
diff --git a/widget/src/gtk2/nsGtkKeyUtils.cpp b/widget/src/gtk2/nsGtkKeyUtils.cpp
index 4db91564bbd..29b458bd41d 100644
--- a/widget/src/gtk2/nsGtkKeyUtils.cpp
+++ b/widget/src/gtk2/nsGtkKeyUtils.cpp
@@ -215,6 +215,53 @@ GdkKeyCodeToDOMKeyCode(int aKeysym)
return((int)0);
}
+int
+DOMKeyCodeToGdkKeyCode(PRUint32 aKeysym)
+{
+ int i, length = 0;
+
+ // First, try to handle alphanumeric input, not listed in nsKeycodes:
+ // most likely, more letters will be getting typed in than things in
+ // the key list, so we will look through these first.
+
+ if (aKeysym >= NS_VK_A && aKeysym <= NS_VK_Z)
+ // gdk and DOM both use the ASCII codes for these keys.
+ return aKeysym;
+
+ // numbers
+ if (aKeysym >= NS_VK_0 && aKeysym <= NS_VK_9)
+ // gdk and DOM both use the ASCII codes for these keys.
+ return aKeysym - GDK_0 + NS_VK_0;
+
+ // keypad numbers
+ if (aKeysym >= NS_VK_NUMPAD0 && aKeysym <= NS_VK_NUMPAD9)
+ return aKeysym - NS_VK_NUMPAD0 + GDK_KP_0;
+
+ // map Sun Keyboard special keysyms
+ if (IS_XSUN_XSERVER(GDK_DISPLAY())) {
+ length = NS_ARRAY_LENGTH(nsSunKeycodes);
+ for (i = 0; i < length; ++i) {
+ if (nsSunKeycodes[i].vkCode == aKeysym) {
+ return nsSunKeycodes[i].keysym;
+ }
+ }
+ }
+
+ // misc other things
+ length = NS_ARRAY_LENGTH(nsKeycodes);
+ for (i = 0; i < length; ++i) {
+ if (nsKeycodes[i].vkCode == aKeysym) {
+ return nsKeycodes[i].keysym;
+ }
+ }
+
+ // function keys
+ if (aKeysym >= NS_VK_F1 && aKeysym <= NS_VK_F9)
+ return aKeysym - NS_VK_F1 + GDK_F1;
+
+ return 0;
+}
+
// Convert gdk key event keyvals to char codes if printable, 0 otherwise
PRUint32 nsConvertCharCodeToUnicode(GdkEventKey* aEvent)
{
diff --git a/widget/src/gtk2/nsGtkKeyUtils.h b/widget/src/gtk2/nsGtkKeyUtils.h
index a5d60f3942c..036c116bbb8 100644
--- a/widget/src/gtk2/nsGtkKeyUtils.h
+++ b/widget/src/gtk2/nsGtkKeyUtils.h
@@ -40,6 +40,7 @@
#define __nsGdkKeyUtils_h__
int GdkKeyCodeToDOMKeyCode (int aKeysym);
+int DOMKeyCodeToGdkKeyCode (PRUint32 aKeysym);
PRUint32 nsConvertCharCodeToUnicode (GdkEventKey* aEvent);
#endif /* __nsGdkKeyUtils_h__ */
diff --git a/widget/src/gtk2/nsNativeKeyBindings.cpp b/widget/src/gtk2/nsNativeKeyBindings.cpp
new file mode 100644
index 00000000000..7dcc3c7af99
--- /dev/null
+++ b/widget/src/gtk2/nsNativeKeyBindings.cpp
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+#include "nsNativeKeyBindings.h"
+#include "nsString.h"
+#include "nsMemory.h"
+#include "nsGtkKeyUtils.h"
+
+#include
+#include
+#include
+#include
+
+static nsINativeKeyBindings::DoCommandCallback gCurrentCallback;
+static void *gCurrentCallbackData;
+
+// Common GtkEntry and GtkTextView signals
+static void
+copy_clipboard_cb(GtkWidget *w, gpointer user_data)
+{
+ gCurrentCallback("cmd_copy", gCurrentCallbackData);
+ g_signal_stop_emission_by_name(w, "copy_clipboard");
+}
+
+static void
+cut_clipboard_cb(GtkWidget *w, gpointer user_data)
+{
+ gCurrentCallback("cmd_cut", gCurrentCallbackData);
+ g_signal_stop_emission_by_name(w, "cut_clipboard");
+}
+
+// GTK distinguishes between display lines (wrapped, as they appear on the
+// screen) and paragraphs, which are runs of text terminated by a newline.
+// We don't have this distinction, so we always use editor's notion of
+// lines, which are newline-terminated.
+
+static const char *const sDeleteCommands[][2] = {
+ // backward, forward
+ { "cmd_deleteCharBackward", "cmd_deleteCharForward" }, // CHARS
+ { "cmd_deleteWordBackward", "cmd_deleteWordForward" }, // WORD_ENDS
+ { "cmd_deleteWordBackward", "cmd_deleteWordForward" }, // WORDS
+ { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // LINES
+ { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // LINE_ENDS
+ { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // PARAGRAPH_ENDS
+ { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // PARAGRAPHS
+ // This deletes from the end of the previous word to the beginning of the
+ // next word, but only if the caret is not in a word.
+ // XXX need to implement in editor
+ { nsnull, nsnull } // WHITESPACE
+};
+
+static void
+delete_from_cursor_cb(GtkWidget *w, GtkDeleteType del_type,
+ gint count, gpointer user_data)
+{
+ g_signal_stop_emission_by_name(w, "delete_from_cursor");
+
+ PRBool forward = count > 0;
+ if (PRUint32(del_type) >= NS_ARRAY_LENGTH(sDeleteCommands)) {
+ // unsupported deletion type
+ return;
+ }
+
+ if (del_type == GTK_DELETE_WORDS) {
+ // This works like word_ends, except we first move the caret to the
+ // beginning/end of the current word.
+ if (forward) {
+ gCurrentCallback("cmd_wordNext", gCurrentCallbackData);
+ gCurrentCallback("cmd_wordPrevious", gCurrentCallbackData);
+ } else {
+ gCurrentCallback("cmd_wordPrevious", gCurrentCallbackData);
+ gCurrentCallback("cmd_wordNext", gCurrentCallbackData);
+ }
+ } else if (del_type == GTK_DELETE_DISPLAY_LINES ||
+ del_type == GTK_DELETE_PARAGRAPHS) {
+
+ // This works like display_line_ends, except we first move the caret to the
+ // beginning/end of the current line.
+ if (forward) {
+ gCurrentCallback("cmd_beginLine", gCurrentCallbackData);
+ } else {
+ gCurrentCallback("cmd_endLine", gCurrentCallbackData);
+ }
+ }
+
+ const char *cmd = sDeleteCommands[del_type][forward];
+ if (!cmd)
+ return; // unsupported command
+
+ count = PR_ABS(count);
+ for (int i = 0; i < count; ++i) {
+ gCurrentCallback(cmd, gCurrentCallbackData);
+ }
+}
+
+static const char *const sMoveCommands[][2][2] = {
+ // non-extend { backward, forward }, extend { backward, forward }
+ // GTK differentiates between logical position, which is prev/next,
+ // and visual position, which is always left/right.
+ // We should fix this to work the same way for RTL text input.
+ { // LOGICAL_POSITIONS
+ { "cmd_charPrevious", "cmd_charNext" },
+ { "cmd_selectCharPrevious", "cmd_selectCharNext" }
+ },
+ { // VISUAL_POSITIONS
+ { "cmd_charPrevious", "cmd_charNext" },
+ { "cmd_selectCharPrevious", "cmd_selectCharNext" }
+ },
+ { // WORDS
+ { "cmd_wordPrevious", "cmd_wordNext" },
+ { "cmd_selectWordPrevious", "cmd_selectWordNext" }
+ },
+ { // DISPLAY_LINES
+ { "cmd_linePrevious", "cmd_lineNext" },
+ { "cmd_selectLinePrevious", "cmd_selectLineNext" }
+ },
+ { // DISPLAY_LINE_ENDS
+ { "cmd_beginLine", "cmd_endLine" },
+ { "cmd_selectBeginLine", "cmd_selectEndLine" }
+ },
+ { // PARAGRAPHS
+ { "cmd_linePrevious", "cmd_lineNext" },
+ { "cmd_selectLinePrevious", "cmd_selectLineNext" }
+ },
+ { // PARAGRAPH_ENDS
+ { "cmd_beginLine", "cmd_endLine" },
+ { "cmd_selectBeginLine", "cmd_selectEndLine" }
+ },
+ { // PAGES
+ { "cmd_movePageUp", "cmd_movePageDown" },
+ { "cmd_selectPageUp", "cmd_selectPageDown" }
+ },
+ { // BUFFER_ENDS
+ { "cmd_moveTop", "cmd_moveBottom" },
+ { "cmd_selectTop", "cmd_selectBottom" }
+ },
+ { // HORIZONTAL_PAGES (unsupported)
+ { nsnull, nsnull },
+ { nsnull, nsnull }
+ }
+};
+
+static void
+move_cursor_cb(GtkWidget *w, GtkMovementStep step, gint count,
+ gboolean extend_selection, gpointer user_data)
+{
+ g_signal_stop_emission_by_name(w, "move_cursor");
+ PRBool forward = count > 0;
+ if (PRUint32(step) >= NS_ARRAY_LENGTH(sMoveCommands)) {
+ // unsupported movement type
+ return;
+ }
+
+ const char *cmd = sMoveCommands[step][extend_selection][forward];
+ if (!cmd)
+ return; // unsupported command
+
+
+ count = PR_ABS(count);
+ for (int i = 0; i < count; ++i) {
+ gCurrentCallback(cmd, gCurrentCallbackData);
+ }
+}
+
+static void
+paste_clipboard_cb(GtkWidget *w, gpointer user_data)
+{
+ gCurrentCallback("cmd_paste", gCurrentCallbackData);
+ g_signal_stop_emission_by_name(w, "paste_clipboard");
+}
+
+// GtkTextView-only signals
+static void
+select_all_cb(GtkWidget *w, gboolean select, gpointer user_data)
+{
+ gCurrentCallback("cmd_selectAll", gCurrentCallbackData);
+ g_signal_stop_emission_by_name(w, "select_all");
+}
+
+void
+nsNativeKeyBindings::Init(NativeKeyBindingsType aType)
+{
+ switch (aType) {
+ case eKeyBindings_Input:
+ mNativeTarget = gtk_entry_new();
+ break;
+ case eKeyBindings_TextArea:
+ mNativeTarget = gtk_text_view_new();
+ g_signal_connect(G_OBJECT(mNativeTarget), "select_all",
+ G_CALLBACK(select_all_cb), this);
+ break;
+ }
+
+ g_signal_connect(G_OBJECT(mNativeTarget), "copy_clipboard",
+ G_CALLBACK(copy_clipboard_cb), this);
+ g_signal_connect(G_OBJECT(mNativeTarget), "cut_clipboard",
+ G_CALLBACK(cut_clipboard_cb), this);
+ g_signal_connect(G_OBJECT(mNativeTarget), "delete_from_cursor",
+ G_CALLBACK(delete_from_cursor_cb), this);
+ g_signal_connect(G_OBJECT(mNativeTarget), "move_cursor",
+ G_CALLBACK(move_cursor_cb), this);
+ g_signal_connect(G_OBJECT(mNativeTarget), "paste_clipboard",
+ G_CALLBACK(paste_clipboard_cb), this);
+}
+
+nsNativeKeyBindings::~nsNativeKeyBindings()
+{
+ gtk_widget_destroy(mNativeTarget);
+}
+
+NS_IMPL_ISUPPORTS1(nsNativeKeyBindings, nsINativeKeyBindings)
+
+PRBool
+nsNativeKeyBindings::KeyDown(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback, void *aCallbackData)
+{
+ return PR_FALSE;
+}
+
+PRBool
+nsNativeKeyBindings::KeyPress(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback, void *aCallbackData)
+{
+ PRUint32 keyCode;
+
+ if (aEvent.charCode != 0)
+ keyCode = gdk_unicode_to_keyval(aEvent.charCode);
+ else
+ keyCode = DOMKeyCodeToGdkKeyCode(aEvent.keyCode);
+
+ int modifiers = 0;
+ if (aEvent.altKey)
+ modifiers |= GDK_MOD1_MASK;
+ if (aEvent.ctrlKey)
+ modifiers |= GDK_CONTROL_MASK;
+ if (aEvent.shiftKey)
+ modifiers |= GDK_SHIFT_MASK;
+ // we don't support meta
+
+ gCurrentCallback = aCallback;
+ gCurrentCallbackData = aCallbackData;
+
+ PRBool handled = PR_FALSE;
+
+ if (gtk_bindings_activate(GTK_OBJECT(mNativeTarget),
+ keyCode, GdkModifierType(modifiers))) {
+ handled = PR_TRUE;
+ }
+
+ gCurrentCallback = nsnull;
+ gCurrentCallbackData = nsnull;
+
+ return handled;
+}
+
+PRBool
+nsNativeKeyBindings::KeyUp(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback, void *aCallbackData)
+{
+ return PR_FALSE;
+}
diff --git a/widget/src/gtk2/nsNativeKeyBindings.h b/widget/src/gtk2/nsNativeKeyBindings.h
new file mode 100644
index 00000000000..3baece47055
--- /dev/null
+++ b/widget/src/gtk2/nsNativeKeyBindings.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+#ifndef nsNativeKeyBindings_h_
+#define nsNativeKeyBindings_h_
+
+// X.h defines KeyPress
+#ifdef KeyPress
+#undef KeyPress
+#endif
+
+#include "nsINativeKeyBindings.h"
+#include
+
+enum NativeKeyBindingsType {
+ eKeyBindings_Input,
+ eKeyBindings_TextArea
+};
+
+#define NS_NATIVEKEYBINDINGSINPUT_CID \
+{0x5c337258, 0xa580, 0x472e, {0x86, 0x15, 0xf2, 0x77, 0xdd, 0xc5, 0xbb, 0x06}}
+
+#define NS_NATIVEKEYBINDINGSINPUT_CONTRACTID \
+NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input"
+
+#define NS_NATIVEKEYBINDINGSTEXTAREA_CID \
+{0x2a898043, 0x180f, 0x4c8b, {0x8e, 0x54, 0x41, 0x0c, 0x7a, 0x54, 0x0f, 0x27}}
+
+#define NS_NATIVEKEYBINDINGSTEXTAREA_CONTRACTID \
+NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea"
+
+class nsNativeKeyBindings : public nsINativeKeyBindings
+{
+public:
+ NS_HIDDEN_(void) Init(NativeKeyBindingsType aType);
+
+ NS_DECL_ISUPPORTS
+
+ // nsINativeKeyBindings
+ virtual NS_HIDDEN_(PRBool) KeyDown(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback,
+ void *aCallbackData);
+
+ virtual NS_HIDDEN_(PRBool) KeyPress(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback,
+ void *aCallbackData);
+
+ virtual NS_HIDDEN_(PRBool) KeyUp(const nsNativeKeyEvent& aEvent,
+ DoCommandCallback aCallback,
+ void *aCallbackData);
+
+private:
+ ~nsNativeKeyBindings() NS_HIDDEN;
+
+ GtkWidget *mNativeTarget;
+};
+
+#endif
diff --git a/widget/src/gtk2/nsWidgetFactory.cpp b/widget/src/gtk2/nsWidgetFactory.cpp
index e3bc507476e..41eeed704b3 100644
--- a/widget/src/gtk2/nsWidgetFactory.cpp
+++ b/widget/src/gtk2/nsWidgetFactory.cpp
@@ -51,6 +51,7 @@
#include "nsFilePicker.h"
#include "nsSound.h"
#include "nsBidiKeyboard.h"
+#include "nsNativeKeyBindings.h"
#include "nsIComponentRegistrar.h"
#include "nsComponentManagerUtils.h"
@@ -147,6 +148,49 @@ nsFilePickerUnregisterSelf(nsIComponentManager *aCompMgr,
return rv;
}
+static NS_IMETHODIMP
+nsNativeKeyBindingsConstructor(nsISupports *aOuter, REFNSIID aIID,
+ void **aResult,
+ NativeKeyBindingsType aKeyBindingsType)
+{
+ nsresult rv;
+
+ nsNativeKeyBindings *inst;
+
+ *aResult = NULL;
+ if (NULL != aOuter) {
+ rv = NS_ERROR_NO_AGGREGATION;
+ return rv;
+ }
+
+ NS_NEWXPCOM(inst, nsNativeKeyBindings);
+ if (NULL == inst) {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ return rv;
+ }
+ NS_ADDREF(inst);
+ inst->Init(aKeyBindingsType);
+ rv = inst->QueryInterface(aIID, aResult);
+ NS_RELEASE(inst);
+
+ return rv;
+}
+
+static NS_IMETHODIMP
+nsNativeKeyBindingsInputConstructor(nsISupports *aOuter, REFNSIID aIID,
+ void **aResult)
+{
+ return nsNativeKeyBindingsConstructor(aOuter, aIID, aResult,
+ eKeyBindings_Input);
+}
+
+static NS_IMETHODIMP
+nsNativeKeyBindingsTextAreaConstructor(nsISupports *aOuter, REFNSIID aIID,
+ void **aResult)
+{
+ return nsNativeKeyBindingsConstructor(aOuter, aIID, aResult,
+ eKeyBindings_TextArea);
+}
static const nsModuleComponentInfo components[] =
{
@@ -204,6 +248,14 @@ static const nsModuleComponentInfo components[] =
NS_BIDIKEYBOARD_CID,
"@mozilla.org/widget/bidikeyboard;1",
nsBidiKeyboardConstructor },
+ { "Input Native Keybindings",
+ NS_NATIVEKEYBINDINGSINPUT_CID,
+ NS_NATIVEKEYBINDINGSINPUT_CONTRACTID,
+ nsNativeKeyBindingsInputConstructor },
+ { "TextArea Native Keybindings",
+ NS_NATIVEKEYBINDINGSTEXTAREA_CID,
+ NS_NATIVEKEYBINDINGSTEXTAREA_CONTRACTID,
+ nsNativeKeyBindingsTextAreaConstructor }
};
PR_STATIC_CALLBACK(void)