#include "wx/dialog.h"
#include "wx/msgdlg.h"
#include "wx/module.h"
+#include "wx/combobox.h"
#if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h"
requisition->width = w;
}
+
+extern "C"
+void wxgtk_combo_size_request_callback(GtkWidget *widget,
+ GtkRequisition *requisition,
+ wxComboBox *win)
+{
+ // This callback is actually hooked into the text entry
+ // of the combo box, not the GtkHBox.
+
+ int w, h;
+ win->GetSize( &w, &h );
+ if (w < 2)
+ w = 2;
+ if (h < 2)
+ h = 2;
+
+ GtkCombo *gcombo = GTK_COMBO(win->m_widget);
+
+ GtkRequisition entry_req;
+ entry_req.width = 2;
+ entry_req.height = 2;
+ (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
+ (gcombo->button, &entry_req );
+
+ requisition->width = w - entry_req.width;
+ requisition->height = entry_req.height+4; // TODO: why +4?
+}
+
//-----------------------------------------------------------------------------
// "expose_event" of m_wxwindow
//-----------------------------------------------------------------------------
#if wxUSE_UNICODE
event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
#endif
+ wxGetMousePosition( &x, &y );
+ win->ScreenToClient( &x, &y );
event.m_x = x;
event.m_y = y;
event.SetEventObject( win );
return FALSE;
if (g_blockEventsOnDrag)
return FALSE;
-
-#ifdef __WXGTK20__
- // 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
- // 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
- // 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
- // seen the same event before (no events from children are lost this way,
- // 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;
-#endif
-
+
+
wxKeyEvent event( wxEVT_KEY_DOWN );
- if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+ bool ret = false;
+ bool return_after_IM = false;
+
+ if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
{
- // unknown key pressed, ignore (the event would be useless anyhow)
+ // Emit KEY_DOWN event
+ ret = win->GetEventHandler()->ProcessEvent( event );
+ }
+ else
+ {
+ // Return after IM processing as we cannot do
+ // anything with it anyhow.
+ return_after_IM = true;
+ }
+
#ifdef __WXGTK20__
- if ( useIM )
+ // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
+ // 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.
+ if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
+ {
+ // 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.
+ // we should send the key_down event anyway.
+ bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
+ win->m_imData->lastKeyEvent = NULL;
+ if (intercepted_by_IM)
{
- // 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;
+ wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
+ return true;
}
-#endif
- return FALSE;
}
+#endif
+ if (return_after_IM)
+ return true;
- // Emit KEY_DOWN event
- bool ret = win->GetEventHandler()->ProcessEvent( event );
+#ifndef __WXGTK20__
+ // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
+ // in the "commit" handler.
+
+ // 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.
+
+ 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 = win;
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+
+ for( const wxChar* pstr = string; *pstr; pstr++ )
+ {
+ #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);
+ win->GetEventHandler()->ProcessEvent( event );
+ }
+ }
+ return true;
+ }
+
+#endif // #ifndef __WXGTK20__
#if wxUSE_ACCEL
if (!ret)
// 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
}
}
+
+
+
+
// win is a control: tab can be propagated up
if ( !ret &&
((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
{
#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
GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
}
- if ( !GTK_IS_COMBO(m_widget))
+ if (GTK_IS_COMBO(m_widget))
+ {
+ GtkCombo *gcombo = GTK_COMBO(m_widget);
+
+ gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
+ GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
+ (gpointer) this );
+ }
+ else
{
// This is needed if we want to add our windows into native
- // GTK control, such as the toolbar. With this callback, the
+ // GTK controls, 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.
+ // programmer). Sadly, it misbehaves for wxComboBox.
gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
(gpointer) this );
if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
- int border = 0;
+ int left_border = 0;
+ int right_border = 0;
+ int top_border = 0;
int bottom_border = 0;
-#ifndef __WXGTK20__
+ /* the default button has a border around it */
if (GTK_WIDGET_CAN_DEFAULT(m_widget))
{
- /* the default button has a border around it */
- border = 6;
+#ifdef __WXGTK20__
+ GtkBorder *default_outside_border = NULL;
+ gtk_widget_style_get( m_widget, "default_outside_border", &default_outside_border, NULL );
+ if (default_outside_border)
+ {
+ left_border += default_outside_border->left;
+ right_border += default_outside_border->right;
+ top_border += default_outside_border->top;
+ bottom_border += default_outside_border->bottom;
+ g_free( default_outside_border );
+ }
+#else
+ left_border = 6;
+ right_border = 6;
+ top_border = 6;
bottom_border = 5;
- }
#endif
+ }
- DoMoveWindow( m_x-border,
- m_y-border,
- m_width+2*border,
- m_height+border+bottom_border );
+ DoMoveWindow( m_x-top_border,
+ m_y-left_border,
+ m_width+left_border+right_border,
+ m_height+top_border+bottom_border );
}
if (m_hasScrolling)
{
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 )
void wxWindowGTK::Update()
{
GtkUpdate();
+
+ // when we call Update() we really want to update the window immediately on
+ // screen, even if itmeans flushing the entire queue and hence slowing down
+ // everything -- but it should still be done, it's just that Update() should
+ // be called very rarely
+ gdk_flush();
}
void wxWindowGTK::GtkUpdate()
// widget to draw on
GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
- if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
+ if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
{
// find ancestor from which to steal background
- wxWindow *parent = GetParent();
- while (parent && !parent->IsTopLevel())
- parent = parent->GetParent();
+ wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
if (!parent)
parent = (wxWindow*)this;