]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
assigning line marker to itself shouldn't invalidate it, add self-assignment check
[wxWidgets.git] / src / gtk / window.cpp
index f71bac7cecf50907200cfc1a64f6f1ea68ab7ed2..367f3aec8bf39ec285a26f1bad74dd4cb6083070 100644 (file)
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkx.h>
 
+#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<typename T> 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<wxWindow*>(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<wxWindowGTK*>(this)->m_x = org_x;
+            const_cast<wxWindowGTK*>(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<wxWindow*>(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()