]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk1/window.cpp
use wx/math.h for math constants - avoids redifinition warnings
[wxWidgets.git] / src / gtk1 / window.cpp
index c2de0e2f975405d3f050fa9ef11820bc09ef34f7..00c74805d15eb2bf429d5f196184151ddd56caac 100644 (file)
@@ -1113,12 +1113,13 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
         return FALSE;
     
 #ifdef __WXGTK20__
+#if 0
     // We have to pass key press events through GTK+'s Input Method context
-    // object in order to get correct characters. By doing so, we loose the
+    // object in order to get correct characters. By doing so, we lose the
     // ability to let other GTK+'s handlers (namely, widgets' default signal
     // handlers) handle the signal by returning false from this callback.
     // Because GTK+ sends the events to parent widgets as well, we can't
-    // afford loosing it, otherwise native widgets inserted into wxPanel
+    // afford losing it, otherwise native widgets inserted into wxPanel
     // would break in subtle ways (e.g. spacebar would no longer toggle
     // wxCheckButton's state). Therefore, we only pass the event to IM if it
     // originated in this window's widget, which we detect by checking if we've
@@ -1126,33 +1127,120 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     // because gtk_window_key_press_callback is installed for native controls
     // as well and the wxKeyEvent it creates propagates upwards).
     static GdkEventKey s_lastEvent;
-    
     bool useIM = (win->m_imData != NULL) &&
                  memcmp(gdk_event, &s_lastEvent, sizeof(GdkEventKey)) != 0;
-    
     s_lastEvent = *gdk_event;
+#else
+    // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
+    // There is no need to store lastEvent. The original code makes GTK+ IM 
+    // dysfunction. When we get a key_press event here, it could be originate
+    // from the current widget or its child widgets.  However, only the widget
+    // with the INPUT FOCUS can generate the INITIAL key_press event.  That is, 
+    // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
+    // originated from its child widgets and shouldn't be passed to IM context.
+    // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
+    // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current
+    // widgets has both IM context and input focus, the event should be filtered 
+    // by gtk_im_context_filter_keypress().
+    // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
+    bool useIM = (win->m_imData != NULL) && ( wxWindow::FindFocus() == win );
+#endif
+
 #endif
     
-    wxKeyEvent event( wxEVT_KEY_DOWN );
-    if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
-    {
-        // unknown key pressed, ignore (the event would be useless anyhow)
+    bool IM_ret = FALSE;
 #ifdef __WXGTK20__
-        if ( useIM )
+    // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
+    // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
+    // docs, if IM filter returns true, no further processing should be done.
+    // wWe should send the key_down event anyway. 
+    if (useIM)
+    {
+        // it may be useful for the input method, though:
+        IM_ret = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
+        win->m_imData->lastKeyEvent = NULL;
+        if (IM_ret)
+            wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
+    }
+#endif
+
+    wxKeyEvent event( wxEVT_KEY_DOWN );
+    bool ret = FALSE;
+
+    // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
+    // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose 
+    // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are 
+    // composed of more than one character, which means gdk_event->length will always 
+    // greater than one. When gtk_event->length == 1, this may be an ASCII character
+    // and can be translated by wx.  However, when MBCS characters are sent by IM, 
+    // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
+    // nor should we pass it to controls. The following explanation was excerpted
+    // from GDK documentation.
+    // gint length : the length of string.
+    // gchar *string : a null-terminated multi-byte string containing the composed
+    // characters resulting from the key press. When text is being input, in a GtkEntry
+    // for example, it is these characters which should be added to the input buffer.
+    // When using Input Methods to support internationalized text input, the composed
+    // characters appear here after the pre-editing has been completed.
+
+#ifndef __WXGTK20__     
+    // This is for GTK+ 1.2 only. The char event generatation for
+    // GTK+ 2.0 is done in the emit handler.
+    
+    if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
+    {
+        // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
+        #if wxUSE_UNICODE   // GTK+ 1.2 is not UTF-8 based.
+            const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
+            if( !string )
+                return false;
+        #else
+            const char* string = gdk_event->string;
+        #endif
+
+        // Implement OnCharHook by checking ancesteror top level windows
+        wxWindow *parent = window;
+        while (parent && !parent->IsTopLevel())
+            parent = parent->GetParent();
+
+        for( wxChar* pstr = string; *pstr; pstr++ )
         {
-            // it may be useful for the input method, though:
-            win->m_imData->lastKeyEvent = gdk_event;
-            bool ret = gtk_im_context_filter_keypress(win->m_imData->context,
-                                                      gdk_event);
-            win->m_imData->lastKeyEvent = NULL;
-            return ret;
+        #if wxUSE_UNICODE
+            event.m_uniChar = *pstr;
+            // Backward compatible for ISO-8859-1
+            event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
+        #else
+            event.m_keyCode = *pstr;
+        #endif
+            if (parent)
+            {
+                event.SetEventType( wxEVT_CHAR_HOOK );
+                ret = parent->GetEventHandler()->ProcessEvent( event );
+            }
+            if (!ret)
+            {
+                event.SetEventType(wxEVT_CHAR);
+                window->GetEventHandler()->ProcessEvent( event );
+            }
         }
-#endif
-        return FALSE;
+        return true;
     }
+    // Only translate the key event when it's not sent with a pre-edited string.
+    else 
+#endif  // #ifndef  __WXGTK20__
 
-    // Emit KEY_DOWN event
-    bool ret = win->GetEventHandler()->ProcessEvent( event );
+    if( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+    {
+        // unknown key pressed, ignore (the event would be useless anyhow)
+        return false;
+    }
+    else // This event doesn't contain a pre-edited string and is not an invalid key either.
+    {
+        // Emit KEY_DOWN event
+        ret = win->GetEventHandler()->ProcessEvent( event );
+    }
+    if (IM_ret)
+        return false;
 
 #if wxUSE_ACCEL
     if (!ret)
@@ -1178,26 +1266,6 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     // will only be sent if it is not in an accelerator table.
     if (!ret)
     {
-#ifdef __WXGTK20__
-        if (useIM)
-        {
-            // In GTK 2.0, we need to hand over the key event to an input method
-            // and the IM will emit a "commit" event containing the actual utf8
-            // character.  In that case the EVT_CHAR events will be sent from
-            // there.
-            win->m_imData->lastKeyEvent = gdk_event;
-            if ( gtk_im_context_filter_keypress(win->m_imData->context,
-                                                gdk_event) )
-            {
-                win->m_imData->lastKeyEvent = NULL;
-                wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
-                return TRUE;
-            }
-            else
-                win->m_imData->lastKeyEvent = NULL;
-        }
-#endif
-
         long key_code;
         KeySym keysym = gdk_event->keyval;
         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
@@ -1345,7 +1413,7 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context,
     {
 #if wxUSE_UNICODE
         event.m_uniChar = *pstr;
-        // Backward compatible for ISO-8859
+        // Backward compatible for ISO-8859-1
         event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
         wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
 #else
@@ -2850,7 +2918,7 @@ void wxWindowGTK::PostCreation()
         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_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
             GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
     }
 
@@ -3709,18 +3777,28 @@ void wxWindowGTK::Raise()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_widget->window) return;
-
-    gdk_window_raise( m_widget->window );
+    if (m_wxwindow && m_wxwindow->window)
+    {
+        gdk_window_raise( m_wxwindow->window );
+    }
+     else if (m_widget->window)
+    {
+        gdk_window_raise( m_widget->window );
+    }
 }
 
 void wxWindowGTK::Lower()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_widget->window) return;
-
-    gdk_window_lower( m_widget->window );
+    if (m_wxwindow && m_wxwindow->window)
+    {
+        gdk_window_lower( m_wxwindow->window );
+    }
+     else if (m_widget->window)
+    {
+        gdk_window_lower( m_widget->window );
+    }
 }
 
 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
@@ -4237,9 +4315,10 @@ void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
     *is_waiting = FALSE;
 }
 
-static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
+void SetInvokingWindow( wxMenu *menu, wxWindow* win )
 {
     menu->SetInvokingWindow( win );
+    
     wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
     while (node)
     {
@@ -4280,6 +4359,10 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 
     wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
 
+    // NOTE: if you change this code, you need to update
+    //       the same code in taskbar.cpp as well. This
+    //       is ugly code duplication, I know,
+
     SetInvokingWindow( menu, this );
 
     menu->UpdateUI();