зеркало из https://github.com/mozilla/gecko-dev.git
Fix bug #76617. Some embedding apps can't get input focus. r=ccarlen,bryner sr=tor
This commit is contained in:
Родитель
8c2283f1e5
Коммит
b4dd5eb12c
|
@ -43,6 +43,9 @@
|
|||
#include <nsIDOMWindowInternal.h>
|
||||
#include <nsIChromeEventHandler.h>
|
||||
|
||||
// for the focus hacking we need to do
|
||||
#include <nsIFocusController.h>
|
||||
|
||||
// for profiles
|
||||
#include <nsMPFileLocProvider.h>
|
||||
|
||||
|
@ -448,6 +451,7 @@ EmbedPrivate::FindPrivateForBrowser(nsIWebBrowserChrome *aBrowser)
|
|||
void
|
||||
EmbedPrivate::ContentStateChange(void)
|
||||
{
|
||||
|
||||
// we don't attach listeners to chrome
|
||||
if (mListenersAttached && !mIsChrome)
|
||||
return;
|
||||
|
@ -492,6 +496,69 @@ EmbedPrivate::ContentFinishedLoading(void)
|
|||
}
|
||||
}
|
||||
|
||||
// handle focus in and focus out events
|
||||
void
|
||||
EmbedPrivate::TopLevelFocusIn(void)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> piWin;
|
||||
GetPIDOMWindow(getter_AddRefs(piWin));
|
||||
|
||||
if (!piWin)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIFocusController> focusController;
|
||||
piWin->GetRootFocusController(getter_AddRefs(focusController));
|
||||
if (focusController)
|
||||
focusController->SetActive(PR_TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
EmbedPrivate::TopLevelFocusOut(void)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> piWin;
|
||||
GetPIDOMWindow(getter_AddRefs(piWin));
|
||||
|
||||
if (!piWin)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIFocusController> focusController;
|
||||
piWin->GetRootFocusController(getter_AddRefs(focusController));
|
||||
if (focusController)
|
||||
focusController->SetActive(PR_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
EmbedPrivate::ChildFocusIn(void)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> piWin;
|
||||
GetPIDOMWindow(getter_AddRefs(piWin));
|
||||
|
||||
if (!piWin)
|
||||
return;
|
||||
|
||||
piWin->Activate();
|
||||
}
|
||||
|
||||
void
|
||||
EmbedPrivate::ChildFocusOut(void)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> piWin;
|
||||
GetPIDOMWindow(getter_AddRefs(piWin));
|
||||
|
||||
if (!piWin)
|
||||
return;
|
||||
|
||||
piWin->Deactivate();
|
||||
|
||||
// but the window is still active until the toplevel gets a focus
|
||||
// out
|
||||
nsCOMPtr<nsIFocusController> focusController;
|
||||
piWin->GetRootFocusController(getter_AddRefs(focusController));
|
||||
if (focusController)
|
||||
focusController->SetActive(PR_TRUE);
|
||||
|
||||
}
|
||||
|
||||
// Get the event listener for the chrome event handler.
|
||||
|
||||
void
|
||||
|
@ -500,28 +567,15 @@ EmbedPrivate::GetListener(void)
|
|||
if (mEventReceiver)
|
||||
return;
|
||||
|
||||
// get the web browser
|
||||
nsCOMPtr<nsIWebBrowser> webBrowser;
|
||||
mWindow->GetWebBrowser(getter_AddRefs(webBrowser));
|
||||
nsCOMPtr<nsPIDOMWindow> piWin;
|
||||
GetPIDOMWindow(getter_AddRefs(piWin));
|
||||
|
||||
// get the content DOM window for that web browser
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
|
||||
if (!domWindow) {
|
||||
NS_WARNING("no dom window in content progress change\n");
|
||||
if (!piWin)
|
||||
return;
|
||||
}
|
||||
|
||||
// get the private DOM window
|
||||
nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
|
||||
// and the root window for that DOM window
|
||||
nsCOMPtr<nsIDOMWindowInternal> rootWindow;
|
||||
domWindowPrivate->GetPrivateRoot(getter_AddRefs(rootWindow));
|
||||
|
||||
nsCOMPtr<nsIChromeEventHandler> chromeHandler;
|
||||
nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
|
||||
piWin->GetChromeEventHandler(getter_AddRefs(chromeHandler));
|
||||
|
||||
|
||||
mEventReceiver = do_QueryInterface(chromeHandler);
|
||||
}
|
||||
|
||||
|
@ -587,6 +641,41 @@ EmbedPrivate::DetachListeners(void)
|
|||
mListenersAttached = PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
EmbedPrivate::GetPIDOMWindow(nsPIDOMWindow **aPIWin)
|
||||
{
|
||||
*aPIWin = nsnull;
|
||||
|
||||
// get the web browser
|
||||
nsCOMPtr<nsIWebBrowser> webBrowser;
|
||||
mWindow->GetWebBrowser(getter_AddRefs(webBrowser));
|
||||
|
||||
// get the content DOM window for that web browser
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
|
||||
if (!domWindow)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// get the private DOM window
|
||||
nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
|
||||
// and the root window for that DOM window
|
||||
nsCOMPtr<nsIDOMWindowInternal> rootWindow;
|
||||
domWindowPrivate->GetPrivateRoot(getter_AddRefs(rootWindow));
|
||||
|
||||
nsCOMPtr<nsIChromeEventHandler> chromeHandler;
|
||||
nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
|
||||
|
||||
*aPIWin = piWin.get();
|
||||
|
||||
if (*aPIWin) {
|
||||
NS_ADDREF(*aPIWin);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
EmbedPrivate::StartupProfile(void)
|
||||
|
|
|
@ -43,6 +43,8 @@ class EmbedContentListener;
|
|||
class EmbedEventListener;
|
||||
class EmbedStream;
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
class EmbedPrivate {
|
||||
|
||||
public:
|
||||
|
@ -83,6 +85,16 @@ class EmbedPrivate {
|
|||
// visibility is set.
|
||||
void ContentFinishedLoading(void);
|
||||
|
||||
// these let the widget code know when the toplevel window gets and
|
||||
// looses focus.
|
||||
void TopLevelFocusIn (void);
|
||||
void TopLevelFocusOut(void);
|
||||
|
||||
// these are when the widget itself gets focus in and focus out
|
||||
// events
|
||||
void ChildFocusIn (void);
|
||||
void ChildFocusOut(void);
|
||||
|
||||
GtkMozEmbed *mOwningWidget;
|
||||
|
||||
// all of the objects that we own
|
||||
|
@ -135,6 +147,9 @@ class EmbedPrivate {
|
|||
void GetListener (void);
|
||||
void AttachListeners(void);
|
||||
void DetachListeners(void);
|
||||
|
||||
// this will get the PIDOMWindow for this widget
|
||||
nsresult GetPIDOMWindow (nsPIDOMWindow **aPIWin);
|
||||
|
||||
static nsresult StartupProfile (void);
|
||||
static void ShutdownProfile(void);
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
// so we can do our get_nsIWebBrowser later...
|
||||
#include <nsIWebBrowser.h>
|
||||
|
||||
// so we can get callbacks from the mozarea
|
||||
#include <gtkmozarea.h>
|
||||
|
||||
// class and instance initialization
|
||||
|
||||
static void
|
||||
|
@ -62,6 +65,26 @@ gtk_moz_embed_map(GtkWidget *widget);
|
|||
static void
|
||||
gtk_moz_embed_unmap(GtkWidget *widget);
|
||||
|
||||
static gint
|
||||
handle_child_focus_in(GtkWidget *aWidget,
|
||||
GdkEventFocus *aGdkFocusEvent,
|
||||
GtkMozEmbed *aEmbed);
|
||||
|
||||
static gint
|
||||
handle_child_focus_out(GtkWidget *aWidget,
|
||||
GdkEventFocus *aGdkFocusEvent,
|
||||
GtkMozEmbed *aEmbed);
|
||||
|
||||
// signal handlers for tracking the focus and and focus out events on
|
||||
// the toplevel window.
|
||||
|
||||
static void
|
||||
handle_toplevel_focus_in (GtkMozArea *aArea,
|
||||
GtkMozEmbed *aEmbed);
|
||||
static void
|
||||
handle_toplevel_focus_out(GtkMozArea *aArea,
|
||||
GtkMozEmbed *aEmbed);
|
||||
|
||||
// globals for this type of widget
|
||||
|
||||
static GtkBinClass *parent_class;
|
||||
|
@ -103,7 +126,7 @@ gtk_moz_embed_class_init(GtkMozEmbedClass *klass)
|
|||
container_class = GTK_CONTAINER_CLASS(klass);
|
||||
bin_class = GTK_BIN_CLASS(klass);
|
||||
widget_class = GTK_WIDGET_CLASS(klass);
|
||||
object_class = (GtkObjectClass *)klass;
|
||||
object_class = GTK_OBJECT_CLASS(klass);
|
||||
|
||||
parent_class = (GtkBinClass *)gtk_type_class(gtk_bin_get_type());
|
||||
|
||||
|
@ -373,6 +396,34 @@ gtk_moz_embed_realize(GtkWidget *widget)
|
|||
|
||||
if (embedPrivate->mURI.Length())
|
||||
embedPrivate->LoadCurrentURI();
|
||||
|
||||
|
||||
// connect to the focus out event for the child
|
||||
GtkWidget *child_widget = GTK_BIN(widget)->child;
|
||||
gtk_signal_connect_while_alive(GTK_OBJECT(child_widget),
|
||||
"focus_out_event",
|
||||
GTK_SIGNAL_FUNC(handle_child_focus_out),
|
||||
embed,
|
||||
GTK_OBJECT(child_widget));
|
||||
gtk_signal_connect_while_alive(GTK_OBJECT(child_widget),
|
||||
"focus_in_event",
|
||||
GTK_SIGNAL_FUNC(handle_child_focus_in),
|
||||
embed,
|
||||
GTK_OBJECT(child_widget));
|
||||
|
||||
// connect to the toplevel focus out events for the child
|
||||
GtkMozArea *mozarea = GTK_MOZAREA(child_widget);
|
||||
gtk_signal_connect_while_alive(GTK_OBJECT(mozarea),
|
||||
"toplevel_focus_in",
|
||||
GTK_SIGNAL_FUNC(handle_toplevel_focus_in),
|
||||
embed,
|
||||
GTK_OBJECT(mozarea));
|
||||
|
||||
gtk_signal_connect_while_alive(GTK_OBJECT(mozarea),
|
||||
"toplevel_focus_out",
|
||||
GTK_SIGNAL_FUNC(handle_toplevel_focus_out),
|
||||
embed,
|
||||
GTK_OBJECT(mozarea));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -452,7 +503,54 @@ gtk_moz_embed_unmap(GtkWidget *widget)
|
|||
gdk_window_hide(widget->window);
|
||||
|
||||
embedPrivate->Hide();
|
||||
}
|
||||
|
||||
static gint
|
||||
handle_child_focus_in(GtkWidget *aWidget,
|
||||
GdkEventFocus *aGdkFocusEvent,
|
||||
GtkMozEmbed *aEmbed)
|
||||
{
|
||||
EmbedPrivate *embedPrivate;
|
||||
|
||||
embedPrivate = (EmbedPrivate *)aEmbed->data;
|
||||
|
||||
embedPrivate->ChildFocusIn();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
handle_child_focus_out(GtkWidget *aWidget,
|
||||
GdkEventFocus *aGdkFocusEvent,
|
||||
GtkMozEmbed *aEmbed)
|
||||
{
|
||||
EmbedPrivate *embedPrivate;
|
||||
|
||||
embedPrivate = (EmbedPrivate *)aEmbed->data;
|
||||
|
||||
embedPrivate->ChildFocusOut();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_toplevel_focus_in (GtkMozArea *aArea,
|
||||
GtkMozEmbed *aEmbed)
|
||||
{
|
||||
EmbedPrivate *embedPrivate;
|
||||
embedPrivate = (EmbedPrivate *)aEmbed->data;
|
||||
|
||||
embedPrivate->TopLevelFocusIn();
|
||||
}
|
||||
|
||||
static void
|
||||
handle_toplevel_focus_out(GtkMozArea *aArea,
|
||||
GtkMozEmbed *aEmbed)
|
||||
{
|
||||
EmbedPrivate *embedPrivate;
|
||||
embedPrivate = (EmbedPrivate *)aEmbed->data;
|
||||
|
||||
embedPrivate->TopLevelFocusOut();
|
||||
}
|
||||
|
||||
// Widget methods
|
||||
|
|
|
@ -1331,16 +1331,6 @@ nsEventStatus PR_CALLBACK nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
|
|||
|
||||
switch(aEvent->message) {
|
||||
|
||||
case NS_ACTIVATE: {
|
||||
browser->Activate();
|
||||
break;
|
||||
}
|
||||
|
||||
case NS_DEACTIVATE: {
|
||||
browser->Deactivate();
|
||||
break;
|
||||
}
|
||||
|
||||
case NS_PAINT: {
|
||||
nsRect *rect = NS_STATIC_CAST(nsPaintEvent *, aEvent)->rect;
|
||||
browser->FillBackground(*rect);
|
||||
|
|
|
@ -1109,28 +1109,30 @@ nsWindow::SetFocus(PRBool aRaise)
|
|||
printf("top moz area is %p\n", NS_STATIC_CAST(void *, top_mozarea));
|
||||
#endif
|
||||
|
||||
// If there is a top_mozarea and it doesn't have focus then we're
|
||||
// going to ignore this request if we're part of the browser. If
|
||||
// we're embedded then we do grab focus on our toplevel window since
|
||||
// it doesn't hurt anything and the widget has to have focus inside
|
||||
// of the GtkWindow. If it doesn't then we will not get the right
|
||||
// events when we do actually get focus.
|
||||
// see if the toplevel window has focus
|
||||
gboolean toplevel_focus =
|
||||
gtk_mozarea_get_toplevel_focus(GTK_MOZAREA(top_mozarea));
|
||||
|
||||
// we need to grab focus or make sure that we get focus the next
|
||||
// time that the toplevel gets focus.
|
||||
if (top_mozarea && !GTK_WIDGET_HAS_FOCUS(top_mozarea)) {
|
||||
// If the toplevel window doesn't have an nsWindow data pointer
|
||||
// then we are embedded.
|
||||
gpointer data = gtk_object_get_data(GTK_OBJECT(toplevel), "nsWindow");
|
||||
// We're embedded so always set focus unconditionally.
|
||||
if (!data) {
|
||||
data = gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow");
|
||||
nsWindow *mozAreaWindow = NS_STATIC_CAST(nsWindow *, data);
|
||||
mozAreaWindow->mBlockMozAreaFocusIn = PR_TRUE;
|
||||
gtk_widget_grab_focus(top_mozarea);
|
||||
mozAreaWindow->mBlockMozAreaFocusIn = PR_FALSE;
|
||||
}
|
||||
// We're not embedded. Just return.
|
||||
else {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
gpointer data = gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow");
|
||||
nsWindow *mozAreaWindow = NS_STATIC_CAST(nsWindow *, data);
|
||||
mozAreaWindow->mBlockMozAreaFocusIn = PR_TRUE;
|
||||
gtk_widget_grab_focus(top_mozarea);
|
||||
mozAreaWindow->mBlockMozAreaFocusIn = PR_FALSE;
|
||||
|
||||
// !!hack alert!! This works around bugs in version of gtk older
|
||||
// than 1.2.9, which is what most people use. If the toplevel
|
||||
// window doesn't have focus then we have to unset the focus flag
|
||||
// on this widget since it was probably just set incorrectly.
|
||||
if (!toplevel_focus)
|
||||
GTK_WIDGET_UNSET_FLAGS(top_mozarea, GTK_HAS_FOCUS);
|
||||
|
||||
// always dispatch a set focus event
|
||||
DispatchSetFocusEvent();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mHasFocus)
|
||||
|
@ -1285,11 +1287,15 @@ void nsWindow::HandleMozAreaFocusIn(void)
|
|||
// want to generate extra focus in events so just return.
|
||||
if (mBlockMozAreaFocusIn)
|
||||
return;
|
||||
|
||||
// otherwise, dispatch our focus events
|
||||
#ifdef DEBUG_FOCUS
|
||||
printf("nsWindow::HandleMozAreaFocusIn %p\n", NS_STATIC_CAST(void *, this));
|
||||
#endif /* DEBUG_FOCUS */
|
||||
gJustGotActivate = PR_TRUE;
|
||||
// we only set the gJustGotActivate signal if we're the toplevel
|
||||
// window. embedding handles activate semantics for us.
|
||||
if (mIsToplevel)
|
||||
gJustGotActivate = PR_TRUE;
|
||||
DispatchSetFocusEvent();
|
||||
}
|
||||
|
||||
|
@ -1334,7 +1340,10 @@ void nsWindow::HandleMozAreaFocusOut(void)
|
|||
nsCOMPtr<nsIWidget> focusWidgetGuard(focusWidget);
|
||||
|
||||
focusWidget->DispatchLostFocusEvent();
|
||||
focusWidget->DispatchDeactivateEvent();
|
||||
// we only send activate/deactivate events for toplevel windows.
|
||||
// activation and deactivation is handled by embedders.
|
||||
if (mIsToplevel)
|
||||
focusWidget->DispatchDeactivateEvent();
|
||||
focusWidget->LoseFocus();
|
||||
}
|
||||
}
|
||||
|
@ -2715,30 +2724,30 @@ gint handle_mozarea_focus_in(GtkWidget * aWidget,
|
|||
gpointer aData)
|
||||
{
|
||||
if (!aWidget)
|
||||
return PR_TRUE;
|
||||
return FALSE;
|
||||
|
||||
if (!aGdkFocusEvent)
|
||||
return PR_TRUE;
|
||||
return FALSE;
|
||||
|
||||
nsWindow *widget = (nsWindow *)aData;
|
||||
|
||||
if (!widget)
|
||||
return PR_TRUE;
|
||||
return FALSE;
|
||||
|
||||
#ifdef DEBUG_FOCUS
|
||||
printf("handle_mozarea_focus_in\n");
|
||||
#endif
|
||||
|
||||
// make sure that we set our focus flag
|
||||
GTK_WIDGET_SET_FLAGS(aWidget, GTK_HAS_FOCUS);
|
||||
|
||||
#ifdef DEBUG_FOCUS
|
||||
printf("aWidget is %p\n", NS_STATIC_CAST(void *, aWidget));
|
||||
#endif
|
||||
|
||||
// set the flag since got a focus in event
|
||||
GTK_WIDGET_SET_FLAGS(aWidget, GTK_HAS_FOCUS);
|
||||
|
||||
widget->HandleMozAreaFocusIn();
|
||||
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gint handle_mozarea_focus_out(GtkWidget * aWidget,
|
||||
|
@ -2750,17 +2759,17 @@ gint handle_mozarea_focus_out(GtkWidget * aWidget,
|
|||
#endif
|
||||
|
||||
if (!aWidget) {
|
||||
return PR_TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!aGdkFocusEvent) {
|
||||
return PR_TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nsWindow *widget = (nsWindow *) aData;
|
||||
|
||||
if (!widget) {
|
||||
return PR_TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// make sure that we unset our focus flag
|
||||
|
@ -2768,7 +2777,7 @@ gint handle_mozarea_focus_out(GtkWidget * aWidget,
|
|||
|
||||
widget->HandleMozAreaFocusOut();
|
||||
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,16 +16,37 @@
|
|||
* Owen Taylor and Christopher Blizzard. All Rights Reserved. */
|
||||
|
||||
#include "gtkmozarea.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
static void gtk_mozarea_class_init (GtkMozAreaClass *klass);
|
||||
static void gtk_mozarea_init (GtkMozArea *mozarea);
|
||||
static void gtk_mozarea_realize (GtkWidget *widget);
|
||||
static void gtk_mozarea_unrealize (GtkWidget *widget);
|
||||
static void gtk_mozarea_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
|
||||
static void gtk_mozarea_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
|
||||
static void
|
||||
attach_toplevel_listener(GtkMozArea *mozarea);
|
||||
|
||||
static Window
|
||||
get_real_toplevel(Window aWindow);
|
||||
|
||||
static GdkFilterReturn
|
||||
toplevel_window_filter(GdkXEvent *aGdkXEvent,
|
||||
GdkEvent *aEvent,
|
||||
gpointer data);
|
||||
|
||||
GtkWidgetClass *parent_class = NULL;
|
||||
|
||||
enum {
|
||||
TOPLEVEL_FOCUS_IN,
|
||||
TOPLEVEL_FOCUS_OUT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint mozarea_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
GtkType
|
||||
gtk_mozarea_get_type (void)
|
||||
{
|
||||
|
@ -55,8 +76,10 @@ static void
|
|||
gtk_mozarea_class_init (GtkMozAreaClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class;
|
||||
GtkObjectClass *object_class;
|
||||
|
||||
widget_class = GTK_WIDGET_CLASS (klass);
|
||||
object_class = GTK_OBJECT_CLASS (klass);
|
||||
|
||||
widget_class->realize = gtk_mozarea_realize;
|
||||
widget_class->unrealize = gtk_mozarea_unrealize;
|
||||
|
@ -64,12 +87,31 @@ gtk_mozarea_class_init (GtkMozAreaClass *klass)
|
|||
|
||||
parent_class = gtk_type_class(gtk_widget_get_type());
|
||||
|
||||
/* set up our signals */
|
||||
|
||||
mozarea_signals[TOPLEVEL_FOCUS_IN] =
|
||||
gtk_signal_new("toplevel_focus_in",
|
||||
GTK_RUN_FIRST,
|
||||
object_class->type,
|
||||
GTK_SIGNAL_OFFSET(GtkMozAreaClass, toplevel_focus_in),
|
||||
gtk_marshal_NONE__NONE,
|
||||
GTK_TYPE_NONE, 0);
|
||||
mozarea_signals[TOPLEVEL_FOCUS_OUT] =
|
||||
gtk_signal_new("toplevel_focus_out",
|
||||
GTK_RUN_FIRST,
|
||||
object_class->type,
|
||||
GTK_SIGNAL_OFFSET(GtkMozAreaClass, toplevel_focus_out),
|
||||
gtk_marshal_NONE__NONE,
|
||||
GTK_TYPE_NONE, 0);
|
||||
gtk_object_class_add_signals(object_class, mozarea_signals, LAST_SIGNAL);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_mozarea_init (GtkMozArea *mozarea)
|
||||
{
|
||||
mozarea->superwin = NULL;
|
||||
mozarea->toplevel_focus = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -84,8 +126,10 @@ gtk_mozarea_realize (GtkWidget *widget)
|
|||
mozarea = GTK_MOZAREA (widget);
|
||||
|
||||
mozarea->superwin = gdk_superwin_new (gtk_widget_get_parent_window (widget),
|
||||
widget->allocation.x, widget->allocation.y,
|
||||
widget->allocation.width, widget->allocation.height);
|
||||
widget->allocation.x,
|
||||
widget->allocation.y,
|
||||
widget->allocation.width,
|
||||
widget->allocation.height);
|
||||
gdk_window_set_user_data (mozarea->superwin->shell_window, mozarea);
|
||||
widget->window = mozarea->superwin->shell_window;
|
||||
widget->style = gtk_style_attach (widget->style, widget->window);
|
||||
|
@ -93,6 +137,9 @@ gtk_mozarea_realize (GtkWidget *widget)
|
|||
if we don't then it will be destroyed by both the superwin
|
||||
destroy method and the widget class destructor */
|
||||
gdk_window_ref(widget->window);
|
||||
|
||||
/* attach the toplevel X listener */
|
||||
attach_toplevel_listener(mozarea);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -138,3 +185,122 @@ gtk_mozarea_new (GdkWindow *parent_window)
|
|||
return GTK_WIDGET (gtk_type_new (GTK_TYPE_MOZAREA));
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_mozarea_get_toplevel_focus(GtkMozArea *area)
|
||||
{
|
||||
g_return_val_if_fail(GTK_IS_MOZAREA(area), FALSE);
|
||||
|
||||
return area->toplevel_focus;
|
||||
}
|
||||
|
||||
/* this function will attach a listener to this widget's real toplevel
|
||||
window */
|
||||
static void
|
||||
attach_toplevel_listener(GtkMozArea *mozarea)
|
||||
{
|
||||
/* get the native window for this widget */
|
||||
GtkWidget *widget = GTK_WIDGET(mozarea);
|
||||
Window window = GDK_WINDOW_XWINDOW(widget->window);
|
||||
|
||||
Window toplevel = get_real_toplevel(window);
|
||||
|
||||
/* check to see if this is an already registered window with the
|
||||
type system. */
|
||||
GdkWindow *gdk_window = gdk_window_lookup(toplevel);
|
||||
|
||||
/* This isn't our window? It is now, fool! */
|
||||
if (!gdk_window) {
|
||||
/* import it into the type system */
|
||||
gdk_window = gdk_window_foreign_new(toplevel);
|
||||
/* make sure that we are listening for the right events on it. */
|
||||
gdk_window_set_events(gdk_window, GDK_FOCUS_CHANGE_MASK);
|
||||
}
|
||||
|
||||
/* attach our passive filter. when the window is destroyed it will
|
||||
automatically be removed. */
|
||||
|
||||
gdk_window_add_filter(gdk_window, toplevel_window_filter, mozarea);
|
||||
}
|
||||
|
||||
/* this function will try to find the real toplevel for a gdk window. */
|
||||
static Window
|
||||
get_real_toplevel(Window aWindow)
|
||||
{
|
||||
Window current = aWindow;
|
||||
Atom atom;
|
||||
|
||||
/* get the atom for the WM_STATE variable that you get on WM
|
||||
managed windows. */
|
||||
|
||||
atom = XInternAtom(GDK_DISPLAY(), "WM_STATE", FALSE);
|
||||
|
||||
while (current) {
|
||||
Atom type = None;
|
||||
int format;
|
||||
unsigned long nitems, after;
|
||||
unsigned char *data;
|
||||
|
||||
Window root_return;
|
||||
Window parent_return;
|
||||
Window *children_return = NULL;
|
||||
unsigned int nchildren_return;
|
||||
|
||||
/* check for the atom on this window */
|
||||
XGetWindowProperty(GDK_DISPLAY(), current, atom,
|
||||
0, 0, /* offsets */
|
||||
False, /* don't delete */
|
||||
AnyPropertyType,
|
||||
&type, &format, &nitems, &after, &data);
|
||||
|
||||
/* did we get something? */
|
||||
if (type != None) {
|
||||
XFree(data);
|
||||
data = NULL;
|
||||
/* ok, this is the toplevel window since it has the property set
|
||||
on it. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* what is the parent? */
|
||||
XQueryTree(GDK_DISPLAY(), current, &root_return,
|
||||
&parent_return, &children_return,
|
||||
&nchildren_return);
|
||||
|
||||
if (children_return)
|
||||
XFree(children_return);
|
||||
|
||||
/* If the parent window of this window is the root window then
|
||||
there is no window manager running so the current window is the
|
||||
toplevel window. */
|
||||
if (parent_return == root_return)
|
||||
break;
|
||||
|
||||
current = parent_return;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
static GdkFilterReturn
|
||||
toplevel_window_filter(GdkXEvent *aGdkXEvent,
|
||||
GdkEvent *aEvent,
|
||||
gpointer data)
|
||||
{
|
||||
XEvent *xevent = (XEvent *)aGdkXEvent;
|
||||
GtkMozArea *mozarea = (GtkMozArea *)data;
|
||||
|
||||
switch (xevent->xany.type) {
|
||||
case FocusIn:
|
||||
mozarea->toplevel_focus = TRUE;
|
||||
gtk_signal_emit(GTK_OBJECT(mozarea), mozarea_signals[TOPLEVEL_FOCUS_IN]);
|
||||
break;
|
||||
case FocusOut:
|
||||
mozarea->toplevel_focus = FALSE;
|
||||
gtk_signal_emit(GTK_OBJECT(mozarea), mozarea_signals[TOPLEVEL_FOCUS_OUT]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return GDK_FILTER_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -38,15 +38,21 @@ struct _GtkMozArea
|
|||
{
|
||||
GtkWidget widget;
|
||||
GdkSuperWin *superwin;
|
||||
gboolean toplevel_focus;
|
||||
};
|
||||
|
||||
struct _GtkMozAreaClass
|
||||
{
|
||||
GtkWindowClass window_class;
|
||||
|
||||
/* signals */
|
||||
void (* toplevel_focus_in ) (GtkMozArea *area);
|
||||
void (* toplevel_focus_out) (GtkMozArea *area);
|
||||
};
|
||||
|
||||
GtkType gtk_mozarea_get_type (void);
|
||||
GtkWidget *gtk_mozarea_new ();
|
||||
gboolean gtk_mozarea_get_toplevel_focus(GtkMozArea *area);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче