X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/edd6813c826edc2311548da53eb83e7f1bc18d2b..05e0b047d879cdbfade7f2ab346c0acdf3e29f96:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 2ea22d82b2..f62c235b8b 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -40,6 +40,29 @@ #include #include +#if !GTK_CHECK_VERSION(2,10,0) + // GTK+ can reliably detect Meta key state only since 2.10 when + // GDK_META_MASK was introduced -- there wasn't any way to detect it + // in older versions. wxGTK used GDK_MOD2_MASK for this purpose, but + // GDK_MOD2_MASK is documented as: + // + // the fifth modifier key (it depends on the modifier mapping of the X + // server which key is interpreted as this modifier) + // + // In other words, it isn't guaranteed to map to Meta. This is a real + // problem: it is common to map NumLock to it (in fact, it's an exception + // if the X server _doesn't_ use it for NumLock). So the old code caused + // wxKeyEvent::MetaDown() to always return true as long as NumLock was on + // on many systems, which broke all applications using + // wxKeyEvent::GetModifiers() to check modifiers state (see e.g. here: + // http://tinyurl.com/56lsk2). + // + // Because of this, it's better to not detect Meta key state at all than + // to detect it incorrectly. Hence the following #define, which causes + // m_metaDown to be always set to false. + #define GDK_META_MASK 0 +#endif + //----------------------------------------------------------------------------- // documentation on internals //----------------------------------------------------------------------------- @@ -185,9 +208,11 @@ extern wxCursor g_globalCursor; static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL; static bool g_captureWindowHasMouse = false; -// The window that currently has focus or is scheduled to get it in the next -// event loop iteration -static wxWindowGTK *gs_focusWindow = NULL; +// The window that currently has focus: +static wxWindowGTK *gs_currentFocus = NULL; +// The window that is scheduled to get focus in the next event loop iteration +// or NULL if there's no pending focus change: +static wxWindowGTK *gs_pendingFocus = NULL; // the window that has deferred focus-out event pending, if any (see // GTKAddDeferredFocusOut() for details) @@ -256,39 +281,15 @@ void wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget), extern "C" { static gboolean -gtk_window_expose_callback( GtkWidget*, +gtk_window_expose_callback( GtkWidget* widget, GdkEventExpose *gdk_event, wxWindow *win ) { -#if 0 - if (win->GetName()) + if (gdk_event->window == widget->window) { - wxPrintf( wxT("OnExpose from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x, - (int)gdk_event->area.y, - (int)gdk_event->area.width, - (int)gdk_event->area.height ); + win->GetUpdateRegion() = wxRegion( gdk_event->region ); + win->GtkSendPaintEvents(); } - - gtk_paint_box - ( - win->m_wxwindow->style, - pizza->bin_window, - GTK_STATE_NORMAL, - GTK_SHADOW_OUT, - (GdkRectangle*) NULL, - win->m_wxwindow, - (char *)"button", // const_cast - 20,20,24,24 - ); -#endif - - win->GetUpdateRegion() = wxRegion( gdk_event->region ); - - win->GtkSendPaintEvents(); - // Let parent window draw window-less widgets return FALSE; } @@ -300,8 +301,6 @@ gtk_window_expose_callback( GtkWidget*, #ifndef __WXUNIVERSAL__ -GtkWidget* GetEntryWidget(); - extern "C" { static gboolean expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win) @@ -342,7 +341,7 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win) // for scrollable ones detail = "viewport"; - GtkWidget* styleWidget = GetEntryWidget(); + GtkWidget* styleWidget = wxGTKPrivate::GetEntryWidget(); gtk_paint_shadow( styleWidget->style, gdk_event->window, GTK_STATE_NORMAL, shadow, NULL, styleWidget, detail, x, y, w, h); @@ -522,11 +521,11 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar) case GDK_KP_7: case GDK_KP_8: case GDK_KP_9: - key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0; + key_code = (isChar ? '0' : int(WXK_NUMPAD0)) + keysym - GDK_KP_0; break; case GDK_KP_Space: - key_code = isChar ? ' ' : WXK_NUMPAD_SPACE; + key_code = isChar ? ' ' : int(WXK_NUMPAD_SPACE); break; case GDK_KP_Tab: @@ -598,32 +597,32 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar) break; case GDK_KP_Equal: - key_code = isChar ? '=' : WXK_NUMPAD_EQUAL; + key_code = isChar ? '=' : int(WXK_NUMPAD_EQUAL); break; case GDK_KP_Multiply: - key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY; + key_code = isChar ? '*' : int(WXK_NUMPAD_MULTIPLY); break; case GDK_KP_Add: - key_code = isChar ? '+' : WXK_NUMPAD_ADD; + key_code = isChar ? '+' : int(WXK_NUMPAD_ADD); break; case GDK_KP_Separator: // FIXME: what is this? - key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR; + key_code = isChar ? '.' : int(WXK_NUMPAD_SEPARATOR); break; case GDK_KP_Subtract: - key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT; + key_code = isChar ? '-' : int(WXK_NUMPAD_SUBTRACT); break; case GDK_KP_Decimal: - key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL; + key_code = isChar ? '.' : int(WXK_NUMPAD_DECIMAL); break; case GDK_KP_Divide: - key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE; + key_code = isChar ? '/' : int(WXK_NUMPAD_DIVIDE); break; @@ -670,7 +669,7 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event, 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_metaDown = (gdk_event->state & GDK_META_MASK) != 0; event.m_scanCode = gdk_event->keyval; event.m_rawCode = (wxUint32) gdk_event->keyval; event.m_rawFlags = 0; @@ -869,8 +868,18 @@ gtk_window_key_press_callback( GtkWidget *widget, int command = ancestor->GetAcceleratorTable()->GetCommand( event ); if (command != -1) { - wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command ); - ret = ancestor->HandleWindowEvent( command_event ); + wxCommandEvent menu_event( wxEVT_COMMAND_MENU_SELECTED, command ); + ret = ancestor->HandleWindowEvent( menu_event ); + + if ( !ret ) + { + // if the accelerator wasn't handled as menu event, try + // it as button click (for compatibility with other + // platforms): + wxCommandEvent button_event( wxEVT_COMMAND_BUTTON_CLICKED, command ); + ret = ancestor->HandleWindowEvent( button_event ); + } + break; } if (ancestor->IsTopLevel()) @@ -1062,7 +1071,7 @@ template void InitMouseEvent(wxWindowGTK *win, 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_metaDown = gdk_event->state & GDK_META_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; @@ -1372,7 +1381,7 @@ gtk_window_button_press_callback( GtkWidget *widget, return TRUE; if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() && - (gs_focusWindow != win) /* && win->IsFocusable() */) + (gs_currentFocus != win) /* && win->IsFocusable() */) { win->SetFocus(); } @@ -1891,8 +1900,9 @@ public: wxWindow *wxWindowBase::DoFindFocus() { + wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus; // the cast is necessary when we compile in wxUniversal mode - return wx_static_cast(wxWindow*, gs_focusWindow); + return wx_static_cast(wxWindow*, focus); } //----------------------------------------------------------------------------- @@ -1951,7 +1961,7 @@ wxMouseState wxGetMouseState() ms.SetControlDown(mask & GDK_CONTROL_MASK); ms.SetShiftDown(mask & GDK_SHIFT_MASK); ms.SetAltDown(mask & GDK_MOD1_MASK); - ms.SetMetaDown(mask & GDK_MOD2_MASK); + ms.SetMetaDown(mask & GDK_META_MASK); return ms; } @@ -2127,6 +2137,8 @@ bool wxWindowGTK::Create( wxWindow *parent, m_focusWidget = m_wxwindow; + SetCanFocus(AcceptsFocus()); + PostCreation(); return true; @@ -2136,8 +2148,10 @@ wxWindowGTK::~wxWindowGTK() { SendDestroyEvent(); - if (gs_focusWindow == this) - gs_focusWindow = NULL; + if (gs_currentFocus == this) + gs_currentFocus = NULL; + if (gs_pendingFocus == this) + gs_pendingFocus = NULL; if ( gs_deferredFocusOut == this ) gs_deferredFocusOut = NULL; @@ -2426,8 +2440,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags if (height != -1) m_height = height; - ConstrainSize(); - if (m_parent->m_wxwindow) { wxPizza* pizza = WX_PIZZA(m_parent->m_wxwindow); @@ -2907,9 +2919,8 @@ bool wxWindowGTK::GTKHandleFocusIn() if (m_imData) gtk_im_context_focus_in(m_imData->context); - // NB: SetFocus() does this assignment too, but not all focus changes - // originate from SetFocus() call - gs_focusWindow = this; + gs_currentFocus = this; + gs_pendingFocus = NULL; #if wxUSE_CARET // caret needs to be informed about focus change @@ -2922,7 +2933,7 @@ bool wxWindowGTK::GTKHandleFocusIn() // Notify the parent keeping track of focus for the kbd navigation // purposes that we got it. - wxChildFocusEvent eventChildFocus(this); + wxChildFocusEvent eventChildFocus(static_cast(this)); GTKProcessEvent(eventChildFocus); wxFocusEvent eventFocus(wxEVT_SET_FOCUS, GetId()); @@ -2971,22 +2982,22 @@ void wxWindowGTK::GTKHandleFocusOutNoDeferring() if (m_imData) gtk_im_context_focus_out(m_imData->context); - if ( gs_focusWindow != this ) + if ( gs_currentFocus != this ) { - // Something is terribly wrong, gs_focusWindow is out of sync with the + // Something is terribly wrong, gs_currentFocus is out of sync with the // real focus. We will reset it to NULL anyway, because after this // focus-out event is handled, one of the following with happen: // // * either focus will go out of the app altogether, in which case - // gs_focusWindow _should_ be NULL + // gs_currentFocus _should_ be NULL // // * or it goes to another control, in which case focus-in event will - // follow immediately and it will set gs_focusWindow to the right + // follow immediately and it will set gs_currentFocus to the right // value wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it", GetClassInfo()->GetClassName(), this, GetLabel()); } - gs_focusWindow = NULL; + gs_currentFocus = NULL; #if wxUSE_CARET // caret needs to be informed about focus change @@ -3037,7 +3048,7 @@ void wxWindowGTK::SetFocus() // Because we want to FindFocus() call immediately following // foo->SetFocus() to return foo, we have to keep track of "pending" focus // ourselves. - gs_focusWindow = this; + gs_pendingFocus = this; GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget; @@ -3579,7 +3590,7 @@ void wxWindowGTK::GtkSendPaintEvents() else { wxWindowDC dc( (wxWindow*)this ); - dc.SetClippingRegion( m_updateRegion ); + dc.SetDeviceClippingRegion( m_updateRegion ); // Work around gtk-qt <= 0.60 bug whereby the window colour // remains grey @@ -4297,16 +4308,68 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const // freeze/thaw // ---------------------------------------------------------------------------- +extern "C" +{ + +// this is called if we attempted to freeze unrealized widget when it finally +// is realized (and so can be frozen): +static void wx_frozen_widget_realize(GtkWidget* w, void* WXUNUSED(data)) +{ + wxASSERT( w && !GTK_WIDGET_NO_WINDOW(w) ); + wxASSERT( GTK_WIDGET_REALIZED(w) ); + + g_signal_handlers_disconnect_by_func + ( + w, + (void*)wx_frozen_widget_realize, + NULL + ); + + gdk_window_freeze_updates(w->window); +} + +} // extern "C" + void wxWindowGTK::GTKFreezeWidget(GtkWidget *w) { - if ( w && !GTK_WIDGET_NO_WINDOW(w) ) - gdk_window_freeze_updates(w->window); + if ( !w || GTK_WIDGET_NO_WINDOW(w) ) + return; // window-less widget, cannot be frozen + + if ( !GTK_WIDGET_REALIZED(w) ) + { + // we can't thaw unrealized widgets because they don't have GdkWindow, + // so set it up to be done immediately after realization: + g_signal_connect_after + ( + w, + "realize", + G_CALLBACK(wx_frozen_widget_realize), + NULL + ); + return; + } + + gdk_window_freeze_updates(w->window); } void wxWindowGTK::GTKThawWidget(GtkWidget *w) { - if ( w && !GTK_WIDGET_NO_WINDOW(w) ) - gdk_window_thaw_updates(w->window); + if ( !w || GTK_WIDGET_NO_WINDOW(w) ) + return; // window-less widget, cannot be frozen + + if ( !GTK_WIDGET_REALIZED(w) ) + { + // the widget wasn't realized yet, no need to thaw + g_signal_handlers_disconnect_by_func + ( + w, + (void*)wx_frozen_widget_realize, + NULL + ); + return; + } + + gdk_window_thaw_updates(w->window); } void wxWindowGTK::DoFreeze()