]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
added support for wxArrayString data in wxVariant
[wxWidgets.git] / src / gtk / window.cpp
index 16d1c5820006d30e84b2f9000c2274d6922f6db1..a6f5fa3652b3b38889dc684b7b0d69be7e3ef779 100644 (file)
@@ -486,10 +486,21 @@ static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNU
 
 static long map_to_unmodified_wx_keysym( GdkEventKey *event )
 {
+    // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
+    //     but only event->keyval which is quite useless to us, so remember
+    //     the last character from GDK_KEY_PRESS and resue it as last resort
+    //
+    // NB: should be MT-neutral as always called from main thread only
+    static struct
+    {
+        KeySym keysym;
+        long   keycode;
+    } s_lastKeyPress = { 0, 0 };
+
     KeySym keysym = event->keyval;
     long key_code;
 
-    switch (keysym)
+    switch ( keysym )
     {
         case GDK_Shift_L:
         case GDK_Shift_R:       key_code = WXK_SHIFT;       break;
@@ -581,16 +592,43 @@ static long map_to_unmodified_wx_keysym( GdkEventKey *event )
         case GDK_F11:           key_code = WXK_F11;         break;
         case GDK_F12:           key_code = WXK_F12;         break;
         default:
-            if ( (keysym & 0xFF) == keysym )
+        {
+            // do we have the translation?
+            if ( event->length == 1 )
             {
-                guint upper = gdk_keyval_to_upper( (guint)keysym );
-                key_code = upper ? upper : keysym;
+                keysym = (KeySym)event->string[0];
             }
-            else
+            else if ( (keysym & 0xFF) != keysym )
             {
-                // unknown key code
-                key_code = 0;
+                // non ASCII key, what to do?
+
+                if ( event->type == GDK_KEY_RELEASE )
+                {
+                    // reuse the one from the last keypress if any
+                    if ( keysym == s_lastKeyPress.keysym )
+                    {
+                        key_code = s_lastKeyPress.keycode;
+
+                        // skip "return 0"
+                        break;
+                    }
+                }
+
+                // ignore this one, we don't know it
+                return 0;
             }
+            //else: ASCII key, ok
+
+            guint upper = gdk_keyval_to_upper( (guint)keysym );
+            key_code = upper ? upper : keysym;
+
+            if ( event->type == GDK_KEY_PRESS )
+            {
+                // remember it to be reused below later
+                s_lastKeyPress.keysym = keysym;
+                s_lastKeyPress.keycode = key_code;
+            }
+        }
     }
 
     return key_code;
@@ -683,7 +721,6 @@ static long map_to_wx_keysym( GdkEventKey *event )
         case GDK_F11:           key_code = WXK_F11;         break;
         case GDK_F12:           key_code = WXK_F12;         break;
         default:
-        {
             if (event->length == 1)
             {
                 key_code = (unsigned char)*event->string;
@@ -692,7 +729,6 @@ static long map_to_wx_keysym( GdkEventKey *event )
             {
                 key_code = (guint)keysym;
             }
-        }
     }
 
     return key_code;
@@ -749,8 +785,14 @@ static int gtk_window_expose_callback( GtkWidget *widget,
         if (!parent)
             parent = win;
 
-        gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
-            GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
+        gtk_paint_flat_box (parent->m_widget->style,
+                            pizza->bin_window,
+                            GTK_STATE_NORMAL,
+                            GTK_SHADOW_NONE,
+                            &gdk_event->area,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1);
     }
 
     win->GetUpdateRegion().Union( gdk_event->area.x,
@@ -892,8 +934,14 @@ static void gtk_window_draw_callback( GtkWidget *widget,
         if (!parent)
             parent = win;
 
-        gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
-            GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
+        gtk_paint_flat_box (parent->m_widget->style,
+                            pizza->bin_window,
+                            GTK_STATE_NORMAL,
+                            GTK_SHADOW_NONE,
+                            rect,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1);
     }
 
 
@@ -1172,6 +1220,27 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk
     return FALSE;
 }
 
+// ============================================================================
+// the mouse events
+// ============================================================================
+
+// init wxMouseEvent with the info from gdk_event
+#define InitMouseEvent(win, event, gdk_event) \
+    { \
+    event.SetTimestamp( gdk_event->time ); \
+    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_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); \
+\
+    wxPoint pt = win->GetClientAreaOrigin(); \
+    event.m_x = (wxCoord)gdk_event->x - pt.x; \
+    event.m_y = (wxCoord)gdk_event->y - pt.y; \
+    }
+
 // ----------------------------------------------------------------------------
 // mouse event processing helper
 // ----------------------------------------------------------------------------
@@ -1284,20 +1353,18 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton
     }
 
     wxMouseEvent event( event_type );
-    event.SetTimestamp( gdk_event->time );
-    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_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);
-
-    event.m_x = (wxCoord)gdk_event->x;
-    event.m_y = (wxCoord)gdk_event->y;
+    InitMouseEvent( win, event, gdk_event );
 
     AdjustEventButtonState(event);
 
