/////////////////////////////////////////////////////////////////////////////
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "window.h"
#endif
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
#ifdef __VMS
#define XWarpPointer XWARPPOINTER
#endif
-#include "wx/defs.h"
#include "wx/window.h"
#include "wx/dcclient.h"
#include "wx/frame.h"
#include "wx/intl.h"
#include "wx/settings.h"
#include "wx/log.h"
+#include "wx/fontutil.h"
#ifdef __WXDEBUG__
#include "wx/thread.h"
#endif
#include <math.h>
+#include <ctype.h>
#include "wx/gtk/private.h"
#include <gdk/gdkprivate.h>
#include "wx/gtk/win_gtk.h"
+#ifdef __WXGTK20__
+#include <pango/pangox.h>
+#endif
+
#ifdef __WXGTK20__
#define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
#else
// send any activate events at all
static int g_sendActivateEvent = -1;
-/* hack: we need something to pass to gtk_menu_popup, so we store the time of
- the last click here */
-static guint32 gs_timeLastClick = 0;
+// hack: we need something to pass to gtk_menu_popup, so we store the time of
+// the last click here
+static guint32 gs_timeLastClick = 0;
extern bool g_mainThreadLocked;
//-----------------------------------------------------------------------------
#ifndef __WXGTK20__
-#define DISABLE_STYLE_IF_BROKEN_THEME 1
+#define DISABLE_STYLE_IF_BROKEN_THEME 0
#endif
#ifdef __WXDEBUG__
if ( winFocus == win )
return (wxWindow *)win;
- for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
+ for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
node;
node = node->GetNext() )
{
// "size_request" of m_widget
//-----------------------------------------------------------------------------
-static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win )
+// make it extern because wxStatitText needs to disconnect this one
+extern "C"
+void wxgtk_window_size_request_callback(GtkWidget *widget,
+ GtkRequisition *requisition,
+ wxWindow *win)
{
- int w,h;
+ int w, h;
win->GetSize( &w, &h );
- if (w < 2) w = 2;
- if (h < 2) h = 2;
+ if (w < 2)
+ w = 2;
+ if (h < 2)
+ h = 2;
requisition->height = h;
requisition->width = w;
if (g_isIdle)
wxapp_install_idle_handler();
+#ifdef __WXGTK20__
+ // This callback gets called in drawing-idle time under
+ // GTK 2.0, so we don't need to defer anything to idle
+ // time anymore.
+
+ GtkPizza *pizza = GTK_PIZZA( widget );
+ if (gdk_event->window != pizza->bin_window) return FALSE;
+
#if 0
if (win->GetName())
{
(int)gdk_event->area.width,
(int)gdk_event->area.height );
}
+
+ 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
+ (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
+#else
+ // This gets called immediately after an expose event
+ // under GTK 1.2 so we collect the calls and wait for
+ // the idle handler to pick things up.
+
win->GetUpdateRegion().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->GtkUpdate();
-
-#ifdef __WXGTK20__
-
- (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
-
+ // win->GtkUpdate();
#endif
- return TRUE;
+ return FALSE;
}
//-----------------------------------------------------------------------------
if (g_isIdle)
wxapp_install_idle_handler();
- // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
- // there are no child windows.
- if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
- (win->GetChildren().GetCount() == 0))
+ // if there are any children we must refresh everything
+ //
+ // VZ: why?
+ if ( !win->HasFlag(wxFULL_REPAINT_ON_RESIZE) &&
+ win->GetChildren().IsEmpty() )
{
return;
}
(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.
-
+ // Update immediately, not in idle time.
win->GtkUpdate();
#ifndef __WXUNIVERSAL__
KeySym keysym = gdk_event->keyval;
- wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %d"),
+ wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
event.GetEventType() == wxEVT_KEY_UP ? _T("release")
: _T("press"),
keysym);
}
}
- wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %d"), key_code);
+ wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
// sending unknown key events doesn't really make sense
if ( !key_code )
return TRUE;
}
+
static gint gtk_window_key_press_callback( GtkWidget *widget,
GdkEventKey *gdk_event,
wxWindow *win )
// 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
+ long key_code;
KeySym keysym = gdk_event->keyval;
- long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
- if ( !key_code )
+#ifdef __WXGTK20__
+ // In GTK 2.0, we need to hand over the key event to an input method
+ // and the IM will emit a "commit" event containing the actual utf8
+ // character. In that case the EVT_CHAR events will be sent from
+ // there. But only do it this way for non-KeySym keys.
+ key_code = wxTranslateKeySymToWXKey(gdk_event->keyval, FALSE /* isChar */);
+ if ( !key_code && win->m_imContext )
{
- if ( gdk_event->length == 1 )
- {
- key_code = (unsigned char)gdk_event->string[0];
- }
- else if ( wxIsAsciiKeysym(keysym) )
- {
- // ASCII key
- key_code = (unsigned char)keysym;
- }
+ gtk_im_context_filter_keypress ( (GtkIMContext*) win->m_imContext, gdk_event );
+ ret = TRUE;
}
-
- if ( key_code )
+ else
+#endif
{
- wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
-
- 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)
+ // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
+ key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
+ if ( !key_code )
{
- event.SetEventType( wxEVT_CHAR_HOOK );
- ret = parent->GetEventHandler()->ProcessEvent( event );
+ if ( gdk_event->length == 1 )
+ {
+ key_code = (unsigned char)gdk_event->string[0];
+ }
+ else if ( wxIsAsciiKeysym(keysym) )
+ {
+ // ASCII key
+ key_code = (unsigned char)keysym;
+ }
}
- if (!ret)
+ if ( key_code )
{
- event.SetEventType(wxEVT_CHAR);
- ret = win->GetEventHandler()->ProcessEvent( event );
+ wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
+
+ 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 );
+ }
+
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = win->GetEventHandler()->ProcessEvent( event );
+ }
}
}
}
if ( !ret &&
(gdk_event->keyval == GDK_Escape) )
{
- wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
- new_event.SetEventObject( win );
- ret = win->GetEventHandler()->ProcessEvent( new_event );
- }
-
- // Doesn't work.
-#if 0
- // Pressing F10 will activate the menu bar of the top frame
- if ( (!ret) &&
- (gdk_event->keyval == GDK_F10) )
- {
- wxWindowGTK *ancestor = win;
- while (ancestor)
+ // however only do it if we have a Cancel button in the dialog,
+ // otherwise the user code may get confused by the events from a
+ // non-existing button and, worse, a wxButton might get button event
+ // from another button which is not really expected
+ wxWindow *winForCancel = win,
+ *btnCancel = NULL;
+ while ( winForCancel )
{
- if (wxIsKindOf(ancestor,wxFrame))
+ btnCancel = winForCancel->FindWindow(wxID_CANCEL);
+ if ( btnCancel )
{
- wxFrame *frame = (wxFrame*) ancestor;
- wxMenuBar *menubar = frame->GetMenuBar();
- if (menubar)
- {
- wxNode *node = menubar->GetMenus().First();
- if (node)
- {
- wxMenu *firstMenu = (wxMenu*) node->Data();
- gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
- ret = TRUE;
- break;
- }
- }
+ // found a cancel button
+ break;
}
- ancestor = ancestor->GetParent();
+
+ if ( winForCancel->IsTopLevel() )
+ {
+ // no need to look further
+ break;
+ }
+
+ // maybe our parent has a cancel button?
+ winForCancel = winForCancel->GetParent();
+ }
+
+ if ( btnCancel )
+ {
+ wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
+ event.SetEventObject(btnCancel);
+ ret = btnCancel->GetEventHandler()->ProcessEvent(event);
}
}
-#endif // 0
if (ret)
{
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
return TRUE;
}
-
+
return FALSE;
}
+#ifdef __WXGTK20__
+static void gtk_wxwindow_commit_cb (GtkIMContext *context,
+ const gchar *str,
+ wxWindow *window)
+{
+ bool ret = FALSE;
+
+ wxKeyEvent event( wxEVT_KEY_DOWN );
+
+#if wxUSE_UNICODE
+ event.m_uniChar = g_utf8_get_char( str );
+
+ // Backward compatible for ISO-8859
+ if (event.m_uniChar < 256)
+ event.m_keyCode = event.m_uniChar;
+#else
+ gunichar uniChar = g_utf8_get_char( str );
+ // We cannot handle Unicode in non-Unicode mode
+ if (uniChar > 255) return;
+
+ event.m_keyCode = uniChar;
+#endif
+
+
+ // TODO: We still need to set all the extra attributes of the
+ // event, modifiers and such...
+
+
+ // Implement OnCharHook by checking ancestor top level windows
+ wxWindow *parent = window;
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+ if (parent)
+ {
+ event.SetEventType( wxEVT_CHAR_HOOK );
+ ret = parent->GetEventHandler()->ProcessEvent( event );
+ }
+
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = window->GetEventHandler()->ProcessEvent( event );
+ }
+}
+#endif
+
+
//-----------------------------------------------------------------------------
// "key_release_event" from any window
//-----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// 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; \
- }
+//
+// 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); \
+ if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
+ { \
+ if (((GdkEventButton*)gdk_event)->button == 4) \
+ event.m_wheelRotation = 120; \
+ else if (((GdkEventButton*)gdk_event)->button == 5) \
+ event.m_wheelRotation = -120; \
+ } \
+ \
+ 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)
{
yy += pizza->yoffset;
}
- wxNode *node = win->GetChildren().First();
+ wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
while (node)
{
- wxWindowGTK *child = (wxWindowGTK*)node->Data();
+ wxWindowGTK *child = node->GetData();
- node = node->Next();
+ node = node->GetNext();
if (!child->IsShown())
continue;
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;
+ int yy2 = child->m_y + child->m_height;
// left
if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
*/
}
+ // GDK sends surplus button down event
+ // before a double click event. We
+ // need to filter these out.
+ if (gdk_event->type == GDK_BUTTON_PRESS)
+ {
+ GdkEvent *peek_event = gdk_event_peek();
+ if (peek_event)
+ {
+ if ((peek_event->type == GDK_2BUTTON_PRESS) ||
+ (peek_event->type == GDK_3BUTTON_PRESS))
+ {
+ gdk_event_free( peek_event );
+ return TRUE;
+ }
+ else
+ {
+ gdk_event_free( peek_event );
+ }
+ }
+ }
+
wxEventType event_type = wxEVT_NULL;
if (gdk_event->button == 1)
{
case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
+ case GDK_3BUTTON_PRESS: return FALSE;
default: break;
}
}
default: break;
}
}
+ else if (gdk_event->button == 4)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS: event_type = wxEVT_MOUSEWHEEL; break;
+ default: break;
+ }
+ }
+ else if (gdk_event->button == 5)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS: event_type = wxEVT_MOUSEWHEEL; break;
+ default: break;
+ }
+ }
if ( event_type == wxEVT_NULL )
{
if ( !g_captureWindow )
win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
- event.SetEventObject( win );
-
gs_timeLastClick = gdk_event->time;
/*
wxPrintf( wxT(".\n") );
*/
+#ifndef __WXGTK20__
+ if (event_type == wxEVT_LEFT_DCLICK)
+ {
+ // GTK 1.2 crashes when intercepting double
+ // click events from both wxSpinButton and
+ // wxSpinCtrl
+ if (GTK_IS_SPIN_BUTTON(win->m_widget))
+ {
+ // Just disable this event for now.
+ return FALSE;
+ }
+ }
+#endif
+
if (win->GetEventHandler()->ProcessEvent( event ))
{
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
// "button_release_event"
//-----------------------------------------------------------------------------
-static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
+static gint gtk_window_button_release_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
-/*
- printf( "OnButtonRelease from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
wxEventType event_type = wxEVT_NULL;
switch (gdk_event->button)
{
- 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;
+ 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:
+ // unknwon button, don't process
+ return FALSE;
}
wxMouseEvent event( event_type );
// same wxListBox hack as above
win->FixUpMouseEvent(widget, event.m_x, event.m_y);
+ if ( event_type == wxEVT_RIGHT_UP )
+ {
+ // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
+ // except that:
+ //
+ // (a) it's a command event and so is propagated to the parent
+ // (b) under MSW it can be generated from kbd too
+ // (c) it uses screen coords (because of (a))
+ wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU,
+ win->GetId(),
+ win->ClientToScreen(event.GetPosition()));
+ (void)win->GetEventHandler()->ProcessEvent(evtCtx);
+ }
+
if ( !g_captureWindow )
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), "button_release_event" );
{
// synthetize a mouse enter or leave event if needed
GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
+ // This seems to be necessary and actually been added to
+ // GDK itself in version 2.0.X
+ gdk_flush();
+
bool hasMouse = winUnderMouse == gdk_event->window;
if ( hasMouse != g_captureWindowHasMouse )
{
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" );
return FALSE;
}
+#ifdef __WXGTK20__
+//-----------------------------------------------------------------------------
+// "mouse_wheel_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_wheel_callback (GtkWidget * widget,
+ GdkEventScroll * gdk_event,
+ wxWindowGTK * win)
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ wxEventType event_type = wxEVT_NULL;
+ if (gdk_event->direction == GDK_SCROLL_UP)
+ event_type = wxEVT_MOUSEWHEEL;
+ else if (gdk_event->direction == GDK_SCROLL_DOWN)
+ event_type = wxEVT_MOUSEWHEEL;
+ else
+ return FALSE;
+
+ wxMouseEvent event( event_type );
+ // Can't use InitMouse macro because scroll events don't have button
+ 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);
+ if (gdk_event->direction == GDK_SCROLL_UP)
+ event.m_wheelRotation = 120;
+ else
+ event.m_wheelRotation = -120;
+
+ 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 );
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "scroll_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
//-----------------------------------------------------------------------------
// "focus_in_event"
//-----------------------------------------------------------------------------
#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;
// 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;
// "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->m_hasVMT) return FALSE;
if (g_blockEventsOnDrag) return FALSE;
- if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
+ // Event was emitted after a grab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
- wxMouseEvent event( wxEVT_ENTER_WINDOW );
- event.SetTimestamp( gdk_event->time );
- event.SetEventObject( win );
+ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
int x = 0;
int y = 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;
if (!win->m_hasVMT) return FALSE;
if (g_blockEventsOnDrag) return FALSE;
+ // Event was emitted after an ungrab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
wxMouseEvent event( wxEVT_LEAVE_WINDOW );
win->m_oldVerticalPos = adjust->value;
+#ifndef __WXGTK20__
GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
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;
+#ifndef __WXGTK20__
GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
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
been realized, so we do this directly after realization. */
static gint
-gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
+gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
{
DEBUG_MAIN_THREAD
if (g_isIdle)
wxapp_install_idle_handler();
-
- if (win->m_delayedBackgroundColour)
+
+ if (win->m_delayedBackgroundColour && !win->GetThemeEnabled())
win->GtkSetBackgroundColour( win->GetBackgroundColour() );
- if (win->m_delayedForegroundColour)
+ if (win->m_delayedForegroundColour && !win->GetThemeEnabled())
win->GtkSetForegroundColour( win->GetForegroundColour() );
+#ifdef __WXGTK20__
+ if (win->m_imContext)
+ {
+ GtkPizza *pizza = GTK_PIZZA( m_widget );
+ gtk_im_context_set_client_window( (GtkIMContext*) win->m_imContext, pizza->bin_window );
+ }
+#endif
+
wxWindowCreateEvent event( win );
event.SetEventObject( win );
win->GetEventHandler()->ProcessEvent( event );
void wxWindowGTK::Init()
{
- // common init
- InitBase();
-
// GTK specific
m_widget = (GtkWidget *) NULL;
m_wxwindow = (GtkWidget *) NULL;
m_hAdjust = (GtkAdjustment*) NULL;
m_vAdjust = (GtkAdjustment*) NULL;
- m_oldHorizontalPos = 0.0;
+ m_oldHorizontalPos =
m_oldVerticalPos = 0.0;
+ m_oldClientWidth =
+ m_oldClientHeight = 0;
m_resizing = FALSE;
m_widgetStyle = (GtkStyle*) NULL;
m_delayedForegroundColour = FALSE;
m_delayedBackgroundColour = FALSE;
+#ifdef __WXGTK20__
+ m_imContext = NULL;
+ m_x11Context = NULL;
+#else
#ifdef HAVE_XIM
m_ic = (GdkIC*) NULL;
m_icattr = (GdkICAttr*) NULL;
#endif
+#endif
}
wxWindowGTK::wxWindowGTK()
}
m_insertCallback = wxInsertChildInWindow;
-
+
// always needed for background clearing
- m_delayedBackgroundColour = TRUE;
+ m_delayedBackgroundColour = TRUE;
m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
(GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
+#ifdef __WXGTK20__
+ // Create input method handler
+ m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
+
+ // Cannot handle drawing preedited text yet
+ gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
+
+ g_signal_connect (G_OBJECT (m_imContext), "commit",
+ G_CALLBACK (gtk_wxwindow_commit_cb), this);
+#endif
+
gtk_widget_show( m_wxwindow );
if (m_parent)
wxWindowGTK::~wxWindowGTK()
{
+ SendDestroyEvent();
+
if (g_focusWindow == this)
g_focusWindow = NULL;
DestroyChildren();
- if (m_parent)
- m_parent->RemoveChild( this );
-
#ifdef HAVE_XIM
if (m_ic)
gdk_ic_destroy (m_ic);
{
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(m_wxwindow), "draw",
GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
- if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
+ if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
{
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
}
#else
- gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
+ // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
+#endif
+
+#ifdef __WXGTK20__
+ // Create input method handler
+ m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
+
+ // Cannot handle drawing preedited text yet
+ gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
+
+ g_signal_connect (G_OBJECT (m_imContext), "commit",
+ G_CALLBACK (gtk_wxwindow_commit_cb), this);
#endif
}
GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
}
- if (!GTK_IS_COMBO(m_widget))
+ 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
// 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 );
+ GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
+ (gpointer) this );
}
m_hasVMT = TRUE;
gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
+#ifdef __WXGTK20__
+ gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
+ GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
+#endif
+
gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
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()
int currentX, currentY;
GetPosition(¤tX, ¤tY);
- if (x == -1)
+ if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
x = currentX;
- if (y == -1)
+ if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
y = currentY;
AdjustForParentClientOrigin(x, y, sizeFlags);
{
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)
{
}
g_activeFrameLostFocus = FALSE;
}
-
+
wxCursor cursor = m_cursor;
if (g_globalCursor.Ok()) cursor = g_globalCursor;
}
}
- UpdateWindowUI();
+ if (wxUpdateUIEvent::CanUpdate(this))
+ UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
}
void wxWindowGTK::DoGetSize( int *width, int *height ) const
else
gtk_widget_hide( m_widget );
+ wxShowEvent eventShow(GetId(), show);
+ eventShow.m_eventObject = this;
+
+ GetEventHandler()->ProcessEvent(eventShow);
+
return TRUE;
}
// 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();
+ for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
+#ifdef __WXGTK20__
+ PangoContext *context = NULL;
+ if (m_widget)
+ context = gtk_widget_get_pango_context( m_widget );
+
+ if (!context)
+ return 0;
+
+ PangoFontDescription *desc = m_font.GetNativeFontInfo()->description;
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_font_description(layout, desc);
+ pango_layout_set_text(layout, "H", 1);
+ PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+ PangoRectangle rect;
+ pango_layout_line_get_extents(line, NULL, &rect);
+
+ g_object_unref( G_OBJECT( layout ) );
+
+ return (int) (rect.height / PANGO_SCALE);
+#else
GdkFont *font = m_font.GetInternalFont( 1.0 );
return font->ascent + font->descent;
+#endif
}
int wxWindowGTK::GetCharWidth() const
wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
+#ifdef __WXGTK20__
+ PangoContext *context = NULL;
+ if (m_widget)
+ context = gtk_widget_get_pango_context( m_widget );
+
+ if (!context)
+ return 0;
+
+ PangoFontDescription *desc = m_font.GetNativeFontInfo()->description;
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_font_description(layout, desc);
+ pango_layout_set_text(layout, "g", 1);
+ PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+ PangoRectangle rect;
+ pango_layout_line_get_extents(line, NULL, &rect);
+
+ g_object_unref( G_OBJECT( layout ) );
+
+ return (int) (rect.width / PANGO_SCALE);
+#else
GdkFont *font = m_font.GetInternalFont( 1.0 );
- return gdk_string_width( font, "H" );
+ return gdk_string_width( font, "g" );
+#endif
}
void wxWindowGTK::GetTextExtent( const wxString& string,
wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
+ if (string.IsEmpty())
+ {
+ if (x) (*x) = 0;
+ if (y) (*y) = 0;
+ return;
+ }
+
+#ifdef __WXGTK20__
+ PangoContext *context = NULL;
+ if (m_widget)
+ context = gtk_widget_get_pango_context( m_widget );
+
+ if (!context)
+ {
+ if (x) (*x) = 0;
+ if (y) (*y) = 0;
+ return;
+ }
+
+ PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_font_description(layout, desc);
+ {
+#if wxUSE_UNICODE
+ const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
+ pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
+#else
+ const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
+ const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
+ pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
+#endif
+ }
+ PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+ PangoRectangle rect;
+ pango_layout_line_get_extents(line, NULL, &rect);
+
+ if (x) (*x) = (wxCoord) (rect.width / PANGO_SCALE);
+ if (y) (*y) = (wxCoord) (rect.height / PANGO_SCALE);
+ if (descent)
+ {
+ // Do something about metrics here
+ (*descent) = 0;
+ }
+ if (externalLeading) (*externalLeading) = 0; // ??
+
+ g_object_unref( G_OBJECT( layout ) );
+#else
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; // ??
+#endif
}
void wxWindowGTK::SetFocus()
gdk_window_warp_pointer( window, x, y );
}
+
void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
{
if (!m_widget) return;
#ifndef __WXGTK20__
if (g_isIdle)
wxapp_install_idle_handler();
-
+
+ wxRect myRect(0,0,0,0);
+ if (m_wxwindow && rect)
+ {
+ myRect.SetSize(wxSize( m_wxwindow->allocation.width,
+ m_wxwindow->allocation.height));
+ myRect.Intersect(*rect);
+ if (!myRect.width || !myRect.height)
+ // nothing to do, rectangle is empty
+ return;
+ rect = &myRect;
+ }
+
if (eraseBackground && m_wxwindow && m_wxwindow->window)
{
if (rect)
#ifdef __WXGTK20__
if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
-#endif
-
+#else
if (!m_updateRegion.IsEmpty())
GtkSendPaintEvents();
+#endif
}
void wxWindowGTK::GtkSendPaintEvents()
{
if (!m_wxwindow)
{
+#ifndef __WXGTK20__
m_clearRegion.Clear();
+#endif
m_updateRegion.Clear();
return;
}
- // widget to draw on
- GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
-
// Clip to paint region in wxClientDC
m_clipPaintRegion = TRUE;
-
+
+#ifndef __WXGTK20__
+ // widget to draw on
+ GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
+
+ // later for GTK 2.0, too.
if (GetThemeEnabled())
{
// find ancestor from which to steal background
parent = parent->GetParent();
if (!parent)
parent = (wxWindow*)this;
-
+
wxRegionIterator upd( m_updateRegion );
while (upd)
{
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,
parent->m_widget,
(char *)"base",
0, 0, -1, -1 );
-
+
upd ++;
}
}
else
- // if (!m_clearRegion.IsEmpty()) // always send an erase event
+#endif
+
+#ifdef __WXGTK20__
{
wxWindowDC dc( (wxWindow*)this );
- dc.SetClippingRegion( m_clearRegion );
+ dc.SetClippingRegion( m_updateRegion );
+
+ wxEraseEvent erase_event( GetId(), &dc );
+ erase_event.SetEventObject( this );
+
+ GetEventHandler()->ProcessEvent(erase_event);
+ }
+#else
+ // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
+ {
+ wxWindowDC dc( (wxWindow*)this );
+ if (m_clearRegion.IsEmpty())
+ dc.SetClippingRegion( m_updateRegion );
+ else
+ dc.SetClippingRegion( m_clearRegion );
wxEraseEvent erase_event( GetId(), &dc );
erase_event.SetEventObject( this );
}
m_clearRegion.Clear();
}
+#endif
wxNcPaintEvent nc_paint_event( GetId() );
nc_paint_event.SetEventObject( this );
{
GtkPizzaChild *child = (GtkPizzaChild*) children->data;
children = children->next;
-
+
if (GTK_WIDGET_NO_WINDOW (child->widget) &&
GTK_WIDGET_DRAWABLE (child->widget))
{
m_updateRegion.Clear();
}
-void wxWindowGTK::Clear()
+void wxWindowGTK::ClearBackground()
{
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+#ifndef __WXGTK20__
if (m_wxwindow && 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
}
#if wxUSE_TOOLTIPS
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.
return TRUE;
}
+#ifdef __WXGTK20__
+PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
+{
+ return gtk_widget_get_pango_context( m_widget );
+}
+
+PangoContext *wxWindowGTK::GtkGetPangoX11Context()
+{
+ if (!m_x11Context)
+ m_x11Context = pango_x_get_context( gdk_display );
+
+ return m_x11Context;
+}
+#endif
+
GtkStyle *wxWindowGTK::GetWidgetStyle()
{
if (m_widgetStyle)
if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
{
- SET_STYLE_FONT(style, m_font.GetInternalFont( 1.0 ));
+#ifdef __WXGTK20__
+ pango_font_description_free( style->font_desc );
+ style->font_desc = pango_font_description_copy( m_font.GetNativeFontInfo()->description );
+#else
+ gdk_font_unref( style->font );
+ style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
+#endif
}
if (m_foregroundColour.Ok())
static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
{
menu->SetInvokingWindow( win );
- wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
+ wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
while (node)
{
wxMenuItem *menuitem = node->GetData();
wxPopupMenuPositionCallback, // function to position it
NULL, // client data
0, // button used to activate it
+#ifdef __WXGTK20__
+ gtk_get_current_event_time()
+#else
gs_timeLastClick // the time of activation
+#endif
);
while (is_waiting)
{
- while (gtk_events_pending())
- gtk_main_iteration();
+ gtk_main_iteration();
}
return TRUE;
bool wxWindowGTK::SetFont( const wxFont &font )
{
- wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
-
- if (!wxWindowBase::SetFont(font))
+ if (!wxWindowBase::SetFont(font) || !m_widget)
{
return FALSE;
}
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 );
}
+#endif
+
m_clipPaintRegion = TRUE;
gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
m_clipPaintRegion = FALSE;
-#else
-
- gdk_window_scroll( GTK_PIZZA(m_wxwindow)->bin_window, dx, dy );
-
- GTK_PIZZA(m_wxwindow)->xoffset += dx;
- GTK_PIZZA(m_wxwindow)->yoffset += dy;
-
-#endif
-
}
int x, y;
GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
- if (!windowAtPtr)
- return wxPoint(-999, -999);
- Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
+ Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
Window rootReturn, childReturn;
int rootX, rootY, winX, winY;