#endif
#include <math.h>
+#include <ctype.h>
#include "wx/gtk/private.h"
#include <gdk/gdkprivate.h>
// 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;
+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 wxWindowGTK *g_activeFrame = (wxWindowGTK*) NULL;
static bool g_activeFrameLostFocus = FALSE;
+// 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
#else
# define DEBUG_MAIN_THREAD
#endif
-
-static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
- GdkEvent *WXUNUSED(event),
- const wxChar *WXUNUSED(name) )
-{
-/*
- static bool s_done = FALSE;
- if ( !s_done )
- {
- wxLog::AddTraceMask("focus");
- s_done = TRUE;
- }
- wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
-*/
-
- return FALSE;
-}
-
-void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
-{
- // suppress warnings about gtk_debug_focus_in_callback being unused with
- // this "if ( 0 )"
- if ( 0 )
- {
- wxString tmp = name;
- tmp += wxT(" FROM ");
- tmp += window;
-
- wxChar *s = new wxChar[tmp.Length()+1];
-
- wxStrcpy( s, tmp );
-
- gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
- GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
- }
-}
-
#else
#define DEBUG_MAIN_THREAD
#endif // Debug
+// the trace mask used for the focus debugging messages
+#define TRACE_FOCUS _T("focus")
+
//-----------------------------------------------------------------------------
// missing gdk functions
//-----------------------------------------------------------------------------
return (wxWindow *)NULL;
}
-// Returns toplevel grandparent of given window:
-static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
-{
- wxWindowGTK *p = win;
- while (p && !p->IsTopLevel())
- p = p->GetParent();
- return p;
-}
-
static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
{
// wxUniversal widgets draw the borders and scrollbars themselves
if (g_isIdle)
wxapp_install_idle_handler();
-/*
- if (win->GetName() == wxT("panel"))
+#if 0
+ if (win->GetName())
{
wxPrintf( wxT("OnExpose from ") );
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
(int)gdk_event->area.width,
(int)gdk_event->area.height );
}
-*/
-
-#ifndef __WXUNIVERSAL__
- 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,
- (char *)"base",
- 0, 0, -1, -1);
- }
#endif
win->GetUpdateRegion().Union( gdk_event->area.x,
gdk_event->area.y,
gdk_event->area.width,
gdk_event->area.height );
+ win->m_clearRegion.Union( gdk_event->area.x,
+ gdk_event->area.y,
+ gdk_event->area.width,
+ gdk_event->area.height );
// Actual redrawing takes place in idle time.
- win->Update();
+ // win->GtkUpdate();
#ifdef __WXGTK20__
return;
}
-/*
- if (win->GetName() == wxT("panel"))
+#if 0
+ if (win->GetName())
{
wxPrintf( wxT("OnDraw from ") );
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
(int)rect->width,
(int)rect->height );
}
-*/
+#endif
#ifndef __WXUNIVERSAL__
GtkPizza *pizza = GTK_PIZZA (widget);
(char *)"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);
- }
#endif
+ win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
- // Actual redrawing takes place in idle time.
-
- win->Update();
+ // Update immediately, not in idle time.
+ win->GtkUpdate();
#ifndef __WXUNIVERSAL__
// Redraw child widgets
} s_lastKeyPress = { 0, 0 };
KeySym keysym = gdk_event->keyval;
+
+ wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
+ event.GetEventType() == wxEVT_KEY_UP ? _T("release")
+ : _T("press"),
+ keysym);
+
long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */);
if ( !key_code )
// and then back but always using the lower register
Display *dpy = (Display *)wxGetDisplay();
KeyCode keycode = XKeysymToKeycode(dpy, keysym);
+
+ wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
+
KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
// use the normalized, i.e. lower register, keysym if we've
}
}
- wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %d => keycode = %ld"),
- event.GetEventType() == wxEVT_KEY_UP ? _T("release")
- : _T("press"),
- gdk_event->keyval, key_code);
+ wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
// sending unknown key events doesn't really make sense
if ( !key_code )
if (g_blockEventsOnDrag)
return FALSE;
+
wxKeyEvent event( wxEVT_KEY_DOWN );
if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
{
return FALSE;
}
+ // Emit KEY_DOWN event
bool ret = win->GetEventHandler()->ProcessEvent( event );
#if wxUSE_ACCEL
}
#endif // wxUSE_ACCEL
- /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
- will only be sent if it is not in an accelerator table. */
- if ( !ret )
+ // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
+ // will only be sent if it is not in an accelerator table.
+ if (!ret)
{
+ // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
KeySym keysym = gdk_event->keyval;
long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
if ( !key_code )
{
if ( gdk_event->length == 1 )
{
- key_code = gdk_event->string[0];
+ key_code = (unsigned char)gdk_event->string[0];
}
- else if ((keysym & 0xFF) == keysym)
+ else if ( wxIsAsciiKeysym(keysym) )
{
// ASCII key
- key_code = (guint)keysym;
+ key_code = (unsigned char)keysym;
}
}
{
wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
- // reuse the same event object, just change its type and use the
- // translated keycode instead of the raw one
- event.SetEventType(wxEVT_CHAR);
event.m_keyCode = key_code;
+
+ // Implement OnCharHook by checking ancesteror top level windows
+ wxWindow *parent = win;
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+ if (parent)
+ {
+ event.SetEventType( wxEVT_CHAR_HOOK );
+ ret = parent->GetEventHandler()->ProcessEvent( event );
+ }
- ret = win->GetEventHandler()->ProcessEvent( event );
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = win->GetEventHandler()->ProcessEvent( event );
+ }
}
}
- /* win is a control: tab can be propagated up */
+ // 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
{
wxNavigationKeyEvent new_event;
new_event.SetEventObject( win->GetParent() );
- /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
+ // 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 */
+ // CTRL-TAB changes the (parent) window, i.e. switch notebook page
new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
new_event.SetCurrentFocus( win );
ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
}
- /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
+ // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
if ( !ret &&
(gdk_event->keyval == GDK_Escape) )
{
ret = win->GetEventHandler()->ProcessEvent( new_event );
}
- /* Doesn't work. */
-#if 0 // (GTK_MINOR_VERSION > 0)
- /* Pressing F10 will activate the menu bar of the top frame. */
+ // Doesn't work.
+#if 0
+ // Pressing F10 will activate the menu bar of the top frame
if ( (!ret) &&
(gdk_event->keyval == GDK_F10) )
{
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
return TRUE;
}
-
+
return FALSE;
}
// the mouse events
// ============================================================================
-// init wxMouseEvent with the info from gdk_event
-#define InitMouseEvent(win, event, gdk_event) \
- { \
- event.SetTimestamp( gdk_event->time ); \
- 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_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); \
-\
- wxPoint pt = win->GetClientAreaOrigin(); \
- event.m_x = (wxCoord)gdk_event->x - pt.x; \
- event.m_y = (wxCoord)gdk_event->y - pt.y; \
- }
-
// ----------------------------------------------------------------------------
-// mouse event processing helper
+// mouse event processing helpers
// ----------------------------------------------------------------------------
+// init wxMouseEvent with the info from gdk_event
+//
+// NB: this has to be a macro as gdk_event type is different for different
+// events we're used with
+#define InitMouseEvent(/* wxWindowGTK * */ win, \
+ /* wxMouseEvent& */ event, \
+ /* GdkEventXXX * */ gdk_event) \
+{ \
+ event.SetTimestamp( gdk_event->time ); \
+ 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_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); \
+ \
+ wxPoint pt = win->GetClientAreaOrigin(); \
+ event.m_x = (wxCoord)gdk_event->x - pt.x; \
+ event.m_y = (wxCoord)gdk_event->y - pt.y; \
+ \
+ event.SetEventObject( win ); \
+ event.SetId( win->GetId() ); \
+ event.SetTimestamp( gdk_event->time ); \
+} \
+
static void AdjustEventButtonState(wxMouseEvent& event)
{
// GDK reports the old state of the button for a button press event, but
}
}
+// find the window to send the mouse event too
+static
+wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
+{
+ wxCoord xx = x;
+ wxCoord yy = y;
+
+ if (win->m_wxwindow)
+ {
+ GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
+ xx += pizza->xoffset;
+ yy += pizza->yoffset;
+ }
+
+ wxNode *node = win->GetChildren().First();
+ while (node)
+ {
+ wxWindowGTK *child = (wxWindowGTK*)node->Data();
+
+ node = node->Next();
+ if (!child->IsShown())
+ continue;
+
+ if (child->IsTransparentForMouse())
+ {
+ // wxStaticBox is transparent in the box itself
+ int xx1 = child->m_x;
+ int yy1 = child->m_y;
+ int xx2 = child->m_x + child->m_width;
+ int yy2 = child->m_x + child->m_height;
+
+ // left
+ if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
+ // right
+ ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
+ // top
+ ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
+ // bottom
+ ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
+ {
+ win = child;
+ x -= child->m_x;
+ y -= child->m_y;
+ break;
+ }
+
+ }
+ else
+ {
+ if ((child->m_wxwindow == (GtkWidget*) NULL) &&
+ (child->m_x <= xx) &&
+ (child->m_y <= yy) &&
+ (child->m_x+child->m_width >= xx) &&
+ (child->m_y+child->m_height >= yy))
+ {
+ win = child;
+ x -= child->m_x;
+ y -= child->m_y;
+ break;
+ }
+ }
+ }
+
+ return win;
+}
+
//-----------------------------------------------------------------------------
// "button_press_event"
//-----------------------------------------------------------------------------
-static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
+static gint gtk_window_button_press_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
AdjustEventButtonState(event);
- // wxListBox actually get mouse events from the item
-
- if (win->m_isListBox)
- {
- event.m_x += widget->allocation.x;
- event.m_y += widget->allocation.y;
- }
-
- // Some control don't have their own X window and thus cannot get
- // any events.
+ // wxListBox actually get mouse events from the item, so we need to give it
+ // a chance to correct this
+ win->FixUpMouseEvent(widget, event.m_x, event.m_y);
- if (!g_captureWindow)
- {
- wxCoord x = event.m_x;
- wxCoord y = event.m_y;
- if (win->m_wxwindow)
- {
- GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
- x += pizza->xoffset;
- y += pizza->yoffset;
- }
-
- wxNode *node = win->GetChildren().First();
- while (node)
- {
- wxWindowGTK *child = (wxWindowGTK*)node->Data();
-
- node = node->Next();
- if (!child->IsShown())
- continue;
-
- if (child->m_isStaticBox)
- {
- // wxStaticBox is transparent in the box itself
- int xx1 = child->m_x;
- int yy1 = child->m_y;
- int xx2 = child->m_x + child->m_width;
- int yy2 = child->m_x + child->m_height;
-
- // left
- if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
- // right
- ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
- // top
- ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
- // bottom
- ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
-
- }
- else
- {
- if ((child->m_wxwindow == (GtkWidget*) NULL) &&
- (child->m_x <= x) &&
- (child->m_y <= y) &&
- (child->m_x+child->m_width >= x) &&
- (child->m_y+child->m_height >= y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- }
- }
- }
-
- event.SetEventObject( win );
+ // 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.
+ if ( !g_captureWindow )
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
gs_timeLastClick = gdk_event->time;
AdjustEventButtonState(event);
- // wxListBox actually get mouse events from the item
-
- if (win->m_isListBox)
- {
- event.m_x += widget->allocation.x;
- event.m_y += widget->allocation.y;
- }
-
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- if (!g_captureWindow)
- {
- wxCoord x = event.m_x;
- wxCoord y = event.m_y;
- if (win->m_wxwindow)
- {
- GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
- x += pizza->xoffset;
- y += pizza->yoffset;
- }
-
- wxNode *node = win->GetChildren().First();
- while (node)
- {
- wxWindowGTK *child = (wxWindowGTK*)node->Data();
-
- node = node->Next();
- if (!child->IsShown())
- continue;
-
- if (child->m_isStaticBox)
- {
- // wxStaticBox is transparent in the box itself
- int xx1 = child->m_x;
- int yy1 = child->m_y;
- int xx2 = child->m_x + child->m_width;
- int yy2 = child->m_x + child->m_height;
-
- // left
- if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
- // right
- ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
- // top
- ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
- // bottom
- ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
-
- }
- else
- {
- if ((child->m_wxwindow == (GtkWidget*) NULL) &&
- (child->m_x <= x) &&
- (child->m_y <= y) &&
- (child->m_x+child->m_width >= x) &&
- (child->m_y+child->m_height >= y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- }
- }
- }
+ // same wxListBox hack as above
+ win->FixUpMouseEvent(widget, event.m_x, event.m_y);
- event.SetEventObject( win );
+ if ( !g_captureWindow )
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
if (win->GetEventHandler()->ProcessEvent( event ))
{
}
else // no capture
{
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- wxCoord x = event.m_x;
- wxCoord y = event.m_y;
- if (win->m_wxwindow)
- {
- GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
- x += pizza->xoffset;
- y += pizza->yoffset;
- }
-
- wxNode *node = win->GetChildren().First();
- while (node)
- {
- wxWindowGTK *child = (wxWindowGTK*)node->Data();
-
- node = node->Next();
- if (!child->IsShown())
- continue;
-
- if (child->m_isStaticBox)
- {
- // wxStaticBox is transparent in the box itself
- int xx1 = child->m_x;
- int yy1 = child->m_y;
- int xx2 = child->m_x + child->m_width;
- int yy2 = child->m_x + child->m_height;
-
- // left
- if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
- // right
- ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
- // top
- ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
- // bottom
- ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
-
- }
- else
- {
- if ((child->m_wxwindow == (GtkWidget*) NULL) &&
- (child->m_x <= x) &&
- (child->m_y <= y) &&
- (child->m_x+child->m_width >= x) &&
- (child->m_y+child->m_height >= y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- }
- }
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
}
- event.SetEventObject( win );
-
if (win->GetEventHandler()->ProcessEvent( event ))
{
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
// "focus_in_event"
//-----------------------------------------------------------------------------
+// send the wxChildFocusEvent and wxFocusEvent, common code of
+// gtk_window_focus_in_callback() and SetFocus()
+static bool DoSendFocusEvents(wxWindow *win)
+{
+ // Notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it.
+ wxChildFocusEvent eventChildFocus(win);
+ (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
+
+ wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
+ eventFocus.SetEventObject(win);
+
+ return win->GetEventHandler()->ProcessEvent(eventFocus);
+}
+
static gint gtk_window_focus_in_callback( GtkWidget *widget,
GdkEvent *WXUNUSED(event),
wxWindow *win )
g_focusWindowLast =
g_focusWindow = win;
-#if 0
- wxLogDebug( wxT("OnSetFocus from %s\n"), win->GetName().c_str() );
-#endif
-
- // notify the parent keeping track of focus for the kbd navigation
- // purposes that we got it
- wxChildFocusEvent eventFocus(win);
- (void)win->GetEventHandler()->ProcessEvent(eventFocus);
+ wxLogTrace(TRACE_FOCUS,
+ _T("%s: focus in"), win->GetName().c_str());
#ifdef HAVE_XIM
if (win->m_ic)
}
#endif // wxUSE_CARET
+ g_activeFrameLostFocus = FALSE;
+
wxWindowGTK *active = wxGetTopLevelParent(win);
if ( active != g_activeFrame )
{
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;
}
- g_activeFrameLostFocus = FALSE;
-
- wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
+ // does the window itself think that it has the focus?
+ if ( !win->m_hasFocus )
{
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
- return TRUE;
- }
+ // not yet, notify it
+ win->m_hasFocus = TRUE;
+ if ( DoSendFocusEvents(win) )
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
+ return TRUE;
+ }
+ }
return FALSE;
}
if (!win->m_hasVMT) return FALSE;
if (g_blockEventsOnDrag) return FALSE;
-#if 0
- wxLogDebug( wxT("OnKillFocus from %s"), win->GetName().c_str() );
-#endif
+ wxLogTrace( TRACE_FOCUS,
+ _T("%s: focus out"), win->GetName().c_str() );
if ( !g_activeFrameLostFocus && g_activeFrame )
{
// always) and makes using Mahogany quite annoying
#if 0
wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
- wxT("unfocusing window that hasn't gained focus properly") )
+ wxT("unfocusing window that hasn't gained focus properly") );
#endif // 0
g_activeFrameLostFocus = TRUE;
}
#endif // wxUSE_CARET
- wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
+ // don't send the window a kill focus event if it thinks that it doesn't
+ // have focus already
+ if ( win->m_hasFocus )
{
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
- return TRUE;
+ win->m_hasFocus = FALSE;
+
+ 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;
+ }
}
return FALSE;
// "enter_notify_event"
//-----------------------------------------------------------------------------
-static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
+static
+gint gtk_window_enter_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
- wxMouseEvent event( wxEVT_ENTER_WINDOW );
- event.SetTimestamp( gdk_event->time );
- event.SetEventObject( win );
-
int x = 0;
int y = 0;
GdkModifierType state = (GdkModifierType)0;
gdk_window_get_pointer( widget->window, &x, &y, &state );
+ wxMouseEvent event( wxEVT_ENTER_WINDOW );
InitMouseEvent(win, event, gdk_event);
wxPoint pt = win->GetClientAreaOrigin();
event.m_x = x + pt.x;
win->m_oldVerticalPos = adjust->value;
- wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget));
+ GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
int value = (int)(adjust->value+0.5);
float diff = adjust->value - win->m_oldHorizontalPos;
if (fabs(diff) < 0.2) return;
- wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget));
+ GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
win->m_oldHorizontalPos = adjust->value;
return (wxWindow *)g_focusWindow;
}
+//-----------------------------------------------------------------------------
+// "destroy" event
+//-----------------------------------------------------------------------------
+
+// VZ: Robert commented the code using out so it generates warnings: should
+// be either fixed or removed completely
+#if 0
+
+static void gtk_window_destroy_callback( GtkWidget* widget, wxWindow *win )
+{
+ wxWindowDestroyEvent event(win);
+ win->GetEventHandler()->ProcessEvent(event);
+}
+
+#endif // 0
+
//-----------------------------------------------------------------------------
// "realize" from m_widget
//-----------------------------------------------------------------------------
wxapp_install_idle_handler();
if (win->m_delayedBackgroundColour)
- win->SetBackgroundColour( win->GetBackgroundColour() );
+ win->GtkSetBackgroundColour( win->GetBackgroundColour() );
if (win->m_delayedForegroundColour)
- win->SetForegroundColour( win->GetForegroundColour() );
+ win->GtkSetForegroundColour( win->GetForegroundColour() );
wxWindowCreateEvent event( win );
event.SetEventObject( win );
wxWindow *wxGetActiveWindow()
{
- // the cast is necessary when we compile in wxUniversal mode
- return (wxWindow *)g_focusWindow;
+ return wxWindow::FindFocus();
}
//-----------------------------------------------------------------------------
m_insertCallback = (wxInsertChildFunction) NULL;
- m_isStaticBox = FALSE;
- m_isRadioButton = FALSE;
- m_isListBox = FALSE;
- m_isFrame = FALSE;
m_acceptsFocus = FALSE;
+ m_hasFocus = FALSE;
m_clipPaintRegion = FALSE;
if (g_activeFrame == this)
g_activeFrame = NULL;
+ if ( g_delayedFocus == this )
+ g_delayedFocus = NULL;
+
m_isBeingDeleted = TRUE;
m_hasVMT = FALSE;
{
wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
- /* this turns -1 into 20 so that a minimal window is
- visible even although -1,-1 has been given as the
- size of the window. the same trick is used in other
- ports and should make debugging easier */
- m_width = WidthDefault(size.x);
+ // This turns -1 into 30 so that a minimal window is
+ // visible even although -1,-1 has been given as the
+ // size of the window. the same trick is used in other
+ // ports and should make debugging easier.
+ m_width = WidthDefault(size.x) ;
m_height = HeightDefault(size.y);
m_x = (int)pos.x;
m_y = (int)pos.y;
- /* some reasonable defaults */
+ // some reasonable defaults
if (!parent)
{
if (m_x == -1)
gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
+
+ // This keeps crashing on me. RR.
+ //
+ // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
+ // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
}
bool wxWindowGTK::Destroy()
{
if (x != -1) m_x = x + pizza->xoffset;
if (y != -1) m_y = y + pizza->yoffset;
- if (width != -1) m_width = width;
- if (height != -1) m_height = height;
}
else
{
m_x = x + pizza->xoffset;
m_y = y + pizza->yoffset;
- m_width = width;
- m_height = height;
}
+ if (width != -1) m_width = width;
+ if (height != -1) m_height = height;
if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
{
void wxWindowGTK::OnInternalIdle()
{
// Update invalidated regions.
- Update();
+ GtkUpdate();
// Synthetize activate events.
if ( g_sendActivateEvent != -1 )
}
g_activeFrameLostFocus = FALSE;
}
-
+
wxCursor cursor = m_cursor;
if (g_globalCursor.Ok()) cursor = g_globalCursor;
wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
GdkFont *font = fontToUse.GetInternalFont( 1.0 );
- if (x) (*x) = gdk_string_width( font, string.mbc_str() );
+ if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
if (y) (*y) = font->ascent + font->descent;
if (descent) (*descent) = font->descent;
if (externalLeading) (*externalLeading) = 0; // ??
void wxWindowGTK::SetFocus()
{
- wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
-#if 0
- wxPrintf( "SetFocus from " );
- if (GetClassInfo() && GetClassInfo()->GetClassName())
- wxPrintf( GetClassInfo()->GetClassName() );
- wxPrintf( ".\n" );
-#endif
+ if ( m_hasFocus )
+ {
+ // don't do anything if we already have focus
+ return;
+ }
if (m_wxwindow)
{
{
if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
{
- gtk_widget_grab_focus (m_widget);
+ if (!GTK_WIDGET_REALIZED(m_widget))
+ {
+ // we can't set the focus to the widget now so we remember that
+ // it should be focused and will do it later, during the idle
+ // time, as soon as we can
+ wxLogTrace(TRACE_FOCUS,
+ _T("Delaying setting focus to %s(%s)"),
+ GetClassInfo()->GetClassName(), GetLabel().c_str());
+
+ g_delayedFocus = this;
+ }
+ else
+ {
+ wxLogTrace(TRACE_FOCUS,
+ _T("Setting focus to %s(%s)"),
+ GetClassInfo()->GetClassName(), GetLabel().c_str());
+
+ gtk_widget_grab_focus (m_widget);
+ }
}
else if (GTK_IS_CONTAINER(m_widget))
{
}
else
{
- // ?
+ wxLogTrace(TRACE_FOCUS,
+ _T("Can't set focus to %s(%s)"),
+ GetClassInfo()->GetClassName(), GetLabel().c_str());
}
}
}
gdk_window_warp_pointer( window, x, y );
}
+
void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
{
if (!m_widget) return;
if (!m_widget->window) return;
-
+
#ifndef __WXGTK20__
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
if (eraseBackground && m_wxwindow && m_wxwindow->window)
{
if (rect)
}
void wxWindowGTK::Update()
+{
+ GtkUpdate();
+}
+
+void wxWindowGTK::GtkUpdate()
{
#ifdef __WXGTK20__
if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
return;
}
+ // widget to draw on
+ GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
+
+ // Clip to paint region in wxClientDC
m_clipPaintRegion = TRUE;
- // if (!m_clearRegion.IsEmpty()) // always send an erase event
+#ifndef __WXGTK20__
+ if (GetThemeEnabled())
+ {
+ // find ancestor from which to steal background
+ wxWindow *parent = GetParent();
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+ if (!parent)
+ parent = (wxWindow*)this;
+
+ wxRegionIterator upd( m_updateRegion );
+ while (upd)
+ {
+ GdkRectangle rect;
+ rect.x = upd.GetX();
+ rect.y = upd.GetY();
+ rect.width = upd.GetWidth();
+ rect.height = upd.GetHeight();
+
+ gtk_paint_flat_box( parent->m_widget->style,
+ pizza->bin_window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &rect,
+ parent->m_widget,
+ (char *)"base",
+ 0, 0, -1, -1 );
+
+ upd ++;
+ }
+ }
+ else
+#endif
+#ifdef __WXGTK20__
+ if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
+#endif
{
wxWindowDC dc( (wxWindow*)this );
- dc.SetClippingRegion( m_clearRegion );
+ if (m_clearRegion.IsEmpty())
+ dc.SetClippingRegion( m_updateRegion );
+ else
+ dc.SetClippingRegion( m_clearRegion );
wxEraseEvent erase_event( GetId(), &dc );
erase_event.SetEventObject( this );
if (!GetEventHandler()->ProcessEvent(erase_event))
{
+#ifndef __WXGTK20__
if (!g_eraseGC)
{
- g_eraseGC = gdk_gc_new( GTK_PIZZA(m_wxwindow)->bin_window );
+ g_eraseGC = gdk_gc_new( pizza->bin_window );
gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
}
gdk_gc_set_foreground( g_eraseGC, m_backgroundColour.GetColor() );
wxRegionIterator upd( m_clearRegion );
while (upd)
{
- gdk_draw_rectangle( GTK_PIZZA(m_wxwindow)->bin_window, g_eraseGC, 1,
- upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
+ gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
+ upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
upd ++;
}
+#endif
}
m_clearRegion.Clear();
}
// being redrawn because the wxWindows class is allowed to
// paint over the window-less widgets.
- GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
-
GList *children = pizza->children;
while (children)
{
GtkPizzaChild *child = (GtkPizzaChild*) children->data;
children = children->next;
-
+
if (GTK_WIDGET_NO_WINDOW (child->widget) &&
GTK_WIDGET_DRAWABLE (child->widget))
{
{
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
- if (!m_widget->window) return;
-
if (m_wxwindow && m_wxwindow->window)
{
- gdk_window_clear( m_wxwindow->window );
+ m_clearRegion.Clear();
+ wxSize size( GetClientSize() );
+ m_clearRegion.Union( 0,0,size.x,size.y );
+
+ // Better do this in idle?
+ GtkUpdate();
}
}
}
#endif // wxUSE_TOOLTIPS
+void wxWindowGTK::GtkSetBackgroundColour( const wxColour &colour )
+{
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
+
+ wxASSERT( window );
+
+ // We need the pixel value e.g. for background clearing.
+ m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
+
+ if (m_wxwindow)
+ {
+ // wxMSW doesn't clear the window here, either.
+ gdk_window_set_background( window, m_backgroundColour.GetColor() );
+ }
+
+ ApplyWidgetStyle();
+}
+
bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
{
wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
if (!wxWindowBase::SetBackgroundColour(colour))
- {
- // don't leave if the GTK widget has just
- // been realized
- if (!m_delayedBackgroundColour) return FALSE;
- }
+ return FALSE;
GdkWindow *window = (GdkWindow*) NULL;
if (m_wxwindow)
// but it couldn't get applied as the
// widget hasn't been realized yet.
m_delayedBackgroundColour = TRUE;
+ return TRUE;
}
-
- if (window)
+ else
{
- // We need the pixel value e.g. for background clearing.
- m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
+ GtkSetBackgroundColour( colour );
}
-
- if ((m_wxwindow) &&
- (m_wxwindow->window) &&
- (m_backgroundColour != wxSystemSettings::GetColour(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. */
- gdk_window_set_background( window, m_backgroundColour.GetColor() );
- }
+ return TRUE;
+}
- ApplyWidgetStyle();
+void wxWindowGTK::GtkSetForegroundColour( const wxColour &colour )
+{
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
- return TRUE;
+ wxASSERT( window );
+
+ ApplyWidgetStyle();
}
bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
// widget hasn't been realized yet.
m_delayedForegroundColour = TRUE;
}
-
- ApplyWidgetStyle();
+ else
+ {
+ GtkSetForegroundColour( colour );
+ }
return TRUE;
}
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
-
+
// No scrolling requested.
if ((dx == 0) && (dy == 0)) return;
GetClientSize( &cw, &ch );
m_clearRegion.Intersect( 0, 0, cw, ch );
}
-
m_clipPaintRegion = TRUE;
gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
gdk_gc_unref( g_eraseGC );
}
+// vi:sts=4:sw=4:et