+    // wxListBox actually get mouse events from the item
+
+    if (win->m_isListBox)
+    {
+        event.m_x += widget->allocation.x;
+        event.m_y += widget->allocation.y;
+    }
+
     // Some control don't have their own X window and thus cannot get
     // any events.
 
@@ -1417,19 +1484,18 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
     }
 
     wxMouseEvent event( event_type );
-    event.SetTimestamp( gdk_event->time );
-    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_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);
-    event.m_x = (wxCoord)gdk_event->x;
-    event.m_y = (wxCoord)gdk_event->y;
+    InitMouseEvent( win, event, gdk_event );
 
     AdjustEventButtonState(event);
 
+    // wxListBox actually get mouse events from the item
+
+    if (win->m_isListBox)
+    {
+        event.m_x += widget->allocation.x;
+        event.m_y += widget->allocation.y;
+    }
+
     // Some control don't have their own X window and thus cannot get
     // any events.
 
@@ -1505,24 +1571,6 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
     return FALSE;
 }
 
-// ============================================================================
-// the mouse events
-// ============================================================================
-
-// init wxMouseEvent with the info from gdk_event
-#define InitMouseEvent(event, gdk_event) \
-    event.SetTimestamp( gdk_event->time ); \
-    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_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); \
-\
-    event.m_x = (wxCoord)gdk_event->x; \
-    event.m_y = (wxCoord)gdk_event->y \
-
 //-----------------------------------------------------------------------------
 // "motion_notify_event"
 //-----------------------------------------------------------------------------
@@ -1560,7 +1608,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
 */
 
     wxMouseEvent event( wxEVT_MOTION );
-    InitMouseEvent(event, gdk_event);
+    InitMouseEvent(win, event, gdk_event);
 
     if ( g_captureWindow )
     {
@@ -1574,7 +1622,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
 
             wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
                                                        : wxEVT_LEAVE_WINDOW);
-            InitMouseEvent(event, gdk_event);
+            InitMouseEvent(win, event, gdk_event);
             event.SetEventObject(win);
             win->GetEventHandler()->ProcessEvent(event);
         }
@@ -1713,17 +1761,18 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     }
 #endif // wxUSE_CARET
 
-    
     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);
@@ -1761,9 +1810,6 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
-    //wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") )
-    g_activeFrameLostFocus = TRUE;
-
     // VZ: this is really weird but GTK+ seems to call us from inside
     //     gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
     //     this widget and then "focus_in". This is totally unexpected and
@@ -1776,6 +1822,19 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
         return FALSE;
     }
 
+    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
@@ -1846,10 +1905,10 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_
 
     gdk_window_get_pointer( widget->window, &x, &y, &state );
 
