X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/db434467a143a2c847c4bcfe987f0202c2d02bf2..dd107c50be43e8d4dbdba20df162faf119a3781c:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 6c749174f2..0e2f089cf7 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: window.cpp +// Name: gtk/window.cpp // Purpose: // Author: Robert Roebling // Id: $Id$ @@ -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" @@ -30,21 +34,32 @@ #include "wx/tooltip.h" #endif +#if wxUSE_CARET + #include "wx/caret.h" +#endif // wxUSE_CARET + #include "wx/menu.h" #include "wx/statusbr.h" #include "wx/intl.h" #include "wx/settings.h" #include "wx/log.h" +#ifdef __WXDEBUG__ + #include "wx/thread.h" +#endif + #include -#include "gdk/gdk.h" -#include "gtk/gtk.h" -#include "gdk/gdkprivate.h" -#include "gdk/gdkkeysyms.h" -#include "wx/gtk/win_gtk.h" +#include +#include +#include +#include +#include -#include "gdk/gdkx.h" +#include +#include + +#include "wx/gtk/win_gtk.h" //----------------------------------------------------------------------------- // documentation on internals @@ -198,12 +213,24 @@ static int g_sendActivateEvent = -1; the last click here */ static guint32 gs_timeLastClick = 0; +extern bool g_mainThreadLocked; + //----------------------------------------------------------------------------- // debug //----------------------------------------------------------------------------- +#ifndef __WXGTK20__ +#define DISABLE_STYLE_IF_BROKEN_THEME 1 +#endif + #ifdef __WXDEBUG__ +#if wxUSE_THREADS +# define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance"); +#else +# define DEBUG_MAIN_THREAD +#endif + static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), const wxChar *WXUNUSED(name) ) @@ -240,6 +267,8 @@ void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window } } +#else +#define DEBUG_MAIN_THREAD #endif // Debug //----------------------------------------------------------------------------- @@ -251,11 +280,23 @@ gdk_window_warp_pointer (GdkWindow *window, gint x, gint y) { +#ifndef __WXGTK20__ GdkWindowPrivate *priv; +#endif if (!window) - window = (GdkWindow*) &gdk_root_parent; + window = GDK_ROOT_PARENT(); +#ifdef __WXGTK20__ + if (!GDK_WINDOW_DESTROYED(window)) + { + XWarpPointer (GDK_WINDOW_XDISPLAY(window), + None, /* not source window -> move from anywhere */ + GDK_WINDOW_XID(window), /* dest window */ + 0, 0, 0, 0, /* not source window -> move from anywhere */ + x, y ); + } +#else priv = (GdkWindowPrivate*) window; if (!priv->destroyed) @@ -266,6 +307,7 @@ gdk_window_warp_pointer (GdkWindow *window, 0, 0, 0, 0, /* not source window -> move from anywhere */ x, y ); } +#endif } //----------------------------------------------------------------------------- @@ -279,6 +321,29 @@ extern bool g_isIdle; // local code (see below) //----------------------------------------------------------------------------- +// returns the child of win which currently has focus or NULL if not found +// Note: can't be static, needed by textctrl.cpp. +/* static */ wxWindow *FindFocusedChild(wxWindow *win) +{ + wxWindow *winFocus = wxWindow::FindFocus(); + if ( !winFocus ) + return (wxWindow *)NULL; + + if ( winFocus == win ) + return win; + + for ( wxWindowList::Node *node = win->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *child = FindFocusedChild(node->GetData()); + if ( child ) + return child; + } + + return (wxWindow *)NULL; +} + static void draw_frame( GtkWidget *widget, wxWindow *win ) { if (!win->m_hasVMT) @@ -287,29 +352,35 @@ static void draw_frame( GtkWidget *widget, wxWindow *win ) int dw = 0; int dh = 0; - if (win->HasScrolling()) + if (win->m_hasScrolling) { - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget); - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(widget)->klass ); + GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget); -/* - GtkWidget *hscrollbar = scroll_window->hscrollbar; - GtkWidget *vscrollbar = scroll_window->vscrollbar; + GtkRequisition vscroll_req; + vscroll_req.width = 2; + vscroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request ) + (scroll_window->vscrollbar, &vscroll_req ); - we use this instead: range.slider_width = 11 + 2*2pts edge -*/ + GtkRequisition hscroll_req; + hscroll_req.width = 2; + hscroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request ) + (scroll_window->hscrollbar, &hscroll_req ); - if (scroll_window->vscrollbar_visible) - { - dw += 15; /* dw += vscrollbar->allocation.width; */ - dw += scroll_class->scrollbar_spacing; - } + GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) ); - if (scroll_window->hscrollbar_visible) - { - dh += 15; /* dh += hscrollbar->allocation.height; */ - dh += scroll_class->scrollbar_spacing; - } + if (scroll_window->vscrollbar_visible) + { + dw += vscroll_req.width; + dw += scroll_class->scrollbar_spacing; + } + + if (scroll_window->hscrollbar_visible) + { + dh += hscroll_req.height; + dh += scroll_class->scrollbar_spacing; + } } int dx = 0; @@ -359,10 +430,13 @@ static void draw_frame( GtkWidget *widget, wxWindow *win ) // "expose_event" of m_widget //----------------------------------------------------------------------------- -static void gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win ) +gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win ) { - if (gdk_event->count > 0) return; + if (gdk_event->count > 0) return FALSE; + draw_frame( widget, win ); + + return TRUE; } //----------------------------------------------------------------------------- @@ -378,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) @@ -475,7 +550,11 @@ static long map_to_unmodified_wx_keysym( KeySym keysym ) case GDK_F12: key_code = WXK_F12; break; default: { - if (keysym <= 0xFF) + 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 */ @@ -487,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) @@ -574,7 +654,11 @@ static long map_to_wx_keysym( KeySym keysym ) case GDK_F12: key_code = WXK_F12; break; default: { - if (keysym <= 0xFF) + if (event->length == 1) + { + key_code = (unsigned char)*event->string; + } + else if ((keysym & 0xFF) == keysym) { key_code = (guint)keysym; } @@ -584,70 +668,189 @@ 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 //----------------------------------------------------------------------------- -static void gtk_window_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxWindow *win ) +static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win ) { - if (!win->m_hasVMT) - return; + DEBUG_MAIN_THREAD + if (g_isIdle) + wxapp_install_idle_handler(); + +/* + if (win->GetName() == wxT("panel")) + { + 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 ); + } +*/ + + 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, &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 ); -/* - wxPrintf( "OnExpose from " ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( " %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 ); -*/ + 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 */ + + GList *children = pizza->children; + while (children) + { + GtkPizzaChild *child = (GtkPizzaChild*) children->data; + children = children->next; - if (gdk_event->count > 0) - return; + GdkEventExpose child_event = *gdk_event; - wxEraseEvent eevent( win->GetId() ); - eevent.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent(eevent); + if (GTK_WIDGET_NO_WINDOW (child->widget) && + GTK_WIDGET_DRAWABLE (child->widget) /* && + gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ ) + { + child_event.area.x = child->widget->allocation.x; + child_event.area.y = child->widget->allocation.y; + child_event.area.width = child->widget->allocation.width; + child_event.area.height = child->widget->allocation.height; + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + } + } + + return TRUE; +} - wxPaintEvent event( win->GetId() ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); +//----------------------------------------------------------------------------- +// "event" of m_wxwindow +//----------------------------------------------------------------------------- - win->GetUpdateRegion().Clear(); +/* GTK thinks it is clever and filters out a certain amount of "unneeded" + expose events. We need them, of course, so we override the main event + procedure in GtkWidget by giving our own handler for all system events. + There, we look for expose events ourselves whereas all other events are + handled normally. */ + +gint gtk_window_event_event_callback( GtkWidget *widget, GdkEventExpose *event, wxWindow *win ) +{ + if (event->type == GDK_EXPOSE) + { + gint ret = gtk_window_expose_callback( widget, event, win ); + return ret; + } + + return FALSE; } //----------------------------------------------------------------------------- // "draw" of m_wxwindow //----------------------------------------------------------------------------- -static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), - GdkRectangle *rect, wxWindow *win ) +/* This callback is a complete replacement of the gtk_pizza_draw() function, + which disabled. */ + +static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); - if (!win->m_hasVMT) + if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) && + (win->GetChildren().GetCount() == 0)) + { return; - - win->GetUpdateRegion().Union( rect->x, rect->y, - rect->width, rect->height ); + } /* - wxPrintf( "OnDraw from " ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - printf( win->GetClassInfo()->GetClassName() ); - wxPrintf( " %d %d %d %d\n", (int)rect->x, - (int)rect->y, - (int)rect->width, - (int)rect->height ); + if (win->GetName() == wxT("panel")) + { + wxPrintf( wxT("OnDraw from ") ); + if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) + wxPrintf( win->GetClassInfo()->GetClassName() ); + wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x, + (int)rect->y, + (int)rect->width, + (int)rect->height ); + } */ + + 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, + rect->x, rect->y, rect->width, rect->height); + } + + win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height ); + win->m_clipPaintRegion = TRUE; + wxEraseEvent eevent( win->GetId() ); eevent.SetEventObject( win ); win->GetEventHandler()->ProcessEvent(eevent); @@ -657,6 +860,22 @@ static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), win->GetEventHandler()->ProcessEvent( event ); win->GetUpdateRegion().Clear(); + + win->m_clipPaintRegion = FALSE; + + + GList *children = pizza->children; + while (children) + { + GtkPizzaChild *child = (GtkPizzaChild*) children->data; + children = children->next; + + GdkRectangle child_area; + if (gtk_widget_intersect (child->widget, rect, &child_area)) + { + gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ ); + } + } } //----------------------------------------------------------------------------- @@ -665,19 +884,22 @@ static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; + /* wxString tmp; tmp += (char)gdk_event->keyval; printf( "KeyDown-Code is: %s.\n", tmp.c_str() ); printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval ); */ - + int x = 0; int y = 0; GdkModifierType state; @@ -685,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; @@ -715,7 +937,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_e ret = ancestor->GetEventHandler()->ProcessEvent( command_event ); break; } - if (ancestor->m_isFrame) + if (ancestor->IsTopLevel()) break; ancestor = ancestor->GetParent(); } @@ -725,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)) @@ -747,18 +969,23 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_e /* win is a control: tab can be propagated up */ if ( (!ret) && ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) && +// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may +// have this style, yet choose not to process this particular TAB in which +// case TAB must still work as a navigational character +#if 0 (!win->HasFlag(wxTE_PROCESS_TAB)) && +#endif // 0 (win->GetParent()) && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) { wxNavigationKeyEvent new_event; - new_event.SetEventObject( win ); + 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->GetEventHandler()->ProcessEvent( new_event ); + ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event ); } /* generate wxID_CANCEL if has been pressed (typically in dialogs) */ @@ -817,6 +1044,8 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_e static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -836,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; @@ -867,12 +1096,50 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk return FALSE; } +// ---------------------------------------------------------------------------- +// mouse event processing helper +// ---------------------------------------------------------------------------- + +static void AdjustEventButtonState(wxMouseEvent& event) +{ + // GDK reports the old state of the button for a button press event, but + // 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 + + if ((event.GetEventType() == wxEVT_LEFT_DOWN) || + (event.GetEventType() == wxEVT_LEFT_DCLICK) || + (event.GetEventType() == wxEVT_LEFT_UP)) + { + event.m_leftDown = !event.m_leftDown; + return; + } + + if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) || + (event.GetEventType() == wxEVT_MIDDLE_DCLICK) || + (event.GetEventType() == wxEVT_MIDDLE_UP)) + { + event.m_middleDown = !event.m_middleDown; + return; + } + + if ((event.GetEventType() == wxEVT_RIGHT_DOWN) || + (event.GetEventType() == wxEVT_RIGHT_DCLICK) || + (event.GetEventType() == wxEVT_RIGHT_UP)) + { + event.m_rightDown = !event.m_rightDown; + return; + } +} + //----------------------------------------------------------------------------- // "button_press_event" //----------------------------------------------------------------------------- static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -904,7 +1171,7 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton } } - wxEventType event_type = wxEVT_LEFT_DOWN; + wxEventType event_type = wxEVT_NULL; if (gdk_event->button == 1) { @@ -934,6 +1201,12 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton } } + if ( event_type == wxEVT_NULL ) + { + // unknown mouse button or click type + return FALSE; + } + wxMouseEvent event( event_type ); event.SetTimestamp( gdk_event->time ); event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); @@ -947,6 +1220,8 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton event.m_x = (wxCoord)gdk_event->x; event.m_y = (wxCoord)gdk_event->y; + AdjustEventButtonState(event); + // Some control don't have their own X window and thus cannot get // any events. @@ -1037,6 +1312,8 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1060,6 +1337,7 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto case 1: event_type = wxEVT_LEFT_UP; break; case 2: event_type = wxEVT_MIDDLE_UP; break; case 3: event_type = wxEVT_RIGHT_UP; break; + default: return FALSE; } wxMouseEvent event( event_type ); @@ -1074,6 +1352,8 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto event.m_x = (wxCoord)gdk_event->x; event.m_y = (wxCoord)gdk_event->y; + AdjustEventButtonState(event); + // Some control don't have their own X window and thus cannot get // any events. @@ -1155,6 +1435,8 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1275,6 +1557,8 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1317,15 +1601,34 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED( gdk_im_begin(win->m_ic, win->m_wxwindow->window); #endif +#ifdef wxUSE_CARET + // caret needs to be informed about focus change + wxCaret *caret = win->GetCaret(); + if ( caret ) + { + caret->OnSetFocus(); + } +#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; } @@ -1335,6 +1638,8 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED( static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1346,6 +1651,10 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED // g_sendActivateEvent to -1 g_sendActivateEvent = 0; + wxWindow *winFocus = FindFocusedChild(win); + if ( winFocus ) + win = winFocus; + g_focusWindow = (wxWindow *)NULL; /* @@ -1360,6 +1669,24 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED gdk_im_end(); #endif +#ifdef wxUSE_CARET + // caret needs to be informed about focus change + wxCaret *caret = win->GetCaret(); + if ( caret ) + { + caret->OnKillFocus(); + } +#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 ); @@ -1378,6 +1705,8 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1424,6 +1753,8 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1470,6 +1801,8 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_ static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1504,6 +1837,8 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindow *win ) static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1532,81 +1867,66 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindow *win ) } //----------------------------------------------------------------------------- -// "changed" from m_vAdjust +// "button_press_event" from scrollbar //----------------------------------------------------------------------------- -static void gtk_window_vscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win ) +static gint gtk_scrollbar_button_press_callback( GtkRange *widget, + GdkEventButton *gdk_event, + wxWindow *win) { - if (g_isIdle) - wxapp_install_idle_handler(); - - if (g_blockEventsOnDrag) return; - if (!win->m_hasVMT) return; - - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - int value = (int)(win->m_vAdjust->value+0.5); - - wxScrollWinEvent event( command, value, wxVERTICAL ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); -} - -//----------------------------------------------------------------------------- -// "changed" from m_hAdjust -//----------------------------------------------------------------------------- + DEBUG_MAIN_THREAD -static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win ) -{ if (g_isIdle) wxapp_install_idle_handler(); - if (g_blockEventsOnDrag) return; - if (!win->m_hasVMT) return; - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - int value = (int)(win->m_hAdjust->value+0.5); + g_blockEventsOnScroll = TRUE; + win->m_isScrolling = (gdk_event->window == widget->slider); - wxScrollWinEvent event( command, value, wxHORIZONTAL ); - event.SetEventObject( win ); - win->GetEventHandler()->ProcessEvent( event ); + return FALSE; } //----------------------------------------------------------------------------- -// "button_press_event" from scrollbar +// "button_release_event" from scrollbar //----------------------------------------------------------------------------- -static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget), - GdkEventButton *WXUNUSED(gdk_event), - wxWindow *win ) +static gint gtk_scrollbar_button_release_callback( GtkRange *widget, + GdkEventButton *WXUNUSED(gdk_event), + wxWindow *win) { - if (g_isIdle) - wxapp_install_idle_handler(); + DEBUG_MAIN_THREAD // don't test here as we can release the mouse while being over // a different window than the slider // // if (gdk_event->window != widget->slider) return FALSE; - win->SetScrolling( TRUE ); + g_blockEventsOnScroll = FALSE; - return FALSE; -} - -//----------------------------------------------------------------------------- -// "button_release_event" from scrollbar -//----------------------------------------------------------------------------- + if (win->m_isScrolling) + { + wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE; + int value = -1; + int dir = -1; -static gint gtk_scrollbar_button_release_callback( GtkRange *WXUNUSED(widget), - GdkEventButton *WXUNUSED(gdk_event), - wxWindow *win ) -{ + GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget); + if (widget == GTK_RANGE(scrolledWindow->hscrollbar)) + { + value = (int)(win->m_hAdjust->value+0.5); + dir = wxHORIZONTAL; + } + if (widget == GTK_RANGE(scrolledWindow->vscrollbar)) + { + value = (int)(win->m_vAdjust->value+0.5); + dir = wxVERTICAL; + } -// don't test here as we can release the mouse while being over -// a different window than the slider -// -// if (gdk_event->window != widget->slider) return FALSE; + wxScrollWinEvent event( command, value, dir ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); + } - win->SetScrolling( FALSE ); + win->m_isScrolling = FALSE; return FALSE; } @@ -1631,6 +1951,8 @@ wxWindow *wxWindowBase::FindFocus() static gint gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win ) { + DEBUG_MAIN_THREAD + if (g_isIdle) wxapp_install_idle_handler(); @@ -1643,7 +1965,7 @@ gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win ) wxWindowCreateEvent event( win ); event.SetEventObject( win ); win->GetEventHandler()->ProcessEvent( event ); - + return FALSE; } @@ -1651,6 +1973,34 @@ gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win ) // "size_allocate" //----------------------------------------------------------------------------- +static +void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), + GtkAllocation *WXUNUSED(alloc), + wxWindow *win ) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + if (!win->m_hasScrolling) return; + + int client_width = 0; + int client_height = 0; + win->GetClientSize( &client_width, &client_height ); + if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight)) + return; + + win->m_oldClientWidth = client_width; + win->m_oldClientHeight = client_height; + + if (!win->m_nativeSizeEvent) + { + wxSizeEvent event( win->GetSize(), win->GetId() ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); + } +} + + #ifdef HAVE_XIM #define WXUNUSED_UNLESS_XIM(param) param #else @@ -1660,9 +2010,9 @@ gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win ) /* Resize XIM window */ static -void gtk_wxwindow_size_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), - GtkAllocation * WXUNUSED_UNLESS_XIM(alloc), - wxFrame * WXUNUSED_UNLESS_XIM(win) ) +void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget), + GtkAllocation* WXUNUSED_UNLESS_XIM(alloc), + wxWindow* WXUNUSED_UNLESS_XIM(win) ) { if (g_isIdle) wxapp_install_idle_handler(); @@ -1703,7 +2053,7 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), win->m_icattr = gdk_ic_attr_new(); if (!win->m_icattr) return FALSE; - + gint width, height; GdkEventMask mask; GdkColormap *colormap; @@ -1712,24 +2062,24 @@ 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; attrmask |= GDK_IC_PREEDIT_BACKGROUND; attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL]; @@ -1737,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; @@ -1859,8 +2209,13 @@ void wxWindow::Init() m_isFrame = FALSE; m_acceptsFocus = FALSE; + m_clipPaintRegion = FALSE; + m_cursor = *wxSTANDARD_CURSOR; - + + m_delayedForegroundColour = FALSE; + m_delayedBackgroundColour = FALSE; + #ifdef HAVE_XIM m_ic = (GdkIC*) NULL; m_icattr = (GdkICAttr*) NULL; @@ -1893,22 +2248,13 @@ bool wxWindow::Create( wxWindow *parent, wxWindowID id, } m_insertCallback = wxInsertChildInWindow; - + m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL ); GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS ); -#ifdef __WXDEBUG__ - debug_focus_in( m_widget, wxT("wxWindow::m_widget"), name ); -#endif - GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget); -#ifdef __WXDEBUG__ - debug_focus_in( scrolledWindow->hscrollbar, wxT("wxWindow::hsrcollbar"), name ); - debug_focus_in( scrolledWindow->vscrollbar, wxT("wxWindow::vsrcollbar"), name ); -#endif - - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass ); + GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) ); scroll_class->scrollbar_spacing = 0; gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); @@ -1918,10 +2264,6 @@ bool wxWindow::Create( wxWindow *parent, wxWindowID id, m_wxwindow = gtk_pizza_new(); -#ifdef __WXDEBUG__ - debug_focus_in( m_wxwindow, wxT("wxWindow::m_wxwindow"), name ); -#endif - gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow ); #if (GTK_MINOR_VERSION > 0) @@ -2010,11 +2352,6 @@ bool wxWindow::Create( wxWindow *parent, wxWindowID id, gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this ); - gtk_signal_connect( GTK_OBJECT(m_hAdjust), "changed", - (GtkSignalFunc) gtk_window_hscroll_change_callback, (gpointer) this ); - gtk_signal_connect(GTK_OBJECT(m_vAdjust), "changed", - (GtkSignalFunc) gtk_window_vscroll_change_callback, (gpointer) this ); - gtk_widget_show( m_wxwindow ); if (m_parent) @@ -2022,8 +2359,6 @@ bool wxWindow::Create( wxWindow *parent, wxWindowID id, PostCreation(); - ApplyWidgetStyle(); - Show( TRUE ); return TRUE; @@ -2031,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; @@ -2051,7 +2389,11 @@ wxWindow::~wxWindow() if (m_widgetStyle) { - gtk_style_unref( m_widgetStyle ); +#if DISABLE_STYLE_IF_BROKEN_THEME + // don't delete if it's a pixmap theme style + if (!m_widgetStyle->engine_data) + gtk_style_unref( m_widgetStyle ); +#endif m_widgetStyle = (GtkStyle*) NULL; } @@ -2109,11 +2451,20 @@ void wxWindow::PostCreation() if (!m_noExpose) { /* these get reported to wxWindows -> wxPaintEvent */ + + gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE ); + 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) @@ -2137,8 +2488,8 @@ 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 ); @@ -2154,18 +2505,33 @@ void wxWindow::PostCreation() been realized, so we do this directly after realization */ gtk_signal_connect( GTK_OBJECT(connect_widget), "realize", GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this ); - + if (m_wxwindow) { - /* Initialize XIM support. */ + // 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 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; } @@ -2206,7 +2572,7 @@ void wxWindow::DoMoveWindow(int x, int y, int width, int height) { gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height ); } - + void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags ) { wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") ); @@ -2214,7 +2580,7 @@ void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags ) if (m_resizing) return; /* I don't like recursions */ m_resizing = TRUE; - + if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */ { /* don't set the size for children of wxNotebook, just take the values. */ @@ -2273,6 +2639,17 @@ void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags ) m_height+border+bottom_border ); } + if (m_hasScrolling) + { + /* Sometimes the client area changes size without the + whole windows's size changing, but if the whole + windows's size doesn't change, no wxSizeEvent will + normally be sent. Here we add an extra test if + the client test has been changed and this will + be used then. */ + GetClientSize( &m_oldClientWidth, &m_oldClientHeight ); + } + /* wxPrintf( "OnSize sent from " ); if (GetClassInfo() && GetClassInfo()->GetClassName()) @@ -2299,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); @@ -2363,24 +2740,6 @@ void wxWindow::DoSetClientSize( int width, int height ) int dw = 0; int dh = 0; -#if (GTK_MINOR_VERSION == 0) - if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) - { - if (HasScrolling()) - { - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); -#if 0 // unused - if this is ok, just remove this line (VZ) - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass ); -#endif // 0 - - GtkWidget *viewport = scroll_window->viewport; - GtkStyleClass *viewport_class = viewport->style->klass; - - dw += 2 * viewport_class->xthickness; - dh += 2 * viewport_class->ythickness; - } - } -#else if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) { /* when using GTK 1.2 we set the shadow border size to 2 */ @@ -2393,32 +2752,37 @@ void wxWindow::DoSetClientSize( int width, int height ) dw += 1 * 2; dh += 1 * 2; } -#endif - if (HasScrolling()) + if (m_hasScrolling) { -/* - GtkWidget *hscrollbar = scroll_window->hscrollbar; - GtkWidget *vscrollbar = scroll_window->vscrollbar; + GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); - we use this instead: range.slider_width = 11 + 2*2pts edge -*/ + GtkRequisition vscroll_req; + vscroll_req.width = 2; + vscroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request ) + (scroll_window->vscrollbar, &vscroll_req ); - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass ); + GtkRequisition hscroll_req; + hscroll_req.width = 2; + hscroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request ) + (scroll_window->hscrollbar, &hscroll_req ); + + GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) ); if (scroll_window->vscrollbar_visible) { - dw += 15; /* dw += vscrollbar->allocation.width; */ + dw += vscroll_req.width; dw += scroll_class->scrollbar_spacing; } if (scroll_window->hscrollbar_visible) { - dh += 15; /* dh += hscrollbar->allocation.height; */ + dh += hscroll_req.height; dh += scroll_class->scrollbar_spacing; } - } + } SetSize( width+dw, height+dh ); } @@ -2438,24 +2802,6 @@ void wxWindow::DoGetClientSize( int *width, int *height ) const int dw = 0; int dh = 0; -#if (GTK_MINOR_VERSION == 0) - if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) - { - if (HasScrolling()) - { - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); -#if 0 // unused - if this is ok, just remove this line (VZ) - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass ); -#endif // 0 - - GtkWidget *viewport = scroll_window->viewport; - GtkStyleClass *viewport_class = viewport->style->klass; - - dw += 2 * viewport_class->xthickness; - dh += 2 * viewport_class->ythickness; - } - } -#else if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER)) { /* when using GTK 1.2 we set the shadow border size to 2 */ @@ -2468,28 +2814,34 @@ void wxWindow::DoGetClientSize( int *width, int *height ) const dw += 1 * 2; dh += 1 * 2; } -#endif - if (HasScrolling()) + + if (m_hasScrolling) { -/* - GtkWidget *hscrollbar = scroll_window->hscrollbar; - GtkWidget *vscrollbar = scroll_window->vscrollbar; + GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); - we use this instead: range.slider_width = 11 + 2*2pts edge -*/ + GtkRequisition vscroll_req; + vscroll_req.width = 2; + vscroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request ) + (scroll_window->vscrollbar, &vscroll_req ); - GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget); - GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass ); + GtkRequisition hscroll_req; + hscroll_req.width = 2; + hscroll_req.height = 2; + (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request ) + (scroll_window->hscrollbar, &hscroll_req ); + + GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) ); if (scroll_window->vscrollbar_visible) { - dw += 15; /* dw += vscrollbar->allocation.width; */ + dw += vscroll_req.width; dw += scroll_class->scrollbar_spacing; } if (scroll_window->hscrollbar_visible) { - dh += 15; /* dh += hscrollbar->allocation.height; */ + dh += hscroll_req.height; dh += scroll_class->scrollbar_spacing; } } @@ -2592,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") ); @@ -2606,6 +2975,8 @@ bool wxWindow::Enable( bool enable ) if ( m_wxwindow ) gtk_widget_set_sensitive( m_wxwindow, enable ); + wxWindowNotifyEnable(this, enable); + return TRUE; } @@ -2653,7 +3024,7 @@ void wxWindow::GetTextExtent( const wxString& string, void wxWindow::SetFocus() { wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); - + if (m_wxwindow) { if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow)) @@ -2756,7 +3127,16 @@ bool wxWindow::SetCursor( const wxCursor &cursor ) { wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") ); - return wxWindowBase::SetCursor( cursor ); + if (cursor == m_cursor) + return FALSE; + + if (g_isIdle) + wxapp_install_idle_handler(); + + if (cursor == wxNullCursor) + return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR ); + else + return wxWindowBase::SetCursor( cursor ); } void wxWindow::WarpPointer( int x, int y ) @@ -2802,37 +3182,69 @@ void wxWindow::Refresh( bool eraseBackground, const wxRect *rect ) { if (m_wxwindow) { + +/* GtkPizza *pizza = GTK_PIZZA(m_wxwindow); gboolean old_clear = pizza->clear_on_draw; gtk_pizza_set_clear( pizza, FALSE ); - gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL ); - gtk_pizza_set_clear( pizza, old_clear ); +*/ + GdkEventExpose gdk_event; + gdk_event.type = GDK_EXPOSE; + gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window; + gdk_event.count = 0; + gdk_event.area.x = 0; + gdk_event.area.y = 0; + gdk_event.area.width = m_wxwindow->allocation.width; + gdk_event.area.height = m_wxwindow->allocation.height; + gtk_window_expose_callback( m_wxwindow, &gdk_event, this ); + } else + { gtk_widget_draw( m_widget, (GdkRectangle*) NULL ); + } } else { - GdkRectangle gdk_rect; - gdk_rect.x = rect->x; - gdk_rect.y = rect->y; - gdk_rect.width = rect->width; - gdk_rect.height = rect->height; if (m_wxwindow) { +/* GtkPizza *pizza = GTK_PIZZA(m_wxwindow); gboolean old_clear = pizza->clear_on_draw; gtk_pizza_set_clear( pizza, FALSE ); + GdkRectangle gdk_rect; + gdk_rect.x = rect->x; + gdk_rect.y = rect->y; + gdk_rect.width = rect->width; + gdk_rect.height = rect->height; gtk_widget_draw( m_wxwindow, &gdk_rect ); + gtk_window_draw_callback( m_wxwindow, &gdk_rect, this ); gtk_pizza_set_clear( pizza, old_clear ); +*/ + GdkEventExpose gdk_event; + gdk_event.type = GDK_EXPOSE; + gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window; + gdk_event.count = 0; + gdk_event.area.x = rect->x; + gdk_event.area.y = rect->y; + gdk_event.area.width = rect->width; + gdk_event.area.height = rect->height; + gtk_window_expose_callback( m_wxwindow, &gdk_event, this ); } else + { + GdkRectangle gdk_rect; + gdk_rect.x = rect->x; + gdk_rect.y = rect->y; + gdk_rect.width = rect->width; + gdk_rect.height = rect->height; gtk_widget_draw( m_widget, &gdk_rect ); + } } } @@ -2844,7 +3256,7 @@ void wxWindow::Clear() if (m_wxwindow && m_wxwindow->window) { - gdk_window_clear( m_wxwindow->window ); +// gdk_window_clear( m_wxwindow->window ); } } @@ -2886,12 +3298,11 @@ bool wxWindow::SetBackgroundColour( const wxColour &colour ) // but it couldn't get applied as the // widget hasn't been realized yet. m_delayedBackgroundColour = TRUE; - - // pretend we have done something - return TRUE; } - if (m_wxwindow) + if ((m_wxwindow) && + (m_wxwindow->window) && + (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))) { /* wxMSW doesn't clear the window here. I don't do that either to provide compatibility. call Clear() to do the job. */ @@ -2900,17 +3311,7 @@ bool wxWindow::SetBackgroundColour( const wxColour &colour ) gdk_window_set_background( window, m_backgroundColour.GetColor() ); } - wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ); - if (sysbg == m_backgroundColour) - { - m_backgroundColour = wxNullColour; - ApplyWidgetStyle(); - m_backgroundColour = sysbg; - } - else - { - ApplyWidgetStyle(); - } + ApplyWidgetStyle(); return TRUE; } @@ -2938,37 +3339,63 @@ bool wxWindow::SetForegroundColour( const wxColour &colour ) // but it couldn't get applied as the // widget hasn't been realized yet. m_delayedForegroundColour = TRUE; - - // pretend we have done something - return TRUE; } - wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ); - if ( sysbg == m_backgroundColour ) - { - m_backgroundColour = wxNullColour; - ApplyWidgetStyle(); - m_backgroundColour = sysbg; - } - else - { - ApplyWidgetStyle(); - } + ApplyWidgetStyle(); return TRUE; } GtkStyle *wxWindow::GetWidgetStyle() { - if (m_widgetStyle) gtk_style_unref( m_widgetStyle ); + if (m_widgetStyle) + { + GtkStyle *remake = gtk_style_copy( m_widgetStyle ); +#ifdef __WXGTK20__ + /* FIXME: is this necessary? */ + _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass); +#else + remake->klass = m_widgetStyle->klass; +#endif + + gtk_style_unref( m_widgetStyle ); + m_widgetStyle = remake; + } + else + { + GtkStyle *def = gtk_rc_get_style( m_widget ); - m_widgetStyle = gtk_style_copy( gtk_rc_get_style( m_widget ) ); + if (!def) + def = gtk_widget_get_default_style(); + + m_widgetStyle = gtk_style_copy( def ); +#ifdef __WXGTK20__ + /* FIXME: is this necessary? */ + _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass); +#else + m_widgetStyle->klass = def->klass; +#endif + } return m_widgetStyle; } void wxWindow::SetWidgetStyle() { +#if DISABLE_STYLE_IF_BROKEN_THEM + if (m_widget->style->engine_data) + { + static bool s_warningPrinted = FALSE; + if (!s_warningPrinted) + { + printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" ); + s_warningPrinted = TRUE; + } + m_widgetStyle = m_widget->style; + return; + } +#endif + GtkStyle *style = GetWidgetStyle(); if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT )) @@ -2986,6 +3413,21 @@ void wxWindow::SetWidgetStyle() style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor(); style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor(); } + else + { + // Try to restore the gtk default style. This is still a little + // 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 foreground colour to *wxBLACK -- RL + GtkStyle *def = gtk_rc_get_style( m_widget ); + + if (!def) + def = gtk_widget_get_default_style(); + + style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL]; + style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT]; + style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE]; + } } if (m_backgroundColour.Ok()) @@ -3001,7 +3443,29 @@ void wxWindow::SetWidgetStyle() style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor(); style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor(); style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor(); - } + } + else + { + // Try to restore the gtk default style. This is still a little + // 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 + // behavior -- RL + GtkStyle *def = gtk_rc_get_style( m_widget ); + + if (!def) + def = gtk_widget_get_default_style(); + + style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL]; + style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL]; + style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT]; + style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT]; + style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE]; + style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE]; + style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE]; + style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE]; + } } } @@ -3155,6 +3619,10 @@ void wxWindow::CaptureMouse() if (!window) return; + wxCursor* cursor = & m_cursor; + if (!cursor->Ok()) + cursor = wxSTANDARD_CURSOR; + gdk_pointer_grab( window, FALSE, (GdkEventMask) (GDK_BUTTON_PRESS_MASK | @@ -3162,7 +3630,7 @@ void wxWindow::CaptureMouse() GDK_POINTER_MOTION_HINT_MASK | GDK_POINTER_MOTION_MASK), (GdkWindow *) NULL, - m_cursor.GetCursor(), + cursor->GetCursor(), (guint32)GDK_CURRENT_TIME ); g_captureWindow = this; } @@ -3282,20 +3750,29 @@ void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) m_vAdjust->value = fpos; } -/* - if (!m_isScrolling) + if (m_wxwindow->window) { -*/ - if (m_wxwindow->window) + if (orient == wxHORIZONTAL) { - if (orient == wxHORIZONTAL) - gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); - else - gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); + gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust), + (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this ); + + gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); + + gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed", + (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this ); + } + else + { + gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust), + (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this ); + + gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); + + gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", + (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this ); } -/* } -*/ } int wxWindow::GetScrollThumb( int orient ) const @@ -3339,67 +3816,104 @@ void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) ) wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); + + if ((dx == 0) && (dy == 0)) return; -/* - printf( "ScrollWindow: %d %d\n", dx, dy ); -*/ - + m_clipPaintRegion = TRUE; gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); - -/* - if (!m_scrollGC) - { - m_scrollGC = gdk_gc_new( m_wxwindow->window ); - gdk_gc_set_exposures( m_scrollGC, TRUE ); - } - - wxNode *node = m_children.First(); - while (node) - { - wxWindow *child = (wxWindow*) node->Data(); - int sx = 0; - int sy = 0; - child->GetSize( &sx, &sy ); - child->SetSize( child->m_x + dx, child->m_y + dy, sx, sy, wxSIZE_ALLOW_MINUS_ONE ); - node = node->Next(); - } - - int cw = 0; - int ch = 0; - GetClientSize( &cw, &ch ); - int w = cw - abs(dx); - int h = ch - abs(dy); - - if ((h < 0) || (w < 0)) + m_clipPaintRegion = FALSE; + +/* + if (m_children.GetCount() > 0) { - Refresh(); + gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy ); } else { - int s_x = 0; - int s_y = 0; - if (dx < 0) s_x = -dx; - if (dy < 0) s_y = -dy; - int d_x = 0; - int d_y = 0; - if (dx > 0) d_x = dx; - if (dy > 0) d_y = dy; - - gdk_window_copy_area( m_wxwindow->window, m_scrollGC, d_x, d_y, - m_wxwindow->window, s_x, s_y, w, h ); + GtkPizza *pizza = GTK_PIZZA(m_wxwindow); + + pizza->xoffset -= dx; + pizza->yoffset -= dy; + + GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window ); + gdk_gc_set_exposures( m_scrollGC, TRUE ); - wxRect rect; - if (dx < 0) rect.x = cw+dx; else rect.x = 0; - if (dy < 0) rect.y = ch+dy; else rect.y = 0; - if (dy != 0) rect.width = cw; else rect.width = abs(dx); - if (dx != 0) rect.height = ch; else rect.height = abs(dy); + int cw = 0; + int ch = 0; + GetClientSize( &cw, &ch ); + int w = cw - abs(dx); + int h = ch - abs(dy); - Refresh( TRUE, &rect ); + if ((h < 0) || (w < 0)) + { + Refresh(); + } + else + { + int s_x = 0; + int s_y = 0; + if (dx < 0) s_x = -dx; + if (dy < 0) s_y = -dy; + int d_x = 0; + int d_y = 0; + if (dx > 0) d_x = dx; + if (dy > 0) d_y = dy; + + gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y, + pizza->bin_window, s_x, s_y, w, h ); + + wxRect rect; + if (dx < 0) rect.x = cw+dx; else rect.x = 0; + if (dy < 0) rect.y = ch+dy; else rect.y = 0; + if (dy != 0) rect.width = cw; else rect.width = abs(dx); + if (dx != 0) rect.height = ch; else rect.height = abs(dy); + + Refresh( TRUE, &rect ); + } + + gdk_gc_unref( m_scrollGC ); } */ } -void wxWindow::SetScrolling(bool scroll) +// 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() { - m_isScrolling = g_blockEventsOnScroll = scroll; + /* 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); + } +