1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/gtk1/window.cpp
4
// Author: Robert Roebling
5
// Id: $Id: window.cpp 67681 2011-05-03 16:29:04Z DS $
6
// Copyright: (c) 1998 Robert Roebling, Julian Smart
7
// Licence: wxWindows licence
8
/////////////////////////////////////////////////////////////////////////////
10
// For compilers that support precompilation, includes "wx.h".
11
#include "wx/wxprec.h"
14
#define XWarpPointer XWARPPOINTER
17
#include "wx/window.h"
25
#include "wx/dcclient.h"
27
#include "wx/dialog.h"
28
#include "wx/settings.h"
29
#include "wx/msgdlg.h"
30
#include "wx/textctrl.h"
31
#include "wx/combobox.h"
32
#include "wx/layout.h"
33
#include "wx/statusbr.h"
35
#include "wx/module.h"
38
#if wxUSE_DRAG_AND_DROP
43
#include "wx/tooltip.h"
50
#include "wx/fontutil.h"
53
#include "wx/thread.h"
58
#include "wx/gtk1/private.h"
59
#include <gdk/gdkprivate.h>
60
#include <gdk/gdkkeysyms.h>
64
#include <gtk/gtkprivate.h>
66
#include "wx/gtk1/win_gtk.h"
68
//-----------------------------------------------------------------------------
69
// documentation on internals
70
//-----------------------------------------------------------------------------
73
I have been asked several times about writing some documentation about
74
the GTK port of wxWidgets, especially its internal structures. Obviously,
75
you cannot understand wxGTK without knowing a little about the GTK, but
76
some more information about what the wxWindow, which is the base class
77
for all other window classes, does seems required as well.
81
What does wxWindow do? It contains the common interface for the following
82
jobs of its descendants:
84
1) Define the rudimentary behaviour common to all window classes, such as
85
resizing, intercepting user input (so as to make it possible to use these
86
events for special purposes in a derived class), window names etc.
88
2) Provide the possibility to contain and manage children, if the derived
89
class is allowed to contain children, which holds true for those window
90
classes which do not display a native GTK widget. To name them, these
91
classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
92
work classes are a special case and are handled a bit differently from
93
the rest. The same holds true for the wxNotebook class.
95
3) Provide the possibility to draw into a client area of a window. This,
96
too, only holds true for classes that do not display a native GTK widget
99
4) Provide the entire mechanism for scrolling widgets. This actual inter-
100
face for this is usually in wxScrolledWindow, but the GTK implementation
103
5) A multitude of helper or extra methods for special purposes, such as
104
Drag'n'Drop, managing validators etc.
106
6) Display a border (sunken, raised, simple or none).
108
Normally one might expect, that one wxWidgets window would always correspond
109
to one GTK widget. Under GTK, there is no such allround widget that has all
110
the functionality. Moreover, the GTK defines a client area as a different
111
widget from the actual widget you are handling. Last but not least some
112
special classes (e.g. wxFrame) handle different categories of widgets and
113
still have the possibility to draw something in the client area.
114
It was therefore required to write a special purpose GTK widget, that would
115
represent a client area in the sense of wxWidgets capable to do the jobs
116
2), 3) and 4). I have written this class and it resides in win_gtk.c of
119
All windows must have a widget, with which they interact with other under-
120
lying GTK widgets. It is this widget, e.g. that has to be resized etc and
121
the wxWindow class has a member variable called m_widget which holds a
122
pointer to this widget. When the window class represents a GTK native widget,
123
this is (in most cases) the only GTK widget the class manages. E.g. the
124
wxStaticText class handles only a GtkLabel widget a pointer to which you
125
can find in m_widget (defined in wxWindow)
127
When the class has a client area for drawing into and for containing children
128
it has to handle the client area widget (of the type GtkPizza, defined in
129
win_gtk.c), but there could be any number of widgets, handled by a class
130
The common rule for all windows is only, that the widget that interacts with
131
the rest of GTK must be referenced in m_widget and all other widgets must be
132
children of this widget on the GTK level. The top-most widget, which also
133
represents the client area, must be in the m_wxwindow field and must be of
136
As I said, the window classes that display a GTK native widget only have
137
one widget, so in the case of e.g. the wxButton class m_widget holds a
138
pointer to a GtkButton widget. But windows with client areas (for drawing
139
and children) have a m_widget field that is a pointer to a GtkScrolled-
140
Window and a m_wxwindow field that is pointer to a GtkPizza and this
141
one is (in the GTK sense) a child of the GtkScrolledWindow.
143
If the m_wxwindow field is set, then all input to this widget is inter-
144
cepted and sent to the wxWidgets class. If not, all input to the widget
145
that gets pointed to by m_widget gets intercepted and sent to the class.
149
The design of scrolling in wxWidgets is markedly different from that offered
150
by the GTK itself and therefore we cannot simply take it as it is. In GTK,
151
clicking on a scrollbar belonging to scrolled window will inevitably move
152
the window. In wxWidgets, the scrollbar will only emit an event, send this
153
to (normally) a wxScrolledWindow and that class will call ScrollWindow()
154
which actually moves the window and its subchildren. Note that GtkPizza
155
memorizes how much it has been scrolled but that wxWidgets forgets this
156
so that the two coordinates systems have to be kept in synch. This is done
157
in various places using the pizza->xoffset and pizza->yoffset values.
161
Singularily the most broken code in GTK is the code that is supposed to
162
inform subwindows (child windows) about new positions. Very often, duplicate
163
events are sent without changes in size or position, equally often no
164
events are sent at all (All this is due to a bug in the GtkContainer code
165
which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
166
GTK's own system and it simply waits for size events for toplevel windows
167
and then iterates down the respective size events to all window. This has
168
the disadvantage that windows might get size events before the GTK widget
169
actually has the reported size. This doesn't normally pose any problem, but
170
the OpenGL drawing routines rely on correct behaviour. Therefore, I have
171
added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
172
i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
173
window that is used for OpenGL output really has that size (as reported by
178
If someone at some point of time feels the immense desire to have a look at,
179
change or attempt to optimise the Refresh() logic, this person will need an
180
intimate understanding of what "draw" and "expose" events are and what
181
they are used for, in particular when used in connection with GTK's
182
own windowless widgets. Beware.
186
Cursors, too, have been a constant source of pleasure. The main difficulty
187
is that a GdkWindow inherits a cursor if the programmer sets a new cursor
188
for the parent. To prevent this from doing too much harm, I use idle time
189
to set the cursor over and over again, starting from the toplevel windows
190
and ending with the youngest generation (speaking of parent and child windows).
191
Also don't forget that cursors (like much else) are connected to GdkWindows,
192
not GtkWidgets and that the "window" field of a GtkWidget might very well
193
point to the GdkWindow of the parent widget (-> "window-less widget") and
194
that the two obviously have very different meanings.
198
//-----------------------------------------------------------------------------
200
//-----------------------------------------------------------------------------
202
extern bool g_blockEventsOnDrag;
203
extern bool g_blockEventsOnScroll;
204
extern wxCursor g_globalCursor;
206
static GdkGC *g_eraseGC = NULL;
208
// mouse capture state: the window which has it and if the mouse is currently
210
static wxWindowGTK *g_captureWindow = NULL;
211
static bool g_captureWindowHasMouse = false;
213
wxWindowGTK *g_focusWindow = NULL;
215
// the last window which had the focus - this is normally never NULL (except
216
// if we never had focus at all) as even when g_focusWindow is NULL it still
217
// keeps its previous value
218
wxWindowGTK *g_focusWindowLast = NULL;
220
// If a window get the focus set but has not been realized
221
// yet, defer setting the focus to idle time.
222
wxWindowGTK *g_delayedFocus = NULL;
224
// hack: we need something to pass to gtk_menu_popup, so we store the time of
225
// the last click here (extern: used from gtk/menu.cpp)
226
guint32 wxGtkTimeLastClick = 0;
228
// global variables because GTK+ DnD want to have the
229
// mouse event that caused it
230
GdkEvent *g_lastMouseEvent = NULL;
231
int g_lastButtonNumber = 0;
233
extern bool g_mainThreadLocked;
235
//-----------------------------------------------------------------------------
237
//-----------------------------------------------------------------------------
240
# define DEBUG_MAIN_THREAD \
241
wxASSERT_MSG( !g_mainThreadLocked || !wxThread::IsMain(), \
242
"GUI reentrancy detected" );
244
# define DEBUG_MAIN_THREAD
247
// the trace mask used for the focus debugging messages
248
#define TRACE_FOCUS wxT("focus")
250
//-----------------------------------------------------------------------------
251
// missing gdk functions
252
//-----------------------------------------------------------------------------
255
gdk_window_warp_pointer (GdkWindow *window,
259
GdkWindowPrivate *priv;
262
window = GDK_ROOT_PARENT();
264
priv = (GdkWindowPrivate*) window;
266
if (!priv->destroyed)
268
XWarpPointer (priv->xdisplay,
269
None, /* not source window -> move from anywhere */
270
priv->xwindow, /* dest window */
271
0, 0, 0, 0, /* not source window -> move from anywhere */
276
//-----------------------------------------------------------------------------
278
//-----------------------------------------------------------------------------
280
extern void wxapp_install_idle_handler();
281
extern bool g_isIdle;
283
//-----------------------------------------------------------------------------
284
// local code (see below)
285
//-----------------------------------------------------------------------------
287
// returns the child of win which currently has focus or NULL if not found
289
// Note: can't be static, needed by textctrl.cpp.
290
wxWindow *wxFindFocusedChild(wxWindowGTK *win)
292
wxWindow *winFocus = wxWindowGTK::FindFocus();
296
if ( winFocus == win )
297
return (wxWindow *)win;
299
for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
301
node = node->GetNext() )
303
wxWindow *child = wxFindFocusedChild(node->GetData());
311
static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
313
// wxUniversal widgets draw the borders and scrollbars themselves
314
#ifndef __WXUNIVERSAL__
321
if (win->m_hasScrolling)
323
GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
325
GtkRequisition vscroll_req;
326
vscroll_req.width = 2;
327
vscroll_req.height = 2;
328
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
329
(scroll_window->vscrollbar, &vscroll_req );
331
GtkRequisition hscroll_req;
332
hscroll_req.width = 2;
333
hscroll_req.height = 2;
334
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
335
(scroll_window->hscrollbar, &hscroll_req );
337
GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
339
if (scroll_window->vscrollbar_visible)
341
dw += vscroll_req.width;
342
dw += scroll_class->scrollbar_spacing;
345
if (scroll_window->hscrollbar_visible)
347
dh += hscroll_req.height;
348
dh += scroll_class->scrollbar_spacing;
354
if (GTK_WIDGET_NO_WINDOW (widget))
356
dx += widget->allocation.x;
357
dy += widget->allocation.y;
360
if (win->HasFlag(wxRAISED_BORDER))
362
gtk_draw_shadow( widget->style,
367
widget->allocation.width-dw, widget->allocation.height-dh );
371
if (win->HasFlag(wxSUNKEN_BORDER) || win->HasFlag(wxBORDER_THEME))
373
gtk_draw_shadow( widget->style,
378
widget->allocation.width-dw, widget->allocation.height-dh );
382
if (win->HasFlag(wxSIMPLE_BORDER))
385
gc = gdk_gc_new( widget->window );
386
gdk_gc_set_foreground( gc, &widget->style->black );
387
gdk_draw_rectangle( widget->window, gc, FALSE,
389
widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
393
#endif // __WXUNIVERSAL__
396
//-----------------------------------------------------------------------------
397
// "expose_event" of m_widget
398
//-----------------------------------------------------------------------------
401
static gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
403
if (gdk_event->count > 0) return FALSE;
405
draw_frame( widget, win );
411
//-----------------------------------------------------------------------------
412
// "draw" of m_widget
413
//-----------------------------------------------------------------------------
416
static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
418
draw_frame( widget, win );
422
//-----------------------------------------------------------------------------
423
// "size_request" of m_widget
424
//-----------------------------------------------------------------------------
426
// make it extern because wxStaticText needs to disconnect this one
428
void wxgtk_window_size_request_callback(GtkWidget *WXUNUSED(widget),
429
GtkRequisition *requisition,
433
win->GetSize( &w, &h );
439
requisition->height = h;
440
requisition->width = w;
446
void wxgtk_combo_size_request_callback(GtkWidget *WXUNUSED(widget),
447
GtkRequisition *requisition,
450
// This callback is actually hooked into the text entry
451
// of the combo box, not the GtkHBox.
454
win->GetSize( &w, &h );
460
GtkCombo *gcombo = GTK_COMBO(win->m_widget);
462
GtkRequisition entry_req;
464
entry_req.height = 2;
465
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
466
(gcombo->button, &entry_req );
468
requisition->width = w - entry_req.width;
469
requisition->height = entry_req.height;
473
//-----------------------------------------------------------------------------
474
// "expose_event" of m_wxwindow
475
//-----------------------------------------------------------------------------
478
static int gtk_window_expose_callback( GtkWidget *WXUNUSED(widget),
479
GdkEventExpose *gdk_event,
485
wxapp_install_idle_handler();
487
// This gets called immediately after an expose event
488
// under GTK 1.2 so we collect the calls and wait for
489
// the idle handler to pick things up.
491
win->GetUpdateRegion().Union( gdk_event->area.x,
493
gdk_event->area.width,
494
gdk_event->area.height );
495
win->m_clearRegion.Union( gdk_event->area.x,
497
gdk_event->area.width,
498
gdk_event->area.height );
500
// Actual redrawing takes place in idle time.
507
//-----------------------------------------------------------------------------
508
// "event" of m_wxwindow
509
//-----------------------------------------------------------------------------
511
// GTK thinks it is clever and filters out a certain amount of "unneeded"
512
// expose events. We need them, of course, so we override the main event
513
// procedure in GtkWidget by giving our own handler for all system events.
514
// There, we look for expose events ourselves whereas all other events are
519
gint gtk_window_event_event_callback( GtkWidget *widget,
520
GdkEventExpose *event,
523
if (event->type == GDK_EXPOSE)
525
gint ret = gtk_window_expose_callback( widget, event, win );
533
//-----------------------------------------------------------------------------
534
// "draw" of m_wxwindow
535
//-----------------------------------------------------------------------------
537
// This callback is a complete replacement of the gtk_pizza_draw() function,
538
// which is disabled.
541
static void gtk_window_draw_callback( GtkWidget *widget,
548
wxapp_install_idle_handler();
550
// if there are any children we must refresh everything
553
if ( !win->HasFlag(wxFULL_REPAINT_ON_RESIZE) &&
554
win->GetChildren().IsEmpty() )
562
wxPrintf( wxT("OnDraw from ") );
563
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
564
wxPrintf( win->GetClassInfo()->GetClassName() );
565
wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
572
#ifndef __WXUNIVERSAL__
573
GtkPizza *pizza = GTK_PIZZA (widget);
575
if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
577
wxWindow *parent = win->GetParent();
578
while (parent && !parent->IsTopLevel())
579
parent = parent->GetParent();
583
gtk_paint_flat_box (parent->m_widget->style,
594
win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
595
win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
597
// Update immediately, not in idle time.
600
#ifndef __WXUNIVERSAL__
601
// Redraw child widgets
602
GList *children = pizza->children;
605
GtkPizzaChild *child = (GtkPizzaChild*) children->data;
606
children = children->next;
608
GdkRectangle child_area;
609
if (gtk_widget_intersect (child->widget, rect, &child_area))
611
gtk_widget_draw (child->widget, &child_area /* NULL*/ );
618
//-----------------------------------------------------------------------------
619
// "key_press_event" from any window
620
//-----------------------------------------------------------------------------
622
// set WXTRACE to this to see the key event codes on the console
623
#define TRACE_KEYS wxT("keyevent")
625
// translates an X key symbol to WXK_XXX value
627
// if isChar is true it means that the value returned will be used for EVT_CHAR
628
// event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
629
// for example, while if it is false it means that the value is going to be
630
// used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
632
static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
638
// Shift, Control and Alt don't generate the CHAR events at all
641
key_code = isChar ? 0 : WXK_SHIFT;
645
key_code = isChar ? 0 : WXK_CONTROL;
653
key_code = isChar ? 0 : WXK_ALT;
656
// neither do the toggle modifies
657
case GDK_Scroll_Lock:
658
key_code = isChar ? 0 : WXK_SCROLL;
662
key_code = isChar ? 0 : WXK_CAPITAL;
666
key_code = isChar ? 0 : WXK_NUMLOCK;
670
// various other special keys
683
case GDK_ISO_Left_Tab:
690
key_code = WXK_RETURN;
694
key_code = WXK_CLEAR;
698
key_code = WXK_PAUSE;
702
key_code = WXK_SELECT;
706
key_code = WXK_PRINT;
710
key_code = WXK_EXECUTE;
714
key_code = WXK_ESCAPE;
717
// cursor and other extended keyboard keys
719
key_code = WXK_DELETE;
735
key_code = WXK_RIGHT;
742
case GDK_Prior: // == GDK_Page_Up
743
key_code = WXK_PAGEUP;
746
case GDK_Next: // == GDK_Page_Down
747
key_code = WXK_PAGEDOWN;
759
key_code = WXK_INSERT;
774
key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
778
key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
782
key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
786
key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
790
key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
794
key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
798
key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
802
key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
806
key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
810
key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
814
key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
818
key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
822
key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
825
case GDK_KP_Prior: // == GDK_KP_Page_Up
826
key_code = isChar ? WXK_PAGEUP : WXK_NUMPAD_PAGEUP;
829
case GDK_KP_Next: // == GDK_KP_Page_Down
830
key_code = isChar ? WXK_PAGEDOWN : WXK_NUMPAD_PAGEDOWN;
834
key_code = isChar ? WXK_END : WXK_NUMPAD_END;
838
key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
842
key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
846
key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
850
key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
853
case GDK_KP_Multiply:
854
key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
858
key_code = isChar ? '+' : WXK_NUMPAD_ADD;
861
case GDK_KP_Separator:
862
// FIXME: what is this?
863
key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
866
case GDK_KP_Subtract:
867
key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
871
key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
875
key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
892
key_code = WXK_F1 + keysym - GDK_F1;
902
static inline bool wxIsAsciiKeysym(KeySym ks)
907
static void wxFillOtherKeyEventFields(wxKeyEvent& event,
909
GdkEventKey *gdk_event)
913
GdkModifierType state;
914
if (gdk_event->window)
915
gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
917
event.SetTimestamp( gdk_event->time );
918
event.SetId(win->GetId());
919
event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
920
event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
921
event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
922
event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
923
event.m_rawCode = (wxUint32) gdk_event->keyval;
924
event.m_rawFlags = 0;
927
// this is not gtk1.x
928
event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
931
wxGetMousePosition( &x, &y );
932
win->ScreenToClient( &x, &y );
935
event.SetEventObject( win );
940
wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
942
GdkEventKey *gdk_event)
944
// VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
945
// but only event->keyval which is quite useless to us, so remember
946
// the last character from GDK_KEY_PRESS and reuse it as last resort
948
// NB: should be MT-safe as we're always called from the main thread only
953
} s_lastKeyPress = { 0, 0 };
955
KeySym keysym = gdk_event->keyval;
957
wxLogTrace(TRACE_KEYS, wxT("Key %s event: keysym = %ld"),
958
event.GetEventType() == wxEVT_KEY_UP ? wxT("release")
962
long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);
966
// do we have the translation or is it a plain ASCII character?
967
if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
969
// we should use keysym if it is ASCII as X does some translations
970
// like "I pressed while Control is down" => "Ctrl-I" == "TAB"
971
// which we don't want here (but which we do use for OnChar())
972
if ( !wxIsAsciiKeysym(keysym) )
974
keysym = (KeySym)gdk_event->string[0];
977
// we want to always get the same key code when the same key is
978
// pressed regardless of the state of the modifiers, i.e. on a
979
// standard US keyboard pressing '5' or '%' ('5' key with
980
// Shift) should result in the same key code in OnKeyDown():
981
// '5' (although OnChar() will get either '5' or '%').
983
// to do it we first translate keysym to keycode (== scan code)
984
// and then back but always using the lower register
985
Display *dpy = (Display *)wxGetDisplay();
986
KeyCode keycode = XKeysymToKeycode(dpy, keysym);
988
wxLogTrace(TRACE_KEYS, wxT("\t-> keycode %d"), keycode);
990
KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
992
// use the normalized, i.e. lower register, keysym if we've
994
key_code = keysymNormalized ? keysymNormalized : keysym;
996
// as explained above, we want to have lower register key codes
997
// normally but for the letter keys we want to have the upper ones
999
// NB: don't use XConvertCase() here, we want to do it for letters
1001
key_code = toupper(key_code);
1003
else // non ASCII key, what to do?
1005
// by default, ignore it
1008
// but if we have cached information from the last KEY_PRESS
1009
if ( gdk_event->type == GDK_KEY_RELEASE )
1012
if ( keysym == s_lastKeyPress.keysym )
1014
key_code = s_lastKeyPress.keycode;
1019
if ( gdk_event->type == GDK_KEY_PRESS )
1021
// remember it to be reused for KEY_UP event later
1022
s_lastKeyPress.keysym = keysym;
1023
s_lastKeyPress.keycode = key_code;
1027
wxLogTrace(TRACE_KEYS, wxT("\t-> wxKeyCode %ld"), key_code);
1029
// sending unknown key events doesn't really make sense
1033
// now fill all the other fields
1034
wxFillOtherKeyEventFields(event, win, gdk_event);
1036
event.m_keyCode = key_code;
1043
static gint gtk_window_key_press_callback( GtkWidget *widget,
1044
GdkEventKey *gdk_event,
1050
wxapp_install_idle_handler();
1054
if (g_blockEventsOnDrag)
1058
wxKeyEvent event( wxEVT_KEY_DOWN );
1060
bool return_after_IM = false;
1062
if ( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1064
// Emit KEY_DOWN event
1065
ret = win->HandleWindowEvent( event );
1069
// Return after IM processing as we cannot do
1070
// anything with it anyhow.
1071
return_after_IM = true;
1074
// This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1075
// in the "commit" handler.
1077
// 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1078
// In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1079
// keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1080
// composed of more than one character, which means gdk_event->length will always
1081
// greater than one. When gtk_event->length == 1, this may be an ASCII character
1082
// and can be translated by wx. However, when MBCS characters are sent by IM,
1083
// gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1084
// nor should we pass it to controls. The following explanation was excerpted
1085
// from GDK documentation.
1086
// gint length : the length of string.
1087
// gchar *string : a null-terminated multi-byte string containing the composed
1088
// characters resulting from the key press. When text is being input, in a GtkEntry
1089
// for example, it is these characters which should be added to the input buffer.
1090
// When using Input Methods to support internationalized text input, the composed
1091
// characters appear here after the pre-editing has been completed.
1093
if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
1095
// We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1096
#if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1097
const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
1101
const char* string = gdk_event->string;
1104
// Implement OnCharHook by checking ancestor top level windows
1105
wxWindow *parent = win;
1106
while (parent && !parent->IsTopLevel())
1107
parent = parent->GetParent();
1109
for( const wxChar* pstr = string; *pstr; pstr++ )
1112
event.m_uniChar = *pstr;
1113
// Backward compatible for ISO-8859-1
1114
event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1116
event.m_keyCode = *pstr;
1120
event.SetEventType( wxEVT_CHAR_HOOK );
1121
ret = parent->HandleWindowEvent( event );
1125
event.SetEventType(wxEVT_CHAR);
1126
win->HandleWindowEvent( event );
1132
if (return_after_IM)
1138
wxWindowGTK *ancestor = win;
1141
int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1144
wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1145
ret = ancestor->HandleWindowEvent( command_event );
1148
if (ancestor->IsTopLevel())
1150
ancestor = ancestor->GetParent();
1153
#endif // wxUSE_ACCEL
1155
// Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1156
// will only be sent if it is not in an accelerator table.
1160
KeySym keysym = gdk_event->keyval;
1161
// Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1162
key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
1165
if ( wxIsAsciiKeysym(keysym) )
1168
key_code = (unsigned char)keysym;
1170
// gdk_event->string is actually deprecated
1171
else if ( gdk_event->length == 1 )
1173
key_code = (unsigned char)gdk_event->string[0];
1179
wxLogTrace(TRACE_KEYS, wxT("Char event: %ld"), key_code);
1181
event.m_keyCode = key_code;
1183
// Implement OnCharHook by checking ancestor top level windows
1184
wxWindow *parent = win;
1185
while (parent && !parent->IsTopLevel())
1186
parent = parent->GetParent();
1189
event.SetEventType( wxEVT_CHAR_HOOK );
1190
ret = parent->HandleWindowEvent( event );
1195
event.SetEventType(wxEVT_CHAR);
1196
ret = win->HandleWindowEvent( event );
1205
// win is a control: tab can be propagated up
1207
((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1208
// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1209
// have this style, yet choose not to process this particular TAB in which
1210
// case TAB must still work as a navigational character
1211
// JS: enabling again to make consistent with other platforms
1212
// (with wxTE_PROCESS_TAB you have to call Navigate to get default
1213
// navigation behaviour)
1215
(! (win->HasFlag(wxTE_PROCESS_TAB) && win->IsKindOf(CLASSINFO(wxTextCtrl)) )) &&
1217
win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1219
wxNavigationKeyEvent new_event;
1220
new_event.SetEventObject( win->GetParent() );
1221
// GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1222
new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1223
// CTRL-TAB changes the (parent) window, i.e. switch notebook page
1224
new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1225
new_event.SetCurrentFocus( win );
1226
ret = win->GetParent()->HandleWindowEvent( new_event );
1229
// generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1231
(gdk_event->keyval == GDK_Escape) )
1233
// however only do it if we have a Cancel button in the dialog,
1234
// otherwise the user code may get confused by the events from a
1235
// non-existing button and, worse, a wxButton might get button event
1236
// from another button which is not really expected
1237
wxWindow *winForCancel = win,
1239
while ( winForCancel )
1241
btnCancel = winForCancel->FindWindow(wxID_CANCEL);
1244
// found a cancel button
1248
if ( winForCancel->IsTopLevel() )
1250
// no need to look further
1254
// maybe our parent has a cancel button?
1255
winForCancel = winForCancel->GetParent();
1260
wxCommandEvent eventClick(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
1261
eventClick.SetEventObject(btnCancel);
1262
ret = btnCancel->HandleWindowEvent(eventClick);
1268
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1276
//-----------------------------------------------------------------------------
1277
// "key_release_event" from any window
1278
//-----------------------------------------------------------------------------
1281
static gint gtk_window_key_release_callback( GtkWidget *widget,
1282
GdkEventKey *gdk_event,
1288
wxapp_install_idle_handler();
1293
if (g_blockEventsOnDrag)
1296
wxKeyEvent event( wxEVT_KEY_UP );
1297
if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1299
// unknown key pressed, ignore (the event would be useless anyhow)
1303
if ( !win->HandleWindowEvent( event ) )
1306
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1311
// ============================================================================
1313
// ============================================================================
1315
// ----------------------------------------------------------------------------
1316
// mouse event processing helpers
1317
// ----------------------------------------------------------------------------
1319
// init wxMouseEvent with the info from GdkEventXXX struct
1320
template<typename T> void InitMouseEvent(wxWindowGTK *win,
1321
wxMouseEvent& event,
1324
event.SetTimestamp( gdk_event->time );
1325
event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1326
event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1327
event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1328
event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1329
event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1330
event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1331
event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1332
if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1334
event.m_linesPerAction = 3;
1335
event.m_wheelDelta = 120;
1336
if (((GdkEventButton*)gdk_event)->button == 4)
1337
event.m_wheelRotation = 120;
1338
else if (((GdkEventButton*)gdk_event)->button == 5)
1339
event.m_wheelRotation = -120;
1342
wxPoint pt = win->GetClientAreaOrigin();
1343
event.m_x = (wxCoord)gdk_event->x - pt.x;
1344
event.m_y = (wxCoord)gdk_event->y - pt.y;
1346
event.SetEventObject( win );
1347
event.SetId( win->GetId() );
1348
event.SetTimestamp( gdk_event->time );
1351
static void AdjustEventButtonState(wxMouseEvent& event)
1353
// GDK reports the old state of the button for a button press event, but
1354
// for compatibility with MSW and common sense we want m_leftDown be true
1355
// for a LEFT_DOWN event, not FALSE, so we will invert
1356
// left/right/middleDown for the corresponding click events
1358
if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1359
(event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1360
(event.GetEventType() == wxEVT_LEFT_UP))
1362
event.m_leftDown = !event.m_leftDown;
1366
if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1367
(event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1368
(event.GetEventType() == wxEVT_MIDDLE_UP))
1370
event.m_middleDown = !event.m_middleDown;
1374
if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1375
(event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1376
(event.GetEventType() == wxEVT_RIGHT_UP))
1378
event.m_rightDown = !event.m_rightDown;
1383
// find the window to send the mouse event too
1385
wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1390
if (win->m_wxwindow)
1392
GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1393
xx += pizza->xoffset;
1394
yy += pizza->yoffset;
1397
wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
1400
wxWindowGTK *child = node->GetData();
1402
node = node->GetNext();
1403
if (!child->IsShown())
1406
if (child->IsTransparentForMouse())
1408
// wxStaticBox is transparent in the box itself
1409
int xx1 = child->m_x;
1410
int yy1 = child->m_y;
1411
int xx2 = child->m_x + child->m_width;
1412
int yy2 = child->m_y + child->m_height;
1415
if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
1417
((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
1419
((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
1421
((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
1432
if ((child->m_wxwindow == NULL) &&
1433
(child->m_x <= xx) &&
1434
(child->m_y <= yy) &&
1435
(child->m_x+child->m_width >= xx) &&
1436
(child->m_y+child->m_height >= yy))
1449
//-----------------------------------------------------------------------------
1450
// "button_press_event"
1451
//-----------------------------------------------------------------------------
1454
static gint gtk_window_button_press_callback( GtkWidget *widget,
1455
GdkEventButton *gdk_event,
1461
wxapp_install_idle_handler();
1464
wxPrintf( wxT("1) OnButtonPress from ") );
1465
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1466
wxPrintf( win->GetClassInfo()->GetClassName() );
1467
wxPrintf( wxT(".\n") );
1469
if (!win->m_hasVMT) return FALSE;
1470
if (g_blockEventsOnDrag) return TRUE;
1471
if (g_blockEventsOnScroll) return TRUE;
1473
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1475
g_lastButtonNumber = gdk_event->button;
1477
if (win->m_wxwindow && (g_focusWindow != win) && win->IsFocusable())
1479
gtk_widget_grab_focus( win->m_wxwindow );
1481
wxPrintf( wxT("GrabFocus from ") );
1482
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1483
wxPrintf( win->GetClassInfo()->GetClassName() );
1484
wxPrintf( wxT(".\n") );
1488
// GDK sends surplus button down events
1489
// before a double click event. We
1490
// need to filter these out.
1491
if (gdk_event->type == GDK_BUTTON_PRESS)
1493
GdkEvent *peek_event = gdk_event_peek();
1496
if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1497
(peek_event->type == GDK_3BUTTON_PRESS))
1499
gdk_event_free( peek_event );
1504
gdk_event_free( peek_event );
1509
wxEventType event_type = wxEVT_NULL;
1511
if (gdk_event->button == 1)
1513
// note that GDK generates triple click events which are not supported
1514
// by wxWidgets but still have to be passed to the app as otherwise
1515
// clicks would simply go missing
1516
switch (gdk_event->type)
1518
// we shouldn't get triple clicks at all for GTK2 because we
1519
// suppress them artificially using the code above but we still
1520
// should map them to something for GTK1 and not just ignore them
1521
// as this would lose clicks
1522
case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
1523
case GDK_BUTTON_PRESS:
1524
event_type = wxEVT_LEFT_DOWN;
1527
case GDK_2BUTTON_PRESS:
1528
event_type = wxEVT_LEFT_DCLICK;
1532
// just to silence gcc warnings
1536
else if (gdk_event->button == 2)
1538
switch (gdk_event->type)
1540
case GDK_3BUTTON_PRESS:
1541
case GDK_BUTTON_PRESS:
1542
event_type = wxEVT_MIDDLE_DOWN;
1545
case GDK_2BUTTON_PRESS:
1546
event_type = wxEVT_MIDDLE_DCLICK;
1553
else if (gdk_event->button == 3)
1555
switch (gdk_event->type)
1557
case GDK_3BUTTON_PRESS:
1558
case GDK_BUTTON_PRESS:
1559
event_type = wxEVT_RIGHT_DOWN;
1562
case GDK_2BUTTON_PRESS:
1563
event_type = wxEVT_RIGHT_DCLICK;
1570
else if (gdk_event->button == 4 || gdk_event->button == 5)
1572
if (gdk_event->type == GDK_BUTTON_PRESS )
1574
event_type = wxEVT_MOUSEWHEEL;
1578
if ( event_type == wxEVT_NULL )
1580
// unknown mouse button or click type
1584
g_lastMouseEvent = (GdkEvent*) gdk_event;
1586
wxMouseEvent event( event_type );
1587
InitMouseEvent( win, event, gdk_event );
1589
AdjustEventButtonState(event);
1591
// wxListBox actually gets mouse events from the item, so we need to give it
1592
// a chance to correct this
1593
win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1595
// find the correct window to send the event to: it may be a different one
1596
// from the one which got it at GTK+ level because some controls don't have
1597
// their own X window and thus cannot get any events.
1598
if ( !g_captureWindow )
1599
win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1601
wxGtkTimeLastClick = gdk_event->time;
1603
if (event_type == wxEVT_LEFT_DCLICK)
1605
// GTK 1.2 crashes when intercepting double
1606
// click events from both wxSpinButton and
1608
if (GTK_IS_SPIN_BUTTON(win->m_widget))
1610
// Just disable this event for now.
1615
if (win->HandleWindowEvent( event ))
1617
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1618
g_lastMouseEvent = NULL;
1621
g_lastMouseEvent = NULL;
1623
if (event_type == wxEVT_RIGHT_DOWN)
1625
// generate a "context menu" event: this is similar to right mouse
1626
// click under many GUIs except that it is generated differently
1627
// (right up under MSW, ctrl-click under Mac, right down here) and
1629
// (a) it's a command event and so is propagated to the parent
1630
// (b) under some ports it can be generated from kbd too
1631
// (c) it uses screen coords (because of (a))
1632
wxContextMenuEvent evtCtx(
1635
win->ClientToScreen(event.GetPosition()));
1636
evtCtx.SetEventObject(win);
1637
return win->HandleWindowEvent(evtCtx);
1644
//-----------------------------------------------------------------------------
1645
// "button_release_event"
1646
//-----------------------------------------------------------------------------
1649
static gint gtk_window_button_release_callback( GtkWidget *widget,
1650
GdkEventButton *gdk_event,
1656
wxapp_install_idle_handler();
1658
if (!win->m_hasVMT) return FALSE;
1659
if (g_blockEventsOnDrag) return FALSE;
1660
if (g_blockEventsOnScroll) return FALSE;
1662
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1664
g_lastButtonNumber = 0;
1666
wxEventType event_type = wxEVT_NULL;
1668
switch (gdk_event->button)
1671
event_type = wxEVT_LEFT_UP;
1675
event_type = wxEVT_MIDDLE_UP;
1679
event_type = wxEVT_RIGHT_UP;
1683
// unknown button, don't process
1687
g_lastMouseEvent = (GdkEvent*) gdk_event;
1689
wxMouseEvent event( event_type );
1690
InitMouseEvent( win, event, gdk_event );
1692
AdjustEventButtonState(event);
1694
// same wxListBox hack as above
1695
win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1697
if ( !g_captureWindow )
1698
win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1700
if (win->HandleWindowEvent( event ))
1702
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1710
//-----------------------------------------------------------------------------
1711
// "motion_notify_event"
1712
//-----------------------------------------------------------------------------
1715
static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1716
GdkEventMotion *gdk_event,
1722
wxapp_install_idle_handler();
1724
if (!win->m_hasVMT) return FALSE;
1725
if (g_blockEventsOnDrag) return FALSE;
1726
if (g_blockEventsOnScroll) return FALSE;
1728
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1730
if (gdk_event->is_hint)
1734
GdkModifierType state;
1735
gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1740
g_lastMouseEvent = (GdkEvent*) gdk_event;
1743
printf( "OnMotion from " );
1744
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1745
printf( win->GetClassInfo()->GetClassName() );
1749
wxMouseEvent event( wxEVT_MOTION );
1750
InitMouseEvent(win, event, gdk_event);
1752
if ( g_captureWindow )
1754
// synthetize a mouse enter or leave event if needed
1755
GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1756
// This seems to be necessary and actually been added to
1757
// GDK itself in version 2.0.X
1760
bool hasMouse = winUnderMouse == gdk_event->window;
1761
if ( hasMouse != g_captureWindowHasMouse )
1763
// the mouse changed window
1764
g_captureWindowHasMouse = hasMouse;
1766
wxMouseEvent eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1767
: wxEVT_LEAVE_WINDOW);
1768
InitMouseEvent(win, eventM, gdk_event);
1769
eventM.SetEventObject(win);
1770
win->HandleWindowEvent(eventM);
1775
win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1778
bool ret = win->HandleWindowEvent( event );
1779
g_lastMouseEvent = NULL;
1783
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1786
return ret ? TRUE : FALSE;
1790
//-----------------------------------------------------------------------------
1792
//-----------------------------------------------------------------------------
1794
// send the wxChildFocusEvent and wxFocusEvent, common code of
1795
// gtk_window_focus_in_callback() and SetFocus()
1796
static bool DoSendFocusEvents(wxWindow *win)
1798
// Notify the parent keeping track of focus for the kbd navigation
1799
// purposes that we got it.
1800
wxChildFocusEvent eventChildFocus(win);
1801
(void)win->HandleWindowEvent(eventChildFocus);
1803
wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
1804
eventFocus.SetEventObject(win);
1806
return win->HandleWindowEvent(eventFocus);
1810
static gint gtk_window_focus_in_callback( GtkWidget *widget,
1811
GdkEvent *WXUNUSED(event),
1817
wxapp_install_idle_handler();
1820
g_focusWindow = win;
1822
wxLogTrace(TRACE_FOCUS,
1823
wxT("%s: focus in"), win->GetName().c_str());
1827
gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1831
// caret needs to be informed about focus change
1832
wxCaret *caret = win->GetCaret();
1835
caret->OnSetFocus();
1837
#endif // wxUSE_CARET
1839
// does the window itself think that it has the focus?
1840
if ( !win->m_hasFocus )
1842
// not yet, notify it
1843
win->m_hasFocus = true;
1845
if ( DoSendFocusEvents(win) )
1847
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1856
//-----------------------------------------------------------------------------
1857
// "focus_out_event"
1858
//-----------------------------------------------------------------------------
1861
static gint gtk_window_focus_out_callback( GtkWidget *WXUNUSED(widget),
1862
GdkEventFocus *WXUNUSED(gdk_event),
1868
wxapp_install_idle_handler();
1870
wxLogTrace( TRACE_FOCUS,
1871
wxT("%s: focus out"), win->GetName().c_str() );
1874
wxWindowGTK *winFocus = wxFindFocusedChild(win);
1878
g_focusWindow = NULL;
1886
// caret needs to be informed about focus change
1887
wxCaret *caret = win->GetCaret();
1890
caret->OnKillFocus();
1892
#endif // wxUSE_CARET
1894
// don't send the window a kill focus event if it thinks that it doesn't
1895
// have focus already
1896
if ( win->m_hasFocus )
1898
win->m_hasFocus = false;
1900
wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1901
event.SetEventObject( win );
1903
// even if we did process the event in wx code, still let GTK itself
1904
// process it too as otherwise bad things happen, especially in GTK2
1905
// where the text control simply aborts the program if it doesn't get
1906
// the matching focus out event
1907
(void)win->HandleWindowEvent( event );
1914
//-----------------------------------------------------------------------------
1915
// "enter_notify_event"
1916
//-----------------------------------------------------------------------------
1920
gint gtk_window_enter_callback( GtkWidget *widget,
1921
GdkEventCrossing *gdk_event,
1927
wxapp_install_idle_handler();
1929
if (!win->m_hasVMT) return FALSE;
1930
if (g_blockEventsOnDrag) return FALSE;
1932
// Event was emitted after a grab
1933
if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
1935
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1939
GdkModifierType state = (GdkModifierType)0;
1941
gdk_window_get_pointer( widget->window, &x, &y, &state );
1943
wxMouseEvent event( wxEVT_ENTER_WINDOW );
1944
InitMouseEvent(win, event, gdk_event);
1945
wxPoint pt = win->GetClientAreaOrigin();
1946
event.m_x = x + pt.x;
1947
event.m_y = y + pt.y;
1949
if (win->HandleWindowEvent( event ))
1951
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1959
//-----------------------------------------------------------------------------
1960
// "leave_notify_event"
1961
//-----------------------------------------------------------------------------
1964
static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1969
wxapp_install_idle_handler();
1971
if (!win->m_hasVMT) return FALSE;
1972
if (g_blockEventsOnDrag) return FALSE;
1974
// Event was emitted after an ungrab
1975
if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
1977
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1979
wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1980
event.SetTimestamp( gdk_event->time );
1981
event.SetEventObject( win );
1985
GdkModifierType state = (GdkModifierType)0;
1987
gdk_window_get_pointer( widget->window, &x, &y, &state );
1989
event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
1990
event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
1991
event.m_altDown = (state & GDK_MOD1_MASK) != 0;
1992
event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
1993
event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
1994
event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
1995
event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
1997
wxPoint pt = win->GetClientAreaOrigin();
1998
event.m_x = x + pt.x;
1999
event.m_y = y + pt.y;
2001
if (win->HandleWindowEvent( event ))
2003
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
2011
//-----------------------------------------------------------------------------
2012
// "value_changed" from m_vAdjust
2013
//-----------------------------------------------------------------------------
2016
static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
2023
wxapp_install_idle_handler();
2025
if (g_blockEventsOnDrag) return;
2027
if (!win->m_hasVMT) return;
2029
float diff = adjust->value - win->m_oldVerticalPos;
2030
if (fabs(diff) < 0.2) return;
2032
win->m_oldVerticalPos = adjust->value;
2034
GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2035
wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
2037
int value = (int)(adjust->value+0.5);
2039
wxScrollWinEvent event( command, value, wxVERTICAL );
2040
event.SetEventObject( win );
2041
win->HandleWindowEvent( event );
2045
//-----------------------------------------------------------------------------
2046
// "value_changed" from m_hAdjust
2047
//-----------------------------------------------------------------------------
2050
static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
2057
wxapp_install_idle_handler();
2059
if (g_blockEventsOnDrag) return;
2060
if (!win->m_hasVMT) return;
2062
float diff = adjust->value - win->m_oldHorizontalPos;
2063
if (fabs(diff) < 0.2) return;
2065
GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2066
wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
2068
win->m_oldHorizontalPos = adjust->value;
2070
int value = (int)(adjust->value+0.5);
2072
wxScrollWinEvent event( command, value, wxHORIZONTAL );
2073
event.SetEventObject( win );
2074
win->HandleWindowEvent( event );
2078
//-----------------------------------------------------------------------------
2079
// "button_press_event" from scrollbar
2080
//-----------------------------------------------------------------------------
2083
static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
2084
GdkEventButton *gdk_event,
2090
wxapp_install_idle_handler();
2093
g_blockEventsOnScroll = true;
2095
// FIXME: there is no 'slider' field in GTK+ 2.0 any more
2096
win->m_isScrolling = (gdk_event->window == widget->slider);
2102
//-----------------------------------------------------------------------------
2103
// "button_release_event" from scrollbar
2104
//-----------------------------------------------------------------------------
2107
static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
2108
GdkEventButton *WXUNUSED(gdk_event),
2113
// don't test here as we can release the mouse while being over
2114
// a different window than the slider
2116
// if (gdk_event->window != widget->slider) return FALSE;
2118
g_blockEventsOnScroll = false;
2120
if (win->m_isScrolling)
2122
wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2126
GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2127
if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2129
value = (int)(win->m_hAdjust->value+0.5);
2132
if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2134
value = (int)(win->m_vAdjust->value+0.5);
2138
wxScrollWinEvent event( command, value, dir );
2139
event.SetEventObject( win );
2140
win->HandleWindowEvent( event );
2143
win->m_isScrolling = false;
2149
// ----------------------------------------------------------------------------
2150
// this wxWindowBase function is implemented here (in platform-specific file)
2151
// because it is static and so couldn't be made virtual
2152
// ----------------------------------------------------------------------------
2154
wxWindow *wxWindowBase::DoFindFocus()
2156
// the cast is necessary when we compile in wxUniversal mode
2157
return (wxWindow *)g_focusWindow;
2160
//-----------------------------------------------------------------------------
2161
// "realize" from m_widget
2162
//-----------------------------------------------------------------------------
2164
/* We cannot set colours and fonts before the widget has
2165
been realized, so we do this directly after realization. */
2169
gtk_window_realized_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
2174
wxapp_install_idle_handler();
2176
wxWindowCreateEvent event( win );
2177
event.SetEventObject( win );
2178
win->HandleWindowEvent( event );
2184
//-----------------------------------------------------------------------------
2186
//-----------------------------------------------------------------------------
2190
void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2191
GtkAllocation *WXUNUSED(alloc),
2195
wxapp_install_idle_handler();
2197
if (!win->m_hasScrolling) return;
2199
int client_width = 0;
2200
int client_height = 0;
2201
win->GetClientSize( &client_width, &client_height );
2202
if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2205
win->m_oldClientWidth = client_width;
2206
win->m_oldClientHeight = client_height;
2208
if (!win->m_nativeSizeEvent)
2210
wxSizeEvent event( win->GetSize(), win->GetId() );
2211
event.SetEventObject( win );
2212
win->HandleWindowEvent( event );
2219
#define WXUNUSED_UNLESS_XIM(param) param
2221
#define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2224
/* Resize XIM window */
2228
void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2229
GtkAllocation* WXUNUSED(alloc),
2230
wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
2233
wxapp_install_idle_handler();
2239
if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2243
gdk_window_get_size (widget->window, &width, &height);
2244
win->m_icattr->preedit_area.width = width;
2245
win->m_icattr->preedit_area.height = height;
2246
gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2252
//-----------------------------------------------------------------------------
2253
// "realize" from m_wxwindow
2254
//-----------------------------------------------------------------------------
2256
/* Initialize XIM support */
2260
gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2261
wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
2264
wxapp_install_idle_handler();
2267
if (win->m_ic) return FALSE;
2268
if (!widget) return FALSE;
2269
if (!gdk_im_ready()) return FALSE;
2271
win->m_icattr = gdk_ic_attr_new();
2272
if (!win->m_icattr) return FALSE;
2276
GdkColormap *colormap;
2277
GdkICAttr *attr = win->m_icattr;
2278
unsigned attrmask = GDK_IC_ALL_REQ;
2280
GdkIMStyle supported_style = (GdkIMStyle)
2281
(GDK_IM_PREEDIT_NONE |
2282
GDK_IM_PREEDIT_NOTHING |
2283
GDK_IM_PREEDIT_POSITION |
2284
GDK_IM_STATUS_NONE |
2285
GDK_IM_STATUS_NOTHING);
2287
if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2288
supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2290
attr->style = style = gdk_im_decide_style (supported_style);
2291
attr->client_window = widget->window;
2293
if ((colormap = gtk_widget_get_colormap (widget)) !=
2294
gtk_widget_get_default_colormap ())
2296
attrmask |= GDK_IC_PREEDIT_COLORMAP;
2297
attr->preedit_colormap = colormap;
2300
attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2301
attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2302
attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2303
attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2305
switch (style & GDK_IM_PREEDIT_MASK)
2307
case GDK_IM_PREEDIT_POSITION:
2308
if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2310
g_warning ("over-the-spot style requires fontset");
2314
gdk_window_get_size (widget->window, &width, &height);
2316
attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2317
attr->spot_location.x = 0;
2318
attr->spot_location.y = height;
2319
attr->preedit_area.x = 0;
2320
attr->preedit_area.y = 0;
2321
attr->preedit_area.width = width;
2322
attr->preedit_area.height = height;
2323
attr->preedit_fontset = widget->style->font;
2328
win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2330
if (win->m_ic == NULL)
2331
g_warning ("Can't create input context.");
2334
mask = gdk_window_get_events (widget->window);
2335
mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2336
gdk_window_set_events (widget->window, mask);
2338
if (GTK_WIDGET_HAS_FOCUS(widget))
2339
gdk_im_begin (win->m_ic, widget->window);
2347
//-----------------------------------------------------------------------------
2348
// InsertChild for wxWindowGTK.
2349
//-----------------------------------------------------------------------------
2351
/* Callback for wxWindowGTK. This very strange beast has to be used because
2352
* C++ has no virtual methods in a constructor. We have to emulate a
2353
* virtual function here as wxNotebook requires a different way to insert
2354
* a child in it. I had opted for creating a wxNotebookPage window class
2355
* which would have made this superfluous (such in the MDI window system),
2356
* but no-one was listening to me... */
2358
static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
2360
/* the window might have been scrolled already, do we
2361
have to adapt the position */
2362
GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2363
child->m_x += pizza->xoffset;
2364
child->m_y += pizza->yoffset;
2366
gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2367
GTK_WIDGET(child->m_widget),
2374
//-----------------------------------------------------------------------------
2376
//-----------------------------------------------------------------------------
2378
wxWindow *wxGetActiveWindow()
2380
return wxWindow::FindFocus();
2384
wxMouseState wxGetMouseState()
2390
GdkModifierType mask;
2392
gdk_window_get_pointer(NULL, &x, &y, &mask);
2396
ms.SetLeftDown(mask & GDK_BUTTON1_MASK);
2397
ms.SetMiddleDown(mask & GDK_BUTTON2_MASK);
2398
ms.SetRightDown(mask & GDK_BUTTON3_MASK);
2400
ms.SetControlDown(mask & GDK_CONTROL_MASK);
2401
ms.SetShiftDown(mask & GDK_SHIFT_MASK);
2402
ms.SetAltDown(mask & GDK_MOD1_MASK);
2403
ms.SetMetaDown(mask & GDK_MOD2_MASK);
2408
//-----------------------------------------------------------------------------
2410
//-----------------------------------------------------------------------------
2412
// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2414
#ifdef __WXUNIVERSAL__
2415
IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2416
#endif // __WXUNIVERSAL__
2418
void wxWindowGTK::Init()
2423
m_focusWidget = NULL;
2433
m_needParent = true;
2436
m_nativeSizeEvent = false;
2438
m_hasScrolling = false;
2439
m_isScrolling = false;
2443
m_oldHorizontalPos =
2444
m_oldVerticalPos = 0.0;
2446
m_oldClientHeight = 0;
2450
m_insertCallback = (wxInsertChildFunction) NULL;
2452
m_acceptsFocus = false;
2455
m_clipPaintRegion = false;
2457
m_needsStyleChange = false;
2459
m_cursor = *wxSTANDARD_CURSOR;
2467
wxWindowGTK::wxWindowGTK()
2472
wxWindowGTK::wxWindowGTK( wxWindow *parent,
2477
const wxString &name )
2481
Create( parent, id, pos, size, style, name );
2484
bool wxWindowGTK::Create( wxWindow *parent,
2489
const wxString &name )
2491
// Get default border
2492
wxBorder border = GetBorder(style);
2493
style &= ~wxBORDER_MASK;
2496
if (!PreCreation( parent, pos, size ) ||
2497
!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2499
wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2503
m_insertCallback = wxInsertChildInWindow;
2505
m_widget = gtk_scrolled_window_new( NULL, NULL );
2506
GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2508
GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2510
GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2511
scroll_class->scrollbar_spacing = 0;
2513
gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2515
m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2516
m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2518
m_wxwindow = gtk_pizza_new();
2520
#ifndef __WXUNIVERSAL__
2521
GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2523
if (HasFlag(wxRAISED_BORDER))
2525
gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2527
else if (HasFlag(wxSUNKEN_BORDER) || HasFlag(wxBORDER_THEME))
2529
gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2531
else if (HasFlag(wxSIMPLE_BORDER))
2533
gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2537
gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2539
#endif // __WXUNIVERSAL__
2541
gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2543
GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2544
m_acceptsFocus = true;
2546
// I _really_ don't want scrollbars in the beginning
2547
m_vAdjust->lower = 0.0;
2548
m_vAdjust->upper = 1.0;
2549
m_vAdjust->value = 0.0;
2550
m_vAdjust->step_increment = 1.0;
2551
m_vAdjust->page_increment = 1.0;
2552
m_vAdjust->page_size = 5.0;
2553
gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2554
m_hAdjust->lower = 0.0;
2555
m_hAdjust->upper = 1.0;
2556
m_hAdjust->value = 0.0;
2557
m_hAdjust->step_increment = 1.0;
2558
m_hAdjust->page_increment = 1.0;
2559
m_hAdjust->page_size = 5.0;
2560
gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2562
// these handlers block mouse events to any window during scrolling such as
2563
// motion events and prevent GTK and wxWidgets from fighting over where the
2566
gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2567
(GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2569
gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2570
(GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2572
gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2573
(GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2575
gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2576
(GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2578
// these handlers get notified when screen updates are required either when
2579
// scrolling or when the window size (and therefore scrollbar configuration)
2582
gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2583
(GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2584
gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2585
(GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2587
gtk_widget_show( m_wxwindow );
2590
m_parent->DoAddChild( this );
2592
m_focusWidget = m_wxwindow;
2599
wxWindowGTK::~wxWindowGTK()
2603
if (g_focusWindow == this)
2604
g_focusWindow = NULL;
2606
if ( g_delayedFocus == this )
2607
g_delayedFocus = NULL;
2611
// destroy children before destroying this window itself
2614
// unhook focus handlers to prevent stray events being
2615
// propagated to this (soon to be) dead object
2616
if (m_focusWidget != NULL)
2618
gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget),
2619
(GtkSignalFunc) gtk_window_focus_in_callback, (gpointer) this );
2620
gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget),
2621
(GtkSignalFunc) gtk_window_focus_out_callback, (gpointer) this );
2629
gdk_ic_destroy (m_ic);
2631
gdk_ic_attr_destroy (m_icattr);
2636
gtk_widget_destroy( m_wxwindow );
2642
gtk_widget_destroy( m_widget );
2647
bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2649
wxCHECK_MSG( !m_needParent || parent, false, wxT("Need complete parent.") );
2651
// Use either the given size, or the default if -1 is given.
2652
// See wxWindowBase for these functions.
2653
m_width = WidthDefault(size.x) ;
2654
m_height = HeightDefault(size.y);
2662
void wxWindowGTK::PostCreation()
2664
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2670
// these get reported to wxWidgets -> wxPaintEvent
2672
gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2674
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2675
GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2677
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2678
GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2680
if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
2682
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2683
GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2687
// these are called when the "sunken" or "raised" borders are drawn
2688
gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2689
GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2691
gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2692
GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2697
if (!GTK_IS_WINDOW(m_widget))
2699
if (m_focusWidget == NULL)
2700
m_focusWidget = m_widget;
2702
gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2703
GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2705
gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
2706
GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2709
// connect to the various key and mouse handlers
2711
GtkWidget *connect_widget = GetConnectWidget();
2713
ConnectWidget( connect_widget );
2715
/* We cannot set colours, fonts and cursors before the widget has
2716
been realized, so we do this directly after realization */
2717
gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2718
GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2722
// Catch native resize events
2723
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2724
GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2726
// Initialize XIM support
2727
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2728
GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2730
// And resize XIM window
2731
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2732
GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2735
if (GTK_IS_COMBO(m_widget))
2737
GtkCombo *gcombo = GTK_COMBO(m_widget);
2739
gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
2740
GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
2745
// This is needed if we want to add our windows into native
2746
// GTK controls, such as the toolbar. With this callback, the
2747
// toolbar gets to know the correct size (the one set by the
2748
// programmer). Sadly, it misbehaves for wxComboBox.
2749
gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2750
GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
2754
InheritAttributes();
2758
// unless the window was created initially hidden (i.e. Hide() had been
2759
// called before Create()), we should show it at GTK+ level as well
2761
gtk_widget_show( m_widget );
2764
void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2766
gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2767
GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2769
gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2770
GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2772
gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2773
GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2775
gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2776
GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2778
gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2779
GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2781
gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2782
GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2784
gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2785
GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2788
bool wxWindowGTK::Destroy()
2790
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2794
return wxWindowBase::Destroy();
2797
void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
2799
gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2802
void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2804
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2805
wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
2808
printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2811
if (m_resizing) return; /* I don't like recursions */
2814
int currentX, currentY;
2815
GetPosition(¤tX, ¤tY);
2816
if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
2818
if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
2820
AdjustForParentClientOrigin(x, y, sizeFlags);
2822
if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2824
/* don't set the size for children of wxNotebook, just take the values. */
2832
GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2833
if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2835
if (x != -1) m_x = x + pizza->xoffset;
2836
if (y != -1) m_y = y + pizza->yoffset;
2840
m_x = x + pizza->xoffset;
2841
m_y = y + pizza->yoffset;
2844
// calculate the best size if we should auto size the window
2845
if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
2846
((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
2848
const wxSize sizeBest = GetBestSize();
2849
if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
2851
if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
2852
height = sizeBest.y;
2860
int minWidth = GetMinWidth(),
2861
minHeight = GetMinHeight(),
2862
maxWidth = GetMaxWidth(),
2863
maxHeight = GetMaxHeight();
2865
if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
2866
if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2867
if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
2868
if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
2870
int left_border = 0;
2871
int right_border = 0;
2873
int bottom_border = 0;
2875
/* the default button has a border around it */
2876
if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2884
DoMoveWindow( m_x-top_border,
2886
m_width+left_border+right_border,
2887
m_height+top_border+bottom_border );
2892
/* Sometimes the client area changes size without the
2893
whole windows's size changing, but if the whole
2894
windows's size doesn't change, no wxSizeEvent will
2895
normally be sent. Here we add an extra test if
2896
the client test has been changed and this will
2898
GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2902
wxPrintf( "OnSize sent from " );
2903
if (GetClassInfo() && GetClassInfo()->GetClassName())
2904
wxPrintf( GetClassInfo()->GetClassName() );
2905
wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2908
if (!m_nativeSizeEvent)
2910
wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2911
event.SetEventObject( this );
2912
HandleWindowEvent( event );
2918
void wxWindowGTK::OnInternalIdle()
2920
// Update style if the window was not yet realized
2921
// and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
2922
if (m_needsStyleChange)
2924
SetBackgroundStyle(GetBackgroundStyle());
2925
m_needsStyleChange = false;
2928
// Update invalidated regions.
2931
wxCursor cursor = m_cursor;
2932
if (g_globalCursor.IsOk()) cursor = g_globalCursor;
2936
/* I now set the cursor anew in every OnInternalIdle call
2937
as setting the cursor in a parent window also effects the
2938
windows above so that checking for the current cursor is
2943
GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2945
gdk_window_set_cursor( window, cursor.GetCursor() );
2947
if (!g_globalCursor.IsOk())
2948
cursor = *wxSTANDARD_CURSOR;
2950
window = m_widget->window;
2951
if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2952
gdk_window_set_cursor( window, cursor.GetCursor() );
2955
else if ( m_widget )
2957
GdkWindow *window = m_widget->window;
2958
if ( window && !GTK_WIDGET_NO_WINDOW(m_widget) )
2959
gdk_window_set_cursor( window, cursor.GetCursor() );
2963
wxWindowBase::OnInternalIdle();
2966
void wxWindowGTK::DoGetSize( int *width, int *height ) const
2968
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2970
if (width) (*width) = m_width;
2971
if (height) (*height) = m_height;
2974
void wxWindowGTK::DoSetClientSize( int width, int height )
2976
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2980
SetSize( width, height );
2987
#ifndef __WXUNIVERSAL__
2988
if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER) || HasFlag(wxBORDER_THEME))
2990
/* when using GTK 1.2 we set the shadow border size to 2 */
2994
if (HasFlag(wxSIMPLE_BORDER))
2996
/* when using GTK 1.2 we set the simple border size to 1 */
3000
#endif // __WXUNIVERSAL__
3004
GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3006
GtkRequisition vscroll_req;
3007
vscroll_req.width = 2;
3008
vscroll_req.height = 2;
3009
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3010
(scroll_window->vscrollbar, &vscroll_req );
3012
GtkRequisition hscroll_req;
3013
hscroll_req.width = 2;
3014
hscroll_req.height = 2;
3015
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3016
(scroll_window->hscrollbar, &hscroll_req );
3018
GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3020
if (scroll_window->vscrollbar_visible)
3022
dw += vscroll_req.width;
3023
dw += scroll_class->scrollbar_spacing;
3026
if (scroll_window->hscrollbar_visible)
3028
dh += hscroll_req.height;
3029
dh += scroll_class->scrollbar_spacing;
3033
SetSize( width+dw, height+dh );
3037
void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
3039
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3043
if (width) (*width) = m_width;
3044
if (height) (*height) = m_height;
3051
#ifndef __WXUNIVERSAL__
3052
if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER) || HasFlag(wxBORDER_THEME))
3054
/* when using GTK 1.2 we set the shadow border size to 2 */
3058
if (HasFlag(wxSIMPLE_BORDER))
3060
/* when using GTK 1.2 we set the simple border size to 1 */
3064
#endif // __WXUNIVERSAL__
3068
GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3070
GtkRequisition vscroll_req;
3071
vscroll_req.width = 2;
3072
vscroll_req.height = 2;
3073
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3074
(scroll_window->vscrollbar, &vscroll_req );
3076
GtkRequisition hscroll_req;
3077
hscroll_req.width = 2;
3078
hscroll_req.height = 2;
3079
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3080
(scroll_window->hscrollbar, &hscroll_req );
3082
GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3084
if (scroll_window->vscrollbar_visible)
3086
dw += vscroll_req.width;
3087
dw += scroll_class->scrollbar_spacing;
3090
if (scroll_window->hscrollbar_visible)
3092
dh += hscroll_req.height;
3093
dh += scroll_class->scrollbar_spacing;
3097
if (width) (*width) = m_width - dw;
3098
if (height) (*height) = m_height - dh;
3102
printf( "GetClientSize, name %s ", GetName().c_str() );
3103
if (width) printf( " width = %d", (*width) );
3104
if (height) printf( " height = %d", (*height) );
3109
void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3111
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3115
if (m_parent && m_parent->m_wxwindow)
3117
GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3118
dx = pizza->xoffset;
3119
dy = pizza->yoffset;
3122
if (x) (*x) = m_x - dx;
3123
if (y) (*y) = m_y - dy;
3126
void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3128
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3130
if (!m_widget->window) return;
3132
GdkWindow *source = NULL;
3134
source = GTK_PIZZA(m_wxwindow)->bin_window;
3136
source = m_widget->window;
3140
gdk_window_get_origin( source, &org_x, &org_y );
3144
if (GTK_WIDGET_NO_WINDOW (m_widget))
3146
org_x += m_widget->allocation.x;
3147
org_y += m_widget->allocation.y;
3155
void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3157
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3159
if (!m_widget->window) return;
3161
GdkWindow *source = NULL;
3163
source = GTK_PIZZA(m_wxwindow)->bin_window;
3165
source = m_widget->window;
3169
gdk_window_get_origin( source, &org_x, &org_y );
3173
if (GTK_WIDGET_NO_WINDOW (m_widget))
3175
org_x += m_widget->allocation.x;
3176
org_y += m_widget->allocation.y;
3184
bool wxWindowGTK::Show( bool show )
3186
wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3188
if (!wxWindowBase::Show(show))
3195
gtk_widget_show( m_widget );
3197
gtk_widget_hide( m_widget );
3199
wxShowEvent eventShow(GetId(), show);
3200
eventShow.SetEventObject(this);
3202
HandleWindowEvent(eventShow);
3207
void wxWindowGTK::DoEnable( bool enable )
3209
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3211
gtk_widget_set_sensitive( m_widget, enable );
3213
gtk_widget_set_sensitive( m_wxwindow, enable );
3216
int wxWindowGTK::GetCharHeight() const
3218
wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3220
wxFont font = GetFont();
3221
wxCHECK_MSG( font.IsOk(), 12, wxT("invalid font") );
3223
GdkFont *gfont = font.GetInternalFont( 1.0 );
3225
return gfont->ascent + gfont->descent;
3228
int wxWindowGTK::GetCharWidth() const
3230
wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3232
wxFont font = GetFont();
3233
wxCHECK_MSG( font.IsOk(), 8, wxT("invalid font") );
3235
GdkFont *gfont = font.GetInternalFont( 1.0 );
3237
return gdk_string_width( gfont, "g" );
3240
void wxWindowGTK::DoGetTextExtent(const wxString& string,
3244
int *externalLeading,
3245
const wxFont *theFont) const
3247
wxFont fontToUse = theFont ? *theFont : GetFont();
3249
wxCHECK_RET( fontToUse.IsOk(), wxT("invalid font") );
3258
GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3259
if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
3260
if (y) (*y) = font->ascent + font->descent;
3261
if (descent) (*descent) = font->descent;
3262
if (externalLeading) (*externalLeading) = 0; // ??
3265
void wxWindowGTK::SetFocus()
3267
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3270
// don't do anything if we already have focus
3276
if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3278
gtk_widget_grab_focus (m_wxwindow);
3283
if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3286
if (!GTK_WIDGET_REALIZED(m_widget))
3288
// we can't set the focus to the widget now so we remember that
3289
// it should be focused and will do it later, during the idle
3290
// time, as soon as we can
3291
wxLogTrace(TRACE_FOCUS,
3292
wxT("Delaying setting focus to %s(%s)"),
3293
GetClassInfo()->GetClassName(), GetLabel().c_str());
3295
g_delayedFocus = this;
3299
wxLogTrace(TRACE_FOCUS,
3300
wxT("Setting focus to %s(%s)"),
3301
GetClassInfo()->GetClassName(), GetLabel().c_str());
3303
gtk_widget_grab_focus (m_widget);
3307
if (GTK_IS_CONTAINER(m_widget))
3309
gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3313
wxLogTrace(TRACE_FOCUS,
3314
wxT("Can't set focus to %s(%s)"),
3315
GetClassInfo()->GetClassName(), GetLabel().c_str());
3320
bool wxWindowGTK::AcceptsFocus() const
3322
return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3325
bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3327
wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3329
wxWindowGTK *oldParent = m_parent,
3330
*newParent = (wxWindowGTK *)newParentBase;
3332
wxASSERT( GTK_IS_WIDGET(m_widget) );
3334
if ( !wxWindowBase::Reparent(newParent) )
3337
wxASSERT( GTK_IS_WIDGET(m_widget) );
3339
/* prevent GTK from deleting the widget arbitrarily */
3340
gtk_widget_ref( m_widget );
3344
gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3347
wxASSERT( GTK_IS_WIDGET(m_widget) );
3351
/* insert GTK representation */
3352
(*(newParent->m_insertCallback))(newParent, this);
3355
/* reverse: prevent GTK from deleting the widget arbitrarily */
3356
gtk_widget_unref( m_widget );
3361
void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3363
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3365
wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3367
wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3372
/* insert GTK representation */
3373
(*m_insertCallback)(this, child);
3376
void wxWindowGTK::Raise()
3378
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3380
if (m_wxwindow && m_wxwindow->window)
3382
gdk_window_raise( m_wxwindow->window );
3384
else if (m_widget->window)
3386
gdk_window_raise( m_widget->window );
3390
void wxWindowGTK::Lower()
3392
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3394
if (m_wxwindow && m_wxwindow->window)
3396
gdk_window_lower( m_wxwindow->window );
3398
else if (m_widget->window)
3400
gdk_window_lower( m_widget->window );
3404
bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3406
wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3408
if ( cursor.IsSameAs(m_cursor) )
3412
wxapp_install_idle_handler();
3414
return wxWindowBase::SetCursor( cursor.IsOk() ? cursor
3415
: *wxSTANDARD_CURSOR );
3418
void wxWindowGTK::WarpPointer( int x, int y )
3420
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3422
// We provide this function ourselves as it is
3423
// missing in GDK (top of this file).
3425
GdkWindow *window = NULL;
3427
window = GTK_PIZZA(m_wxwindow)->bin_window;
3429
window = GetConnectWidget()->window;
3432
gdk_window_warp_pointer( window, x, y );
3436
void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3440
if (!m_widget->window)
3444
wxapp_install_idle_handler();
3447
if (m_wxwindow && rect)
3449
myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3450
m_wxwindow->allocation.height));
3451
if ( myRect.Intersect(*rect).IsEmpty() )
3453
// nothing to do, rectangle is empty
3460
// schedule the area for later updating in GtkUpdate()
3461
if (eraseBackground && m_wxwindow && m_wxwindow->window)
3465
m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
3469
m_clearRegion.Clear();
3470
m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3478
m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
3482
GdkRectangle gdk_rect;
3483
gdk_rect.x = rect->x;
3484
gdk_rect.y = rect->y;
3485
gdk_rect.width = rect->width;
3486
gdk_rect.height = rect->height;
3487
gtk_widget_draw( m_widget, &gdk_rect );
3494
m_updateRegion.Clear();
3495
m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3499
gtk_widget_draw( m_widget, NULL );
3504
void wxWindowGTK::Update()
3508
// when we call Update() we really want to update the window immediately on
3509
// screen, even if it means flushing the entire queue and hence slowing down
3510
// everything -- but it should still be done, it's just that Update() should
3511
// be called very rarely
3515
void wxWindowGTK::GtkUpdate()
3517
if (!m_updateRegion.IsEmpty())
3518
GtkSendPaintEvents();
3520
// for consistency with other platforms (and also because it's convenient
3521
// to be able to update an entire TLW by calling Update() only once), we
3522
// should also update all our children here
3523
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3525
node = node->GetNext() )
3527
node->GetData()->GtkUpdate();
3531
void wxWindowGTK::GtkSendPaintEvents()
3535
m_clearRegion.Clear();
3536
m_updateRegion.Clear();
3540
// Clip to paint region in wxClientDC
3541
m_clipPaintRegion = true;
3543
// widget to draw on
3544
GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
3546
if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
3548
// find ancestor from which to steal background
3549
wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
3551
parent = (wxWindow*)this;
3553
if (GTK_WIDGET_MAPPED(parent->m_widget))
3555
wxRegionIterator upd( m_updateRegion );
3559
rect.x = upd.GetX();
3560
rect.y = upd.GetY();
3561
rect.width = upd.GetWidth();
3562
rect.height = upd.GetHeight();
3564
gtk_paint_flat_box( parent->m_widget->style,
3566
(GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
3577
else // Always send an erase event under GTK 1.2
3579
wxWindowDC dc( (wxWindow*)this );
3580
dc.SetDeviceClippingRegion( m_clearRegion.IsEmpty() ? m_updateRegion
3583
wxEraseEvent erase_event( GetId(), &dc );
3584
erase_event.SetEventObject( this );
3586
if (!HandleWindowEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
3590
g_eraseGC = gdk_gc_new( pizza->bin_window );
3591
gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
3593
gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
3595
wxRegionIterator upd( m_clearRegion );
3598
gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
3599
upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
3603
m_clearRegion.Clear();
3606
wxNcPaintEvent nc_paint_event( GetId() );
3607
nc_paint_event.SetEventObject( this );
3608
HandleWindowEvent( nc_paint_event );
3610
wxPaintEvent paint_event( GetId() );
3611
paint_event.SetEventObject( this );
3612
HandleWindowEvent( paint_event );
3614
m_clipPaintRegion = false;
3616
#if !defined(__WXUNIVERSAL__)
3617
// The following code will result in all window-less widgets
3618
// being redrawn because the wxWidgets class is allowed to
3619
// paint over the window-less widgets.
3621
GList *children = pizza->children;
3624
GtkPizzaChild *child = (GtkPizzaChild*) children->data;
3625
children = children->next;
3627
if (GTK_WIDGET_NO_WINDOW (child->widget) &&
3628
GTK_WIDGET_DRAWABLE (child->widget))
3630
// Get intersection of widget area and update region
3631
wxRegion region( m_updateRegion );
3633
GdkEventExpose gdk_event;
3634
gdk_event.type = GDK_EXPOSE;
3635
gdk_event.window = pizza->bin_window;
3636
gdk_event.count = 0;
3637
gdk_event.send_event = TRUE;
3639
wxRegionIterator upd( m_updateRegion );
3643
rect.x = upd.GetX();
3644
rect.y = upd.GetY();
3645
rect.width = upd.GetWidth();
3646
rect.height = upd.GetHeight();
3648
if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
3650
gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
3657
#endif // native GTK 1
3659
m_updateRegion.Clear();
3662
void wxWindowGTK::ClearBackground()
3664
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3666
if (m_wxwindow && m_wxwindow->window)
3668
m_clearRegion.Clear();
3669
wxSize size( GetClientSize() );
3670
m_clearRegion.Union( 0,0,size.x,size.y );
3672
// Better do this in idle?
3678
void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
3680
wxWindowBase::DoSetToolTip(tip);
3683
m_tooltip->Apply( (wxWindow *)this );
3686
void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3688
wxString tmp( tip );
3689
gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), NULL );
3691
#endif // wxUSE_TOOLTIPS
3693
bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
3695
wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
3697
if (!wxWindowBase::SetBackgroundColour(colour))
3702
// We need the pixel value e.g. for background clearing.
3703
m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
3706
// apply style change (forceStyle=true so that new style is applied
3707
// even if the bg colour changed from valid to wxNullColour)
3708
if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
3709
ApplyWidgetStyle(true);
3714
bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
3716
wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
3718
if (!wxWindowBase::SetForegroundColour(colour))
3725
// We need the pixel value e.g. for background clearing.
3726
m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
3729
// apply style change (forceStyle=true so that new style is applied
3730
// even if the bg colour changed from valid to wxNullColour):
3731
ApplyWidgetStyle(true);
3736
GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
3738
// do we need to apply any changes at all?
3741
!m_foregroundColour.IsOk() && !m_backgroundColour.IsOk() )
3746
GtkRcStyle *style = gtk_rc_style_new();
3748
if ( m_font.IsOk() )
3750
wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
3751
style->fontset_name = g_strdup(xfontname.c_str());
3754
if ( m_foregroundColour.IsOk() )
3756
GdkColor *fg = m_foregroundColour.GetColor();
3758
style->fg[GTK_STATE_NORMAL] = *fg;
3759
style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
3761
style->fg[GTK_STATE_PRELIGHT] = *fg;
3762
style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
3764
style->fg[GTK_STATE_ACTIVE] = *fg;
3765
style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
3768
if ( m_backgroundColour.IsOk() )
3770
GdkColor *bg = m_backgroundColour.GetColor();
3772
style->bg[GTK_STATE_NORMAL] = *bg;
3773
style->base[GTK_STATE_NORMAL] = *bg;
3774
style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
3775
(style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
3777
style->bg[GTK_STATE_PRELIGHT] = *bg;
3778
style->base[GTK_STATE_PRELIGHT] = *bg;
3779
style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
3780
(style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
3782
style->bg[GTK_STATE_ACTIVE] = *bg;
3783
style->base[GTK_STATE_ACTIVE] = *bg;
3784
style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
3785
(style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
3787
style->bg[GTK_STATE_INSENSITIVE] = *bg;
3788
style->base[GTK_STATE_INSENSITIVE] = *bg;
3789
style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
3790
(style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
3796
void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
3798
GtkRcStyle *style = CreateWidgetStyle(forceStyle);
3801
DoApplyWidgetStyle(style);
3802
gtk_rc_style_unref(style);
3805
// Style change may affect GTK+'s size calculation:
3806
InvalidateBestSize();
3809
void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
3812
gtk_widget_modify_style(m_wxwindow, style);
3814
gtk_widget_modify_style(m_widget, style);
3817
bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
3819
wxWindowBase::SetBackgroundStyle(style);
3821
if (style == wxBG_STYLE_CUSTOM)
3823
GdkWindow *window = NULL;
3825
window = GTK_PIZZA(m_wxwindow)->bin_window;
3827
window = GetConnectWidget()->window;
3831
// Make sure GDK/X11 doesn't refresh the window
3833
gdk_window_set_back_pixmap( window, None, False );
3835
Display* display = GDK_WINDOW_DISPLAY(window);
3838
m_needsStyleChange = false;
3841
// Do in OnIdle, because the window is not yet available
3842
m_needsStyleChange = true;
3844
// Don't apply widget style, or we get a grey background
3848
// apply style change (forceStyle=true so that new style is applied
3849
// even if the bg colour changed from valid to wxNullColour):
3850
ApplyWidgetStyle(true);
3855
#if wxUSE_DRAG_AND_DROP
3857
void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
3859
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3861
GtkWidget *dnd_widget = GetConnectWidget();
3863
if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3865
if (m_dropTarget) delete m_dropTarget;
3866
m_dropTarget = dropTarget;
3868
if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3871
#endif // wxUSE_DRAG_AND_DROP
3873
GtkWidget* wxWindowGTK::GetConnectWidget()
3875
GtkWidget *connect_widget = m_widget;
3876
if (m_wxwindow) connect_widget = m_wxwindow;
3878
return connect_widget;
3881
bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
3884
return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3886
return (window == m_widget->window);
3889
bool wxWindowGTK::SetFont( const wxFont &font )
3891
wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
3893
if (!wxWindowBase::SetFont(font))
3896
// apply style change (forceStyle=true so that new style is applied
3897
// even if the font changed from valid to wxNullFont):
3898
ApplyWidgetStyle(true);
3903
void wxWindowGTK::DoCaptureMouse()
3905
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3907
GdkWindow *window = NULL;
3909
window = GTK_PIZZA(m_wxwindow)->bin_window;
3911
window = GetConnectWidget()->window;
3913
wxCHECK_RET( window, wxT("CaptureMouse() failed") );
3915
const wxCursor* cursor = &m_cursor;
3916
if (!cursor->IsOk())
3917
cursor = wxSTANDARD_CURSOR;
3919
gdk_pointer_grab( window, FALSE,
3921
(GDK_BUTTON_PRESS_MASK |
3922
GDK_BUTTON_RELEASE_MASK |
3923
GDK_POINTER_MOTION_HINT_MASK |
3924
GDK_POINTER_MOTION_MASK),
3926
cursor->GetCursor(),
3927
(guint32)GDK_CURRENT_TIME );
3928
g_captureWindow = this;
3929
g_captureWindowHasMouse = true;
3932
void wxWindowGTK::DoReleaseMouse()
3934
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3936
wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
3938
g_captureWindow = NULL;
3940
GdkWindow *window = NULL;
3942
window = GTK_PIZZA(m_wxwindow)->bin_window;
3944
window = GetConnectWidget()->window;
3949
gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3953
wxWindow *wxWindowBase::GetCapture()
3955
return (wxWindow *)g_captureWindow;
3958
bool wxWindowGTK::IsRetained() const
3963
void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
3964
int range, bool refresh )
3966
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3968
wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3970
m_hasScrolling = true;
3972
if (orient == wxHORIZONTAL)
3974
float fpos = (float)pos;
3975
float frange = (float)range;
3976
float fthumb = (float)thumbVisible;
3977
if (fpos > frange-fthumb) fpos = frange-fthumb;
3978
if (fpos < 0.0) fpos = 0.0;
3980
if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3981
(fabs(fthumb-m_hAdjust->page_size) < 0.2))
3983
SetScrollPos( orient, pos, refresh );
3987
m_oldHorizontalPos = fpos;
3989
m_hAdjust->lower = 0.0;
3990
m_hAdjust->upper = frange;
3991
m_hAdjust->value = fpos;
3992
m_hAdjust->step_increment = 1.0;
3993
m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3994
m_hAdjust->page_size = fthumb;
3998
float fpos = (float)pos;
3999
float frange = (float)range;
4000
float fthumb = (float)thumbVisible;
4001
if (fpos > frange-fthumb) fpos = frange-fthumb;
4002
if (fpos < 0.0) fpos = 0.0;
4004
if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4005
(fabs(fthumb-m_vAdjust->page_size) < 0.2))
4007
SetScrollPos( orient, pos, refresh );
4011
m_oldVerticalPos = fpos;
4013
m_vAdjust->lower = 0.0;
4014
m_vAdjust->upper = frange;
4015
m_vAdjust->value = fpos;
4016
m_vAdjust->step_increment = 1.0;
4017
m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4018
m_vAdjust->page_size = fthumb;
4021
if (orient == wxHORIZONTAL)
4022
gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4024
gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
4027
void wxWindowGTK::GtkUpdateScrollbar(int orient)
4029
GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
4030
GtkSignalFunc fn = orient == wxHORIZONTAL
4031
? (GtkSignalFunc)gtk_window_hscroll_callback
4032
: (GtkSignalFunc)gtk_window_vscroll_callback;
4034
gtk_signal_disconnect_by_func(GTK_OBJECT(adj), fn, (gpointer)this);
4035
gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
4036
gtk_signal_connect(GTK_OBJECT(adj), "value_changed", fn, (gpointer)this);
4039
void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
4041
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4042
wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4044
GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
4046
float fpos = (float)pos;
4047
if (fpos > adj->upper - adj->page_size)
4048
fpos = adj->upper - adj->page_size;
4051
*(orient == wxHORIZONTAL ? &m_oldHorizontalPos : &m_oldVerticalPos) = fpos;
4053
if (fabs(fpos-adj->value) < 0.2)
4057
if ( m_wxwindow->window )
4062
int wxWindowGTK::GetScrollThumb( int orient ) const
4064
wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4066
wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4068
if (orient == wxHORIZONTAL)
4069
return (int)(m_hAdjust->page_size+0.5);
4071
return (int)(m_vAdjust->page_size+0.5);
4074
int wxWindowGTK::GetScrollPos( int orient ) const
4076
wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4078
wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4080
if (orient == wxHORIZONTAL)
4081
return (int)(m_hAdjust->value+0.5);
4083
return (int)(m_vAdjust->value+0.5);
4086
int wxWindowGTK::GetScrollRange( int orient ) const
4088
wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4090
wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4092
if (orient == wxHORIZONTAL)
4093
return (int)(m_hAdjust->upper+0.5);
4095
return (int)(m_vAdjust->upper+0.5);
4098
void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
4100
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4102
wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4104
// No scrolling requested.
4105
if ((dx == 0) && (dy == 0)) return;
4107
if (!m_updateRegion.IsEmpty())
4109
m_updateRegion.Offset( dx, dy );
4113
GetClientSize( &cw, &ch );
4114
m_updateRegion.Intersect( 0, 0, cw, ch );
4117
if (!m_clearRegion.IsEmpty())
4119
m_clearRegion.Offset( dx, dy );
4123
GetClientSize( &cw, &ch );
4124
m_clearRegion.Intersect( 0, 0, cw, ch );
4127
m_clipPaintRegion = true;
4129
gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4131
m_clipPaintRegion = false;
4134
void wxWindowGTK::SetWindowStyleFlag( long style )
4136
// Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4137
wxWindowBase::SetWindowStyleFlag(style);
4140
// Find the wxWindow at the current mouse position, also returning the mouse
4142
wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4144
pt = wxGetMousePosition();
4145
wxWindow* found = wxFindWindowAtPoint(pt);
4149
// Get the current mouse position.
4150
wxPoint wxGetMousePosition()
4152
/* This crashes when used within wxHelpContext,
4153
so we have to use the X-specific implementation below.
4155
GdkModifierType *mask;
4156
(void) gdk_window_get_pointer(NULL, &x, &y, mask);
4158
return wxPoint(x, y);
4162
GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4164
Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
4165
Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4166
Window rootReturn, childReturn;
4167
int rootX, rootY, winX, winY;
4168
unsigned int maskReturn;
4170
XQueryPointer (display,
4174
&rootX, &rootY, &winX, &winY, &maskReturn);
4175
return wxPoint(rootX, rootY);
4179
// Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4180
void wxAddGrab(wxWindow* window)
4182
gtk_grab_add( (GtkWidget*) window->GetHandle() );
4185
void wxRemoveGrab(wxWindow* window)
4187
gtk_grab_remove( (GtkWidget*) window->GetHandle() );
4190
// ----------------------------------------------------------------------------
4192
// ----------------------------------------------------------------------------
4194
class wxWinModule : public wxModule
4201
DECLARE_DYNAMIC_CLASS(wxWinModule)
4204
IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4206
bool wxWinModule::OnInit()
4208
// g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4209
// gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4214
void wxWinModule::OnExit()
4217
gdk_gc_unref( g_eraseGC );
4220
GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
4222
GdkWindow* window = NULL;
4224
window = GTK_PIZZA(m_wxwindow)->bin_window;