#include "wx/caret.h"
#include "wx/fontutil.h"
#include "wx/sysopt.h"
+#ifdef __WXGTK3__
+ #include "wx/gtk/dc.h"
+#endif
#include <ctype.h>
+#include <gtk/gtk.h>
#include "wx/gtk/private.h"
-#include "wx/gtk/private/win_gtk.h"
+#include "wx/gtk/private/gtk2-compat.h"
#include "wx/gtk/private/event.h"
+#include "wx/gtk/private/win_gtk.h"
using namespace wxGTKImpl;
#ifdef GDK_WINDOWING_X11
#endif
#include <gdk/gdkkeysyms.h>
-#if GTK_CHECK_VERSION(3,0,0)
+#ifdef __WXGTK3__
#include <gdk/gdkkeysyms-compat.h>
#endif
#define TRACE_FOCUS wxT("focus")
//-----------------------------------------------------------------------------
-// "expose_event" of m_wxwindow
+// "expose_event"/"draw" from m_wxwindow
//-----------------------------------------------------------------------------
extern "C" {
-static gboolean
-gtk_window_expose_callback( GtkWidget*,
- GdkEventExpose *gdk_event,
- wxWindow *win )
+#ifdef __WXGTK3__
+static gboolean draw(GtkWidget*, cairo_t* cr, wxWindow* win)
+{
+ if (gtk_cairo_should_draw_window(cr, win->GTKGetDrawingWindow()))
+ win->GTKSendPaintEvents(cr);
+
+ return false;
+}
+#else // !__WXGTK3__
+static gboolean expose_event(GtkWidget*, GdkEventExpose* gdk_event, wxWindow* win)
{
if (gdk_event->window == win->GTKGetDrawingWindow())
- {
- win->GetUpdateRegion() = wxRegion( gdk_event->region );
- win->GtkSendPaintEvents();
- }
- // Let parent window draw window-less widgets
- return FALSE;
+ win->GTKSendPaintEvents(gdk_event->region);
+
+ return false;
}
+#endif // !__WXGTK3__
}
#ifndef __WXUNIVERSAL__
//-----------------------------------------------------------------------------
-// "expose_event" from m_wxwindow->parent, for drawing border
+// "expose_event"/"draw" from m_wxwindow->parent, for drawing border
//-----------------------------------------------------------------------------
extern "C" {
static gboolean
-expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
+#ifdef __WXGTK3__
+draw_border(GtkWidget*, cairo_t* cr, wxWindow* win)
+#else
+draw_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
+#endif
{
+#ifdef __WXGTK3__
+ if (!gtk_cairo_should_draw_window(cr, gtk_widget_get_parent_window(win->m_wxwindow)))
+#else
if (gdk_event->window != gtk_widget_get_parent_window(win->m_wxwindow))
+#endif
return false;
if (!win->IsShown())
if (win->HasFlag(wxBORDER_SIMPLE))
{
+#ifdef __WXGTK3__
+ GtkStyleContext* sc = gtk_widget_get_style_context(win->m_wxwindow);
+ GdkRGBA c;
+ gtk_style_context_get_border_color(sc, GTK_STATE_FLAG_NORMAL, &c);
+ gdk_cairo_set_source_rgba(cr, &c);
+ cairo_set_line_width(cr, 1);
+ cairo_rectangle(cr, x + 0.5, y + 0.5, w - 1, h - 1);
+ cairo_stroke(cr);
+#else
gdk_draw_rectangle(gdk_event->window,
gtk_widget_get_style(widget)->black_gc, false, x, y, w - 1, h - 1);
+#endif
}
- else
+ else if (win->HasFlag(wxBORDER_RAISED | wxBORDER_SUNKEN | wxBORDER_THEME))
{
+#ifdef __WXGTK3__
+ //TODO: wxBORDER_RAISED/wxBORDER_SUNKEN
+ GtkStyleContext* sc;
+ if (win->HasFlag(wxHSCROLL | wxVSCROLL))
+ sc = gtk_widget_get_style_context(wxGTKPrivate::GetTreeWidget());
+ else
+ sc = gtk_widget_get_style_context(wxGTKPrivate::GetEntryWidget());
+
+ gtk_render_frame(sc, cr, x, y, w, h);
+#else // !__WXGTK3__
GtkShadowType shadow = GTK_SHADOW_IN;
if (win->HasFlag(wxBORDER_RAISED))
shadow = GTK_SHADOW_OUT;
- // Style detail to use
+ GtkStyle* style;
const char* detail;
- if (win->m_widget == win->m_wxwindow)
- // for non-scrollable wxWindows
- detail = "entry";
- else
- // for scrollable ones
+ if (win->HasFlag(wxHSCROLL | wxVSCROLL))
+ {
+ style = gtk_widget_get_style(wxGTKPrivate::GetTreeWidget());
detail = "viewport";
+ }
+ else
+ {
+ style = gtk_widget_get_style(wxGTKPrivate::GetEntryWidget());
+ detail = "entry";
+ }
// clip rect is required to avoid painting background
// over upper left (w,h) of parent window
GdkRectangle clipRect = { x, y, w, h };
gtk_paint_shadow(
- gtk_widget_get_style(win->m_wxwindow), gdk_event->window, GTK_STATE_NORMAL,
- shadow, &clipRect, wxGTKPrivate::GetEntryWidget(), detail, x, y, w, h);
+ style, gdk_event->window, GTK_STATE_NORMAL,
+ shadow, &clipRect, widget, detail, x, y, w, h);
+#endif // !__WXGTK3__
}
return false;
}
if (old_parent)
{
g_signal_handlers_disconnect_by_func(
- old_parent, (void*)expose_event_border, win);
+ old_parent, (void*)draw_border, win);
}
GtkWidget* parent = gtk_widget_get_parent(widget);
if (parent)
{
- g_signal_connect_after(parent, "expose_event",
- G_CALLBACK(expose_event_border), win);
+#ifdef __WXGTK3__
+ g_signal_connect_after(parent, "draw", G_CALLBACK(draw_border), win);
+#else
+ g_signal_connect_after(parent, "expose_event", G_CALLBACK(draw_border), win);
+#endif
}
}
}
event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0;
+ // At least with current Linux systems, MOD5 corresponds to AltGr key and
+ // we represent it, for consistency with Windows, which really allows to
+ // use Ctrl+Alt as a replacement for AltGr if this key is not present, as a
+ // combination of these two modifiers.
+ if ( gdk_event->state & GDK_MOD5_MASK )
+ {
+ event.m_controlDown =
+ event.m_altDown = true;
+ }
+
// Normally we take the state of modifiers directly from the low level GDK
// event but unfortunately GDK uses a different convention from MSW for the
// key events corresponding to the modifier keys themselves: in it, when
event.m_rawCode = (wxUint32) gdk_event->keyval;
event.m_rawFlags = gdk_event->hardware_keycode;
- wxGetMousePosition(&event.m_x, &event.m_y);
- win->ScreenToClient(&event.m_x, &event.m_y);
event.SetEventObject( win );
}
return TRUE;
}
- // Emit KEY_DOWN event
- ret = win->HandleWindowEvent( event );
+ // Next check for accelerators.
+#if wxUSE_ACCEL
+ wxWindowGTK *ancestor = win;
+ while (ancestor)
+ {
+ int command = ancestor->GetAcceleratorTable()->GetCommand( event );
+ if (command != -1)
+ {
+ 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())
+ break;
+ ancestor = ancestor->GetParent();
+ }
+#endif // wxUSE_ACCEL
+
+ // If not an accelerator, then emit KEY_DOWN event
+ if ( !ret )
+ ret = win->HandleWindowEvent( event );
}
else
{
if (return_after_IM)
return FALSE;
-#if wxUSE_ACCEL
- if (!ret)
- {
- wxWindowGTK *ancestor = win;
- while (ancestor)
- {
- int command = ancestor->GetAcceleratorTable()->GetCommand( event );
- if (command != -1)
- {
- 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())
- break;
- ancestor = ancestor->GetParent();
- }
- }
-#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)
{
- long key_code;
KeySym keysym = gdk_event->keyval;
// Find key code for EVT_CHAR and EVT_CHAR_HOOK events
- key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
+ long key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
if ( !key_code )
{
if ( wxIsAsciiKeysym(keysym) )
wxLogTrace(TRACE_KEYS, wxT("Char event: %ld"), key_code);
eventChar.m_keyCode = key_code;
+#if wxUSE_UNICODE
+ eventChar.m_uniChar = gdk_keyval_to_unicode(key_code);
+#endif // wxUSE_UNICODE
AdjustCharEventKeyCodes(eventChar);
//-----------------------------------------------------------------------------
static gboolean
-gtk_window_button_press_callback( GtkWidget *widget,
+gtk_window_button_press_callback( GtkWidget* WXUNUSED_IN_GTK3(widget),
GdkEventButton *gdk_event,
wxWindowGTK *win )
{
g_lastButtonNumber = gdk_event->button;
- // GDK sends surplus button down events
- // before a double click event. We
- // need to filter these out.
- if ((gdk_event->type == GDK_BUTTON_PRESS) && (win->m_wxwindow))
+ wxEventType event_type;
+ wxEventType down;
+ wxEventType dclick;
+ switch (gdk_event->button)
{
- GdkEvent *peek_event = gdk_event_peek();
- if (peek_event)
- {
- if ((peek_event->type == GDK_2BUTTON_PRESS) ||
- (peek_event->type == GDK_3BUTTON_PRESS))
+ case 1:
+ down = wxEVT_LEFT_DOWN;
+ dclick = wxEVT_LEFT_DCLICK;
+ break;
+ case 2:
+ down = wxEVT_MIDDLE_DOWN;
+ dclick = wxEVT_MIDDLE_DCLICK;
+ break;
+ case 3:
+ down = wxEVT_RIGHT_DOWN;
+ dclick = wxEVT_RIGHT_DCLICK;
+ break;
+ case 8:
+ down = wxEVT_AUX1_DOWN;
+ dclick = wxEVT_AUX1_DCLICK;
+ break;
+ case 9:
+ down = wxEVT_AUX2_DOWN;
+ dclick = wxEVT_AUX2_DCLICK;
+ break;
+ default:
+ return false;
+ }
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ event_type = down;
+ // GDK sends surplus button down events
+ // before a double click event. We
+ // need to filter these out.
+ if (win->m_wxwindow)
{
- gdk_event_free( peek_event );
- return TRUE;
+ GdkEvent* peek_event = gdk_event_peek();
+ if (peek_event)
+ {
+ const GdkEventType peek_event_type = peek_event->type;
+ gdk_event_free(peek_event);
+ if (peek_event_type == GDK_2BUTTON_PRESS ||
+ peek_event_type == GDK_3BUTTON_PRESS)
+ {
+ return true;
+ }
+ }
}
- else
+ break;
+ case GDK_2BUTTON_PRESS:
+ event_type = dclick;
+#ifndef __WXGTK3__
+ if (gdk_event->button >= 1 && gdk_event->button <= 3)
{
- gdk_event_free( peek_event );
+ // Reset GDK internal timestamp variables in order to disable GDK
+ // triple click events. GDK will then next time believe no button has
+ // been clicked just before, and send a normal button click event.
+ GdkDisplay* display = gtk_widget_get_display(widget);
+ display->button_click_time[1] = 0;
+ display->button_click_time[0] = 0;
}
- }
- }
-
- wxEventType event_type = wxEVT_NULL;
-
- if ( gdk_event->type == GDK_2BUTTON_PRESS &&
- gdk_event->button >= 1 && gdk_event->button <= 3 )
- {
- // Reset GDK internal timestamp variables in order to disable GDK
- // triple click events. GDK will then next time believe no button has
- // been clicked just before, and send a normal button click event.
- GdkDisplay* display = gtk_widget_get_display (widget);
- display->button_click_time[1] = 0;
- display->button_click_time[0] = 0;
- }
-
- if (gdk_event->button == 1)
- {
- // note that GDK generates triple click events which are not supported
- // by wxWidgets but still have to be passed to the app as otherwise
- // clicks would simply go missing
- switch (gdk_event->type)
- {
- // we shouldn't get triple clicks at all for GTK2 because we
- // suppress them artificially using the code above but we still
- // should map them to something for GTK1 and not just ignore them
- // as this would lose clicks
- case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
- case GDK_BUTTON_PRESS:
- event_type = wxEVT_LEFT_DOWN;
- break;
-
- case GDK_2BUTTON_PRESS:
- event_type = wxEVT_LEFT_DCLICK;
- break;
-
- default:
- // just to silence gcc warnings
- ;
- }
- }
- else if (gdk_event->button == 2)
- {
- switch (gdk_event->type)
- {
- case GDK_3BUTTON_PRESS:
- case GDK_BUTTON_PRESS:
- event_type = wxEVT_MIDDLE_DOWN;
- break;
-
- case GDK_2BUTTON_PRESS:
- event_type = wxEVT_MIDDLE_DCLICK;
- break;
-
- default:
- ;
- }
- }
- else if (gdk_event->button == 3)
- {
- switch (gdk_event->type)
- {
- case GDK_3BUTTON_PRESS:
- case GDK_BUTTON_PRESS:
- event_type = wxEVT_RIGHT_DOWN;
- break;
-
- case GDK_2BUTTON_PRESS:
- event_type = wxEVT_RIGHT_DCLICK;
- break;
-
- default:
- ;
- }
- }
-
- else if (gdk_event->button == 8)
- {
- switch (gdk_event->type)
- {
- case GDK_3BUTTON_PRESS:
- case GDK_BUTTON_PRESS:
- event_type = wxEVT_AUX1_DOWN;
- break;
-
- case GDK_2BUTTON_PRESS:
- event_type = wxEVT_AUX1_DCLICK;
- break;
-
- default:
- ;
- }
- }
-
- else if (gdk_event->button == 9)
- {
- switch (gdk_event->type)
- {
- case GDK_3BUTTON_PRESS:
- case GDK_BUTTON_PRESS:
- event_type = wxEVT_AUX2_DOWN;
- break;
-
- case GDK_2BUTTON_PRESS:
- event_type = wxEVT_AUX2_DCLICK;
- break;
-
- default:
- ;
- }
- }
-
- if ( event_type == wxEVT_NULL )
- {
- // unknown mouse button or click type
- return FALSE;
+#endif // !__WXGTK3__
+ break;
+ // we shouldn't get triple clicks at all for GTK2 because we
+ // suppress them artificially using the code above but we still
+ // should map them to something for GTK3 and not just ignore them
+ // as this would lose clicks
+ case GDK_3BUTTON_PRESS:
+ event_type = down;
+ break;
+ default:
+ return false;
}
g_lastMouseEvent = (GdkEvent*) gdk_event;
win->GTKHandleRealized();
}
-//-----------------------------------------------------------------------------
-// "unrealize" from m_wxwindow
-//-----------------------------------------------------------------------------
-
-static void unrealize(GtkWidget*, wxWindowGTK* win)
-{
- if (win->m_imData)
- gtk_im_context_set_client_window(win->m_imData->context, NULL);
-}
-
//-----------------------------------------------------------------------------
// "size_allocate" from m_wxwindow or m_widget
//-----------------------------------------------------------------------------
int h = alloc->height;
if (win->m_wxwindow)
{
- int border_x, border_y;
- WX_PIZZA(win->m_wxwindow)->get_border_widths(border_x, border_y);
- w -= 2 * border_x;
- h -= 2 * border_y;
+ GtkBorder border;
+ WX_PIZZA(win->m_wxwindow)->get_border(border);
+ w -= border.left + border.right;
+ h -= border.top + border.bottom;
if (w < 0) w = 0;
if (h < 0) h = 0;
}
#endif
//-----------------------------------------------------------------------------
-// "style_set"
+// "style_set"/"style_updated"
//-----------------------------------------------------------------------------
-static
-void gtk_window_style_set_callback( GtkWidget *WXUNUSED(widget),
- GtkStyle *previous_style,
- wxWindow* win )
+#ifdef __WXGTK3__
+static void style_updated(GtkWidget*, wxWindow* win)
+#else
+static void style_updated(GtkWidget*, GtkStyle*, wxWindow* win)
+#endif
{
- if (win && previous_style)
+ if (win->IsTopLevel())
{
- if (win->IsTopLevel())
- {
- wxSysColourChangedEvent event;
- event.SetEventObject(win);
- win->GTKProcessEvent(event);
- }
- else
- {
- // Border width could change, which will change client size.
- // Make sure size event occurs for this
- win->m_oldClientWidth = 0;
- }
+ wxSysColourChangedEvent event;
+ event.SetEventObject(win);
+ win->GTKProcessEvent(event);
+ }
+ else
+ {
+ // Border width could change, which will change client size.
+ // Make sure size event occurs for this
+ win->m_oldClientWidth = 0;
}
}
+//-----------------------------------------------------------------------------
+// "unrealize" from m_wxwindow
+//-----------------------------------------------------------------------------
+
+static void unrealize(GtkWidget*, wxWindow* win)
+{
+ if (win->m_imData)
+ gtk_im_context_set_client_window(win->m_imData->context, NULL);
+
+ g_signal_handlers_disconnect_by_func(
+ win->m_wxwindow, (void*)style_updated, win);
+}
+
} // extern "C"
void wxWindowGTK::GTKHandleRealized()
GTKProcessEvent( event );
GTKUpdateCursor(true, false);
+
+ if (m_wxwindow &&
+ (IsTopLevel() || HasFlag(wxBORDER_RAISED | wxBORDER_SUNKEN | wxBORDER_THEME)))
+ {
+ // attaching to style changed signal after realization avoids initial
+ // changes we don't care about
+ const gchar *detailed_signal =
+#ifdef __WXGTK3__
+ "style_updated";
+#else
+ "style_set";
+#endif
+ g_signal_connect(m_wxwindow,
+ detailed_signal,
+ G_CALLBACK(style_updated), this);
+ }
}
// ----------------------------------------------------------------------------
}
+// Under Unix this is implemented using X11 functions in utilsx11.cpp but we
+// need to have this function under Windows too, so provide at least a stub.
+#ifndef GDK_WINDOWING_X11
+bool wxGetKeyState(wxKeyCode WXUNUSED(key))
+{
+ wxFAIL_MSG(wxS("Not implemented under Windows"));
+ return false;
+}
+#endif // __WINDOWS__
+
+static void GetMouseState(int& x, int& y, GdkModifierType& mask)
+{
+ wxWindow* tlw = NULL;
+ if (!wxTopLevelWindows.empty())
+ tlw = wxTopLevelWindows.front();
+ GdkDisplay* display;
+ if (tlw && tlw->m_widget)
+ display = gtk_widget_get_display(tlw->m_widget);
+ else
+ display = gdk_display_get_default();
+ gdk_display_get_pointer(display, NULL, &x, &y, &mask);
+}
+
wxMouseState wxGetMouseState()
{
wxMouseState ms;
gint y;
GdkModifierType mask;
- gdk_window_get_pointer(NULL, &x, &y, &mask);
+ GetMouseState(x, y, mask);
ms.SetX(x);
ms.SetY(y);
m_noExpose = false;
m_nativeSizeEvent = false;
+#ifdef __WXGTK3__
+ m_paintContext = NULL;
+#endif
m_isScrolling = false;
m_mouseButtonDown = false;
Create( parent, id, pos, size, style, name );
}
+void wxWindowGTK::GTKCreateScrolledWindowWith(GtkWidget* view)
+{
+ wxASSERT_MSG( HasFlag(wxHSCROLL) || HasFlag(wxVSCROLL),
+ wxS("Must not be called if scrolling is not needed.") );
+
+ m_widget = gtk_scrolled_window_new( NULL, NULL );
+
+ GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
+
+ // 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
+ // direction and notebooks for changing pages -- we decide that if we don't
+ // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
+ // means we can get working keyboard navigation in notebooks
+ if ( !HasFlag(wxHSCROLL) )
+ {
+ GtkBindingSet *
+ bindings = gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget));
+ if ( bindings )
+ {
+ gtk_binding_entry_remove(bindings, GDK_Page_Up, GDK_CONTROL_MASK);
+ gtk_binding_entry_remove(bindings, GDK_Page_Down, GDK_CONTROL_MASK);
+ }
+ }
+
+ if (HasFlag(wxALWAYS_SHOW_SB))
+ {
+ gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS );
+ }
+ else
+ {
+ gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+ }
+
+ m_scrollBar[ScrollDir_Horz] = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(scrolledWindow));
+ m_scrollBar[ScrollDir_Vert] = GTK_RANGE(gtk_scrolled_window_get_vscrollbar(scrolledWindow));
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE );
+
+ gtk_container_add( GTK_CONTAINER(m_widget), view );
+
+ // connect various scroll-related events
+ for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+ {
+ // these handlers block mouse events to any window during scrolling
+ // such as motion events and prevent GTK and wxWidgets from fighting
+ // over where the slider should be
+ g_signal_connect(m_scrollBar[dir], "button_press_event",
+ G_CALLBACK(gtk_scrollbar_button_press_event), this);
+ g_signal_connect(m_scrollBar[dir], "button_release_event",
+ G_CALLBACK(gtk_scrollbar_button_release_event), this);
+
+ gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after",
+ G_CALLBACK(gtk_scrollbar_event_after), this);
+ g_signal_handler_block(m_scrollBar[dir], handler_id);
+
+ // these handlers get notified when scrollbar slider moves
+ g_signal_connect_after(m_scrollBar[dir], "value_changed",
+ G_CALLBACK(gtk_scrollbar_value_changed), this);
+ }
+
+ gtk_widget_show( view );
+}
+
bool wxWindowGTK::Create( wxWindow *parent,
wxWindowID id,
const wxPoint &pos,
if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
m_widget = m_wxwindow;
else
- {
- m_widget = gtk_scrolled_window_new( NULL, NULL );
-
- GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
-
- // 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
- // direction and notebooks for changing pages -- we decide that if we don't
- // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
- // means we can get working keyboard navigation in notebooks
- if ( !HasFlag(wxHSCROLL) )
- {
- GtkBindingSet *
- bindings = gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget));
- if ( bindings )
- {
- gtk_binding_entry_remove(bindings, GDK_Page_Up, GDK_CONTROL_MASK);
- gtk_binding_entry_remove(bindings, GDK_Page_Down, GDK_CONTROL_MASK);
- }
- }
-
- if (HasFlag(wxALWAYS_SHOW_SB))
- {
- gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS );
- }
- else
- {
- gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
- }
-
- m_scrollBar[ScrollDir_Horz] = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(scrolledWindow));
- m_scrollBar[ScrollDir_Vert] = GTK_RANGE(gtk_scrolled_window_get_vscrollbar(scrolledWindow));
- if (GetLayoutDirection() == wxLayout_RightToLeft)
- gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE );
-
- gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
-
- // connect various scroll-related events
- for ( int dir = 0; dir < ScrollDir_Max; dir++ )
- {
- // these handlers block mouse events to any window during scrolling
- // such as motion events and prevent GTK and wxWidgets from fighting
- // over where the slider should be
- g_signal_connect(m_scrollBar[dir], "button_press_event",
- G_CALLBACK(gtk_scrollbar_button_press_event), this);
- g_signal_connect(m_scrollBar[dir], "button_release_event",
- G_CALLBACK(gtk_scrollbar_button_release_event), this);
-
- gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after",
- G_CALLBACK(gtk_scrollbar_event_after), this);
- g_signal_handler_block(m_scrollBar[dir], handler_id);
-
- // these handlers get notified when scrollbar slider moves
- g_signal_connect_after(m_scrollBar[dir], "value_changed",
- G_CALLBACK(gtk_scrollbar_value_changed), this);
- }
-
- gtk_widget_show( m_wxwindow );
- }
+ GTKCreateScrolledWindowWith(m_wxwindow);
g_object_ref(m_widget);
if (m_parent)
IsTransparentBackgroundSupported() )
{
GdkScreen *screen = gtk_widget_get_screen (m_widget);
-
+#ifdef __WXGTK3__
+ gtk_widget_set_visual(m_widget, gdk_screen_get_rgba_visual(screen));
+#else
GdkColormap *rgba_colormap = gdk_screen_get_rgba_colormap (screen);
if (rgba_colormap)
gtk_widget_set_colormap(m_widget, rgba_colormap);
+#endif
}
#endif // wxGTK_HAS_COMPOSITING_SUPPORT
if (!m_noExpose)
{
// these get reported to wxWidgets -> wxPaintEvent
-
- g_signal_connect (m_wxwindow, "expose_event",
- G_CALLBACK (gtk_window_expose_callback), this);
+#ifdef __WXGTK3__
+ g_signal_connect(m_wxwindow, "draw", G_CALLBACK(draw), this);
+#else
+ g_signal_connect(m_wxwindow, "expose_event", G_CALLBACK(expose_event), this);
+#endif
if (GetLayoutDirection() == wxLayout_LeftToRight)
gtk_widget_set_redraw_on_allocate(m_wxwindow, HasFlag(wxFULL_REPAINT_ON_RESIZE));
}
#if GTK_CHECK_VERSION(2, 8, 0)
+#ifndef __WXGTK3__
if ( gtk_check_version(2,8,0) == NULL )
+#endif
{
// Make sure we can notify the app when mouse capture is lost
if ( m_wxwindow )
G_CALLBACK (gtk_window_enter_callback), this);
g_signal_connect (widget, "leave_notify_event",
G_CALLBACK (gtk_window_leave_callback), this);
-
- if (m_wxwindow && (IsTopLevel() || HasFlag(wxBORDER_RAISED | wxBORDER_SUNKEN | wxBORDER_THEME)))
- g_signal_connect (m_wxwindow, "style_set",
- G_CALLBACK (gtk_window_style_set_callback), this);
}
bool wxWindowGTK::Destroy()
gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(m_widget),
&policy[ScrollDir_Horz],
&policy[ScrollDir_Vert]);
+ const int scrollbar_spacing =
+ GTK_SCROLLED_WINDOW_GET_CLASS(m_widget)->scrollbar_spacing;
for ( int i = 0; i < ScrollDir_Max; i++ )
{
continue;
}
- GtkScrolledWindowClass *scroll_class =
- GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
-
GtkRequisition req;
+#ifdef __WXGTK3__
+ GtkWidget* widget = GTK_WIDGET(range);
+ if (i == ScrollDir_Horz)
+ {
+ if (height)
+ {
+ gtk_widget_get_preferred_height(widget, NULL, &req.height);
+ h -= req.height + scrollbar_spacing;
+ }
+ }
+ else
+ {
+ if (width)
+ {
+ gtk_widget_get_preferred_width(widget, NULL, &req.width);
+ w -= req.width + scrollbar_spacing;
+ }
+ }
+#else // !__WXGTK3__
gtk_widget_size_request(GTK_WIDGET(range), &req);
if (i == ScrollDir_Horz)
- h -= req.height + scroll_class->scrollbar_spacing;
+ h -= req.height + scrollbar_spacing;
else
- w -= req.width + scroll_class->scrollbar_spacing;
+ w -= req.width + scrollbar_spacing;
+#endif // !__WXGTK3__
}
}
if ( !m_wxwindow )
return wxWindowBase::DoGetBorderSize();
- int x, y;
- WX_PIZZA(m_wxwindow)->get_border_widths(x, y);
-
- return 2*wxSize(x, y);
+ GtkBorder border;
+ WX_PIZZA(m_wxwindow)->get_border(border);
+ return wxSize(border.left + border.right, border.top + border.bottom);
}
void wxWindowGTK::DoGetPosition( int *x, int *y ) const
ClientToScreen(&x, &y);
GdkDisplay* display = gtk_widget_get_display(m_widget);
GdkScreen* screen = gtk_widget_get_screen(m_widget);
-#ifdef __WXGTK30__
+#ifdef __WXGTK3__
GdkDeviceManager* manager = gdk_display_get_device_manager(display);
gdk_device_warp(gdk_device_manager_get_client_pointer(manager), screen, x, y);
#else
return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
}
-void wxWindowGTK::GtkSendPaintEvents()
+#ifdef __WXGTK3__
+void wxWindowGTK::GTKSendPaintEvents(cairo_t* cr)
+#else
+void wxWindowGTK::GTKSendPaintEvents(const GdkRegion* region)
+#endif
{
- if (!m_wxwindow)
- {
- m_updateRegion.Clear();
- return;
- }
+#ifdef __WXGTK3__
+ m_paintContext = cr;
+ double x1, y1, x2, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ m_updateRegion = wxRegion(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
+#else // !__WXGTK3__
+ m_updateRegion = wxRegion(region);
#if wxGTK_HAS_COMPOSITING_SUPPORT
cairo_t* cr = NULL;
#endif
+#endif // !__WXGTK3__
// Clip to paint region in wxClientDC
m_clipPaintRegion = true;
// Transform m_updateRegion under RTL
m_updateRegion.Clear();
- gint width;
- gdk_drawable_get_size(gtk_widget_get_window(m_wxwindow), &width, NULL);
+ const int width = gdk_window_get_width(GTKGetDrawingWindow());
wxRegionIterator upd( m_nativeUpdateRegion );
while (upd)
// explicitly paint.
// NB: it works also for top level windows (but this is the
// windows manager which then does the compositing job)
+#ifndef __WXGTK3__
cr = gdk_cairo_create(m_wxwindow->window);
gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
cairo_clip(cr);
-
+#endif
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+#ifndef __WXGTK3__
cairo_surface_flush(cairo_get_target(cr));
+#endif
}
#endif // wxGTK_HAS_COMPOSITING_SUPPORT
break;
case wxBG_STYLE_ERASE:
{
+#ifdef __WXGTK3__
+ wxGTKCairoDC dc(cr);
+#else
wxWindowDC dc( (wxWindow*)this );
dc.SetDeviceClippingRegion( m_updateRegion );
dc.SetBackground(GetBackgroundColour());
dc.Clear();
}
-
+#endif // !__WXGTK3__
wxEraseEvent erase_event( GetId(), &dc );
erase_event.SetEventObject( this );
case wxBG_STYLE_SYSTEM:
if ( GetThemeEnabled() )
{
+ GdkWindow* gdkWindow = GTKGetDrawingWindow();
+ const int w = gdk_window_get_width(gdkWindow);
+ const int h = gdk_window_get_height(gdkWindow);
+#ifdef __WXGTK3__
+ GtkStyleContext* sc = gtk_widget_get_style_context(m_wxwindow);
+ gtk_render_background(sc, cr, 0, 0, w, h);
+#else
// find ancestor from which to steal background
wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
if (!parent)
parent = (wxWindow*)this;
-
- if (gtk_widget_get_mapped(parent->m_widget))
- {
- wxRegionIterator upd( m_nativeUpdateRegion );
- while (upd)
- {
- GdkRectangle rect;
- rect.x = upd.GetX();
- rect.y = upd.GetY();
- rect.width = upd.GetWidth();
- rect.height = upd.GetHeight();
-
- gtk_paint_flat_box(gtk_widget_get_style(parent->m_widget),
- GTKGetDrawingWindow(),
+ GdkRectangle rect;
+ m_nativeUpdateRegion.GetBox(rect.x, rect.y, rect.width, rect.height);
+ gtk_paint_flat_box(gtk_widget_get_style(parent->m_widget),
+ gdkWindow,
gtk_widget_get_state(m_wxwindow),
GTK_SHADOW_NONE,
&rect,
parent->m_widget,
(char *)"base",
- 0, 0, -1, -1 );
-
- ++upd;
- }
- }
+ 0, 0, w, h);
+#endif // !__WXGTK3__
}
break;
wxWindow *compositeChild = node->GetData();
if (compositeChild->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT)
{
+#ifndef __WXGTK3__
if (cr == NULL)
{
cr = gdk_cairo_create(m_wxwindow->window);
gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
cairo_clip(cr);
}
-
+#endif // !__WXGTK3__
GtkWidget *child = compositeChild->m_wxwindow;
GtkAllocation alloc;
gtk_widget_get_allocation(child, &alloc);
cairo_paint(cr);
}
}
+#ifndef __WXGTK3__
if (cr)
cairo_destroy(cr);
+#endif
}
#endif // wxGTK_HAS_COMPOSITING_SUPPORT
m_clipPaintRegion = false;
-
+#ifdef __WXGTK3__
+ m_paintContext = NULL;
+#endif
m_updateRegion.Clear();
m_nativeUpdateRegion.Clear();
}
if (!wxWindowBase::SetBackgroundColour(colour))
return false;
+#ifndef __WXGTK3__
if (colour.IsOk())
{
// We need the pixel value e.g. for background clearing.
m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
}
+#endif
// apply style change (forceStyle=true so that new style is applied
// even if the bg colour changed from valid to wxNullColour)
return false;
}
+#ifndef __WXGTK3__
if (colour.IsOk())
{
// We need the pixel value e.g. for background clearing.
m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
}
+#endif
// apply style change (forceStyle=true so that new style is applied
// even if the bg colour changed from valid to wxNullColour):
return gtk_widget_get_pango_context( m_widget );
}
+#ifndef __WXGTK3__
GtkRcStyle *wxWindowGTK::GTKCreateWidgetStyle(bool forceStyle)
{
// do we need to apply any changes at all?
return style;
}
+#endif // !__WXGTK3__
-void wxWindowGTK::GTKApplyWidgetStyle(bool forceStyle)
+void wxWindowGTK::GTKApplyWidgetStyle(bool WXUNUSED_IN_GTK3(forceStyle))
{
+#ifdef __WXGTK3__
+ DoApplyWidgetStyle(NULL);
+#else
GtkRcStyle *style = GTKCreateWidgetStyle(forceStyle);
if ( style )
{
DoApplyWidgetStyle(style);
g_object_unref(style);
}
+#endif
// Style change may affect GTK+'s size calculation:
InvalidateBestSize();
void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
{
- if ( m_wxwindow )
+ GtkWidget* widget = m_wxwindow ? m_wxwindow : m_widget;
+
+ // block the signal temporarily to avoid sending
+ // wxSysColourChangedEvents when we change the colours ourselves
+ bool unblock = false;
+ if (m_wxwindow && IsTopLevel())
{
- // block the signal temporarily to avoid sending
- // wxSysColourChangedEvents when we change the colours ourselves
- bool unblock = false;
- if ( IsTopLevel() )
- {
- unblock = true;
- g_signal_handlers_block_by_func(
- m_wxwindow, (void *)gtk_window_style_set_callback, this);
- }
+ unblock = true;
+ g_signal_handlers_block_by_func(
+ m_wxwindow, (void*)style_updated, this);
+ }
- gtk_widget_modify_style(m_wxwindow, style);
+ GTKApplyStyle(widget, style);
- if ( unblock )
- {
- g_signal_handlers_unblock_by_func(
- m_wxwindow, (void *)gtk_window_style_set_callback, this);
- }
- }
- else
+ if (unblock)
{
- gtk_widget_modify_style(m_widget, style);
+ g_signal_handlers_unblock_by_func(
+ m_wxwindow, (void*)style_updated, this);
}
}
+void wxWindowGTK::GTKApplyStyle(GtkWidget* widget, GtkRcStyle* WXUNUSED_IN_GTK3(style))
+{
+#ifdef __WXGTK3__
+ const PangoFontDescription* pfd = NULL;
+ if (m_font.IsOk())
+ pfd = pango_font_description_copy(m_font.GetNativeFontInfo()->description);
+ gtk_widget_override_font(widget, pfd);
+ gtk_widget_override_color(widget, GTK_STATE_FLAG_NORMAL, m_foregroundColour);
+ gtk_widget_override_background_color(widget, GTK_STATE_FLAG_NORMAL, m_backgroundColour);
+#else
+ gtk_widget_modify_style(widget, style);
+#endif
+}
+
bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
{
if (!wxWindowBase::SetBackgroundStyle(style))
return false;
+#ifndef __WXGTK3__
GdkWindow *window;
if ( m_wxwindow )
{
// even if the bg colour changed from valid to wxNullColour):
GTKApplyWidgetStyle(true);
}
+#endif // !__WXGTK3__
return true;
}
bool wxWindowGTK::IsTransparentBackgroundSupported(wxString* reason) const
{
#if wxGTK_HAS_COMPOSITING_SUPPORT
+#ifndef __WXGTK3__
if (gtk_check_version(wxGTK_VERSION_REQUIRED_FOR_COMPOSITING) != NULL)
{
if (reason)
return false;
}
+#endif // !__WXGTK3__
// NB: We don't check here if the particular kind of widget supports
// transparency, we check only if it would be possible for a generic window
// Get the current mouse position.
wxPoint wxGetMousePosition()
{
- wxWindow* tlw = NULL;
- if (!wxTopLevelWindows.empty())
- tlw = wxTopLevelWindows.front();
- GdkDisplay* display;
- if (tlw && tlw->m_widget)
- display = gtk_widget_get_display(tlw->m_widget);
- else
- display = gdk_display_get_default();
-
int x, y;
- gdk_display_get_pointer(display, NULL, &x, &y, NULL);
+ GdkModifierType unused;
+ GetMouseState(x, y, unused);
return wxPoint(x, y);
}