X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/22f43cb5a7a54be1e76eff40072ebde6ddd36ff3..e81ea1070d473b2a0d67cf395125d0eef9eed516:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index f71bac7cec..367f3aec8b 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -40,6 +40,29 @@ #include #include +#if !GTK_CHECK_VERSION(2,10,0) + // GTK+ can reliably detect Meta key state only since 2.10 when + // GDK_META_MASK was introduced -- there wasn't any way to detect it + // in older versions. wxGTK used GDK_MOD2_MASK for this purpose, but + // GDK_MOD2_MASK is documented as: + // + // the fifth modifier key (it depends on the modifier mapping of the X + // server which key is interpreted as this modifier) + // + // In other words, it isn't guaranteed to map to Meta. This is a real + // problem: it is common to map NumLock to it (in fact, it's an exception + // if the X server _doesn't_ use it for NumLock). So the old code caused + // wxKeyEvent::MetaDown() to always return true as long as NumLock was on + // on many systems, which broke all applications using + // wxKeyEvent::GetModifiers() to check modifiers state (see e.g. here: + // http://tinyurl.com/56lsk2). + // + // Because of this, it's better to not detect Meta key state at all than + // to detect it incorrectly. Hence the following #define, which causes + // m_metaDown to be always set to false. + #define GDK_META_MASK 0 +#endif + //----------------------------------------------------------------------------- // documentation on internals //----------------------------------------------------------------------------- @@ -258,39 +281,15 @@ void wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget), extern "C" { static gboolean -gtk_window_expose_callback( GtkWidget*, +gtk_window_expose_callback( GtkWidget* widget, GdkEventExpose *gdk_event, wxWindow *win ) { -#if 0 - if (win->GetName()) + if (gdk_event->window == widget->window) { - wxPrintf( wxT("OnExpose from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x, - (int)gdk_event->area.y, - (int)gdk_event->area.width, - (int)gdk_event->area.height ); + win->GetUpdateRegion() = wxRegion( gdk_event->region ); + win->GtkSendPaintEvents(); } - - gtk_paint_box - ( - win->m_wxwindow->style, - pizza->bin_window, - GTK_STATE_NORMAL, - GTK_SHADOW_OUT, - (GdkRectangle*) NULL, - win->m_wxwindow, - (char *)"button", // const_cast - 20,20,24,24 - ); -#endif - - win->GetUpdateRegion() = wxRegion( gdk_event->region ); - - win->GtkSendPaintEvents(); - // Let parent window draw window-less widgets return FALSE; } @@ -302,8 +301,6 @@ gtk_window_expose_callback( GtkWidget*, #ifndef __WXUNIVERSAL__ -GtkWidget* GetEntryWidget(); - extern "C" { static gboolean expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win) @@ -324,10 +321,8 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win) int h = win->m_wxwindow->allocation.height; if (win->HasFlag(wxBORDER_SIMPLE)) { - GdkGC* gc = gdk_gc_new(gdk_event->window); - gdk_gc_set_foreground(gc, &widget->style->black); - gdk_draw_rectangle(gdk_event->window, gc, false, x, y, w - 1, h - 1); - g_object_unref(gc); + gdk_draw_rectangle(gdk_event->window, + widget->style->black_gc, false, x, y, w - 1, h - 1); } else { @@ -344,10 +339,9 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win) // for scrollable ones detail = "viewport"; - GtkWidget* styleWidget = GetEntryWidget(); gtk_paint_shadow( - styleWidget->style, gdk_event->window, GTK_STATE_NORMAL, - shadow, NULL, styleWidget, detail, x, y, w, h); + win->m_wxwindow->style, gdk_event->window, GTK_STATE_NORMAL, + shadow, NULL, wxGTKPrivate::GetEntryWidget(), detail, x, y, w, h); } // no further painting is needed for border-only GdkWindow @@ -524,11 +518,11 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar) case GDK_KP_7: case GDK_KP_8: case GDK_KP_9: - key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0; + key_code = (isChar ? '0' : int(WXK_NUMPAD0)) + keysym - GDK_KP_0; break; case GDK_KP_Space: - key_code = isChar ? ' ' : WXK_NUMPAD_SPACE; + key_code = isChar ? ' ' : int(WXK_NUMPAD_SPACE); break; case GDK_KP_Tab: @@ -600,32 +594,32 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar) break; case GDK_KP_Equal: - key_code = isChar ? '=' : WXK_NUMPAD_EQUAL; + key_code = isChar ? '=' : int(WXK_NUMPAD_EQUAL); break; case GDK_KP_Multiply: - key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY; + key_code = isChar ? '*' : int(WXK_NUMPAD_MULTIPLY); break; case GDK_KP_Add: - key_code = isChar ? '+' : WXK_NUMPAD_ADD; + key_code = isChar ? '+' : int(WXK_NUMPAD_ADD); break; case GDK_KP_Separator: // FIXME: what is this? - key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR; + key_code = isChar ? '.' : int(WXK_NUMPAD_SEPARATOR); break; case GDK_KP_Subtract: - key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT; + key_code = isChar ? '-' : int(WXK_NUMPAD_SUBTRACT); break; case GDK_KP_Decimal: - key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL; + key_code = isChar ? '.' : int(WXK_NUMPAD_DECIMAL); break; case GDK_KP_Divide: - key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE; + key_code = isChar ? '/' : int(WXK_NUMPAD_DIVIDE); break; @@ -672,7 +666,7 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event, event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0; event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0; event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0; - event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0; + event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0; event.m_scanCode = gdk_event->keyval; event.m_rawCode = (wxUint32) gdk_event->keyval; event.m_rawFlags = 0; @@ -814,7 +808,7 @@ struct wxGtkIMData extern "C" { static gboolean -gtk_window_key_press_callback( GtkWidget *widget, +gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), GdkEventKey *gdk_event, wxWindow *win ) { @@ -823,12 +817,6 @@ gtk_window_key_press_callback( GtkWidget *widget, if (g_blockEventsOnDrag) return FALSE; - // GTK+ sends keypress events to the focus widget and then - // to all its parent and grandparent widget. We only want - // the key events from the focus widget. - if (!GTK_WIDGET_HAS_FOCUS(widget)) - return FALSE; - wxKeyEvent event( wxEVT_KEY_DOWN ); bool ret = false; bool return_after_IM = false; @@ -1074,7 +1062,7 @@ template void InitMouseEvent(wxWindowGTK *win, event.m_shiftDown = gdk_event->state & GDK_SHIFT_MASK; event.m_controlDown = gdk_event->state & GDK_CONTROL_MASK; event.m_altDown = gdk_event->state & GDK_MOD1_MASK; - event.m_metaDown = gdk_event->state & GDK_MOD2_MASK; + event.m_metaDown = gdk_event->state & GDK_META_MASK; event.m_leftDown = gdk_event->state & GDK_BUTTON1_MASK; event.m_middleDown = gdk_event->state & GDK_BUTTON2_MASK; event.m_rightDown = gdk_event->state & GDK_BUTTON3_MASK; @@ -1905,32 +1893,21 @@ wxWindow *wxWindowBase::DoFindFocus() { wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus; // the cast is necessary when we compile in wxUniversal mode - return wx_static_cast(wxWindow*, focus); + return static_cast(focus); } -//----------------------------------------------------------------------------- -// 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 ) +void wxWindowGTK::AddChildGTK(wxWindowGTK* child) { /* the window might have been scrolled already, do we have to adapt the position */ - wxPizza* pizza = WX_PIZZA(parent->m_wxwindow); + wxPizza* pizza = WX_PIZZA(m_wxwindow); child->m_x += pizza->m_scroll_x; child->m_y += pizza->m_scroll_y; gtk_widget_set_size_request( child->m_widget, child->m_width, child->m_height); gtk_fixed_put( - GTK_FIXED(parent->m_wxwindow), child->m_widget, child->m_x, child->m_y); + GTK_FIXED(m_wxwindow), child->m_widget, child->m_x, child->m_y); } //----------------------------------------------------------------------------- @@ -1964,7 +1941,7 @@ wxMouseState wxGetMouseState() ms.SetControlDown(mask & GDK_CONTROL_MASK); ms.SetShiftDown(mask & GDK_SHIFT_MASK); ms.SetAltDown(mask & GDK_MOD1_MASK); - ms.SetMetaDown(mask & GDK_MOD2_MASK); + ms.SetMetaDown(mask & GDK_META_MASK); return ms; } @@ -2015,8 +1992,6 @@ void wxWindowGTK::Init() m_oldClientWidth = m_oldClientHeight = 0; - m_insertCallback = wxInsertChildInWindow; - m_clipPaintRegion = false; m_needsStyleChange = false; @@ -2134,12 +2109,15 @@ bool wxWindowGTK::Create( wxWindow *parent, gtk_widget_show( m_wxwindow ); } + g_object_ref(m_widget); if (m_parent) m_parent->DoAddChild( this ); m_focusWidget = m_wxwindow; + SetCanFocus(AcceptsFocus()); + PostCreation(); return true; @@ -2181,17 +2159,17 @@ wxWindowGTK::~wxWindowGTK() // delete before the widgets to avoid a crash on solaris delete m_imData; - if (m_wxwindow && (m_wxwindow != m_widget)) - { - gtk_widget_destroy( m_wxwindow ); - m_wxwindow = (GtkWidget*) NULL; - } - if (m_widget) { - gtk_widget_destroy( m_widget ); - m_widget = (GtkWidget*) NULL; + // Note that gtk_widget_destroy() does not destroy the widget, it just + // emits the "destroy" signal. The widget is not actually destroyed + // until its reference count drops to zero. + gtk_widget_destroy(m_widget); + // Release our reference, should be the last one + g_object_unref(m_widget); + m_widget = NULL; } + m_wxwindow = NULL; } bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size ) @@ -2441,8 +2419,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags if (height != -1) m_height = height; - ConstrainSize(); - if (m_parent->m_wxwindow) { wxPizza* pizza = WX_PIZZA(m_parent->m_wxwindow); @@ -2657,8 +2633,8 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const if (m_parent) m_parent->ScreenToClient(&org_x, &org_y); - wx_const_cast(wxWindowGTK*, this)->m_x = org_x; - wx_const_cast(wxWindowGTK*, this)->m_y = org_y; + const_cast(this)->m_x = org_x; + const_cast(this)->m_y = org_y; } } @@ -2882,6 +2858,17 @@ void wxWindowGTK::GetTextExtent( const wxString& string, g_object_unref (layout); } +void wxWindowGTK::GTKDisableFocusOutEvent() +{ + g_signal_handlers_block_by_func( m_focusWidget, + (gpointer) gtk_window_focus_out_callback, this); +} + +void wxWindowGTK::GTKEnableFocusOutEvent() +{ + g_signal_handlers_unblock_by_func( m_focusWidget, + (gpointer) gtk_window_focus_out_callback, this); +} bool wxWindowGTK::GTKHandleFocusIn() { @@ -2936,7 +2923,7 @@ bool wxWindowGTK::GTKHandleFocusIn() // Notify the parent keeping track of focus for the kbd navigation // purposes that we got it. - wxChildFocusEvent eventChildFocus(this); + wxChildFocusEvent eventChildFocus(static_cast(this)); GTKProcessEvent(eventChildFocus); wxFocusEvent eventFocus(wxEVT_SET_FOCUS, GetId()); @@ -3102,13 +3089,8 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase ) wxASSERT( GTK_IS_WIDGET(m_widget) ); - /* prevent GTK from deleting the widget arbitrarily */ - gtk_widget_ref( m_widget ); - if (oldParent) - { gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget ); - } wxASSERT( GTK_IS_WIDGET(m_widget) ); @@ -3119,14 +3101,10 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase ) m_showOnIdle = true; gtk_widget_hide( m_widget ); } - /* insert GTK representation */ - (*(newParent->m_insertCallback))(newParent, this); + newParent->AddChildGTK(this); } - /* reverse: prevent GTK from deleting the widget arbitrarily */ - gtk_widget_unref( m_widget ); - SetLayoutDirection(wxLayout_Default); return true; @@ -3141,7 +3119,7 @@ void wxWindowGTK::DoAddChild(wxWindowGTK *child) AddChild( child ); /* insert GTK representation */ - (*m_insertCallback)(this, child); + AddChildGTK(child); } void wxWindowGTK::AddChild(wxWindowBase *child) @@ -3593,7 +3571,7 @@ void wxWindowGTK::GtkSendPaintEvents() else { wxWindowDC dc( (wxWindow*)this ); - dc.SetClippingRegion( m_updateRegion ); + dc.SetDeviceClippingRegion( m_updateRegion ); // Work around gtk-qt <= 0.60 bug whereby the window colour // remains grey @@ -4311,16 +4289,68 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const // freeze/thaw // ---------------------------------------------------------------------------- +extern "C" +{ + +// this is called if we attempted to freeze unrealized widget when it finally +// is realized (and so can be frozen): +static void wx_frozen_widget_realize(GtkWidget* w, void* WXUNUSED(data)) +{ + wxASSERT( w && !GTK_WIDGET_NO_WINDOW(w) ); + wxASSERT( GTK_WIDGET_REALIZED(w) ); + + g_signal_handlers_disconnect_by_func + ( + w, + (void*)wx_frozen_widget_realize, + NULL + ); + + gdk_window_freeze_updates(w->window); +} + +} // extern "C" + void wxWindowGTK::GTKFreezeWidget(GtkWidget *w) { - if ( w && !GTK_WIDGET_NO_WINDOW(w) ) - gdk_window_freeze_updates(w->window); + if ( !w || GTK_WIDGET_NO_WINDOW(w) ) + return; // window-less widget, cannot be frozen + + if ( !GTK_WIDGET_REALIZED(w) ) + { + // we can't thaw unrealized widgets because they don't have GdkWindow, + // so set it up to be done immediately after realization: + g_signal_connect_after + ( + w, + "realize", + G_CALLBACK(wx_frozen_widget_realize), + NULL + ); + return; + } + + gdk_window_freeze_updates(w->window); } void wxWindowGTK::GTKThawWidget(GtkWidget *w) { - if ( w && !GTK_WIDGET_NO_WINDOW(w) ) - gdk_window_thaw_updates(w->window); + if ( !w || GTK_WIDGET_NO_WINDOW(w) ) + return; // window-less widget, cannot be frozen + + if ( !GTK_WIDGET_REALIZED(w) ) + { + // the widget wasn't realized yet, no need to thaw + g_signal_handlers_disconnect_by_func + ( + w, + (void*)wx_frozen_widget_realize, + NULL + ); + return; + } + + gdk_window_thaw_updates(w->window); } void wxWindowGTK::DoFreeze()