+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "scroll_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// "focus_in_event"
+//-----------------------------------------------------------------------------
+
+// send the wxChildFocusEvent and wxFocusEvent, common code of
+// gtk_window_focus_in_callback() and SetFocus()
+static bool DoSendFocusEvents(wxWindow *win)
+{
+ // Notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it.
+ wxChildFocusEvent eventChildFocus(win);
+ (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
+
+ wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
+ eventFocus.SetEventObject(win);
+
+ return win->GetEventHandler()->ProcessEvent(eventFocus);
+}
+
+static gint gtk_window_focus_in_callback( GtkWidget *widget,
+ GdkEvent *WXUNUSED(event),
+ wxWindow *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ switch ( g_sendActivateEvent )
+ {
+ case -1:
+ // we've got focus from outside, synthetize wxActivateEvent
+ g_sendActivateEvent = 1;
+ break;
+
+ case 0:
+ // another our window just lost focus, it was already ours before
+ // - don't send any wxActivateEvent
+ g_sendActivateEvent = -1;
+ break;
+ }
+
+ g_focusWindowLast =
+ g_focusWindow = win;
+
+ wxLogTrace(TRACE_FOCUS,
+ _T("%s: focus in"), win->GetName().c_str());
+
+#ifdef HAVE_XIM
+ if (win->m_ic)
+ gdk_im_begin(win->m_ic, win->m_wxwindow->window);
+#endif
+
+#if wxUSE_CARET
+ // caret needs to be informed about focus change
+ wxCaret *caret = win->GetCaret();
+ if ( caret )
+ {
+ caret->OnSetFocus();
+ }
+#endif // wxUSE_CARET
+
+ g_activeFrameLostFocus = FALSE;
+
+ wxWindowGTK *active = wxGetTopLevelParent(win);
+ if ( active != g_activeFrame )
+ {
+ if ( g_activeFrame )
+ {
+ wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
+ wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
+ event.SetEventObject(g_activeFrame);
+ g_activeFrame->GetEventHandler()->ProcessEvent(event);
+ }
+
+ wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
+ g_activeFrame = active;
+ wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
+ event.SetEventObject(g_activeFrame);
+ g_activeFrame->GetEventHandler()->ProcessEvent(event);
+
+ // Don't send focus events in addition to activate
+ // if (win == g_activeFrame)
+ // return TRUE;
+ }
+
+ // does the window itself think that it has the focus?
+ if ( !win->m_hasFocus )
+ {
+ // not yet, notify it
+ win->m_hasFocus = TRUE;
+
+ if ( DoSendFocusEvents(win) )
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "focus_out_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ wxLogTrace( TRACE_FOCUS,
+ _T("%s: focus out"), win->GetName().c_str() );
+
+ if ( !g_activeFrameLostFocus && g_activeFrame )
+ {
+ // VZ: commenting this out because it does happen (although not easy
+ // to reproduce, I only see it when using wxMiniFrame and not
+ // always) and makes using Mahogany quite annoying
+#if 0
+ wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
+ wxT("unfocusing window that hasn't gained focus properly") );
+#endif // 0
+
+ g_activeFrameLostFocus = TRUE;
+ }
+
+ // if the focus goes out of our app alltogether, OnIdle() will send
+ // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
+ // g_sendActivateEvent to -1
+ g_sendActivateEvent = 0;
+
+ wxWindowGTK *winFocus = wxFindFocusedChild(win);
+ if ( winFocus )
+ win = winFocus;
+
+ g_focusWindow = (wxWindowGTK *)NULL;
+
+#ifdef HAVE_XIM
+ if (win->m_ic)
+ gdk_im_end();
+#endif
+
+#if wxUSE_CARET
+ // caret needs to be informed about focus change
+ wxCaret *caret = win->GetCaret();
+ if ( caret )
+ {
+ caret->OnKillFocus();
+ }
+#endif // wxUSE_CARET
+
+ // don't send the window a kill focus event if it thinks that it doesn't
+ // have focus already
+ if ( win->m_hasFocus )
+ {
+ win->m_hasFocus = FALSE;
+
+ wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
+ event.SetEventObject( win );
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "enter_notify_event"
+//-----------------------------------------------------------------------------
+
+static
+gint gtk_window_enter_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ // Event was emitted after a grab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
+
+ int x = 0;
+ int y = 0;
+ GdkModifierType state = (GdkModifierType)0;
+
+ gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+ wxMouseEvent event( wxEVT_ENTER_WINDOW );
+ InitMouseEvent(win, event, gdk_event);
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = x + pt.x;
+ event.m_y = y + pt.y;
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "leave_notify_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ // Event was emitted after an ungrab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
+
+ wxMouseEvent event( wxEVT_LEAVE_WINDOW );
+ event.SetTimestamp( gdk_event->time );
+ event.SetEventObject( win );
+
+ int x = 0;
+ int y = 0;
+ GdkModifierType state = (GdkModifierType)0;
+
+ gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+ event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
+ event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
+ event.m_altDown = (state & GDK_MOD1_MASK) != 0;
+ event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
+ event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
+ event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
+ event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
+
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = x + pt.x;
+ event.m_y = y + pt.y;
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "value_changed" from m_vAdjust
+//-----------------------------------------------------------------------------
+
+static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
+ SCROLLBAR_CBACK_ARG
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (g_blockEventsOnDrag) return;
+
+ if (!win->m_hasVMT) return;
+
+ float diff = adjust->value - win->m_oldVerticalPos;
+ if (fabs(diff) < 0.2) return;
+
+ win->m_oldVerticalPos = adjust->value;
+
+#ifndef __WXGTK20__
+ GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
+
+ int value = (int)(adjust->value+0.5);
+
+ wxScrollWinEvent event( command, value, wxVERTICAL );
+ event.SetEventObject( win );
+ win->GetEventHandler()->ProcessEvent( event );
+}
+
+//-----------------------------------------------------------------------------
+// "value_changed" from m_hAdjust
+//-----------------------------------------------------------------------------
+
+static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
+ SCROLLBAR_CBACK_ARG
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (g_blockEventsOnDrag) return;
+ if (!win->m_hasVMT) return;
+
+ float diff = adjust->value - win->m_oldHorizontalPos;
+ if (fabs(diff) < 0.2) return;
+
+#ifndef __WXGTK20__
+ GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
+
+ win->m_oldHorizontalPos = adjust->value;
+
+ int value = (int)(adjust->value+0.5);
+
+ wxScrollWinEvent event( command, value, wxHORIZONTAL );
+ event.SetEventObject( win );
+ win->GetEventHandler()->ProcessEvent( event );
+}
+
+//-----------------------------------------------------------------------------
+// "button_press_event" from scrollbar
+//-----------------------------------------------------------------------------
+
+static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win)
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+
+ g_blockEventsOnScroll = TRUE;
+
+ // FIXME: there is no 'slider' field in GTK+ 2.0 any more
+#ifndef __WXGTK20__
+ win->m_isScrolling = (gdk_event->window == widget->slider);
+#endif
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "button_release_event" from scrollbar
+//-----------------------------------------------------------------------------
+
+static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
+ GdkEventButton *WXUNUSED(gdk_event),
+ wxWindowGTK *win)
+{
+ DEBUG_MAIN_THREAD
+
+// don't test here as we can release the mouse while being over
+// a different window than the slider
+//
+// if (gdk_event->window != widget->slider) return FALSE;
+
+ g_blockEventsOnScroll = FALSE;
+
+ if (win->m_isScrolling)
+ {
+ wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
+ int value = -1;
+ int dir = -1;
+
+ GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
+ if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
+ {
+ value = (int)(win->m_hAdjust->value+0.5);
+ dir = wxHORIZONTAL;
+ }
+ if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
+ {
+ value = (int)(win->m_vAdjust->value+0.5);
+ dir = wxVERTICAL;
+ }
+
+ wxScrollWinEvent event( command, value, dir );
+ event.SetEventObject( win );
+ win->GetEventHandler()->ProcessEvent( event );
+ }
+
+ win->m_isScrolling = FALSE;
+
+ return FALSE;
+}
+
+// ----------------------------------------------------------------------------
+// this wxWindowBase function is implemented here (in platform-specific file)
+// because it is static and so couldn't be made virtual
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::FindFocus()
+{
+ // the cast is necessary when we compile in wxUniversal mode
+ return (wxWindow *)g_focusWindow;
+}
+
+
+//-----------------------------------------------------------------------------
+// "realize" from m_widget
+//-----------------------------------------------------------------------------
+
+/* We cannot set colours and fonts before the widget has
+ been realized, so we do this directly after realization. */
+
+static gint
+gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (win->m_delayedBackgroundColour && !win->GetThemeEnabled())
+ win->GtkSetBackgroundColour( win->GetBackgroundColour() );
+
+ if (win->m_delayedForegroundColour && !win->GetThemeEnabled())
+ win->GtkSetForegroundColour( win->GetForegroundColour() );
+
+#ifdef __WXGTK20__
+ if (win->m_imContext)
+ {
+ GtkPizza *pizza = GTK_PIZZA( m_widget );
+ gtk_im_context_set_client_window( (GtkIMContext*) win->m_imContext, pizza->bin_window );
+ }
+#endif
+
+ wxWindowCreateEvent event( win );
+ event.SetEventObject( win );
+ win->GetEventHandler()->ProcessEvent( event );
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "size_allocate"
+//-----------------------------------------------------------------------------
+
+static
+void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
+ GtkAllocation *WXUNUSED(alloc),
+ wxWindow *win )
+{
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasScrolling) return;
+
+ int client_width = 0;
+ int client_height = 0;
+ win->GetClientSize( &client_width, &client_height );
+ if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
+ return;
+
+ win->m_oldClientWidth = client_width;
+ win->m_oldClientHeight = client_height;
+
+ if (!win->m_nativeSizeEvent)
+ {
+ wxSizeEvent event( win->GetSize(), win->GetId() );
+ event.SetEventObject( win );
+ win->GetEventHandler()->ProcessEvent( event );
+ }
+}
+
+
+#ifdef HAVE_XIM
+ #define WXUNUSED_UNLESS_XIM(param) param
+#else
+ #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
+#endif
+
+/* Resize XIM window */
+
+static
+void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
+ GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
+ wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
+{
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+#ifdef HAVE_XIM
+ if (!win->m_ic)
+ return;
+
+ if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
+ {
+ gint width, height;
+
+ gdk_window_get_size (widget->window, &width, &height);
+ win->m_icattr->preedit_area.width = width;
+ win->m_icattr->preedit_area.height = height;
+ gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
+ }
+#endif // HAVE_XIM
+}
+
+//-----------------------------------------------------------------------------
+// "realize" from m_wxwindow
+//-----------------------------------------------------------------------------
+
+/* Initialize XIM support */
+
+static gint
+gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
+ wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
+{
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+#ifdef HAVE_XIM
+ if (win->m_ic) return FALSE;
+ if (!widget) return FALSE;
+ if (!gdk_im_ready()) return FALSE;
+
+ win->m_icattr = gdk_ic_attr_new();
+ if (!win->m_icattr) return FALSE;
+
+ gint width, height;
+ GdkEventMask mask;
+ GdkColormap *colormap;
+ GdkICAttr *attr = win->m_icattr;
+ unsigned attrmask = GDK_IC_ALL_REQ;
+ GdkIMStyle style;
+ GdkIMStyle supported_style = (GdkIMStyle)
+ (GDK_IM_PREEDIT_NONE |
+ GDK_IM_PREEDIT_NOTHING |
+ GDK_IM_PREEDIT_POSITION |
+ GDK_IM_STATUS_NONE |
+ GDK_IM_STATUS_NOTHING);
+
+ if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
+ supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
+
+ attr->style = style = gdk_im_decide_style (supported_style);
+ attr->client_window = widget->window;
+
+ if ((colormap = gtk_widget_get_colormap (widget)) !=
+ gtk_widget_get_default_colormap ())
+ {
+ attrmask |= GDK_IC_PREEDIT_COLORMAP;
+ attr->preedit_colormap = colormap;
+ }
+
+ attrmask |= GDK_IC_PREEDIT_FOREGROUND;
+ attrmask |= GDK_IC_PREEDIT_BACKGROUND;
+ attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
+ attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
+
+ switch (style & GDK_IM_PREEDIT_MASK)
+ {
+ case GDK_IM_PREEDIT_POSITION:
+ if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
+ {
+ g_warning ("over-the-spot style requires fontset");
+ break;
+ }
+
+ gdk_window_get_size (widget->window, &width, &height);
+
+ attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
+ attr->spot_location.x = 0;
+ attr->spot_location.y = height;
+ attr->preedit_area.x = 0;
+ attr->preedit_area.y = 0;
+ attr->preedit_area.width = width;
+ attr->preedit_area.height = height;
+ attr->preedit_fontset = widget->style->font;
+
+ break;
+ }
+
+ win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
+
+ if (win->m_ic == NULL)
+ g_warning ("Can't create input context.");
+ else
+ {
+ mask = gdk_window_get_events (widget->window);
+ mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
+ gdk_window_set_events (widget->window, mask);
+
+ if (GTK_WIDGET_HAS_FOCUS(widget))
+ gdk_im_begin (win->m_ic, widget->window);
+ }
+#endif // HAVE_XIM
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// InsertChild for wxWindowGTK.
+//-----------------------------------------------------------------------------
+
+/* Callback for wxWindowGTK. This very strange beast has to be used because
+ * C++ has no virtual methods in a constructor. We have to emulate a
+ * virtual function here as wxNotebook requires a different way to insert
+ * a child in it. I had opted for creating a wxNotebookPage window class
+ * which would have made this superfluous (such in the MDI window system),
+ * but no-one was listening to me... */
+
+static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
+{
+ /* the window might have been scrolled already, do we
+ have to adapt the position */
+ GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
+ child->m_x += pizza->xoffset;
+ child->m_y += pizza->yoffset;
+
+ gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
+ GTK_WIDGET(child->m_widget),
+ child->m_x,
+ child->m_y,
+ child->m_width,
+ child->m_height );
+}
+
+//-----------------------------------------------------------------------------
+// global functions
+//-----------------------------------------------------------------------------
+
+wxWindow *wxGetActiveWindow()
+{
+ return wxWindow::FindFocus();
+}
+
+//-----------------------------------------------------------------------------
+// wxWindowGTK
+//-----------------------------------------------------------------------------
+
+// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
+// method
+#ifdef __WXUNIVERSAL__
+ IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
+#else // __WXGTK__
+ IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
+#endif // __WXUNIVERSAL__/__WXGTK__
+
+void wxWindowGTK::Init()
+{
+ // GTK specific
+ m_widget = (GtkWidget *) NULL;
+ m_wxwindow = (GtkWidget *) NULL;
+ m_focusWidget = (GtkWidget *) NULL;
+
+ // position/size
+ m_x = 0;
+ m_y = 0;
+ m_width = 0;
+ m_height = 0;
+
+ m_sizeSet = FALSE;
+ m_hasVMT = FALSE;
+ m_needParent = TRUE;
+ m_isBeingDeleted = FALSE;
+
+ m_noExpose = FALSE;
+ m_nativeSizeEvent = FALSE;
+
+ m_hasScrolling = FALSE;
+ m_isScrolling = FALSE;
+
+ m_hAdjust = (GtkAdjustment*) NULL;
+ m_vAdjust = (GtkAdjustment*) NULL;
+ m_oldHorizontalPos =
+ m_oldVerticalPos = 0.0;
+ m_oldClientWidth =
+ m_oldClientHeight = 0;
+
+ m_resizing = FALSE;
+ m_widgetStyle = (GtkStyle*) NULL;
+
+ m_insertCallback = (wxInsertChildFunction) NULL;
+
+ m_acceptsFocus = FALSE;
+ m_hasFocus = FALSE;
+
+ m_clipPaintRegion = FALSE;
+
+ m_cursor = *wxSTANDARD_CURSOR;
+
+ m_delayedForegroundColour = FALSE;
+ m_delayedBackgroundColour = FALSE;
+
+#ifdef __WXGTK20__
+ m_imContext = NULL;
+ m_x11Context = NULL;
+#else
+#ifdef HAVE_XIM
+ m_ic = (GdkIC*) NULL;
+ m_icattr = (GdkICAttr*) NULL;
+#endif
+#endif
+}
+
+wxWindowGTK::wxWindowGTK()
+{
+ Init();
+}
+
+wxWindowGTK::wxWindowGTK( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint &pos,
+ const wxSize &size,
+ long style,
+ const wxString &name )
+{
+ Init();
+
+ Create( parent, id, pos, size, style, name );
+}
+
+bool wxWindowGTK::Create( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint &pos,
+ const wxSize &size,
+ long style,
+ const wxString &name )
+{
+ if (!PreCreation( parent, pos, size ) ||
+ !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
+ {
+ wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
+ return FALSE;
+ }
+
+ m_insertCallback = wxInsertChildInWindow;
+
+ // always needed for background clearing
+ m_delayedBackgroundColour = TRUE;
+
+ m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
+ GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
+
+ GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
+
+ GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
+ scroll_class->scrollbar_spacing = 0;
+
+ gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+
+ m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
+ m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
+
+ m_wxwindow = gtk_pizza_new();
+
+#ifndef __WXUNIVERSAL__
+ GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
+
+ if (HasFlag(wxRAISED_BORDER))
+ {
+ gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
+ }
+ else if (HasFlag(wxSUNKEN_BORDER))
+ {
+ gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
+ }
+ else if (HasFlag(wxSIMPLE_BORDER))
+ {
+ gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
+ }
+ else
+ {
+ gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
+ }
+#endif // __WXUNIVERSAL__
+
+ gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
+
+ GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
+ m_acceptsFocus = TRUE;
+
+ // I _really_ don't want scrollbars in the beginning
+ m_vAdjust->lower = 0.0;
+ m_vAdjust->upper = 1.0;
+ m_vAdjust->value = 0.0;
+ m_vAdjust->step_increment = 1.0;
+ m_vAdjust->page_increment = 1.0;
+ m_vAdjust->page_size = 5.0;
+ gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
+ m_hAdjust->lower = 0.0;
+ m_hAdjust->upper = 1.0;
+ m_hAdjust->value = 0.0;
+ m_hAdjust->step_increment = 1.0;
+ m_hAdjust->page_increment = 1.0;
+ m_hAdjust->page_size = 5.0;
+ gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
+
+ // these handlers block mouse events to any window during scrolling such as
+ // motion events and prevent GTK and wxWindows from fighting over where the
+ // slider should be
+
+ gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
+ (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
+
+ gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
+ (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
+
+ gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
+ (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
+
+ gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
+ (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
+
+ // these handlers get notified when screen updates are required either when
+ // scrolling or when the window size (and therefore scrollbar configuration)
+ // has changed
+
+ gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
+ (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
+ gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
+ (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
+
+#ifdef __WXGTK20__
+ // Create input method handler
+ m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
+
+ // Cannot handle drawing preedited text yet
+ gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
+
+ g_signal_connect (G_OBJECT (m_imContext), "commit",
+ G_CALLBACK (gtk_wxwindow_commit_cb), this);
+#endif
+
+ gtk_widget_show( m_wxwindow );
+
+ if (m_parent)
+ m_parent->DoAddChild( this );
+
+ m_focusWidget = m_wxwindow;
+
+ PostCreation();
+
+ Show( TRUE );
+
+ return TRUE;
+}
+
+wxWindowGTK::~wxWindowGTK()
+{
+ SendDestroyEvent();
+
+ if (g_focusWindow == this)
+ g_focusWindow = NULL;
+
+ if (g_activeFrame == this)
+ g_activeFrame = NULL;
+
+ if ( g_delayedFocus == this )
+ g_delayedFocus = NULL;
+
+ m_isBeingDeleted = TRUE;
+ m_hasVMT = FALSE;
+
+ if (m_widget)
+ Show( FALSE );
+
+ DestroyChildren();
+
+#ifdef HAVE_XIM
+ if (m_ic)
+ gdk_ic_destroy (m_ic);
+ if (m_icattr)
+ gdk_ic_attr_destroy (m_icattr);
+#endif
+
+ if (m_widgetStyle)
+ {
+#if DISABLE_STYLE_IF_BROKEN_THEME
+ // don't delete if it's a pixmap theme style
+ if (!m_widgetStyle->engine_data)
+ gtk_style_unref( m_widgetStyle );
+#endif
+ m_widgetStyle = (GtkStyle*) NULL;
+ }
+
+ if (m_wxwindow)
+ {
+ gtk_widget_destroy( m_wxwindow );
+ m_wxwindow = (GtkWidget*) NULL;
+ }
+
+ if (m_widget)
+ {
+ gtk_widget_destroy( m_widget );
+ m_widget = (GtkWidget*) NULL;
+ }
+}
+
+bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
+{
+ wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
+
+ // This turns -1 into 30 so that a minimal window is
+ // visible even although -1,-1 has been given as the
+ // size of the window. the same trick is used in other
+ // ports and should make debugging easier.
+ m_width = WidthDefault(size.x) ;
+ m_height = HeightDefault(size.y);
+
+ m_x = (int)pos.x;
+ m_y = (int)pos.y;
+
+ // some reasonable defaults
+ if (!parent)
+ {
+ if (m_x == -1)
+ {
+ m_x = (gdk_screen_width () - m_width) / 2;
+ if (m_x < 10) m_x = 10;
+ }
+ if (m_y == -1)
+ {
+ m_y = (gdk_screen_height () - m_height) / 2;
+ if (m_y < 10) m_y = 10;
+ }
+ }
+
+ return TRUE;
+}
+
+void wxWindowGTK::PostCreation()
+{
+ wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+
+ if (m_wxwindow)
+ {
+ if (!m_noExpose)
+ {
+ // these get reported to wxWindows -> wxPaintEvent
+
+ gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
+
+ gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
+ GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
+
+#ifndef __WXGTK20__
+ gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
+ GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
+
+ if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
+ {
+ gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
+ GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
+ }
+#else
+ // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
+#endif
+
+#ifdef __WXGTK20__
+ // Create input method handler
+ m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
+
+ // Cannot handle drawing preedited text yet
+ gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
+
+ g_signal_connect (G_OBJECT (m_imContext), "commit",
+ G_CALLBACK (gtk_wxwindow_commit_cb), this);
+#endif
+ }
+
+ // these are called when the "sunken" or "raised" borders are drawn
+ gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
+ GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
+
+#ifndef __WXGTK20__
+ gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
+ GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
+#endif
+ }
+
+ // focus handling
+
+ if (m_focusWidget == NULL)
+ m_focusWidget = m_widget;
+
+ gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
+ GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
+
+ gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
+ GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
+
+ // connect to the various key and mouse handlers
+
+ GtkWidget *connect_widget = GetConnectWidget();
+
+ ConnectWidget( connect_widget );
+
+ /* We cannot set colours, fonts and cursors before the widget has
+ been realized, so we do this directly after realization */
+ gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
+ GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
+
+ if (m_wxwindow)
+ {
+ // Catch native resize events
+ gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
+ GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
+
+ // Initialize XIM support
+ gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
+ GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
+
+ // And resize XIM window
+ gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
+ GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
+ }
+
+ if ( !GTK_IS_COMBO(m_widget))
+ {
+ // This is needed if we want to add our windows into native
+ // GTK control, such as the toolbar. With this callback, the
+ // toolbar gets to know the correct size (the one set by the
+ // programmer). Sadly, it misbehaves for wxComboBox. FIXME
+ // when moving to GTK 2.0.
+ gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
+ GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
+ (gpointer) this );
+ }
+
+ m_hasVMT = TRUE;
+}
+
+void wxWindowGTK::ConnectWidget( GtkWidget *widget )
+{
+ gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
+ GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
+
+ gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
+ GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
+
+ gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
+ GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
+
+ gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
+ GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
+
+ gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
+ GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
+
+#ifdef __WXGTK20__
+ gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
+ GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
+#endif
+
+ gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
+ GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
+
+ gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
+ GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
+}
+
+bool wxWindowGTK::Destroy()
+{
+ wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+
+ m_hasVMT = FALSE;
+
+ return wxWindowBase::Destroy();
+}
+
+void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
+{
+ gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
+}
+
+void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
+{
+ wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+ wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
+
+/*
+ printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
+*/
+
+ if (m_resizing) return; /* I don't like recursions */
+ m_resizing = TRUE;
+
+ int currentX, currentY;
+ GetPosition(¤tX, ¤tY);
+ if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+ x = currentX;
+ if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+ y = currentY;
+ AdjustForParentClientOrigin(x, y, sizeFlags);
+
+ if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
+ {
+ /* don't set the size for children of wxNotebook, just take the values. */
+ m_x = x;
+ m_y = y;
+ m_width = width;
+ m_height = height;
+ }
+ else
+ {
+ GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
+ if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
+ {
+ if (x != -1) m_x = x + pizza->xoffset;
+ if (y != -1) m_y = y + pizza->yoffset;
+ }
+ else
+ {
+ m_x = x + pizza->xoffset;
+ m_y = y + pizza->yoffset;
+ }
+ if (width != -1) m_width = width;
+ if (height != -1) m_height = height;
+
+ if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
+ {
+ if (width == -1) m_width = 80;
+ }
+
+ if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
+ {
+ if (height == -1) m_height = 26;
+ }
+
+ int minWidth = GetMinWidth(),
+ minHeight = GetMinHeight(),
+ maxWidth = GetMaxWidth(),
+ maxHeight = GetMaxHeight();
+
+ if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
+ if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
+ if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
+ if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
+
+ int border = 0;
+ int bottom_border = 0;
+
+#ifndef __WXGTK20__
+ if (GTK_WIDGET_CAN_DEFAULT(m_widget))
+ {
+ /* the default button has a border around it */
+ border = 6;
+ bottom_border = 5;
+ }
+#endif
+
+ DoMoveWindow( m_x-border,
+ m_y-border,
+ m_width+2*border,
+ m_height+border+bottom_border );
+ }
+
+ if (m_hasScrolling)