X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a589495eeb083bee99e4c92f8ff4e12457ca82bb..f68535b0a71224f6da88857e530607c12cd280eb:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 8e6e0f5a81..8878e9dbba 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -73,11 +73,6 @@ #include #endif -#ifdef __WXGTK20__ - #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d)) -#else - #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d)) -#endif #ifdef __WXGTK20__ #ifdef HAVE_XIM @@ -235,28 +230,17 @@ static GdkGC *g_eraseGC = NULL; static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL; static bool g_captureWindowHasMouse = FALSE; -/* extern */ wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL; +wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL; // the last window which had the focus - this is normally never NULL (except // if we never had focus at all) as even when g_focusWindow is NULL it still // keeps its previous value -static wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL; - -// the frame that is currently active (i.e. its child has focus). It is -// used to generate wxActivateEvents -static wxWindowGTK *g_activeFrame = (wxWindowGTK*) NULL; -static bool g_activeFrameLostFocus = FALSE; +wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL; // If a window get the focus set but has not been realized // yet, defer setting the focus to idle time. wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL; -// if we detect that the app has got/lost the focus, we set this variable to -// either TRUE or FALSE and an activate event will be sent during the next -// OnIdle() call and it is reset to -1: this value means that we shouldn't -// 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; @@ -632,7 +616,7 @@ static void gtk_window_draw_callback( GtkWidget *widget, #ifndef __WXUNIVERSAL__ GtkPizza *pizza = GTK_PIZZA (widget); - if (win->GetThemeEnabled()) + if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM) { wxWindow *parent = win->GetParent(); while (parent && !parent->IsTopLevel()) @@ -983,6 +967,9 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event, event.m_scanCode = gdk_event->keyval; event.m_rawCode = (wxUint32) gdk_event->keyval; event.m_rawFlags = 0; +#if wxUSE_UNICODE + event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval); +#endif event.m_x = x; event.m_y = y; event.SetEventObject( win ); @@ -1337,24 +1324,13 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, } #if wxUSE_UNICODE - event.m_uniChar = g_utf8_get_char( str ); - - // Backward compatible for ISO-8859 - if (event.m_uniChar < 256) - event.m_keyCode = event.m_uniChar; - wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar); + const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str ); #else - wchar_t unistr[2]; - unistr[0] = g_utf8_get_char(str); - unistr[1] = 0; - wxCharBuffer ansistr(wxConvLocal.cWC2MB(unistr)); - // We cannot handle characters that cannot be represented in - // current locale's charset in non-Unicode mode: - if (ansistr.data() == NULL) - return; - event.m_keyCode = ansistr[0u]; - wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), (wxChar)event.m_keyCode); + const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str ); + const wxCharBuffer data = wxConvLocal.cWC2MB( wdata ); #endif // wxUSE_UNICODE + if( !(const wxChar*)data ) + return; bool ret = false; @@ -1362,16 +1338,28 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context, wxWindow *parent = window; while (parent && !parent->IsTopLevel()) parent = parent->GetParent(); - if (parent) - { - event.SetEventType( wxEVT_CHAR_HOOK ); - ret = parent->GetEventHandler()->ProcessEvent( event ); - } - if (!ret) + for( const wxChar* pstr = data; *pstr; pstr++ ) { - event.SetEventType(wxEVT_CHAR); - ret = window->GetEventHandler()->ProcessEvent( event ); +#if wxUSE_UNICODE + event.m_uniChar = *pstr; + // Backward compatible for ISO-8859 + event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0; + wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar); +#else + event.m_keyCode = *pstr; +#endif // wxUSE_UNICODE + if (parent) + { + event.SetEventType( wxEVT_CHAR_HOOK ); + ret = parent->GetEventHandler()->ProcessEvent( event ); + } + + if (!ret) + { + event.SetEventType(wxEVT_CHAR); + ret = window->GetEventHandler()->ProcessEvent( event ); + } } } #endif @@ -1434,6 +1422,7 @@ template void InitMouseEvent(wxWindowGTK *win, if (event.GetEventType() == wxEVT_MOUSEWHEEL) { event.m_linesPerAction = 3; + event.m_wheelDelta = 120; if (((GdkEventButton*)gdk_event)->button == 4) event.m_wheelRotation = 120; else if (((GdkEventButton*)gdk_event)->button == 5) @@ -1702,6 +1691,21 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, // a chance to correct this win->FixUpMouseEvent(widget, event.m_x, event.m_y); + if ( event_type == wxEVT_RIGHT_DOWN ) + { + // generate a "context menu" event: this is similar to right mouse + // click under many GUIs except that it is generated differently + // (right up under MSW, ctrl-click under Mac, right down here) and + // + // (a) it's a command event and so is propagated to the parent + // (b) under MSW it can be generated from kbd too + // (c) it uses screen coords (because of (a)) + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, + win->GetId(), + win->ClientToScreen(event.GetPosition())); + (void)win->GetEventHandler()->ProcessEvent(evtCtx); + } + // find the correct window to send the event too: it may be a different one // from the one which got it at GTK+ level because some control don't have // their own X window and thus cannot get any events. @@ -1710,13 +1714,6 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, gs_timeLastClick = gdk_event->time; -/* - wxPrintf( wxT("2) OnButtonPress from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(".\n") ); -*/ - #ifndef __WXGTK20__ if (event_type == wxEVT_LEFT_DCLICK) { @@ -1788,20 +1785,6 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, // same wxListBox hack as above win->FixUpMouseEvent(widget, event.m_x, event.m_y); - if ( event_type == wxEVT_RIGHT_UP ) - { - // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP - // except that: - // - // (a) it's a command event and so is propagated to the parent - // (b) under MSW it can be generated from kbd too - // (c) it uses screen coords (because of (a)) - wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, - win->GetId(), - win->ClientToScreen(event.GetPosition())); - (void)win->GetEventHandler()->ProcessEvent(evtCtx); - } - if ( !g_captureWindow ) win = FindWindowForMouseEvent(win, event.m_x, event.m_y); @@ -1921,6 +1904,7 @@ static gint gtk_window_wheel_callback (GtkWidget * widget, event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); event.m_linesPerAction = 3; + event.m_wheelDelta = 120; if (gdk_event->direction == GDK_SCROLL_UP) event.m_wheelRotation = 120; else @@ -1968,7 +1952,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, wxWindow *win ) { DEBUG_MAIN_THREAD - + if (g_isIdle) wxapp_install_idle_handler(); @@ -1977,23 +1961,6 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, gtk_im_context_focus_in(win->m_imData->context); #endif - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; - - switch ( g_sendActivateEvent ) - { - case -1: - // we've got focus from outside, synthetize wxActivateEvent - g_sendActivateEvent = 1; - break; - - case 0: - // another our window just lost focus, it was already ours before - // - don't send any wxActivateEvent - g_sendActivateEvent = -1; - break; - } - g_focusWindowLast = g_focusWindow = win; @@ -2014,36 +1981,12 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, } #endif // wxUSE_CARET - g_activeFrameLostFocus = FALSE; - - 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); - g_activeFrame->GetEventHandler()->ProcessEvent(event); - - // Don't send focus events in addition to activate - // if (win == g_activeFrame) - // return TRUE; - } - // does the window itself think that it has the focus? if ( !win->m_hasFocus ) { // not yet, notify it win->m_hasFocus = TRUE; - + if ( DoSendFocusEvents(win) ) { gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" ); @@ -2070,29 +2013,9 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk gtk_im_context_focus_out(win->m_imData->context); #endif - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; - wxLogTrace( TRACE_FOCUS, _T("%s: focus out"), win->GetName().c_str() ); - 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 - g_sendActivateEvent = 0; wxWindowGTK *winFocus = wxFindFocusedChild(win); if ( winFocus ) @@ -2123,11 +2046,11 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() ); event.SetEventObject( win ); - if (win->GetEventHandler()->ProcessEvent( event )) - { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" ); - return TRUE; - } + // even if we did process the event in wx code, still let GTK itself + // process it too as otherwise bad things happen, especially in GTK2 + // where the text control simply aborts the program if it doesn't get + // the matching focus out event + (void)win->GetEventHandler()->ProcessEvent( event ); } return FALSE; @@ -2367,7 +2290,7 @@ static gint gtk_scrollbar_button_release_callback( GtkRange *widget, // because it is static and so couldn't be made virtual // ---------------------------------------------------------------------------- -wxWindow *wxWindowBase::FindFocus() +wxWindow *wxWindowBase::DoFindFocus() { // the cast is necessary when we compile in wxUniversal mode return (wxWindow *)g_focusWindow; @@ -2650,6 +2573,8 @@ void wxWindowGTK::Init() m_clipPaintRegion = FALSE; + m_needsStyleChange = false; + m_cursor = *wxSTANDARD_CURSOR; #ifdef __WXGTK20__ @@ -2798,9 +2723,6 @@ wxWindowGTK::~wxWindowGTK() if (g_focusWindow == this) g_focusWindow = NULL; - if (g_activeFrame == this) - g_activeFrame = NULL; - if ( g_delayedFocus == this ) g_delayedFocus = NULL; @@ -2903,14 +2825,17 @@ void wxWindowGTK::PostCreation() // focus handling - if (m_focusWidget == NULL) - m_focusWidget = m_widget; - - gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event", - GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this ); + if (!GTK_IS_WINDOW(m_widget)) + { + if (m_focusWidget == NULL) + m_focusWidget = m_widget; + + 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_FUNC(gtk_window_focus_out_callback), (gpointer)this ); + gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event", + GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this ); + } // connect to the various key and mouse handlers @@ -2950,6 +2875,8 @@ void wxWindowGTK::PostCreation() (gpointer) this ); } + InheritAttributes(); + m_hasVMT = TRUE; // unless the window was created initially hidden (i.e. Hide() had been @@ -3121,33 +3048,16 @@ void wxWindowGTK::OnInternalIdle() if ( m_dirtyTabOrder ) RealizeTabOrder(); #endif - - // Update invalidated regions. - GtkUpdate(); - - // Synthetize activate events. - if ( g_sendActivateEvent != -1 ) + // Update style if the window was not yet realized + // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called + if (m_needsStyleChange) { - bool activate = g_sendActivateEvent != 0; - - // do it only once - g_sendActivateEvent = -1; - - wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast); + SetBackgroundStyle(GetBackgroundStyle()); + m_needsStyleChange = false; } - if ( g_activeFrameLostFocus ) - { - 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); - g_activeFrame = NULL; - } - g_activeFrameLostFocus = FALSE; - } + // Update invalidated regions. + GtkUpdate(); wxCursor cursor = m_cursor; if (g_globalCursor.Ok()) cursor = g_globalCursor; @@ -3575,10 +3485,9 @@ void wxWindowGTK::GetTextExtent( const wxString& string, pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data )); #endif } - PangoLayoutLine *line = pango_layout_get_line(layout, 0); PangoRectangle rect; - pango_layout_line_get_extents(line, NULL, &rect); + pango_layout_get_extents(layout, NULL, &rect); if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width); if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height); @@ -3604,7 +3513,6 @@ void wxWindowGTK::GetTextExtent( const wxString& string, void wxWindowGTK::SetFocus() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); - if ( m_hasFocus ) { // don't do anything if we already have focus @@ -3620,8 +3528,16 @@ void wxWindowGTK::SetFocus() } else if (m_widget) { +#ifdef __WXGTK20__ + if (GTK_IS_CONTAINER(m_widget)) + { + gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD ); + } + else +#endif if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) ) { + if (!GTK_WIDGET_REALIZED(m_widget)) { // we can't set the focus to the widget now so we remember that @@ -3642,11 +3558,14 @@ void wxWindowGTK::SetFocus() gtk_widget_grab_focus (m_widget); } } - else if (GTK_IS_CONTAINER(m_widget)) + else +#ifndef __WXGTK20__ + if (GTK_IS_CONTAINER(m_widget)) { - SET_CONTAINER_FOCUS( m_widget, GTK_DIR_TAB_FORWARD ); + gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD ); } else +#endif { wxLogTrace(TRACE_FOCUS, _T("Can't set focus to %s(%s)"), @@ -3938,7 +3857,7 @@ void wxWindowGTK::GtkSendPaintEvents() // widget to draw on GtkPizza *pizza = GTK_PIZZA (m_wxwindow); - if (GetThemeEnabled()) + if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM) { // find ancestor from which to steal background wxWindow *parent = GetParent(); @@ -3992,7 +3911,7 @@ void wxWindowGTK::GtkSendPaintEvents() wxEraseEvent erase_event( GetId(), &dc ); erase_event.SetEventObject( this ); - if (!GetEventHandler()->ProcessEvent(erase_event)) + if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM) { if (!g_eraseGC) { @@ -4117,8 +4036,9 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour ) } // apply style change (forceStyle=true so that new style is applied - // even if the bg colour changed from valid to wxNullColour): - ApplyWidgetStyle(true); + // even if the bg colour changed from valid to wxNullColour) + if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM) + ApplyWidgetStyle(true); return true; } @@ -4233,17 +4153,55 @@ void wxWindowGTK::ApplyWidgetStyle(bool forceStyle) DoApplyWidgetStyle(style); gtk_rc_style_unref(style); } + + // Style change may affect GTK+'s size calculation: + InvalidateBestSize(); } void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style) { if (m_wxwindow) - // should we also do m_widget in this case? gtk_widget_modify_style(m_wxwindow, style); - else - gtk_widget_modify_style(m_widget, style); + gtk_widget_modify_style(m_widget, style); } +bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style) +{ + wxWindowBase::SetBackgroundStyle(style); + + if (style == wxBG_STYLE_CUSTOM) + { + GdkWindow *window = (GdkWindow*) NULL; + if (m_wxwindow) + window = GTK_PIZZA(m_wxwindow)->bin_window; + else + window = GetConnectWidget()->window; + + if (window) + { + // Make sure GDK/X11 doesn't refresh the window + // automatically. + gdk_window_set_back_pixmap( window, None, False ); +#ifdef __X__ + Display* display = GDK_WINDOW_DISPLAY(window); + XFlush(display); +#endif + m_needsStyleChange = false; + } + else + // Do in OnIdle, because the window is not yet available + m_needsStyleChange = true; + + // Don't apply widget style, or we get a grey background + } + else + { + // apply style change (forceStyle=true so that new style is applied + // even if the bg colour changed from valid to wxNullColour): + ApplyWidgetStyle(true); + } + return true; +} //----------------------------------------------------------------------------- // Pop-up menu stuff @@ -4306,10 +4264,10 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y ) bool is_waiting = true; - gtk_signal_connect( GTK_OBJECT(menu->m_menu), - "hide", - GTK_SIGNAL_FUNC(gtk_pop_hide_callback), - (gpointer)&is_waiting ); + gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu), + "hide", + GTK_SIGNAL_FUNC(gtk_pop_hide_callback), + (gpointer)&is_waiting ); wxPoint pos; gpointer userdata; @@ -4346,6 +4304,8 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y ) gtk_main_iteration(); } + gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler); + return true; }