#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
+#if !GTK_CHECK_VERSION(2,10,0)
+ // GTK+ can reliably detect Meta key state only since 2.10 when
+ // GDK_META_MASK was introduced -- there wasn't any way to detect it
+ // in older versions. wxGTK used GDK_MOD2_MASK for this purpose, but
+ // GDK_MOD2_MASK is documented as:
+ //
+ // the fifth modifier key (it depends on the modifier mapping of the X
+ // server which key is interpreted as this modifier)
+ //
+ // In other words, it isn't guaranteed to map to Meta. This is a real
+ // problem: it is common to map NumLock to it (in fact, it's an exception
+ // if the X server _doesn't_ use it for NumLock). So the old code caused
+ // wxKeyEvent::MetaDown() to always return true as long as NumLock was on
+ // on many systems, which broke all applications using
+ // wxKeyEvent::GetModifiers() to check modifiers state (see e.g. here:
+ // http://tinyurl.com/56lsk2).
+ //
+ // Because of this, it's better to not detect Meta key state at all than
+ // to detect it incorrectly. Hence the following #define, which causes
+ // m_metaDown to be always set to false.
+ #define GDK_META_MASK 0
+#endif
+
//-----------------------------------------------------------------------------
// documentation on internals
//-----------------------------------------------------------------------------
// mouse capture state: the window which has it and if the mouse is currently
// inside it
-static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
+static wxWindowGTK *g_captureWindow = NULL;
static bool g_captureWindowHasMouse = false;
-// The window that currently has focus or is scheduled to get it in the next
-// event loop iteration
-static wxWindowGTK *gs_focusWindow = NULL;
+// The window that currently has focus:
+static wxWindowGTK *gs_currentFocus = NULL;
+// The window that is scheduled to get focus in the next event loop iteration
+// or NULL if there's no pending focus change:
+static wxWindowGTK *gs_pendingFocus = NULL;
// the window that has deferred focus-out event pending, if any (see
// GTKAddDeferredFocusOut() for details)
// global variables because GTK+ DnD want to have the
// mouse event that caused it
-GdkEvent *g_lastMouseEvent = (GdkEvent*) NULL;
+GdkEvent *g_lastMouseEvent = NULL;
int g_lastButtonNumber = 0;
//-----------------------------------------------------------------------------
// "size_request" of m_widget
//-----------------------------------------------------------------------------
-// make it extern because wxStaticText needs to disconnect this one
extern "C" {
-void wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
- GtkRequisition *requisition,
- wxWindow * win)
+static void
+wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
+ GtkRequisition *requisition,
+ wxWindow * win)
{
int w, h;
win->GetSize( &w, &h );
extern "C" {
static gboolean
-gtk_window_expose_callback( GtkWidget*,
+gtk_window_expose_callback( GtkWidget* widget,
GdkEventExpose *gdk_event,
wxWindow *win )
{
-#if 0
- if (win->GetName())
+ if (gdk_event->window == widget->window)
{
- wxPrintf( wxT("OnExpose from ") );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- wxPrintf( win->GetClassInfo()->GetClassName() );
- wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
- (int)gdk_event->area.y,
- (int)gdk_event->area.width,
- (int)gdk_event->area.height );
+ win->GetUpdateRegion() = wxRegion( gdk_event->region );
+ win->GtkSendPaintEvents();
}
-
- gtk_paint_box
- (
- win->m_wxwindow->style,
- pizza->bin_window,
- GTK_STATE_NORMAL,
- GTK_SHADOW_OUT,
- (GdkRectangle*) NULL,
- win->m_wxwindow,
- (char *)"button", // const_cast
- 20,20,24,24
- );
-#endif
-
- win->GetUpdateRegion() = wxRegion( gdk_event->region );
-
- win->GtkSendPaintEvents();
-
// Let parent window draw window-less widgets
return FALSE;
}
}
+#ifndef __WXUNIVERSAL__
//-----------------------------------------------------------------------------
-// "expose_event" from m_widget, for drawing border
+// "expose_event" from m_wxwindow->parent, for drawing border
//-----------------------------------------------------------------------------
-#ifndef __WXUNIVERSAL__
-
-GtkWidget* GetEntryWidget();
-
extern "C" {
static gboolean
expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
{
- // if this event is not for the GdkWindow the border is drawn on
- if (win->m_wxwindow == win->m_widget && gdk_event->window == widget->window)
+ if (gdk_event->window != widget->window)
+ return false;
+
+ const GtkAllocation& alloc = win->m_wxwindow->allocation;
+ const int x = alloc.x;
+ const int y = alloc.y;
+ const int w = alloc.width;
+ const int h = alloc.height;
+
+ if (w <= 0 || h <= 0)
return false;
- int x = 0;
- int y = 0;
- // GtkScrolledWindow is GTK_NO_WINDOW
- if (GTK_WIDGET_NO_WINDOW(widget))
- {
- x = widget->allocation.x;
- y = widget->allocation.y;
- }
- int w = win->m_wxwindow->allocation.width;
- int h = win->m_wxwindow->allocation.height;
if (win->HasFlag(wxBORDER_SIMPLE))
{
- GdkGC* gc = gdk_gc_new(gdk_event->window);
- gdk_gc_set_foreground(gc, &widget->style->black);
- gdk_draw_rectangle(gdk_event->window, gc, false, x, y, w - 1, h - 1);
- g_object_unref(gc);
+ gdk_draw_rectangle(gdk_event->window,
+ widget->style->black_gc, false, x, y, w - 1, h - 1);
}
else
{
// Style detail to use
const char* detail;
- if (widget == win->m_wxwindow)
+ if (win->m_widget == win->m_wxwindow)
// for non-scrollable wxWindows
detail = "entry";
else
// for scrollable ones
detail = "viewport";
- GtkWidget* styleWidget = GetEntryWidget();
gtk_paint_shadow(
- styleWidget->style, gdk_event->window, GTK_STATE_NORMAL,
- shadow, NULL, styleWidget, detail, x, y, w, h);
+ win->m_wxwindow->style, gdk_event->window, GTK_STATE_NORMAL,
+ shadow, NULL, wxGTKPrivate::GetEntryWidget(), detail, x, y, w, h);
}
+ return false;
+}
+}
+
+//-----------------------------------------------------------------------------
+// "parent_set" from m_wxwindow
+//-----------------------------------------------------------------------------
- // no further painting is needed for border-only GdkWindow
- return win->m_wxwindow == win->m_widget;
+extern "C" {
+static void
+parent_set(GtkWidget* widget, GtkObject* old_parent, wxWindow* win)
+{
+ if (old_parent)
+ {
+ g_signal_handlers_disconnect_by_func(
+ old_parent, (void*)expose_event_border, win);
+ }
+ if (widget->parent)
+ {
+ g_signal_connect_after(widget->parent, "expose_event",
+ G_CALLBACK(expose_event_border), win);
+ }
}
}
#endif // !__WXUNIVERSAL__
case GDK_KP_7:
case GDK_KP_8:
case GDK_KP_9:
- key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
+ key_code = (isChar ? '0' : int(WXK_NUMPAD0)) + keysym - GDK_KP_0;
break;
case GDK_KP_Space:
- key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
+ key_code = isChar ? ' ' : int(WXK_NUMPAD_SPACE);
break;
case GDK_KP_Tab:
break;
case GDK_KP_Equal:
- key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
+ key_code = isChar ? '=' : int(WXK_NUMPAD_EQUAL);
break;
case GDK_KP_Multiply:
- key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
+ key_code = isChar ? '*' : int(WXK_NUMPAD_MULTIPLY);
break;
case GDK_KP_Add:
- key_code = isChar ? '+' : WXK_NUMPAD_ADD;
+ key_code = isChar ? '+' : int(WXK_NUMPAD_ADD);
break;
case GDK_KP_Separator:
// FIXME: what is this?
- key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
+ key_code = isChar ? '.' : int(WXK_NUMPAD_SEPARATOR);
break;
case GDK_KP_Subtract:
- key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
+ key_code = isChar ? '-' : int(WXK_NUMPAD_SUBTRACT);
break;
case GDK_KP_Decimal:
- key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
+ key_code = isChar ? '.' : int(WXK_NUMPAD_DECIMAL);
break;
case GDK_KP_Divide:
- key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
+ key_code = isChar ? '/' : int(WXK_NUMPAD_DIVIDE);
break;
event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
- event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
+ event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0;
event.m_scanCode = gdk_event->keyval;
event.m_rawCode = (wxUint32) gdk_event->keyval;
event.m_rawFlags = 0;
extern "C" {
static gboolean
-gtk_window_key_press_callback( GtkWidget *widget,
+gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
GdkEventKey *gdk_event,
wxWindow *win )
{
if (g_blockEventsOnDrag)
return FALSE;
- // GTK+ sends keypress events to the focus widget and then
- // to all its parent and grandparent widget. We only want
- // the key events from the focus widget.
- if (!GTK_WIDGET_HAS_FOCUS(widget))
- return FALSE;
-
wxKeyEvent event( wxEVT_KEY_DOWN );
bool ret = false;
bool return_after_IM = false;
int command = ancestor->GetAcceleratorTable()->GetCommand( event );
if (command != -1)
{
- wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
- ret = ancestor->HandleWindowEvent( command_event );
+ wxCommandEvent menu_event( wxEVT_COMMAND_MENU_SELECTED, command );
+ ret = ancestor->HandleWindowEvent( menu_event );
+
+ if ( !ret )
+ {
+ // if the accelerator wasn't handled as menu event, try
+ // it as button click (for compatibility with other
+ // platforms):
+ wxCommandEvent button_event( wxEVT_COMMAND_BUTTON_CLICKED, command );
+ ret = ancestor->HandleWindowEvent( button_event );
+ }
+
break;
}
if (ancestor->IsTopLevel())
event.m_shiftDown = gdk_event->state & GDK_SHIFT_MASK;
event.m_controlDown = gdk_event->state & GDK_CONTROL_MASK;
event.m_altDown = gdk_event->state & GDK_MOD1_MASK;
- event.m_metaDown = gdk_event->state & GDK_MOD2_MASK;
+ event.m_metaDown = gdk_event->state & GDK_META_MASK;
event.m_leftDown = gdk_event->state & GDK_BUTTON1_MASK;
event.m_middleDown = gdk_event->state & GDK_BUTTON2_MASK;
event.m_rightDown = gdk_event->state & GDK_BUTTON3_MASK;
}
else
{
- if ((child->m_wxwindow == (GtkWidget*) NULL) &&
+ if ((child->m_wxwindow == NULL) &&
(child->m_x <= xx) &&
(child->m_y <= yy) &&
(child->m_x+child->m_width >= xx) &&
return TRUE;
if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
- (gs_focusWindow != win) /* && win->IsFocusable() */)
+ (gs_currentFocus != win) /* && win->IsFocusable() */)
{
win->SetFocus();
}
// "scroll_event" (mouse wheel event)
//-----------------------------------------------------------------------------
+static gboolean
+window_scroll_event_hscrollbar(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
+{
+ if (gdk_event->direction != GDK_SCROLL_LEFT &&
+ gdk_event->direction != GDK_SCROLL_RIGHT)
+ {
+ return false;
+ }
+
+ wxMouseEvent event(wxEVT_MOUSEWHEEL);
+ InitMouseEvent(win, event, gdk_event);
+
+ GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Horz];
+ if (!range) return FALSE;
+
+ if (range && GTK_WIDGET_VISIBLE (range))
+ {
+ GtkAdjustment *adj = range->adjustment;
+ gdouble delta = adj->step_increment * 3;
+ if (gdk_event->direction == GDK_SCROLL_LEFT)
+ delta = -delta;
+
+ gdouble new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
+
+ gtk_adjustment_set_value (adj, new_value);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static gboolean
window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
{
else
event.m_wheelRotation = -120;
- return win->GTKProcessEvent(event);
+ if (win->GTKProcessEvent(event))
+ return TRUE;
+
+ GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Vert];
+ if (!range) return FALSE;
+
+ if (range && GTK_WIDGET_VISIBLE (range))
+ {
+ GtkAdjustment *adj = range->adjustment;
+ gdouble delta = adj->step_increment * 3;
+ if (gdk_event->direction == GDK_SCROLL_UP)
+ delta = -delta;
+
+ gdouble new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
+
+ gtk_adjustment_set_value (adj, new_value);
+
+ return TRUE;
+ }
+
+ return FALSE;
}
//-----------------------------------------------------------------------------
wxWindow *wxWindowBase::DoFindFocus()
{
+ wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus;
// the cast is necessary when we compile in wxUniversal mode
- return wx_static_cast(wxWindow*, gs_focusWindow);
+ return static_cast<wxWindow*>(focus);
}
-//-----------------------------------------------------------------------------
-// InsertChild for wxWindowGTK.
-//-----------------------------------------------------------------------------
-
-/* Callback for wxWindowGTK. This very strange beast has to be used because
- * C++ has no virtual methods in a constructor. We have to emulate a
- * virtual function here as wxNotebook requires a different way to insert
- * a child in it. I had opted for creating a wxNotebookPage window class
- * which would have made this superfluous (such in the MDI window system),
- * but no-one was listening to me... */
-
-static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
+void wxWindowGTK::AddChildGTK(wxWindowGTK* child)
{
/* the window might have been scrolled already, do we
have to adapt the position */
- wxPizza* pizza = WX_PIZZA(parent->m_wxwindow);
+ wxPizza* pizza = WX_PIZZA(m_wxwindow);
child->m_x += pizza->m_scroll_x;
child->m_y += pizza->m_scroll_y;
gtk_widget_set_size_request(
child->m_widget, child->m_width, child->m_height);
gtk_fixed_put(
- GTK_FIXED(parent->m_wxwindow), child->m_widget, child->m_x, child->m_y);
+ GTK_FIXED(m_wxwindow), child->m_widget, child->m_x, child->m_y);
}
//-----------------------------------------------------------------------------
ms.SetControlDown(mask & GDK_CONTROL_MASK);
ms.SetShiftDown(mask & GDK_SHIFT_MASK);
ms.SetAltDown(mask & GDK_MOD1_MASK);
- ms.SetMetaDown(mask & GDK_MOD2_MASK);
+ ms.SetMetaDown(mask & GDK_META_MASK);
return ms;
}
void wxWindowGTK::Init()
{
// GTK specific
- m_widget = (GtkWidget *) NULL;
- m_wxwindow = (GtkWidget *) NULL;
- m_focusWidget = (GtkWidget *) NULL;
+ m_widget = NULL;
+ m_wxwindow = NULL;
+ m_focusWidget = NULL;
// position/size
m_x = 0;
m_height = 0;
m_hasVMT = false;
- m_isBeingDeleted = false;
- m_showOnIdle= false;
+ m_showOnIdle = false;
m_noExpose = false;
m_nativeSizeEvent = false;
m_oldClientWidth =
m_oldClientHeight = 0;
- m_insertCallback = wxInsertChildInWindow;
-
m_clipPaintRegion = false;
m_needsStyleChange = false;
{
// Get default border
wxBorder border = GetBorder(style);
+
style &= ~wxBORDER_MASK;
style |= border;
return false;
}
+ // We should accept the native look
+#if 0
+ GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
+ scroll_class->scrollbar_spacing = 0;
+#endif
+
- m_wxwindow = wxPizza::New(m_windowStyle);
+ m_wxwindow = wxPizza::New(m_windowStyle,this);
+#ifndef __WXUNIVERSAL__
+ if (HasFlag(wxPizza::BORDER_STYLES))
+ {
+ g_signal_connect(m_wxwindow, "parent_set",
+ G_CALLBACK(parent_set), this);
+ }
+#endif
if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
m_widget = m_wxwindow;
else
{
- m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
+ m_widget = gtk_scrolled_window_new( NULL, NULL );
GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
- GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
- scroll_class->scrollbar_spacing = 0;
-
// There is a conflict with default bindings at GTK+
// level between scrolled windows and notebooks both of which want to use
// Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
gtk_widget_show( m_wxwindow );
}
+ g_object_ref(m_widget);
if (m_parent)
m_parent->DoAddChild( this );
m_focusWidget = m_wxwindow;
+ SetCanFocus(AcceptsFocus());
+
PostCreation();
return true;
{
SendDestroyEvent();
- if (gs_focusWindow == this)
- gs_focusWindow = NULL;
+ if (gs_currentFocus == this)
+ gs_currentFocus = NULL;
+ if (gs_pendingFocus == this)
+ gs_pendingFocus = NULL;
if ( gs_deferredFocusOut == this )
gs_deferredFocusOut = NULL;
- m_isBeingDeleted = true;
m_hasVMT = false;
// destroy children before destroying this window itself
// delete before the widgets to avoid a crash on solaris
delete m_imData;
- if (m_wxwindow && (m_wxwindow != m_widget))
- {
- gtk_widget_destroy( m_wxwindow );
- m_wxwindow = (GtkWidget*) NULL;
- }
-
if (m_widget)
{
- gtk_widget_destroy( m_widget );
- m_widget = (GtkWidget*) NULL;
+ // Note that gtk_widget_destroy() does not destroy the widget, it just
+ // emits the "destroy" signal. The widget is not actually destroyed
+ // until its reference count drops to zero.
+ gtk_widget_destroy(m_widget);
+ // Release our reference, should be the last one
+ g_object_unref(m_widget);
+ m_widget = NULL;
}
+ m_wxwindow = NULL;
}
bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
g_signal_connect (m_imData->context, "commit",
G_CALLBACK (gtk_wxwindow_commit_cb), this);
-
- // border drawing
-#ifndef __WXUNIVERSAL__
- if (HasFlag(wxPizza::BORDER_STYLES))
- {
- g_signal_connect(m_widget, "expose_event",
- G_CALLBACK(expose_event_border), this);
- }
-#endif
}
// focus handling
G_CALLBACK (gtk_window_button_release_callback), this);
g_signal_connect (widget, "motion_notify_event",
G_CALLBACK (gtk_window_motion_notify_callback), this);
+
g_signal_connect (widget, "scroll_event",
G_CALLBACK (window_scroll_event), this);
+ if (m_scrollBar[ScrollDir_Horz])
+ g_signal_connect (m_scrollBar[ScrollDir_Horz], "scroll_event",
+ G_CALLBACK (window_scroll_event_hscrollbar), this);
+ if (m_scrollBar[ScrollDir_Vert])
+ g_signal_connect (m_scrollBar[ScrollDir_Vert], "scroll_event",
+ G_CALLBACK (window_scroll_event), this);
+
g_signal_connect (widget, "popup_menu",
G_CALLBACK (wxgtk_window_popup_menu_callback), this);
g_signal_connect (widget, "enter_notify_event",
if (height != -1)
m_height = height;
- ConstrainSize();
-
if (m_parent->m_wxwindow)
{
wxPizza* pizza = WX_PIZZA(m_parent->m_wxwindow);
event.SetEventObject( this );
HandleWindowEvent( event );
}
+ } else
+ if (sizeFlags & wxSIZE_FORCE_EVENT)
+ {
+ wxSizeEvent event( wxSize(m_width,m_height), GetId() );
+ event.SetEventObject( this );
+ HandleWindowEvent( event );
}
}
int w = m_width;
int h = m_height;
- if (m_wxwindow)
+ if ( m_wxwindow )
{
// if window is scrollable, account for scrollbars
- for (int i = 0; i < 2 && m_scrollBar[i]; i++)
+ if ( GTK_IS_SCROLLED_WINDOW(m_widget) )
{
- GtkRequisition req;
- GtkAdjustment* adj = gtk_range_get_adjustment(m_scrollBar[i]);
- // if scrollbar enabled
- if (adj->upper > adj->page_size)
+ GtkPolicyType policy[ScrollDir_Max];
+ gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(m_widget),
+ &policy[ScrollDir_Horz],
+ &policy[ScrollDir_Vert]);
+
+ for ( int i = 0; i < ScrollDir_Max; i++ )
{
- gtk_widget_size_request(GTK_WIDGET(m_scrollBar[i]), &req);
+ // don't account for the scrollbars we don't have
+ GtkRange * const range = m_scrollBar[i];
+ if ( !range )
+ continue;
+
+ // nor for the ones we have but don't current show
+ switch ( policy[i] )
+ {
+ case GTK_POLICY_NEVER:
+ // never shown so doesn't take any place
+ continue;
+
+ case GTK_POLICY_ALWAYS:
+ // no checks necessary
+ break;
+
+ case GTK_POLICY_AUTOMATIC:
+ // may be shown or not, check
+ GtkAdjustment *adj = gtk_range_get_adjustment(range);
+ if ( adj->upper <= adj->page_size )
+ continue;
+ }
+
+ GtkScrolledWindowClass *scroll_class =
+ GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
+
+ GtkRequisition req;
+ gtk_widget_size_request(GTK_WIDGET(range), &req);
if (i == ScrollDir_Horz)
- h -= req.height;
+ h -= req.height + scroll_class->scrollbar_spacing;
else
- w -= req.width;
+ w -= req.width + scroll_class->scrollbar_spacing;
}
}
if (m_x == -1 && m_y == -1)
{
- GdkWindow *source = (GdkWindow *) NULL;
+ GdkWindow *source = NULL;
if (m_wxwindow)
source = m_wxwindow->window;
else
if (m_parent)
m_parent->ScreenToClient(&org_x, &org_y);
- wx_const_cast(wxWindowGTK*, this)->m_x = org_x;
- wx_const_cast(wxWindowGTK*, this)->m_y = org_y;
+ const_cast<wxWindowGTK*>(this)->m_x = org_x;
+ const_cast<wxWindowGTK*>(this)->m_y = org_y;
}
}
if (!m_widget->window) return;
- GdkWindow *source = (GdkWindow *) NULL;
+ GdkWindow *source = NULL;
if (m_wxwindow)
source = m_wxwindow->window;
else
if (!m_widget->window) return;
- GdkWindow *source = (GdkWindow *) NULL;
+ GdkWindow *source = NULL;
if (m_wxwindow)
source = m_wxwindow->window;
else
g_object_unref (layout);
}
+void wxWindowGTK::GTKDisableFocusOutEvent()
+{
+ g_signal_handlers_block_by_func( m_focusWidget,
+ (gpointer) gtk_window_focus_out_callback, this);
+}
+
+void wxWindowGTK::GTKEnableFocusOutEvent()
+{
+ g_signal_handlers_unblock_by_func( m_focusWidget,
+ (gpointer) gtk_window_focus_out_callback, this);
+}
bool wxWindowGTK::GTKHandleFocusIn()
{
if (m_imData)
gtk_im_context_focus_in(m_imData->context);
- // NB: SetFocus() does this assignment too, but not all focus changes
- // originate from SetFocus() call
- gs_focusWindow = this;
+ gs_currentFocus = this;
+ gs_pendingFocus = NULL;
#if wxUSE_CARET
// caret needs to be informed about focus change
// Notify the parent keeping track of focus for the kbd navigation
// purposes that we got it.
- wxChildFocusEvent eventChildFocus(this);
+ wxChildFocusEvent eventChildFocus(static_cast<wxWindow*>(this));
GTKProcessEvent(eventChildFocus);
wxFocusEvent eventFocus(wxEVT_SET_FOCUS, GetId());
if (m_imData)
gtk_im_context_focus_out(m_imData->context);
- if ( gs_focusWindow != this )
+ if ( gs_currentFocus != this )
{
- // Something is terribly wrong, gs_focusWindow is out of sync with the
+ // Something is terribly wrong, gs_currentFocus is out of sync with the
// real focus. We will reset it to NULL anyway, because after this
// focus-out event is handled, one of the following with happen:
//
// * either focus will go out of the app altogether, in which case
- // gs_focusWindow _should_ be NULL
+ // gs_currentFocus _should_ be NULL
//
// * or it goes to another control, in which case focus-in event will
- // follow immediately and it will set gs_focusWindow to the right
+ // follow immediately and it will set gs_currentFocus to the right
// value
wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
GetClassInfo()->GetClassName(), this, GetLabel());
}
- gs_focusWindow = NULL;
+ gs_currentFocus = NULL;
#if wxUSE_CARET
// caret needs to be informed about focus change
// Because we want to FindFocus() call immediately following
// foo->SetFocus() to return foo, we have to keep track of "pending" focus
// ourselves.
- gs_focusWindow = this;
+ gs_pendingFocus = this;
GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
wxASSERT( GTK_IS_WIDGET(m_widget) );
- /* prevent GTK from deleting the widget arbitrarily */
- gtk_widget_ref( m_widget );
-
if (oldParent)
- {
gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
- }
wxASSERT( GTK_IS_WIDGET(m_widget) );
m_showOnIdle = true;
gtk_widget_hide( m_widget );
}
-
/* insert GTK representation */
- (*(newParent->m_insertCallback))(newParent, this);
+ newParent->AddChildGTK(this);
}
- /* reverse: prevent GTK from deleting the widget arbitrarily */
- gtk_widget_unref( m_widget );
-
SetLayoutDirection(wxLayout_Default);
return true;
AddChild( child );
/* insert GTK representation */
- (*m_insertCallback)(this, child);
+ AddChildGTK(child);
}
void wxWindowGTK::AddChild(wxWindowBase *child)
// We provide this function ourselves as it is
// missing in GDK (top of this file).
- GdkWindow *window = (GdkWindow*) NULL;
+ GdkWindow *window = NULL;
if (m_wxwindow)
window = m_wxwindow->window;
else
else
{
wxWindowDC dc( (wxWindow*)this );
- dc.SetClippingRegion( m_updateRegion );
+ dc.SetDeviceClippingRegion( m_updateRegion );
// Work around gtk-qt <= 0.60 bug whereby the window colour
// remains grey
#if wxUSE_MENUS_NATIVE
-extern "C" WXDLLIMPEXP_CORE
-void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
-{
- *is_waiting = false;
-}
-
-WXDLLIMPEXP_CORE void SetInvokingWindow( wxMenu *menu, wxWindow* win )
+static void SetInvokingWindow( wxMenu *menu, wxWindow* win )
{
menu->SetInvokingWindow( win );
}
}
-extern "C" WXDLLIMPEXP_CORE
+extern "C" {
+static
void wxPopupMenuPositionCallback( GtkMenu *menu,
gint *x, gint *y,
gboolean * WXUNUSED(whatever),
*x = pos->x < xmax ? pos->x : xmax;
*y = pos->y < ymax ? pos->y : ymax;
}
+}
+
+void wxWindowGTK::DoPopupMenuUpdateUI(wxMenu* menu)
+{
+ menu->UpdateUI();
+}
bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
{
wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
- // NOTE: if you change this code, you need to update
- // the same code in taskbar.cpp as well. This
- // is ugly code duplication, I know.
-
SetInvokingWindow( menu, this );
- menu->UpdateUI();
+ DoPopupMenuUpdateUI(menu);
wxPoint pos;
gpointer userdata;
menu->m_popupShown = true;
gtk_menu_popup(
GTK_MENU(menu->m_menu),
- (GtkWidget *) NULL, // parent menu shell
- (GtkWidget *) NULL, // parent menu item
+ NULL, // parent menu shell
+ NULL, // parent menu item
posfunc, // function to position it
userdata, // client data
0, // button used to activate it
GtkWidget *dnd_widget = GetConnectWidget();
- if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
+ if (m_dropTarget) m_dropTarget->GtkUnregisterWidget( dnd_widget );
if (m_dropTarget) delete m_dropTarget;
m_dropTarget = dropTarget;
- if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
+ if (m_dropTarget) m_dropTarget->GtkRegisterWidget( dnd_widget );
}
#endif // wxUSE_DRAG_AND_DROP
{
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
- GdkWindow *window = (GdkWindow*) NULL;
+ GdkWindow *window = NULL;
if (m_wxwindow)
window = m_wxwindow->window;
else
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_HINT_MASK |
GDK_POINTER_MOTION_MASK),
- (GdkWindow *) NULL,
+ NULL,
cursor->GetCursor(),
(guint32)GDK_CURRENT_TIME );
g_captureWindow = this;
wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
- g_captureWindow = (wxWindowGTK*) NULL;
+ g_captureWindow = NULL;
- GdkWindow *window = (GdkWindow*) NULL;
+ GdkWindow *window = NULL;
if (m_wxwindow)
window = m_wxwindow->window;
else
// freeze/thaw
// ----------------------------------------------------------------------------
+extern "C"
+{
+
+// this is called if we attempted to freeze unrealized widget when it finally
+// is realized (and so can be frozen):
+static void wx_frozen_widget_realize(GtkWidget* w, void* WXUNUSED(data))
+{
+ wxASSERT( w && !GTK_WIDGET_NO_WINDOW(w) );
+ wxASSERT( GTK_WIDGET_REALIZED(w) );
+
+ g_signal_handlers_disconnect_by_func
+ (
+ w,
+ (void*)wx_frozen_widget_realize,
+ NULL
+ );
+
+ gdk_window_freeze_updates(w->window);
+}
+
+} // extern "C"
+
void wxWindowGTK::GTKFreezeWidget(GtkWidget *w)
{
- if ( w && !GTK_WIDGET_NO_WINDOW(w) )
- gdk_window_freeze_updates(w->window);
+ if ( !w || GTK_WIDGET_NO_WINDOW(w) )
+ return; // window-less widget, cannot be frozen
+
+ if ( !GTK_WIDGET_REALIZED(w) )
+ {
+ // we can't thaw unrealized widgets because they don't have GdkWindow,
+ // so set it up to be done immediately after realization:
+ g_signal_connect_after
+ (
+ w,
+ "realize",
+ G_CALLBACK(wx_frozen_widget_realize),
+ NULL
+ );
+ return;
+ }
+
+ gdk_window_freeze_updates(w->window);
}
void wxWindowGTK::GTKThawWidget(GtkWidget *w)
{
- if ( w && !GTK_WIDGET_NO_WINDOW(w) )
- gdk_window_thaw_updates(w->window);
+ if ( !w || GTK_WIDGET_NO_WINDOW(w) )
+ return; // window-less widget, cannot be frozen
+
+ if ( !GTK_WIDGET_REALIZED(w) )
+ {
+ // the widget wasn't realized yet, no need to thaw
+ g_signal_handlers_disconnect_by_func
+ (
+ w,
+ (void*)wx_frozen_widget_realize,
+ NULL
+ );
+ return;
+ }
+
+ gdk_window_thaw_updates(w->window);
}
void wxWindowGTK::DoFreeze()