-    InitMouseEvent(event, gdk_event);
-
-    event.m_x = x;
-    event.m_y = y;
+    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 ))
     {
@@ -1894,8 +1953,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
     event.m_middleDown = (state & GDK_BUTTON2_MASK);
     event.m_rightDown = (state & GDK_BUTTON3_MASK);
 
-    event.m_x = x;
-    event.m_y = y;
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = x + pt.x;
+    event.m_y = y + pt.y;
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
@@ -2310,7 +2370,7 @@ void wxWindowGTK::Init()
 
     m_noExpose = FALSE;
     m_nativeSizeEvent = FALSE;
-    
+
     m_hasScrolling = FALSE;
     m_isScrolling = FALSE;
 
@@ -2326,6 +2386,7 @@ void wxWindowGTK::Init()
 
     m_isStaticBox = FALSE;
     m_isRadioButton = FALSE;
+    m_isListBox = FALSE;
     m_isFrame = FALSE;
     m_acceptsFocus = FALSE;
 
@@ -2484,7 +2545,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
     if (m_parent)
         m_parent->DoAddChild( this );
-        
+
     m_focusWidget = m_wxwindow;
 
     PostCreation();
@@ -2578,7 +2639,7 @@ bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const w
 void wxWindowGTK::PostCreation()
 {
     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-    
+
     if (m_wxwindow)
     {
         if (!m_noExpose)
@@ -2825,6 +2886,7 @@ void wxWindowGTK::OnInternalIdle()
     {
         if ( g_activeFrame )
         {
+            wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
             wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
             event.SetEventObject(g_activeFrame);
             g_activeFrame->GetEventHandler()->ProcessEvent(event);
@@ -3025,7 +3087,7 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const
         dx = pizza->xoffset;
         dy = pizza->yoffset;
     }
-    
+
     if (x) (*x) = m_x - dx;
     if (y) (*y) = m_y - dy;
 }
@@ -3187,6 +3249,13 @@ void wxWindowGTK::SetFocus()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
+#if 0
+    wxPrintf( "SetFocus from " );
+    if (GetClassInfo() && GetClassInfo()->GetClassName())
+        wxPrintf( GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
+
     if (m_wxwindow)
     {
         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
@@ -3211,6 +3280,14 @@ void wxWindowGTK::SetFocus()
            // ?
         }
     }
+
+#if 0
+    wxPrintf( "SetFocus finished in " );
+    if (GetClassInfo() && GetClassInfo()->GetClassName())
+        wxPrintf( GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
+
 }
 
 bool wxWindowGTK::AcceptsFocus() const
@@ -3471,7 +3548,7 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
 
     if ((m_wxwindow) &&
         (m_wxwindow->window) &&
-        (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
+        (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
     {
         /* wxMSW doesn't clear the window here. I don't do that either to
           provide compatibility. call Clear() to do the job. */
@@ -3567,7 +3644,7 @@ void wxWindowGTK::SetWidgetStyle()
 
     GtkStyle *style = GetWidgetStyle();
 
-    if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
+    if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
     {
         gdk_font_unref( style->font );
         style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
@@ -3576,7 +3653,7 @@ void wxWindowGTK::SetWidgetStyle()
     if (m_foregroundColour.Ok())
     {
         m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
-        if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
+        if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT))
         {
             style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
             style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
@@ -3602,7 +3679,7 @@ void wxWindowGTK::SetWidgetStyle()
     if (m_backgroundColour.Ok())
     {
         m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
-        if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
+        if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))
         {
             style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
             style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
@@ -3648,7 +3725,8 @@ void wxWindowGTK::ApplyWidgetStyle()
 
 #if wxUSE_MENUS_NATIVE
 
-static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
+extern "C"
+void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
 {
     *is_waiting = FALSE;
 }
@@ -3669,16 +3747,29 @@ static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
     }
 }
 
+// used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
+// wxPopupMenuPositionCallback()
+//
+// should be safe even in the MT case as the user can hardly popup 2 menus
+// simultaneously, can he?
 static gint gs_pop_x = 0;
 static gint gs_pop_y = 0;
 
-static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
-                              gint *x, gint *y,
-                              wxWindowGTK *win )
+extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
+                                             gint *x, gint *y,
+                                             gpointer WXUNUSED(user_data) )
 {
-    win->ClientToScreen( &gs_pop_x, &gs_pop_y );
-    *x = gs_pop_x;
-    *y = gs_pop_y;
+    // ensure that the menu appears entirely on screen
+    GtkRequisition req;
+    gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
+
+    wxSize sizeScreen = wxGetDisplaySize();
+
+    gint xmax = sizeScreen.x - req.width,
+         ymax = sizeScreen.y - req.height;
+
+    *x = gs_pop_x < xmax ? gs_pop_x : xmax;
+    *y = gs_pop_y < ymax ? gs_pop_y : ymax;
 }
 
 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
@@ -3693,20 +3784,23 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 
     gs_pop_x = x;
     gs_pop_y = y;
+    ClientToScreen( &gs_pop_x, &gs_pop_y );
 
     bool is_waiting = TRUE;
 
-    gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
-      GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
+    gtk_signal_connect( GTK_OBJECT(menu->m_menu),
+                        "hide",
+                        GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
+                        (gpointer)&is_waiting );
 
     gtk_menu_popup(
                   GTK_MENU(menu->m_menu),
-                  (GtkWidget *) NULL,          // parent menu shell
-                  (GtkWidget *) NULL,          // parent menu item
-                  (GtkMenuPositionFunc) pop_pos_callback,
-                  (gpointer) this,             // client data
-                  0,                           // button used to activate it
-                  gs_timeLastClick             // the time of activation
+                  (GtkWidget *) NULL,           // parent menu shell
+                  (GtkWidget *) NULL,           // parent menu item
+                  wxPopupMenuPositionCallback,  // function to position it
+                  NULL,                         // client data
+                  0,                            // button used to activate it
+                  gs_timeLastClick              // the time of activation
                 );
 
     while (is_waiting)
@@ -3763,7 +3857,7 @@ bool wxWindowGTK::SetFont( const wxFont &font )
         return FALSE;
     }
 
-    wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
+    wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
     if ( sysbg == m_backgroundColour )
     {
         m_backgroundColour = wxNullColour;
@@ -3778,7 +3872,7 @@ bool wxWindowGTK::SetFont( const wxFont &font )
     return TRUE;
 }
 
-void wxWindowGTK::CaptureMouse()
+void wxWindowGTK::DoCaptureMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
@@ -3807,12 +3901,14 @@ void wxWindowGTK::CaptureMouse()
     g_captureWindowHasMouse = TRUE;
 }
 
-void wxWindowGTK::ReleaseMouse()
+void wxWindowGTK::DoReleaseMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
     wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
 
+    g_captureWindow = (wxWindowGTK*) NULL;
+
     GdkWindow *window = (GdkWindow*) NULL;
     if (m_wxwindow)
         window = GTK_PIZZA(m_wxwindow)->bin_window;
@@ -3823,7 +3919,6 @@ void wxWindowGTK::ReleaseMouse()
         return;
 
     gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
-    g_captureWindow = (wxWindowGTK*) NULL;
 }
 
 /* static */