X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/dd00f3f6fa06de66a8c5dedb0494eecc66633994..dd107c50be43e8d4dbdba20df162faf119a3781c:/src/gtk/window.cpp?ds=inline diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index aa212c4d05..0e2f089cf7 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -12,6 +12,10 @@ #pragma implementation "window.h" #endif +#ifdef __VMS +#define XWarpPointer XWARPPOINTER +#endif + #include "wx/defs.h" #include "wx/window.h" #include "wx/dc.h" @@ -215,7 +219,9 @@ extern bool g_mainThreadLocked; // debug //----------------------------------------------------------------------------- +#ifndef __WXGTK20__ #define DISABLE_STYLE_IF_BROKEN_THEME 1 +#endif #ifdef __WXDEBUG__ @@ -316,7 +322,8 @@ extern bool g_isIdle; //----------------------------------------------------------------------------- // returns the child of win which currently has focus or NULL if not found -static wxWindow *FindFocusedChild(wxWindow *win) +// Note: can't be static, needed by textctrl.cpp. +/* static */ wxWindow *FindFocusedChild(wxWindow *win) { wxWindow *winFocus = wxWindow::FindFocus(); if ( !winFocus ) @@ -445,8 +452,9 @@ static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNU // key code mapping routines //----------------------------------------------------------------------------- -static long map_to_unmodified_wx_keysym( KeySym keysym ) +static long map_to_unmodified_wx_keysym( GdkEventKey *event ) { + KeySym keysym = event->keyval; guint key_code = 0; switch (keysym) @@ -542,7 +550,11 @@ static long map_to_unmodified_wx_keysym( KeySym keysym ) case GDK_F12: key_code = WXK_F12; break; default: { - if ((keysym & 0xF000) == 0) + if (event->length == 1) + { + key_code = toupper( (unsigned char)*event->string ); + } + else if ((keysym & 0xFF) == keysym) { guint upper = gdk_keyval_to_upper( (guint)keysym ); keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */ @@ -554,8 +566,9 @@ static long map_to_unmodified_wx_keysym( KeySym keysym ) return (key_code); } -static long map_to_wx_keysym( KeySym keysym ) +static long map_to_wx_keysym( GdkEventKey *event ) { + KeySym keysym = event->keyval; guint key_code = 0; switch (keysym) @@ -641,7 +654,11 @@ static long map_to_wx_keysym( KeySym keysym ) case GDK_F12: key_code = WXK_F12; break; default: { - if ((keysym & 0xF000) == 0) + if (event->length == 1) + { + key_code = (unsigned char)*event->string; + } + else if ((keysym & 0xFF) == keysym) { key_code = (guint)keysym; } @@ -651,6 +668,21 @@ static long map_to_wx_keysym( KeySym keysym ) return (key_code); } +//----------------------------------------------------------------------------- +// "size_request" of m_widget +//----------------------------------------------------------------------------- + +static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win ) +{ + int w,h; + win->GetSize( &w, &h ); + if (w < 2) w = 2; + if (h < 2) h = 2; + + requisition->height = h; + requisition->width = w; +} + //----------------------------------------------------------------------------- // "expose_event" of m_wxwindow //----------------------------------------------------------------------------- @@ -675,31 +707,47 @@ static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_ev } */ - win->GetUpdateRegion().Union( gdk_event->area.x, - gdk_event->area.y, - gdk_event->area.width, - gdk_event->area.height ); + GtkPizza *pizza = GTK_PIZZA (widget); - if (gdk_event->count == 0) - { - wxEraseEvent eevent( win->GetId() ); - eevent.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent(eevent); + if (win->GetThemeEnabled()) + { + wxWindow *parent = win->GetParent(); + while (parent && !parent->IsTopLevel()) + parent = parent->GetParent(); + if (!parent) + parent = win; - wxPaintEvent event( win->GetId() ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); + gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL, + GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1); + } + + win->GetUpdateRegion().Union( gdk_event->area.x, + gdk_event->area.y, + gdk_event->area.width, + gdk_event->area.height ); - win->GetUpdateRegion().Clear(); - } + if (gdk_event->count == 0) + { + win->m_clipPaintRegion = TRUE; + + wxEraseEvent eevent( win->GetId() ); + eevent.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent(eevent); + + wxPaintEvent event( win->GetId() ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); + + win->GetUpdateRegion().Clear(); + + win->m_clipPaintRegion = FALSE; + } /* The following code will result in all window-less widgets being redrawn if the wxWindows class is given a chance to paint *anything* because it will then be allowed to paint over the window-less widgets */ - GtkPizza *pizza = GTK_PIZZA (widget); - GList *children = pizza->children; while (children) { @@ -757,7 +805,13 @@ static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxW if (g_isIdle) wxapp_install_idle_handler(); - + + if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) && + (win->GetChildren().GetCount() == 0)) + { + return; + } + /* if (win->GetName() == wxT("panel")) { @@ -772,34 +826,47 @@ static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxW */ GtkPizza *pizza = GTK_PIZZA (widget); + + if (win->GetThemeEnabled()) + { + wxWindow *parent = win->GetParent(); + while (parent && !parent->IsTopLevel()) + parent = parent->GetParent(); + if (!parent) + parent = win; + + gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL, + GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1); + } - if (!(GTK_WIDGET_APP_PAINTABLE (widget)) && - (pizza->clear_on_draw)) - { - gdk_window_clear_area( pizza->bin_window, + + if (!(GTK_WIDGET_APP_PAINTABLE (widget)) && + (pizza->clear_on_draw)) + { + gdk_window_clear_area( pizza->bin_window, rect->x, rect->y, rect->width, rect->height); - } + } - win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height ); + win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height ); - win->m_clipPaintRegion = TRUE; + win->m_clipPaintRegion = TRUE; - wxEraseEvent eevent( win->GetId() ); - eevent.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent(eevent); + wxEraseEvent eevent( win->GetId() ); + eevent.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent(eevent); - wxPaintEvent event( win->GetId() ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); + wxPaintEvent event( win->GetId() ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); - win->GetUpdateRegion().Clear(); + win->GetUpdateRegion().Clear(); - win->m_clipPaintRegion = FALSE; + win->m_clipPaintRegion = FALSE; - GList *children = pizza->children; - while (children) - { + GList *children = pizza->children; + while (children) + { GtkPizzaChild *child = (GtkPizzaChild*) children->data; children = children->next; @@ -808,7 +875,7 @@ static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxW { gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ ); } - } + } } //----------------------------------------------------------------------------- @@ -840,7 +907,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_e bool ret = FALSE; - long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval ); + long key_code = map_to_unmodified_wx_keysym( gdk_event ); /* sending unknown key events doesn't really make sense */ if (key_code == 0) return FALSE; @@ -880,7 +947,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_e /* wxMSW doesn't send char events with Alt pressed */ /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x will only be sent if it is not in an accelerator table. */ - key_code = map_to_wx_keysym( gdk_event->keyval ); + key_code = map_to_wx_keysym( gdk_event ); if ( (!ret) && (key_code != 0)) @@ -998,7 +1065,7 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk printf( "\n" ); */ - long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval ); + long key_code = map_to_unmodified_wx_keysym( gdk_event ); /* sending unknown key events doesn't really make sense */ if (key_code == 0) return FALSE; @@ -1039,25 +1106,29 @@ static void AdjustEventButtonState(wxMouseEvent& event) // for compatibility with MSW and common sense we want m_leftDown be TRUE // for a LEFT_DOWN event, not FALSE, so we will invert // left/right/middleDown for the corresponding click events - switch ( event.GetEventType() ) + + if ((event.GetEventType() == wxEVT_LEFT_DOWN) || + (event.GetEventType() == wxEVT_LEFT_DCLICK) || + (event.GetEventType() == wxEVT_LEFT_UP)) { - case wxEVT_LEFT_DOWN: - case wxEVT_LEFT_DCLICK: - case wxEVT_LEFT_UP: - event.m_leftDown = !event.m_leftDown; - break; + event.m_leftDown = !event.m_leftDown; + return; + } - case wxEVT_MIDDLE_DOWN: - case wxEVT_MIDDLE_DCLICK: - case wxEVT_MIDDLE_UP: - event.m_middleDown = !event.m_middleDown; - break; + if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) || + (event.GetEventType() == wxEVT_MIDDLE_DCLICK) || + (event.GetEventType() == wxEVT_MIDDLE_UP)) + { + event.m_middleDown = !event.m_middleDown; + return; + } - case wxEVT_RIGHT_DOWN: - case wxEVT_RIGHT_DCLICK: - case wxEVT_RIGHT_UP: - event.m_rightDown = !event.m_rightDown; - break; + if ((event.GetEventType() == wxEVT_RIGHT_DOWN) || + (event.GetEventType() == wxEVT_RIGHT_DCLICK) || + (event.GetEventType() == wxEVT_RIGHT_UP)) + { + event.m_rightDown = !event.m_rightDown; + return; } } @@ -1539,15 +1610,25 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED( } #endif // wxUSE_CARET + if (win->IsTopLevel()) + { + wxActivateEvent event( wxEVT_ACTIVATE, TRUE, win->GetId() ); + event.SetEventObject( win ); + + // ignore return value + win->GetEventHandler()->ProcessEvent( event ); + } + wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() ); event.SetEventObject( win ); if (win->GetEventHandler()->ProcessEvent( event )) { - gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" ); - return TRUE; + gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" ); + return TRUE; } + return FALSE; } @@ -1597,6 +1678,15 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED } #endif // wxUSE_CARET + if (win->IsTopLevel()) + { + wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() ); + event.SetEventObject( win ); + + // ignore return value + win->GetEventHandler()->ProcessEvent( event ); + } + wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() ); event.SetEventObject( win ); @@ -1972,22 +2062,22 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), GdkIMStyle style; GdkIMStyle supported_style = (GdkIMStyle) (GDK_IM_PREEDIT_NONE | - GDK_IM_PREEDIT_NOTHING | - GDK_IM_PREEDIT_POSITION | - GDK_IM_STATUS_NONE | - GDK_IM_STATUS_NOTHING); + GDK_IM_PREEDIT_NOTHING | + GDK_IM_PREEDIT_POSITION | + GDK_IM_STATUS_NONE | + GDK_IM_STATUS_NOTHING); if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) - supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION); + supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION); attr->style = style = gdk_im_decide_style (supported_style); attr->client_window = widget->window; if ((colormap = gtk_widget_get_colormap (widget)) != - gtk_widget_get_default_colormap ()) + gtk_widget_get_default_colormap ()) { - attrmask |= GDK_IC_PREEDIT_COLORMAP; - attr->preedit_colormap = colormap; + attrmask |= GDK_IC_PREEDIT_COLORMAP; + attr->preedit_colormap = colormap; } attrmask |= GDK_IC_PREEDIT_FOREGROUND; @@ -1997,40 +2087,40 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), switch (style & GDK_IM_PREEDIT_MASK) { - case GDK_IM_PREEDIT_POSITION: - if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) - { - g_warning ("over-the-spot style requires fontset"); - break; - } + case GDK_IM_PREEDIT_POSITION: + if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) + { + g_warning ("over-the-spot style requires fontset"); + break; + } - gdk_window_get_size (widget->window, &width, &height); + gdk_window_get_size (widget->window, &width, &height); - attrmask |= GDK_IC_PREEDIT_POSITION_REQ; - attr->spot_location.x = 0; - attr->spot_location.y = height; - attr->preedit_area.x = 0; - attr->preedit_area.y = 0; - attr->preedit_area.width = width; - attr->preedit_area.height = height; - attr->preedit_fontset = widget->style->font; + attrmask |= GDK_IC_PREEDIT_POSITION_REQ; + attr->spot_location.x = 0; + attr->spot_location.y = height; + attr->preedit_area.x = 0; + attr->preedit_area.y = 0; + attr->preedit_area.width = width; + attr->preedit_area.height = height; + attr->preedit_fontset = widget->style->font; - break; + break; } win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask); if (win->m_ic == NULL) - g_warning ("Can't create input context."); + g_warning ("Can't create input context."); else - { - mask = gdk_window_get_events (widget->window); - mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic)); - gdk_window_set_events (widget->window, mask); - - if (GTK_WIDGET_HAS_FOCUS(widget)) - gdk_im_begin (win->m_ic, widget->window); - } + { + mask = gdk_window_get_events (widget->window); + mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic)); + gdk_window_set_events (widget->window, mask); + + if (GTK_WIDGET_HAS_FOCUS(widget)) + gdk_im_begin (win->m_ic, widget->window); + } #endif return FALSE; @@ -2276,6 +2366,9 @@ bool wxWindow::Create( wxWindow *parent, wxWindowID id, wxWindow::~wxWindow() { + if (g_focusWindow == this) + g_focusWindow = NULL; + m_isBeingDeleted = TRUE; m_hasVMT = FALSE; @@ -2361,14 +2454,17 @@ void wxWindow::PostCreation() gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE ); - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event", - GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this ); - gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event", GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this ); gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw", GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this ); + + if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) + { + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event", + GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this ); + } } #if (GTK_MINOR_VERSION > 0) @@ -2392,7 +2488,7 @@ void wxWindow::PostCreation() else { // For dialogs and frames, we are interested mainly in - // m_widget's focus. + // m_widget's focus. gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event", GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this ); @@ -2412,19 +2508,30 @@ void wxWindow::PostCreation() if (m_wxwindow) { - /* Catch native resize events. */ + // Catch native resize events gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate", GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this ); - /* Initialize XIM support. */ + // Initialize XIM support gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize", GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this ); - /* And resize XIM window. */ + // And resize XIM window gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate", GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this ); } + 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 + // 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. + gtk_signal_connect( GTK_OBJECT(m_widget), "size_request", + GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this ); + } + m_hasVMT = TRUE; } @@ -2569,7 +2676,7 @@ void wxWindow::OnInternalIdle() // do it only once g_sendActivateEvent = -1; - wxActivateEvent event(wxEVT_ACTIVATE, activate, GetId()); + wxActivateEvent event(wxEVT_ACTIVATE_APP, activate, GetId()); event.SetEventObject(this); (void)GetEventHandler()->ProcessEvent(event); @@ -2837,6 +2944,23 @@ bool wxWindow::Show( bool show ) return TRUE; } +static void wxWindowNotifyEnable(wxWindow* win, bool enable) +{ + win->OnParentEnable(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(); + node; + node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame))) + wxWindowNotifyEnable(child, enable); + } +} + bool wxWindow::Enable( bool enable ) { wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") ); @@ -2851,6 +2975,8 @@ bool wxWindow::Enable( bool enable ) if ( m_wxwindow ) gtk_widget_set_sensitive( m_wxwindow, enable ); + wxWindowNotifyEnable(this, enable); + return TRUE; } @@ -3287,7 +3413,7 @@ void wxWindow::SetWidgetStyle() style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor(); style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor(); } - else + else { // Try to restore the gtk default style. This is still a little // oversimplified for what is probably really needed here for controls @@ -3324,7 +3450,7 @@ void wxWindow::SetWidgetStyle() // oversimplified for what is probably really needed here for controls // other than buttons, but is better than not being able to (re)set a // control's background colour to default grey and means resetting a - // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting + // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting // behavior -- RL GtkStyle *def = gtk_rc_get_style( m_widget ); @@ -3749,3 +3875,45 @@ void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) } */ } + +// Find the wxWindow at the current mouse position, also returning the mouse +// position. +wxWindow* wxFindWindowAtPointer(wxPoint& pt) +{ + pt = wxGetMousePosition(); + wxWindow* found = wxFindWindowAtPoint(pt); + return found; +} + +// Get the current mouse position. +wxPoint wxGetMousePosition() +{ + /* This crashes when used within wxHelpContext, + so we have to use the X-specific implementation below. + gint x, y; + GdkModifierType *mask; + (void) gdk_window_get_pointer(NULL, &x, &y, mask); + + return wxPoint(x, y); + */ + + int x, y; + GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y); + if (!windowAtPtr) + return wxPoint(-999, -999); + + Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr); + Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display)); + Window rootReturn, childReturn; + int rootX, rootY, winX, winY; + unsigned int maskReturn; + + XQueryPointer (display, + rootWindow, + &rootReturn, + &childReturn, + &rootX, &rootY, &winX, &winY, &maskReturn); + return wxPoint(rootX, rootY); + +} +