2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
|
|
*/
|
|
|
|
/* ***** 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.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Christopher Blizzard
|
|
|
|
* <blizzard@mozilla.org>. Portions created by the Initial Developer
|
|
|
|
* are Copyright (C) 2001 the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Mats Palmgren <mats.palmgren@bredband.net>
|
|
|
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
|
|
|
*
|
|
|
|
* 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 ***** */
|
|
|
|
|
2008-09-10 09:12:58 -07:00
|
|
|
#ifdef MOZ_PLATFORM_HILDON
|
|
|
|
#define MAEMO_CHANGES
|
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "prlink.h"
|
|
|
|
|
|
|
|
#include "nsWindow.h"
|
|
|
|
#include "nsGTKToolkit.h"
|
|
|
|
#include "nsIDeviceContext.h"
|
|
|
|
#include "nsIRenderingContext.h"
|
|
|
|
#include "nsIRegion.h"
|
|
|
|
#include "nsIRollupListener.h"
|
|
|
|
#include "nsIMenuRollup.h"
|
|
|
|
#include "nsIDOMNode.h"
|
|
|
|
|
|
|
|
#include "nsWidgetsCID.h"
|
2009-04-20 17:54:46 -07:00
|
|
|
#include "nsDragService.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDragSessionGTK.h"
|
|
|
|
|
|
|
|
#include "nsGtkKeyUtils.h"
|
|
|
|
#include "nsGtkCursors.h"
|
|
|
|
|
2009-01-02 23:37:52 -08:00
|
|
|
#include <gtk/gtk.h>
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
#include <gdk/gdkx.h>
|
2008-08-06 16:24:13 -07:00
|
|
|
#include <X11/XF86keysym.h>
|
2008-08-06 13:48:55 -07:00
|
|
|
#include "gtk2xtbin.h"
|
|
|
|
#endif /* MOZ_X11 */
|
|
|
|
#include <gdk/gdkkeysyms.h>
|
2009-07-21 17:44:55 -07:00
|
|
|
#include <gtk/gtkprivate.h>
|
2008-02-06 13:56:02 -08:00
|
|
|
|
|
|
|
#include "nsWidgetAtoms.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
|
|
|
|
#define SN_API_NOT_YET_FROZEN
|
|
|
|
#include <startup-notification-1.0/libsn/sn.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "nsIPrefService.h"
|
|
|
|
#include "nsIPrefBranch.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsIStringBundle.h"
|
|
|
|
#include "nsGfxCIID.h"
|
2009-09-25 09:52:11 -07:00
|
|
|
#include "nsIObserverService.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-10-06 11:47:46 -07:00
|
|
|
#include "nsIdleService.h"
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef ACCESSIBILITY
|
2008-11-03 19:36:36 -08:00
|
|
|
#include "nsIAccessibilityService.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIAccessibleRole.h"
|
|
|
|
#include "nsIAccessibleEvent.h"
|
|
|
|
#include "prenv.h"
|
|
|
|
#include "stdlib.h"
|
|
|
|
static PRBool sAccessibilityChecked = PR_FALSE;
|
|
|
|
/* static */
|
|
|
|
PRBool nsWindow::sAccessibilityEnabled = PR_FALSE;
|
|
|
|
static const char sSysPrefService [] = "@mozilla.org/system-preference-service;1";
|
|
|
|
static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
|
|
|
|
static const char sAccessibilityKey [] = "config.use_system_prefs.accessibility";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* For SetIcon */
|
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
#include "nsXPIDLString.h"
|
|
|
|
#include "nsIFile.h"
|
|
|
|
#include "nsILocalFile.h"
|
|
|
|
|
|
|
|
/* SetCursor(imgIContainer*) */
|
|
|
|
#include <gdk/gdk.h>
|
2009-09-25 09:52:11 -07:00
|
|
|
#include <wchar.h>
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "imgIContainer.h"
|
|
|
|
#include "nsGfxCIID.h"
|
|
|
|
#include "nsImageToPixbuf.h"
|
|
|
|
#include "nsIInterfaceRequestorUtils.h"
|
|
|
|
#include "nsAutoPtr.h"
|
|
|
|
|
|
|
|
#include "gfxPlatformGtk.h"
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxImageSurface.h"
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
|
|
|
#include "gfxXlibSurface.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MOZ_DFB
|
|
|
|
extern "C" {
|
|
|
|
#ifdef MOZ_DIRECT_DEBUG
|
|
|
|
#define DIRECT_ENABLE_DEBUG
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <direct/debug.h>
|
|
|
|
|
|
|
|
D_DEBUG_DOMAIN( ns_Window, "nsWindow", "nsWindow" );
|
|
|
|
}
|
|
|
|
#include "gfxDirectFBSurface.h"
|
|
|
|
#define GDK_WINDOW_XWINDOW(_win) _win
|
|
|
|
#endif
|
|
|
|
|
2009-02-15 17:10:24 -08:00
|
|
|
// Don't put more than this many rects in the dirty region, just fluff
|
|
|
|
// out to the bounding-box if there are more
|
|
|
|
#define MAX_RECTS_IN_REGION 100
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* For PrepareNativeWidget */
|
|
|
|
static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
|
|
|
|
|
|
|
|
/* utility functions */
|
|
|
|
static PRBool check_for_rollup(GdkWindow *aWindow,
|
|
|
|
gdouble aMouseX, gdouble aMouseY,
|
|
|
|
PRBool aIsWheel);
|
|
|
|
static PRBool is_mouse_in_window(GdkWindow* aWindow,
|
|
|
|
gdouble aMouseX, gdouble aMouseY);
|
|
|
|
static nsWindow *get_window_for_gtk_widget(GtkWidget *widget);
|
|
|
|
static nsWindow *get_window_for_gdk_window(GdkWindow *window);
|
|
|
|
static nsWindow *get_owning_window_for_gdk_window(GdkWindow *window);
|
|
|
|
static GtkWidget *get_gtk_widget_for_gdk_window(GdkWindow *window);
|
|
|
|
static GdkCursor *get_gtk_cursor(nsCursor aCursor);
|
|
|
|
|
|
|
|
static GdkWindow *get_inner_gdk_window (GdkWindow *aWindow,
|
|
|
|
gint x, gint y,
|
|
|
|
gint *retx, gint *rety);
|
|
|
|
|
|
|
|
static inline PRBool is_context_menu_key(const nsKeyEvent& inKeyEvent);
|
2008-02-20 02:04:56 -08:00
|
|
|
static void key_event_to_context_menu_event(nsMouseEvent &aEvent,
|
|
|
|
GdkEventKey *aGdkEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
static int is_parent_ungrab_enter(GdkEventCrossing *aEvent);
|
|
|
|
static int is_parent_grab_leave(GdkEventCrossing *aEvent);
|
|
|
|
|
|
|
|
/* callbacks from widgets */
|
|
|
|
static gboolean expose_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventExpose *event);
|
|
|
|
static gboolean configure_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventConfigure *event);
|
2009-05-14 19:14:45 -07:00
|
|
|
static void container_unrealize_cb (GtkWidget *widget);
|
2007-03-22 10:30:00 -07:00
|
|
|
static void size_allocate_cb (GtkWidget *widget,
|
|
|
|
GtkAllocation *allocation);
|
|
|
|
static gboolean delete_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventAny *event);
|
|
|
|
static gboolean enter_notify_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventCrossing *event);
|
|
|
|
static gboolean leave_notify_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventCrossing *event);
|
|
|
|
static gboolean motion_notify_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventMotion *event);
|
|
|
|
static gboolean button_press_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventButton *event);
|
|
|
|
static gboolean button_release_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventButton *event);
|
|
|
|
static gboolean focus_in_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventFocus *event);
|
|
|
|
static gboolean focus_out_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventFocus *event);
|
|
|
|
static gboolean key_press_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventKey *event);
|
|
|
|
static gboolean key_release_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventKey *event);
|
|
|
|
static gboolean scroll_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventScroll *event);
|
|
|
|
static gboolean visibility_notify_event_cb(GtkWidget *widget,
|
|
|
|
GdkEventVisibility *event);
|
2009-11-01 18:03:12 -08:00
|
|
|
static void hierarchy_changed_cb (GtkWidget *widget,
|
|
|
|
GtkWidget *previous_toplevel);
|
2007-03-22 10:30:00 -07:00
|
|
|
static gboolean window_state_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventWindowState *event);
|
|
|
|
static void theme_changed_cb (GtkSettings *settings,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
nsWindow *data);
|
2007-12-13 23:00:44 -08:00
|
|
|
static nsWindow* GetFirstNSWindowForGDKWindow (GdkWindow *aGdkWindow);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif /* __cplusplus */
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
static GdkFilterReturn plugin_window_filter_func (GdkXEvent *gdk_xevent,
|
|
|
|
GdkEvent *event,
|
|
|
|
gpointer data);
|
|
|
|
static GdkFilterReturn plugin_client_message_filter (GdkXEvent *xevent,
|
|
|
|
GdkEvent *event,
|
|
|
|
gpointer data);
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
static gboolean drag_motion_event_cb (GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData);
|
|
|
|
static void drag_leave_event_cb (GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData);
|
|
|
|
static gboolean drag_drop_event_cb (GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
guint aTime,
|
|
|
|
gpointer *aData);
|
|
|
|
static void drag_data_received_event_cb(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
GtkSelectionData *aSelectionData,
|
|
|
|
guint aInfo,
|
|
|
|
guint32 aTime,
|
|
|
|
gpointer aData);
|
|
|
|
|
2007-06-16 12:19:46 -07:00
|
|
|
static GdkModifierType gdk_keyboard_get_modifiers();
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-06-16 12:19:46 -07:00
|
|
|
static PRBool gdk_keyboard_get_modmap_masks(Display* aDisplay,
|
|
|
|
PRUint32* aCapsLockMask,
|
|
|
|
PRUint32* aNumLockMask,
|
|
|
|
PRUint32* aScrollLockMask);
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-06-16 12:19:46 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* initialization static functions */
|
|
|
|
static nsresult initialize_prefs (void);
|
|
|
|
|
2009-09-17 10:13:45 -07:00
|
|
|
PRUint32 gLastInputEventTime = 0;
|
|
|
|
|
2009-10-06 11:47:46 -07:00
|
|
|
static void UpdateLastInputEventTime() {
|
|
|
|
gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
|
|
|
|
nsCOMPtr<nsIIdleService> idleService = do_GetService("@mozilla.org/widget/idleservice;1");
|
|
|
|
nsIdleService* is = static_cast<nsIdleService*>(idleService.get());
|
|
|
|
if (is)
|
|
|
|
is->IdleTimeWasModified();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// this is the last window that had a drag event happen on it.
|
|
|
|
nsWindow *nsWindow::mLastDragMotionWindow = NULL;
|
|
|
|
PRBool nsWindow::sIsDraggingOutOf = PR_FALSE;
|
|
|
|
|
|
|
|
// This is the time of the last button press event. The drag service
|
|
|
|
// uses it as the time to start drags.
|
|
|
|
guint32 nsWindow::mLastButtonPressTime = 0;
|
|
|
|
// Time of the last button release event. We use it to detect when the
|
|
|
|
// drag ended before we could properly setup drag and drop.
|
|
|
|
guint32 nsWindow::mLastButtonReleaseTime = 0;
|
|
|
|
|
|
|
|
static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
|
|
|
|
|
|
|
|
// the current focus window
|
|
|
|
static nsWindow *gFocusWindow = NULL;
|
|
|
|
static PRBool gGlobalsInitialized = PR_FALSE;
|
|
|
|
static PRBool gRaiseWindows = PR_TRUE;
|
|
|
|
static nsWindow *gPluginFocusWindow = NULL;
|
|
|
|
|
2008-01-14 01:40:45 -08:00
|
|
|
static nsCOMPtr<nsIRollupListener> gRollupListener;
|
|
|
|
static nsWeakPtr gRollupWindow;
|
|
|
|
static PRBool gConsumeRollupEvent;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#define NS_WINDOW_TITLE_MAX_LENGTH 4095
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
|
|
|
|
static nsWindow *gIMEFocusWindow = NULL;
|
|
|
|
static GdkEventKey *gKeyEvent = NULL;
|
|
|
|
static PRBool gKeyEventCommitted = PR_FALSE;
|
|
|
|
static PRBool gKeyEventChanged = PR_FALSE;
|
|
|
|
static PRBool gIMESuppressCommit = PR_FALSE;
|
2008-09-15 08:58:57 -07:00
|
|
|
#ifdef MOZ_PLATFORM_HILDON
|
|
|
|
static PRBool gIMEVirtualKeyboardOpened = PR_FALSE;
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
static void IM_commit_cb (GtkIMContext *aContext,
|
|
|
|
const gchar *aString,
|
|
|
|
nsWindow *aWindow);
|
|
|
|
static void IM_commit_cb_internal (const gchar *aString,
|
|
|
|
nsWindow *aWindow);
|
|
|
|
static void IM_preedit_changed_cb (GtkIMContext *aContext,
|
|
|
|
nsWindow *aWindow);
|
|
|
|
static void IM_set_text_range (const PRInt32 aLen,
|
|
|
|
const gchar *aPreeditString,
|
|
|
|
const gint aCursorPos,
|
|
|
|
const PangoAttrList *aFeedback,
|
|
|
|
PRUint32 *aTextRangeListLengthResult,
|
|
|
|
nsTextRangeArray *aTextRangeListResult);
|
|
|
|
|
|
|
|
static GtkIMContext *IM_get_input_context(nsWindow *window);
|
|
|
|
|
|
|
|
// If after selecting profile window, the startup fail, please refer to
|
|
|
|
// http://bugzilla.gnome.org/show_bug.cgi?id=88940
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// needed for imgIContainer cursors
|
|
|
|
// GdkDisplay* was added in 2.2
|
|
|
|
typedef struct _GdkDisplay GdkDisplay;
|
|
|
|
typedef GdkDisplay* (*_gdk_display_get_default_fn)(void);
|
|
|
|
|
|
|
|
typedef GdkCursor* (*_gdk_cursor_new_from_pixbuf_fn)(GdkDisplay *display,
|
|
|
|
GdkPixbuf *pixbuf,
|
|
|
|
gint x,
|
|
|
|
gint y);
|
|
|
|
static _gdk_display_get_default_fn _gdk_display_get_default;
|
|
|
|
static _gdk_cursor_new_from_pixbuf_fn _gdk_cursor_new_from_pixbuf;
|
|
|
|
static PRBool sPixbufCursorChecked;
|
|
|
|
|
|
|
|
// needed for GetAttention calls
|
|
|
|
// gdk_window_set_urgency_hint was added in 2.8
|
|
|
|
typedef void (*_gdk_window_set_urgency_hint_fn)(GdkWindow *window,
|
|
|
|
gboolean urgency);
|
|
|
|
|
|
|
|
#define kWindowPositionSlop 20
|
|
|
|
|
|
|
|
// cursor cache
|
|
|
|
static GdkCursor *gCursorCache[eCursorCount];
|
|
|
|
|
2008-09-17 14:15:52 -07:00
|
|
|
// Global update pixmap
|
|
|
|
static PRBool gUseBufferPixmap = PR_FALSE;
|
|
|
|
static GdkPixmap *gBufferPixmap = nsnull;
|
|
|
|
static gfxIntSize gBufferPixmapSize(0,0);
|
|
|
|
static gfxIntSize gBufferPixmapMaxSize(0,0);
|
|
|
|
static int gBufferPixmapUsageCount = 0;
|
|
|
|
|
|
|
|
// imported in nsWidgetFactory.cpp
|
|
|
|
PRBool gDisableNativeTheme = PR_FALSE;
|
|
|
|
|
|
|
|
// If this is 1, then a 24bpp buffer surface is always
|
|
|
|
// created for exposes, even if the display has a different depth
|
|
|
|
static PRBool gForce24bpp = PR_FALSE;
|
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
static GtkWidget *gInvisibleContainer = NULL;
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
// Some gobject functions expect functions for gpointer arguments.
|
|
|
|
// gpointer is void* but C++ doesn't like casting functions to void*.
|
|
|
|
template<class T> gpointer
|
|
|
|
FuncToGpointer(T aFunction)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<gpointer>
|
|
|
|
(reinterpret_cast<uintptr_t>
|
|
|
|
// This cast just provides a warning if T is not a function.
|
|
|
|
(reinterpret_cast<void (*)()>(aFunction)));
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsWindow::nsWindow()
|
|
|
|
{
|
2008-10-18 18:13:27 -07:00
|
|
|
mIsTopLevel = PR_FALSE;
|
|
|
|
mIsDestroyed = PR_FALSE;
|
|
|
|
mNeedsResize = PR_FALSE;
|
|
|
|
mNeedsMove = PR_FALSE;
|
|
|
|
mListenForResizes = PR_FALSE;
|
|
|
|
mIsShown = PR_FALSE;
|
|
|
|
mNeedsShow = PR_FALSE;
|
|
|
|
mEnabled = PR_TRUE;
|
|
|
|
mCreated = PR_FALSE;
|
|
|
|
mPlaced = PR_FALSE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mContainer = nsnull;
|
2009-07-26 18:39:36 -07:00
|
|
|
mGdkWindow = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
mShell = nsnull;
|
|
|
|
mWindowGroup = nsnull;
|
|
|
|
mContainerGotFocus = PR_FALSE;
|
|
|
|
mContainerLostFocus = PR_FALSE;
|
|
|
|
mContainerBlockFocus = PR_FALSE;
|
2009-11-01 18:03:12 -08:00
|
|
|
mHasMappedToplevel = PR_FALSE;
|
|
|
|
mIsFullyObscured = PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
mRetryPointerGrab = PR_FALSE;
|
|
|
|
mRetryKeyboardGrab = PR_FALSE;
|
|
|
|
mTransientParent = nsnull;
|
|
|
|
mWindowType = eWindowType_child;
|
|
|
|
mSizeState = nsSizeMode_Normal;
|
2009-08-26 17:09:47 -07:00
|
|
|
mLastSizeMode = nsSizeMode_Normal;
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
mOldFocusWindow = 0;
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
mPluginType = PluginType_NONE;
|
|
|
|
|
|
|
|
if (!gGlobalsInitialized) {
|
|
|
|
gGlobalsInitialized = PR_TRUE;
|
|
|
|
|
|
|
|
// It's OK if either of these fail, but it may not be one day.
|
|
|
|
initialize_prefs();
|
|
|
|
}
|
|
|
|
|
2007-04-27 09:34:44 -07:00
|
|
|
memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags));
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mLastDragMotionWindow == this)
|
|
|
|
mLastDragMotionWindow = NULL;
|
|
|
|
mDragMotionWidget = 0;
|
|
|
|
mDragMotionContext = 0;
|
|
|
|
mDragMotionX = 0;
|
|
|
|
mDragMotionY = 0;
|
|
|
|
mDragMotionTime = 0;
|
|
|
|
mDragMotionTimerID = 0;
|
2008-12-11 15:55:15 -08:00
|
|
|
mLastMotionPressure = 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
mIMEData = nsnull;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
mRootAccessible = nsnull;
|
|
|
|
#endif
|
|
|
|
|
2007-12-19 11:40:18 -08:00
|
|
|
mIsTransparent = PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
mTransparencyBitmap = nsnull;
|
|
|
|
|
|
|
|
mTransparencyBitmapWidth = 0;
|
|
|
|
mTransparencyBitmapHeight = 0;
|
2008-08-06 13:48:55 -07:00
|
|
|
|
|
|
|
#ifdef MOZ_DFB
|
|
|
|
mDFBCursorX = 0;
|
|
|
|
mDFBCursorY = 0;
|
|
|
|
|
|
|
|
mDFBCursorCount = 0;
|
|
|
|
|
|
|
|
mDFB = NULL;
|
|
|
|
mDFBLayer = NULL;
|
|
|
|
#endif
|
2008-09-17 14:15:52 -07:00
|
|
|
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2008-09-17 14:15:52 -07:00
|
|
|
if (gUseBufferPixmap) {
|
|
|
|
if (gBufferPixmapMaxSize.width == 0) {
|
|
|
|
gBufferPixmapMaxSize.width = gdk_screen_width();
|
|
|
|
gBufferPixmapMaxSize.height = gdk_screen_height();
|
|
|
|
}
|
|
|
|
|
|
|
|
gBufferPixmapUsageCount++;
|
|
|
|
}
|
|
|
|
|
2009-09-17 10:13:45 -07:00
|
|
|
// Set gLastInputEventTime to some valid number
|
|
|
|
gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow::~nsWindow()
|
|
|
|
{
|
|
|
|
LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
|
|
|
|
if (mLastDragMotionWindow == this) {
|
|
|
|
mLastDragMotionWindow = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] mTransparencyBitmap;
|
|
|
|
mTransparencyBitmap = nsnull;
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_DFB
|
|
|
|
if (mDFBLayer)
|
|
|
|
mDFBLayer->Release( mDFBLayer );
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
if (mDFB)
|
|
|
|
mDFB->Release( mDFB );
|
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
Destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
nsWindow::ReleaseGlobals()
|
|
|
|
{
|
2007-04-25 23:56:36 -07:00
|
|
|
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gCursorCache); ++i) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (gCursorCache[i]) {
|
|
|
|
gdk_cursor_unref(gCursorCache[i]);
|
|
|
|
gCursorCache[i] = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-18 18:13:27 -07:00
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(nsWindow, nsBaseWidget,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsISupportsWeakReference)
|
|
|
|
|
2008-10-18 18:13:27 -07:00
|
|
|
void
|
|
|
|
nsWindow::CommonCreate(nsIWidget *aParent, PRBool aListenForResizes)
|
|
|
|
{
|
|
|
|
mParent = aParent;
|
|
|
|
mListenForResizes = aListenForResizes;
|
|
|
|
mCreated = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::InitKeyEvent(nsKeyEvent &aEvent, GdkEventKey *aGdkEvent)
|
|
|
|
{
|
|
|
|
aEvent.keyCode = GdkKeyCodeToDOMKeyCode(aGdkEvent->keyval);
|
|
|
|
aEvent.isShift = (aGdkEvent->state & GDK_SHIFT_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
aEvent.isControl = (aGdkEvent->state & GDK_CONTROL_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
aEvent.isAlt = (aGdkEvent->state & GDK_MOD1_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
aEvent.isMeta = (aGdkEvent->state & GDK_MOD4_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
// The transformations above and in gdk for the keyval are not invertible
|
|
|
|
// so link to the GdkEvent (which will vanish soon after return from the
|
|
|
|
// event callback) to give plugins access to hardware_keycode and state.
|
|
|
|
// (An XEvent would be nice but the GdkEvent is good enough.)
|
2009-11-10 13:55:38 -08:00
|
|
|
aEvent.pluginEvent = (void *)aGdkEvent;
|
2008-10-18 18:13:27 -07:00
|
|
|
|
|
|
|
aEvent.time = aGdkEvent->time;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-14 19:27:09 -08:00
|
|
|
nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
|
2008-10-18 18:13:27 -07:00
|
|
|
{
|
|
|
|
nsSizeEvent event(PR_TRUE, NS_SIZE, this);
|
|
|
|
|
|
|
|
event.windowSize = &aRect;
|
|
|
|
event.refPoint.x = aRect.x;
|
|
|
|
event.refPoint.y = aRect.y;
|
|
|
|
event.mWinWidth = aRect.width;
|
|
|
|
event.mWinHeight = aRect.height;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
2009-02-27 17:47:40 -08:00
|
|
|
DispatchEvent(&event, status);
|
2008-10-18 18:13:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::DispatchActivateEvent(void)
|
|
|
|
{
|
2009-09-15 19:01:09 -07:00
|
|
|
NS_ASSERTION(mContainer || mIsDestroyed,
|
|
|
|
"DispatchActivateEvent only intended for container windows");
|
|
|
|
|
2008-10-18 18:13:27 -07:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
DispatchActivateEventAccessible();
|
|
|
|
#endif //ACCESSIBILITY
|
|
|
|
nsGUIEvent event(PR_TRUE, NS_ACTIVATE, this);
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::DispatchDeactivateEvent(void)
|
|
|
|
{
|
|
|
|
nsGUIEvent event(PR_TRUE, NS_DEACTIVATE, this);
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
DispatchDeactivateEventAccessible();
|
|
|
|
#endif //ACCESSIBILITY
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2009-03-07 09:08:51 -08:00
|
|
|
nsWindow::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus)
|
2008-10-18 18:13:27 -07:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
debug_DumpEvent(stdout, aEvent->widget, aEvent,
|
|
|
|
nsCAutoString("something"), 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
aStatus = nsEventStatus_eIgnore;
|
|
|
|
|
|
|
|
// send it to the standard callback
|
|
|
|
if (mEventCallback)
|
|
|
|
aStatus = (* mEventCallback)(aEvent);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnDestroy(void)
|
|
|
|
{
|
|
|
|
if (mOnDestroyCalled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mOnDestroyCalled = PR_TRUE;
|
|
|
|
|
|
|
|
// release references to children, device context, toolkit + app shell
|
|
|
|
nsBaseWidget::OnDestroy();
|
|
|
|
|
|
|
|
// let go of our parent
|
|
|
|
mParent = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
|
|
|
|
|
|
|
|
nsGUIEvent event(PR_TRUE, NS_DESTROY, this);
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsWindow::AreBoundsSane(void)
|
|
|
|
{
|
|
|
|
if (mBounds.width > 0 && mBounds.height > 0)
|
|
|
|
return PR_TRUE;
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
static GtkWidget*
|
|
|
|
EnsureInvisibleContainer()
|
|
|
|
{
|
|
|
|
if (!gInvisibleContainer) {
|
|
|
|
// GtkWidgets need to be anchored to a GtkWindow to be realized (to
|
|
|
|
// have a window). Using GTK_WINDOW_POPUP rather than
|
|
|
|
// GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
|
|
|
|
// initialization and window manager interaction.
|
|
|
|
GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
|
|
|
|
gInvisibleContainer = moz_container_new();
|
|
|
|
gtk_container_add(GTK_CONTAINER(window), gInvisibleContainer);
|
|
|
|
gtk_widget_realize(gInvisibleContainer);
|
|
|
|
|
|
|
|
}
|
|
|
|
return gInvisibleContainer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
CheckDestroyInvisibleContainer()
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(gInvisibleContainer, "oh, no");
|
|
|
|
|
|
|
|
if (!gdk_window_peek_children(gInvisibleContainer->window)) {
|
|
|
|
// No children, so not in use.
|
|
|
|
// Make sure to destroy the GtkWindow also.
|
|
|
|
gtk_widget_destroy(gInvisibleContainer->parent);
|
|
|
|
gInvisibleContainer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change the containing GtkWidget on a sub-hierarchy of GdkWindows belonging
|
|
|
|
// to aOldWidget and rooted at aWindow, and reparent any child GtkWidgets of
|
2009-11-10 13:57:25 -08:00
|
|
|
// the GdkWindow hierarchy to aNewWidget.
|
2009-05-14 19:14:45 -07:00
|
|
|
static void
|
|
|
|
SetWidgetForHierarchy(GdkWindow *aWindow,
|
|
|
|
GtkWidget *aOldWidget,
|
|
|
|
GtkWidget *aNewWidget)
|
|
|
|
{
|
|
|
|
gpointer data;
|
|
|
|
gdk_window_get_user_data(aWindow, &data);
|
|
|
|
|
|
|
|
if (data != aOldWidget) {
|
|
|
|
if (!GTK_IS_WIDGET(data))
|
|
|
|
return;
|
|
|
|
|
|
|
|
GtkWidget* widget = static_cast<GtkWidget*>(data);
|
|
|
|
if (widget->parent != aOldWidget)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// This window belongs to a child widget, which will no longer be a
|
|
|
|
// child of aOldWidget.
|
2009-11-10 13:57:25 -08:00
|
|
|
gtk_widget_reparent(widget, aNewWidget);
|
2009-05-14 19:14:45 -07:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-16 03:20:19 -07:00
|
|
|
GList *children = gdk_window_get_children(aWindow);
|
|
|
|
for(GList *list = children; list; list = list->next) {
|
2009-05-14 19:14:45 -07:00
|
|
|
SetWidgetForHierarchy(GDK_WINDOW(list->data), aOldWidget, aNewWidget);
|
|
|
|
}
|
2009-05-16 03:20:19 -07:00
|
|
|
g_list_free(children);
|
2009-05-14 19:14:45 -07:00
|
|
|
|
|
|
|
gdk_window_set_user_data(aWindow, aNewWidget);
|
|
|
|
}
|
|
|
|
|
2009-11-10 13:57:25 -08:00
|
|
|
// Walk the list of child windows and call destroy on them.
|
|
|
|
void
|
|
|
|
nsWindow::DestroyChildWindows()
|
|
|
|
{
|
|
|
|
if (!mGdkWindow)
|
|
|
|
return;
|
|
|
|
|
2009-11-12 20:20:23 -08:00
|
|
|
while (GList *children = gdk_window_peek_children(mGdkWindow)) {
|
2009-11-10 13:57:25 -08:00
|
|
|
GdkWindow *child = GDK_WINDOW(children->data);
|
|
|
|
nsWindow *kid = get_window_for_gdk_window(child);
|
|
|
|
if (kid) {
|
|
|
|
kid->Destroy();
|
|
|
|
} else {
|
|
|
|
// This child is not an nsWindow.
|
|
|
|
// Destroy the child GtkWidget.
|
|
|
|
gpointer data;
|
|
|
|
gdk_window_get_user_data(child, &data);
|
|
|
|
if (GTK_IS_WIDGET(data)) {
|
|
|
|
gtk_widget_destroy(static_cast<GtkWidget*>(data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::Destroy(void)
|
|
|
|
{
|
|
|
|
if (mIsDestroyed || !mCreated)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
LOG(("nsWindow::Destroy [%p]\n", (void *)this));
|
|
|
|
mIsDestroyed = PR_TRUE;
|
|
|
|
mCreated = PR_FALSE;
|
2008-09-17 14:15:52 -07:00
|
|
|
|
|
|
|
if (gUseBufferPixmap &&
|
|
|
|
gBufferPixmapUsageCount &&
|
|
|
|
--gBufferPixmapUsageCount == 0)
|
|
|
|
{
|
|
|
|
if (gBufferPixmap)
|
|
|
|
g_object_unref(G_OBJECT(gBufferPixmap));
|
|
|
|
|
|
|
|
gBufferPixmap = nsnull;
|
|
|
|
gBufferPixmapSize.width = 0;
|
|
|
|
gBufferPixmapSize.height = 0;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
|
2009-11-01 18:03:12 -08:00
|
|
|
FuncToGpointer(theme_changed_cb),
|
2007-03-22 10:30:00 -07:00
|
|
|
this);
|
|
|
|
|
|
|
|
// ungrab if required
|
|
|
|
nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
|
2007-07-08 00:08:04 -07:00
|
|
|
if (static_cast<nsIWidget *>(this) == rollupWidget.get()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (gRollupListener)
|
2009-06-12 11:23:16 -07:00
|
|
|
gRollupListener->Rollup(nsnull, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
gRollupWindow = nsnull;
|
|
|
|
gRollupListener = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NativeShow(PR_FALSE);
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
IMEDestroyContext();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// make sure that we remove ourself as the focus window
|
|
|
|
if (gFocusWindow == this) {
|
|
|
|
LOGFOCUS(("automatically losing focus...\n"));
|
|
|
|
gFocusWindow = nsnull;
|
|
|
|
}
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
// make sure that we remove ourself as the plugin focus window
|
|
|
|
if (gPluginFocusWindow == this) {
|
|
|
|
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-10-07 22:02:38 -07:00
|
|
|
if (mWindowGroup) {
|
|
|
|
g_object_unref(G_OBJECT(mWindowGroup));
|
|
|
|
mWindowGroup = nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Destroy thebes surface now. Badness can happen if we destroy
|
|
|
|
// the surface after its X Window.
|
|
|
|
mThebesSurface = nsnull;
|
|
|
|
|
|
|
|
if (mDragMotionTimerID) {
|
2009-02-02 09:49:58 -08:00
|
|
|
g_source_remove(mDragMotionTimerID);
|
2007-03-22 10:30:00 -07:00
|
|
|
mDragMotionTimerID = 0;
|
|
|
|
}
|
|
|
|
|
2009-03-07 09:08:51 -08:00
|
|
|
if (mDragLeaveTimer) {
|
|
|
|
mDragLeaveTimer->Cancel();
|
|
|
|
mDragLeaveTimer = nsnull;
|
|
|
|
}
|
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
GtkWidget *owningWidget = GetMozContainerWidget();
|
|
|
|
if (mShell) {
|
|
|
|
gtk_widget_destroy(mShell);
|
|
|
|
mShell = nsnull;
|
|
|
|
mContainer = nsnull;
|
2009-07-26 18:40:46 -07:00
|
|
|
NS_ABORT_IF_FALSE(!mGdkWindow,
|
|
|
|
"mGdkWindow should be NULL when mContainer is destroyed");
|
2009-05-14 19:14:45 -07:00
|
|
|
}
|
|
|
|
else if (mContainer) {
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(mContainer));
|
|
|
|
mContainer = nsnull;
|
2009-07-26 18:40:46 -07:00
|
|
|
NS_ABORT_IF_FALSE(!mGdkWindow,
|
|
|
|
"mGdkWindow should be NULL when mContainer is destroyed");
|
2009-05-14 19:14:45 -07:00
|
|
|
}
|
2009-07-26 18:40:46 -07:00
|
|
|
else if (mGdkWindow) {
|
2009-11-10 13:57:25 -08:00
|
|
|
// Destroy child windows to ensure that their mThebesSurfaces are
|
|
|
|
// released and to remove references from GdkWindows back to their
|
|
|
|
// container widget. (OnContainerUnrealize() does this when the
|
|
|
|
// MozContainer widget is destroyed.)
|
|
|
|
DestroyChildWindows();
|
2009-05-14 19:14:45 -07:00
|
|
|
|
2009-11-10 13:57:25 -08:00
|
|
|
gdk_window_set_user_data(mGdkWindow, NULL);
|
2009-07-26 18:40:46 -07:00
|
|
|
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", NULL);
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_destroy(mGdkWindow);
|
|
|
|
mGdkWindow = nsnull;
|
2008-08-27 19:04:06 -07:00
|
|
|
}
|
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
if (gInvisibleContainer && owningWidget == gInvisibleContainer) {
|
|
|
|
CheckDestroyInvisibleContainer();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
OnDestroy();
|
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
if (mRootAccessible) {
|
|
|
|
mRootAccessible = nsnull;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-18 18:13:27 -07:00
|
|
|
nsIWidget *
|
|
|
|
nsWindow::GetParent(void)
|
|
|
|
{
|
|
|
|
return mParent;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetParent(nsIWidget *aNewParent)
|
|
|
|
{
|
2009-07-26 18:39:36 -07:00
|
|
|
if (mContainer || !mGdkWindow || !mParent) {
|
2009-05-14 19:14:45 -07:00
|
|
|
NS_NOTREACHED("nsWindow::SetParent - reparenting a non-child window");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
// nsBaseWidget::SetZIndex adds child widgets to the parent's list.
|
|
|
|
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
|
|
|
|
mParent->RemoveChild(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
mParent = aNewParent;
|
|
|
|
|
|
|
|
GtkWidget* oldContainer = GetMozContainerWidget();
|
|
|
|
if (!oldContainer) {
|
|
|
|
// The GdkWindows have been destroyed so there is nothing else to
|
|
|
|
// reparent.
|
2009-07-26 18:39:36 -07:00
|
|
|
NS_ABORT_IF_FALSE(GDK_WINDOW_OBJECT(mGdkWindow)->destroyed,
|
2009-05-14 19:14:45 -07:00
|
|
|
"live GdkWindow with no widget");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
NS_ABORT_IF_FALSE(!GDK_WINDOW_OBJECT(mGdkWindow)->destroyed,
|
2009-05-14 19:14:45 -07:00
|
|
|
"destroyed GdkWindow with widget");
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
|
2009-05-14 19:14:45 -07:00
|
|
|
GdkWindow* newParentWindow = NULL;
|
|
|
|
GtkWidget* newContainer = NULL;
|
|
|
|
if (aNewParent) {
|
2009-11-01 18:03:12 -08:00
|
|
|
newParentWindow = newParent->mGdkWindow;
|
2009-05-14 19:14:45 -07:00
|
|
|
if (newParentWindow) {
|
|
|
|
newContainer = get_gtk_widget_for_gdk_window(newParentWindow);
|
2008-08-27 19:04:06 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2009-05-14 19:14:45 -07:00
|
|
|
// aNewParent is NULL, but reparent to a hidden window to avoid
|
|
|
|
// destroying the GdkWindow and its descendants.
|
|
|
|
// An invisible container widget is needed to hold descendant
|
|
|
|
// GtkWidgets.
|
|
|
|
newContainer = EnsureInvisibleContainer();
|
|
|
|
newParentWindow = newContainer->window;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!newContainer) {
|
|
|
|
// The new parent GdkWindow has been destroyed.
|
|
|
|
NS_ABORT_IF_FALSE(!newParentWindow ||
|
|
|
|
GDK_WINDOW_OBJECT(newParentWindow)->destroyed,
|
|
|
|
"live GdkWindow with no widget");
|
|
|
|
Destroy();
|
|
|
|
} else {
|
|
|
|
if (newContainer != oldContainer) {
|
|
|
|
NS_ABORT_IF_FALSE(!GDK_WINDOW_OBJECT(newParentWindow)->destroyed,
|
|
|
|
"destroyed GdkWindow with widget");
|
2009-07-26 18:39:36 -07:00
|
|
|
SetWidgetForHierarchy(mGdkWindow, oldContainer, newContainer);
|
2009-05-14 19:14:45 -07:00
|
|
|
}
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_reparent(mGdkWindow, newParentWindow, 0, 0);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-05-14 19:14:45 -07:00
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
PRBool parentHasMappedToplevel =
|
|
|
|
newParent && newParent->mHasMappedToplevel;
|
|
|
|
if (mHasMappedToplevel != parentHasMappedToplevel) {
|
|
|
|
SetHasMappedToplevel(parentHasMappedToplevel);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetModal(PRBool aModal)
|
|
|
|
{
|
|
|
|
LOG(("nsWindow::SetModal [%p] %d\n", (void *)this, aModal));
|
|
|
|
|
2007-10-09 13:58:24 -07:00
|
|
|
// find the toplevel window and set its modality
|
2007-03-22 10:30:00 -07:00
|
|
|
GtkWidget *grabWidget = nsnull;
|
|
|
|
|
|
|
|
GetToplevelWidget(&grabWidget);
|
|
|
|
|
|
|
|
if (!grabWidget)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-10-09 13:58:24 -07:00
|
|
|
// block focus tracking via gFocusWindow internally in case the window
|
|
|
|
// manager does not block focus to parents of modal windows
|
|
|
|
if (mTransientParent) {
|
|
|
|
GtkWidget *transientWidget = GTK_WIDGET(mTransientParent);
|
|
|
|
nsRefPtr<nsWindow> parent = get_window_for_gtk_widget(transientWidget);
|
|
|
|
if (!parent)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
parent->mContainerBlockFocus = aModal;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aModal)
|
2007-10-09 13:58:24 -07:00
|
|
|
gtk_window_set_modal(GTK_WINDOW(grabWidget), TRUE);
|
2007-03-22 10:30:00 -07:00
|
|
|
else
|
2007-10-09 13:58:24 -07:00
|
|
|
gtk_window_set_modal(GTK_WINDOW(grabWidget), FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-07-26 18:28:05 -07:00
|
|
|
// nsIWidget method, which means IsShown.
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
2009-07-26 18:28:05 -07:00
|
|
|
nsWindow::IsVisible(PRBool& aState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-07-26 18:28:05 -07:00
|
|
|
aState = mIsShown;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::ConstrainPosition(PRBool aAllowSlop, PRInt32 *aX, PRInt32 *aY)
|
|
|
|
{
|
|
|
|
if (mIsTopLevel && mShell) {
|
|
|
|
PRInt32 screenWidth = gdk_screen_width();
|
|
|
|
PRInt32 screenHeight = gdk_screen_height();
|
|
|
|
if (aAllowSlop) {
|
|
|
|
if (*aX < (kWindowPositionSlop - mBounds.width))
|
|
|
|
*aX = kWindowPositionSlop - mBounds.width;
|
|
|
|
if (*aX > (screenWidth - kWindowPositionSlop))
|
|
|
|
*aX = screenWidth - kWindowPositionSlop;
|
|
|
|
if (*aY < (kWindowPositionSlop - mBounds.height))
|
|
|
|
*aY = kWindowPositionSlop - mBounds.height;
|
|
|
|
if (*aY > (screenHeight - kWindowPositionSlop))
|
|
|
|
*aY = screenHeight - kWindowPositionSlop;
|
|
|
|
} else {
|
|
|
|
if (*aX < 0)
|
|
|
|
*aX = 0;
|
|
|
|
if (*aX > (screenWidth - mBounds.width))
|
|
|
|
*aX = screenWidth - mBounds.width;
|
|
|
|
if (*aY < 0)
|
|
|
|
*aY = 0;
|
|
|
|
if (*aY > (screenHeight - mBounds.height))
|
|
|
|
*aY = screenHeight - mBounds.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-18 18:13:27 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::Show(PRBool aState)
|
|
|
|
{
|
2009-11-01 18:03:12 -08:00
|
|
|
if (aState == mIsShown)
|
|
|
|
return NS_OK;
|
|
|
|
|
2008-10-18 18:13:27 -07:00
|
|
|
mIsShown = aState;
|
|
|
|
|
|
|
|
LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState));
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
if (aState) {
|
|
|
|
// Now that this window is shown, mHasMappedToplevel needs to be
|
|
|
|
// tracked on viewable descendants.
|
|
|
|
SetHasMappedToplevel(mHasMappedToplevel);
|
|
|
|
}
|
|
|
|
|
2008-10-18 18:13:27 -07:00
|
|
|
// Ok, someone called show on a window that isn't sized to a sane
|
|
|
|
// value. Mark this window as needing to have Show() called on it
|
|
|
|
// and return.
|
|
|
|
if ((aState && !AreBoundsSane()) || !mCreated) {
|
|
|
|
LOG(("\tbounds are insane or window hasn't been created yet\n"));
|
|
|
|
mNeedsShow = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If someone is hiding this widget, clear any needing show flag.
|
|
|
|
if (!aState)
|
|
|
|
mNeedsShow = PR_FALSE;
|
|
|
|
|
|
|
|
// If someone is showing this window and it needs a resize then
|
|
|
|
// resize the widget.
|
|
|
|
if (aState) {
|
|
|
|
if (mNeedsMove) {
|
|
|
|
NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
|
|
|
|
PR_FALSE);
|
|
|
|
} else if (mNeedsResize) {
|
|
|
|
NativeResize(mBounds.width, mBounds.height, PR_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NativeShow(aState);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
|
|
|
|
{
|
2009-01-14 19:27:09 -08:00
|
|
|
mBounds.SizeTo(GetSafeWindowSize(nsIntSize(aWidth, aHeight)));
|
2008-10-18 18:13:27 -07:00
|
|
|
|
|
|
|
if (!mCreated)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// There are several cases here that we need to handle, based on a
|
|
|
|
// matrix of the visibility of the widget, the sanity of this resize
|
|
|
|
// and whether or not the widget was previously sane.
|
|
|
|
|
|
|
|
// Has this widget been set to visible?
|
|
|
|
if (mIsShown) {
|
|
|
|
// Are the bounds sane?
|
|
|
|
if (AreBoundsSane()) {
|
|
|
|
// Yep? Resize the window
|
|
|
|
//Maybe, the toplevel has moved
|
|
|
|
|
|
|
|
// Note that if the widget needs to be shown because it
|
|
|
|
// was previously insane in Resize(x,y,w,h), then we need
|
|
|
|
// to set the x and y here too, because the widget wasn't
|
|
|
|
// moved back then
|
|
|
|
if (mIsTopLevel || mNeedsShow)
|
|
|
|
NativeResize(mBounds.x, mBounds.y,
|
|
|
|
mBounds.width, mBounds.height, aRepaint);
|
|
|
|
else
|
|
|
|
NativeResize(mBounds.width, mBounds.height, aRepaint);
|
|
|
|
|
|
|
|
// Does it need to be shown because it was previously insane?
|
|
|
|
if (mNeedsShow)
|
|
|
|
NativeShow(PR_TRUE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If someone has set this so that the needs show flag is false
|
|
|
|
// and it needs to be hidden, update the flag and hide the
|
|
|
|
// window. This flag will be cleared the next time someone
|
|
|
|
// hides the window or shows it. It also prevents us from
|
|
|
|
// calling NativeShow(PR_FALSE) excessively on the window which
|
|
|
|
// causes unneeded X traffic.
|
|
|
|
if (!mNeedsShow) {
|
|
|
|
mNeedsShow = PR_TRUE;
|
|
|
|
NativeShow(PR_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If the widget hasn't been shown, mark the widget as needing to be
|
|
|
|
// resized before it is shown.
|
|
|
|
else {
|
|
|
|
if (AreBoundsSane() && mListenForResizes) {
|
|
|
|
// For widgets that we listen for resizes for (widgets created
|
|
|
|
// with native parents) we apparently _always_ have to resize. I
|
|
|
|
// dunno why, but apparently we're lame like that.
|
|
|
|
NativeResize(aWidth, aHeight, aRepaint);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mNeedsResize = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// synthesize a resize event if this isn't a toplevel
|
|
|
|
if (mIsTopLevel || mListenForResizes) {
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntRect rect(mBounds.x, mBounds.y, aWidth, aHeight);
|
2008-10-18 18:13:27 -07:00
|
|
|
nsEventStatus status;
|
|
|
|
DispatchResizeEvent(rect, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
|
|
|
|
PRBool aRepaint)
|
|
|
|
{
|
|
|
|
mBounds.x = aX;
|
|
|
|
mBounds.y = aY;
|
2009-01-14 19:27:09 -08:00
|
|
|
mBounds.SizeTo(GetSafeWindowSize(nsIntSize(aWidth, aHeight)));
|
2008-10-18 18:13:27 -07:00
|
|
|
|
|
|
|
mPlaced = PR_TRUE;
|
|
|
|
|
|
|
|
if (!mCreated)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// There are several cases here that we need to handle, based on a
|
|
|
|
// matrix of the visibility of the widget, the sanity of this resize
|
|
|
|
// and whether or not the widget was previously sane.
|
|
|
|
|
|
|
|
// Has this widget been set to visible?
|
|
|
|
if (mIsShown) {
|
|
|
|
// Are the bounds sane?
|
|
|
|
if (AreBoundsSane()) {
|
|
|
|
// Yep? Resize the window
|
|
|
|
NativeResize(aX, aY, aWidth, aHeight, aRepaint);
|
|
|
|
// Does it need to be shown because it was previously insane?
|
|
|
|
if (mNeedsShow)
|
|
|
|
NativeShow(PR_TRUE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If someone has set this so that the needs show flag is false
|
|
|
|
// and it needs to be hidden, update the flag and hide the
|
|
|
|
// window. This flag will be cleared the next time someone
|
|
|
|
// hides the window or shows it. It also prevents us from
|
|
|
|
// calling NativeShow(PR_FALSE) excessively on the window which
|
|
|
|
// causes unneeded X traffic.
|
|
|
|
if (!mNeedsShow) {
|
|
|
|
mNeedsShow = PR_TRUE;
|
|
|
|
NativeShow(PR_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If the widget hasn't been shown, mark the widget as needing to be
|
|
|
|
// resized before it is shown
|
|
|
|
else {
|
|
|
|
if (AreBoundsSane() && mListenForResizes){
|
|
|
|
// For widgets that we listen for resizes for (widgets created
|
|
|
|
// with native parents) we apparently _always_ have to resize. I
|
|
|
|
// dunno why, but apparently we're lame like that.
|
|
|
|
NativeResize(aX, aY, aWidth, aHeight, aRepaint);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mNeedsResize = PR_TRUE;
|
|
|
|
mNeedsMove = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mIsTopLevel || mListenForResizes) {
|
|
|
|
// synthesize a resize event
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntRect rect(aX, aY, aWidth, aHeight);
|
2008-10-18 18:13:27 -07:00
|
|
|
nsEventStatus status;
|
|
|
|
DispatchResizeEvent(rect, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::Enable(PRBool aState)
|
|
|
|
{
|
|
|
|
mEnabled = aState;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::IsEnabled(PRBool *aState)
|
|
|
|
{
|
|
|
|
*aState = mEnabled;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::Move(PRInt32 aX, PRInt32 aY)
|
|
|
|
{
|
|
|
|
LOG(("nsWindow::Move [%p] %d %d\n", (void *)this,
|
|
|
|
aX, aY));
|
|
|
|
|
2009-11-02 11:10:07 -08:00
|
|
|
if (mWindowType == eWindowType_toplevel ||
|
|
|
|
mWindowType == eWindowType_dialog) {
|
|
|
|
SetSizeMode(nsSizeMode_Normal);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mPlaced = PR_TRUE;
|
|
|
|
|
|
|
|
// Since a popup window's x/y coordinates are in relation to to
|
|
|
|
// the parent, the parent might have moved so we always move a
|
|
|
|
// popup window.
|
|
|
|
if (aX == mBounds.x && aY == mBounds.y &&
|
|
|
|
mWindowType != eWindowType_popup)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// XXX Should we do some AreBoundsSane check here?
|
|
|
|
|
|
|
|
mBounds.x = aX;
|
|
|
|
mBounds.y = aY;
|
|
|
|
|
|
|
|
if (!mCreated)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
if (mIsTopLevel) {
|
2007-11-28 12:18:11 -08:00
|
|
|
gtk_window_move(GTK_WINDOW(mShell), aX, aY);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-07-26 18:39:36 -07:00
|
|
|
else if (mGdkWindow) {
|
|
|
|
gdk_window_move(mGdkWindow, aX, aY);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2008-05-05 16:44:18 -07:00
|
|
|
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
|
|
|
|
nsIWidget *aWidget,
|
|
|
|
PRBool aActivate)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetZIndex(PRInt32 aZIndex)
|
|
|
|
{
|
|
|
|
nsIWidget* oldPrev = GetPrevSibling();
|
|
|
|
|
|
|
|
nsBaseWidget::SetZIndex(aZIndex);
|
|
|
|
|
|
|
|
if (GetPrevSibling() == oldPrev) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(!mContainer, "Expected Mozilla child widget");
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
// We skip the nsWindows that don't have mGdkWindows.
|
2007-03-22 10:30:00 -07:00
|
|
|
// These are probably in the process of being destroyed.
|
|
|
|
|
|
|
|
if (!GetNextSibling()) {
|
|
|
|
// We're to be on top.
|
2009-07-26 18:39:36 -07:00
|
|
|
if (mGdkWindow)
|
|
|
|
gdk_window_raise(mGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2009-02-27 17:47:40 -08:00
|
|
|
// All the siblings before us need to be below our widget.
|
2007-03-22 10:30:00 -07:00
|
|
|
for (nsWindow* w = this; w;
|
2007-07-08 00:08:04 -07:00
|
|
|
w = static_cast<nsWindow*>(w->GetPrevSibling())) {
|
2009-07-26 18:39:36 -07:00
|
|
|
if (w->mGdkWindow)
|
|
|
|
gdk_window_lower(w->mGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetSizeMode(PRInt32 aMode)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
|
|
|
|
|
|
|
|
// Save the requested state.
|
|
|
|
rv = nsBaseWidget::SetSizeMode(aMode);
|
|
|
|
|
|
|
|
// return if there's no shell or our current state is the same as
|
|
|
|
// the mode we were just set to.
|
|
|
|
if (!mShell || mSizeState == mSizeMode) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (aMode) {
|
|
|
|
case nsSizeMode_Maximized:
|
|
|
|
gtk_window_maximize(GTK_WINDOW(mShell));
|
|
|
|
break;
|
|
|
|
case nsSizeMode_Minimized:
|
|
|
|
gtk_window_iconify(GTK_WINDOW(mShell));
|
|
|
|
break;
|
2009-08-14 12:56:56 -07:00
|
|
|
case nsSizeMode_Fullscreen:
|
|
|
|
MakeFullScreen(PR_TRUE);
|
|
|
|
break;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
default:
|
|
|
|
// nsSizeMode_Normal, really.
|
|
|
|
if (mSizeState == nsSizeMode_Minimized)
|
|
|
|
gtk_window_deiconify(GTK_WINDOW(mShell));
|
|
|
|
else if (mSizeState == nsSizeMode_Maximized)
|
|
|
|
gtk_window_unmaximize(GTK_WINDOW(mShell));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mSizeState = mSizeMode;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef void (* SetUserTimeFunc)(GdkWindow* aWindow, guint32 aTimestamp);
|
|
|
|
|
|
|
|
// This will become obsolete when new GTK APIs are widely supported,
|
|
|
|
// as described here: http://bugzilla.gnome.org/show_bug.cgi?id=347375
|
|
|
|
static void
|
|
|
|
SetUserTimeAndStartupIDForActivatedWindow(GtkWidget* aWindow)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIToolkit> toolkit;
|
|
|
|
NS_GetCurrentToolkit(getter_AddRefs(toolkit));
|
|
|
|
if (!toolkit)
|
|
|
|
return;
|
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
nsGTKToolkit* GTKToolkit = static_cast<nsGTKToolkit*>
|
|
|
|
(static_cast<nsIToolkit*>(toolkit));
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCAutoString desktopStartupID;
|
|
|
|
GTKToolkit->GetDesktopStartupID(&desktopStartupID);
|
|
|
|
if (desktopStartupID.IsEmpty()) {
|
|
|
|
// We don't have the data we need. Fall back to an
|
|
|
|
// approximation ... using the timestamp of the remote command
|
|
|
|
// being received as a guess for the timestamp of the user event
|
|
|
|
// that triggered it.
|
|
|
|
PRUint32 timestamp = GTKToolkit->GetFocusTimestamp();
|
|
|
|
if (timestamp) {
|
|
|
|
gdk_window_focus(aWindow->window, timestamp);
|
|
|
|
GTKToolkit->SetFocusTimestamp(0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
|
|
|
|
GdkDrawable* drawable = GDK_DRAWABLE(aWindow->window);
|
|
|
|
GtkWindow* win = GTK_WINDOW(aWindow);
|
|
|
|
if (!win) {
|
|
|
|
NS_WARNING("Passed in widget was not a GdkWindow!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
GdkScreen* screen = gtk_window_get_screen(win);
|
|
|
|
SnDisplay* snd =
|
|
|
|
sn_display_new(gdk_x11_drawable_get_xdisplay(drawable), nsnull, nsnull);
|
|
|
|
if (!snd)
|
|
|
|
return;
|
|
|
|
SnLauncheeContext* ctx =
|
|
|
|
sn_launchee_context_new(snd, gdk_screen_get_number(screen),
|
|
|
|
desktopStartupID.get());
|
|
|
|
if (!ctx) {
|
|
|
|
sn_display_unref(snd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sn_launchee_context_get_id_has_timestamp(ctx)) {
|
|
|
|
PRLibrary* gtkLibrary;
|
|
|
|
SetUserTimeFunc setUserTimeFunc = (SetUserTimeFunc)
|
|
|
|
PR_FindFunctionSymbolAndLibrary("gdk_x11_window_set_user_time", >kLibrary);
|
|
|
|
if (setUserTimeFunc) {
|
|
|
|
setUserTimeFunc(aWindow->window, sn_launchee_context_get_timestamp(ctx));
|
|
|
|
PR_UnloadLibrary(gtkLibrary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sn_launchee_context_setup_window(ctx, gdk_x11_drawable_get_xid(drawable));
|
|
|
|
sn_launchee_context_complete(ctx);
|
|
|
|
|
|
|
|
sn_launchee_context_unref(ctx);
|
|
|
|
sn_display_unref(snd);
|
|
|
|
#endif
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
GTKToolkit->SetDesktopStartupID(EmptyCString());
|
2009-02-27 17:47:40 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetFocus(PRBool aRaise)
|
|
|
|
{
|
|
|
|
// Make sure that our owning widget has focus. If it doesn't try to
|
|
|
|
// grab it. Note that we don't set our focus flag in this case.
|
|
|
|
|
|
|
|
LOGFOCUS((" SetFocus [%p]\n", (void *)this));
|
|
|
|
|
2008-08-27 19:04:06 -07:00
|
|
|
GtkWidget *owningWidget = GetMozContainerWidget();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!owningWidget)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Raise the window if someone passed in PR_TRUE and the prefs are
|
|
|
|
// set properly.
|
|
|
|
GtkWidget *toplevelWidget = gtk_widget_get_toplevel(owningWidget);
|
|
|
|
|
|
|
|
if (gRaiseWindows && aRaise && toplevelWidget &&
|
|
|
|
!GTK_WIDGET_HAS_FOCUS(owningWidget) &&
|
|
|
|
!GTK_WIDGET_HAS_FOCUS(toplevelWidget)) {
|
|
|
|
GtkWidget* top_window = nsnull;
|
|
|
|
GetToplevelWidget(&top_window);
|
|
|
|
if (top_window && (GTK_WIDGET_VISIBLE(top_window)))
|
|
|
|
{
|
|
|
|
gdk_window_show_unraised(top_window->window);
|
|
|
|
// Unset the urgency hint if possible.
|
|
|
|
SetUrgencyHint(top_window, PR_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> owningWindow = get_window_for_gtk_widget(owningWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!owningWindow)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
if (!GTK_WIDGET_HAS_FOCUS(owningWidget)) {
|
|
|
|
LOGFOCUS((" grabbing focus for the toplevel [%p]\n", (void *)this));
|
2009-09-15 19:01:09 -07:00
|
|
|
owningWindow->mContainerBlockFocus = PR_FALSE;
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Set focus to the window
|
|
|
|
if (gRaiseWindows && aRaise && toplevelWidget &&
|
|
|
|
!GTK_WIDGET_HAS_FOCUS(toplevelWidget) &&
|
|
|
|
owningWindow->mIsShown && GTK_IS_WINDOW(owningWindow->mShell))
|
|
|
|
gtk_window_present(GTK_WINDOW(owningWindow->mShell));
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
gtk_widget_grab_focus(owningWidget);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is the widget that already has focus, return.
|
|
|
|
if (gFocusWindow == this) {
|
|
|
|
LOGFOCUS((" already have focus [%p]\n", (void *)this));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
if (gFocusWindow) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// If the focus window and this window share the same input
|
|
|
|
// context we don't have to change the focus of the IME
|
|
|
|
// context
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = gFocusWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (IM_get_input_context(this) !=
|
|
|
|
IM_get_input_context(gFocusWindow))
|
|
|
|
gFocusWindow->IMELoseFocus();
|
|
|
|
}
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
// Set this window to be the focused child window
|
2007-03-22 10:30:00 -07:00
|
|
|
gFocusWindow = this;
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
IMESetFocus();
|
|
|
|
#endif
|
|
|
|
|
2009-07-22 18:18:39 -07:00
|
|
|
LOGFOCUS((" widget now has focus in SetFocus() [%p]\n",
|
2007-03-22 10:30:00 -07:00
|
|
|
(void *)this));
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-01-14 19:27:09 -08:00
|
|
|
nsWindow::GetScreenBounds(nsIntRect &aRect)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-02-18 16:11:49 -08:00
|
|
|
aRect = nsIntRect(WidgetToScreenOffset(), mBounds.Size());
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
|
|
|
|
aRect.x, aRect.y,
|
|
|
|
mBounds.width, mBounds.height,
|
|
|
|
aRect.width, aRect.height));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetForegroundColor(const nscolor &aColor)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetBackgroundColor(const nscolor &aColor)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetCursor(nsCursor aCursor)
|
|
|
|
{
|
|
|
|
// if we're not the toplevel window pass up the cursor request to
|
|
|
|
// the toplevel window to handle it.
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mContainer && mGdkWindow) {
|
2009-02-19 18:07:08 -08:00
|
|
|
nsWindow *window = GetContainerWindow();
|
|
|
|
if (!window)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return window->SetCursor(aCursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only change cursor if it's actually been changed
|
|
|
|
if (aCursor != mCursor) {
|
|
|
|
GdkCursor *newCursor = NULL;
|
|
|
|
|
|
|
|
newCursor = get_gtk_cursor(aCursor);
|
|
|
|
|
|
|
|
if (nsnull != newCursor) {
|
|
|
|
mCursor = aCursor;
|
|
|
|
|
|
|
|
if (!mContainer)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
gdk_window_set_cursor(GTK_WIDGET(mContainer)->window, newCursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
PRUint8* Data32BitTo1Bit(PRUint8* aImageData,
|
|
|
|
PRUint32 aImageBytesPerRow,
|
|
|
|
PRUint32 aWidth, PRUint32 aHeight)
|
|
|
|
{
|
|
|
|
PRUint32 outBpr = (aWidth + 7) / 8;
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRUint8* outData = new PRUint8[outBpr * aHeight];
|
|
|
|
if (!outData)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
PRUint8 *outRow = outData,
|
|
|
|
*imageRow = aImageData;
|
|
|
|
|
|
|
|
for (PRUint32 curRow = 0; curRow < aHeight; curRow++) {
|
|
|
|
PRUint8 *irow = imageRow;
|
|
|
|
PRUint8 *orow = outRow;
|
|
|
|
PRUint8 imagePixels = 0;
|
|
|
|
PRUint8 offset = 0;
|
|
|
|
|
|
|
|
for (PRUint32 curCol = 0; curCol < aWidth; curCol++) {
|
|
|
|
PRUint8 r = *imageRow++,
|
|
|
|
g = *imageRow++,
|
|
|
|
b = *imageRow++;
|
|
|
|
/* a = * */imageRow++;
|
|
|
|
|
|
|
|
if ((r + b + g) < 3 * 128)
|
|
|
|
imagePixels |= (1 << offset);
|
|
|
|
|
|
|
|
if (offset == 7) {
|
|
|
|
*outRow++ = imagePixels;
|
|
|
|
offset = 0;
|
|
|
|
imagePixels = 0;
|
|
|
|
} else {
|
|
|
|
offset++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (offset != 0)
|
|
|
|
*outRow++ = imagePixels;
|
|
|
|
|
|
|
|
imageRow = irow + aImageBytesPerRow;
|
|
|
|
outRow = orow + outBpr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return outData;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetCursor(imgIContainer* aCursor,
|
|
|
|
PRUint32 aHotspotX, PRUint32 aHotspotY)
|
|
|
|
{
|
|
|
|
// if we're not the toplevel window pass up the cursor request to
|
|
|
|
// the toplevel window to handle it.
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mContainer && mGdkWindow) {
|
2009-02-19 18:07:08 -08:00
|
|
|
nsWindow *window = GetContainerWindow();
|
|
|
|
if (!window)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return window->SetCursor(aCursor, aHotspotX, aHotspotY);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sPixbufCursorChecked) {
|
|
|
|
PRLibrary* lib;
|
|
|
|
_gdk_cursor_new_from_pixbuf = (_gdk_cursor_new_from_pixbuf_fn)
|
|
|
|
PR_FindFunctionSymbolAndLibrary("gdk_cursor_new_from_pixbuf", &lib);
|
2007-04-15 15:22:58 -07:00
|
|
|
if (lib) {
|
|
|
|
// We already link against GDK, so we can unload it.
|
|
|
|
PR_UnloadLibrary(lib);
|
|
|
|
lib = nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
_gdk_display_get_default = (_gdk_display_get_default_fn)
|
|
|
|
PR_FindFunctionSymbolAndLibrary("gdk_display_get_default", &lib);
|
2007-04-15 15:22:58 -07:00
|
|
|
if (lib) {
|
|
|
|
// We already link against GDK, so we can unload it.
|
|
|
|
PR_UnloadLibrary(lib);
|
|
|
|
lib = nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
sPixbufCursorChecked = PR_TRUE;
|
|
|
|
}
|
|
|
|
mCursor = nsCursor(-1);
|
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
// Get the image's current frame
|
|
|
|
GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(aCursor);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!pixbuf)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
|
|
|
|
int width = gdk_pixbuf_get_width(pixbuf);
|
|
|
|
int height = gdk_pixbuf_get_height(pixbuf);
|
|
|
|
// Reject cursors greater than 128 pixels in some direction, to prevent
|
|
|
|
// spoofing.
|
|
|
|
// XXX ideally we should rescale. Also, we could modify the API to
|
|
|
|
// allow trusted content to set larger cursors.
|
2007-10-10 05:21:29 -07:00
|
|
|
if (width > 128 || height > 128) {
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(pixbuf);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
2007-10-10 05:21:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
|
|
|
|
// is of course not documented anywhere...
|
|
|
|
// So add one if there isn't one yet
|
|
|
|
if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
|
|
|
|
GdkPixbuf* alphaBuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(pixbuf);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!alphaBuf) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
pixbuf = alphaBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkCursor* cursor;
|
|
|
|
if (!_gdk_cursor_new_from_pixbuf || !_gdk_display_get_default) {
|
|
|
|
// Fallback to a monochrome cursor
|
|
|
|
GdkPixmap* mask = gdk_pixmap_new(NULL, width, height, 1);
|
2007-10-10 05:21:29 -07:00
|
|
|
if (!mask) {
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(pixbuf);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2007-10-10 05:21:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRUint8* data = Data32BitTo1Bit(gdk_pixbuf_get_pixels(pixbuf),
|
|
|
|
gdk_pixbuf_get_rowstride(pixbuf),
|
|
|
|
width, height);
|
|
|
|
if (!data) {
|
|
|
|
g_object_unref(mask);
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(pixbuf);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkPixmap* image = gdk_bitmap_create_from_data(NULL, (const gchar*)data, width,
|
|
|
|
height);
|
|
|
|
delete[] data;
|
|
|
|
if (!image) {
|
|
|
|
g_object_unref(mask);
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(pixbuf);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
gdk_pixbuf_render_threshold_alpha(pixbuf, mask, 0, 0, 0, 0, width,
|
|
|
|
height, 1);
|
|
|
|
|
|
|
|
GdkColor fg = { 0, 0, 0, 0 }; // Black
|
|
|
|
GdkColor bg = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; // White
|
|
|
|
|
|
|
|
cursor = gdk_cursor_new_from_pixmap(image, mask, &fg, &bg, aHotspotX,
|
|
|
|
aHotspotY);
|
|
|
|
g_object_unref(image);
|
|
|
|
g_object_unref(mask);
|
|
|
|
} else {
|
|
|
|
// Now create the cursor
|
|
|
|
cursor = _gdk_cursor_new_from_pixbuf(_gdk_display_get_default(),
|
|
|
|
pixbuf,
|
|
|
|
aHotspotX, aHotspotY);
|
|
|
|
}
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(pixbuf);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
if (cursor) {
|
|
|
|
if (mContainer) {
|
|
|
|
gdk_window_set_cursor(GTK_WIDGET(mContainer)->window, cursor);
|
|
|
|
rv = NS_OK;
|
|
|
|
}
|
|
|
|
gdk_cursor_unref(cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-01-14 19:27:09 -08:00
|
|
|
nsWindow::Invalidate(const nsIntRect &aRect,
|
|
|
|
PRBool aIsSynchronous)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-11-01 18:03:12 -08:00
|
|
|
if (!mGdkWindow)
|
2009-07-26 18:28:05 -07:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-26 18:28:05 -07:00
|
|
|
GdkRectangle rect;
|
2007-03-22 10:30:00 -07:00
|
|
|
rect.x = aRect.x;
|
|
|
|
rect.y = aRect.y;
|
|
|
|
rect.width = aRect.width;
|
|
|
|
rect.height = aRect.height;
|
|
|
|
|
|
|
|
LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d (sync: %d)\n", (void *)this,
|
|
|
|
rect.x, rect.y, rect.width, rect.height, aIsSynchronous));
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aIsSynchronous)
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_process_updates(mGdkWindow, FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::Update()
|
|
|
|
{
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
LOGDRAW(("Update [%p] %p\n", this, mGdkWindow));
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_process_updates(mGdkWindow, FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-07-21 17:45:13 -07:00
|
|
|
void
|
2009-08-13 19:09:51 -07:00
|
|
|
nsWindow::Scroll(const nsIntPoint& aDelta,
|
|
|
|
const nsTArray<nsIntRect>& aDestRects,
|
2009-07-21 17:45:13 -07:00
|
|
|
const nsTArray<Configuration>& aConfigurations)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow) {
|
2009-07-21 17:45:13 -07:00
|
|
|
NS_ERROR("Cannot scroll widget");
|
|
|
|
return;
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
|
2009-07-21 17:45:13 -07:00
|
|
|
nsAutoTArray<nsWindow*,1> windowsToShow;
|
|
|
|
// Hide any widgets that are becoming invisible or that are moving.
|
|
|
|
// Moving widgets are hidden for the duration of the scroll so that
|
|
|
|
// the XCopyArea treats their drawn pixels as part of the window
|
|
|
|
// that should be scrolled. This works well when the widgets are
|
|
|
|
// moving because they're being scrolled, which is normally true.
|
|
|
|
for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
|
|
|
|
const Configuration& configuration = aConfigurations[i];
|
|
|
|
nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
|
|
|
|
NS_ASSERTION(w->GetParent() == this,
|
|
|
|
"Configured widget is not a child");
|
|
|
|
if (w->mIsShown &&
|
|
|
|
(configuration.mClipRegion.IsEmpty() ||
|
|
|
|
configuration.mBounds != w->mBounds)) {
|
|
|
|
w->NativeShow(PR_FALSE);
|
|
|
|
windowsToShow.AppendElement(w);
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
}
|
|
|
|
|
2009-11-26 16:24:39 -08:00
|
|
|
// The parts of source regions not covered by their destination get marked
|
|
|
|
// invalid (by GDK). This is necessary (until covered by another blit)
|
|
|
|
// because GDK translates any pending expose events to the destination,
|
|
|
|
// and so doesn't know whether an expose event might have been due on the
|
|
|
|
// source.
|
|
|
|
//
|
|
|
|
// However, GDK 2.18 does not subtract the invalid regions at the
|
|
|
|
// destinations from the update_area, so the seams between different moves
|
|
|
|
// remain invalid. GDK 2.18 also delays and queues move operations. If
|
|
|
|
// gdk_window_process_updates is called before the moves are flushed, GDK
|
|
|
|
// 2.18 removes the invalid seams from the move regions, so the seams are
|
|
|
|
// left with their old content until they get redrawn. Therefore, the
|
|
|
|
// subtraction of destination invalid regions is performed here.
|
|
|
|
GdkRegion* updateArea = gdk_window_get_update_area(mGdkWindow);
|
|
|
|
if (!updateArea) {
|
|
|
|
updateArea = gdk_region_new(); // Aborts on OOM.
|
|
|
|
}
|
|
|
|
|
|
|
|
// gdk_window_move_region, up to GDK 2.16, has a ghastly bug where it
|
|
|
|
// doesn't restrict blitting to the given region, and blits its full
|
|
|
|
// bounding box. So we have to work around that by blitting one rectangle
|
|
|
|
// at a time.
|
2009-08-13 19:09:51 -07:00
|
|
|
for (PRUint32 i = 0; i < aDestRects.Length(); ++i) {
|
|
|
|
const nsIntRect& r = aDestRects[i];
|
|
|
|
GdkRectangle gdkSource =
|
|
|
|
{ r.x - aDelta.x, r.y - aDelta.y, r.width, r.height };
|
2009-11-26 16:24:39 -08:00
|
|
|
GdkRegion* rectRegion = gdk_region_rectangle(&gdkSource);
|
|
|
|
gdk_window_move_region(GDK_WINDOW(mGdkWindow), rectRegion,
|
|
|
|
aDelta.x, aDelta.y);
|
|
|
|
|
|
|
|
// The part of the old invalid region that is moving.
|
|
|
|
GdkRegion* updateChanges = gdk_region_copy(rectRegion);
|
|
|
|
gdk_region_intersect(updateChanges, updateArea);
|
|
|
|
gdk_region_offset(updateChanges, aDelta.x, aDelta.y);
|
|
|
|
|
|
|
|
// Make |rectRegion| the destination
|
|
|
|
gdk_region_offset(rectRegion, aDelta.x, aDelta.y);
|
|
|
|
// Remove any old invalid areas covered at the destination.
|
|
|
|
gdk_region_subtract(updateArea, rectRegion);
|
|
|
|
gdk_region_destroy(rectRegion);
|
|
|
|
|
|
|
|
// The update_area from the move_region contains:
|
|
|
|
// 1. The part of the source region not covered by the destination.
|
|
|
|
// 2. Any destination regions for which the source was obscured by
|
|
|
|
// parent window clips or child windows.
|
|
|
|
GdkRegion* newUpdates = gdk_window_get_update_area(mGdkWindow);
|
|
|
|
if (newUpdates) {
|
|
|
|
gdk_region_union(updateChanges, newUpdates);
|
|
|
|
gdk_region_destroy(newUpdates);
|
|
|
|
}
|
|
|
|
gdk_region_union(updateArea, updateChanges);
|
|
|
|
gdk_region_destroy(updateChanges);
|
2009-08-13 19:09:51 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-11-26 16:24:39 -08:00
|
|
|
gdk_window_invalidate_region(mGdkWindow, updateArea, FALSE);
|
|
|
|
gdk_region_destroy(updateArea);
|
|
|
|
|
2009-07-21 17:45:13 -07:00
|
|
|
ConfigureChildren(aConfigurations);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-21 17:45:13 -07:00
|
|
|
for (PRUint32 i = 0; i < windowsToShow.Length(); ++i) {
|
|
|
|
windowsToShow[i]->NativeShow(PR_TRUE);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
nsWindow::GetNativeData(PRUint32 aDataType)
|
|
|
|
{
|
|
|
|
switch (aDataType) {
|
|
|
|
case NS_NATIVE_WINDOW:
|
|
|
|
case NS_NATIVE_WIDGET: {
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
return mGdkWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NS_NATIVE_PLUGIN_PORT:
|
|
|
|
return SetupPluginPort();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_NATIVE_DISPLAY:
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
return GDK_DISPLAY();
|
2008-08-06 13:48:55 -07:00
|
|
|
#else
|
|
|
|
return nsnull;
|
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_NATIVE_GRAPHIC: {
|
|
|
|
NS_ASSERTION(nsnull != mToolkit, "NULL toolkit, unable to get a GC");
|
2007-07-08 00:08:04 -07:00
|
|
|
return (void *)static_cast<nsGTKToolkit *>(mToolkit)->GetSharedGC();
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NS_NATIVE_SHELLWIDGET:
|
|
|
|
return (void *) mShell;
|
|
|
|
|
|
|
|
default:
|
|
|
|
NS_WARNING("nsWindow::GetNativeData called with bad value");
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetTitle(const nsAString& aTitle)
|
|
|
|
{
|
|
|
|
if (!mShell)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// convert the string into utf8 and set the title.
|
|
|
|
#define UTF8_FOLLOWBYTE(ch) (((ch) & 0xC0) == 0x80)
|
|
|
|
NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
|
|
|
|
if (titleUTF8.Length() > NS_WINDOW_TITLE_MAX_LENGTH) {
|
|
|
|
// Truncate overlong titles (bug 167315). Make sure we chop after a
|
|
|
|
// complete sequence by making sure the next char isn't a follow-byte.
|
|
|
|
PRUint32 len = NS_WINDOW_TITLE_MAX_LENGTH;
|
|
|
|
while(UTF8_FOLLOWBYTE(titleUTF8[len]))
|
|
|
|
--len;
|
|
|
|
titleUTF8.Truncate(len);
|
|
|
|
}
|
|
|
|
gtk_window_set_title(GTK_WINDOW(mShell), (const char *)titleUTF8.get());
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetIcon(const nsAString& aIconSpec)
|
|
|
|
{
|
|
|
|
if (!mShell)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsILocalFile> iconFile;
|
|
|
|
nsCAutoString path;
|
2009-01-21 20:15:34 -08:00
|
|
|
nsTArray<nsCString> iconList;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-01-09 22:04:51 -08:00
|
|
|
// Look for icons with the following suffixes appended to the base name.
|
|
|
|
// The last two entries (for the old XPM format) will be ignored unless
|
|
|
|
// no icons are found using the other suffixes. XPM icons are depricated.
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-01-09 22:04:51 -08:00
|
|
|
const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png",
|
|
|
|
".xpm", "16.xpm" };
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(extensions); i++) {
|
|
|
|
// Don't bother looking for XPM versions if we found a PNG.
|
2009-01-21 20:15:34 -08:00
|
|
|
if (i == NS_ARRAY_LENGTH(extensions) - 2 && iconList.Length())
|
2008-01-09 22:04:51 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
nsAutoString extension;
|
|
|
|
extension.AppendASCII(extensions[i]);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-01-09 22:04:51 -08:00
|
|
|
ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile));
|
|
|
|
if (iconFile) {
|
|
|
|
iconFile->GetNativePath(path);
|
2009-01-21 20:15:34 -08:00
|
|
|
iconList.AppendElement(path);
|
2008-01-09 22:04:51 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// leave the default icon intact if no matching icons were found
|
2009-01-21 20:15:34 -08:00
|
|
|
if (iconList.Length() == 0)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
return SetWindowIconList(iconList);
|
|
|
|
}
|
|
|
|
|
2009-02-18 16:11:49 -08:00
|
|
|
nsIntPoint
|
|
|
|
nsWindow::WidgetToScreenOffset()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
gint x = 0, y = 0;
|
|
|
|
|
|
|
|
if (mContainer) {
|
|
|
|
gdk_window_get_root_origin(GTK_WIDGET(mContainer)->window,
|
|
|
|
&x, &y);
|
2009-02-18 16:11:49 -08:00
|
|
|
LOG(("WidgetToScreenOffset (container) %d %d\n", x, y));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-07-26 18:39:36 -07:00
|
|
|
else if (mGdkWindow) {
|
|
|
|
gdk_window_get_origin(mGdkWindow, &x, &y);
|
2009-02-18 16:11:49 -08:00
|
|
|
LOG(("WidgetToScreenOffset (drawing) %d %d\n", x, y));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-02-18 16:11:49 -08:00
|
|
|
return nsIntPoint(x, y);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::EnableDragDrop(PRBool aEnable)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::CaptureMouse(PRBool aCapture)
|
|
|
|
{
|
|
|
|
LOG(("CaptureMouse %p\n", (void *)this));
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2008-08-27 19:04:06 -07:00
|
|
|
GtkWidget *widget = GetMozContainerWidget();
|
2009-02-19 18:07:08 -08:00
|
|
|
if (!widget)
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (aCapture) {
|
|
|
|
gtk_grab_add(widget);
|
|
|
|
GrabPointer();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ReleaseGrabs();
|
|
|
|
gtk_grab_remove(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
|
|
|
|
PRBool aDoCapture,
|
|
|
|
PRBool aConsumeRollupEvent)
|
|
|
|
{
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2008-08-27 19:04:06 -07:00
|
|
|
GtkWidget *widget = GetMozContainerWidget();
|
2009-02-19 18:07:08 -08:00
|
|
|
if (!widget)
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
LOG(("CaptureRollupEvents %p\n", (void *)this));
|
|
|
|
|
|
|
|
if (aDoCapture) {
|
2008-01-14 01:40:45 -08:00
|
|
|
gConsumeRollupEvent = aConsumeRollupEvent;
|
2007-03-22 10:30:00 -07:00
|
|
|
gRollupListener = aListener;
|
2007-07-08 00:08:04 -07:00
|
|
|
gRollupWindow = do_GetWeakReference(static_cast<nsIWidget*>
|
|
|
|
(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
// real grab is only done when there is no dragging
|
|
|
|
if (!nsWindow::DragInProgress()) {
|
|
|
|
gtk_grab_add(widget);
|
|
|
|
GrabPointer();
|
|
|
|
GrabKeyboard();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!nsWindow::DragInProgress()) {
|
|
|
|
ReleaseGrabs();
|
|
|
|
gtk_grab_remove(widget);
|
|
|
|
}
|
|
|
|
gRollupListener = nsnull;
|
|
|
|
gRollupWindow = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::GetAttention(PRInt32 aCycleCount)
|
|
|
|
{
|
|
|
|
LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
|
|
|
|
|
|
|
|
GtkWidget* top_window = nsnull;
|
|
|
|
GtkWidget* top_focused_window = nsnull;
|
|
|
|
GetToplevelWidget(&top_window);
|
|
|
|
if (gFocusWindow)
|
|
|
|
gFocusWindow->GetToplevelWidget(&top_focused_window);
|
|
|
|
|
|
|
|
// Don't get attention if the window is focused anyway.
|
|
|
|
if (top_window && (GTK_WIDGET_VISIBLE(top_window)) &&
|
|
|
|
top_window != top_focused_window) {
|
|
|
|
SetUrgencyHint(top_window, PR_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-04-21 16:53:52 -07:00
|
|
|
PRBool
|
|
|
|
nsWindow::HasPendingInputEvent()
|
|
|
|
{
|
|
|
|
// This sucks, but gtk/gdk has no way to answer the question we want while
|
|
|
|
// excluding paint events, and there's no X API that will let us peek
|
|
|
|
// without blocking or removing. To prevent event reordering, peek
|
|
|
|
// anything except expose events. Reordering expose and others should be
|
|
|
|
// ok, hopefully.
|
|
|
|
PRBool haveEvent;
|
|
|
|
#ifdef MOZ_X11
|
|
|
|
XEvent ev;
|
|
|
|
haveEvent =
|
|
|
|
XCheckMaskEvent(GDK_DISPLAY(),
|
|
|
|
KeyPressMask | KeyReleaseMask | ButtonPressMask |
|
|
|
|
ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
|
|
|
|
PointerMotionMask | PointerMotionHintMask |
|
|
|
|
Button1MotionMask | Button2MotionMask |
|
|
|
|
Button3MotionMask | Button4MotionMask |
|
|
|
|
Button5MotionMask | ButtonMotionMask | KeymapStateMask |
|
|
|
|
VisibilityChangeMask | StructureNotifyMask |
|
|
|
|
ResizeRedirectMask | SubstructureNotifyMask |
|
|
|
|
SubstructureRedirectMask | FocusChangeMask |
|
|
|
|
PropertyChangeMask | ColormapChangeMask |
|
|
|
|
OwnerGrabButtonMask, &ev);
|
|
|
|
if (haveEvent) {
|
|
|
|
XPutBackEvent(GDK_DISPLAY(), &ev);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
haveEvent = PR_FALSE;
|
|
|
|
#endif
|
|
|
|
return haveEvent;
|
|
|
|
}
|
|
|
|
|
2008-08-27 19:04:06 -07:00
|
|
|
#if 0
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG
|
2008-08-27 19:04:06 -07:00
|
|
|
// Paint flashing code (disabled for cairo - see below)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#define CAPS_LOCK_IS_ON \
|
|
|
|
(gdk_keyboard_get_modifiers() & GDK_LOCK_MASK)
|
|
|
|
|
|
|
|
#define WANT_PAINT_FLASHING \
|
|
|
|
(debug_WantPaintFlashing() && CAPS_LOCK_IS_ON)
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
static void
|
|
|
|
gdk_window_flash(GdkWindow * aGdkWindow,
|
|
|
|
unsigned int aTimes,
|
|
|
|
unsigned int aInterval, // Milliseconds
|
|
|
|
GdkRegion * aRegion)
|
|
|
|
{
|
|
|
|
gint x;
|
|
|
|
gint y;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
guint i;
|
|
|
|
GdkGC * gc = 0;
|
|
|
|
GdkColor white;
|
|
|
|
|
|
|
|
gdk_window_get_geometry(aGdkWindow,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&width,
|
|
|
|
&height,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
gdk_window_get_origin (aGdkWindow,
|
|
|
|
&x,
|
|
|
|
&y);
|
|
|
|
|
|
|
|
gc = gdk_gc_new(GDK_ROOT_PARENT());
|
|
|
|
|
|
|
|
white.pixel = WhitePixel(gdk_display,DefaultScreen(gdk_display));
|
|
|
|
|
|
|
|
gdk_gc_set_foreground(gc,&white);
|
|
|
|
gdk_gc_set_function(gc,GDK_XOR);
|
|
|
|
gdk_gc_set_subwindow(gc,GDK_INCLUDE_INFERIORS);
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
gdk_region_offset(aRegion, x, y);
|
|
|
|
gdk_gc_set_clip_region(gc, aRegion);
|
|
|
|
|
|
|
|
/*
|
2009-02-27 17:47:40 -08:00
|
|
|
* Need to do this twice so that the XOR effect can replace
|
2007-03-22 10:30:00 -07:00
|
|
|
* the original window contents.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < aTimes * 2; i++)
|
|
|
|
{
|
|
|
|
gdk_draw_rectangle(GDK_ROOT_PARENT(),
|
|
|
|
gc,
|
|
|
|
TRUE,
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height);
|
|
|
|
|
|
|
|
gdk_flush();
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PR_Sleep(PR_MillisecondsToInterval(aInterval));
|
|
|
|
}
|
|
|
|
|
|
|
|
gdk_gc_destroy(gc);
|
|
|
|
|
|
|
|
gdk_region_offset(aRegion, -x, -y);
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif // DEBUG
|
2008-08-27 19:04:06 -07:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
|
|
|
|
{
|
|
|
|
if (mIsDestroyed) {
|
|
|
|
LOG(("Expose event on destroyed window [%p] window %p\n",
|
|
|
|
(void *)this, (void *)aEvent->window));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
// Windows that are not visible will be painted after they become visible.
|
|
|
|
if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
|
2007-03-22 10:30:00 -07:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRegion> updateRegion = do_CreateInstance(kRegionCID);
|
|
|
|
if (!updateRegion)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
updateRegion->Init();
|
|
|
|
|
|
|
|
GdkRectangle *rects;
|
|
|
|
gint nrects;
|
|
|
|
gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
|
2007-07-11 17:59:37 -07:00
|
|
|
if (NS_UNLIKELY(!rects)) // OOM
|
|
|
|
return FALSE;
|
|
|
|
|
2009-02-15 17:10:24 -08:00
|
|
|
if (nrects > MAX_RECTS_IN_REGION) {
|
|
|
|
// Just use the bounding box
|
|
|
|
rects[0] = aEvent->area;
|
|
|
|
nrects = 1;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
|
|
|
|
(void *)this, (void *)aEvent->window,
|
|
|
|
GDK_WINDOW_XWINDOW(aEvent->window)));
|
|
|
|
|
|
|
|
GdkRectangle *r;
|
|
|
|
GdkRectangle *r_end = rects + nrects;
|
|
|
|
for (r = rects; r < r_end; ++r) {
|
|
|
|
updateRegion->Union(r->x, r->y, r->width, r->height);
|
|
|
|
LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
|
|
|
|
}
|
|
|
|
|
2009-07-21 17:44:55 -07:00
|
|
|
PRBool translucent = eTransparencyTransparent == GetTransparencyMode();
|
|
|
|
if (!translucent) {
|
|
|
|
GList *children =
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_peek_children(mGdkWindow);
|
2009-07-21 17:44:55 -07:00
|
|
|
while (children) {
|
|
|
|
GdkWindow *gdkWin = GDK_WINDOW(children->data);
|
|
|
|
nsWindow *kid = get_window_for_gdk_window(gdkWin);
|
2009-07-23 19:08:07 -07:00
|
|
|
if (kid && gdk_window_is_visible(gdkWin)) {
|
2009-07-21 17:44:55 -07:00
|
|
|
nsAutoTArray<nsIntRect,1> clipRects;
|
|
|
|
kid->GetWindowClipRegion(&clipRects);
|
|
|
|
nsIntRect bounds;
|
|
|
|
kid->GetBounds(bounds);
|
|
|
|
for (PRUint32 i = 0; i < clipRects.Length(); ++i) {
|
|
|
|
nsIntRect r = clipRects[i] + bounds.TopLeft();
|
|
|
|
updateRegion->Subtract(r.x, r.y, r.width, r.height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
children = children->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (updateRegion->IsEmpty()) {
|
|
|
|
g_free(rects);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_DFB
|
|
|
|
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
|
|
|
|
if (NS_UNLIKELY(!rc)) {
|
|
|
|
g_free(rects);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// do double-buffering and clipping here
|
|
|
|
nsRefPtr<gfxContext> ctx = rc->ThebesContext();
|
|
|
|
|
2008-08-18 20:22:42 -07:00
|
|
|
gfxPlatformGtk::GetPlatform()->SetGdkDrawable(ctx->OriginalSurface(),
|
2009-07-26 18:39:36 -07:00
|
|
|
GDK_DRAWABLE(mGdkWindow));
|
2008-08-06 13:48:55 -07:00
|
|
|
|
|
|
|
// clip to the update region
|
|
|
|
ctx->Save();
|
|
|
|
ctx->NewPath();
|
|
|
|
for (r = rects; r < r_end; ++r) {
|
|
|
|
ctx->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
|
|
|
|
}
|
|
|
|
ctx->Clip();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
|
2007-07-11 17:59:37 -07:00
|
|
|
if (NS_UNLIKELY(!rc)) {
|
|
|
|
g_free(rects);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsIntRect boundsRect;
|
2008-09-17 14:15:52 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
GdkPixmap* bufferPixmap = nsnull;
|
2008-09-17 14:15:52 -07:00
|
|
|
gfxIntSize bufferPixmapSize;
|
|
|
|
|
2008-06-18 02:20:29 -07:00
|
|
|
nsRefPtr<gfxASurface> bufferPixmapSurface;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
updateRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y,
|
|
|
|
&boundsRect.width, &boundsRect.height);
|
|
|
|
|
|
|
|
// do double-buffering and clipping here
|
2007-12-18 15:01:15 -08:00
|
|
|
nsRefPtr<gfxContext> ctx = rc->ThebesContext();
|
2007-03-22 10:30:00 -07:00
|
|
|
ctx->Save();
|
|
|
|
ctx->NewPath();
|
|
|
|
if (translucent) {
|
|
|
|
// Collapse update area to the bounding box. This is so we only have to
|
|
|
|
// call UpdateTranslucentWindowAlpha once. After we have dropped
|
|
|
|
// support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
|
|
|
|
// our private interface so we can rework things to avoid this.
|
|
|
|
ctx->Rectangle(gfxRect(boundsRect.x, boundsRect.y,
|
|
|
|
boundsRect.width, boundsRect.height));
|
|
|
|
} else {
|
|
|
|
for (r = rects; r < r_end; ++r) {
|
|
|
|
ctx->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx->Clip();
|
|
|
|
|
|
|
|
// double buffer
|
|
|
|
if (translucent) {
|
|
|
|
ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
|
|
|
} else {
|
|
|
|
// Instead of just doing PushGroup we're going to do a little dance
|
|
|
|
// to ensure that GDK creates the pixmap, so it doesn't go all
|
|
|
|
// XGetGeometry on us in gdk_pixmap_foreign_new_for_display when we
|
|
|
|
// paint native themes
|
2008-09-17 14:15:52 -07:00
|
|
|
gint depth;
|
|
|
|
|
|
|
|
if (gForce24bpp) {
|
|
|
|
depth = 24; // 24 always
|
|
|
|
} else {
|
2009-07-26 18:39:36 -07:00
|
|
|
depth = gdk_drawable_get_depth(GDK_DRAWABLE(mGdkWindow));
|
2008-09-17 14:15:52 -07:00
|
|
|
}
|
|
|
|
|
2008-12-02 17:18:58 -08:00
|
|
|
// Make sure we won't create something that will overload the X server
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntSize safeSize = GetSafeWindowSize(boundsRect.Size());
|
2008-12-02 17:18:58 -08:00
|
|
|
boundsRect.width = safeSize.width;
|
|
|
|
boundsRect.height = safeSize.height;
|
|
|
|
|
2008-09-17 14:15:52 -07:00
|
|
|
if (!gUseBufferPixmap ||
|
|
|
|
boundsRect.width > gBufferPixmapMaxSize.width ||
|
|
|
|
boundsRect.height > gBufferPixmapMaxSize.height)
|
|
|
|
{
|
|
|
|
// create a one-off always if we're not using the global pixmap
|
|
|
|
// if gUseBufferPixmap == TRUE, who's redrawing an area bigger than the screen?
|
2009-07-26 18:39:36 -07:00
|
|
|
bufferPixmap = gdk_pixmap_new(GDK_DRAWABLE(mGdkWindow),
|
2008-09-17 14:15:52 -07:00
|
|
|
boundsRect.width, boundsRect.height,
|
|
|
|
depth);
|
|
|
|
bufferPixmapSize.width = boundsRect.width;
|
|
|
|
bufferPixmapSize.height = boundsRect.height;
|
|
|
|
} else if (boundsRect.width > gBufferPixmapSize.width ||
|
|
|
|
boundsRect.height > gBufferPixmapSize.height)
|
|
|
|
{
|
|
|
|
// grow the global pixmap
|
|
|
|
if (gBufferPixmap)
|
|
|
|
g_object_unref(G_OBJECT(gBufferPixmap));
|
|
|
|
|
|
|
|
gBufferPixmapSize.width = PR_MAX(gBufferPixmapSize.width, boundsRect.width);
|
|
|
|
gBufferPixmapSize.height = PR_MAX(gBufferPixmapSize.height, boundsRect.height);
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
gBufferPixmap = gdk_pixmap_new(GDK_DRAWABLE(mGdkWindow),
|
2008-09-17 14:15:52 -07:00
|
|
|
gBufferPixmapSize.width, gBufferPixmapSize.height,
|
|
|
|
depth);
|
|
|
|
|
|
|
|
// use the newly-resized global
|
|
|
|
bufferPixmap = gBufferPixmap;
|
|
|
|
bufferPixmapSize = gBufferPixmapSize;
|
|
|
|
} else {
|
|
|
|
// global's big enough, just use it
|
|
|
|
bufferPixmap = gBufferPixmap;
|
|
|
|
bufferPixmapSize = gBufferPixmapSize;
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (bufferPixmap) {
|
2008-06-18 02:20:29 -07:00
|
|
|
bufferPixmapSurface = GetSurfaceForGdkDrawable(GDK_DRAWABLE(bufferPixmap),
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntSize(bufferPixmapSize.width, bufferPixmapSize.height));
|
2008-09-17 14:15:52 -07:00
|
|
|
|
2008-06-28 14:45:53 -07:00
|
|
|
if (bufferPixmapSurface && bufferPixmapSurface->CairoStatus()) {
|
|
|
|
bufferPixmapSurface = nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
if (bufferPixmapSurface) {
|
2008-08-06 13:48:55 -07:00
|
|
|
gfxPlatformGtk::GetPlatform()->SetGdkDrawable(
|
2009-02-27 17:47:40 -08:00
|
|
|
static_cast<gfxASurface *>(bufferPixmapSurface),
|
2008-08-06 13:48:55 -07:00
|
|
|
GDK_DRAWABLE(bufferPixmap));
|
2008-08-18 20:22:42 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
bufferPixmapSurface->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y));
|
|
|
|
nsCOMPtr<nsIRenderingContext> newRC;
|
|
|
|
nsresult rv = GetDeviceContext()->
|
|
|
|
CreateRenderingContextInstance(*getter_AddRefs(newRC));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
bufferPixmapSurface = nsnull;
|
|
|
|
} else {
|
|
|
|
rv = newRC->Init(GetDeviceContext(), bufferPixmapSurface);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
bufferPixmapSurface = nsnull;
|
|
|
|
} else {
|
|
|
|
rc = newRC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-15 19:13:52 -07:00
|
|
|
#if 0
|
2007-03-22 10:30:00 -07:00
|
|
|
// NOTE: Paint flashing region would be wrong for cairo, since
|
|
|
|
// cairo inflates the update region, etc. So don't paint flash
|
|
|
|
// for cairo.
|
2007-06-15 19:13:52 -07:00
|
|
|
#ifdef DEBUG
|
2007-03-22 10:30:00 -07:00
|
|
|
if (WANT_PAINT_FLASHING && aEvent->window)
|
|
|
|
gdk_window_flash(aEvent->window, 1, 100, aEvent->region);
|
2007-06-15 19:13:52 -07:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif // MOZ_X11
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
|
|
|
|
event.refPoint.x = aEvent->area.x;
|
|
|
|
event.refPoint.y = aEvent->area.y;
|
|
|
|
event.rect = nsnull;
|
|
|
|
event.region = updateRegion;
|
|
|
|
event.renderingContext = rc;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-04-29 17:46:47 -07:00
|
|
|
// DispatchEvent can Destroy us (bug 378273), avoid doing any paint
|
|
|
|
// operations below if that happened - it will lead to XError and exit().
|
|
|
|
if (NS_LIKELY(!mIsDestroyed)) {
|
|
|
|
if (status != nsEventStatus_eIgnore) {
|
|
|
|
if (translucent) {
|
|
|
|
nsRefPtr<gfxPattern> pattern = ctx->PopGroup();
|
|
|
|
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
|
|
|
ctx->SetPattern(pattern);
|
|
|
|
ctx->Paint();
|
|
|
|
|
|
|
|
nsRefPtr<gfxImageSurface> img =
|
|
|
|
new gfxImageSurface(gfxIntSize(boundsRect.width, boundsRect.height),
|
|
|
|
gfxImageSurface::ImageFormatA8);
|
2007-07-11 17:59:37 -07:00
|
|
|
if (img && !img->CairoStatus()) {
|
|
|
|
img->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y));
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-07-11 17:59:37 -07:00
|
|
|
nsRefPtr<gfxContext> imgCtx = new gfxContext(img);
|
|
|
|
if (imgCtx) {
|
|
|
|
imgCtx->SetPattern(pattern);
|
|
|
|
imgCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
|
|
|
imgCtx->Paint();
|
|
|
|
}
|
|
|
|
|
2009-01-14 19:27:09 -08:00
|
|
|
UpdateTranslucentWindowAlphaInternal(nsIntRect(boundsRect.x, boundsRect.y,
|
|
|
|
boundsRect.width, boundsRect.height),
|
2007-07-11 17:59:37 -07:00
|
|
|
img->Data(), img->Stride());
|
|
|
|
}
|
2007-04-29 17:46:47 -07:00
|
|
|
} else {
|
|
|
|
if (bufferPixmapSurface) {
|
2008-09-17 14:15:52 -07:00
|
|
|
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
2007-04-29 17:46:47 -07:00
|
|
|
ctx->SetSource(bufferPixmapSurface);
|
|
|
|
ctx->Paint();
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2007-04-29 17:46:47 -07:00
|
|
|
// ignore
|
2008-09-17 14:15:52 -07:00
|
|
|
if (translucent)
|
2007-04-29 17:46:47 -07:00
|
|
|
ctx->PopGroup();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-09-17 14:15:52 -07:00
|
|
|
// if we had to allocate a local pixmap, free it here
|
|
|
|
if (bufferPixmap && bufferPixmap != gBufferPixmap)
|
2007-04-29 17:46:47 -07:00
|
|
|
g_object_unref(G_OBJECT(bufferPixmap));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
ctx->Restore();
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif // MOZ_X11
|
|
|
|
|
|
|
|
#ifdef MOZ_DFB
|
|
|
|
ctx->Restore();
|
|
|
|
#endif
|
2007-04-29 17:46:47 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
g_free(rects);
|
|
|
|
|
|
|
|
// check the return value!
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
nsWindow::OnConfigureEvent(GtkWidget *aWidget, GdkEventConfigure *aEvent)
|
|
|
|
{
|
|
|
|
LOG(("configure event [%p] %d %d %d %d\n", (void *)this,
|
|
|
|
aEvent->x, aEvent->y, aEvent->width, aEvent->height));
|
|
|
|
|
|
|
|
// can we shortcut?
|
|
|
|
if (mBounds.x == aEvent->x &&
|
|
|
|
mBounds.y == aEvent->y)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
// Toplevel windows need to have their bounds set so that we can
|
|
|
|
// keep track of our location. It's not often that the x,y is set
|
|
|
|
// by the layout engine. Width and height are set elsewhere.
|
|
|
|
if (mIsTopLevel) {
|
|
|
|
mPlaced = PR_TRUE;
|
|
|
|
// Need to translate this into the right coordinates
|
2009-02-18 16:11:49 -08:00
|
|
|
mBounds.MoveTo(WidgetToScreenOffset());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsGUIEvent event(PR_TRUE, NS_MOVE, this);
|
|
|
|
|
|
|
|
event.refPoint.x = aEvent->x;
|
|
|
|
event.refPoint.y = aEvent->y;
|
|
|
|
|
|
|
|
// XXX mozilla will invalidate the entire window after this move
|
|
|
|
// complete. wtf?
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
void
|
|
|
|
nsWindow::OnContainerUnrealize(GtkWidget *aWidget)
|
|
|
|
{
|
|
|
|
// The GdkWindows are about to be destroyed (but not deleted), so remove
|
|
|
|
// their references back to their container widget while the GdkWindow
|
|
|
|
// hierarchy is still available.
|
|
|
|
|
|
|
|
NS_ASSERTION(mContainer == MOZ_CONTAINER(aWidget),
|
|
|
|
"unexpected \"unrealize\" signal");
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (mGdkWindow) {
|
2009-11-10 13:57:25 -08:00
|
|
|
DestroyChildWindows();
|
2009-07-26 18:40:46 -07:00
|
|
|
|
|
|
|
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", NULL);
|
|
|
|
mGdkWindow = NULL;
|
2009-05-14 19:14:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::OnSizeAllocate(GtkWidget *aWidget, GtkAllocation *aAllocation)
|
|
|
|
{
|
|
|
|
LOG(("size_allocate [%p] %d %d %d %d\n",
|
|
|
|
(void *)this, aAllocation->x, aAllocation->y,
|
|
|
|
aAllocation->width, aAllocation->height));
|
|
|
|
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntRect rect(aAllocation->x, aAllocation->y,
|
|
|
|
aAllocation->width, aAllocation->height);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
ResizeTransparencyBitmap(rect.width, rect.height);
|
|
|
|
|
|
|
|
mBounds.width = rect.width;
|
|
|
|
mBounds.height = rect.height;
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (mTransparencyBitmap) {
|
|
|
|
ApplyTransparencyBitmap();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchResizeEvent (rect, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnDeleteEvent(GtkWidget *aWidget, GdkEventAny *aEvent)
|
|
|
|
{
|
|
|
|
nsGUIEvent event(PR_TRUE, NS_XUL_CLOSE, this);
|
|
|
|
|
|
|
|
event.refPoint.x = 0;
|
|
|
|
event.refPoint.y = 0;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnEnterNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
|
|
|
|
{
|
|
|
|
// XXXldb Is this the right test for embedding cases?
|
|
|
|
if (aEvent->subwindow != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsMouseEvent event(PR_TRUE, NS_MOUSE_ENTER, this, nsMouseEvent::eReal);
|
|
|
|
|
|
|
|
event.refPoint.x = nscoord(aEvent->x);
|
|
|
|
event.refPoint.y = nscoord(aEvent->y);
|
|
|
|
|
|
|
|
event.time = aEvent->time;
|
|
|
|
|
|
|
|
LOG(("OnEnterNotify: %p\n", (void *)this));
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
2008-03-12 15:44:45 -07:00
|
|
|
static PRBool
|
|
|
|
is_top_level_mouse_exit(GdkWindow* aWindow, GdkEventCrossing *aEvent)
|
|
|
|
{
|
|
|
|
gint x = gint(aEvent->x_root);
|
|
|
|
gint y = gint(aEvent->y_root);
|
|
|
|
GdkDisplay* display = gdk_drawable_get_display(aWindow);
|
|
|
|
GdkWindow* winAtPt = gdk_display_get_window_at_pointer(display, &x, &y);
|
|
|
|
if (!winAtPt)
|
|
|
|
return PR_TRUE;
|
|
|
|
GdkWindow* topLevelAtPt = gdk_window_get_toplevel(winAtPt);
|
|
|
|
GdkWindow* topLevelWidget = gdk_window_get_toplevel(aWindow);
|
|
|
|
return topLevelAtPt != topLevelWidget;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::OnLeaveNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
|
|
|
|
{
|
|
|
|
// XXXldb Is this the right test for embedding cases?
|
|
|
|
if (aEvent->subwindow != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsMouseEvent event(PR_TRUE, NS_MOUSE_EXIT, this, nsMouseEvent::eReal);
|
|
|
|
|
|
|
|
event.refPoint.x = nscoord(aEvent->x);
|
|
|
|
event.refPoint.y = nscoord(aEvent->y);
|
|
|
|
|
|
|
|
event.time = aEvent->time;
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
event.exit = is_top_level_mouse_exit(mGdkWindow, aEvent)
|
2008-03-12 15:44:45 -07:00
|
|
|
? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("OnLeaveNotify: %p\n", (void *)this));
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_DFB
|
|
|
|
void
|
|
|
|
nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
|
|
|
|
{
|
|
|
|
int cursorX = (int) aEvent->x_root;
|
|
|
|
int cursorY = (int) aEvent->y_root;
|
|
|
|
|
|
|
|
D_DEBUG_AT( ns_Window, "%s( %4d,%4d - [%d] )\n", __FUNCTION__, cursorX, cursorY, mDFBCursorCount );
|
|
|
|
|
|
|
|
D_ASSUME( mDFBLayer != NULL );
|
|
|
|
|
|
|
|
if (mDFBLayer)
|
|
|
|
mDFBLayer->GetCursorPosition( mDFBLayer, &cursorX, &cursorY );
|
|
|
|
|
|
|
|
mDFBCursorCount++;
|
|
|
|
|
|
|
|
#if D_DEBUG_ENABLED
|
|
|
|
if (cursorX != (int) aEvent->x_root || cursorY != (int) aEvent->y_root)
|
|
|
|
D_DEBUG_AT( ns_Window, " -> forward to %4d,%4d\n", cursorX, cursorY );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (cursorX == mDFBCursorX && cursorY == mDFBCursorY) {
|
|
|
|
D_DEBUG_AT( ns_Window, " -> dropping %4d,%4d\n", cursorX, cursorY );
|
|
|
|
|
|
|
|
/* drop zero motion */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mDFBCursorX = cursorX;
|
|
|
|
mDFBCursorY = cursorY;
|
|
|
|
|
|
|
|
|
|
|
|
// when we receive this, it must be that the gtk dragging is over,
|
|
|
|
// it is dropped either in or out of mozilla, clear the flag
|
|
|
|
sIsDraggingOutOf = PR_FALSE;
|
|
|
|
|
|
|
|
nsMouseEvent event(PR_TRUE, NS_MOUSE_MOVE, this, nsMouseEvent::eReal);
|
|
|
|
|
2008-12-11 15:55:15 -08:00
|
|
|
// should we move this into !synthEvent?
|
|
|
|
gdouble pressure = 0;
|
|
|
|
gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
|
|
|
|
// Sometime gdk generate 0 pressure value between normal values
|
|
|
|
// We have to ignore that and use last valid value
|
|
|
|
if (pressure)
|
|
|
|
mLastMotionPressure = pressure;
|
|
|
|
event.pressure = mLastMotionPressure;
|
|
|
|
|
2009-02-18 16:11:49 -08:00
|
|
|
event.refPoint = nsIntPoint(cursorX, cursorY) - WidgetToScreenOffset();
|
2008-08-06 13:48:55 -07:00
|
|
|
|
|
|
|
event.isShift = (aEvent->state & GDK_SHIFT_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isControl = (aEvent->state & GDK_CONTROL_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isAlt = (aEvent->state & GDK_MOD1_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
|
|
|
|
event.time = aEvent->time;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
#else
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
|
|
|
|
{
|
|
|
|
// when we receive this, it must be that the gtk dragging is over,
|
|
|
|
// it is dropped either in or out of mozilla, clear the flag
|
|
|
|
sIsDraggingOutOf = PR_FALSE;
|
|
|
|
|
|
|
|
// see if we can compress this event
|
2008-10-19 18:25:26 -07:00
|
|
|
// XXXldb Why skip every other motion event when we have multiple,
|
|
|
|
// but not more than that?
|
2008-08-06 16:24:13 -07:00
|
|
|
PRPackedBool synthEvent = PR_FALSE;
|
2008-10-19 18:25:26 -07:00
|
|
|
#ifdef MOZ_X11
|
|
|
|
XEvent xevent;
|
2008-10-17 15:38:49 -07:00
|
|
|
|
2008-10-19 18:25:26 -07:00
|
|
|
while (XPending (GDK_WINDOW_XDISPLAY(aEvent->window))) {
|
|
|
|
XEvent peeked;
|
|
|
|
XPeekEvent (GDK_WINDOW_XDISPLAY(aEvent->window), &peeked);
|
|
|
|
if (peeked.xany.window != GDK_WINDOW_XWINDOW(aEvent->window)
|
|
|
|
|| peeked.type != MotionNotify)
|
2008-10-12 19:32:56 -07:00
|
|
|
break;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
synthEvent = PR_TRUE;
|
2008-10-19 18:25:26 -07:00
|
|
|
XNextEvent (GDK_WINDOW_XDISPLAY(aEvent->window), &xevent);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// if plugins still keeps the focus, get it back
|
|
|
|
if (gPluginFocusWindow && gPluginFocusWindow != this) {
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = gPluginFocusWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsMouseEvent event(PR_TRUE, NS_MOUSE_MOVE, this, nsMouseEvent::eReal);
|
|
|
|
|
2008-12-11 15:55:15 -08:00
|
|
|
gdouble pressure = 0;
|
|
|
|
gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
|
|
|
|
// Sometime gdk generate 0 pressure value between normal values
|
|
|
|
// We have to ignore that and use last valid value
|
|
|
|
if (pressure)
|
|
|
|
mLastMotionPressure = pressure;
|
|
|
|
event.pressure = mLastMotionPressure;
|
|
|
|
|
2008-10-19 18:25:26 -07:00
|
|
|
if (synthEvent) {
|
|
|
|
#ifdef MOZ_X11
|
|
|
|
event.refPoint.x = nscoord(xevent.xmotion.x);
|
|
|
|
event.refPoint.y = nscoord(xevent.xmotion.y);
|
|
|
|
|
|
|
|
event.isShift = (xevent.xmotion.state & GDK_SHIFT_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isControl = (xevent.xmotion.state & GDK_CONTROL_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isAlt = (xevent.xmotion.state & GDK_MOD1_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
|
|
|
|
event.time = xevent.xmotion.time;
|
|
|
|
#else
|
2008-08-06 13:48:55 -07:00
|
|
|
event.refPoint.x = nscoord(aEvent->x);
|
|
|
|
event.refPoint.y = nscoord(aEvent->y);
|
|
|
|
|
2008-10-19 18:25:26 -07:00
|
|
|
event.isShift = (aEvent->state & GDK_SHIFT_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isControl = (aEvent->state & GDK_CONTROL_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isAlt = (aEvent->state & GDK_MOD1_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
|
|
|
|
event.time = aEvent->time;
|
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-10-19 18:25:26 -07:00
|
|
|
else {
|
|
|
|
// XXX see OnScrollEvent()
|
2009-07-26 18:39:36 -07:00
|
|
|
if (aEvent->window == mGdkWindow) {
|
2008-10-19 18:25:26 -07:00
|
|
|
event.refPoint.x = nscoord(aEvent->x);
|
|
|
|
event.refPoint.y = nscoord(aEvent->y);
|
|
|
|
} else {
|
2009-02-18 16:11:49 -08:00
|
|
|
nsIntPoint point(NSToIntFloor(aEvent->x_root), NSToIntFloor(aEvent->y_root));
|
|
|
|
event.refPoint = point - WidgetToScreenOffset();
|
2008-10-19 18:25:26 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-10-19 18:25:26 -07:00
|
|
|
event.isShift = (aEvent->state & GDK_SHIFT_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isControl = (aEvent->state & GDK_CONTROL_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
event.isAlt = (aEvent->state & GDK_MOD1_MASK)
|
|
|
|
? PR_TRUE : PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-10-19 18:25:26 -07:00
|
|
|
event.time = aEvent->time;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-12-13 23:00:44 -08:00
|
|
|
void
|
|
|
|
nsWindow::InitButtonEvent(nsMouseEvent &aEvent,
|
|
|
|
GdkEventButton *aGdkEvent)
|
|
|
|
{
|
|
|
|
// XXX see OnScrollEvent()
|
2009-07-26 18:39:36 -07:00
|
|
|
if (aGdkEvent->window == mGdkWindow) {
|
2007-12-13 23:00:44 -08:00
|
|
|
aEvent.refPoint.x = nscoord(aGdkEvent->x);
|
|
|
|
aEvent.refPoint.y = nscoord(aGdkEvent->y);
|
|
|
|
} else {
|
2009-02-18 16:11:49 -08:00
|
|
|
nsIntPoint point(NSToIntFloor(aGdkEvent->x_root), NSToIntFloor(aGdkEvent->y_root));
|
|
|
|
aEvent.refPoint = point - WidgetToScreenOffset();
|
2007-12-13 23:00:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
aEvent.isShift = (aGdkEvent->state & GDK_SHIFT_MASK) != 0;
|
|
|
|
aEvent.isControl = (aGdkEvent->state & GDK_CONTROL_MASK) != 0;
|
|
|
|
aEvent.isAlt = (aGdkEvent->state & GDK_MOD1_MASK) != 0;
|
|
|
|
aEvent.isMeta = (aGdkEvent->state & GDK_MOD4_MASK) != 0;
|
|
|
|
|
|
|
|
aEvent.time = aGdkEvent->time;
|
|
|
|
|
|
|
|
switch (aGdkEvent->type) {
|
|
|
|
case GDK_2BUTTON_PRESS:
|
|
|
|
aEvent.clickCount = 2;
|
|
|
|
break;
|
|
|
|
case GDK_3BUTTON_PRESS:
|
|
|
|
aEvent.clickCount = 3;
|
|
|
|
break;
|
|
|
|
// default is one click
|
|
|
|
default:
|
|
|
|
aEvent.clickCount = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::OnButtonPressEvent(GtkWidget *aWidget, GdkEventButton *aEvent)
|
|
|
|
{
|
|
|
|
nsEventStatus status;
|
|
|
|
|
|
|
|
// If you double click in GDK, it will actually generate a single
|
|
|
|
// click event before sending the double click event, and this is
|
|
|
|
// different than the DOM spec. GDK puts this in the queue
|
|
|
|
// programatically, so it's safe to assume that if there's a
|
|
|
|
// double click in the queue, it was generated so we can just drop
|
|
|
|
// this click.
|
|
|
|
GdkEvent *peekedEvent = gdk_event_peek();
|
|
|
|
if (peekedEvent) {
|
|
|
|
GdkEventType type = peekedEvent->any.type;
|
|
|
|
gdk_event_free(peekedEvent);
|
|
|
|
if (type == GDK_2BUTTON_PRESS || type == GDK_3BUTTON_PRESS)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always save the time of this event
|
|
|
|
mLastButtonPressTime = aEvent->time;
|
|
|
|
mLastButtonReleaseTime = 0;
|
|
|
|
|
2009-02-19 18:07:08 -08:00
|
|
|
nsWindow *containerWindow = GetContainerWindow();
|
|
|
|
if (!gFocusWindow && containerWindow) {
|
2009-07-22 18:18:39 -07:00
|
|
|
containerWindow->DispatchActivateEvent();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-01-14 01:40:45 -08:00
|
|
|
|
2009-07-22 18:18:39 -07:00
|
|
|
// check to see if we should rollup
|
2008-01-14 01:40:45 -08:00
|
|
|
PRBool rolledUp = check_for_rollup(aEvent->window, aEvent->x_root,
|
|
|
|
aEvent->y_root, PR_FALSE);
|
|
|
|
if (gConsumeRollupEvent && rolledUp)
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-12-11 15:55:15 -08:00
|
|
|
gdouble pressure = 0;
|
|
|
|
gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
|
|
|
|
mLastMotionPressure = pressure;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRUint16 domButton;
|
|
|
|
switch (aEvent->button) {
|
2007-07-25 14:26:16 -07:00
|
|
|
case 1:
|
|
|
|
domButton = nsMouseEvent::eLeftButton;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case 2:
|
|
|
|
domButton = nsMouseEvent::eMiddleButton;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
domButton = nsMouseEvent::eRightButton;
|
|
|
|
break;
|
2008-03-18 12:36:09 -07:00
|
|
|
// These are mapped to horizontal scroll
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
{
|
|
|
|
nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_SCROLL, this);
|
2008-12-11 15:55:15 -08:00
|
|
|
event.pressure = mLastMotionPressure;
|
2008-03-18 12:36:09 -07:00
|
|
|
event.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
|
|
|
|
event.refPoint.x = nscoord(aEvent->x);
|
|
|
|
event.refPoint.y = nscoord(aEvent->y);
|
2009-09-24 03:58:04 -07:00
|
|
|
// XXX Why is this delta value different from the scroll event?
|
2008-03-18 12:36:09 -07:00
|
|
|
event.delta = (aEvent->button == 6) ? -2 : 2;
|
|
|
|
|
|
|
|
event.isShift = (aEvent->state & GDK_SHIFT_MASK) != 0;
|
|
|
|
event.isControl = (aEvent->state & GDK_CONTROL_MASK) != 0;
|
|
|
|
event.isAlt = (aEvent->state & GDK_MOD1_MASK) != 0;
|
|
|
|
event.isMeta = (aEvent->state & GDK_MOD4_MASK) != 0;
|
|
|
|
|
|
|
|
event.time = aEvent->time;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Map buttons 8-9 to back/forward
|
2008-02-20 02:10:08 -08:00
|
|
|
case 8:
|
|
|
|
DispatchCommandEvent(nsWidgetAtoms::Back);
|
|
|
|
return;
|
|
|
|
case 9:
|
|
|
|
DispatchCommandEvent(nsWidgetAtoms::Forward);
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
default:
|
2007-07-25 14:26:16 -07:00
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsMouseEvent event(PR_TRUE, NS_MOUSE_BUTTON_DOWN, this, nsMouseEvent::eReal);
|
|
|
|
event.button = domButton;
|
|
|
|
InitButtonEvent(event, aEvent);
|
2008-12-11 15:55:15 -08:00
|
|
|
event.pressure = mLastMotionPressure;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
|
|
|
|
// right menu click on linux should also pop up a context menu
|
2007-04-29 17:46:47 -07:00
|
|
|
if (domButton == nsMouseEvent::eRightButton &&
|
|
|
|
NS_LIKELY(!mIsDestroyed)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsMouseEvent contextMenuEvent(PR_TRUE, NS_CONTEXTMENU, this,
|
|
|
|
nsMouseEvent::eReal);
|
|
|
|
InitButtonEvent(contextMenuEvent, aEvent);
|
2008-12-11 15:55:15 -08:00
|
|
|
contextMenuEvent.pressure = mLastMotionPressure;
|
2007-03-22 10:30:00 -07:00
|
|
|
DispatchEvent(&contextMenuEvent, status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnButtonReleaseEvent(GtkWidget *aWidget, GdkEventButton *aEvent)
|
|
|
|
{
|
|
|
|
PRUint16 domButton;
|
|
|
|
mLastButtonReleaseTime = aEvent->time;
|
|
|
|
|
|
|
|
switch (aEvent->button) {
|
2007-07-25 14:26:16 -07:00
|
|
|
case 1:
|
|
|
|
domButton = nsMouseEvent::eLeftButton;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case 2:
|
|
|
|
domButton = nsMouseEvent::eMiddleButton;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
domButton = nsMouseEvent::eRightButton;
|
|
|
|
break;
|
|
|
|
default:
|
2007-07-25 14:26:16 -07:00
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsMouseEvent event(PR_TRUE, NS_MOUSE_BUTTON_UP, this, nsMouseEvent::eReal);
|
|
|
|
event.button = domButton;
|
|
|
|
InitButtonEvent(event, aEvent);
|
2008-12-11 15:55:15 -08:00
|
|
|
gdouble pressure = 0;
|
|
|
|
gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
|
|
|
|
event.pressure = pressure ? pressure : mLastMotionPressure;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
2008-12-11 15:55:15 -08:00
|
|
|
mLastMotionPressure = pressure;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnContainerFocusInEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
|
|
|
|
{
|
|
|
|
LOGFOCUS(("OnContainerFocusInEvent [%p]\n", (void *)this));
|
2009-09-15 19:01:09 -07:00
|
|
|
// Return if someone has blocked events for this widget.
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mContainerBlockFocus) {
|
|
|
|
LOGFOCUS(("Container focus is blocked [%p]\n", (void *)this));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unset the urgency hint, if possible
|
|
|
|
GtkWidget* top_window = nsnull;
|
|
|
|
GetToplevelWidget(&top_window);
|
|
|
|
if (top_window && (GTK_WIDGET_VISIBLE(top_window)))
|
|
|
|
SetUrgencyHint(top_window, PR_FALSE);
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
gFocusWindow = this;
|
|
|
|
DispatchActivateEvent();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnContainerFocusOutEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
|
|
|
|
{
|
|
|
|
LOGFOCUS(("OnContainerFocusOutEvent [%p]\n", (void *)this));
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
// plugin lose focus
|
|
|
|
if (gPluginFocusWindow) {
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = gPluginFocusWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Figure out if the focus widget is the child of this window. If
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
// it is, send a deactivate event for it.
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!gFocusWindow)
|
|
|
|
return;
|
|
|
|
|
|
|
|
GdkWindow *tmpWindow;
|
|
|
|
tmpWindow = (GdkWindow *)gFocusWindow->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
nsWindow *tmpnsWindow = get_window_for_gdk_window(tmpWindow);
|
|
|
|
|
|
|
|
while (tmpWindow && tmpnsWindow) {
|
|
|
|
// found it!
|
|
|
|
if (tmpnsWindow == this)
|
|
|
|
goto foundit;
|
|
|
|
|
|
|
|
tmpWindow = gdk_window_get_parent(tmpWindow);
|
|
|
|
if (!tmpWindow)
|
|
|
|
break;
|
|
|
|
|
|
|
|
tmpnsWindow = get_owning_window_for_gdk_window(tmpWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGFOCUS(("The focus widget was not a child of this window [%p]\n",
|
|
|
|
(void *)this));
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
foundit:
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = gFocusWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef USE_XIM
|
|
|
|
gFocusWindow->IMELoseFocus();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// We only dispatch a deactivate event if we are a toplevel
|
|
|
|
// window, otherwise the embedding code takes care of it.
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
if (NS_LIKELY(!gFocusWindow->mIsDestroyed))
|
|
|
|
DispatchDeactivateEvent();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gFocusWindow = nsnull;
|
|
|
|
|
|
|
|
LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
|
|
|
|
}
|
|
|
|
|
2008-02-06 13:56:02 -08:00
|
|
|
PRBool
|
2008-02-20 02:10:08 -08:00
|
|
|
nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
|
2008-02-06 13:56:02 -08:00
|
|
|
{
|
|
|
|
nsEventStatus status;
|
|
|
|
nsCommandEvent event(PR_TRUE, nsWidgetAtoms::onAppCommand, aCommand, this);
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-04-14 21:16:24 -07:00
|
|
|
static PRUint32
|
2008-04-30 16:14:01 -07:00
|
|
|
GetCharCodeFor(const GdkEventKey *aEvent, guint aShiftState,
|
2008-04-14 21:16:24 -07:00
|
|
|
gint aGroup)
|
|
|
|
{
|
|
|
|
guint keyval;
|
2008-04-30 16:14:01 -07:00
|
|
|
if (gdk_keymap_translate_keyboard_state(NULL, aEvent->hardware_keycode,
|
|
|
|
GdkModifierType(aShiftState),
|
|
|
|
aGroup,
|
2008-04-14 21:16:24 -07:00
|
|
|
&keyval, NULL, NULL, NULL)) {
|
|
|
|
GdkEventKey tmpEvent = *aEvent;
|
|
|
|
tmpEvent.state = guint(aShiftState);
|
|
|
|
tmpEvent.keyval = keyval;
|
|
|
|
tmpEvent.group = aGroup;
|
|
|
|
return nsConvertCharCodeToUnicode(&tmpEvent);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
|
|
GetKeyLevel(GdkEventKey *aEvent)
|
|
|
|
{
|
|
|
|
gint level;
|
|
|
|
if (!gdk_keymap_translate_keyboard_state(NULL,
|
|
|
|
aEvent->hardware_keycode,
|
|
|
|
GdkModifierType(aEvent->state),
|
|
|
|
aEvent->group,
|
|
|
|
NULL, NULL, &level, NULL))
|
|
|
|
return -1;
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRBool
|
|
|
|
IsBasicLatinLetterOrNumeral(PRUint32 aChar)
|
|
|
|
{
|
|
|
|
return (aChar >= 'a' && aChar <= 'z') ||
|
|
|
|
(aChar >= 'A' && aChar <= 'Z') ||
|
|
|
|
(aChar >= '0' && aChar <= '9');
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
gboolean
|
2008-05-05 16:44:18 -07:00
|
|
|
nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
// if we are in the middle of composing text, XIM gets to see it
|
|
|
|
// before mozilla does.
|
|
|
|
LOGIM(("key press [%p]: composing %d val %d\n",
|
|
|
|
(void *)this, IMEComposingWindow() != nsnull, aEvent->keyval));
|
|
|
|
if (IMEFilterEvent(aEvent))
|
|
|
|
return TRUE;
|
|
|
|
LOGIM(("sending as regular key press event\n"));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
|
|
|
|
// work around for annoying things.
|
|
|
|
if (aEvent->keyval == GDK_Tab && aEvent->state & GDK_CONTROL_MASK &&
|
|
|
|
aEvent->state & GDK_MOD1_MASK) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
|
|
|
|
|
2007-04-27 09:34:44 -07:00
|
|
|
// If the key down flag isn't set then set it so we don't send
|
2007-03-22 10:30:00 -07:00
|
|
|
// another key down event on the next key press -- DOM events are
|
|
|
|
// key down, key press and key up. X only has key press and key
|
|
|
|
// release. gtk2 already filters the extra key release events for
|
|
|
|
// us.
|
|
|
|
|
|
|
|
PRBool isKeyDownCancelled = PR_FALSE;
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-04-27 09:34:44 -07:00
|
|
|
PRUint32 domVirtualKeyCode = GdkKeyCodeToDOMKeyCode(aEvent->keyval);
|
|
|
|
|
|
|
|
if (!IsKeyDown(domVirtualKeyCode)) {
|
|
|
|
SetKeyDownFlag(domVirtualKeyCode);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// send the key down event
|
|
|
|
nsKeyEvent downEvent(PR_TRUE, NS_KEY_DOWN, this);
|
|
|
|
InitKeyEvent(downEvent, aEvent);
|
|
|
|
DispatchEvent(&downEvent, status);
|
2007-04-29 17:46:47 -07:00
|
|
|
if (NS_UNLIKELY(mIsDestroyed))
|
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
isKeyDownCancelled = (status == nsEventStatus_eConsumeNoDefault);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't pass modifiers as NS_KEY_PRESS events.
|
|
|
|
// TODO: Instead of selectively excluding some keys from NS_KEY_PRESS events,
|
|
|
|
// we should instead selectively include (as per MSDN spec; no official
|
|
|
|
// spec covers KeyPress events).
|
|
|
|
if (aEvent->keyval == GDK_Shift_L
|
|
|
|
|| aEvent->keyval == GDK_Shift_R
|
|
|
|
|| aEvent->keyval == GDK_Control_L
|
|
|
|
|| aEvent->keyval == GDK_Control_R
|
|
|
|
|| aEvent->keyval == GDK_Alt_L
|
|
|
|
|| aEvent->keyval == GDK_Alt_R
|
|
|
|
|| aEvent->keyval == GDK_Meta_L
|
|
|
|
|| aEvent->keyval == GDK_Meta_R) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
2008-02-06 13:56:02 -08:00
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2008-02-06 13:56:02 -08:00
|
|
|
// Look for specialized app-command keys
|
|
|
|
switch (aEvent->keyval) {
|
|
|
|
case XF86XK_Back:
|
2008-02-20 02:10:08 -08:00
|
|
|
return DispatchCommandEvent(nsWidgetAtoms::Back);
|
2008-02-06 13:56:02 -08:00
|
|
|
case XF86XK_Forward:
|
2008-02-20 02:10:08 -08:00
|
|
|
return DispatchCommandEvent(nsWidgetAtoms::Forward);
|
2008-02-06 13:56:02 -08:00
|
|
|
case XF86XK_Refresh:
|
2008-02-20 02:10:08 -08:00
|
|
|
return DispatchCommandEvent(nsWidgetAtoms::Reload);
|
2008-02-06 13:56:02 -08:00
|
|
|
case XF86XK_Stop:
|
2008-02-20 02:10:08 -08:00
|
|
|
return DispatchCommandEvent(nsWidgetAtoms::Stop);
|
2008-02-06 13:56:02 -08:00
|
|
|
case XF86XK_Search:
|
2008-02-20 02:10:08 -08:00
|
|
|
return DispatchCommandEvent(nsWidgetAtoms::Search);
|
2008-02-06 13:56:02 -08:00
|
|
|
case XF86XK_Favorites:
|
2008-02-20 02:10:08 -08:00
|
|
|
return DispatchCommandEvent(nsWidgetAtoms::Bookmarks);
|
2008-02-06 13:56:02 -08:00
|
|
|
case XF86XK_HomePage:
|
2008-02-20 02:10:08 -08:00
|
|
|
return DispatchCommandEvent(nsWidgetAtoms::Home);
|
2008-02-06 13:56:02 -08:00
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2008-02-06 13:56:02 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsKeyEvent event(PR_TRUE, NS_KEY_PRESS, this);
|
|
|
|
InitKeyEvent(event, aEvent);
|
|
|
|
if (isKeyDownCancelled) {
|
|
|
|
// If prevent default set for onkeydown, do the same for onkeypress
|
|
|
|
event.flags |= NS_EVENT_FLAG_NO_DEFAULT;
|
|
|
|
}
|
|
|
|
event.charCode = nsConvertCharCodeToUnicode(aEvent);
|
|
|
|
if (event.charCode) {
|
|
|
|
event.keyCode = 0;
|
2008-04-14 21:16:24 -07:00
|
|
|
gint level = GetKeyLevel(aEvent);
|
|
|
|
if ((event.isControl || event.isAlt || event.isMeta) &&
|
|
|
|
(level == 0 || level == 1)) {
|
2008-04-30 16:14:01 -07:00
|
|
|
guint baseState =
|
|
|
|
aEvent->state & ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK |
|
|
|
|
GDK_MOD1_MASK | GDK_MOD4_MASK);
|
2008-04-14 21:16:24 -07:00
|
|
|
// We shold send both shifted char and unshifted char,
|
|
|
|
// all keyboard layout users can use all keys.
|
|
|
|
// Don't change event.charCode. On some keyboard layouts,
|
|
|
|
// ctrl/alt/meta keys are used for inputting some characters.
|
|
|
|
nsAlternativeCharCode altCharCodes(0, 0);
|
|
|
|
// unshifted charcode of current keyboard layout.
|
|
|
|
altCharCodes.mUnshiftedCharCode =
|
2008-04-30 16:14:01 -07:00
|
|
|
GetCharCodeFor(aEvent, baseState, aEvent->group);
|
2008-04-14 21:16:24 -07:00
|
|
|
PRBool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF);
|
|
|
|
// shifted charcode of current keyboard layout.
|
|
|
|
altCharCodes.mShiftedCharCode =
|
2008-04-30 16:14:01 -07:00
|
|
|
GetCharCodeFor(aEvent, baseState | GDK_SHIFT_MASK,
|
|
|
|
aEvent->group);
|
2008-04-14 21:16:24 -07:00
|
|
|
isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF);
|
|
|
|
if (altCharCodes.mUnshiftedCharCode ||
|
|
|
|
altCharCodes.mShiftedCharCode) {
|
|
|
|
event.alternativeCharCodes.AppendElement(altCharCodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isLatin) {
|
|
|
|
// Next, find latin inputtable keyboard layout.
|
2007-11-22 17:38:40 -08:00
|
|
|
GdkKeymapKey *keys;
|
2008-04-14 21:16:24 -07:00
|
|
|
gint count;
|
|
|
|
gint minGroup = -1;
|
|
|
|
if (gdk_keymap_get_entries_for_keyval(NULL, GDK_a,
|
|
|
|
&keys, &count)) {
|
|
|
|
// find the minimum number group for latin inputtable layout
|
|
|
|
for (gint i = 0; i < count && minGroup != 0; ++i) {
|
|
|
|
if (keys[i].level != 0 && keys[i].level != 1)
|
2007-11-22 17:38:40 -08:00
|
|
|
continue;
|
2008-04-14 21:16:24 -07:00
|
|
|
if (minGroup >= 0 && keys[i].group > minGroup)
|
2007-11-22 17:38:40 -08:00
|
|
|
continue;
|
2008-04-14 21:16:24 -07:00
|
|
|
minGroup = keys[i].group;
|
2007-11-22 17:38:40 -08:00
|
|
|
}
|
|
|
|
g_free(keys);
|
2008-04-14 21:16:24 -07:00
|
|
|
}
|
|
|
|
if (minGroup >= 0) {
|
2008-05-05 21:11:52 -07:00
|
|
|
PRUint32 unmodifiedCh =
|
|
|
|
event.isShift ? altCharCodes.mShiftedCharCode :
|
|
|
|
altCharCodes.mUnshiftedCharCode;
|
2008-04-14 21:16:24 -07:00
|
|
|
// unshifted charcode of found keyboard layout.
|
|
|
|
PRUint32 ch =
|
2008-04-30 16:14:01 -07:00
|
|
|
GetCharCodeFor(aEvent, baseState, minGroup);
|
2008-04-14 21:16:24 -07:00
|
|
|
altCharCodes.mUnshiftedCharCode =
|
|
|
|
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
|
|
|
|
// shifted charcode of found keyboard layout.
|
2008-04-30 16:14:01 -07:00
|
|
|
ch = GetCharCodeFor(aEvent, baseState | GDK_SHIFT_MASK,
|
|
|
|
minGroup);
|
2008-04-14 21:16:24 -07:00
|
|
|
altCharCodes.mShiftedCharCode =
|
|
|
|
IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
|
|
|
|
if (altCharCodes.mUnshiftedCharCode ||
|
|
|
|
altCharCodes.mShiftedCharCode) {
|
|
|
|
event.alternativeCharCodes.AppendElement(altCharCodes);
|
|
|
|
}
|
2008-05-05 21:11:52 -07:00
|
|
|
// If the charCode is not Latin, and the level is 0 or 1,
|
|
|
|
// we should replace the charCode to Latin char if Alt and
|
|
|
|
// Meta keys are not pressed. (Alt should be sent the
|
|
|
|
// localized char for accesskey like handling of Web
|
|
|
|
// Applications.)
|
|
|
|
ch = event.isShift ? altCharCodes.mShiftedCharCode :
|
|
|
|
altCharCodes.mUnshiftedCharCode;
|
|
|
|
if (ch && !(event.isAlt || event.isMeta) &&
|
|
|
|
event.charCode == unmodifiedCh) {
|
|
|
|
event.charCode = ch;
|
|
|
|
}
|
2007-11-22 17:38:40 -08:00
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// before we dispatch a key, check if it's the context menu key.
|
|
|
|
// If so, send a context menu key event instead.
|
|
|
|
if (is_context_menu_key(event)) {
|
2008-02-20 02:04:56 -08:00
|
|
|
nsMouseEvent contextMenuEvent(PR_TRUE, NS_CONTEXTMENU, this,
|
|
|
|
nsMouseEvent::eReal,
|
|
|
|
nsMouseEvent::eContextMenuKey);
|
|
|
|
key_event_to_context_menu_event(contextMenuEvent, aEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
DispatchEvent(&contextMenuEvent, status);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// send the key press event
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the event was consumed, return.
|
|
|
|
LOGIM(("status %d\n", status));
|
|
|
|
if (status == nsEventStatus_eConsumeNoDefault) {
|
|
|
|
LOGIM(("key press consumed\n"));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2008-05-05 16:44:18 -07:00
|
|
|
nsWindow::OnKeyReleaseEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
if (IMEFilterEvent(aEvent))
|
|
|
|
return TRUE;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// send the key event as a key up event
|
|
|
|
nsKeyEvent event(PR_TRUE, NS_KEY_UP, this);
|
|
|
|
InitKeyEvent(event, aEvent);
|
|
|
|
|
2007-04-27 09:34:44 -07:00
|
|
|
// unset the key down flag
|
|
|
|
ClearKeyDownFlag(event.keyCode);
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsEventStatus status;
|
2007-03-22 10:30:00 -07:00
|
|
|
DispatchEvent(&event, status);
|
|
|
|
|
|
|
|
// If the event was consumed, return.
|
|
|
|
if (status == nsEventStatus_eConsumeNoDefault) {
|
|
|
|
LOGIM(("key release consumed\n"));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnScrollEvent(GtkWidget *aWidget, GdkEventScroll *aEvent)
|
|
|
|
{
|
|
|
|
// check to see if we should rollup
|
2008-01-14 01:40:45 -08:00
|
|
|
PRBool rolledUp = check_for_rollup(aEvent->window, aEvent->x_root,
|
|
|
|
aEvent->y_root, PR_TRUE);
|
|
|
|
if (gConsumeRollupEvent && rolledUp)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
2007-12-11 00:49:46 -08:00
|
|
|
nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_SCROLL, this);
|
|
|
|
switch (aEvent->direction) {
|
|
|
|
case GDK_SCROLL_UP:
|
|
|
|
event.scrollFlags = nsMouseScrollEvent::kIsVertical;
|
|
|
|
event.delta = -3;
|
|
|
|
break;
|
|
|
|
case GDK_SCROLL_DOWN:
|
|
|
|
event.scrollFlags = nsMouseScrollEvent::kIsVertical;
|
|
|
|
event.delta = 3;
|
|
|
|
break;
|
|
|
|
case GDK_SCROLL_LEFT:
|
|
|
|
event.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
|
2008-02-09 22:08:58 -08:00
|
|
|
event.delta = -1;
|
2007-12-11 00:49:46 -08:00
|
|
|
break;
|
|
|
|
case GDK_SCROLL_RIGHT:
|
|
|
|
event.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
|
2008-02-09 22:08:58 -08:00
|
|
|
event.delta = 1;
|
2007-12-11 00:49:46 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (aEvent->window == mGdkWindow) {
|
2009-02-18 16:11:49 -08:00
|
|
|
// we are the window that the event happened on so no need for expensive WidgetToScreenOffset
|
2007-12-11 00:49:46 -08:00
|
|
|
event.refPoint.x = nscoord(aEvent->x);
|
|
|
|
event.refPoint.y = nscoord(aEvent->y);
|
|
|
|
} else {
|
|
|
|
// XXX we're never quite sure which GdkWindow the event came from due to our custom bubbling
|
|
|
|
// in scroll_event_cb(), so use ScreenToWidget to translate the screen root coordinates into
|
|
|
|
// coordinates relative to this widget.
|
2009-02-18 16:11:49 -08:00
|
|
|
nsIntPoint point(NSToIntFloor(aEvent->x_root), NSToIntFloor(aEvent->y_root));
|
|
|
|
event.refPoint = point - WidgetToScreenOffset();
|
2007-12-11 00:49:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
event.isShift = (aEvent->state & GDK_SHIFT_MASK) != 0;
|
|
|
|
event.isControl = (aEvent->state & GDK_CONTROL_MASK) != 0;
|
|
|
|
event.isAlt = (aEvent->state & GDK_MOD1_MASK) != 0;
|
|
|
|
event.isMeta = (aEvent->state & GDK_MOD4_MASK) != 0;
|
|
|
|
|
|
|
|
event.time = aEvent->time;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnVisibilityNotifyEvent(GtkWidget *aWidget,
|
|
|
|
GdkEventVisibility *aEvent)
|
|
|
|
{
|
2009-11-01 18:03:12 -08:00
|
|
|
LOGDRAW(("Visibility event %i on [%p] %p\n",
|
|
|
|
aEvent->state, this, aEvent->window));
|
|
|
|
|
|
|
|
if (!mGdkWindow)
|
|
|
|
return;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
switch (aEvent->state) {
|
|
|
|
case GDK_VISIBILITY_UNOBSCURED:
|
|
|
|
case GDK_VISIBILITY_PARTIAL:
|
2009-11-01 18:03:12 -08:00
|
|
|
if (mIsFullyObscured && mHasMappedToplevel) {
|
|
|
|
// GDK_EXPOSE events have been ignored, so make sure GDK
|
|
|
|
// doesn't think that the window has already been painted.
|
|
|
|
gdk_window_invalidate_rect(mGdkWindow, NULL, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
mIsFullyObscured = PR_FALSE;
|
|
|
|
|
2008-09-15 08:58:57 -07:00
|
|
|
#ifdef MOZ_PLATFORM_HILDON
|
|
|
|
#ifdef USE_XIM
|
|
|
|
// In Hildon/Maemo, a browser window will get into 'patially visible' state wheneven an
|
|
|
|
// autocomplete feature is dropped down (from urlbar or from an entry form completion),
|
|
|
|
// and there are no much further ways for that to happen in the plaftorm. In such cases, if hildon
|
|
|
|
// virtual keyboard is up, we can not grab focus to any dropdown list. Reason: nsWindow::EnsureGrabs()
|
|
|
|
// calls gdk_pointer_grab() which grabs the pointer (usually a mouse) so that all events are passed
|
|
|
|
// to this it until the pointer is ungrabbed.
|
|
|
|
if(!gIMEVirtualKeyboardOpened)
|
|
|
|
#endif // USE_XIM
|
|
|
|
#endif // MOZ_PLATFORM_HILDON
|
2007-03-22 10:30:00 -07:00
|
|
|
// if we have to retry the grab, retry it.
|
|
|
|
EnsureGrabs();
|
|
|
|
break;
|
|
|
|
default: // includes GDK_VISIBILITY_FULLY_OBSCURED
|
2009-11-01 18:03:12 -08:00
|
|
|
mIsFullyObscured = PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent)
|
|
|
|
{
|
|
|
|
LOG(("nsWindow::OnWindowStateEvent [%p] changed %d new_window_state %d\n",
|
|
|
|
(void *)this, aEvent->changed_mask, aEvent->new_window_state));
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
if (IS_MOZ_CONTAINER(aWidget)) {
|
|
|
|
// This event is notifying the container widget of changes to the
|
|
|
|
// toplevel window. Just detect changes affecting whether windows are
|
|
|
|
// viewable.
|
|
|
|
//
|
|
|
|
// (A visibility notify event is sent to each window that becomes
|
|
|
|
// viewable when the toplevel is mapped, but we can't rely on that for
|
|
|
|
// setting mHasMappedToplevel because these toplevel window state
|
|
|
|
// events are asynchronous. The windows in the hierarchy now may not
|
|
|
|
// be the same windows as when the toplevel was mapped, so they may
|
|
|
|
// not get VisibilityNotify events.)
|
|
|
|
PRBool mapped =
|
|
|
|
!(aEvent->new_window_state &
|
|
|
|
(GDK_WINDOW_STATE_ICONIFIED|GDK_WINDOW_STATE_WITHDRAWN));
|
|
|
|
if (mHasMappedToplevel != mapped) {
|
|
|
|
SetHasMappedToplevel(mapped);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// else the widget is a shell widget.
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
|
|
|
|
|
|
|
|
// We don't care about anything but changes in the maximized/icon
|
|
|
|
// states
|
2007-12-19 03:21:05 -08:00
|
|
|
if ((aEvent->changed_mask
|
|
|
|
& (GDK_WINDOW_STATE_ICONIFIED|GDK_WINDOW_STATE_MAXIMIZED)) == 0) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
|
|
|
|
LOG(("\tIconified\n"));
|
|
|
|
event.mSizeMode = nsSizeMode_Minimized;
|
|
|
|
mSizeState = nsSizeMode_Minimized;
|
|
|
|
}
|
|
|
|
else if (aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
|
|
|
|
LOG(("\tMaximized\n"));
|
|
|
|
event.mSizeMode = nsSizeMode_Maximized;
|
|
|
|
mSizeState = nsSizeMode_Maximized;
|
|
|
|
}
|
2009-08-14 12:56:56 -07:00
|
|
|
else if (aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
|
|
|
|
LOG(("\tFullscreen\n"));
|
|
|
|
event.mSizeMode = nsSizeMode_Fullscreen;
|
|
|
|
mSizeState = nsSizeMode_Fullscreen;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
else {
|
|
|
|
LOG(("\tNormal\n"));
|
|
|
|
event.mSizeMode = nsSizeMode_Normal;
|
|
|
|
mSizeState = nsSizeMode_Normal;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::ThemeChanged()
|
|
|
|
{
|
|
|
|
nsGUIEvent event(PR_TRUE, NS_THEMECHANGED, this);
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow || NS_UNLIKELY(mIsDestroyed))
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Dispatch NS_THEMECHANGED to all child windows
|
|
|
|
GList *children =
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_peek_children(mGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
while (children) {
|
|
|
|
GdkWindow *gdkWin = GDK_WINDOW(children->data);
|
|
|
|
|
|
|
|
nsWindow *win = (nsWindow*) g_object_get_data(G_OBJECT(gdkWin),
|
|
|
|
"nsWindow");
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
if (win && win != this) { // guard against infinite recursion
|
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = win;
|
2007-03-22 10:30:00 -07:00
|
|
|
win->ThemeChanged();
|
2007-04-29 17:46:47 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
children = children->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
nsWindow::OnDragMotionEvent(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData)
|
|
|
|
{
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::OnDragMotionSignal\n"));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mLastButtonReleaseTime) {
|
|
|
|
// The drag ended before it was even setup to handle the end of the drag
|
|
|
|
// So, we fake the button getting released again to release the drag
|
|
|
|
GtkWidget *widget = gtk_grab_get_current();
|
|
|
|
GdkEvent event;
|
|
|
|
gboolean retval;
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
event.type = GDK_BUTTON_RELEASE;
|
|
|
|
event.button.time = mLastButtonReleaseTime;
|
|
|
|
event.button.button = 1;
|
|
|
|
mLastButtonReleaseTime = 0;
|
|
|
|
if (widget) {
|
|
|
|
g_signal_emit_by_name(widget, "button_release_event", &event, &retval);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sIsDraggingOutOf = PR_FALSE;
|
|
|
|
|
|
|
|
// Reset out drag motion timer
|
|
|
|
ResetDragMotionTimer(aWidget, aDragContext, aX, aY, aTime);
|
|
|
|
|
|
|
|
// get our drag context
|
|
|
|
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
|
|
|
|
nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
|
|
|
|
|
|
|
|
// first, figure out which internal widget this drag motion actually
|
|
|
|
// happened on
|
|
|
|
nscoord retx = 0;
|
|
|
|
nscoord rety = 0;
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
GdkWindow *innerWindow = get_inner_gdk_window(aWidget->window, aX, aY,
|
|
|
|
&retx, &rety);
|
|
|
|
nsRefPtr<nsWindow> innerMostWidget = get_window_for_gdk_window(innerWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (!innerMostWidget)
|
|
|
|
innerMostWidget = this;
|
|
|
|
|
|
|
|
// check to see if there was a drag motion window already in place
|
|
|
|
if (mLastDragMotionWindow) {
|
|
|
|
// if it wasn't this
|
|
|
|
if (mLastDragMotionWindow != innerMostWidget) {
|
|
|
|
// send a drag event to the last window that got a motion event
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = mLastDragMotionWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
mLastDragMotionWindow->OnDragLeave();
|
|
|
|
// and enter on the new one
|
|
|
|
innerMostWidget->OnDragEnter(retx, rety);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// if there was no other motion window, then we're starting a
|
|
|
|
// drag. Send an enter event to initiate the drag.
|
|
|
|
|
|
|
|
innerMostWidget->OnDragEnter(retx, rety);
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the last window to the innerMostWidget
|
|
|
|
mLastDragMotionWindow = innerMostWidget;
|
|
|
|
|
|
|
|
// update the drag context
|
|
|
|
dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
|
|
|
|
|
|
|
|
// notify the drag service that we are starting a drag motion.
|
|
|
|
dragSessionGTK->TargetStartDragMotion();
|
|
|
|
|
2007-04-11 21:37:39 -07:00
|
|
|
dragService->FireDragEventAtSource(NS_DRAGDROP_DRAG);
|
|
|
|
|
2008-08-27 05:07:27 -07:00
|
|
|
nsDragEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
InitDragEvent(event);
|
|
|
|
|
|
|
|
// now that we have initialized the event update our drag status
|
|
|
|
UpdateDragStatus(event, aDragContext, dragService);
|
|
|
|
|
|
|
|
event.refPoint.x = retx;
|
|
|
|
event.refPoint.y = rety;
|
|
|
|
event.time = aTime;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
innerMostWidget->DispatchEvent(&event, status);
|
|
|
|
|
|
|
|
// we're done with the drag motion event. notify the drag service.
|
|
|
|
dragSessionGTK->TargetEndDragMotion(aWidget, aDragContext, aTime);
|
|
|
|
|
|
|
|
// and unset our context
|
|
|
|
dragSessionGTK->TargetSetLastContext(0, 0, 0);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnDragLeaveEvent(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData)
|
|
|
|
{
|
|
|
|
// XXX Do we want to pass this on only if the event's subwindow is null?
|
|
|
|
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::OnDragLeaveSignal(%p)\n", (void*)this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
sIsDraggingOutOf = PR_TRUE;
|
|
|
|
|
|
|
|
// make sure to unset any drag motion timers here.
|
|
|
|
ResetDragMotionTimer(0, 0, 0, 0, 0);
|
|
|
|
|
2009-03-07 09:08:51 -08:00
|
|
|
if (mDragLeaveTimer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// create a fast timer - we're delaying the drag leave until the
|
|
|
|
// next mainloop in hopes that we might be able to get a drag drop
|
|
|
|
// signal
|
|
|
|
mDragLeaveTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
|
|
NS_ASSERTION(mDragLeaveTimer, "Failed to create drag leave timer!");
|
|
|
|
// fire this baby asafp, but not too quickly... see bug 216800 ;-)
|
|
|
|
mDragLeaveTimer->InitWithFuncCallback(DragLeaveTimerCallback,
|
|
|
|
(void *)this,
|
|
|
|
20, nsITimer::TYPE_ONE_SHOT);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
nsWindow::OnDragDropEvent(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
guint aTime,
|
|
|
|
gpointer *aData)
|
|
|
|
|
|
|
|
{
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::OnDragDropSignal\n"));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// get our drag context
|
|
|
|
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
|
|
|
|
nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
|
|
|
|
|
|
|
|
nscoord retx = 0;
|
|
|
|
nscoord rety = 0;
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
GdkWindow *innerWindow = get_inner_gdk_window(aWidget->window, aX, aY,
|
|
|
|
&retx, &rety);
|
|
|
|
nsRefPtr<nsWindow> innerMostWidget = get_window_for_gdk_window(innerWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// set this now before any of the drag enter or leave events happen
|
|
|
|
dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
|
|
|
|
|
|
|
|
if (!innerMostWidget)
|
|
|
|
innerMostWidget = this;
|
|
|
|
|
|
|
|
// check to see if there was a drag motion window already in place
|
|
|
|
if (mLastDragMotionWindow) {
|
|
|
|
// if it wasn't this
|
|
|
|
if (mLastDragMotionWindow != innerMostWidget) {
|
|
|
|
// send a drag event to the last window that got a motion event
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = mLastDragMotionWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
mLastDragMotionWindow->OnDragLeave();
|
|
|
|
// and enter on the new one
|
|
|
|
innerMostWidget->OnDragEnter(retx, rety);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// if there was no other motion window, send an enter event to
|
|
|
|
// initiate the drag session.
|
|
|
|
innerMostWidget->OnDragEnter(retx, rety);
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear any drag leave timer that might be pending so that it
|
|
|
|
// doesn't get processed when we actually go out to get data.
|
|
|
|
if (mDragLeaveTimer) {
|
|
|
|
mDragLeaveTimer->Cancel();
|
2009-03-07 09:08:51 -08:00
|
|
|
mDragLeaveTimer = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// set the last window to this
|
|
|
|
mLastDragMotionWindow = innerMostWidget;
|
|
|
|
|
|
|
|
// What we do here is dispatch a new drag motion event to
|
|
|
|
// re-validate the drag target and then we do the drop. The events
|
|
|
|
// look the same except for the type.
|
|
|
|
|
2008-08-27 05:07:27 -07:00
|
|
|
nsDragEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
InitDragEvent(event);
|
|
|
|
|
|
|
|
// now that we have initialized the event update our drag status
|
|
|
|
UpdateDragStatus(event, aDragContext, dragService);
|
|
|
|
|
|
|
|
event.refPoint.x = retx;
|
|
|
|
event.refPoint.y = rety;
|
|
|
|
event.time = aTime;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
innerMostWidget->DispatchEvent(&event, status);
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
// We need to check innerMostWidget->mIsDestroyed here because the nsRefPtr
|
|
|
|
// only protects innerMostWidget from being deleted, it does NOT protect
|
|
|
|
// against nsView::~nsView() calling Destroy() on it, bug 378670.
|
|
|
|
if (!innerMostWidget->mIsDestroyed) {
|
2008-09-01 12:51:12 -07:00
|
|
|
nsDragEvent event(PR_TRUE, NS_DRAGDROP_DROP, innerMostWidget);
|
2007-04-29 17:46:47 -07:00
|
|
|
event.refPoint.x = retx;
|
|
|
|
event.refPoint.y = rety;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-01 12:51:12 -07:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
2007-04-29 17:46:47 -07:00
|
|
|
innerMostWidget->DispatchEvent(&event, status);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// before we unset the context we need to do a drop_finish
|
|
|
|
|
|
|
|
gdk_drop_finish(aDragContext, TRUE, aTime);
|
|
|
|
|
|
|
|
// after a drop takes place we need to make sure that the drag
|
|
|
|
// service doesn't think that it still has a context. if the other
|
|
|
|
// way ( besides the drop ) to end a drag event is during the leave
|
|
|
|
// event and and that case is handled in that handler.
|
|
|
|
dragSessionGTK->TargetSetLastContext(0, 0, 0);
|
|
|
|
|
2008-04-16 14:06:57 -07:00
|
|
|
// clear the mLastDragMotion window
|
2007-03-22 10:30:00 -07:00
|
|
|
mLastDragMotionWindow = 0;
|
|
|
|
|
|
|
|
// Make sure to end the drag session. If this drag started in a
|
|
|
|
// different app, we won't get a drag_end signal to end it from.
|
2009-04-20 17:54:46 -07:00
|
|
|
gint x, y;
|
|
|
|
GdkDisplay* display = gdk_display_get_default();
|
|
|
|
if (display) {
|
|
|
|
// get the current cursor position
|
|
|
|
gdk_display_get_pointer(display, NULL, &x, &y, NULL);
|
|
|
|
((nsDragService *)dragService.get())->SetDragEndPoint(nsIntPoint(x, y));
|
|
|
|
}
|
2007-04-11 21:37:39 -07:00
|
|
|
dragService->EndDragSession(PR_TRUE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
GtkSelectionData *aSelectionData,
|
|
|
|
guint aInfo,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData)
|
|
|
|
{
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::OnDragDataReceived(%p)\n", (void*)this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// get our drag context
|
|
|
|
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
|
|
|
|
nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
|
|
|
|
|
|
|
|
dragSessionGTK->TargetDataReceived(aWidget, aDragContext, aX, aY,
|
|
|
|
aSelectionData, aInfo, aTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnDragLeave(void)
|
|
|
|
{
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::OnDragLeave(%p)\n", (void*)this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-27 05:07:27 -07:00
|
|
|
nsDragEvent event(PR_TRUE, NS_DRAGDROP_EXIT, this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
|
|
|
|
|
|
|
|
if (dragService) {
|
|
|
|
nsCOMPtr<nsIDragSession> currentDragSession;
|
|
|
|
dragService->GetCurrentSession(getter_AddRefs(currentDragSession));
|
|
|
|
|
|
|
|
if (currentDragSession) {
|
|
|
|
nsCOMPtr<nsIDOMNode> sourceNode;
|
|
|
|
currentDragSession->GetSourceNode(getter_AddRefs(sourceNode));
|
|
|
|
|
|
|
|
if (!sourceNode) {
|
|
|
|
// We're leaving a window while doing a drag that was
|
|
|
|
// initiated in a different app. End the drag session,
|
|
|
|
// since we're done with it for now (until the user
|
|
|
|
// drags back into mozilla).
|
2007-04-11 21:37:39 -07:00
|
|
|
dragService->EndDragSession(PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::OnDragEnter(nscoord aX, nscoord aY)
|
|
|
|
{
|
|
|
|
// XXX Do we want to pass this on only if the event's subwindow is null?
|
|
|
|
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::OnDragEnter(%p)\n", (void*)this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
|
|
|
|
|
|
|
|
if (dragService) {
|
|
|
|
// Make sure that the drag service knows we're now dragging.
|
|
|
|
dragService->StartDragSession();
|
|
|
|
}
|
|
|
|
|
2008-08-27 05:07:27 -07:00
|
|
|
nsDragEvent event(PR_TRUE, NS_DRAGDROP_ENTER, this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
event.refPoint.x = aX;
|
|
|
|
event.refPoint.y = aY;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
GetBrandName(nsXPIDLString& brandName)
|
|
|
|
{
|
2009-02-27 17:47:40 -08:00
|
|
|
nsCOMPtr<nsIStringBundleService> bundleService =
|
2007-03-22 10:30:00 -07:00
|
|
|
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIStringBundle> bundle;
|
|
|
|
if (bundleService)
|
|
|
|
bundleService->CreateBundle(
|
|
|
|
"chrome://branding/locale/brand.properties",
|
|
|
|
getter_AddRefs(bundle));
|
|
|
|
|
|
|
|
if (bundle)
|
|
|
|
bundle->GetStringFromName(
|
|
|
|
NS_LITERAL_STRING("brandShortName").get(),
|
|
|
|
getter_Copies(brandName));
|
|
|
|
|
|
|
|
if (brandName.IsEmpty())
|
|
|
|
brandName.Assign(NS_LITERAL_STRING("Mozilla"));
|
|
|
|
}
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
static GdkWindow *
|
|
|
|
CreateGdkWindow(GdkWindow *parent, GtkWidget *widget)
|
|
|
|
{
|
|
|
|
GdkWindowAttr attributes;
|
|
|
|
gint attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
|
|
|
|
|
|
attributes.event_mask = (GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
|
|
|
|
GDK_VISIBILITY_NOTIFY_MASK |
|
|
|
|
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
|
|
|
|
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
|
|
|
#ifdef HAVE_GTK_MOTION_HINTS
|
|
|
|
GDK_POINTER_MOTION_HINT_MASK |
|
|
|
|
#endif
|
|
|
|
GDK_POINTER_MOTION_MASK);
|
|
|
|
|
|
|
|
attributes.width = 1;
|
|
|
|
attributes.height = 1;
|
|
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
|
|
attributes.visual = gtk_widget_get_visual(widget);
|
|
|
|
attributes.colormap = gtk_widget_get_colormap(widget);
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
|
|
|
|
|
|
GdkWindow *window = gdk_window_new(parent, &attributes, attributes_mask);
|
|
|
|
gdk_window_set_user_data(window, widget);
|
|
|
|
|
|
|
|
/* set the default pixmap to None so that you don't end up with the
|
|
|
|
gtk default which is BlackPixel. */
|
|
|
|
gdk_window_set_back_pixmap(window, NULL, FALSE);
|
|
|
|
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
2009-09-23 23:18:10 -07:00
|
|
|
nsWindow::Create(nsIWidget *aParent,
|
|
|
|
nsNativeWidget aNativeParent,
|
|
|
|
const nsIntRect &aRect,
|
|
|
|
EVENT_CALLBACK aHandleEventFunction,
|
|
|
|
nsIDeviceContext *aContext,
|
|
|
|
nsIAppShell *aAppShell,
|
|
|
|
nsIToolkit *aToolkit,
|
|
|
|
nsWidgetInitData *aInitData)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// only set the base parent if we're going to be a dialog or a
|
|
|
|
// toplevel
|
|
|
|
nsIWidget *baseParent = aInitData &&
|
|
|
|
(aInitData->mWindowType == eWindowType_dialog ||
|
|
|
|
aInitData->mWindowType == eWindowType_toplevel ||
|
|
|
|
aInitData->mWindowType == eWindowType_invisible) ?
|
|
|
|
nsnull : aParent;
|
|
|
|
|
2007-10-07 22:02:38 -07:00
|
|
|
NS_ASSERTION(!mWindowGroup, "already have window group (leaking it)");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// initialize all the common bits of this class
|
|
|
|
BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
|
|
|
|
aAppShell, aToolkit, aInitData);
|
|
|
|
|
|
|
|
// Do we need to listen for resizes?
|
|
|
|
PRBool listenForResizes = PR_FALSE;;
|
|
|
|
if (aNativeParent || (aInitData && aInitData->mListenForResizes))
|
|
|
|
listenForResizes = PR_TRUE;
|
|
|
|
|
|
|
|
// and do our common creation
|
|
|
|
CommonCreate(aParent, listenForResizes);
|
|
|
|
|
|
|
|
// save our bounds
|
|
|
|
mBounds = aRect;
|
2009-09-24 02:32:20 -07:00
|
|
|
if (mWindowType != eWindowType_child &&
|
|
|
|
mWindowType != eWindowType_plugin) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// The window manager might place us. Indicate that if we're
|
|
|
|
// shown, we want to go through
|
|
|
|
// nsWindow::NativeResize(x,y,w,h) to maybe set our own
|
|
|
|
// position.
|
|
|
|
mNeedsMove = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// figure out our parent window
|
2009-07-26 18:39:36 -07:00
|
|
|
GtkWidget *parentMozContainer = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
GtkContainer *parentGtkContainer = nsnull;
|
|
|
|
GdkWindow *parentGdkWindow = nsnull;
|
|
|
|
GtkWindow *topLevelParent = nsnull;
|
|
|
|
|
|
|
|
if (aParent)
|
|
|
|
parentGdkWindow = GDK_WINDOW(aParent->GetNativeData(NS_NATIVE_WINDOW));
|
|
|
|
else if (aNativeParent && GDK_IS_WINDOW(aNativeParent))
|
|
|
|
parentGdkWindow = GDK_WINDOW(aNativeParent);
|
|
|
|
else if (aNativeParent && GTK_IS_CONTAINER(aNativeParent))
|
|
|
|
parentGtkContainer = GTK_CONTAINER(aNativeParent);
|
|
|
|
|
|
|
|
if (parentGdkWindow) {
|
2009-07-26 18:39:36 -07:00
|
|
|
// get the widget for the window - it should be a moz container
|
|
|
|
parentMozContainer = get_gtk_widget_for_gdk_window(parentGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!IS_MOZ_CONTAINER(parentMozContainer))
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// get the toplevel window just in case someone needs to use it
|
|
|
|
// for setting transients or whatever.
|
|
|
|
topLevelParent =
|
|
|
|
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(parentMozContainer)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// ok, create our windows
|
|
|
|
switch (mWindowType) {
|
|
|
|
case eWindowType_dialog:
|
|
|
|
case eWindowType_popup:
|
|
|
|
case eWindowType_toplevel:
|
|
|
|
case eWindowType_invisible: {
|
|
|
|
mIsTopLevel = PR_TRUE;
|
|
|
|
|
|
|
|
nsXPIDLString brandName;
|
|
|
|
GetBrandName(brandName);
|
|
|
|
NS_ConvertUTF16toUTF8 cBrand(brandName);
|
|
|
|
|
|
|
|
if (mWindowType == eWindowType_dialog) {
|
|
|
|
mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
SetDefaultIcon();
|
|
|
|
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Dialog", cBrand.get());
|
|
|
|
gtk_window_set_type_hint(GTK_WINDOW(mShell),
|
|
|
|
GDK_WINDOW_TYPE_HINT_DIALOG);
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(mShell),
|
|
|
|
topLevelParent);
|
|
|
|
mTransientParent = topLevelParent;
|
|
|
|
// add ourselves to the parent window's window group
|
|
|
|
if (!topLevelParent) {
|
|
|
|
gtk_widget_realize(mShell);
|
|
|
|
GdkWindow* dialoglead = mShell->window;
|
|
|
|
gdk_window_set_group(dialoglead, dialoglead);
|
|
|
|
}
|
2009-07-26 18:39:36 -07:00
|
|
|
if (parentGdkWindow) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsWindow *parentnsWindow =
|
2009-07-26 18:39:36 -07:00
|
|
|
get_window_for_gdk_window(parentGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(parentnsWindow,
|
2009-07-26 18:39:36 -07:00
|
|
|
"no nsWindow for parentGdkWindow!");
|
2007-03-22 10:30:00 -07:00
|
|
|
if (parentnsWindow && parentnsWindow->mWindowGroup) {
|
|
|
|
gtk_window_group_add_window(parentnsWindow->mWindowGroup,
|
|
|
|
GTK_WINDOW(mShell));
|
|
|
|
// store this in case any children are created
|
|
|
|
mWindowGroup = parentnsWindow->mWindowGroup;
|
2007-10-07 22:02:38 -07:00
|
|
|
g_object_ref(G_OBJECT(mWindowGroup));
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("adding window %p to group %p\n",
|
|
|
|
(void *)mShell, (void *)mWindowGroup));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mWindowType == eWindowType_popup) {
|
2008-03-14 09:26:13 -07:00
|
|
|
// treat popups with a parent as top level windows
|
|
|
|
if (mParent) {
|
|
|
|
mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel", cBrand.get());
|
|
|
|
gtk_window_set_decorated(GTK_WINDOW(mShell), FALSE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mShell = gtk_window_new(GTK_WINDOW_POPUP);
|
|
|
|
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Popup", cBrand.get());
|
|
|
|
}
|
2008-03-08 03:32:25 -08:00
|
|
|
|
|
|
|
GdkWindowTypeHint gtkTypeHint;
|
|
|
|
switch (aInitData->mPopupHint) {
|
|
|
|
case ePopupTypeMenu:
|
|
|
|
gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
|
|
|
|
break;
|
|
|
|
case ePopupTypeTooltip:
|
|
|
|
gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
|
|
|
|
break;
|
2007-11-28 12:18:11 -08:00
|
|
|
}
|
2008-03-08 03:32:25 -08:00
|
|
|
gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (topLevelParent) {
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(mShell),
|
|
|
|
topLevelParent);
|
|
|
|
mTransientParent = topLevelParent;
|
|
|
|
|
|
|
|
if (topLevelParent->group) {
|
|
|
|
gtk_window_group_add_window(topLevelParent->group,
|
|
|
|
GTK_WINDOW(mShell));
|
|
|
|
mWindowGroup = topLevelParent->group;
|
2007-10-07 22:02:38 -07:00
|
|
|
g_object_ref(G_OBJECT(mWindowGroup));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // must be eWindowType_toplevel
|
|
|
|
mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
SetDefaultIcon();
|
|
|
|
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel", cBrand.get());
|
|
|
|
|
|
|
|
// each toplevel window gets its own window group
|
|
|
|
mWindowGroup = gtk_window_group_new();
|
|
|
|
|
|
|
|
// and add ourselves to the window group
|
|
|
|
LOG(("adding window %p to new group %p\n",
|
|
|
|
(void *)mShell, (void *)mWindowGroup));
|
|
|
|
gtk_window_group_add_window(mWindowGroup, GTK_WINDOW(mShell));
|
|
|
|
}
|
|
|
|
|
|
|
|
// create our container
|
2009-07-26 18:39:36 -07:00
|
|
|
GtkWidget *container = moz_container_new();
|
|
|
|
mContainer = MOZ_CONTAINER(container);
|
|
|
|
gtk_container_add(GTK_CONTAINER(mShell), container);
|
|
|
|
gtk_widget_realize(container);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-21 17:44:55 -07:00
|
|
|
// Don't let GTK mess with the shapes of our GdkWindows
|
2009-07-26 18:39:36 -07:00
|
|
|
GTK_PRIVATE_SET_FLAG(container, GTK_HAS_SHAPE_MASK);
|
2009-07-21 17:44:55 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// make sure this is the focus widget in the container
|
2009-07-26 18:39:36 -07:00
|
|
|
gtk_window_set_focus(GTK_WINDOW(mShell), container);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-26 18:40:46 -07:00
|
|
|
// the drawing window
|
|
|
|
mGdkWindow = container->window;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mWindowType == eWindowType_popup) {
|
|
|
|
// gdk does not automatically set the cursor for "temporary"
|
|
|
|
// windows, which are what gtk uses for popups.
|
|
|
|
|
|
|
|
mCursor = eCursor_wait; // force SetCursor to actually set the
|
|
|
|
// cursor, even though our internal state
|
|
|
|
// indicates that we already have the
|
|
|
|
// standard cursor.
|
|
|
|
SetCursor(eCursor_standard);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2009-09-24 02:32:20 -07:00
|
|
|
case eWindowType_plugin:
|
2007-03-22 10:30:00 -07:00
|
|
|
case eWindowType_child: {
|
|
|
|
if (parentMozContainer) {
|
2009-07-26 18:39:36 -07:00
|
|
|
mGdkWindow = CreateGdkWindow(parentGdkWindow, parentMozContainer);
|
2009-11-01 18:03:12 -08:00
|
|
|
nsWindow *parentnsWindow =
|
|
|
|
get_window_for_gdk_window(parentGdkWindow);
|
|
|
|
if (parentnsWindow)
|
|
|
|
mHasMappedToplevel = parentnsWindow->mHasMappedToplevel;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else if (parentGtkContainer) {
|
2009-07-26 18:39:36 -07:00
|
|
|
GtkWidget *container = moz_container_new();
|
|
|
|
mContainer = MOZ_CONTAINER(container);
|
|
|
|
gtk_container_add(parentGtkContainer, container);
|
|
|
|
gtk_widget_realize(container);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-21 17:44:55 -07:00
|
|
|
// Don't let GTK mess with the shapes of our GdkWindows
|
2009-07-26 18:39:36 -07:00
|
|
|
GTK_PRIVATE_SET_FLAG(container, GTK_HAS_SHAPE_MASK);
|
2009-07-21 17:44:55 -07:00
|
|
|
|
2009-07-26 18:40:46 -07:00
|
|
|
mGdkWindow = container->window;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_WARNING("Warning: tried to create a new child widget with no parent!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Disable the double buffer because it will make the caret crazy
|
|
|
|
// For bug#153805 (Gtk2 double buffer makes carets misbehave)
|
2008-08-06 13:48:55 -07:00
|
|
|
// DirectFB's expose code depends on gtk double buffering
|
|
|
|
// XXX - I think this bug is probably dead, we can just use gtk's
|
|
|
|
// double-buffering everywhere
|
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mContainer)
|
|
|
|
gtk_widget_set_double_buffered (GTK_WIDGET(mContainer),FALSE);
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
// label the drawing window with this object so we can find our way home
|
|
|
|
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mContainer)
|
|
|
|
g_object_set_data(G_OBJECT(mContainer), "nsWindow", this);
|
|
|
|
|
|
|
|
if (mShell)
|
|
|
|
g_object_set_data(G_OBJECT(mShell), "nsWindow", this);
|
|
|
|
|
|
|
|
// attach listeners for events
|
|
|
|
if (mShell) {
|
|
|
|
g_signal_connect(G_OBJECT(mShell), "configure_event",
|
|
|
|
G_CALLBACK(configure_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mShell), "delete_event",
|
|
|
|
G_CALLBACK(delete_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mShell), "window_state_event",
|
|
|
|
G_CALLBACK(window_state_event_cb), NULL);
|
|
|
|
|
|
|
|
GtkSettings* default_settings = gtk_settings_get_default();
|
|
|
|
g_signal_connect_after(default_settings,
|
|
|
|
"notify::gtk-theme-name",
|
|
|
|
G_CALLBACK(theme_changed_cb), this);
|
|
|
|
g_signal_connect_after(default_settings,
|
|
|
|
"notify::gtk-font-name",
|
|
|
|
G_CALLBACK(theme_changed_cb), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mContainer) {
|
2009-05-14 19:14:45 -07:00
|
|
|
g_signal_connect(G_OBJECT(mContainer), "unrealize",
|
|
|
|
G_CALLBACK(container_unrealize_cb), NULL);
|
2007-03-22 10:30:00 -07:00
|
|
|
g_signal_connect_after(G_OBJECT(mContainer), "size_allocate",
|
|
|
|
G_CALLBACK(size_allocate_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "expose_event",
|
|
|
|
G_CALLBACK(expose_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "enter_notify_event",
|
|
|
|
G_CALLBACK(enter_notify_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "leave_notify_event",
|
|
|
|
G_CALLBACK(leave_notify_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "motion_notify_event",
|
|
|
|
G_CALLBACK(motion_notify_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "button_press_event",
|
|
|
|
G_CALLBACK(button_press_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "button_release_event",
|
|
|
|
G_CALLBACK(button_release_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "focus_in_event",
|
|
|
|
G_CALLBACK(focus_in_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "focus_out_event",
|
|
|
|
G_CALLBACK(focus_out_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "key_press_event",
|
|
|
|
G_CALLBACK(key_press_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "key_release_event",
|
|
|
|
G_CALLBACK(key_release_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "scroll_event",
|
|
|
|
G_CALLBACK(scroll_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "visibility_notify_event",
|
|
|
|
G_CALLBACK(visibility_notify_event_cb), NULL);
|
2009-11-01 18:03:12 -08:00
|
|
|
g_signal_connect(G_OBJECT(mContainer), "hierarchy_changed",
|
|
|
|
G_CALLBACK(hierarchy_changed_cb), NULL);
|
|
|
|
// Initialize mHasMappedToplevel.
|
|
|
|
hierarchy_changed_cb(GTK_WIDGET(mContainer), NULL);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gtk_drag_dest_set((GtkWidget *)mContainer,
|
|
|
|
(GtkDestDefaults)0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
(GdkDragAction)0);
|
|
|
|
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "drag_motion",
|
|
|
|
G_CALLBACK(drag_motion_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "drag_leave",
|
|
|
|
G_CALLBACK(drag_leave_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "drag_drop",
|
|
|
|
G_CALLBACK(drag_drop_event_cb), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(mContainer), "drag_data_received",
|
|
|
|
G_CALLBACK(drag_data_received_event_cb), NULL);
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
// We create input contexts for all containers, except for
|
|
|
|
// toplevel popup windows
|
|
|
|
if (mWindowType != eWindowType_popup)
|
|
|
|
IMECreateContext();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG(("nsWindow [%p]\n", (void *)this));
|
|
|
|
if (mShell) {
|
|
|
|
LOG(("\tmShell %p %p %lx\n", (void *)mShell, (void *)mShell->window,
|
|
|
|
GDK_WINDOW_XWINDOW(mShell->window)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mContainer) {
|
|
|
|
LOG(("\tmContainer %p %p %lx\n", (void *)mContainer,
|
|
|
|
(void *)GTK_WIDGET(mContainer)->window,
|
|
|
|
GDK_WINDOW_XWINDOW(GTK_WIDGET(mContainer)->window)));
|
|
|
|
}
|
2009-07-26 18:40:46 -07:00
|
|
|
else if (mGdkWindow) {
|
2009-07-26 18:39:36 -07:00
|
|
|
LOG(("\tmGdkWindow %p %lx\n", (void *)mGdkWindow,
|
|
|
|
GDK_WINDOW_XWINDOW(mGdkWindow)));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// resize so that everything is set to the right dimensions
|
2007-06-05 12:57:38 -07:00
|
|
|
if (!mIsTopLevel)
|
|
|
|
Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
nsresult rv;
|
|
|
|
if (!sAccessibilityChecked) {
|
|
|
|
sAccessibilityChecked = PR_TRUE;
|
|
|
|
|
|
|
|
//check if accessibility enabled/disabled by environment variable
|
|
|
|
const char *envValue = PR_GetEnv(sAccEnv);
|
|
|
|
if (envValue) {
|
2008-09-15 17:00:09 -07:00
|
|
|
sAccessibilityEnabled = atoi(envValue) != 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("Accessibility Env %s=%s\n", sAccEnv, envValue));
|
|
|
|
}
|
|
|
|
//check gconf-2 setting
|
|
|
|
else {
|
|
|
|
nsCOMPtr<nsIPrefBranch> sysPrefService =
|
|
|
|
do_GetService(sSysPrefService, &rv);
|
|
|
|
if (NS_SUCCEEDED(rv) && sysPrefService) {
|
|
|
|
|
|
|
|
// do the work to get gconf setting.
|
|
|
|
// will be done soon later.
|
|
|
|
sysPrefService->GetBoolPref(sAccessibilityKey,
|
|
|
|
&sAccessibilityEnabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sAccessibilityEnabled) {
|
|
|
|
LOG(("nsWindow:: Create Toplevel Accessibility\n"));
|
|
|
|
CreateRootAccessible();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_DFB
|
|
|
|
if (!mDFB) {
|
|
|
|
DirectFBCreate( &mDFB );
|
|
|
|
|
|
|
|
D_ASSUME( mDFB != NULL );
|
|
|
|
|
|
|
|
if (mDFB)
|
|
|
|
mDFB->GetDisplayLayer( mDFB, DLID_PRIMARY, &mDFBLayer );
|
|
|
|
|
|
|
|
D_ASSUME( mDFBLayer != NULL );
|
|
|
|
|
|
|
|
if (mDFBLayer)
|
|
|
|
mDFBLayer->GetCursorPosition( mDFBLayer, &mDFBCursorX, &mDFBCursorY );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetWindowClass(const nsAString &xulWinType)
|
|
|
|
{
|
|
|
|
if (!mShell)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
nsXPIDLString brandName;
|
|
|
|
GetBrandName(brandName);
|
|
|
|
|
|
|
|
XClassHint *class_hint = XAllocClassHint();
|
|
|
|
if (!class_hint)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
const char *role = NULL;
|
|
|
|
class_hint->res_name = ToNewCString(xulWinType);
|
|
|
|
if (!class_hint->res_name) {
|
|
|
|
XFree(class_hint);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
class_hint->res_class = ToNewCString(brandName);
|
|
|
|
if (!class_hint->res_class) {
|
|
|
|
nsMemory::Free(class_hint->res_name);
|
|
|
|
XFree(class_hint);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse res_name into a name and role. Characters other than
|
|
|
|
// [A-Za-z0-9_-] are converted to '_'. Anything after the first
|
|
|
|
// colon is assigned to role; if there's no colon, assign the
|
|
|
|
// whole thing to both role and res_name.
|
|
|
|
for (char *c = class_hint->res_name; *c; c++) {
|
|
|
|
if (':' == *c) {
|
|
|
|
*c = 0;
|
|
|
|
role = c + 1;
|
|
|
|
}
|
|
|
|
else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
|
|
|
|
*c = '_';
|
|
|
|
}
|
|
|
|
class_hint->res_name[0] = toupper(class_hint->res_name[0]);
|
|
|
|
if (!role) role = class_hint->res_name;
|
|
|
|
|
|
|
|
gdk_window_set_role(GTK_WIDGET(mShell)->window, role);
|
|
|
|
// Can't use gtk_window_set_wmclass() for this; it prints
|
|
|
|
// a warning & refuses to make the change.
|
|
|
|
XSetClassHint(GDK_DISPLAY(),
|
|
|
|
GDK_WINDOW_XWINDOW(GTK_WIDGET(mShell)->window),
|
|
|
|
class_hint);
|
|
|
|
nsMemory::Free(class_hint->res_class);
|
|
|
|
nsMemory::Free(class_hint->res_name);
|
|
|
|
XFree(class_hint);
|
2008-08-06 13:48:55 -07:00
|
|
|
#else /* MOZ_X11 */
|
|
|
|
|
|
|
|
char *res_name;
|
|
|
|
|
|
|
|
res_name = ToNewCString(xulWinType);
|
|
|
|
if (!res_name)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
printf("WARN: res_name = '%s'\n", res_name);
|
|
|
|
|
|
|
|
|
|
|
|
const char *role = NULL;
|
|
|
|
|
|
|
|
// Parse res_name into a name and role. Characters other than
|
|
|
|
// [A-Za-z0-9_-] are converted to '_'. Anything after the first
|
|
|
|
// colon is assigned to role; if there's no colon, assign the
|
|
|
|
// whole thing to both role and res_name.
|
|
|
|
for (char *c = res_name; *c; c++) {
|
|
|
|
if (':' == *c) {
|
|
|
|
*c = 0;
|
|
|
|
role = c + 1;
|
|
|
|
}
|
|
|
|
else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
|
|
|
|
*c = '_';
|
|
|
|
}
|
|
|
|
res_name[0] = toupper(res_name[0]);
|
|
|
|
if (!role) role = res_name;
|
|
|
|
|
|
|
|
gdk_window_set_role(GTK_WIDGET(mShell)->window, role);
|
|
|
|
|
|
|
|
nsMemory::Free(res_name);
|
|
|
|
|
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::NativeResize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
|
|
|
|
{
|
|
|
|
LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
|
|
|
|
aWidth, aHeight));
|
|
|
|
|
|
|
|
ResizeTransparencyBitmap(aWidth, aHeight);
|
|
|
|
|
|
|
|
// clear our resize flag
|
|
|
|
mNeedsResize = PR_FALSE;
|
|
|
|
|
|
|
|
if (mIsTopLevel) {
|
|
|
|
gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
|
|
|
|
}
|
|
|
|
else if (mContainer) {
|
2009-07-26 18:40:46 -07:00
|
|
|
GtkWidget *widget = GTK_WIDGET(mContainer);
|
2007-03-22 10:30:00 -07:00
|
|
|
GtkAllocation allocation;
|
2009-07-26 18:40:46 -07:00
|
|
|
allocation.x = widget->allocation.x;
|
|
|
|
allocation.y = widget->allocation.y;
|
2007-03-22 10:30:00 -07:00
|
|
|
allocation.width = aWidth;
|
|
|
|
allocation.height = aHeight;
|
2009-07-26 18:40:46 -07:00
|
|
|
gtk_widget_size_allocate(widget, &allocation);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-07-26 18:40:46 -07:00
|
|
|
else if (mGdkWindow) {
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_resize(mGdkWindow, aWidth, aHeight);
|
2009-03-31 03:03:43 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::NativeResize(PRInt32 aX, PRInt32 aY,
|
|
|
|
PRInt32 aWidth, PRInt32 aHeight,
|
|
|
|
PRBool aRepaint)
|
|
|
|
{
|
|
|
|
mNeedsResize = PR_FALSE;
|
|
|
|
mNeedsMove = PR_FALSE;
|
|
|
|
|
|
|
|
LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
|
|
|
|
aX, aY, aWidth, aHeight));
|
|
|
|
|
|
|
|
ResizeTransparencyBitmap(aWidth, aHeight);
|
|
|
|
|
|
|
|
if (mIsTopLevel) {
|
2007-11-28 12:18:11 -08:00
|
|
|
// We only move the toplevel window if someone has
|
|
|
|
// actually placed the window somewhere. If no placement
|
|
|
|
// has taken place, we just let the window manager Do The
|
|
|
|
// Right Thing.
|
|
|
|
if (mPlaced)
|
|
|
|
gtk_window_move(GTK_WINDOW(mShell), aX, aY);
|
|
|
|
|
|
|
|
gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else if (mContainer) {
|
|
|
|
GtkAllocation allocation;
|
2009-07-26 18:40:46 -07:00
|
|
|
allocation.x = aX;
|
|
|
|
allocation.y = aY;
|
2007-03-22 10:30:00 -07:00
|
|
|
allocation.width = aWidth;
|
|
|
|
allocation.height = aHeight;
|
|
|
|
gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
|
|
|
|
}
|
2009-07-26 18:39:36 -07:00
|
|
|
else if (mGdkWindow) {
|
|
|
|
gdk_window_move_resize(mGdkWindow, aX, aY, aWidth, aHeight);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::NativeShow (PRBool aAction)
|
|
|
|
{
|
|
|
|
if (aAction) {
|
|
|
|
// GTK wants us to set the window mask before we show the window
|
|
|
|
// for the first time, or setting the mask later won't work.
|
|
|
|
// GTK also wants us to NOT set the window mask if we're not really
|
|
|
|
// going to need it, because GTK won't let us unset the mask properly
|
|
|
|
// later.
|
|
|
|
// So, we delay setting the mask until the last moment: when the window
|
|
|
|
// is shown.
|
|
|
|
// XXX that may or may not be true for GTK+ 2.x
|
|
|
|
if (mTransparencyBitmap) {
|
|
|
|
ApplyTransparencyBitmap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// unset our flag now that our window has been shown
|
|
|
|
mNeedsShow = PR_FALSE;
|
|
|
|
|
|
|
|
if (mIsTopLevel) {
|
|
|
|
// Set up usertime/startupID metadata for the created window.
|
|
|
|
if (mWindowType != eWindowType_invisible) {
|
|
|
|
SetUserTimeAndStartupIDForActivatedWindow(mShell);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_widget_show(GTK_WIDGET(mContainer));
|
|
|
|
gtk_widget_show(mShell);
|
|
|
|
}
|
|
|
|
else if (mContainer) {
|
|
|
|
gtk_widget_show(GTK_WIDGET(mContainer));
|
|
|
|
}
|
2009-07-26 18:39:36 -07:00
|
|
|
else if (mGdkWindow) {
|
|
|
|
gdk_window_show_unraised(mGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (mIsTopLevel) {
|
|
|
|
gtk_widget_hide(GTK_WIDGET(mShell));
|
|
|
|
gtk_widget_hide(GTK_WIDGET(mContainer));
|
|
|
|
}
|
|
|
|
else if (mContainer) {
|
|
|
|
gtk_widget_hide(GTK_WIDGET(mContainer));
|
|
|
|
}
|
2009-07-26 18:40:46 -07:00
|
|
|
else if (mGdkWindow) {
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_hide(mGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
void
|
|
|
|
nsWindow::SetHasMappedToplevel(PRBool aState)
|
|
|
|
{
|
|
|
|
// Even when aState == mHasMappedToplevel (as when this method is called
|
|
|
|
// from Show()), child windows need to have their state checked, so don't
|
|
|
|
// return early.
|
|
|
|
PRBool oldState = mHasMappedToplevel;
|
|
|
|
mHasMappedToplevel = aState;
|
|
|
|
|
|
|
|
// mHasMappedToplevel is not updated for children of windows that are
|
|
|
|
// hidden; GDK knows not to send expose events for these windows. The
|
|
|
|
// state is recorded on the hidden window itself, but, for child trees of
|
|
|
|
// hidden windows, their state essentially becomes disconnected from their
|
|
|
|
// hidden parent. When the hidden parent gets shown, the child trees are
|
|
|
|
// reconnected, and the state of the window being shown can be easily
|
|
|
|
// propagated.
|
|
|
|
if (!mIsShown || !mGdkWindow)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (aState && !oldState && !mIsFullyObscured) {
|
|
|
|
// GDK_EXPOSE events have been ignored but the window is now visible,
|
|
|
|
// so make sure GDK doesn't think that the window has already been
|
|
|
|
// painted.
|
|
|
|
gdk_window_invalidate_rect(mGdkWindow, NULL, FALSE);
|
|
|
|
|
|
|
|
// Check that a grab didn't fail due to the window not being
|
|
|
|
// viewable.
|
|
|
|
EnsureGrabs();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (GList *children = gdk_window_peek_children(mGdkWindow);
|
|
|
|
children;
|
|
|
|
children = children->next) {
|
|
|
|
GdkWindow *gdkWin = GDK_WINDOW(children->data);
|
|
|
|
nsWindow *child = get_window_for_gdk_window(gdkWin);
|
|
|
|
|
|
|
|
if (child && child->mHasMappedToplevel != aState) {
|
|
|
|
child->SetHasMappedToplevel(aState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntSize
|
|
|
|
nsWindow::GetSafeWindowSize(nsIntSize aSize)
|
2008-07-02 04:09:15 -07:00
|
|
|
{
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntSize result = aSize;
|
2008-09-03 08:39:08 -07:00
|
|
|
const PRInt32 kInt16Max = 32767;
|
|
|
|
if (result.width > kInt16Max) {
|
2008-07-02 04:09:15 -07:00
|
|
|
NS_WARNING("Clamping huge window width");
|
2008-09-03 08:39:08 -07:00
|
|
|
result.width = kInt16Max;
|
2008-07-02 04:09:15 -07:00
|
|
|
}
|
2008-09-03 08:39:08 -07:00
|
|
|
if (result.height > kInt16Max) {
|
2008-07-02 04:09:15 -07:00
|
|
|
NS_WARNING("Clamping huge window height");
|
2008-09-03 08:39:08 -07:00
|
|
|
result.height = kInt16Max;
|
2008-07-02 04:09:15 -07:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::EnsureGrabs(void)
|
|
|
|
{
|
|
|
|
if (mRetryPointerGrab)
|
|
|
|
GrabPointer();
|
|
|
|
if (mRetryKeyboardGrab)
|
|
|
|
GrabKeyboard();
|
|
|
|
}
|
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
void
|
|
|
|
nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (!mShell) {
|
|
|
|
// Pass the request to the toplevel window
|
|
|
|
GtkWidget *topWidget = nsnull;
|
|
|
|
GetToplevelWidget(&topWidget);
|
|
|
|
if (!topWidget)
|
2008-08-12 17:44:14 -07:00
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
|
|
|
|
if (!topWindow)
|
2008-08-12 17:44:14 -07:00
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
topWindow->SetTransparencyMode(aMode);
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-08-12 17:44:14 -07:00
|
|
|
PRBool isTransparent = aMode == eTransparencyTransparent;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
if (mIsTransparent == isTransparent)
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
if (!isTransparent) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mTransparencyBitmap) {
|
|
|
|
delete[] mTransparencyBitmap;
|
|
|
|
mTransparencyBitmap = nsnull;
|
|
|
|
mTransparencyBitmapWidth = 0;
|
|
|
|
mTransparencyBitmapHeight = 0;
|
|
|
|
gtk_widget_reset_shapes(mShell);
|
|
|
|
}
|
|
|
|
} // else the new default alpha values are "all 1", so we don't
|
|
|
|
// need to change anything yet
|
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
mIsTransparent = isTransparent;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
nsTransparencyMode
|
|
|
|
nsWindow::GetTransparencyMode()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (!mShell) {
|
|
|
|
// Pass the request to the toplevel window
|
|
|
|
GtkWidget *topWidget = nsnull;
|
|
|
|
GetToplevelWidget(&topWidget);
|
|
|
|
if (!topWidget) {
|
2008-08-12 17:44:14 -07:00
|
|
|
return eTransparencyOpaque;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
|
|
|
|
if (!topWindow) {
|
2008-08-12 17:44:14 -07:00
|
|
|
return eTransparencyOpaque;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
return topWindow->GetTransparencyMode();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
return mIsTransparent ? eTransparencyTransparent : eTransparencyOpaque;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-07-21 17:44:55 -07:00
|
|
|
nsresult
|
|
|
|
nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
|
|
|
|
{
|
|
|
|
for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
|
|
|
|
const Configuration& configuration = aConfigurations[i];
|
|
|
|
nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
|
|
|
|
NS_ASSERTION(w->GetParent() == this,
|
|
|
|
"Configured widget is not a child");
|
|
|
|
nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (w->mBounds.Size() != configuration.mBounds.Size()) {
|
|
|
|
w->Resize(configuration.mBounds.x, configuration.mBounds.y,
|
|
|
|
configuration.mBounds.width, configuration.mBounds.height,
|
|
|
|
PR_TRUE);
|
|
|
|
} else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
|
|
|
|
w->Move(configuration.mBounds.x, configuration.mBounds.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects)
|
|
|
|
{
|
2009-07-26 14:19:15 -07:00
|
|
|
if (!StoreWindowClipRegion(aRects))
|
|
|
|
return NS_OK;
|
2009-07-21 17:44:55 -07:00
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2009-07-21 17:44:55 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
GdkRegion *region = gdk_region_new();
|
|
|
|
if (!region)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
for (PRUint32 i = 0; i < aRects.Length(); ++i) {
|
|
|
|
const nsIntRect& r = aRects[i];
|
|
|
|
GdkRectangle rect = { r.x, r.y, r.width, r.height };
|
|
|
|
gdk_region_union_with_rect(region, &rect);
|
|
|
|
}
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
|
2009-07-21 17:44:55 -07:00
|
|
|
gdk_region_destroy(region);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight)
|
|
|
|
{
|
|
|
|
if (!mTransparencyBitmap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (aNewWidth == mTransparencyBitmapWidth &&
|
|
|
|
aNewHeight == mTransparencyBitmapHeight)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PRInt32 newSize = ((aNewWidth+7)/8)*aNewHeight;
|
|
|
|
gchar* newBits = new gchar[newSize];
|
|
|
|
if (!newBits) {
|
|
|
|
delete[] mTransparencyBitmap;
|
|
|
|
mTransparencyBitmap = nsnull;
|
|
|
|
mTransparencyBitmapWidth = 0;
|
|
|
|
mTransparencyBitmapHeight = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// fill new mask with "opaque", first
|
|
|
|
memset(newBits, 255, newSize);
|
|
|
|
|
|
|
|
// Now copy the intersection of the old and new areas into the new mask
|
|
|
|
PRInt32 copyWidth = PR_MIN(aNewWidth, mTransparencyBitmapWidth);
|
|
|
|
PRInt32 copyHeight = PR_MIN(aNewHeight, mTransparencyBitmapHeight);
|
|
|
|
PRInt32 oldRowBytes = (mTransparencyBitmapWidth+7)/8;
|
|
|
|
PRInt32 newRowBytes = (aNewWidth+7)/8;
|
|
|
|
PRInt32 copyBytes = (copyWidth+7)/8;
|
|
|
|
|
|
|
|
PRInt32 i;
|
|
|
|
gchar* fromPtr = mTransparencyBitmap;
|
|
|
|
gchar* toPtr = newBits;
|
|
|
|
for (i = 0; i < copyHeight; i++) {
|
|
|
|
memcpy(toPtr, fromPtr, copyBytes);
|
|
|
|
fromPtr += oldRowBytes;
|
|
|
|
toPtr += newRowBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] mTransparencyBitmap;
|
|
|
|
mTransparencyBitmap = newBits;
|
|
|
|
mTransparencyBitmapWidth = aNewWidth;
|
|
|
|
mTransparencyBitmapHeight = aNewHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRBool
|
|
|
|
ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
|
2009-01-14 19:27:09 -08:00
|
|
|
const nsIntRect& aRect, PRUint8* aAlphas, PRInt32 aStride)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
|
|
|
|
PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
|
|
|
|
for (y = aRect.y; y < yMax; y++) {
|
|
|
|
gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
|
|
|
|
PRUint8* alphas = aAlphas;
|
|
|
|
for (x = aRect.x; x < xMax; x++) {
|
|
|
|
PRBool newBit = *alphas > 0;
|
|
|
|
alphas++;
|
|
|
|
|
|
|
|
gchar maskByte = maskBytes[x >> 3];
|
|
|
|
PRBool maskBit = (maskByte & (1 << (x & 7))) != 0;
|
|
|
|
|
|
|
|
if (maskBit != newBit) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
aAlphas += aStride;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
void UpdateMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
|
2009-01-14 19:27:09 -08:00
|
|
|
const nsIntRect& aRect, PRUint8* aAlphas, PRInt32 aStride)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
|
|
|
|
PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
|
|
|
|
for (y = aRect.y; y < yMax; y++) {
|
|
|
|
gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
|
|
|
|
PRUint8* alphas = aAlphas;
|
|
|
|
for (x = aRect.x; x < xMax; x++) {
|
|
|
|
PRBool newBit = *alphas > 0;
|
|
|
|
alphas++;
|
|
|
|
|
|
|
|
gchar mask = 1 << (x & 7);
|
|
|
|
gchar maskByte = maskBytes[x >> 3];
|
|
|
|
// Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
|
|
|
|
maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask);
|
|
|
|
}
|
|
|
|
aAlphas += aStride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::ApplyTransparencyBitmap()
|
|
|
|
{
|
|
|
|
gtk_widget_reset_shapes(mShell);
|
|
|
|
GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(mShell->window,
|
|
|
|
mTransparencyBitmap,
|
|
|
|
mTransparencyBitmapWidth, mTransparencyBitmapHeight);
|
|
|
|
if (!maskBitmap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gtk_widget_shape_combine_mask(mShell, maskBitmap, 0, 0);
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(maskBitmap);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2009-01-14 19:27:09 -08:00
|
|
|
nsWindow::UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
|
2007-03-22 10:30:00 -07:00
|
|
|
PRUint8* aAlphas, PRInt32 aStride)
|
|
|
|
{
|
|
|
|
if (!mShell) {
|
|
|
|
// Pass the request to the toplevel window
|
|
|
|
GtkWidget *topWidget = nsnull;
|
|
|
|
GetToplevelWidget(&topWidget);
|
|
|
|
if (!topWidget)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
|
|
|
|
if (!topWindow)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return topWindow->UpdateTranslucentWindowAlphaInternal(aRect, aAlphas, aStride);
|
|
|
|
}
|
|
|
|
|
2007-12-19 11:40:18 -08:00
|
|
|
NS_ASSERTION(mIsTransparent, "Window is not transparent");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mTransparencyBitmap == nsnull) {
|
|
|
|
PRInt32 size = ((mBounds.width+7)/8)*mBounds.height;
|
|
|
|
mTransparencyBitmap = new gchar[size];
|
|
|
|
if (mTransparencyBitmap == nsnull)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
memset(mTransparencyBitmap, 255, size);
|
|
|
|
mTransparencyBitmapWidth = mBounds.width;
|
|
|
|
mTransparencyBitmapHeight = mBounds.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(aRect.x >= 0 && aRect.y >= 0
|
|
|
|
&& aRect.XMost() <= mBounds.width && aRect.YMost() <= mBounds.height,
|
|
|
|
"Rect is out of window bounds");
|
|
|
|
|
|
|
|
if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
|
|
|
|
aRect, aAlphas, aStride))
|
|
|
|
// skip the expensive stuff if the mask bits haven't changed; hopefully
|
|
|
|
// this is the common case
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
|
|
|
|
aRect, aAlphas, aStride);
|
|
|
|
|
|
|
|
if (!mNeedsShow) {
|
|
|
|
ApplyTransparencyBitmap();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::GrabPointer(void)
|
|
|
|
{
|
|
|
|
LOG(("GrabPointer %d\n", mRetryPointerGrab));
|
|
|
|
|
|
|
|
mRetryPointerGrab = PR_FALSE;
|
|
|
|
|
|
|
|
// If the window isn't visible, just set the flag to retry the
|
|
|
|
// grab. When this window becomes visible, the grab will be
|
|
|
|
// retried.
|
2009-11-01 18:03:12 -08:00
|
|
|
if (!mHasMappedToplevel || mIsFullyObscured) {
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("GrabPointer: window not visible\n"));
|
|
|
|
mRetryPointerGrab = PR_TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
gint retval;
|
2009-07-26 18:39:36 -07:00
|
|
|
retval = gdk_pointer_grab(mGdkWindow, TRUE,
|
2007-03-22 10:30:00 -07:00
|
|
|
(GdkEventMask)(GDK_BUTTON_PRESS_MASK |
|
|
|
|
GDK_BUTTON_RELEASE_MASK |
|
|
|
|
GDK_ENTER_NOTIFY_MASK |
|
|
|
|
GDK_LEAVE_NOTIFY_MASK |
|
2008-11-26 05:43:36 -08:00
|
|
|
#ifdef HAVE_GTK_MOTION_HINTS
|
|
|
|
GDK_POINTER_MOTION_HINT_MASK |
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
GDK_POINTER_MOTION_MASK),
|
|
|
|
(GdkWindow *)NULL, NULL, GDK_CURRENT_TIME);
|
|
|
|
|
|
|
|
if (retval != GDK_GRAB_SUCCESS) {
|
|
|
|
LOG(("GrabPointer: pointer grab failed\n"));
|
|
|
|
mRetryPointerGrab = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::GrabKeyboard(void)
|
|
|
|
{
|
|
|
|
LOG(("GrabKeyboard %d\n", mRetryKeyboardGrab));
|
|
|
|
|
|
|
|
mRetryKeyboardGrab = PR_FALSE;
|
|
|
|
|
|
|
|
// If the window isn't visible, just set the flag to retry the
|
|
|
|
// grab. When this window becomes visible, the grab will be
|
|
|
|
// retried.
|
2009-11-01 18:03:12 -08:00
|
|
|
if (!mHasMappedToplevel || mIsFullyObscured) {
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("GrabKeyboard: window not visible\n"));
|
|
|
|
mRetryKeyboardGrab = PR_TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we need to grab the keyboard on the transient parent so that we
|
|
|
|
// don't end up with any focus events that end up on the parent
|
|
|
|
// window that will cause the popup to go away
|
|
|
|
GdkWindow *grabWindow;
|
|
|
|
|
|
|
|
if (mTransientParent)
|
|
|
|
grabWindow = GTK_WIDGET(mTransientParent)->window;
|
2009-07-26 18:39:36 -07:00
|
|
|
else if (mGdkWindow)
|
|
|
|
grabWindow = mGdkWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
gint retval;
|
|
|
|
retval = gdk_keyboard_grab(grabWindow, TRUE, GDK_CURRENT_TIME);
|
|
|
|
|
|
|
|
if (retval != GDK_GRAB_SUCCESS) {
|
|
|
|
LOG(("GrabKeyboard: keyboard grab failed %d\n", retval));
|
|
|
|
gdk_pointer_ungrab(GDK_CURRENT_TIME);
|
|
|
|
mRetryKeyboardGrab = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::ReleaseGrabs(void)
|
|
|
|
{
|
|
|
|
LOG(("ReleaseGrabs\n"));
|
|
|
|
|
|
|
|
mRetryPointerGrab = PR_FALSE;
|
|
|
|
mRetryKeyboardGrab = PR_FALSE;
|
|
|
|
|
|
|
|
gdk_pointer_ungrab(GDK_CURRENT_TIME);
|
|
|
|
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::GetToplevelWidget(GtkWidget **aWidget)
|
|
|
|
{
|
|
|
|
*aWidget = nsnull;
|
|
|
|
|
|
|
|
if (mShell) {
|
|
|
|
*aWidget = mShell;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-08-27 19:04:06 -07:00
|
|
|
GtkWidget *widget = GetMozContainerWidget();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!widget)
|
|
|
|
return;
|
|
|
|
|
|
|
|
*aWidget = gtk_widget_get_toplevel(widget);
|
|
|
|
}
|
|
|
|
|
2008-08-27 19:04:06 -07:00
|
|
|
GtkWidget *
|
|
|
|
nsWindow::GetMozContainerWidget()
|
|
|
|
{
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2009-02-19 18:07:08 -08:00
|
|
|
return NULL;
|
|
|
|
|
2008-08-27 19:04:06 -07:00
|
|
|
GtkWidget *owningWidget =
|
2009-07-26 18:39:36 -07:00
|
|
|
get_gtk_widget_for_gdk_window(mGdkWindow);
|
2008-08-27 19:04:06 -07:00
|
|
|
return owningWidget;
|
|
|
|
}
|
|
|
|
|
2009-02-19 18:07:08 -08:00
|
|
|
nsWindow *
|
|
|
|
nsWindow::GetContainerWindow()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-08-27 19:04:06 -07:00
|
|
|
GtkWidget *owningWidget = GetMozContainerWidget();
|
2009-02-19 18:07:08 -08:00
|
|
|
if (!owningWidget)
|
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-02-19 18:07:08 -08:00
|
|
|
nsWindow *window = get_window_for_gtk_widget(owningWidget);
|
|
|
|
NS_ASSERTION(window, "No nsWindow for container widget");
|
|
|
|
return window;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::SetUrgencyHint(GtkWidget *top_window, PRBool state)
|
|
|
|
{
|
|
|
|
if (!top_window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Try to get a pointer to gdk_window_set_urgency_hint
|
|
|
|
PRLibrary* lib;
|
|
|
|
_gdk_window_set_urgency_hint_fn _gdk_window_set_urgency_hint = nsnull;
|
|
|
|
_gdk_window_set_urgency_hint = (_gdk_window_set_urgency_hint_fn)
|
|
|
|
PR_FindFunctionSymbolAndLibrary("gdk_window_set_urgency_hint", &lib);
|
|
|
|
|
|
|
|
if (_gdk_window_set_urgency_hint) {
|
|
|
|
_gdk_window_set_urgency_hint(top_window->window, state);
|
|
|
|
PR_UnloadLibrary(lib);
|
|
|
|
}
|
|
|
|
else if (state) {
|
|
|
|
gdk_window_show_unraised(top_window->window);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
nsWindow::SetupPluginPort(void)
|
|
|
|
{
|
2009-07-26 18:39:36 -07:00
|
|
|
if (!mGdkWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
if (GDK_WINDOW_OBJECT(mGdkWindow)->destroyed == TRUE)
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
// we have to flush the X queue here so that any plugins that
|
|
|
|
// might be running on separate X connections will be able to use
|
|
|
|
// this window in case it was just created
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
XWindowAttributes xattrs;
|
2009-07-26 18:39:36 -07:00
|
|
|
XGetWindowAttributes(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(mGdkWindow),
|
2007-03-22 10:30:00 -07:00
|
|
|
&xattrs);
|
|
|
|
XSelectInput (GDK_DISPLAY (),
|
2009-07-26 18:39:36 -07:00
|
|
|
GDK_WINDOW_XWINDOW(mGdkWindow),
|
2007-03-22 10:30:00 -07:00
|
|
|
xattrs.your_event_mask |
|
|
|
|
SubstructureNotifyMask);
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_add_filter(mGdkWindow, plugin_window_filter_func, this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
XSync(GDK_DISPLAY(), False);
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
return (void *)GDK_WINDOW_XWINDOW(mGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2009-01-21 20:15:34 -08:00
|
|
|
nsWindow::SetWindowIconList(const nsTArray<nsCString> &aIconList)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
GList *list = NULL;
|
|
|
|
|
2009-01-21 20:15:34 -08:00
|
|
|
for (PRUint32 i = 0; i < aIconList.Length(); ++i) {
|
|
|
|
const char *path = aIconList[i].get();
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("window [%p] Loading icon from %s\n", (void *)this, path));
|
|
|
|
|
|
|
|
GdkPixbuf *icon = gdk_pixbuf_new_from_file(path, NULL);
|
|
|
|
if (!icon)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
list = g_list_append(list, icon);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!list)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
gtk_window_set_icon_list(GTK_WINDOW(mShell), list);
|
|
|
|
|
|
|
|
g_list_foreach(list, (GFunc) g_object_unref, NULL);
|
|
|
|
g_list_free(list);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::SetDefaultIcon(void)
|
|
|
|
{
|
2008-01-09 22:04:51 -08:00
|
|
|
SetIcon(NS_LITERAL_STRING("default"));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::SetPluginType(PluginType aPluginType)
|
|
|
|
{
|
|
|
|
mPluginType = aPluginType;
|
|
|
|
}
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::SetNonXEmbedPluginFocus()
|
|
|
|
{
|
|
|
|
if (gPluginFocusWindow == this || mPluginType!=PluginType_NONXEMBED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gPluginFocusWindow) {
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = gPluginFocusWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus\n"));
|
|
|
|
|
|
|
|
Window curFocusWindow;
|
|
|
|
int focusState;
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
XGetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow),
|
2007-03-22 10:30:00 -07:00
|
|
|
&curFocusWindow,
|
|
|
|
&focusState);
|
|
|
|
|
|
|
|
LOGFOCUS(("\t curFocusWindow=%p\n", curFocusWindow));
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
GdkWindow* toplevel = gdk_window_get_toplevel(mGdkWindow);
|
2007-03-22 10:30:00 -07:00
|
|
|
GdkWindow *gdkfocuswin = gdk_window_lookup(curFocusWindow);
|
|
|
|
|
|
|
|
// lookup with the focus proxy window is supposed to get the
|
|
|
|
// same GdkWindow as toplevel. If the current focused window
|
|
|
|
// is not the focus proxy, we return without any change.
|
|
|
|
if (gdkfocuswin != toplevel) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// switch the focus from the focus proxy to the plugin window
|
|
|
|
mOldFocusWindow = curFocusWindow;
|
2009-07-26 18:39:36 -07:00
|
|
|
XRaiseWindow(GDK_WINDOW_XDISPLAY(mGdkWindow),
|
|
|
|
GDK_WINDOW_XWINDOW(mGdkWindow));
|
2007-03-22 10:30:00 -07:00
|
|
|
gdk_error_trap_push();
|
2009-07-26 18:39:36 -07:00
|
|
|
XSetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow),
|
|
|
|
GDK_WINDOW_XWINDOW(mGdkWindow),
|
2007-03-22 10:30:00 -07:00
|
|
|
RevertToNone,
|
|
|
|
CurrentTime);
|
|
|
|
gdk_flush();
|
|
|
|
gdk_error_trap_pop();
|
|
|
|
gPluginFocusWindow = this;
|
|
|
|
gdk_window_add_filter(NULL, plugin_client_message_filter, this);
|
|
|
|
|
|
|
|
LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus oldfocus=%p new=%p\n",
|
2009-07-26 18:39:36 -07:00
|
|
|
mOldFocusWindow, GDK_WINDOW_XWINDOW(mGdkWindow)));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::LoseNonXEmbedPluginFocus()
|
|
|
|
{
|
|
|
|
LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus\n"));
|
|
|
|
|
|
|
|
// This method is only for the nsWindow which contains a
|
|
|
|
// Non-XEmbed plugin, for example, JAVA plugin.
|
|
|
|
if (gPluginFocusWindow != this || mPluginType!=PluginType_NONXEMBED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window curFocusWindow;
|
|
|
|
int focusState;
|
|
|
|
|
2009-07-26 18:39:36 -07:00
|
|
|
XGetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow),
|
2007-03-22 10:30:00 -07:00
|
|
|
&curFocusWindow,
|
|
|
|
&focusState);
|
|
|
|
|
|
|
|
// we only switch focus between plugin window and focus proxy. If the
|
|
|
|
// current focused window is not the plugin window, just removing the
|
|
|
|
// event filter that blocks the WM_TAKE_FOCUS is enough. WM and gtk2
|
|
|
|
// will take care of the focus later.
|
|
|
|
if (!curFocusWindow ||
|
2009-07-26 18:39:36 -07:00
|
|
|
curFocusWindow == GDK_WINDOW_XWINDOW(mGdkWindow)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gdk_error_trap_push();
|
2009-07-26 18:39:36 -07:00
|
|
|
XRaiseWindow(GDK_WINDOW_XDISPLAY(mGdkWindow),
|
2007-03-22 10:30:00 -07:00
|
|
|
mOldFocusWindow);
|
2009-07-26 18:39:36 -07:00
|
|
|
XSetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow),
|
2007-03-22 10:30:00 -07:00
|
|
|
mOldFocusWindow,
|
|
|
|
RevertToParent,
|
|
|
|
CurrentTime);
|
|
|
|
gdk_flush();
|
|
|
|
gdk_error_trap_pop();
|
|
|
|
}
|
|
|
|
gPluginFocusWindow = NULL;
|
|
|
|
mOldFocusWindow = 0;
|
|
|
|
gdk_window_remove_filter(NULL, plugin_client_message_filter, this);
|
|
|
|
|
|
|
|
LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus end\n"));
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
|
|
|
|
gint
|
|
|
|
nsWindow::ConvertBorderStyles(nsBorderStyle aStyle)
|
|
|
|
{
|
|
|
|
gint w = 0;
|
|
|
|
|
|
|
|
if (aStyle == eBorderStyle_default)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (aStyle & eBorderStyle_all)
|
|
|
|
w |= GDK_DECOR_ALL;
|
|
|
|
if (aStyle & eBorderStyle_border)
|
|
|
|
w |= GDK_DECOR_BORDER;
|
|
|
|
if (aStyle & eBorderStyle_resizeh)
|
|
|
|
w |= GDK_DECOR_RESIZEH;
|
|
|
|
if (aStyle & eBorderStyle_title)
|
|
|
|
w |= GDK_DECOR_TITLE;
|
|
|
|
if (aStyle & eBorderStyle_menu)
|
|
|
|
w |= GDK_DECOR_MENU;
|
|
|
|
if (aStyle & eBorderStyle_minimize)
|
|
|
|
w |= GDK_DECOR_MINIMIZE;
|
|
|
|
if (aStyle & eBorderStyle_maximize)
|
|
|
|
w |= GDK_DECOR_MAXIMIZE;
|
|
|
|
if (aStyle & eBorderStyle_close) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("we don't handle eBorderStyle_close yet... please fix me\n");
|
|
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::MakeFullScreen(PRBool aFullScreen)
|
|
|
|
{
|
2009-08-14 12:56:56 -07:00
|
|
|
LOG(("nsWindow::MakeFullScreen [%p] aFullScreen %d\n",
|
|
|
|
(void *)this, aFullScreen));
|
|
|
|
|
|
|
|
if (aFullScreen) {
|
2009-08-26 17:09:47 -07:00
|
|
|
if (mSizeMode != nsSizeMode_Fullscreen)
|
|
|
|
mLastSizeMode = mSizeMode;
|
|
|
|
|
2009-08-14 12:56:56 -07:00
|
|
|
mSizeMode = nsSizeMode_Fullscreen;
|
2009-11-10 12:46:09 -08:00
|
|
|
gtk_window_fullscreen(GTK_WINDOW(mShell));
|
2009-08-14 12:56:56 -07:00
|
|
|
}
|
2009-08-26 17:09:47 -07:00
|
|
|
else {
|
|
|
|
mSizeMode = mLastSizeMode;
|
2009-11-10 12:46:09 -08:00
|
|
|
gtk_window_unfullscreen(GTK_WINDOW(mShell));
|
2009-08-26 17:09:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen,
|
|
|
|
"mLastSizeMode should never be fullscreen");
|
2008-01-04 21:34:00 -08:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::HideWindowChrome(PRBool aShouldHide)
|
|
|
|
{
|
|
|
|
if (!mShell) {
|
|
|
|
// Pass the request to the toplevel window
|
|
|
|
GtkWidget *topWidget = nsnull;
|
|
|
|
GetToplevelWidget(&topWidget);
|
2009-02-19 18:07:08 -08:00
|
|
|
if (!topWidget)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
|
2009-02-19 18:07:08 -08:00
|
|
|
if (!topWindow)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return topWindow->HideWindowChrome(aShouldHide);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sawfish, metacity, and presumably other window managers get
|
|
|
|
// confused if we change the window decorations while the window
|
|
|
|
// is visible.
|
2008-01-14 01:35:19 -08:00
|
|
|
PRBool wasVisible = PR_FALSE;
|
|
|
|
if (gdk_window_is_visible(mShell->window)) {
|
|
|
|
gdk_window_hide(mShell->window);
|
|
|
|
wasVisible = PR_TRUE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gint wmd;
|
|
|
|
if (aShouldHide)
|
|
|
|
wmd = 0;
|
|
|
|
else
|
|
|
|
wmd = ConvertBorderStyles(mBorderStyle);
|
|
|
|
|
|
|
|
gdk_window_set_decorations(mShell->window, (GdkWMDecoration) wmd);
|
|
|
|
|
2008-01-14 01:35:19 -08:00
|
|
|
if (wasVisible)
|
|
|
|
gdk_window_show(mShell->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// For some window managers, adding or removing window decorations
|
|
|
|
// requires unmapping and remapping our toplevel window. Go ahead
|
|
|
|
// and flush the queue here so that we don't end up with a BadWindow
|
|
|
|
// error later when this happens (when the persistence timer fires
|
|
|
|
// and GetWindowPos is called)
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
XSync(GDK_DISPLAY(), False);
|
2008-08-06 13:48:55 -07:00
|
|
|
#else
|
|
|
|
gdk_flush ();
|
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
check_for_rollup(GdkWindow *aWindow, gdouble aMouseX, gdouble aMouseY,
|
|
|
|
PRBool aIsWheel)
|
|
|
|
{
|
|
|
|
PRBool retVal = PR_FALSE;
|
|
|
|
nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
|
|
|
|
|
|
|
|
if (rollupWidget && gRollupListener) {
|
|
|
|
GdkWindow *currentPopup =
|
|
|
|
(GdkWindow *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
|
|
|
|
PRBool rollup = PR_TRUE;
|
|
|
|
if (aIsWheel) {
|
|
|
|
gRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
|
|
|
|
retVal = PR_TRUE;
|
|
|
|
}
|
|
|
|
// if we're dealing with menus, we probably have submenus and
|
|
|
|
// we don't want to rollup if the clickis in a parent menu of
|
|
|
|
// the current submenu
|
2009-06-12 11:23:16 -07:00
|
|
|
PRUint32 popupsToRollup = PR_UINT32_MAX;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIMenuRollup> menuRollup;
|
|
|
|
menuRollup = (do_QueryInterface(gRollupListener));
|
|
|
|
if (menuRollup) {
|
2008-01-16 22:57:13 -08:00
|
|
|
nsAutoTArray<nsIWidget*, 5> widgetChain;
|
2009-06-12 11:23:16 -07:00
|
|
|
PRUint32 sameTypeCount = menuRollup->GetSubmenuWidgetChain(&widgetChain);
|
2008-01-16 22:57:13 -08:00
|
|
|
for (PRUint32 i=0; i<widgetChain.Length(); ++i) {
|
2009-06-12 11:23:16 -07:00
|
|
|
nsIWidget* widget = widgetChain[i];
|
2008-01-16 22:57:13 -08:00
|
|
|
GdkWindow* currWindow =
|
|
|
|
(GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
|
2009-06-12 11:23:16 -07:00
|
|
|
// don't roll up if the mouse event occured within a
|
|
|
|
// menu of the same type. If the mouse event occured
|
|
|
|
// in a menu higher than that, roll up, but pass the
|
|
|
|
// number of popups to Rollup so that only those of the
|
|
|
|
// same type close up.
|
|
|
|
if (i < sameTypeCount) {
|
|
|
|
rollup = PR_FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
popupsToRollup = sameTypeCount;
|
|
|
|
}
|
|
|
|
break;
|
2008-01-16 22:57:13 -08:00
|
|
|
}
|
|
|
|
} // foreach parent menu widget
|
2007-03-22 10:30:00 -07:00
|
|
|
} // if rollup listener knows about menus
|
|
|
|
|
|
|
|
// if we've determined that we should still rollup, do it.
|
|
|
|
if (rollup) {
|
2009-06-12 11:23:16 -07:00
|
|
|
gRollupListener->Rollup(popupsToRollup, nsnull);
|
|
|
|
if (popupsToRollup == PR_UINT32_MAX) {
|
|
|
|
retVal = PR_TRUE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
gRollupWindow = nsnull;
|
|
|
|
gRollupListener = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
PRBool
|
|
|
|
nsWindow::DragInProgress(void)
|
|
|
|
{
|
|
|
|
// mLastDragMotionWindow means the drag arrow is over mozilla
|
|
|
|
// sIsDraggingOutOf means the drag arrow is out of mozilla
|
|
|
|
// both cases mean the dragging is happenning.
|
|
|
|
return (mLastDragMotionWindow || sIsDraggingOutOf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
PRBool
|
|
|
|
is_mouse_in_window (GdkWindow* aWindow, gdouble aMouseX, gdouble aMouseY)
|
|
|
|
{
|
|
|
|
gint x = 0;
|
|
|
|
gint y = 0;
|
|
|
|
gint w, h;
|
|
|
|
|
|
|
|
gint offsetX = 0;
|
|
|
|
gint offsetY = 0;
|
|
|
|
|
2009-02-19 18:07:08 -08:00
|
|
|
GdkWindow *window = aWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
while (window) {
|
|
|
|
gint tmpX = 0;
|
|
|
|
gint tmpY = 0;
|
|
|
|
|
|
|
|
gdk_window_get_position(window, &tmpX, &tmpY);
|
2009-02-19 18:07:08 -08:00
|
|
|
GtkWidget *widget = get_gtk_widget_for_gdk_window(window);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// if this is a window, compute x and y given its origin and our
|
|
|
|
// offset
|
|
|
|
if (GTK_IS_WINDOW(widget)) {
|
|
|
|
x = tmpX + offsetX;
|
|
|
|
y = tmpY + offsetY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
offsetX += tmpX;
|
|
|
|
offsetY += tmpY;
|
|
|
|
window = gdk_window_get_parent(window);
|
|
|
|
}
|
|
|
|
|
2009-02-02 09:49:58 -08:00
|
|
|
gdk_drawable_get_size(aWindow, &w, &h);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (aMouseX > x && aMouseX < x + w &&
|
|
|
|
aMouseY > y && aMouseY < y + h)
|
|
|
|
return PR_TRUE;
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsWindow *
|
|
|
|
get_window_for_gtk_widget(GtkWidget *widget)
|
|
|
|
{
|
2009-02-19 18:07:08 -08:00
|
|
|
gpointer user_data = g_object_get_data(G_OBJECT(widget), "nsWindow");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
return static_cast<nsWindow *>(user_data);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsWindow *
|
|
|
|
get_window_for_gdk_window(GdkWindow *window)
|
|
|
|
{
|
2009-02-19 18:07:08 -08:00
|
|
|
gpointer user_data = g_object_get_data(G_OBJECT(window), "nsWindow");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
return static_cast<nsWindow *>(user_data);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsWindow *
|
|
|
|
get_owning_window_for_gdk_window(GdkWindow *window)
|
|
|
|
{
|
|
|
|
GtkWidget *owningWidget = get_gtk_widget_for_gdk_window(window);
|
|
|
|
if (!owningWidget)
|
|
|
|
return nsnull;
|
|
|
|
|
2009-02-19 18:07:08 -08:00
|
|
|
gpointer user_data = g_object_get_data(G_OBJECT(owningWidget), "nsWindow");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-02-19 18:07:08 -08:00
|
|
|
return static_cast<nsWindow *>(user_data);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
GtkWidget *
|
|
|
|
get_gtk_widget_for_gdk_window(GdkWindow *window)
|
|
|
|
{
|
|
|
|
gpointer user_data = NULL;
|
|
|
|
gdk_window_get_user_data(window, &user_data);
|
|
|
|
|
|
|
|
return GTK_WIDGET(user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
GdkCursor *
|
|
|
|
get_gtk_cursor(nsCursor aCursor)
|
|
|
|
{
|
|
|
|
GdkPixmap *cursor;
|
|
|
|
GdkPixmap *mask;
|
|
|
|
GdkColor fg, bg;
|
|
|
|
GdkCursor *gdkcursor = nsnull;
|
|
|
|
PRUint8 newType = 0xff;
|
|
|
|
|
|
|
|
if ((gdkcursor = gCursorCache[aCursor])) {
|
|
|
|
return gdkcursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (aCursor) {
|
|
|
|
case eCursor_standard:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
|
|
|
|
break;
|
|
|
|
case eCursor_wait:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_WATCH);
|
|
|
|
break;
|
|
|
|
case eCursor_select:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_XTERM);
|
|
|
|
break;
|
|
|
|
case eCursor_hyperlink:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_HAND2);
|
|
|
|
break;
|
|
|
|
case eCursor_n_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_TOP_SIDE);
|
|
|
|
break;
|
|
|
|
case eCursor_s_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_BOTTOM_SIDE);
|
|
|
|
break;
|
|
|
|
case eCursor_w_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_LEFT_SIDE);
|
|
|
|
break;
|
|
|
|
case eCursor_e_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_RIGHT_SIDE);
|
|
|
|
break;
|
|
|
|
case eCursor_nw_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_TOP_LEFT_CORNER);
|
|
|
|
break;
|
|
|
|
case eCursor_se_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
|
|
|
|
break;
|
|
|
|
case eCursor_ne_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_TOP_RIGHT_CORNER);
|
|
|
|
break;
|
|
|
|
case eCursor_sw_resize:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER);
|
|
|
|
break;
|
|
|
|
case eCursor_crosshair:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_CROSSHAIR);
|
|
|
|
break;
|
|
|
|
case eCursor_move:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_FLEUR);
|
|
|
|
break;
|
|
|
|
case eCursor_help:
|
2007-09-17 14:03:34 -07:00
|
|
|
gdkcursor = gdk_cursor_new(GDK_QUESTION_ARROW);
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
case eCursor_copy: // CSS3
|
|
|
|
newType = MOZ_CURSOR_COPY;
|
|
|
|
break;
|
|
|
|
case eCursor_alias:
|
|
|
|
newType = MOZ_CURSOR_ALIAS;
|
|
|
|
break;
|
|
|
|
case eCursor_context_menu:
|
|
|
|
newType = MOZ_CURSOR_CONTEXT_MENU;
|
|
|
|
break;
|
|
|
|
case eCursor_cell:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_PLUS);
|
|
|
|
break;
|
|
|
|
case eCursor_grab:
|
|
|
|
newType = MOZ_CURSOR_HAND_GRAB;
|
|
|
|
break;
|
|
|
|
case eCursor_grabbing:
|
|
|
|
newType = MOZ_CURSOR_HAND_GRABBING;
|
|
|
|
break;
|
|
|
|
case eCursor_spinning:
|
|
|
|
newType = MOZ_CURSOR_SPINNING;
|
|
|
|
break;
|
|
|
|
case eCursor_zoom_in:
|
|
|
|
newType = MOZ_CURSOR_ZOOM_IN;
|
|
|
|
break;
|
|
|
|
case eCursor_zoom_out:
|
|
|
|
newType = MOZ_CURSOR_ZOOM_OUT;
|
|
|
|
break;
|
|
|
|
case eCursor_not_allowed:
|
|
|
|
case eCursor_no_drop:
|
|
|
|
newType = MOZ_CURSOR_NOT_ALLOWED;
|
|
|
|
break;
|
|
|
|
case eCursor_vertical_text:
|
|
|
|
newType = MOZ_CURSOR_VERTICAL_TEXT;
|
|
|
|
break;
|
|
|
|
case eCursor_all_scroll:
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_FLEUR);
|
|
|
|
break;
|
|
|
|
case eCursor_nesw_resize:
|
|
|
|
newType = MOZ_CURSOR_NESW_RESIZE;
|
|
|
|
break;
|
|
|
|
case eCursor_nwse_resize:
|
|
|
|
newType = MOZ_CURSOR_NWSE_RESIZE;
|
|
|
|
break;
|
|
|
|
case eCursor_ns_resize:
|
2009-07-04 03:03:16 -07:00
|
|
|
case eCursor_row_resize:
|
2007-03-22 10:30:00 -07:00
|
|
|
gdkcursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
|
|
|
|
break;
|
|
|
|
case eCursor_ew_resize:
|
2009-07-04 03:03:16 -07:00
|
|
|
case eCursor_col_resize:
|
2007-03-22 10:30:00 -07:00
|
|
|
gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
|
|
|
|
break;
|
2008-01-18 10:39:49 -08:00
|
|
|
case eCursor_none:
|
|
|
|
newType = MOZ_CURSOR_NONE;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
default:
|
|
|
|
NS_ASSERTION(aCursor, "Invalid cursor type");
|
|
|
|
gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if by now we don't have a xcursor, this means we have to make a
|
|
|
|
// custom one
|
|
|
|
if (newType != 0xff) {
|
|
|
|
gdk_color_parse("#000000", &fg);
|
|
|
|
gdk_color_parse("#ffffff", &bg);
|
|
|
|
|
|
|
|
cursor = gdk_bitmap_create_from_data(NULL,
|
|
|
|
(char *)GtkCursors[newType].bits,
|
|
|
|
32, 32);
|
2007-10-10 05:21:29 -07:00
|
|
|
if (!cursor)
|
|
|
|
return NULL;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mask =
|
|
|
|
gdk_bitmap_create_from_data(NULL,
|
|
|
|
(char *)GtkCursors[newType].mask_bits,
|
|
|
|
32, 32);
|
2007-10-10 05:21:29 -07:00
|
|
|
if (!mask) {
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(cursor);
|
2007-10-10 05:21:29 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gdkcursor = gdk_cursor_new_from_pixmap(cursor, mask, &fg, &bg,
|
|
|
|
GtkCursors[newType].hot_x,
|
|
|
|
GtkCursors[newType].hot_y);
|
|
|
|
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(mask);
|
|
|
|
g_object_unref(cursor);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCursorCache[aCursor] = gdkcursor;
|
|
|
|
|
|
|
|
return gdkcursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// gtk callbacks
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
|
|
|
expose_event_cb(GtkWidget *widget, GdkEventExpose *event)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
// XXX We are so getting lucky here. We are doing all of
|
|
|
|
// mozilla's painting and then allowing default processing to occur.
|
|
|
|
// This means that Mozilla paints in all of it's stuff and then
|
|
|
|
// NO_WINDOW widgets (like scrollbars, for example) are painted by
|
|
|
|
// Gtk on top of what we painted.
|
|
|
|
|
|
|
|
// This return window->OnExposeEvent(widget, event); */
|
|
|
|
|
|
|
|
window->OnExposeEvent(widget, event);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
|
|
|
configure_event_cb(GtkWidget *widget,
|
|
|
|
GdkEventConfigure *event)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return window->OnConfigureEvent(widget, event);
|
|
|
|
}
|
|
|
|
|
2009-05-14 19:14:45 -07:00
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
container_unrealize_cb (GtkWidget *widget)
|
|
|
|
{
|
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
|
|
|
|
if (!window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
window->OnContainerUnrealize(widget);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
window->OnSizeAllocate(widget, allocation);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
|
|
|
delete_event_cb(GtkWidget *widget, GdkEventAny *event)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
window->OnDeleteEvent(widget, event);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
enter_notify_event_cb(GtkWidget *widget,
|
|
|
|
GdkEventCrossing *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (is_parent_ungrab_enter(event)) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
window->OnEnterNotifyEvent(widget, event);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
leave_notify_event_cb(GtkWidget *widget,
|
|
|
|
GdkEventCrossing *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (is_parent_grab_leave(event)) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-12-19 03:21:05 -08:00
|
|
|
// bug 369599: Suppress LeaveNotify events caused by pointer grabs to
|
|
|
|
// avoid generating spurious mouse exit events.
|
|
|
|
gint x = gint(event->x_root);
|
|
|
|
gint y = gint(event->y_root);
|
|
|
|
GdkDisplay* display = gtk_widget_get_display(widget);
|
|
|
|
GdkWindow* winAtPt = gdk_display_get_window_at_pointer(display, &x, &y);
|
|
|
|
if (winAtPt == event->window) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
window->OnLeaveNotifyEvent(widget, event);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-12-13 23:00:44 -08:00
|
|
|
nsWindow*
|
|
|
|
GetFirstNSWindowForGDKWindow(GdkWindow *aGdkWindow)
|
|
|
|
{
|
|
|
|
nsWindow* window;
|
|
|
|
while (!(window = get_window_for_gdk_window(aGdkWindow))) {
|
|
|
|
// The event has bubbled to the moz_container widget as passed into each caller's *widget parameter,
|
|
|
|
// but its corresponding nsWindow is an ancestor of the window that we need. Instead, look at
|
|
|
|
// event->window and find the first ancestor nsWindow of it because event->window may be in a plugin.
|
|
|
|
aGdkWindow = gdk_window_get_parent(aGdkWindow);
|
|
|
|
if (!aGdkWindow) {
|
|
|
|
window = nsnull;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
motion_notify_event_cb(GtkWidget *widget, GdkEventMotion *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-10-06 11:47:46 -07:00
|
|
|
UpdateLastInputEventTime();
|
2009-09-17 10:13:45 -07:00
|
|
|
|
2007-12-13 23:00:44 -08:00
|
|
|
nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
2007-12-13 23:00:44 -08:00
|
|
|
return FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
window->OnMotionNotifyEvent(widget, event);
|
|
|
|
|
2008-11-26 05:43:36 -08:00
|
|
|
#ifdef HAVE_GTK_MOTION_HINTS
|
|
|
|
gdk_event_request_motions(event);
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
button_press_event_cb(GtkWidget *widget, GdkEventButton *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-10-06 11:47:46 -07:00
|
|
|
UpdateLastInputEventTime();
|
2009-09-17 10:13:45 -07:00
|
|
|
|
2007-12-13 23:00:44 -08:00
|
|
|
nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
2007-12-13 23:00:44 -08:00
|
|
|
return FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
window->OnButtonPressEvent(widget, event);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
button_release_event_cb(GtkWidget *widget, GdkEventButton *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-10-06 11:47:46 -07:00
|
|
|
UpdateLastInputEventTime();
|
2009-09-17 10:13:45 -07:00
|
|
|
|
2007-12-13 23:00:44 -08:00
|
|
|
nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
2007-12-13 23:00:44 -08:00
|
|
|
return FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
window->OnButtonReleaseEvent(widget, event);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
focus_in_event_cb(GtkWidget *widget, GdkEventFocus *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
window->OnContainerFocusInEvent(widget, event);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
focus_out_event_cb(GtkWidget *widget, GdkEventFocus *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
window->OnContainerFocusOutEvent(widget, event);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-03-22 10:30:00 -07:00
|
|
|
/* static */
|
|
|
|
GdkFilterReturn
|
2007-04-29 17:46:47 -07:00
|
|
|
plugin_window_filter_func(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
GdkWindow *plugin_window;
|
|
|
|
XEvent *xevent;
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> nswindow = (nsWindow*)data;
|
2007-03-22 10:30:00 -07:00
|
|
|
GdkFilterReturn return_val;
|
|
|
|
|
|
|
|
xevent = (XEvent *)gdk_xevent;
|
|
|
|
return_val = GDK_FILTER_CONTINUE;
|
|
|
|
|
|
|
|
switch (xevent->type)
|
|
|
|
{
|
|
|
|
case CreateNotify:
|
|
|
|
case ReparentNotify:
|
|
|
|
if (xevent->type==CreateNotify) {
|
|
|
|
plugin_window = gdk_window_lookup(xevent->xcreatewindow.window);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (xevent->xreparent.event != xevent->xreparent.parent)
|
|
|
|
break;
|
|
|
|
plugin_window = gdk_window_lookup (xevent->xreparent.window);
|
|
|
|
}
|
|
|
|
if (plugin_window) {
|
2009-02-19 18:07:08 -08:00
|
|
|
GtkWidget *widget =
|
|
|
|
get_gtk_widget_for_gdk_window(plugin_window);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (GTK_IS_XTBIN(widget)) {
|
|
|
|
nswindow->SetPluginType(nsWindow::PluginType_NONXEMBED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if(GTK_IS_SOCKET(widget)) {
|
|
|
|
nswindow->SetPluginType(nsWindow::PluginType_XEMBED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nswindow->SetPluginType(nsWindow::PluginType_NONXEMBED);
|
|
|
|
return_val = GDK_FILTER_REMOVE;
|
|
|
|
break;
|
|
|
|
case EnterNotify:
|
|
|
|
nswindow->SetNonXEmbedPluginFocus();
|
|
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
|
|
gdk_window_remove_filter
|
|
|
|
((GdkWindow*)(nswindow->GetNativeData(NS_NATIVE_WINDOW)),
|
|
|
|
plugin_window_filter_func,
|
|
|
|
nswindow);
|
|
|
|
// Currently we consider all plugins are non-xembed and calls
|
|
|
|
// LoseNonXEmbedPluginFocus without any checking.
|
|
|
|
nswindow->LoseNonXEmbedPluginFocus();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return return_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
GdkFilterReturn
|
2007-04-29 17:46:47 -07:00
|
|
|
plugin_client_message_filter(GdkXEvent *gdk_xevent,
|
|
|
|
GdkEvent *event,
|
|
|
|
gpointer data)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
XEvent *xevent;
|
|
|
|
xevent = (XEvent *)gdk_xevent;
|
|
|
|
|
|
|
|
GdkFilterReturn return_val;
|
|
|
|
return_val = GDK_FILTER_CONTINUE;
|
|
|
|
|
|
|
|
if (!gPluginFocusWindow || xevent->type!=ClientMessage) {
|
|
|
|
return return_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
// When WM sends out WM_TAKE_FOCUS, gtk2 will use XSetInputFocus
|
|
|
|
// to set the focus to the focus proxy. To prevent this happen
|
|
|
|
// while the focus is on the plugin, we filter the WM_TAKE_FOCUS
|
|
|
|
// out.
|
|
|
|
if (gdk_x11_get_xatom_by_name("WM_PROTOCOLS")
|
|
|
|
!= xevent->xclient.message_type) {
|
|
|
|
return return_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((Atom) xevent->xclient.data.l[0] ==
|
|
|
|
gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
|
|
|
|
// block it from gtk2.0 focus proxy
|
|
|
|
return_val = GDK_FILTER_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return return_val;
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
key_press_event_cb(GtkWidget *widget, GdkEventKey *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
LOG(("key_press_event_cb\n"));
|
2009-09-17 10:13:45 -07:00
|
|
|
|
2009-10-06 11:47:46 -07:00
|
|
|
UpdateLastInputEventTime();
|
2009-09-17 10:13:45 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// find the window with focus and dispatch this event to that widget
|
|
|
|
nsWindow *window = get_window_for_gtk_widget(widget);
|
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-12-15 03:34:05 -08:00
|
|
|
#ifdef MOZ_X11
|
|
|
|
// Keyboard repeat can cause key press events to queue up when there are
|
|
|
|
// slow event handlers (bug 301029). Throttle these events by removing
|
|
|
|
// consecutive pending duplicate KeyPress events to the same window.
|
|
|
|
// We use the event time of the last one.
|
|
|
|
// Note: GDK calls XkbSetDetectableAutorepeat so that KeyRelease events
|
|
|
|
// are generated only when the key is physically released.
|
|
|
|
#define NS_GDKEVENT_MATCH_MASK 0x1FFF /* GDK_SHIFT_MASK .. GDK_BUTTON5_MASK */
|
|
|
|
GdkDisplay* gdkDisplay = gtk_widget_get_display(widget);
|
|
|
|
Display* dpy = GDK_DISPLAY_XDISPLAY(gdkDisplay);
|
|
|
|
while (XPending(dpy)) {
|
|
|
|
XEvent next_event;
|
|
|
|
XPeekEvent(dpy, &next_event);
|
|
|
|
GdkWindow* nextGdkWindow =
|
|
|
|
gdk_window_lookup_for_display(gdkDisplay, next_event.xany.window);
|
|
|
|
if (nextGdkWindow != event->window ||
|
|
|
|
next_event.type != KeyPress ||
|
|
|
|
next_event.xkey.keycode != event->hardware_keycode ||
|
|
|
|
next_event.xkey.state != (event->state & NS_GDKEVENT_MATCH_MASK)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
XNextEvent(dpy, &next_event);
|
|
|
|
event->time = next_event.xkey.time;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-05-05 16:44:18 -07:00
|
|
|
return focusWindow->OnKeyPressEvent(widget, event);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
key_release_event_cb(GtkWidget *widget, GdkEventKey *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
LOG(("key_release_event_cb\n"));
|
2009-09-17 10:13:45 -07:00
|
|
|
|
2009-10-06 11:47:46 -07:00
|
|
|
UpdateLastInputEventTime();
|
2009-09-17 10:13:45 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// find the window with focus and dispatch this event to that widget
|
|
|
|
nsWindow *window = get_window_for_gtk_widget(widget);
|
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-05-05 16:44:18 -07:00
|
|
|
return focusWindow->OnKeyReleaseEvent(widget, event);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
2007-04-29 17:46:47 -07:00
|
|
|
scroll_event_cb(GtkWidget *widget, GdkEventScroll *event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-12-13 23:00:44 -08:00
|
|
|
nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
|
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
window->OnScrollEvent(widget, event);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
|
|
|
visibility_notify_event_cb (GtkWidget *widget, GdkEventVisibility *event)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
window->OnVisibilityNotifyEvent(widget, event);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-11-01 18:03:12 -08:00
|
|
|
static void
|
|
|
|
hierarchy_changed_cb (GtkWidget *widget,
|
|
|
|
GtkWidget *previous_toplevel)
|
|
|
|
{
|
|
|
|
GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
|
|
|
|
GdkWindowState old_window_state = GDK_WINDOW_STATE_WITHDRAWN;
|
|
|
|
GdkEventWindowState event;
|
|
|
|
|
|
|
|
event.new_window_state = GDK_WINDOW_STATE_WITHDRAWN;
|
|
|
|
|
|
|
|
if (GTK_IS_WINDOW(previous_toplevel)) {
|
|
|
|
g_signal_handlers_disconnect_by_func(previous_toplevel,
|
|
|
|
FuncToGpointer(window_state_event_cb),
|
|
|
|
widget);
|
|
|
|
if (widget->window) {
|
|
|
|
old_window_state = gdk_window_get_state(widget->window);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GTK_IS_WINDOW(toplevel)) {
|
|
|
|
g_signal_connect_swapped(toplevel, "window-state-event",
|
|
|
|
G_CALLBACK(window_state_event_cb), widget);
|
|
|
|
if (widget->window) {
|
|
|
|
event.new_window_state = gdk_window_get_state(widget->window);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
event.changed_mask = static_cast<GdkWindowState>
|
|
|
|
(old_window_state ^ event.new_window_state);
|
|
|
|
|
|
|
|
if (event.changed_mask) {
|
|
|
|
event.type = GDK_WINDOW_STATE;
|
|
|
|
event.window = NULL;
|
|
|
|
event.send_event = TRUE;
|
|
|
|
window_state_event_cb(widget, &event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* static */
|
|
|
|
gboolean
|
|
|
|
window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
window->OnWindowStateEvent(widget, event);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = data;
|
|
|
|
window->ThemeChanged();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// These are all of our drag and drop operations
|
|
|
|
|
|
|
|
void
|
2008-08-27 05:07:27 -07:00
|
|
|
nsWindow::InitDragEvent(nsDragEvent &aEvent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// set the keyboard modifiers
|
|
|
|
gint x, y;
|
|
|
|
GdkModifierType state = (GdkModifierType)0;
|
|
|
|
gdk_window_get_pointer(NULL, &x, &y, &state);
|
|
|
|
aEvent.isShift = (state & GDK_SHIFT_MASK) ? PR_TRUE : PR_FALSE;
|
|
|
|
aEvent.isControl = (state & GDK_CONTROL_MASK) ? PR_TRUE : PR_FALSE;
|
|
|
|
aEvent.isAlt = (state & GDK_MOD1_MASK) ? PR_TRUE : PR_FALSE;
|
|
|
|
aEvent.isMeta = PR_FALSE; // GTK+ doesn't support the meta key
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will update the drag action based on the information in the
|
|
|
|
// drag context. Gtk gets this from a combination of the key settings
|
|
|
|
// and what the source is offering.
|
|
|
|
|
|
|
|
void
|
2008-08-27 05:07:27 -07:00
|
|
|
nsWindow::UpdateDragStatus(nsDragEvent &aEvent,
|
2007-03-22 10:30:00 -07:00
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
nsIDragService *aDragService)
|
|
|
|
{
|
|
|
|
// default is to do nothing
|
|
|
|
int action = nsIDragService::DRAGDROP_ACTION_NONE;
|
|
|
|
|
|
|
|
// set the default just in case nothing matches below
|
|
|
|
if (aDragContext->actions & GDK_ACTION_DEFAULT)
|
|
|
|
action = nsIDragService::DRAGDROP_ACTION_MOVE;
|
|
|
|
|
|
|
|
// first check to see if move is set
|
|
|
|
if (aDragContext->actions & GDK_ACTION_MOVE)
|
|
|
|
action = nsIDragService::DRAGDROP_ACTION_MOVE;
|
|
|
|
|
|
|
|
// then fall to the others
|
|
|
|
else if (aDragContext->actions & GDK_ACTION_LINK)
|
|
|
|
action = nsIDragService::DRAGDROP_ACTION_LINK;
|
|
|
|
|
|
|
|
// copy is ctrl
|
|
|
|
else if (aDragContext->actions & GDK_ACTION_COPY)
|
|
|
|
action = nsIDragService::DRAGDROP_ACTION_COPY;
|
|
|
|
|
|
|
|
// update the drag information
|
|
|
|
nsCOMPtr<nsIDragSession> session;
|
|
|
|
aDragService->GetCurrentSession(getter_AddRefs(session));
|
|
|
|
|
|
|
|
if (session)
|
|
|
|
session->SetDragAction(action);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
|
|
|
drag_motion_event_cb(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return window->OnDragMotionEvent(aWidget,
|
|
|
|
aDragContext,
|
|
|
|
aX, aY, aTime, aData);
|
|
|
|
}
|
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
drag_leave_event_cb(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
window->OnDragLeaveEvent(aWidget, aDragContext, aTime, aData);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
gboolean
|
|
|
|
drag_drop_event_cb(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
guint aTime,
|
|
|
|
gpointer *aData)
|
|
|
|
{
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return window->OnDragDropEvent(aWidget,
|
|
|
|
aDragContext,
|
|
|
|
aX, aY, aTime, aData);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void
|
2007-04-29 17:46:47 -07:00
|
|
|
drag_data_received_event_cb(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX,
|
|
|
|
gint aY,
|
|
|
|
GtkSelectionData *aSelectionData,
|
|
|
|
guint aInfo,
|
|
|
|
guint aTime,
|
|
|
|
gpointer aData)
|
|
|
|
{
|
|
|
|
nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
window->OnDragDataReceivedEvent(aWidget,
|
|
|
|
aDragContext,
|
|
|
|
aX, aY,
|
|
|
|
aSelectionData,
|
|
|
|
aInfo, aTime, aData);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsresult
|
|
|
|
initialize_prefs(void)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
2007-06-16 12:19:46 -07:00
|
|
|
if (!prefs)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
PRBool val = PR_TRUE;
|
|
|
|
nsresult rv;
|
2008-09-17 14:15:52 -07:00
|
|
|
|
2007-06-16 12:19:46 -07:00
|
|
|
rv = prefs->GetBoolPref("mozilla.widget.raise-on-setfocus", &val);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
gRaiseWindows = val;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-17 14:15:52 -07:00
|
|
|
rv = prefs->GetBoolPref("mozilla.widget.force-24bpp", &val);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
gForce24bpp = val;
|
|
|
|
|
|
|
|
rv = prefs->GetBoolPref("mozilla.widget.use-buffer-pixmap", &val);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
gUseBufferPixmap = val;
|
|
|
|
|
|
|
|
rv = prefs->GetBoolPref("mozilla.widget.disable-native-theme", &val);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
gDisableNativeTheme = val;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::ResetDragMotionTimer(GtkWidget *aWidget,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
gint aX, gint aY, guint aTime)
|
|
|
|
{
|
|
|
|
|
|
|
|
// We have to be careful about ref ordering here. if aWidget ==
|
|
|
|
// mDraMotionWidget be careful not to let the refcnt drop to zero.
|
|
|
|
// Same with the drag context.
|
|
|
|
if (aWidget)
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_ref(aWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mDragMotionWidget)
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(mDragMotionWidget);
|
2007-03-22 10:30:00 -07:00
|
|
|
mDragMotionWidget = aWidget;
|
|
|
|
|
|
|
|
if (aDragContext)
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_ref(aDragContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mDragMotionContext)
|
2009-02-02 09:49:58 -08:00
|
|
|
g_object_unref(mDragMotionContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
mDragMotionContext = aDragContext;
|
|
|
|
|
|
|
|
mDragMotionX = aX;
|
|
|
|
mDragMotionY = aY;
|
|
|
|
mDragMotionTime = aTime;
|
|
|
|
|
|
|
|
// always clear the timer
|
|
|
|
if (mDragMotionTimerID) {
|
2009-02-02 09:49:58 -08:00
|
|
|
g_source_remove(mDragMotionTimerID);
|
2007-03-22 10:30:00 -07:00
|
|
|
mDragMotionTimerID = 0;
|
|
|
|
LOG(("*** canceled motion timer\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no widget was passed in, just return instead of setting a new
|
|
|
|
// timer
|
|
|
|
if (!aWidget) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise we create a new timer
|
2009-02-02 09:49:58 -08:00
|
|
|
mDragMotionTimerID = g_timeout_add(100,
|
|
|
|
(GtkFunction)DragMotionTimerCallback,
|
|
|
|
this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::FireDragMotionTimer(void)
|
|
|
|
{
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::FireDragMotionTimer(%p)\n", (void*)this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
OnDragMotionEvent(mDragMotionWidget, mDragMotionContext,
|
|
|
|
mDragMotionX, mDragMotionY, mDragMotionTime,
|
|
|
|
this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::FireDragLeaveTimer(void)
|
|
|
|
{
|
2009-06-14 17:48:52 -07:00
|
|
|
LOGDRAG(("nsWindow::FireDragLeaveTimer(%p)\n", (void*)this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-03-07 09:08:51 -08:00
|
|
|
mDragLeaveTimer = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// clean up any pending drag motion window info
|
|
|
|
if (mLastDragMotionWindow) {
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> kungFuDeathGrip = mLastDragMotionWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
// send our leave signal
|
|
|
|
mLastDragMotionWindow->OnDragLeave();
|
|
|
|
mLastDragMotionWindow = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
guint
|
|
|
|
nsWindow::DragMotionTimerCallback(gpointer aClosure)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
nsRefPtr<nsWindow> window = static_cast<nsWindow *>(aClosure);
|
2007-03-22 10:30:00 -07:00
|
|
|
window->FireDragMotionTimer();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
nsWindow::DragLeaveTimerCallback(nsITimer *aTimer, void *aClosure)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
nsRefPtr<nsWindow> window = static_cast<nsWindow *>(aClosure);
|
2007-03-22 10:30:00 -07:00
|
|
|
window->FireDragLeaveTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
GdkWindow *
|
|
|
|
get_inner_gdk_window (GdkWindow *aWindow,
|
|
|
|
gint x, gint y,
|
|
|
|
gint *retx, gint *rety)
|
|
|
|
{
|
|
|
|
gint cx, cy, cw, ch, cd;
|
|
|
|
GList * children = gdk_window_peek_children(aWindow);
|
|
|
|
guint num = g_list_length(children);
|
|
|
|
for (int i = 0; i < (int)num; i++) {
|
|
|
|
GList * child = g_list_nth(children, num - i - 1) ;
|
|
|
|
if (child) {
|
|
|
|
GdkWindow * childWindow = (GdkWindow *) child->data;
|
|
|
|
gdk_window_get_geometry (childWindow, &cx, &cy, &cw, &ch, &cd);
|
|
|
|
if ((cx < x) && (x < (cx + cw)) &&
|
|
|
|
(cy < y) && (y < (cy + ch)) &&
|
|
|
|
gdk_window_is_visible (childWindow)) {
|
|
|
|
return get_inner_gdk_window (childWindow,
|
|
|
|
x - cx, y - cy,
|
|
|
|
retx, rety);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*retx = x;
|
|
|
|
*rety = y;
|
|
|
|
return aWindow;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PRBool
|
|
|
|
is_context_menu_key(const nsKeyEvent& aKeyEvent)
|
|
|
|
{
|
|
|
|
return ((aKeyEvent.keyCode == NS_VK_F10 && aKeyEvent.isShift &&
|
|
|
|
!aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt) ||
|
|
|
|
(aKeyEvent.keyCode == NS_VK_CONTEXT_MENU && !aKeyEvent.isShift &&
|
|
|
|
!aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-02-20 02:04:56 -08:00
|
|
|
key_event_to_context_menu_event(nsMouseEvent &aEvent,
|
|
|
|
GdkEventKey *aGdkEvent)
|
|
|
|
{
|
2009-01-14 19:27:09 -08:00
|
|
|
aEvent.refPoint = nsIntPoint(0, 0);
|
2008-02-20 02:04:56 -08:00
|
|
|
aEvent.isShift = PR_FALSE;
|
|
|
|
aEvent.isControl = PR_FALSE;
|
|
|
|
aEvent.isAlt = PR_FALSE;
|
|
|
|
aEvent.isMeta = PR_FALSE;
|
|
|
|
aEvent.time = aGdkEvent->time;
|
|
|
|
aEvent.clickCount = 1;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
int
|
|
|
|
is_parent_ungrab_enter(GdkEventCrossing *aEvent)
|
|
|
|
{
|
|
|
|
return (GDK_CROSSING_UNGRAB == aEvent->mode) &&
|
|
|
|
((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
|
|
|
|
(GDK_NOTIFY_VIRTUAL == aEvent->detail));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
int
|
|
|
|
is_parent_grab_leave(GdkEventCrossing *aEvent)
|
|
|
|
{
|
|
|
|
return (GDK_CROSSING_GRAB == aEvent->mode) &&
|
|
|
|
((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
|
|
|
|
(GDK_NOTIFY_VIRTUAL == aEvent->detail));
|
|
|
|
}
|
|
|
|
|
2007-06-16 12:19:46 -07:00
|
|
|
static GdkModifierType
|
|
|
|
gdk_keyboard_get_modifiers()
|
|
|
|
{
|
|
|
|
GdkModifierType m = (GdkModifierType) 0;
|
|
|
|
|
|
|
|
gdk_window_get_pointer(NULL, NULL, NULL, &m);
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2007-06-16 12:19:46 -07:00
|
|
|
// Get the modifier masks for GDK_Caps_Lock, GDK_Num_Lock and GDK_Scroll_Lock.
|
|
|
|
// Return PR_TRUE on success, PR_FALSE on error.
|
|
|
|
static PRBool
|
|
|
|
gdk_keyboard_get_modmap_masks(Display* aDisplay,
|
|
|
|
PRUint32* aCapsLockMask,
|
|
|
|
PRUint32* aNumLockMask,
|
|
|
|
PRUint32* aScrollLockMask)
|
|
|
|
{
|
|
|
|
*aCapsLockMask = 0;
|
|
|
|
*aNumLockMask = 0;
|
|
|
|
*aScrollLockMask = 0;
|
|
|
|
|
|
|
|
int min_keycode = 0;
|
|
|
|
int max_keycode = 0;
|
|
|
|
XDisplayKeycodes(aDisplay, &min_keycode, &max_keycode);
|
|
|
|
|
|
|
|
int keysyms_per_keycode = 0;
|
|
|
|
KeySym* xkeymap = XGetKeyboardMapping(aDisplay, min_keycode,
|
|
|
|
max_keycode - min_keycode + 1,
|
|
|
|
&keysyms_per_keycode);
|
|
|
|
if (!xkeymap) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
XModifierKeymap* xmodmap = XGetModifierMapping(aDisplay);
|
|
|
|
if (!xmodmap) {
|
|
|
|
XFree(xkeymap);
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
The modifiermap member of the XModifierKeymap structure contains 8 sets
|
|
|
|
of max_keypermod KeyCodes, one for each modifier in the order Shift,
|
|
|
|
Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5.
|
|
|
|
Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are ignored.
|
|
|
|
*/
|
|
|
|
const unsigned int map_size = 8 * xmodmap->max_keypermod;
|
|
|
|
for (unsigned int i = 0; i < map_size; i++) {
|
|
|
|
KeyCode keycode = xmodmap->modifiermap[i];
|
|
|
|
if (!keycode || keycode < min_keycode || keycode > max_keycode)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const KeySym* syms = xkeymap + (keycode - min_keycode) * keysyms_per_keycode;
|
|
|
|
const unsigned int mask = 1 << (i / xmodmap->max_keypermod);
|
|
|
|
for (int j = 0; j < keysyms_per_keycode; j++) {
|
|
|
|
switch (syms[j]) {
|
|
|
|
case GDK_Caps_Lock: *aCapsLockMask |= mask; break;
|
|
|
|
case GDK_Num_Lock: *aNumLockMask |= mask; break;
|
|
|
|
case GDK_Scroll_Lock: *aScrollLockMask |= mask; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XFreeModifiermap(xmodmap);
|
|
|
|
XFree(xkeymap);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif /* MOZ_X11 */
|
2007-06-16 12:19:46 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
/**
|
|
|
|
* void
|
|
|
|
* nsWindow::CreateRootAccessible
|
|
|
|
*
|
|
|
|
* request to create the nsIAccessible Object for the toplevel window
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
nsWindow::CreateRootAccessible()
|
|
|
|
{
|
|
|
|
if (mIsTopLevel && !mRootAccessible) {
|
|
|
|
nsCOMPtr<nsIAccessible> acc;
|
|
|
|
DispatchAccessibleEvent(getter_AddRefs(acc));
|
|
|
|
|
|
|
|
if (acc) {
|
|
|
|
mRootAccessible = acc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::GetRootAccessible(nsIAccessible** aAccessible)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAccessible> accessible, parentAccessible;
|
|
|
|
DispatchAccessibleEvent(getter_AddRefs(accessible));
|
|
|
|
PRUint32 role;
|
|
|
|
|
|
|
|
if (!accessible) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (PR_TRUE) {
|
|
|
|
accessible->GetParent(getter_AddRefs(parentAccessible));
|
|
|
|
if (!parentAccessible) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
parentAccessible->GetRole(&role);
|
|
|
|
if (role == nsIAccessibleRole::ROLE_APP_ROOT) {
|
|
|
|
NS_ADDREF(*aAccessible = accessible);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
accessible = parentAccessible;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* void
|
|
|
|
* nsWindow::DispatchAccessibleEvent
|
|
|
|
* @aAccessible: the out var, hold the new accessible object
|
|
|
|
*
|
|
|
|
* generate the NS_GETACCESSIBLE event, the event handler is
|
|
|
|
* reponsible to create an nsIAccessible instant.
|
|
|
|
**/
|
|
|
|
PRBool
|
|
|
|
nsWindow::DispatchAccessibleEvent(nsIAccessible** aAccessible)
|
|
|
|
{
|
|
|
|
PRBool result = PR_FALSE;
|
|
|
|
nsAccessibleEvent event(PR_TRUE, NS_GETACCESSIBLE, this);
|
|
|
|
|
|
|
|
*aAccessible = nsnull;
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
result = (nsEventStatus_eConsumeNoDefault == status) ? PR_TRUE : PR_FALSE;
|
|
|
|
|
|
|
|
// if the event returned an accesssible get it.
|
|
|
|
if (event.accessible)
|
|
|
|
*aAccessible = event.accessible;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-18 18:13:27 -07:00
|
|
|
nsWindow::DispatchActivateEventAccessible(void)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (sAccessibilityEnabled) {
|
|
|
|
nsCOMPtr<nsIAccessible> rootAcc;
|
|
|
|
GetRootAccessible(getter_AddRefs(rootAcc));
|
2008-11-03 19:36:36 -08:00
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessibilityService> accService =
|
|
|
|
do_GetService("@mozilla.org/accessibilityService;1");
|
|
|
|
|
|
|
|
if (accService) {
|
|
|
|
accService->FireAccessibleEvent(
|
|
|
|
nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE,
|
|
|
|
rootAcc);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-18 18:13:27 -07:00
|
|
|
nsWindow::DispatchDeactivateEventAccessible(void)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (sAccessibilityEnabled) {
|
|
|
|
nsCOMPtr<nsIAccessible> rootAcc;
|
|
|
|
GetRootAccessible(getter_AddRefs(rootAcc));
|
2008-11-03 19:36:36 -08:00
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessibilityService> accService =
|
|
|
|
do_GetService("@mozilla.org/accessibilityService;1");
|
|
|
|
|
|
|
|
if (accService) {
|
|
|
|
accService->FireAccessibleEvent(
|
|
|
|
nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE,
|
|
|
|
rootAcc);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-10-18 18:13:27 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif /* #ifdef ACCESSIBILITY */
|
|
|
|
|
|
|
|
// nsChildWindow class
|
|
|
|
|
|
|
|
nsChildWindow::nsChildWindow()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsChildWindow::~nsChildWindow()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_XIM
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::IMEInitData(void)
|
|
|
|
{
|
|
|
|
if (mIMEData)
|
|
|
|
return;
|
2009-02-19 18:07:08 -08:00
|
|
|
nsWindow *win = GetContainerWindow();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!win)
|
|
|
|
return;
|
|
|
|
mIMEData = win->mIMEData;
|
|
|
|
if (!mIMEData)
|
|
|
|
return;
|
|
|
|
mIMEData->mRefCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::IMEReleaseData(void)
|
|
|
|
{
|
|
|
|
if (!mIMEData)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mIMEData->mRefCount--;
|
|
|
|
if (mIMEData->mRefCount != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
delete mIMEData;
|
|
|
|
mIMEData = nsnull;
|
|
|
|
}
|
|
|
|
|
2007-10-11 20:02:26 -07:00
|
|
|
// Work around gtk bug http://bugzilla.gnome.org/show_bug.cgi?id=483223:
|
2007-10-24 23:51:23 -07:00
|
|
|
// (and the similar issue of GTK+ IIIM)
|
|
|
|
// The GTK+ XIM and IIIM modules register handlers for the "closed" signal
|
|
|
|
// on the display, but:
|
2007-10-11 20:02:26 -07:00
|
|
|
// * The signal handlers are not disconnected when the module is unloaded.
|
2009-02-27 17:47:40 -08:00
|
|
|
//
|
|
|
|
// The GTK+ XIM module has another problem:
|
2007-10-11 20:02:26 -07:00
|
|
|
// * When the signal handler is run (with the module loaded) it tries
|
|
|
|
// XFree (and fails) on a pointer that did not come from Xmalloc.
|
|
|
|
//
|
2007-10-24 23:51:23 -07:00
|
|
|
// To prevent these modules from being unloaded, use static variables to
|
|
|
|
// hold ref of GtkIMContext class.
|
|
|
|
// For GTK+ XIM module, to prevent the signal handler from being run,
|
|
|
|
// find the signal handlers and remove them.
|
2009-02-27 17:47:40 -08:00
|
|
|
//
|
2007-10-11 20:02:26 -07:00
|
|
|
// GtkIMContextXIMs share XOpenIM connections and display closed signal
|
|
|
|
// handlers (where possible).
|
|
|
|
|
2007-10-24 23:51:23 -07:00
|
|
|
static void workaround_gtk_im_display_closed(GtkWidget *aGtkWidget,
|
|
|
|
GtkIMContext *aContext)
|
2007-10-11 20:02:26 -07:00
|
|
|
{
|
|
|
|
GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (aContext);
|
|
|
|
GtkIMContext *slave = multicontext->slave;
|
|
|
|
if (!slave)
|
|
|
|
return;
|
|
|
|
|
|
|
|
GType slaveType = G_TYPE_FROM_INSTANCE(slave);
|
2007-10-24 23:51:23 -07:00
|
|
|
const gchar *im_type_name = g_type_name(slaveType);
|
|
|
|
if (strcmp(im_type_name, "GtkIMContextXIM") == 0) {
|
|
|
|
if (gtk_check_version(2, 12, 1) == NULL) // gtk bug has been fixed
|
|
|
|
return;
|
|
|
|
|
|
|
|
struct GtkIMContextXIM
|
|
|
|
{
|
|
|
|
GtkIMContext parent;
|
|
|
|
gpointer private_data;
|
|
|
|
// ... other fields
|
|
|
|
};
|
|
|
|
gpointer signal_data =
|
|
|
|
reinterpret_cast<GtkIMContextXIM*>(slave)->private_data;
|
|
|
|
if (!signal_data)
|
|
|
|
return; // no corresponding handler
|
2007-10-11 20:02:26 -07:00
|
|
|
|
|
|
|
g_signal_handlers_disconnect_matched(gtk_widget_get_display(aGtkWidget),
|
|
|
|
G_SIGNAL_MATCH_DATA, 0, 0, NULL,
|
|
|
|
NULL, signal_data);
|
|
|
|
|
2007-10-24 23:51:23 -07:00
|
|
|
// Add a reference to prevent the XIM module from being unloaded
|
2007-10-11 20:02:26 -07:00
|
|
|
// and reloaded: each time the module is loaded and used, it
|
|
|
|
// opens (and doesn't close) new XOpenIM connections.
|
2007-10-24 23:51:23 -07:00
|
|
|
static gpointer gtk_xim_context_class =
|
|
|
|
g_type_class_ref(slaveType);
|
2009-03-07 09:08:51 -08:00
|
|
|
// Mute unused variable warning:
|
|
|
|
gtk_xim_context_class = gtk_xim_context_class;
|
2007-10-24 23:51:23 -07:00
|
|
|
}
|
|
|
|
else if (strcmp(im_type_name, "GtkIMContextIIIM") == 0) {
|
|
|
|
// Add a reference to prevent the IIIM module from being unloaded
|
|
|
|
static gpointer gtk_iiim_context_class =
|
|
|
|
g_type_class_ref(slaveType);
|
2009-03-07 09:08:51 -08:00
|
|
|
// Mute unused variable warning:
|
|
|
|
gtk_iiim_context_class = gtk_iiim_context_class;
|
2007-10-11 20:02:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsWindow::IMEDestroyContext(void)
|
|
|
|
{
|
|
|
|
if (!mIMEData || mIMEData->mOwner != this) {
|
|
|
|
// This nsWindow is not the owner of the instance of mIMEData.
|
|
|
|
if (IMEComposingWindow() == this)
|
|
|
|
CancelIMEComposition();
|
|
|
|
if (gIMEFocusWindow == this)
|
|
|
|
gIMEFocusWindow = nsnull;
|
|
|
|
IMEReleaseData();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NOTE:
|
|
|
|
* This nsWindow is the owner of the instance of mIMEData,
|
|
|
|
* so, we must release the contexts now. But that might be referred from
|
|
|
|
* other nsWindows.(They are children of this. But we don't know why there
|
|
|
|
* are the cases.) So, we need to clear the pointers that refers to contexts
|
|
|
|
* and this if the other referrers are still alive. See bug 349727.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// If this is the focus window and we have an IM context we need
|
|
|
|
// to unset the focus on this window before we destroy the window.
|
|
|
|
GtkIMContext *im = IMEGetContext();
|
|
|
|
if (im && gIMEFocusWindow && gIMEFocusWindow->IMEGetContext() == im) {
|
|
|
|
gIMEFocusWindow->IMELoseFocus();
|
|
|
|
gIMEFocusWindow = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
mIMEData->mOwner = nsnull;
|
2008-07-13 19:56:18 -07:00
|
|
|
mIMEData->mEnabled = nsIWidget::IME_STATUS_DISABLED;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mIMEData->mContext) {
|
2007-10-24 23:51:23 -07:00
|
|
|
workaround_gtk_im_display_closed(GTK_WIDGET(mContainer),
|
|
|
|
mIMEData->mContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
gtk_im_context_set_client_window(mIMEData->mContext, nsnull);
|
|
|
|
g_object_unref(G_OBJECT(mIMEData->mContext));
|
|
|
|
mIMEData->mContext = nsnull;
|
|
|
|
}
|
|
|
|
|
2008-04-29 08:31:51 -07:00
|
|
|
if (mIMEData->mSimpleContext) {
|
|
|
|
gtk_im_context_set_client_window(mIMEData->mSimpleContext, nsnull);
|
|
|
|
g_object_unref(G_OBJECT(mIMEData->mSimpleContext));
|
|
|
|
mIMEData->mSimpleContext = nsnull;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mIMEData->mDummyContext) {
|
2007-10-11 20:02:26 -07:00
|
|
|
// mIMEData->mContext and mIMEData->mDummyContext have the same
|
|
|
|
// slaveType and signal_data so no need for another
|
2007-10-24 23:51:23 -07:00
|
|
|
// workaround_gtk_im_display_closed.
|
2007-03-22 10:30:00 -07:00
|
|
|
gtk_im_context_set_client_window(mIMEData->mDummyContext, nsnull);
|
|
|
|
g_object_unref(G_OBJECT(mIMEData->mDummyContext));
|
|
|
|
mIMEData->mDummyContext = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMEReleaseData();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::IMESetFocus(void)
|
|
|
|
{
|
|
|
|
IMEInitData();
|
|
|
|
|
|
|
|
LOGIM(("IMESetFocus %p\n", (void *)this));
|
|
|
|
GtkIMContext *im = IMEGetContext();
|
|
|
|
if (!im)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gtk_im_context_focus_in(im);
|
|
|
|
gIMEFocusWindow = this;
|
|
|
|
|
2008-04-29 08:31:51 -07:00
|
|
|
if (!IMEIsEnabledState()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// We should release IME focus for uim and scim.
|
|
|
|
// These IMs are using snooper that is released at losing focus.
|
|
|
|
IMELoseFocus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::IMELoseFocus(void)
|
|
|
|
{
|
|
|
|
LOGIM(("IMELoseFocus %p\n", (void *)this));
|
|
|
|
GtkIMContext *im = IMEGetContext();
|
|
|
|
if (!im)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gtk_im_context_focus_out(im);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::IMEComposeStart(void)
|
|
|
|
{
|
|
|
|
LOGIM(("IMEComposeStart [%p]\n", (void *)this));
|
|
|
|
|
|
|
|
if (!mIMEData) {
|
|
|
|
NS_ERROR("This widget doesn't support IM");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IMEComposingWindow()) {
|
|
|
|
NS_WARNING("tried to re-start text composition\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mIMEData->mComposingWindow = this;
|
|
|
|
|
|
|
|
nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_START, this);
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&compEvent, status);
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
if (NS_UNLIKELY(mIsDestroyed))
|
|
|
|
return;
|
|
|
|
|
2008-07-30 09:12:49 -07:00
|
|
|
IMESetCursorPosition(compEvent.theReply);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-04-29 17:46:47 -07:00
|
|
|
nsWindow::IMEComposeText(const PRUnichar *aText,
|
|
|
|
const PRInt32 aLen,
|
|
|
|
const gchar *aPreeditString,
|
|
|
|
const gint aCursorPos,
|
|
|
|
const PangoAttrList *aFeedback)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (!mIMEData) {
|
|
|
|
NS_ERROR("This widget doesn't support IM");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send our start composition event if we need to
|
2007-04-29 17:46:47 -07:00
|
|
|
if (!IMEComposingWindow()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
IMEComposeStart();
|
2007-04-29 17:46:47 -07:00
|
|
|
if (NS_UNLIKELY(mIsDestroyed))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
LOGIM(("IMEComposeText\n"));
|
|
|
|
nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, this);
|
|
|
|
|
|
|
|
if (aLen != 0) {
|
|
|
|
textEvent.theText = (PRUnichar*)aText;
|
|
|
|
|
|
|
|
if (aPreeditString && aFeedback && (aLen > 0)) {
|
|
|
|
IM_set_text_range(aLen, aPreeditString, aCursorPos, aFeedback,
|
|
|
|
&(textEvent.rangeCount),
|
|
|
|
&(textEvent.rangeArray));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&textEvent, status);
|
|
|
|
|
|
|
|
if (textEvent.rangeArray) {
|
|
|
|
delete[] textEvent.rangeArray;
|
|
|
|
}
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
if (NS_UNLIKELY(mIsDestroyed))
|
|
|
|
return;
|
|
|
|
|
2008-07-30 09:12:49 -07:00
|
|
|
IMESetCursorPosition(textEvent.theReply);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::IMEComposeEnd(void)
|
|
|
|
{
|
|
|
|
LOGIM(("IMEComposeEnd [%p]\n", (void *)this));
|
|
|
|
NS_ASSERTION(mIMEData, "This widget doesn't support IM");
|
|
|
|
|
|
|
|
if (!IMEComposingWindow()) {
|
|
|
|
NS_WARNING("tried to end text composition before it was started");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mIMEData->mComposingWindow = nsnull;
|
|
|
|
|
|
|
|
nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_END, this);
|
|
|
|
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&compEvent, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkIMContext*
|
|
|
|
nsWindow::IMEGetContext()
|
|
|
|
{
|
|
|
|
return IM_get_input_context(this);
|
|
|
|
}
|
|
|
|
|
2007-04-15 06:43:55 -07:00
|
|
|
static PRBool
|
|
|
|
IsIMEEnabledState(PRUint32 aState)
|
|
|
|
{
|
2009-08-20 21:31:56 -07:00
|
|
|
#ifdef MOZ_PLATFORM_HILDON
|
|
|
|
return aState == nsIWidget::IME_STATUS_ENABLED ||
|
|
|
|
aState == nsIWidget::IME_STATUS_PLUGIN ||
|
|
|
|
aState == nsIWidget::IME_STATUS_PASSWORD;
|
|
|
|
#else
|
2008-12-14 19:54:54 -08:00
|
|
|
return aState == nsIWidget::IME_STATUS_ENABLED ||
|
|
|
|
aState == nsIWidget::IME_STATUS_PLUGIN;
|
2009-08-20 21:31:56 -07:00
|
|
|
#endif
|
2007-04-15 06:43:55 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRBool
|
2008-04-29 08:31:51 -07:00
|
|
|
nsWindow::IMEIsEnabledState(void)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-15 06:43:55 -07:00
|
|
|
return mIMEData ? IsIMEEnabledState(mIMEData->mEnabled) : PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-04-29 08:31:51 -07:00
|
|
|
static PRBool
|
|
|
|
IsIMEEditableState(PRUint32 aState)
|
|
|
|
{
|
2008-07-13 19:56:18 -07:00
|
|
|
return aState == nsIWidget::IME_STATUS_ENABLED ||
|
2008-12-14 19:54:54 -08:00
|
|
|
aState == nsIWidget::IME_STATUS_PLUGIN ||
|
2008-07-13 19:56:18 -07:00
|
|
|
aState == nsIWidget::IME_STATUS_PASSWORD;
|
2008-04-29 08:31:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsWindow::IMEIsEditableState(void)
|
|
|
|
{
|
|
|
|
return mIMEData ? IsIMEEditableState(mIMEData->mEnabled) : PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsWindow*
|
|
|
|
nsWindow::IMEComposingWindow(void)
|
|
|
|
{
|
|
|
|
return mIMEData ? mIMEData->mComposingWindow : nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::IMECreateContext(void)
|
|
|
|
{
|
|
|
|
mIMEData = new nsIMEData(this);
|
|
|
|
if (!mIMEData)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mIMEData->mContext = gtk_im_multicontext_new();
|
2008-04-29 08:31:51 -07:00
|
|
|
mIMEData->mSimpleContext = gtk_im_context_simple_new();
|
2007-03-22 10:30:00 -07:00
|
|
|
mIMEData->mDummyContext = gtk_im_multicontext_new();
|
2008-04-29 08:31:51 -07:00
|
|
|
if (!mIMEData->mContext || !mIMEData->mSimpleContext ||
|
|
|
|
!mIMEData->mDummyContext) {
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ERROR("failed to create IM context.");
|
|
|
|
IMEDestroyContext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_im_context_set_client_window(mIMEData->mContext,
|
|
|
|
GTK_WIDGET(mContainer)->window);
|
2008-04-29 08:31:51 -07:00
|
|
|
gtk_im_context_set_client_window(mIMEData->mSimpleContext,
|
|
|
|
GTK_WIDGET(mContainer)->window);
|
2007-03-22 10:30:00 -07:00
|
|
|
gtk_im_context_set_client_window(mIMEData->mDummyContext,
|
|
|
|
GTK_WIDGET(mContainer)->window);
|
|
|
|
|
|
|
|
g_signal_connect(G_OBJECT(mIMEData->mContext), "preedit_changed",
|
|
|
|
G_CALLBACK(IM_preedit_changed_cb), this);
|
|
|
|
g_signal_connect(G_OBJECT(mIMEData->mContext), "commit",
|
|
|
|
G_CALLBACK(IM_commit_cb), this);
|
2008-04-29 08:31:51 -07:00
|
|
|
g_signal_connect(G_OBJECT(mIMEData->mSimpleContext), "preedit_changed",
|
|
|
|
G_CALLBACK(IM_preedit_changed_cb), this);
|
|
|
|
g_signal_connect(G_OBJECT(mIMEData->mSimpleContext), "commit",
|
|
|
|
G_CALLBACK(IM_commit_cb), this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsWindow::IMEFilterEvent(GdkEventKey *aEvent)
|
|
|
|
{
|
2008-04-29 08:31:51 -07:00
|
|
|
if (!IMEIsEditableState())
|
2007-03-22 10:30:00 -07:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
GtkIMContext *im = IMEGetContext();
|
|
|
|
if (!im)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gKeyEvent = aEvent;
|
|
|
|
gboolean filtered = gtk_im_context_filter_keypress(im, aEvent);
|
|
|
|
gKeyEvent = NULL;
|
|
|
|
|
|
|
|
LOGIM(("key filtered: %d committed: %d changed: %d\n",
|
|
|
|
filtered, gKeyEventCommitted, gKeyEventChanged));
|
|
|
|
|
|
|
|
// We filter the key event if the event was not committed (because
|
|
|
|
// it's probably part of a composition) or if the key event was
|
|
|
|
// committed _and_ changed. This way we still let key press
|
|
|
|
// events go through as simple key press events instead of
|
|
|
|
// composed characters.
|
|
|
|
|
|
|
|
PRBool retval = PR_FALSE;
|
|
|
|
if (filtered &&
|
|
|
|
(!gKeyEventCommitted || (gKeyEventCommitted && gKeyEventChanged)))
|
|
|
|
retval = PR_TRUE;
|
|
|
|
|
|
|
|
gKeyEventChanged = PR_FALSE;
|
|
|
|
gKeyEventCommitted = PR_FALSE;
|
|
|
|
gKeyEventChanged = PR_FALSE;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2008-07-30 09:12:49 -07:00
|
|
|
void
|
|
|
|
nsWindow::IMESetCursorPosition(const nsTextEventReply& aReply)
|
|
|
|
{
|
|
|
|
nsIWidget *refWidget = aReply.mReferenceWidget;
|
|
|
|
if (!refWidget) {
|
|
|
|
NS_WARNING("mReferenceWidget is null");
|
|
|
|
refWidget = this;
|
|
|
|
}
|
|
|
|
nsWindow* refWindow = static_cast<nsWindow*>(refWidget);
|
|
|
|
|
2009-02-19 18:07:08 -08:00
|
|
|
nsWindow* ownerWindow = GetContainerWindow();
|
2008-07-30 09:12:49 -07:00
|
|
|
if (!ownerWindow) {
|
|
|
|
NS_ERROR("there is no owner");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the position of the refWindow in screen.
|
|
|
|
gint refX, refY;
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_get_origin(refWindow->mGdkWindow, &refX, &refY);
|
2008-07-30 09:12:49 -07:00
|
|
|
|
|
|
|
// Get the position of IM context owner window in screen.
|
|
|
|
gint ownerX, ownerY;
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_get_origin(ownerWindow->mGdkWindow, &ownerX, &ownerY);
|
2008-07-30 09:12:49 -07:00
|
|
|
|
|
|
|
// Compute the caret position in the IM owner window.
|
|
|
|
GdkRectangle area;
|
|
|
|
area.x = aReply.mCursorPosition.x + refX - ownerX;
|
|
|
|
area.y = aReply.mCursorPosition.y + refY - ownerY;
|
|
|
|
area.width = 0;
|
|
|
|
area.height = aReply.mCursorPosition.height;
|
|
|
|
|
|
|
|
gtk_im_context_set_cursor_location(IMEGetContext(), &area);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::ResetInputState()
|
|
|
|
{
|
|
|
|
IMEInitData();
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> win = IMEComposingWindow();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (win) {
|
|
|
|
GtkIMContext *im = IMEGetContext();
|
|
|
|
if (!im)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
gchar *preedit_string;
|
|
|
|
gint cursor_pos;
|
|
|
|
PangoAttrList *feedback_list;
|
|
|
|
gtk_im_context_get_preedit_string(im, &preedit_string,
|
|
|
|
&feedback_list, &cursor_pos);
|
|
|
|
if (preedit_string && *preedit_string) {
|
|
|
|
IM_commit_cb_internal(preedit_string, win);
|
|
|
|
g_free(preedit_string);
|
|
|
|
}
|
|
|
|
if (feedback_list)
|
|
|
|
pango_attr_list_unref(feedback_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
CancelIMEComposition();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::SetIMEOpenState(PRBool aState)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::GetIMEOpenState(PRBool* aState)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-04-15 06:43:55 -07:00
|
|
|
nsWindow::SetIMEEnabled(PRUint32 aState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
IMEInitData();
|
2007-04-15 06:43:55 -07:00
|
|
|
if (!mIMEData)
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-29 08:31:51 -07:00
|
|
|
if (aState == mIMEData->mEnabled)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
GtkIMContext *focusedIm = nsnull;
|
|
|
|
// XXX Don't we need to check gFocusWindow?
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> focusedWin = gIMEFocusWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (focusedWin && focusedWin->mIMEData)
|
|
|
|
focusedIm = focusedWin->mIMEData->mContext;
|
|
|
|
|
|
|
|
if (focusedIm && focusedIm == mIMEData->mContext) {
|
|
|
|
// Release current IME focus if IME is enabled.
|
2008-04-29 08:31:51 -07:00
|
|
|
if (IsIMEEditableState(mIMEData->mEnabled)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
focusedWin->ResetInputState();
|
|
|
|
focusedWin->IMELoseFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
mIMEData->mEnabled = aState;
|
|
|
|
|
|
|
|
// Even when aState is not PR_TRUE, we need to set IME focus.
|
|
|
|
// Because some IMs are updating the status bar of them in this time.
|
|
|
|
focusedWin->IMESetFocus();
|
2008-09-10 09:12:58 -07:00
|
|
|
#ifdef MOZ_PLATFORM_HILDON
|
2008-09-15 08:58:57 -07:00
|
|
|
if (mIMEData->mEnabled) {
|
2008-12-14 22:43:25 -08:00
|
|
|
// It is not desired that the hildon's autocomplete mechanism displays
|
|
|
|
// user previous entered passwds, so lets make completions invisible
|
|
|
|
// in these cases.
|
|
|
|
int mode;
|
2009-08-20 21:31:56 -07:00
|
|
|
g_object_get (G_OBJECT(IMEGetContext()), "hildon-input-mode", &mode, NULL);
|
|
|
|
|
|
|
|
if (mIMEData->mEnabled == nsIWidget::IME_STATUS_ENABLED ||
|
|
|
|
mIMEData->mEnabled == nsIWidget::IME_STATUS_PLUGIN)
|
2008-12-14 22:43:25 -08:00
|
|
|
mode &= ~HILDON_GTK_INPUT_MODE_INVISIBLE;
|
|
|
|
else if (mIMEData->mEnabled == nsIWidget::IME_STATUS_PASSWORD)
|
|
|
|
mode |= HILDON_GTK_INPUT_MODE_INVISIBLE;
|
|
|
|
|
2009-09-24 21:30:55 -07:00
|
|
|
// Turn off auto-capitalization for editboxes
|
|
|
|
mode &= ~HILDON_GTK_INPUT_MODE_AUTOCAP;
|
|
|
|
|
2009-08-20 21:31:56 -07:00
|
|
|
g_object_set (G_OBJECT(IMEGetContext()), "hildon-input-mode", (HildonGtkInputMode)mode, NULL);
|
2008-09-15 08:58:57 -07:00
|
|
|
gIMEVirtualKeyboardOpened = PR_TRUE;
|
2009-08-20 21:31:56 -07:00
|
|
|
hildon_gtk_im_context_show (IMEGetContext());
|
2008-09-15 08:58:57 -07:00
|
|
|
} else {
|
|
|
|
gIMEVirtualKeyboardOpened = PR_FALSE;
|
2009-08-20 21:31:56 -07:00
|
|
|
hildon_gtk_im_context_hide (IMEGetContext());
|
2008-09-15 08:58:57 -07:00
|
|
|
}
|
2009-09-25 09:52:11 -07:00
|
|
|
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
|
|
|
|
if (observerService) {
|
|
|
|
nsAutoString rectBuf;
|
|
|
|
PRInt32 x, y, w, h;
|
|
|
|
gdk_window_get_position(mGdkWindow, &x, &y);
|
|
|
|
gdk_window_get_size(mGdkWindow, &w, &h);
|
|
|
|
rectBuf.Assign(NS_LITERAL_STRING("{\"left\": "));
|
|
|
|
rectBuf.AppendInt(x);
|
|
|
|
rectBuf.Append(NS_LITERAL_STRING(" \"top\": "));
|
|
|
|
rectBuf.AppendInt(y);
|
|
|
|
rectBuf.Append(NS_LITERAL_STRING(", \"right\": "));
|
|
|
|
rectBuf.AppendInt(w);
|
|
|
|
rectBuf.Append(NS_LITERAL_STRING(", \"bottom\": "));
|
|
|
|
rectBuf.AppendInt(h);
|
|
|
|
rectBuf.Append(NS_LITERAL_STRING("}"));
|
|
|
|
observerService->NotifyObservers(nsnull, "softkb-change", rectBuf.get());
|
|
|
|
}
|
2008-09-10 09:12:58 -07:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2008-04-29 08:31:51 -07:00
|
|
|
if (IsIMEEditableState(mIMEData->mEnabled))
|
2007-03-22 10:30:00 -07:00
|
|
|
ResetInputState();
|
|
|
|
mIMEData->mEnabled = aState;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-04-15 06:43:55 -07:00
|
|
|
nsWindow::GetIMEEnabled(PRUint32* aState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aState);
|
|
|
|
|
|
|
|
IMEInitData();
|
|
|
|
|
2007-04-15 06:43:55 -07:00
|
|
|
*aState =
|
2008-07-13 19:56:18 -07:00
|
|
|
mIMEData ? mIMEData->mEnabled : nsIWidget::IME_STATUS_DISABLED;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::CancelIMEComposition()
|
|
|
|
{
|
|
|
|
IMEInitData();
|
|
|
|
|
|
|
|
GtkIMContext *im = IMEGetContext();
|
|
|
|
if (!im)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
NS_ASSERTION(!gIMESuppressCommit,
|
|
|
|
"CancelIMEComposition is already called!");
|
|
|
|
gIMESuppressCommit = PR_TRUE;
|
|
|
|
gtk_im_context_reset(im);
|
|
|
|
gIMESuppressCommit = PR_FALSE;
|
|
|
|
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> win = IMEComposingWindow();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (win) {
|
|
|
|
win->IMEComposeText(nsnull, 0, nsnull, 0, nsnull);
|
|
|
|
win->IMEComposeEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-06-16 12:19:46 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aLEDState);
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
|
|
|
|
2007-06-16 12:19:46 -07:00
|
|
|
GdkModifierType modifiers = gdk_keyboard_get_modifiers();
|
|
|
|
PRUint32 capsLockMask, numLockMask, scrollLockMask;
|
|
|
|
PRBool foundMasks = gdk_keyboard_get_modmap_masks(
|
2009-07-26 18:39:36 -07:00
|
|
|
GDK_WINDOW_XDISPLAY(mGdkWindow),
|
2007-06-16 12:19:46 -07:00
|
|
|
&capsLockMask, &numLockMask, &scrollLockMask);
|
2008-01-01 02:21:28 -08:00
|
|
|
if (!foundMasks)
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
2007-06-16 12:19:46 -07:00
|
|
|
|
|
|
|
PRUint32 mask = 0;
|
|
|
|
switch (aKeyCode) {
|
|
|
|
case NS_VK_CAPS_LOCK: mask = capsLockMask; break;
|
|
|
|
case NS_VK_NUM_LOCK: mask = numLockMask; break;
|
|
|
|
case NS_VK_SCROLL_LOCK: mask = scrollLockMask; break;
|
|
|
|
}
|
|
|
|
if (mask == 0)
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
|
|
|
|
*aLEDState = (modifiers & mask) != 0;
|
|
|
|
return NS_OK;
|
2008-08-06 13:48:55 -07:00
|
|
|
#else
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
#endif /* MOZ_X11 */
|
2007-06-16 12:19:46 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
IM_preedit_changed_cb(GtkIMContext *aContext,
|
|
|
|
nsWindow *aWindow)
|
|
|
|
{
|
|
|
|
gchar *preedit_string;
|
|
|
|
gint cursor_pos;
|
|
|
|
PangoAttrList *feedback_list;
|
|
|
|
|
|
|
|
// if gFocusWindow is null, use the last focused gIMEFocusWindow
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = gFocusWindow ? gFocusWindow : gIMEFocusWindow;
|
2009-01-13 23:10:52 -08:00
|
|
|
if (!window || IM_get_input_context(window) != aContext)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Should use cursor_pos ?
|
|
|
|
// Of course!!!
|
|
|
|
gtk_im_context_get_preedit_string(aContext, &preedit_string,
|
|
|
|
&feedback_list, &cursor_pos);
|
|
|
|
|
|
|
|
LOGIM(("preedit string is: %s length is: %d\n",
|
|
|
|
preedit_string, strlen(preedit_string)));
|
|
|
|
|
|
|
|
if (!preedit_string || !*preedit_string) {
|
|
|
|
LOGIM(("preedit ended\n"));
|
|
|
|
window->IMEComposeText(NULL, 0, NULL, 0, NULL);
|
|
|
|
window->IMEComposeEnd();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGIM(("preedit len %d\n", strlen(preedit_string)));
|
|
|
|
|
|
|
|
gunichar2 * uniStr;
|
|
|
|
glong uniStrLen;
|
|
|
|
|
|
|
|
uniStr = NULL;
|
|
|
|
uniStrLen = 0;
|
|
|
|
uniStr = g_utf8_to_utf16(preedit_string, -1, NULL, &uniStrLen, NULL);
|
|
|
|
|
|
|
|
if (!uniStr) {
|
|
|
|
g_free(preedit_string);
|
|
|
|
LOG(("utf8-utf16 string tranfer failed!\n"));
|
|
|
|
if (feedback_list)
|
|
|
|
pango_attr_list_unref(feedback_list);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uniStrLen) {
|
2007-07-08 00:08:04 -07:00
|
|
|
window->IMEComposeText(static_cast<const PRUnichar *>(uniStr),
|
2007-03-22 10:30:00 -07:00
|
|
|
uniStrLen, preedit_string, cursor_pos, feedback_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(preedit_string);
|
|
|
|
g_free(uniStr);
|
|
|
|
|
|
|
|
if (feedback_list)
|
|
|
|
pango_attr_list_unref(feedback_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void
|
2007-04-29 17:46:47 -07:00
|
|
|
IM_commit_cb(GtkIMContext *aContext,
|
|
|
|
const gchar *aUtf8_str,
|
|
|
|
nsWindow *aWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (gIMESuppressCommit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LOGIM(("IM_commit_cb\n"));
|
|
|
|
|
|
|
|
gKeyEventCommitted = PR_TRUE;
|
|
|
|
|
|
|
|
// if gFocusWindow is null, use the last focused gIMEFocusWindow
|
2007-04-29 17:46:47 -07:00
|
|
|
nsRefPtr<nsWindow> window = gFocusWindow ? gFocusWindow : gIMEFocusWindow;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-20 21:31:56 -07:00
|
|
|
if (!window || IM_get_input_context(window) != aContext)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* If IME doesn't change they keyevent that generated this commit,
|
|
|
|
don't send it through XIM - just send it as a normal key press
|
|
|
|
event. */
|
|
|
|
|
|
|
|
if (gKeyEvent) {
|
|
|
|
char keyval_utf8[8]; /* should have at least 6 bytes of space */
|
|
|
|
gint keyval_utf8_len;
|
|
|
|
guint32 keyval_unicode;
|
|
|
|
|
|
|
|
keyval_unicode = gdk_keyval_to_unicode(gKeyEvent->keyval);
|
|
|
|
keyval_utf8_len = g_unichar_to_utf8(keyval_unicode, keyval_utf8);
|
|
|
|
keyval_utf8[keyval_utf8_len] = '\0';
|
|
|
|
|
|
|
|
if (!strcmp(aUtf8_str, keyval_utf8)) {
|
|
|
|
gKeyEventChanged = PR_FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gKeyEventChanged = PR_TRUE;
|
|
|
|
IM_commit_cb_internal(aUtf8_str, window);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void
|
2007-04-29 17:46:47 -07:00
|
|
|
IM_commit_cb_internal(const gchar *aUtf8_str,
|
|
|
|
nsWindow *aWindow)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
gunichar2 *uniStr = nsnull;
|
|
|
|
glong uniStrLen = 0;
|
|
|
|
uniStr = g_utf8_to_utf16(aUtf8_str, -1, NULL, &uniStrLen, NULL);
|
|
|
|
|
|
|
|
if (!uniStr) {
|
|
|
|
LOGIM(("utf80utf16 string tranfer failed!\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uniStrLen) {
|
|
|
|
aWindow->IMEComposeText((const PRUnichar *)uniStr,
|
|
|
|
(PRInt32)uniStrLen, nsnull, 0, nsnull);
|
|
|
|
aWindow->IMEComposeEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(uniStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define START_OFFSET(I) \
|
|
|
|
(*aTextRangeListResult)[I].mStartOffset
|
|
|
|
|
|
|
|
#define END_OFFSET(I) \
|
|
|
|
(*aTextRangeListResult)[I].mEndOffset
|
|
|
|
|
|
|
|
#define SET_FEEDBACKTYPE(I,T) (*aTextRangeListResult)[I].mRangeType = T
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
IM_set_text_range(const PRInt32 aLen,
|
|
|
|
const gchar *aPreeditString,
|
|
|
|
const gint aCursorPos,
|
|
|
|
const PangoAttrList *aFeedback,
|
|
|
|
PRUint32 *aTextRangeListLengthResult,
|
|
|
|
nsTextRangeArray *aTextRangeListResult)
|
|
|
|
{
|
|
|
|
if (aLen == 0) {
|
|
|
|
aTextRangeListLengthResult = 0;
|
|
|
|
aTextRangeListResult = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PangoAttrIterator * aFeedbackIterator;
|
|
|
|
aFeedbackIterator = pango_attr_list_get_iterator((PangoAttrList*)aFeedback);
|
2007-07-08 00:08:04 -07:00
|
|
|
//(reinterpret_cast<PangoAttrList*>(aFeedback));
|
2007-03-22 10:30:00 -07:00
|
|
|
// Since some compilers don't permit this casting -- from const to un-const
|
|
|
|
if (aFeedbackIterator == NULL) return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't use pango_attr_iterator_range, it'll mislead you.
|
|
|
|
* As for going through the list to get the attribute number,
|
|
|
|
* it take much time for performance.
|
|
|
|
* Now it's simple and enough, although maybe waste a little space.
|
|
|
|
*/
|
|
|
|
PRInt32 aMaxLenOfTextRange;
|
|
|
|
aMaxLenOfTextRange = 2*aLen + 1;
|
|
|
|
*aTextRangeListResult = new nsTextRange[aMaxLenOfTextRange];
|
|
|
|
NS_ASSERTION(*aTextRangeListResult, "No enough memory.");
|
|
|
|
|
|
|
|
// Set caret's postion
|
|
|
|
SET_FEEDBACKTYPE(0, NS_TEXTRANGE_CARETPOSITION);
|
|
|
|
START_OFFSET(0) = aCursorPos;
|
|
|
|
END_OFFSET(0) = aCursorPos;
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
PangoAttribute * aPangoAttr;
|
|
|
|
PangoAttribute * aPangoAttrReverse, * aPangoAttrUnderline;
|
|
|
|
/*
|
|
|
|
* Depend on gtk2's implementation on XIM support.
|
|
|
|
* In aFeedback got from gtk2, there are only three types of data:
|
|
|
|
* PANGO_ATTR_UNDERLINE, PANGO_ATTR_FOREGROUND, PANGO_ATTR_BACKGROUND.
|
|
|
|
* Corresponding to XIMUnderline, XIMReverse.
|
|
|
|
* Don't take PANGO_ATTR_BACKGROUND into account, since
|
|
|
|
* PANGO_ATTR_BACKGROUND and PANGO_ATTR_FOREGROUND are always
|
|
|
|
* a couple.
|
|
|
|
*/
|
|
|
|
gint start, end;
|
|
|
|
gunichar2 * uniStr;
|
|
|
|
glong uniStrLen;
|
|
|
|
do {
|
|
|
|
aPangoAttrUnderline = pango_attr_iterator_get(aFeedbackIterator,
|
|
|
|
PANGO_ATTR_UNDERLINE);
|
|
|
|
aPangoAttrReverse = pango_attr_iterator_get(aFeedbackIterator,
|
|
|
|
PANGO_ATTR_FOREGROUND);
|
|
|
|
if (!aPangoAttrUnderline && !aPangoAttrReverse)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get the range of the current attribute(s)
|
|
|
|
pango_attr_iterator_range(aFeedbackIterator, &start, &end);
|
|
|
|
|
|
|
|
PRUint32 feedbackType = 0;
|
|
|
|
// XIMReverse | XIMUnderline
|
|
|
|
if (aPangoAttrUnderline && aPangoAttrReverse) {
|
|
|
|
feedbackType = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
|
|
|
|
// Doesn't matter which attribute we use here since we
|
|
|
|
// are using pango_attr_iterator_range to determine the
|
|
|
|
// range of the attributes.
|
|
|
|
aPangoAttr = aPangoAttrUnderline;
|
|
|
|
}
|
|
|
|
// XIMUnderline
|
|
|
|
else if (aPangoAttrUnderline) {
|
|
|
|
feedbackType = NS_TEXTRANGE_CONVERTEDTEXT;
|
|
|
|
aPangoAttr = aPangoAttrUnderline;
|
|
|
|
}
|
|
|
|
// XIMReverse
|
|
|
|
else if (aPangoAttrReverse) {
|
|
|
|
feedbackType = NS_TEXTRANGE_SELECTEDRAWTEXT;
|
|
|
|
aPangoAttr = aPangoAttrReverse;
|
|
|
|
}
|
|
|
|
|
|
|
|
count++;
|
|
|
|
START_OFFSET(count) = 0;
|
|
|
|
END_OFFSET(count) = 0;
|
|
|
|
|
|
|
|
uniStr = NULL;
|
|
|
|
if (start > 0) {
|
|
|
|
uniStr = g_utf8_to_utf16(aPreeditString, start,
|
|
|
|
NULL, &uniStrLen, NULL);
|
|
|
|
}
|
|
|
|
if (uniStr) {
|
|
|
|
START_OFFSET(count) = uniStrLen;
|
|
|
|
g_free(uniStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
uniStr = NULL;
|
|
|
|
uniStr = g_utf8_to_utf16(aPreeditString + start, end - start,
|
|
|
|
NULL, &uniStrLen, NULL);
|
|
|
|
if (uniStr) {
|
|
|
|
END_OFFSET(count) = START_OFFSET(count) + uniStrLen;
|
|
|
|
SET_FEEDBACKTYPE(count, feedbackType);
|
|
|
|
g_free(uniStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
} while ((count < aMaxLenOfTextRange - 1) &&
|
|
|
|
(pango_attr_iterator_next(aFeedbackIterator)));
|
|
|
|
|
|
|
|
*aTextRangeListLengthResult = count + 1;
|
|
|
|
|
|
|
|
pango_attr_iterator_destroy(aFeedbackIterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
GtkIMContext *
|
|
|
|
IM_get_input_context(nsWindow *aWindow)
|
|
|
|
{
|
|
|
|
if (!aWindow)
|
|
|
|
return nsnull;
|
|
|
|
nsWindow::nsIMEData *data = aWindow->mIMEData;
|
|
|
|
if (!data)
|
|
|
|
return nsnull;
|
2008-12-14 19:54:54 -08:00
|
|
|
if (data->mEnabled == nsIWidget::IME_STATUS_ENABLED ||
|
|
|
|
data->mEnabled == nsIWidget::IME_STATUS_PLUGIN)
|
2008-04-29 08:31:51 -07:00
|
|
|
return data->mContext;
|
2008-07-13 19:56:18 -07:00
|
|
|
if (data->mEnabled == nsIWidget::IME_STATUS_PASSWORD)
|
2009-08-20 21:31:56 -07:00
|
|
|
#ifdef MOZ_PLATFORM_HILDON
|
|
|
|
return data->mContext;
|
|
|
|
#else
|
2008-04-29 08:31:51 -07:00
|
|
|
return data->mSimpleContext;
|
2009-08-20 21:31:56 -07:00
|
|
|
#endif
|
2008-04-29 08:31:51 -07:00
|
|
|
return data->mDummyContext;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
#ifdef MOZ_X11
|
2008-06-18 02:20:29 -07:00
|
|
|
/* static */ already_AddRefed<gfxASurface>
|
|
|
|
nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
|
2009-01-14 19:27:09 -08:00
|
|
|
const nsIntSize& aSize)
|
2008-06-18 02:20:29 -07:00
|
|
|
{
|
|
|
|
GdkVisual* visual = gdk_drawable_get_visual(aDrawable);
|
|
|
|
Display* xDisplay = gdk_x11_drawable_get_xdisplay(aDrawable);
|
|
|
|
Drawable xDrawable = gdk_x11_drawable_get_xid(aDrawable);
|
|
|
|
|
2008-09-17 14:15:52 -07:00
|
|
|
gfxASurface* result = nsnull;
|
|
|
|
|
|
|
|
if (visual) {
|
|
|
|
Visual* xVisual = gdk_x11_visual_get_xvisual(visual);
|
|
|
|
|
|
|
|
result = new gfxXlibSurface(xDisplay, xDrawable, xVisual,
|
|
|
|
gfxIntSize(aSize.width, aSize.height));
|
|
|
|
} else {
|
|
|
|
// no visual? we must be using an xrender format. Find a format
|
|
|
|
// for this depth.
|
|
|
|
XRenderPictFormat *pf = NULL;
|
|
|
|
switch (gdk_drawable_get_depth(aDrawable)) {
|
|
|
|
case 32:
|
|
|
|
pf = XRenderFindStandardFormat(xDisplay, PictStandardARGB32);
|
|
|
|
break;
|
|
|
|
case 24:
|
|
|
|
pf = XRenderFindStandardFormat(xDisplay, PictStandardRGB24);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NS_ERROR("Don't know how to handle the given depth!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = new gfxXlibSurface(xDisplay, xDrawable, pf,
|
|
|
|
gfxIntSize(aSize.width, aSize.height));
|
|
|
|
}
|
|
|
|
|
2008-06-18 02:20:29 -07:00
|
|
|
NS_IF_ADDREF(result);
|
|
|
|
return result;
|
|
|
|
}
|
2008-08-06 13:48:55 -07:00
|
|
|
#endif
|
2008-06-18 02:20:29 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// return the gfxASurface for rendering to this widget
|
|
|
|
gfxASurface*
|
|
|
|
nsWindow::GetThebesSurface()
|
|
|
|
{
|
2009-11-10 13:57:25 -08:00
|
|
|
if (!mGdkWindow)
|
|
|
|
return nsnull;
|
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
GdkDrawable* d;
|
|
|
|
gint x_offset, y_offset;
|
2009-07-26 18:39:36 -07:00
|
|
|
gdk_window_get_internal_paint_info(mGdkWindow, &d, &x_offset, &y_offset);
|
2008-08-06 13:48:55 -07:00
|
|
|
|
|
|
|
#ifdef MOZ_X11
|
|
|
|
gint width, height;
|
|
|
|
gdk_drawable_get_size(d, &width, &height);
|
|
|
|
// Owen Taylor says this is the right thing to do!
|
|
|
|
width = PR_MIN(32767, width);
|
|
|
|
height = PR_MIN(32767, height);
|
|
|
|
|
|
|
|
mThebesSurface = new gfxXlibSurface
|
|
|
|
(GDK_WINDOW_XDISPLAY(d),
|
|
|
|
GDK_WINDOW_XWINDOW(d),
|
|
|
|
GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(d)),
|
|
|
|
gfxIntSize(width, height));
|
|
|
|
#endif
|
|
|
|
#ifdef MOZ_DFB
|
|
|
|
mThebesSurface = new gfxDirectFBSurface(gdk_directfb_surface_lookup(d));
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2008-03-14 01:08:18 -07:00
|
|
|
|
2008-08-06 13:48:55 -07:00
|
|
|
// if the surface creation is reporting an error, then
|
|
|
|
// we don't have a surface to give back
|
|
|
|
if (mThebesSurface && mThebesSurface->CairoStatus() != 0) {
|
|
|
|
mThebesSurface = nsnull;
|
|
|
|
} else {
|
|
|
|
mThebesSurface->SetDeviceOffset(gfxPoint(-x_offset, -y_offset));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return mThebesSurface;
|
|
|
|
}
|
2007-12-11 02:08:35 -08:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aEvent);
|
|
|
|
|
|
|
|
if (aEvent->eventStructType != NS_MOUSE_EVENT) {
|
|
|
|
// you can only begin a resize drag with a mouse event
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsMouseEvent* mouse_event = static_cast<nsMouseEvent*>(aEvent);
|
2009-02-27 17:47:40 -08:00
|
|
|
|
2007-12-11 02:08:35 -08:00
|
|
|
if (mouse_event->button != nsMouseEvent::eLeftButton) {
|
|
|
|
// you can only begin a resize drag with the left mouse button
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
// work out what GdkWindowEdge we're talking about
|
|
|
|
GdkWindowEdge window_edge;
|
|
|
|
if (aVertical < 0) {
|
|
|
|
if (aHorizontal < 0) {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_NORTH_WEST;
|
|
|
|
} else if (aHorizontal == 0) {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_NORTH;
|
|
|
|
} else {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_NORTH_EAST;
|
|
|
|
}
|
|
|
|
} else if (aVertical == 0) {
|
|
|
|
if (aHorizontal < 0) {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_WEST;
|
|
|
|
} else if (aHorizontal == 0) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
} else {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_EAST;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (aHorizontal < 0) {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_SOUTH_WEST;
|
|
|
|
} else if (aHorizontal == 0) {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_SOUTH;
|
|
|
|
} else {
|
|
|
|
window_edge = GDK_WINDOW_EDGE_SOUTH_EAST;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the gdk window for this widget
|
2009-07-26 18:39:36 -07:00
|
|
|
GdkWindow* gdk_window = mGdkWindow;
|
2007-12-11 02:08:35 -08:00
|
|
|
if (!GDK_IS_WINDOW(gdk_window)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the top-level window
|
|
|
|
gdk_window = gdk_window_get_toplevel(gdk_window);
|
|
|
|
if (!GDK_IS_WINDOW(gdk_window)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// get the current (default) display
|
|
|
|
GdkDisplay* display = gdk_display_get_default();
|
|
|
|
if (!GDK_IS_DISPLAY(display)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the current pointer position and button state
|
|
|
|
GdkScreen* screen = NULL;
|
|
|
|
gint screenX, screenY;
|
|
|
|
GdkModifierType mask;
|
|
|
|
gdk_display_get_pointer(display, &screen, &screenX, &screenY, &mask);
|
|
|
|
|
|
|
|
// we only support resizing with button 1
|
|
|
|
if (!(mask & GDK_BUTTON1_MASK)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tell the window manager to start the resize
|
|
|
|
gdk_window_begin_resize_drag(gdk_window, window_edge, 1,
|
|
|
|
screenX, screenY, aEvent->time);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|