X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/37d81cc2e2e27c640f22de52dcd4f2d936333372..1978421a6d8b81c1f8a961da4b8ddf544fec7b1b:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 5208da0f59..b966d46d21 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -8,15 +8,17 @@ ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "window.h" #endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + #ifdef __VMS #define XWarpPointer XWARPPOINTER #endif -#include "wx/defs.h" #include "wx/window.h" #include "wx/dcclient.h" #include "wx/frame.h" @@ -255,9 +257,9 @@ wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL; // send any activate events at all static int g_sendActivateEvent = -1; -/* hack: we need something to pass to gtk_menu_popup, so we store the time of - the last click here */ -static guint32 gs_timeLastClick = 0; +// hack: we need something to pass to gtk_menu_popup, so we store the time of +// the last click here +static guint32 gs_timeLastClick = 0; extern bool g_mainThreadLocked; @@ -345,7 +347,7 @@ wxWindow *wxFindFocusedChild(wxWindowGTK *win) if ( winFocus == win ) return (wxWindow *)win; - for ( wxWindowList::Node *node = win->GetChildren().GetFirst(); + for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); node; node = node->GetNext() ) { @@ -477,12 +479,18 @@ static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNU // "size_request" of m_widget //----------------------------------------------------------------------------- -static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win ) +// make it extern because wxStatitText needs to disconnect this one +extern "C" +void wxgtk_window_size_request_callback(GtkWidget *widget, + GtkRequisition *requisition, + wxWindow *win) { - int w,h; + int w, h; win->GetSize( &w, &h ); - if (w < 2) w = 2; - if (h < 2) h = 2; + if (w < 2) + w = 2; + if (h < 2) + h = 2; requisition->height = h; requisition->width = w; @@ -1065,7 +1073,7 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event, return TRUE; } -#ifndef __WXGTK20__ + static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win ) @@ -1115,42 +1123,58 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, // will only be sent if it is not in an accelerator table. if (!ret) { - // Find key code for EVT_CHAR and EVT_CHAR_HOOK events + long key_code; KeySym keysym = gdk_event->keyval; - long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */); - if ( !key_code ) +#ifdef __WXGTK20__ + // 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. But only do it this way for non-KeySym keys. + key_code = wxTranslateKeySymToWXKey(gdk_event->keyval, FALSE /* isChar */); + if ( !key_code && win->m_imContext ) { - if ( gdk_event->length == 1 ) - { - key_code = (unsigned char)gdk_event->string[0]; - } - else if ( wxIsAsciiKeysym(keysym) ) - { - // ASCII key - key_code = (unsigned char)keysym; - } + gtk_im_context_filter_keypress ( (GtkIMContext*) win->m_imContext, gdk_event ); + ret = TRUE; } - - if ( key_code ) + else +#endif { - wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code); - - event.m_keyCode = key_code; - - // Implement OnCharHook by checking ancesteror top level windows - wxWindow *parent = win; - while (parent && !parent->IsTopLevel()) - parent = parent->GetParent(); - if (parent) + // Find key code for EVT_CHAR and EVT_CHAR_HOOK events + key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */); + if ( !key_code ) { - event.SetEventType( wxEVT_CHAR_HOOK ); - ret = parent->GetEventHandler()->ProcessEvent( event ); + if ( gdk_event->length == 1 ) + { + key_code = (unsigned char)gdk_event->string[0]; + } + else if ( wxIsAsciiKeysym(keysym) ) + { + // ASCII key + key_code = (unsigned char)keysym; + } } - if (!ret) + if ( key_code ) { - event.SetEventType(wxEVT_CHAR); - ret = win->GetEventHandler()->ProcessEvent( event ); + wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code); + + event.m_keyCode = key_code; + + // Implement OnCharHook by checking ancesteror top level windows + wxWindow *parent = win; + while (parent && !parent->IsTopLevel()) + parent = parent->GetParent(); + if (parent) + { + event.SetEventType( wxEVT_CHAR_HOOK ); + ret = parent->GetEventHandler()->ProcessEvent( event ); + } + + if (!ret) + { + event.SetEventType(wxEVT_CHAR); + ret = win->GetEventHandler()->ProcessEvent( event ); + } } } } @@ -1221,132 +1245,8 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, return FALSE; } -#endif #ifdef __WXGTK20__ -static gint gtk_window_key_press_callback( GtkWidget *widget, - GdkEventKey *gdk_event, - wxWindow *win ) -{ - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) - return FALSE; - if (g_blockEventsOnDrag) - return FALSE; - - bool ret = FALSE; - bool dont_use_IM = FALSE; - - wxKeyEvent event( wxEVT_KEY_DOWN ); - long keycode = wxTranslateKeySymToWXKey( gdk_event->keyval, FALSE ); - if (keycode) - { - // We were able to decode the key press without - // any input method, so don't use it. - dont_use_IM = TRUE; - - // now fill all the other fields - int x = 0; - int y = 0; - GdkModifierType state; - if (gdk_event->window) - gdk_window_get_pointer(gdk_event->window, &x, &y, &state); - - event.SetTimestamp( gdk_event->time ); - 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_keyCode = keycode; - event.m_scanCode = gdk_event->keyval; - event.m_rawCode = (wxUint32) gdk_event->keyval; - event.m_rawFlags = 0; - event.m_x = x; - event.m_y = y; - event.SetEventObject( win ); - - // send key down event - ret = win->GetEventHandler()->ProcessEvent( event ); - - if (!ret) - { - // Implement OnCharHook by checking ancesteror top level windows - wxWindow *parent = win; - while (parent && !parent->IsTopLevel()) - parent = parent->GetParent(); - if (parent) - { - event.SetEventType( wxEVT_CHAR_HOOK ); - ret = parent->GetEventHandler()->ProcessEvent( event ); - } - - if (!ret) - { - event.SetEventType(wxEVT_CHAR); - ret = win->GetEventHandler()->ProcessEvent( event ); - } - } - - // win is a control: tab can be propagated up - if ( !ret && - ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) && - win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) - { - wxNavigationKeyEvent new_event; - new_event.SetEventObject( win->GetParent() ); - // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB - new_event.SetDirection( (gdk_event->keyval == GDK_Tab) ); - // CTRL-TAB changes the (parent) window, i.e. switch notebook page - new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) ); - new_event.SetCurrentFocus( win ); - ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event ); - } - - if ( !ret && - (gdk_event->keyval == GDK_Escape) ) - { - wxWindow *winForCancel = win, *btnCancel = NULL; - while ( winForCancel ) - { - btnCancel = winForCancel->FindWindow(wxID_CANCEL); - if ( btnCancel ) break; - - if ( winForCancel->IsTopLevel() ) break; - - winForCancel = winForCancel->GetParent(); - } - - if ( btnCancel ) - { - wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); - event.SetEventObject(btnCancel); - ret = btnCancel->GetEventHandler()->ProcessEvent(event); - } - } - } - - if (ret) - { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" ); - return TRUE; - } - - if (!dont_use_IM && win->m_imContext) - { - // 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. - gtk_im_context_filter_keypress ( (GtkIMContext*) win->m_imContext, gdk_event ); - - return TRUE; - } - - return FALSE; -} - static void gtk_wxwindow_commit_cb (GtkIMContext *context, const gchar *str, wxWindow *window) @@ -1369,23 +1269,25 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, event.m_keyCode = uniChar; #endif - if (!ret) - { - // Implement OnCharHook by checking ancesteror top level windows - wxWindow *parent = window; - while (parent && !parent->IsTopLevel()) + + // TODO: We still need to set all the extra attributes of the + // event, modifiers and such... + + + // Implement OnCharHook by checking ancestor top level windows + wxWindow *parent = window; + while (parent && !parent->IsTopLevel()) parent = parent->GetParent(); - if (parent) - { - event.SetEventType( wxEVT_CHAR_HOOK ); - ret = parent->GetEventHandler()->ProcessEvent( event ); - } + if (parent) + { + event.SetEventType( wxEVT_CHAR_HOOK ); + ret = parent->GetEventHandler()->ProcessEvent( event ); + } - if (!ret) - { - event.SetEventType(wxEVT_CHAR); - ret = window->GetEventHandler()->ProcessEvent( event ); - } + if (!ret) + { + event.SetEventType(wxEVT_CHAR); + ret = window->GetEventHandler()->ProcessEvent( event ); } } #endif @@ -1511,12 +1413,12 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y) yy += pizza->yoffset; } - wxNode *node = win->GetChildren().First(); + wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); while (node) { - wxWindowGTK *child = (wxWindowGTK*)node->Data(); + wxWindowGTK *child = node->GetData(); - node = node->Next(); + node = node->GetNext(); if (!child->IsShown()) continue; @@ -1526,7 +1428,7 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y) int xx1 = child->m_x; int yy1 = child->m_y; int xx2 = child->m_x + child->m_width; - int yy2 = child->m_x + child->m_height; + int yy2 = child->m_y + child->m_height; // left if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) || @@ -1835,6 +1737,10 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, { // synthetize a mouse enter or leave event if needed GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL); + // This seems to be necessary and actually been added to + // GDK itself in version 2.0.X + gdk_flush(); + bool hasMouse = winUnderMouse == gdk_event->window; if ( hasMouse != g_captureWindowHasMouse ) { @@ -1912,7 +1818,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, wxLogTrace(TRACE_FOCUS, _T("%s: focus in"), win->GetName().c_str()); - + #ifdef HAVE_XIM if (win->m_ic) gdk_im_begin(win->m_ic, win->m_wxwindow->window); @@ -2058,6 +1964,9 @@ gint gtk_window_enter_callback( GtkWidget *widget, if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; + // Event was emitted after a grab + if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE; + if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; int x = 0; @@ -2095,6 +2004,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; + // Event was emitted after an ungrab + if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE; + if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; wxMouseEvent event( wxEVT_LEAVE_WINDOW ); @@ -2275,21 +2187,6 @@ wxWindow *wxWindowBase::FindFocus() return (wxWindow *)g_focusWindow; } -//----------------------------------------------------------------------------- -// "destroy" event -//----------------------------------------------------------------------------- - -// VZ: Robert commented the code using out so it generates warnings: should -// be either fixed or removed completely -#if 0 - -static void gtk_window_destroy_callback( GtkWidget* widget, wxWindow *win ) -{ - wxWindowDestroyEvent event(win); - win->GetEventHandler()->ProcessEvent(event); -} - -#endif // 0 //----------------------------------------------------------------------------- // "realize" from m_widget @@ -2305,11 +2202,11 @@ gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win ) if (g_isIdle) wxapp_install_idle_handler(); - - if (win->m_delayedBackgroundColour) + + if (win->m_delayedBackgroundColour && !win->GetThemeEnabled()) win->GtkSetBackgroundColour( win->GetBackgroundColour() ); - if (win->m_delayedForegroundColour) + if (win->m_delayedForegroundColour && !win->GetThemeEnabled()) win->GtkSetForegroundColour( win->GetForegroundColour() ); #ifdef __WXGTK20__ @@ -2561,8 +2458,10 @@ void wxWindowGTK::Init() m_hAdjust = (GtkAdjustment*) NULL; m_vAdjust = (GtkAdjustment*) NULL; - m_oldHorizontalPos = 0.0; + m_oldHorizontalPos = m_oldVerticalPos = 0.0; + m_oldClientWidth = + m_oldClientHeight = 0; m_resizing = FALSE; m_widgetStyle = (GtkStyle*) NULL; @@ -2735,6 +2634,8 @@ bool wxWindowGTK::Create( wxWindow *parent, wxWindowGTK::~wxWindowGTK() { + SendDestroyEvent(); + if (g_focusWindow == this) g_focusWindow = NULL; @@ -2904,7 +2805,7 @@ void wxWindowGTK::PostCreation() GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this ); } - if (!GTK_IS_COMBO(m_widget)) + if ( !GTK_IS_COMBO(m_widget)) { // This is needed if we want to add our windows into native // GTK control, such as the toolbar. With this callback, the @@ -2912,7 +2813,8 @@ void wxWindowGTK::PostCreation() // programmer). Sadly, it misbehaves for wxComboBox. FIXME // when moving to GTK 2.0. gtk_signal_connect( GTK_OBJECT(m_widget), "size_request", - GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this ); + GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback), + (gpointer) this ); } m_hasVMT = TRUE; @@ -2940,11 +2842,6 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget ) gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event", GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this ); - - // This keeps crashing on me. RR. - // - // gtk_signal_connect( GTK_OBJECT(widget), "destroy", - // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this ); } bool wxWindowGTK::Destroy() @@ -3134,7 +3031,8 @@ void wxWindowGTK::OnInternalIdle() } } - UpdateWindowUI(); + if (wxUpdateUIEvent::CanUpdate(this)) + UpdateWindowUI(wxUPDATE_UI_FROMIDLE); } void wxWindowGTK::DoGetSize( int *width, int *height ) const @@ -3385,7 +3283,7 @@ static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable) // Recurse, so that children have the opportunity to Do The Right Thing // and reset colours that have been messed up by a parent's (really ancestor's) // Enable call - for ( wxWindowList::Node *node = win->GetChildren().GetFirst(); + for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); node; node = node->GetNext() ) { @@ -3420,9 +3318,31 @@ int wxWindowGTK::GetCharHeight() const wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") ); +#ifdef __WXGTK20__ + PangoContext *context = NULL; + if (m_widget) + context = gtk_widget_get_pango_context( m_widget ); + + if (!context) + return 0; + + PangoFontDescription *desc = m_font.GetNativeFontInfo()->description; + PangoLayout *layout = pango_layout_new(context); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, "H", 1); + PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data; + + PangoRectangle rect; + pango_layout_line_get_extents(line, NULL, &rect); + + g_object_unref( G_OBJECT( layout ) ); + + return (int) (rect.height / PANGO_SCALE); +#else GdkFont *font = m_font.GetInternalFont( 1.0 ); return font->ascent + font->descent; +#endif } int wxWindowGTK::GetCharWidth() const @@ -3431,9 +3351,31 @@ int wxWindowGTK::GetCharWidth() const wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") ); +#ifdef __WXGTK20__ + PangoContext *context = NULL; + if (m_widget) + context = gtk_widget_get_pango_context( m_widget ); + + if (!context) + return 0; + + PangoFontDescription *desc = m_font.GetNativeFontInfo()->description; + PangoLayout *layout = pango_layout_new(context); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, "H", 1); + PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data; + + PangoRectangle rect; + pango_layout_line_get_extents(line, NULL, &rect); + + g_object_unref( G_OBJECT( layout ) ); + + return (int) (rect.width / PANGO_SCALE); +#else GdkFont *font = m_font.GetInternalFont( 1.0 ); return gdk_string_width( font, "H" ); +#endif } void wxWindowGTK::GetTextExtent( const wxString& string, @@ -3675,6 +3617,18 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) if (g_isIdle) wxapp_install_idle_handler(); + wxRect myRect(0,0,0,0); + if (m_wxwindow && rect) + { + myRect.SetSize(wxSize( m_wxwindow->allocation.width, + m_wxwindow->allocation.height)); + myRect.Intersect(*rect); + if (!myRect.width || !myRect.height) + // nothing to do, rectangle is empty + return; + rect = &myRect; + } + if (eraseBackground && m_wxwindow && m_wxwindow->window) { if (rect) @@ -3908,7 +3862,7 @@ void wxWindowGTK::GtkSendPaintEvents() m_updateRegion.Clear(); } -void wxWindowGTK::Clear() +void wxWindowGTK::ClearBackground() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); @@ -4103,7 +4057,13 @@ void wxWindowGTK::SetWidgetStyle() if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT )) { - SET_STYLE_FONT(style, m_font.GetInternalFont( 1.0 )); +#ifdef __WXGTK20__ + pango_font_description_free( style->font_desc ); + style->font_desc = pango_font_description_copy( m_font.GetNativeFontInfo()->description ); +#else + gdk_font_unref( style->font ); + style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) ); +#endif } if (m_foregroundColour.Ok()) @@ -4190,7 +4150,7 @@ void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting ) static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win ) { menu->SetInvokingWindow( win ); - wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst(); while (node) { wxMenuItem *menuitem = node->GetData(); @@ -4259,13 +4219,16 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y ) wxPopupMenuPositionCallback, // function to position it NULL, // client data 0, // button used to activate it +#ifdef __WXGTK20__ + gtk_get_current_event_time() +#else gs_timeLastClick // the time of activation +#endif ); while (is_waiting) { - while (gtk_events_pending()) - gtk_main_iteration(); + gtk_main_iteration(); } return TRUE;