1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
31 #include "wx/combobox.h"
33 #if wxUSE_DRAG_AND_DROP
38 #include "wx/tooltip.h"
46 #include "wx/textctrl.h"
50 #include "wx/statusbr.h"
52 #include "wx/settings.h"
54 #include "wx/fontutil.h"
57 #include "wx/thread.h"
63 #include "wx/gtk/private.h"
64 #include <gdk/gdkprivate.h>
65 #include <gdk/gdkkeysyms.h>
69 #include <gtk/gtkprivate.h>
71 #include "wx/gtk/win_gtk.h"
74 #include <pango/pangox.h>
85 extern GtkContainerClass
*pizza_parent_class
;
88 //-----------------------------------------------------------------------------
89 // documentation on internals
90 //-----------------------------------------------------------------------------
93 I have been asked several times about writing some documentation about
94 the GTK port of wxWidgets, especially its internal structures. Obviously,
95 you cannot understand wxGTK without knowing a little about the GTK, but
96 some more information about what the wxWindow, which is the base class
97 for all other window classes, does seems required as well.
101 What does wxWindow do? It contains the common interface for the following
102 jobs of its descendants:
104 1) Define the rudimentary behaviour common to all window classes, such as
105 resizing, intercepting user input (so as to make it possible to use these
106 events for special purposes in a derived class), window names etc.
108 2) Provide the possibility to contain and manage children, if the derived
109 class is allowed to contain children, which holds true for those window
110 classes which do not display a native GTK widget. To name them, these
111 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
112 work classes are a special case and are handled a bit differently from
113 the rest. The same holds true for the wxNotebook class.
115 3) Provide the possibility to draw into a client area of a window. This,
116 too, only holds true for classes that do not display a native GTK widget
119 4) Provide the entire mechanism for scrolling widgets. This actual inter-
120 face for this is usually in wxScrolledWindow, but the GTK implementation
123 5) A multitude of helper or extra methods for special purposes, such as
124 Drag'n'Drop, managing validators etc.
126 6) Display a border (sunken, raised, simple or none).
128 Normally one might expect, that one wxWidgets window would always correspond
129 to one GTK widget. Under GTK, there is no such allround widget that has all
130 the functionality. Moreover, the GTK defines a client area as a different
131 widget from the actual widget you are handling. Last but not least some
132 special classes (e.g. wxFrame) handle different categories of widgets and
133 still have the possibility to draw something in the client area.
134 It was therefore required to write a special purpose GTK widget, that would
135 represent a client area in the sense of wxWidgets capable to do the jobs
136 2), 3) and 4). I have written this class and it resides in win_gtk.c of
139 All windows must have a widget, with which they interact with other under-
140 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
141 thw wxWindow class has a member variable called m_widget which holds a
142 pointer to this widget. When the window class represents a GTK native widget,
143 this is (in most cases) the only GTK widget the class manages. E.g. the
144 wxStaticText class handles only a GtkLabel widget a pointer to which you
145 can find in m_widget (defined in wxWindow)
147 When the class has a client area for drawing into and for containing children
148 it has to handle the client area widget (of the type GtkPizza, defined in
149 win_gtk.c), but there could be any number of widgets, handled by a class
150 The common rule for all windows is only, that the widget that interacts with
151 the rest of GTK must be referenced in m_widget and all other widgets must be
152 children of this widget on the GTK level. The top-most widget, which also
153 represents the client area, must be in the m_wxwindow field and must be of
156 As I said, the window classes that display a GTK native widget only have
157 one widget, so in the case of e.g. the wxButton class m_widget holds a
158 pointer to a GtkButton widget. But windows with client areas (for drawing
159 and children) have a m_widget field that is a pointer to a GtkScrolled-
160 Window and a m_wxwindow field that is pointer to a GtkPizza and this
161 one is (in the GTK sense) a child of the GtkScrolledWindow.
163 If the m_wxwindow field is set, then all input to this widget is inter-
164 cepted and sent to the wxWidgets class. If not, all input to the widget
165 that gets pointed to by m_widget gets intercepted and sent to the class.
169 The design of scrolling in wxWidgets is markedly different from that offered
170 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
171 clicking on a scrollbar belonging to scrolled window will inevitably move
172 the window. In wxWidgets, the scrollbar will only emit an event, send this
173 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
174 which actually moves the window and its subchildren. Note that GtkPizza
175 memorizes how much it has been scrolled but that wxWidgets forgets this
176 so that the two coordinates systems have to be kept in synch. This is done
177 in various places using the pizza->xoffset and pizza->yoffset values.
181 Singularily the most broken code in GTK is the code that is supposes to
182 inform subwindows (child windows) about new positions. Very often, duplicate
183 events are sent without changes in size or position, equally often no
184 events are sent at all (All this is due to a bug in the GtkContainer code
185 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
186 GTK's own system and it simply waits for size events for toplevel windows
187 and then iterates down the respective size events to all window. This has
188 the disadvantage, that windows might get size events before the GTK widget
189 actually has the reported size. This doesn't normally pose any problem, but
190 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
191 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
192 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
193 window that is used for OpenGl output really has that size (as reported by
198 If someone at some point of time feels the immense desire to have a look at,
199 change or attempt to optimse the Refresh() logic, this person will need an
200 intimate understanding of what a "draw" and what an "expose" events are and
201 what there are used for, in particular when used in connection with GTK's
202 own windowless widgets. Beware.
206 Cursors, too, have been a constant source of pleasure. The main difficulty
207 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
208 for the parent. To prevent this from doing too much harm, I use idle time
209 to set the cursor over and over again, starting from the toplevel windows
210 and ending with the youngest generation (speaking of parent and child windows).
211 Also don't forget that cursors (like much else) are connected to GdkWindows,
212 not GtkWidgets and that the "window" field of a GtkWidget might very well
213 point to the GdkWindow of the parent widget (-> "window less widget") and
214 that the two obviously have very different meanings.
218 //-----------------------------------------------------------------------------
220 //-----------------------------------------------------------------------------
222 extern wxList wxPendingDelete
;
223 extern bool g_blockEventsOnDrag
;
224 extern bool g_blockEventsOnScroll
;
225 extern wxCursor g_globalCursor
;
227 static GdkGC
*g_eraseGC
= NULL
;
229 // mouse capture state: the window which has it and if the mouse is currently
231 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
232 static bool g_captureWindowHasMouse
= FALSE
;
234 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
236 // the last window which had the focus - this is normally never NULL (except
237 // if we never had focus at all) as even when g_focusWindow is NULL it still
238 // keeps its previous value
239 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
241 // If a window get the focus set but has not been realized
242 // yet, defer setting the focus to idle time.
243 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
245 // hack: we need something to pass to gtk_menu_popup, so we store the time of
246 // the last click here
247 static guint32 gs_timeLastClick
= 0;
249 extern bool g_mainThreadLocked
;
251 //-----------------------------------------------------------------------------
253 //-----------------------------------------------------------------------------
258 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
260 # define DEBUG_MAIN_THREAD
263 #define DEBUG_MAIN_THREAD
266 // the trace mask used for the focus debugging messages
267 #define TRACE_FOCUS _T("focus")
269 //-----------------------------------------------------------------------------
270 // missing gdk functions
271 //-----------------------------------------------------------------------------
274 gdk_window_warp_pointer (GdkWindow
*window
,
279 GdkWindowPrivate
*priv
;
283 window
= GDK_ROOT_PARENT();
286 if (!GDK_WINDOW_DESTROYED(window
))
288 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
289 None
, /* not source window -> move from anywhere */
290 GDK_WINDOW_XID(window
), /* dest window */
291 0, 0, 0, 0, /* not source window -> move from anywhere */
295 priv
= (GdkWindowPrivate
*) window
;
297 if (!priv
->destroyed
)
299 XWarpPointer (priv
->xdisplay
,
300 None
, /* not source window -> move from anywhere */
301 priv
->xwindow
, /* dest window */
302 0, 0, 0, 0, /* not source window -> move from anywhere */
308 //-----------------------------------------------------------------------------
310 //-----------------------------------------------------------------------------
312 extern void wxapp_install_idle_handler();
313 extern bool g_isIdle
;
315 //-----------------------------------------------------------------------------
316 // local code (see below)
317 //-----------------------------------------------------------------------------
319 // returns the child of win which currently has focus or NULL if not found
321 // Note: can't be static, needed by textctrl.cpp.
322 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
324 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
326 return (wxWindow
*)NULL
;
328 if ( winFocus
== win
)
329 return (wxWindow
*)win
;
331 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
333 node
= node
->GetNext() )
335 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
340 return (wxWindow
*)NULL
;
343 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
345 // wxUniversal widgets draw the borders and scrollbars themselves
346 #ifndef __WXUNIVERSAL__
353 if (win
->m_hasScrolling
)
355 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
357 GtkRequisition vscroll_req
;
358 vscroll_req
.width
= 2;
359 vscroll_req
.height
= 2;
360 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
361 (scroll_window
->vscrollbar
, &vscroll_req
);
363 GtkRequisition hscroll_req
;
364 hscroll_req
.width
= 2;
365 hscroll_req
.height
= 2;
366 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
367 (scroll_window
->hscrollbar
, &hscroll_req
);
369 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
371 if (scroll_window
->vscrollbar_visible
)
373 dw
+= vscroll_req
.width
;
374 dw
+= scroll_class
->scrollbar_spacing
;
377 if (scroll_window
->hscrollbar_visible
)
379 dh
+= hscroll_req
.height
;
380 dh
+= scroll_class
->scrollbar_spacing
;
386 if (GTK_WIDGET_NO_WINDOW (widget
))
388 dx
+= widget
->allocation
.x
;
389 dy
+= widget
->allocation
.y
;
392 if (win
->HasFlag(wxRAISED_BORDER
))
394 gtk_draw_shadow( widget
->style
,
399 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
403 if (win
->HasFlag(wxSUNKEN_BORDER
))
405 gtk_draw_shadow( widget
->style
,
410 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
414 if (win
->HasFlag(wxSIMPLE_BORDER
))
417 gc
= gdk_gc_new( widget
->window
);
418 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
419 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
421 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
425 #endif // __WXUNIVERSAL__
428 //-----------------------------------------------------------------------------
429 // "expose_event" of m_widget
430 //-----------------------------------------------------------------------------
432 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
434 if (gdk_event
->count
> 0) return FALSE
;
436 draw_frame( widget
, win
);
440 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
446 //-----------------------------------------------------------------------------
447 // "draw" of m_widget
448 //-----------------------------------------------------------------------------
452 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
454 draw_frame( widget
, win
);
459 //-----------------------------------------------------------------------------
460 // "size_request" of m_widget
461 //-----------------------------------------------------------------------------
463 // make it extern because wxStatitText needs to disconnect this one
465 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
466 GtkRequisition
*requisition
,
470 win
->GetSize( &w
, &h
);
476 requisition
->height
= h
;
477 requisition
->width
= w
;
482 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
483 GtkRequisition
*requisition
,
486 // This callback is actually hooked into the text entry
487 // of the combo box, not the GtkHBox.
490 win
->GetSize( &w
, &h
);
496 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
498 GtkRequisition entry_req
;
500 entry_req
.height
= 2;
501 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
502 (gcombo
->button
, &entry_req
);
504 requisition
->width
= w
- entry_req
.width
;
505 requisition
->height
= entry_req
.height
+4; // TODO: why +4?
508 //-----------------------------------------------------------------------------
509 // "expose_event" of m_wxwindow
510 //-----------------------------------------------------------------------------
512 static int gtk_window_expose_callback( GtkWidget
*widget
,
513 GdkEventExpose
*gdk_event
,
519 wxapp_install_idle_handler();
522 // This callback gets called in drawing-idle time under
523 // GTK 2.0, so we don't need to defer anything to idle
526 GtkPizza
*pizza
= GTK_PIZZA( widget
);
527 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
532 wxPrintf( wxT("OnExpose from ") );
533 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
534 wxPrintf( win
->GetClassInfo()->GetClassName() );
535 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
536 (int)gdk_event
->area
.y
,
537 (int)gdk_event
->area
.width
,
538 (int)gdk_event
->area
.height
);
543 win
->m_wxwindow
->style
,
547 (GdkRectangle
*) NULL
,
549 (char *)"button", // const_cast
554 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
556 win
->GtkSendPaintEvents();
559 // Let parent window draw window less widgets
560 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
562 // This gets called immediately after an expose event
563 // under GTK 1.2 so we collect the calls and wait for
564 // the idle handler to pick things up.
566 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
568 gdk_event
->area
.width
,
569 gdk_event
->area
.height
);
570 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
572 gdk_event
->area
.width
,
573 gdk_event
->area
.height
);
575 // Actual redrawing takes place in idle time.
582 //-----------------------------------------------------------------------------
583 // "event" of m_wxwindow
584 //-----------------------------------------------------------------------------
586 // GTK thinks it is clever and filters out a certain amount of "unneeded"
587 // expose events. We need them, of course, so we override the main event
588 // procedure in GtkWidget by giving our own handler for all system events.
589 // There, we look for expose events ourselves whereas all other events are
592 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
593 GdkEventExpose
*event
,
596 if (event
->type
== GDK_EXPOSE
)
598 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
605 //-----------------------------------------------------------------------------
606 // "draw" of m_wxwindow
607 //-----------------------------------------------------------------------------
611 // This callback is a complete replacement of the gtk_pizza_draw() function,
612 // which is disabled.
614 static void gtk_window_draw_callback( GtkWidget
*widget
,
621 wxapp_install_idle_handler();
623 // if there are any children we must refresh everything
626 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
627 win
->GetChildren().IsEmpty() )
635 wxPrintf( wxT("OnDraw from ") );
636 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
637 wxPrintf( win
->GetClassInfo()->GetClassName() );
638 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
645 #ifndef __WXUNIVERSAL__
646 GtkPizza
*pizza
= GTK_PIZZA (widget
);
648 if (win
->GetThemeEnabled() && win
->GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
650 wxWindow
*parent
= win
->GetParent();
651 while (parent
&& !parent
->IsTopLevel())
652 parent
= parent
->GetParent();
656 gtk_paint_flat_box (parent
->m_widget
->style
,
667 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
668 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
670 // Update immediately, not in idle time.
673 #ifndef __WXUNIVERSAL__
674 // Redraw child widgets
675 GList
*children
= pizza
->children
;
678 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
679 children
= children
->next
;
681 GdkRectangle child_area
;
682 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
684 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
692 //-----------------------------------------------------------------------------
693 // "key_press_event" from any window
694 //-----------------------------------------------------------------------------
696 // set WXTRACE to this to see the key event codes on the console
697 #define TRACE_KEYS _T("keyevent")
699 // translates an X key symbol to WXK_XXX value
701 // if isChar is true it means that the value returned will be used for EVT_CHAR
702 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
703 // for example, while if it is false it means that the value is going to be
704 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
706 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
712 // Shift, Control and Alt don't generate the CHAR events at all
715 key_code
= isChar
? 0 : WXK_SHIFT
;
719 key_code
= isChar
? 0 : WXK_CONTROL
;
727 key_code
= isChar
? 0 : WXK_ALT
;
730 // neither do the toggle modifies
731 case GDK_Scroll_Lock
:
732 key_code
= isChar
? 0 : WXK_SCROLL
;
736 key_code
= isChar
? 0 : WXK_CAPITAL
;
740 key_code
= isChar
? 0 : WXK_NUMLOCK
;
744 // various other special keys
757 case GDK_ISO_Left_Tab
:
764 key_code
= WXK_RETURN
;
768 key_code
= WXK_CLEAR
;
772 key_code
= WXK_PAUSE
;
776 key_code
= WXK_SELECT
;
780 key_code
= WXK_PRINT
;
784 key_code
= WXK_EXECUTE
;
788 key_code
= WXK_ESCAPE
;
791 // cursor and other extended keyboard keys
793 key_code
= WXK_DELETE
;
809 key_code
= WXK_RIGHT
;
816 case GDK_Prior
: // == GDK_Page_Up
817 key_code
= WXK_PRIOR
;
820 case GDK_Next
: // == GDK_Page_Down
833 key_code
= WXK_INSERT
;
848 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
852 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
856 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
860 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
864 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
868 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
872 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
876 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
880 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
884 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
888 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
892 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
896 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
899 case GDK_KP_Prior
: // == GDK_KP_Page_Up
900 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
903 case GDK_KP_Next
: // == GDK_KP_Page_Down
904 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
908 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
912 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
916 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
920 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
924 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
927 case GDK_KP_Multiply
:
928 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
932 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
935 case GDK_KP_Separator
:
936 // FIXME: what is this?
937 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
940 case GDK_KP_Subtract
:
941 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
945 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
949 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
966 key_code
= WXK_F1
+ keysym
- GDK_F1
;
976 static inline bool wxIsAsciiKeysym(KeySym ks
)
981 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
983 GdkEventKey
*gdk_event
)
987 GdkModifierType state
;
988 if (gdk_event
->window
)
989 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
991 event
.SetTimestamp( gdk_event
->time
);
992 event
.SetId(win
->GetId());
993 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
994 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
995 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
996 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
997 event
.m_scanCode
= gdk_event
->keyval
;
998 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
999 event
.m_rawFlags
= 0;
1001 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
1005 event
.SetEventObject( win
);
1010 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
1012 GdkEventKey
*gdk_event
)
1014 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1015 // but only event->keyval which is quite useless to us, so remember
1016 // the last character from GDK_KEY_PRESS and reuse it as last resort
1018 // NB: should be MT-safe as we're always called from the main thread only
1023 } s_lastKeyPress
= { 0, 0 };
1025 KeySym keysym
= gdk_event
->keyval
;
1027 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
1028 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1032 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1036 // do we have the translation or is it a plain ASCII character?
1037 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1039 // we should use keysym if it is ASCII as X does some translations
1040 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1041 // which we don't want here (but which we do use for OnChar())
1042 if ( !wxIsAsciiKeysym(keysym
) )
1044 keysym
= (KeySym
)gdk_event
->string
[0];
1047 // we want to always get the same key code when the same key is
1048 // pressed regardless of the state of the modifies, i.e. on a
1049 // standard US keyboard pressing '5' or '%' ('5' key with
1050 // Shift) should result in the same key code in OnKeyDown():
1051 // '5' (although OnChar() will get either '5' or '%').
1053 // to do it we first translate keysym to keycode (== scan code)
1054 // and then back but always using the lower register
1055 Display
*dpy
= (Display
*)wxGetDisplay();
1056 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1058 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1060 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1062 // use the normalized, i.e. lower register, keysym if we've
1064 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1066 // as explained above, we want to have lower register key codes
1067 // normally but for the letter keys we want to have the upper ones
1069 // NB: don't use XConvertCase() here, we want to do it for letters
1071 key_code
= toupper(key_code
);
1073 else // non ASCII key, what to do?
1075 // by default, ignore it
1078 // but if we have cached information from the last KEY_PRESS
1079 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1082 if ( keysym
== s_lastKeyPress
.keysym
)
1084 key_code
= s_lastKeyPress
.keycode
;
1089 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1091 // remember it to be reused for KEY_UP event later
1092 s_lastKeyPress
.keysym
= keysym
;
1093 s_lastKeyPress
.keycode
= key_code
;
1097 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1099 // sending unknown key events doesn't really make sense
1103 // now fill all the other fields
1104 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1106 event
.m_keyCode
= key_code
;
1115 GtkIMContext
*context
;
1116 GdkEventKey
*lastKeyEvent
;
1120 context
= gtk_im_multicontext_new();
1121 lastKeyEvent
= NULL
;
1125 g_object_unref(context
);
1130 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1131 GdkEventKey
*gdk_event
,
1137 wxapp_install_idle_handler();
1141 if (g_blockEventsOnDrag
)
1145 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1147 bool return_after_IM
= false;
1149 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1151 // Emit KEY_DOWN event
1152 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1156 // Return after IM processing as we cannot do
1157 // anything with it anyhow.
1158 return_after_IM
= true;
1162 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1163 // When we get a key_press event here, it could be originate
1164 // from the current widget or its child widgets. However, only the widget
1165 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1166 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1167 // originated from its child widgets and shouldn't be passed to IM context.
1168 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1169 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1170 // widgets has both IM context and input focus, the event should be filtered
1171 // by gtk_im_context_filter_keypress().
1172 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1173 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1175 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1176 // docs, if IM filter returns true, no further processing should be done.
1177 // we should send the key_down event anyway.
1178 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1179 win
->m_imData
->lastKeyEvent
= NULL
;
1180 if (intercepted_by_IM
)
1182 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1187 if (return_after_IM
)
1191 // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1192 // in the "commit" handler.
1194 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1195 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1196 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1197 // composed of more than one character, which means gdk_event->length will always
1198 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1199 // and can be translated by wx. However, when MBCS characters are sent by IM,
1200 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1201 // nor should we pass it to controls. The following explanation was excerpted
1202 // from GDK documentation.
1203 // gint length : the length of string.
1204 // gchar *string : a null-terminated multi-byte string containing the composed
1205 // characters resulting from the key press. When text is being input, in a GtkEntry
1206 // for example, it is these characters which should be added to the input buffer.
1207 // When using Input Methods to support internationalized text input, the composed
1208 // characters appear here after the pre-editing has been completed.
1210 if ( (!ret
) && (gdk_event
->length
> 1) ) // If this event contains a pre-edited string from IM.
1212 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1213 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1214 const wxWCharBuffer string
= wxConvLocal
.cMB2WC( gdk_event
->string
);
1218 const char* string
= gdk_event
->string
;
1221 // Implement OnCharHook by checking ancesteror top level windows
1222 wxWindow
*parent
= win
;
1223 while (parent
&& !parent
->IsTopLevel())
1224 parent
= parent
->GetParent();
1226 for( const wxChar
* pstr
= string
; *pstr
; pstr
++ )
1229 event
.m_uniChar
= *pstr
;
1230 // Backward compatible for ISO-8859-1
1231 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1233 event
.m_keyCode
= *pstr
;
1237 event
.SetEventType( wxEVT_CHAR_HOOK
);
1238 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1242 event
.SetEventType(wxEVT_CHAR
);
1243 win
->GetEventHandler()->ProcessEvent( event
);
1249 #endif // #ifndef __WXGTK20__
1254 wxWindowGTK
*ancestor
= win
;
1257 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1260 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1261 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1264 if (ancestor
->IsTopLevel())
1266 ancestor
= ancestor
->GetParent();
1269 #endif // wxUSE_ACCEL
1271 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1272 // will only be sent if it is not in an accelerator table.
1276 KeySym keysym
= gdk_event
->keyval
;
1277 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1278 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1281 if ( wxIsAsciiKeysym(keysym
) )
1284 key_code
= (unsigned char)keysym
;
1286 // gdk_event->string is actually deprecated
1287 else if ( gdk_event
->length
== 1 )
1289 key_code
= (unsigned char)gdk_event
->string
[0];
1295 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1297 event
.m_keyCode
= key_code
;
1299 // Implement OnCharHook by checking ancesteror top level windows
1300 wxWindow
*parent
= win
;
1301 while (parent
&& !parent
->IsTopLevel())
1302 parent
= parent
->GetParent();
1305 event
.SetEventType( wxEVT_CHAR_HOOK
);
1306 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1311 event
.SetEventType(wxEVT_CHAR
);
1312 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1321 // win is a control: tab can be propagated up
1323 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1324 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1325 // have this style, yet choose not to process this particular TAB in which
1326 // case TAB must still work as a navigational character
1327 // JS: enabling again to make consistent with other platforms
1328 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1329 // navigation behaviour)
1331 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1333 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1335 wxNavigationKeyEvent new_event
;
1336 new_event
.SetEventObject( win
->GetParent() );
1337 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1338 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1339 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1340 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1341 new_event
.SetCurrentFocus( win
);
1342 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1345 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1347 (gdk_event
->keyval
== GDK_Escape
) )
1349 // however only do it if we have a Cancel button in the dialog,
1350 // otherwise the user code may get confused by the events from a
1351 // non-existing button and, worse, a wxButton might get button event
1352 // from another button which is not really expected
1353 wxWindow
*winForCancel
= win
,
1355 while ( winForCancel
)
1357 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1360 // found a cancel button
1364 if ( winForCancel
->IsTopLevel() )
1366 // no need to look further
1370 // maybe our parent has a cancel button?
1371 winForCancel
= winForCancel
->GetParent();
1376 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1377 event
.SetEventObject(btnCancel
);
1378 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1384 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1392 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1396 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1398 // take modifiers, cursor position, timestamp etc. from the last
1399 // key_press_event that was fed into Input Method:
1400 if (window
->m_imData
->lastKeyEvent
)
1402 wxFillOtherKeyEventFields(event
,
1403 window
, window
->m_imData
->lastKeyEvent
);
1407 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1409 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1410 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1411 #endif // wxUSE_UNICODE
1412 if( !(const wxChar
*)data
)
1417 // Implement OnCharHook by checking ancestor top level windows
1418 wxWindow
*parent
= window
;
1419 while (parent
&& !parent
->IsTopLevel())
1420 parent
= parent
->GetParent();
1422 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1425 event
.m_uniChar
= *pstr
;
1426 // Backward compatible for ISO-8859-1
1427 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1428 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1430 event
.m_keyCode
= *pstr
;
1431 #endif // wxUSE_UNICODE
1434 event
.SetEventType( wxEVT_CHAR_HOOK
);
1435 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1440 event
.SetEventType(wxEVT_CHAR
);
1441 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1448 //-----------------------------------------------------------------------------
1449 // "key_release_event" from any window
1450 //-----------------------------------------------------------------------------
1452 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1453 GdkEventKey
*gdk_event
,
1459 wxapp_install_idle_handler();
1464 if (g_blockEventsOnDrag
)
1467 wxKeyEvent
event( wxEVT_KEY_UP
);
1468 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1470 // unknown key pressed, ignore (the event would be useless anyhow
1474 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1477 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1481 // ============================================================================
1483 // ============================================================================
1485 // ----------------------------------------------------------------------------
1486 // mouse event processing helpers
1487 // ----------------------------------------------------------------------------
1489 // init wxMouseEvent with the info from GdkEventXXX struct
1490 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1491 wxMouseEvent
& event
,
1494 event
.SetTimestamp( gdk_event
->time
);
1495 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1496 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1497 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1498 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1499 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1500 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1501 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1502 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1504 event
.m_linesPerAction
= 3;
1505 event
.m_wheelDelta
= 120;
1506 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1507 event
.m_wheelRotation
= 120;
1508 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1509 event
.m_wheelRotation
= -120;
1512 wxPoint pt
= win
->GetClientAreaOrigin();
1513 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1514 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1516 event
.SetEventObject( win
);
1517 event
.SetId( win
->GetId() );
1518 event
.SetTimestamp( gdk_event
->time
);
1521 static void AdjustEventButtonState(wxMouseEvent
& event
)
1523 // GDK reports the old state of the button for a button press event, but
1524 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1525 // for a LEFT_DOWN event, not FALSE, so we will invert
1526 // left/right/middleDown for the corresponding click events
1528 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1529 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1530 (event
.GetEventType() == wxEVT_LEFT_UP
))
1532 event
.m_leftDown
= !event
.m_leftDown
;
1536 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1537 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1538 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1540 event
.m_middleDown
= !event
.m_middleDown
;
1544 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1545 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1546 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1548 event
.m_rightDown
= !event
.m_rightDown
;
1553 // find the window to send the mouse event too
1555 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1560 if (win
->m_wxwindow
)
1562 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1563 xx
+= pizza
->xoffset
;
1564 yy
+= pizza
->yoffset
;
1567 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1570 wxWindowGTK
*child
= node
->GetData();
1572 node
= node
->GetNext();
1573 if (!child
->IsShown())
1576 if (child
->IsTransparentForMouse())
1578 // wxStaticBox is transparent in the box itself
1579 int xx1
= child
->m_x
;
1580 int yy1
= child
->m_y
;
1581 int xx2
= child
->m_x
+ child
->m_width
;
1582 int yy2
= child
->m_y
+ child
->m_height
;
1585 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1587 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1589 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1591 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1602 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1603 (child
->m_x
<= xx
) &&
1604 (child
->m_y
<= yy
) &&
1605 (child
->m_x
+child
->m_width
>= xx
) &&
1606 (child
->m_y
+child
->m_height
>= yy
))
1619 //-----------------------------------------------------------------------------
1620 // "button_press_event"
1621 //-----------------------------------------------------------------------------
1623 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1624 GdkEventButton
*gdk_event
,
1630 wxapp_install_idle_handler();
1633 wxPrintf( wxT("1) OnButtonPress from ") );
1634 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1635 wxPrintf( win->GetClassInfo()->GetClassName() );
1636 wxPrintf( wxT(".\n") );
1638 if (!win
->m_hasVMT
) return FALSE
;
1639 if (g_blockEventsOnDrag
) return TRUE
;
1640 if (g_blockEventsOnScroll
) return TRUE
;
1642 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1644 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1646 gtk_widget_grab_focus( win
->m_wxwindow
);
1648 wxPrintf( wxT("GrabFocus from ") );
1649 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1650 wxPrintf( win->GetClassInfo()->GetClassName() );
1651 wxPrintf( wxT(".\n") );
1655 // GDK sends surplus button down event
1656 // before a double click event. We
1657 // need to filter these out.
1658 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1660 GdkEvent
*peek_event
= gdk_event_peek();
1663 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1664 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1666 gdk_event_free( peek_event
);
1671 gdk_event_free( peek_event
);
1676 wxEventType event_type
= wxEVT_NULL
;
1678 // GdkDisplay is a GTK+ 2.2.0 thing
1679 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1680 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1681 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1683 // Reset GDK internal timestamp variables in order to disable GDK
1684 // triple click events. GDK will then next time believe no button has
1685 // been clicked just before, and send a normal button click event.
1686 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1687 display
->button_click_time
[1] = 0;
1688 display
->button_click_time
[0] = 0;
1692 if (gdk_event
->button
== 1)
1694 // note that GDK generates triple click events which are not supported
1695 // by wxWidgets but still have to be passed to the app as otherwise
1696 // clicks would simply go missing
1697 switch (gdk_event
->type
)
1699 // we shouldn't get triple clicks at all for GTK2 because we
1700 // suppress them artificially using the code above but we still
1701 // should map them to something for GTK1 and not just ignore them
1702 // as this would lose clicks
1703 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1704 case GDK_BUTTON_PRESS
:
1705 event_type
= wxEVT_LEFT_DOWN
;
1708 case GDK_2BUTTON_PRESS
:
1709 event_type
= wxEVT_LEFT_DCLICK
;
1713 // just to silence gcc warnings
1717 else if (gdk_event
->button
== 2)
1719 switch (gdk_event
->type
)
1721 case GDK_3BUTTON_PRESS
:
1722 case GDK_BUTTON_PRESS
:
1723 event_type
= wxEVT_MIDDLE_DOWN
;
1726 case GDK_2BUTTON_PRESS
:
1727 event_type
= wxEVT_MIDDLE_DCLICK
;
1734 else if (gdk_event
->button
== 3)
1736 switch (gdk_event
->type
)
1738 case GDK_3BUTTON_PRESS
:
1739 case GDK_BUTTON_PRESS
:
1740 event_type
= wxEVT_RIGHT_DOWN
;
1743 case GDK_2BUTTON_PRESS
:
1744 event_type
= wxEVT_RIGHT_DCLICK
;
1751 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1753 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1755 event_type
= wxEVT_MOUSEWHEEL
;
1759 if ( event_type
== wxEVT_NULL
)
1761 // unknown mouse button or click type
1765 wxMouseEvent
event( event_type
);
1766 InitMouseEvent( win
, event
, gdk_event
);
1768 AdjustEventButtonState(event
);
1770 // wxListBox actually get mouse events from the item, so we need to give it
1771 // a chance to correct this
1772 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1774 // find the correct window to send the event too: it may be a different one
1775 // from the one which got it at GTK+ level because some control don't have
1776 // their own X window and thus cannot get any events.
1777 if ( !g_captureWindow
)
1778 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1780 gs_timeLastClick
= gdk_event
->time
;
1783 if (event_type
== wxEVT_LEFT_DCLICK
)
1785 // GTK 1.2 crashes when intercepting double
1786 // click events from both wxSpinButton and
1788 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1790 // Just disable this event for now.
1796 if (win
->GetEventHandler()->ProcessEvent( event
))
1798 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1802 if (event_type
== wxEVT_RIGHT_DOWN
)
1804 // generate a "context menu" event: this is similar to right mouse
1805 // click under many GUIs except that it is generated differently
1806 // (right up under MSW, ctrl-click under Mac, right down here) and
1808 // (a) it's a command event and so is propagated to the parent
1809 // (b) under some ports it can be generated from kbd too
1810 // (c) it uses screen coords (because of (a))
1811 wxContextMenuEvent
evtCtx(
1814 win
->ClientToScreen(event
.GetPosition()));
1815 evtCtx
.SetEventObject(win
);
1816 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1822 //-----------------------------------------------------------------------------
1823 // "button_release_event"
1824 //-----------------------------------------------------------------------------
1826 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1827 GdkEventButton
*gdk_event
,
1833 wxapp_install_idle_handler();
1835 if (!win
->m_hasVMT
) return FALSE
;
1836 if (g_blockEventsOnDrag
) return FALSE
;
1837 if (g_blockEventsOnScroll
) return FALSE
;
1839 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1841 wxEventType event_type
= wxEVT_NULL
;
1843 switch (gdk_event
->button
)
1846 event_type
= wxEVT_LEFT_UP
;
1850 event_type
= wxEVT_MIDDLE_UP
;
1854 event_type
= wxEVT_RIGHT_UP
;
1858 // unknwon button, don't process
1862 wxMouseEvent
event( event_type
);
1863 InitMouseEvent( win
, event
, gdk_event
);
1865 AdjustEventButtonState(event
);
1867 // same wxListBox hack as above
1868 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1870 if ( !g_captureWindow
)
1871 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1873 if (win
->GetEventHandler()->ProcessEvent( event
))
1875 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1882 //-----------------------------------------------------------------------------
1883 // "motion_notify_event"
1884 //-----------------------------------------------------------------------------
1886 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1887 GdkEventMotion
*gdk_event
,
1893 wxapp_install_idle_handler();
1895 if (!win
->m_hasVMT
) return FALSE
;
1896 if (g_blockEventsOnDrag
) return FALSE
;
1897 if (g_blockEventsOnScroll
) return FALSE
;
1899 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1901 if (gdk_event
->is_hint
)
1905 GdkModifierType state
;
1906 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1912 printf( "OnMotion from " );
1913 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1914 printf( win->GetClassInfo()->GetClassName() );
1918 wxMouseEvent
event( wxEVT_MOTION
);
1919 InitMouseEvent(win
, event
, gdk_event
);
1921 if ( g_captureWindow
)
1923 // synthetize a mouse enter or leave event if needed
1924 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1925 // This seems to be necessary and actually been added to
1926 // GDK itself in version 2.0.X
1929 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1930 if ( hasMouse
!= g_captureWindowHasMouse
)
1932 // the mouse changed window
1933 g_captureWindowHasMouse
= hasMouse
;
1935 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1936 : wxEVT_LEAVE_WINDOW
);
1937 InitMouseEvent(win
, event
, gdk_event
);
1938 event
.SetEventObject(win
);
1939 win
->GetEventHandler()->ProcessEvent(event
);
1944 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1947 if (win
->GetEventHandler()->ProcessEvent( event
))
1949 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1957 //-----------------------------------------------------------------------------
1958 // "mouse_wheel_event"
1959 //-----------------------------------------------------------------------------
1961 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1962 GdkEventScroll
* gdk_event
,
1968 wxapp_install_idle_handler();
1970 wxEventType event_type
= wxEVT_NULL
;
1971 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1972 event_type
= wxEVT_MOUSEWHEEL
;
1973 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1974 event_type
= wxEVT_MOUSEWHEEL
;
1978 wxMouseEvent
event( event_type
);
1979 // Can't use InitMouse macro because scroll events don't have button
1980 event
.SetTimestamp( gdk_event
->time
);
1981 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1982 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1983 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1984 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1985 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1986 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1987 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1988 event
.m_linesPerAction
= 3;
1989 event
.m_wheelDelta
= 120;
1990 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1991 event
.m_wheelRotation
= 120;
1993 event
.m_wheelRotation
= -120;
1995 wxPoint pt
= win
->GetClientAreaOrigin();
1996 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1997 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1999 event
.SetEventObject( win
);
2000 event
.SetId( win
->GetId() );
2001 event
.SetTimestamp( gdk_event
->time
);
2003 if (win
->GetEventHandler()->ProcessEvent( event
))
2005 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
2012 //-----------------------------------------------------------------------------
2014 //-----------------------------------------------------------------------------
2015 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
2017 wxContextMenuEvent
event(
2021 event
.SetEventObject(win
);
2022 return win
->GetEventHandler()->ProcessEvent(event
);
2024 #endif // __WXGTK20__
2026 //-----------------------------------------------------------------------------
2028 //-----------------------------------------------------------------------------
2030 // send the wxChildFocusEvent and wxFocusEvent, common code of
2031 // gtk_window_focus_in_callback() and SetFocus()
2032 static bool DoSendFocusEvents(wxWindow
*win
)
2034 // Notify the parent keeping track of focus for the kbd navigation
2035 // purposes that we got it.
2036 wxChildFocusEvent
eventChildFocus(win
);
2037 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
2039 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
2040 eventFocus
.SetEventObject(win
);
2042 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
2045 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
2046 GdkEvent
*WXUNUSED(event
),
2052 wxapp_install_idle_handler();
2056 gtk_im_context_focus_in(win
->m_imData
->context
);
2060 g_focusWindow
= win
;
2062 wxLogTrace(TRACE_FOCUS
,
2063 _T("%s: focus in"), win
->GetName().c_str());
2067 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
2071 // caret needs to be informed about focus change
2072 wxCaret
*caret
= win
->GetCaret();
2075 caret
->OnSetFocus();
2077 #endif // wxUSE_CARET
2079 // does the window itself think that it has the focus?
2080 if ( !win
->m_hasFocus
)
2082 // not yet, notify it
2083 win
->m_hasFocus
= TRUE
;
2085 if ( DoSendFocusEvents(win
) )
2087 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2095 //-----------------------------------------------------------------------------
2096 // "focus_out_event"
2097 //-----------------------------------------------------------------------------
2099 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2104 wxapp_install_idle_handler();
2108 gtk_im_context_focus_out(win
->m_imData
->context
);
2111 wxLogTrace( TRACE_FOCUS
,
2112 _T("%s: focus out"), win
->GetName().c_str() );
2115 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2119 g_focusWindow
= (wxWindowGTK
*)NULL
;
2127 // caret needs to be informed about focus change
2128 wxCaret
*caret
= win
->GetCaret();
2131 caret
->OnKillFocus();
2133 #endif // wxUSE_CARET
2135 // don't send the window a kill focus event if it thinks that it doesn't
2136 // have focus already
2137 if ( win
->m_hasFocus
)
2139 win
->m_hasFocus
= FALSE
;
2141 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2142 event
.SetEventObject( win
);
2144 // even if we did process the event in wx code, still let GTK itself
2145 // process it too as otherwise bad things happen, especially in GTK2
2146 // where the text control simply aborts the program if it doesn't get
2147 // the matching focus out event
2148 (void)win
->GetEventHandler()->ProcessEvent( event
);
2154 //-----------------------------------------------------------------------------
2155 // "enter_notify_event"
2156 //-----------------------------------------------------------------------------
2159 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2160 GdkEventCrossing
*gdk_event
,
2166 wxapp_install_idle_handler();
2168 if (!win
->m_hasVMT
) return FALSE
;
2169 if (g_blockEventsOnDrag
) return FALSE
;
2171 // Event was emitted after a grab
2172 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2174 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2178 GdkModifierType state
= (GdkModifierType
)0;
2180 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2182 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2183 InitMouseEvent(win
, event
, gdk_event
);
2184 wxPoint pt
= win
->GetClientAreaOrigin();
2185 event
.m_x
= x
+ pt
.x
;
2186 event
.m_y
= y
+ pt
.y
;
2188 if (win
->GetEventHandler()->ProcessEvent( event
))
2190 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2197 //-----------------------------------------------------------------------------
2198 // "leave_notify_event"
2199 //-----------------------------------------------------------------------------
2201 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2206 wxapp_install_idle_handler();
2208 if (!win
->m_hasVMT
) return FALSE
;
2209 if (g_blockEventsOnDrag
) return FALSE
;
2211 // Event was emitted after an ungrab
2212 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2214 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2216 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2217 event
.SetTimestamp( gdk_event
->time
);
2218 event
.SetEventObject( win
);
2222 GdkModifierType state
= (GdkModifierType
)0;
2224 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2226 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2227 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2228 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2229 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2230 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2231 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2232 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2234 wxPoint pt
= win
->GetClientAreaOrigin();
2235 event
.m_x
= x
+ pt
.x
;
2236 event
.m_y
= y
+ pt
.y
;
2238 if (win
->GetEventHandler()->ProcessEvent( event
))
2240 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2247 //-----------------------------------------------------------------------------
2248 // "value_changed" from m_vAdjust
2249 //-----------------------------------------------------------------------------
2251 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2258 wxapp_install_idle_handler();
2260 if (g_blockEventsOnDrag
) return;
2262 if (!win
->m_hasVMT
) return;
2264 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2265 if (fabs(diff
) < 0.2) return;
2267 win
->m_oldVerticalPos
= adjust
->value
;
2270 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2272 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2274 int value
= (int)(adjust
->value
+0.5);
2276 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2277 event
.SetEventObject( win
);
2278 win
->GetEventHandler()->ProcessEvent( event
);
2281 //-----------------------------------------------------------------------------
2282 // "value_changed" from m_hAdjust
2283 //-----------------------------------------------------------------------------
2285 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2292 wxapp_install_idle_handler();
2294 if (g_blockEventsOnDrag
) return;
2295 if (!win
->m_hasVMT
) return;
2297 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2298 if (fabs(diff
) < 0.2) return;
2301 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2303 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2305 win
->m_oldHorizontalPos
= adjust
->value
;
2307 int value
= (int)(adjust
->value
+0.5);
2309 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2310 event
.SetEventObject( win
);
2311 win
->GetEventHandler()->ProcessEvent( event
);
2314 //-----------------------------------------------------------------------------
2315 // "button_press_event" from scrollbar
2316 //-----------------------------------------------------------------------------
2318 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2319 GdkEventButton
*gdk_event
,
2325 wxapp_install_idle_handler();
2328 g_blockEventsOnScroll
= TRUE
;
2330 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2332 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2338 //-----------------------------------------------------------------------------
2339 // "button_release_event" from scrollbar
2340 //-----------------------------------------------------------------------------
2342 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2343 GdkEventButton
*WXUNUSED(gdk_event
),
2348 // don't test here as we can release the mouse while being over
2349 // a different window than the slider
2351 // if (gdk_event->window != widget->slider) return FALSE;
2353 g_blockEventsOnScroll
= FALSE
;
2355 if (win
->m_isScrolling
)
2357 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2361 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2362 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2364 value
= (int)(win
->m_hAdjust
->value
+0.5);
2367 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2369 value
= (int)(win
->m_vAdjust
->value
+0.5);
2373 wxScrollWinEvent
event( command
, value
, dir
);
2374 event
.SetEventObject( win
);
2375 win
->GetEventHandler()->ProcessEvent( event
);
2378 win
->m_isScrolling
= FALSE
;
2383 // ----------------------------------------------------------------------------
2384 // this wxWindowBase function is implemented here (in platform-specific file)
2385 // because it is static and so couldn't be made virtual
2386 // ----------------------------------------------------------------------------
2388 wxWindow
*wxWindowBase::DoFindFocus()
2390 // the cast is necessary when we compile in wxUniversal mode
2391 return (wxWindow
*)g_focusWindow
;
2395 //-----------------------------------------------------------------------------
2396 // "realize" from m_widget
2397 //-----------------------------------------------------------------------------
2399 /* We cannot set colours and fonts before the widget has
2400 been realized, so we do this directly after realization. */
2403 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2408 wxapp_install_idle_handler();
2413 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2414 gtk_im_context_set_client_window( win
->m_imData
->context
,
2415 pizza
->bin_window
);
2419 wxWindowCreateEvent
event( win
);
2420 event
.SetEventObject( win
);
2421 win
->GetEventHandler()->ProcessEvent( event
);
2426 //-----------------------------------------------------------------------------
2428 //-----------------------------------------------------------------------------
2431 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2432 GtkAllocation
*WXUNUSED(alloc
),
2436 wxapp_install_idle_handler();
2438 if (!win
->m_hasScrolling
) return;
2440 int client_width
= 0;
2441 int client_height
= 0;
2442 win
->GetClientSize( &client_width
, &client_height
);
2443 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2446 win
->m_oldClientWidth
= client_width
;
2447 win
->m_oldClientHeight
= client_height
;
2449 if (!win
->m_nativeSizeEvent
)
2451 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2452 event
.SetEventObject( win
);
2453 win
->GetEventHandler()->ProcessEvent( event
);
2459 #define WXUNUSED_UNLESS_XIM(param) param
2461 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2464 /* Resize XIM window */
2467 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2468 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2469 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2472 wxapp_install_idle_handler();
2478 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2482 gdk_window_get_size (widget
->window
, &width
, &height
);
2483 win
->m_icattr
->preedit_area
.width
= width
;
2484 win
->m_icattr
->preedit_area
.height
= height
;
2485 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2490 //-----------------------------------------------------------------------------
2491 // "realize" from m_wxwindow
2492 //-----------------------------------------------------------------------------
2494 /* Initialize XIM support */
2497 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2498 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2501 wxapp_install_idle_handler();
2504 if (win
->m_ic
) return FALSE
;
2505 if (!widget
) return FALSE
;
2506 if (!gdk_im_ready()) return FALSE
;
2508 win
->m_icattr
= gdk_ic_attr_new();
2509 if (!win
->m_icattr
) return FALSE
;
2513 GdkColormap
*colormap
;
2514 GdkICAttr
*attr
= win
->m_icattr
;
2515 unsigned attrmask
= GDK_IC_ALL_REQ
;
2517 GdkIMStyle supported_style
= (GdkIMStyle
)
2518 (GDK_IM_PREEDIT_NONE
|
2519 GDK_IM_PREEDIT_NOTHING
|
2520 GDK_IM_PREEDIT_POSITION
|
2521 GDK_IM_STATUS_NONE
|
2522 GDK_IM_STATUS_NOTHING
);
2524 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2525 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2527 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2528 attr
->client_window
= widget
->window
;
2530 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2531 gtk_widget_get_default_colormap ())
2533 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2534 attr
->preedit_colormap
= colormap
;
2537 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2538 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2539 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2540 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2542 switch (style
& GDK_IM_PREEDIT_MASK
)
2544 case GDK_IM_PREEDIT_POSITION
:
2545 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2547 g_warning ("over-the-spot style requires fontset");
2551 gdk_window_get_size (widget
->window
, &width
, &height
);
2553 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2554 attr
->spot_location
.x
= 0;
2555 attr
->spot_location
.y
= height
;
2556 attr
->preedit_area
.x
= 0;
2557 attr
->preedit_area
.y
= 0;
2558 attr
->preedit_area
.width
= width
;
2559 attr
->preedit_area
.height
= height
;
2560 attr
->preedit_fontset
= widget
->style
->font
;
2565 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2567 if (win
->m_ic
== NULL
)
2568 g_warning ("Can't create input context.");
2571 mask
= gdk_window_get_events (widget
->window
);
2572 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2573 gdk_window_set_events (widget
->window
, mask
);
2575 if (GTK_WIDGET_HAS_FOCUS(widget
))
2576 gdk_im_begin (win
->m_ic
, widget
->window
);
2583 //-----------------------------------------------------------------------------
2584 // InsertChild for wxWindowGTK.
2585 //-----------------------------------------------------------------------------
2587 /* Callback for wxWindowGTK. This very strange beast has to be used because
2588 * C++ has no virtual methods in a constructor. We have to emulate a
2589 * virtual function here as wxNotebook requires a different way to insert
2590 * a child in it. I had opted for creating a wxNotebookPage window class
2591 * which would have made this superfluous (such in the MDI window system),
2592 * but no-one was listening to me... */
2594 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2596 /* the window might have been scrolled already, do we
2597 have to adapt the position */
2598 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2599 child
->m_x
+= pizza
->xoffset
;
2600 child
->m_y
+= pizza
->yoffset
;
2602 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2603 GTK_WIDGET(child
->m_widget
),
2610 //-----------------------------------------------------------------------------
2612 //-----------------------------------------------------------------------------
2614 wxWindow
*wxGetActiveWindow()
2616 return wxWindow::FindFocus();
2619 //-----------------------------------------------------------------------------
2621 //-----------------------------------------------------------------------------
2623 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2625 #ifdef __WXUNIVERSAL__
2626 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2628 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2629 #endif // __WXUNIVERSAL__/__WXGTK__
2631 void wxWindowGTK::Init()
2634 m_widget
= (GtkWidget
*) NULL
;
2635 m_wxwindow
= (GtkWidget
*) NULL
;
2636 m_focusWidget
= (GtkWidget
*) NULL
;
2646 m_needParent
= TRUE
;
2647 m_isBeingDeleted
= FALSE
;
2650 m_nativeSizeEvent
= FALSE
;
2652 m_hasScrolling
= FALSE
;
2653 m_isScrolling
= FALSE
;
2655 m_hAdjust
= (GtkAdjustment
*) NULL
;
2656 m_vAdjust
= (GtkAdjustment
*) NULL
;
2657 m_oldHorizontalPos
=
2658 m_oldVerticalPos
= 0.0;
2660 m_oldClientHeight
= 0;
2664 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2666 m_acceptsFocus
= FALSE
;
2669 m_clipPaintRegion
= FALSE
;
2671 m_needsStyleChange
= false;
2673 m_cursor
= *wxSTANDARD_CURSOR
;
2677 m_x11Context
= NULL
;
2678 m_dirtyTabOrder
= false;
2681 m_ic
= (GdkIC
*) NULL
;
2682 m_icattr
= (GdkICAttr
*) NULL
;
2687 wxWindowGTK::wxWindowGTK()
2692 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2697 const wxString
&name
)
2701 Create( parent
, id
, pos
, size
, style
, name
);
2704 bool wxWindowGTK::Create( wxWindow
*parent
,
2709 const wxString
&name
)
2711 if (!PreCreation( parent
, pos
, size
) ||
2712 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2714 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2718 m_insertCallback
= wxInsertChildInWindow
;
2720 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2721 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2723 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2725 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2726 scroll_class
->scrollbar_spacing
= 0;
2728 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2730 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2731 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2733 m_wxwindow
= gtk_pizza_new();
2735 #ifndef __WXUNIVERSAL__
2736 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2738 if (HasFlag(wxRAISED_BORDER
))
2740 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2742 else if (HasFlag(wxSUNKEN_BORDER
))
2744 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2746 else if (HasFlag(wxSIMPLE_BORDER
))
2748 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2752 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2754 #endif // __WXUNIVERSAL__
2756 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2758 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2759 m_acceptsFocus
= TRUE
;
2761 // I _really_ don't want scrollbars in the beginning
2762 m_vAdjust
->lower
= 0.0;
2763 m_vAdjust
->upper
= 1.0;
2764 m_vAdjust
->value
= 0.0;
2765 m_vAdjust
->step_increment
= 1.0;
2766 m_vAdjust
->page_increment
= 1.0;
2767 m_vAdjust
->page_size
= 5.0;
2768 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2769 m_hAdjust
->lower
= 0.0;
2770 m_hAdjust
->upper
= 1.0;
2771 m_hAdjust
->value
= 0.0;
2772 m_hAdjust
->step_increment
= 1.0;
2773 m_hAdjust
->page_increment
= 1.0;
2774 m_hAdjust
->page_size
= 5.0;
2775 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2777 // these handlers block mouse events to any window during scrolling such as
2778 // motion events and prevent GTK and wxWidgets from fighting over where the
2781 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2782 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2784 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2785 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2787 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2788 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2790 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2791 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2793 // these handlers get notified when screen updates are required either when
2794 // scrolling or when the window size (and therefore scrollbar configuration)
2797 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2798 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2799 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2800 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2802 gtk_widget_show( m_wxwindow
);
2805 m_parent
->DoAddChild( this );
2807 m_focusWidget
= m_wxwindow
;
2814 wxWindowGTK::~wxWindowGTK()
2818 if (g_focusWindow
== this)
2819 g_focusWindow
= NULL
;
2821 if ( g_delayedFocus
== this )
2822 g_delayedFocus
= NULL
;
2824 m_isBeingDeleted
= TRUE
;
2834 gdk_ic_destroy (m_ic
);
2836 gdk_ic_attr_destroy (m_icattr
);
2841 gtk_widget_destroy( m_wxwindow
);
2842 m_wxwindow
= (GtkWidget
*) NULL
;
2847 gtk_widget_destroy( m_widget
);
2848 m_widget
= (GtkWidget
*) NULL
;
2856 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2858 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2860 // Use either the given size, or the default if -1 is given.
2861 // See wxWindowBase for these functions.
2862 m_width
= WidthDefault(size
.x
) ;
2863 m_height
= HeightDefault(size
.y
);
2871 void wxWindowGTK::PostCreation()
2873 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2879 // these get reported to wxWidgets -> wxPaintEvent
2881 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2883 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2884 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2887 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2888 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2890 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2892 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2893 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2896 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2901 // Create input method handler
2902 m_imData
= new wxGtkIMData
;
2904 // Cannot handle drawing preedited text yet
2905 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2907 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2908 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2911 // these are called when the "sunken" or "raised" borders are drawn
2912 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2913 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2916 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2917 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2923 if (!GTK_IS_WINDOW(m_widget
))
2925 if (m_focusWidget
== NULL
)
2926 m_focusWidget
= m_widget
;
2928 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2929 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2931 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2932 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2935 // connect to the various key and mouse handlers
2937 GtkWidget
*connect_widget
= GetConnectWidget();
2939 ConnectWidget( connect_widget
);
2941 /* We cannot set colours, fonts and cursors before the widget has
2942 been realized, so we do this directly after realization */
2943 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2944 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2948 // Catch native resize events
2949 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2950 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2952 // Initialize XIM support
2953 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2954 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2956 // And resize XIM window
2957 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2958 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2961 if (GTK_IS_COMBO(m_widget
))
2963 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
2965 gtk_signal_connect( GTK_OBJECT(gcombo
->entry
), "size_request",
2966 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback
),
2971 // This is needed if we want to add our windows into native
2972 // GTK controls, such as the toolbar. With this callback, the
2973 // toolbar gets to know the correct size (the one set by the
2974 // programmer). Sadly, it misbehaves for wxComboBox.
2975 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2976 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2980 InheritAttributes();
2984 // unless the window was created initially hidden (i.e. Hide() had been
2985 // called before Create()), we should show it at GTK+ level as well
2987 gtk_widget_show( m_widget
);
2990 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2992 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2993 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2995 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2996 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2998 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2999 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
3001 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
3002 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
3004 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
3005 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
3008 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
3009 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
3010 g_signal_connect(widget
, "popup_menu",
3011 G_CALLBACK(wxgtk_window_popup_menu_callback
), this);
3014 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
3015 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
3017 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
3018 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
3021 bool wxWindowGTK::Destroy()
3023 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3027 return wxWindowBase::Destroy();
3030 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
3032 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
3035 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
3037 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3038 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
3041 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3044 if (m_resizing
) return; /* I don't like recursions */
3047 int currentX
, currentY
;
3048 GetPosition(¤tX
, ¤tY
);
3049 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3051 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3053 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
3055 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
3057 /* don't set the size for children of wxNotebook, just take the values. */
3065 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3066 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
3068 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
3069 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3073 m_x
= x
+ pizza
->xoffset
;
3074 m_y
= y
+ pizza
->yoffset
;
3077 // calculate the best size if we should auto size the window
3078 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
3079 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
3081 const wxSize sizeBest
= GetBestSize();
3082 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3084 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3085 height
= sizeBest
.y
;
3093 int minWidth
= GetMinWidth(),
3094 minHeight
= GetMinHeight(),
3095 maxWidth
= GetMaxWidth(),
3096 maxHeight
= GetMaxHeight();
3098 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3099 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3100 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3101 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3104 int bottom_border
= 0;
3107 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3109 /* the default button has a border around it */
3115 DoMoveWindow( m_x
-border
,
3118 m_height
+border
+bottom_border
);
3123 /* Sometimes the client area changes size without the
3124 whole windows's size changing, but if the whole
3125 windows's size doesn't change, no wxSizeEvent will
3126 normally be sent. Here we add an extra test if
3127 the client test has been changed and this will
3129 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3133 wxPrintf( "OnSize sent from " );
3134 if (GetClassInfo() && GetClassInfo()->GetClassName())
3135 wxPrintf( GetClassInfo()->GetClassName() );
3136 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3139 if (!m_nativeSizeEvent
)
3141 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3142 event
.SetEventObject( this );
3143 GetEventHandler()->ProcessEvent( event
);
3149 void wxWindowGTK::OnInternalIdle()
3152 if ( m_dirtyTabOrder
)
3155 // Update style if the window was not yet realized
3156 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3157 if (m_needsStyleChange
)
3159 SetBackgroundStyle(GetBackgroundStyle());
3160 m_needsStyleChange
= false;
3163 // Update invalidated regions.
3166 wxCursor cursor
= m_cursor
;
3167 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3171 /* I now set the cursor anew in every OnInternalIdle call
3172 as setting the cursor in a parent window also effects the
3173 windows above so that checking for the current cursor is
3178 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3180 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3182 if (!g_globalCursor
.Ok())
3183 cursor
= *wxSTANDARD_CURSOR
;
3185 window
= m_widget
->window
;
3186 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3187 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3193 GdkWindow
*window
= m_widget
->window
;
3194 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3195 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3200 if (wxUpdateUIEvent::CanUpdate(this))
3201 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3204 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3206 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3208 if (width
) (*width
) = m_width
;
3209 if (height
) (*height
) = m_height
;
3212 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3214 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3218 SetSize( width
, height
);
3225 #ifndef __WXUNIVERSAL__
3226 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3228 /* when using GTK 1.2 we set the shadow border size to 2 */
3232 if (HasFlag(wxSIMPLE_BORDER
))
3234 /* when using GTK 1.2 we set the simple border size to 1 */
3238 #endif // __WXUNIVERSAL__
3242 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3244 GtkRequisition vscroll_req
;
3245 vscroll_req
.width
= 2;
3246 vscroll_req
.height
= 2;
3247 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3248 (scroll_window
->vscrollbar
, &vscroll_req
);
3250 GtkRequisition hscroll_req
;
3251 hscroll_req
.width
= 2;
3252 hscroll_req
.height
= 2;
3253 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3254 (scroll_window
->hscrollbar
, &hscroll_req
);
3256 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3258 if (scroll_window
->vscrollbar_visible
)
3260 dw
+= vscroll_req
.width
;
3261 dw
+= scroll_class
->scrollbar_spacing
;
3264 if (scroll_window
->hscrollbar_visible
)
3266 dh
+= hscroll_req
.height
;
3267 dh
+= scroll_class
->scrollbar_spacing
;
3271 SetSize( width
+dw
, height
+dh
);
3275 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3277 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3281 if (width
) (*width
) = m_width
;
3282 if (height
) (*height
) = m_height
;
3289 #ifndef __WXUNIVERSAL__
3290 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3292 /* when using GTK 1.2 we set the shadow border size to 2 */
3296 if (HasFlag(wxSIMPLE_BORDER
))
3298 /* when using GTK 1.2 we set the simple border size to 1 */
3302 #endif // __WXUNIVERSAL__
3306 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3308 GtkRequisition vscroll_req
;
3309 vscroll_req
.width
= 2;
3310 vscroll_req
.height
= 2;
3311 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3312 (scroll_window
->vscrollbar
, &vscroll_req
);
3314 GtkRequisition hscroll_req
;
3315 hscroll_req
.width
= 2;
3316 hscroll_req
.height
= 2;
3317 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3318 (scroll_window
->hscrollbar
, &hscroll_req
);
3320 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3322 if (scroll_window
->vscrollbar_visible
)
3324 dw
+= vscroll_req
.width
;
3325 dw
+= scroll_class
->scrollbar_spacing
;
3328 if (scroll_window
->hscrollbar_visible
)
3330 dh
+= hscroll_req
.height
;
3331 dh
+= scroll_class
->scrollbar_spacing
;
3335 if (width
) (*width
) = m_width
- dw
;
3336 if (height
) (*height
) = m_height
- dh
;
3340 printf( "GetClientSize, name %s ", GetName().c_str() );
3341 if (width) printf( " width = %d", (*width) );
3342 if (height) printf( " height = %d", (*height) );
3347 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3349 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3353 if (m_parent
&& m_parent
->m_wxwindow
)
3355 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3356 dx
= pizza
->xoffset
;
3357 dy
= pizza
->yoffset
;
3360 if (x
) (*x
) = m_x
- dx
;
3361 if (y
) (*y
) = m_y
- dy
;
3364 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3366 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3368 if (!m_widget
->window
) return;
3370 GdkWindow
*source
= (GdkWindow
*) NULL
;
3372 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3374 source
= m_widget
->window
;
3378 gdk_window_get_origin( source
, &org_x
, &org_y
);
3382 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3384 org_x
+= m_widget
->allocation
.x
;
3385 org_y
+= m_widget
->allocation
.y
;
3393 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3395 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3397 if (!m_widget
->window
) return;
3399 GdkWindow
*source
= (GdkWindow
*) NULL
;
3401 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3403 source
= m_widget
->window
;
3407 gdk_window_get_origin( source
, &org_x
, &org_y
);
3411 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3413 org_x
+= m_widget
->allocation
.x
;
3414 org_y
+= m_widget
->allocation
.y
;
3422 bool wxWindowGTK::Show( bool show
)
3424 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3426 if (!wxWindowBase::Show(show
))
3433 gtk_widget_show( m_widget
);
3435 gtk_widget_hide( m_widget
);
3437 wxShowEvent
eventShow(GetId(), show
);
3438 eventShow
.SetEventObject(this);
3440 GetEventHandler()->ProcessEvent(eventShow
);
3445 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3447 win
->OnParentEnable(enable
);
3449 // Recurse, so that children have the opportunity to Do The Right Thing
3450 // and reset colours that have been messed up by a parent's (really ancestor's)
3452 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3454 node
= node
->GetNext() )
3456 wxWindow
*child
= node
->GetData();
3457 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3458 wxWindowNotifyEnable(child
, enable
);
3462 bool wxWindowGTK::Enable( bool enable
)
3464 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3466 if (!wxWindowBase::Enable(enable
))
3472 gtk_widget_set_sensitive( m_widget
, enable
);
3474 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3476 wxWindowNotifyEnable(this, enable
);
3481 int wxWindowGTK::GetCharHeight() const
3483 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3485 wxFont font
= GetFont();
3486 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3489 PangoContext
*context
= NULL
;
3491 context
= gtk_widget_get_pango_context( m_widget
);
3496 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3497 PangoLayout
*layout
= pango_layout_new(context
);
3498 pango_layout_set_font_description(layout
, desc
);
3499 pango_layout_set_text(layout
, "H", 1);
3500 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3502 PangoRectangle rect
;
3503 pango_layout_line_get_extents(line
, NULL
, &rect
);
3505 g_object_unref( G_OBJECT( layout
) );
3507 return (int) PANGO_PIXELS(rect
.height
);
3509 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3511 return gfont
->ascent
+ gfont
->descent
;
3515 int wxWindowGTK::GetCharWidth() const
3517 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3519 wxFont font
= GetFont();
3520 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3523 PangoContext
*context
= NULL
;
3525 context
= gtk_widget_get_pango_context( m_widget
);
3530 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3531 PangoLayout
*layout
= pango_layout_new(context
);
3532 pango_layout_set_font_description(layout
, desc
);
3533 pango_layout_set_text(layout
, "g", 1);
3534 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3536 PangoRectangle rect
;
3537 pango_layout_line_get_extents(line
, NULL
, &rect
);
3539 g_object_unref( G_OBJECT( layout
) );
3541 return (int) PANGO_PIXELS(rect
.width
);
3543 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3545 return gdk_string_width( gfont
, "g" );
3549 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3553 int *externalLeading
,
3554 const wxFont
*theFont
) const
3556 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3558 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3560 if (string
.IsEmpty())
3568 PangoContext
*context
= NULL
;
3570 context
= gtk_widget_get_pango_context( m_widget
);
3579 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3580 PangoLayout
*layout
= pango_layout_new(context
);
3581 pango_layout_set_font_description(layout
, desc
);
3584 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3585 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3587 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3588 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3589 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3593 PangoRectangle rect
;
3594 pango_layout_get_extents(layout
, NULL
, &rect
);
3596 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3597 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3600 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3601 int baseline
= pango_layout_iter_get_baseline(iter
);
3602 pango_layout_iter_free(iter
);
3603 *descent
= *y
- PANGO_PIXELS(baseline
);
3605 if (externalLeading
) (*externalLeading
) = 0; // ??
3607 g_object_unref( G_OBJECT( layout
) );
3609 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3610 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3611 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3612 if (descent
) (*descent
) = font
->descent
;
3613 if (externalLeading
) (*externalLeading
) = 0; // ??
3617 void wxWindowGTK::SetFocus()
3619 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3622 // don't do anything if we already have focus
3628 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3630 gtk_widget_grab_focus (m_wxwindow
);
3636 if (GTK_IS_CONTAINER(m_widget
))
3638 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3642 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3645 if (!GTK_WIDGET_REALIZED(m_widget
))
3647 // we can't set the focus to the widget now so we remember that
3648 // it should be focused and will do it later, during the idle
3649 // time, as soon as we can
3650 wxLogTrace(TRACE_FOCUS
,
3651 _T("Delaying setting focus to %s(%s)"),
3652 GetClassInfo()->GetClassName(), GetLabel().c_str());
3654 g_delayedFocus
= this;
3658 wxLogTrace(TRACE_FOCUS
,
3659 _T("Setting focus to %s(%s)"),
3660 GetClassInfo()->GetClassName(), GetLabel().c_str());
3662 gtk_widget_grab_focus (m_widget
);
3667 if (GTK_IS_CONTAINER(m_widget
))
3669 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3674 wxLogTrace(TRACE_FOCUS
,
3675 _T("Can't set focus to %s(%s)"),
3676 GetClassInfo()->GetClassName(), GetLabel().c_str());
3681 bool wxWindowGTK::AcceptsFocus() const
3683 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3686 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3688 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3690 wxWindowGTK
*oldParent
= m_parent
,
3691 *newParent
= (wxWindowGTK
*)newParentBase
;
3693 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3695 if ( !wxWindowBase::Reparent(newParent
) )
3698 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3700 /* prevent GTK from deleting the widget arbitrarily */
3701 gtk_widget_ref( m_widget
);
3705 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3708 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3712 /* insert GTK representation */
3713 (*(newParent
->m_insertCallback
))(newParent
, this);
3716 /* reverse: prevent GTK from deleting the widget arbitrarily */
3717 gtk_widget_unref( m_widget
);
3722 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3724 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3726 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3728 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3733 /* insert GTK representation */
3734 (*m_insertCallback
)(this, child
);
3739 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3741 wxWindowBase::AddChild(child
);
3742 m_dirtyTabOrder
= true;
3744 wxapp_install_idle_handler();
3747 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3749 wxWindowBase::RemoveChild(child
);
3750 m_dirtyTabOrder
= true;
3752 wxapp_install_idle_handler();
3755 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3757 wxWindowBase::DoMoveInTabOrder(win
, move
);
3758 m_dirtyTabOrder
= true;
3760 wxapp_install_idle_handler();
3763 void wxWindowGTK::RealizeTabOrder()
3767 if (m_children
.size() > 0)
3769 GList
*chain
= NULL
;
3771 for (wxWindowList::const_iterator i
= m_children
.begin();
3772 i
!= m_children
.end(); ++i
)
3774 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3777 chain
= g_list_reverse(chain
);
3779 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3784 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3788 m_dirtyTabOrder
= false;
3791 #endif // __WXGTK20__
3793 void wxWindowGTK::Raise()
3795 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3797 if (m_wxwindow
&& m_wxwindow
->window
)
3799 gdk_window_raise( m_wxwindow
->window
);
3801 else if (m_widget
->window
)
3803 gdk_window_raise( m_widget
->window
);
3807 void wxWindowGTK::Lower()
3809 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3811 if (m_wxwindow
&& m_wxwindow
->window
)
3813 gdk_window_lower( m_wxwindow
->window
);
3815 else if (m_widget
->window
)
3817 gdk_window_lower( m_widget
->window
);
3821 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3823 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3825 if (cursor
== m_cursor
)
3829 wxapp_install_idle_handler();
3831 if (cursor
== wxNullCursor
)
3832 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3834 return wxWindowBase::SetCursor( cursor
);
3837 void wxWindowGTK::WarpPointer( int x
, int y
)
3839 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3841 // We provide this function ourselves as it is
3842 // missing in GDK (top of this file).
3844 GdkWindow
*window
= (GdkWindow
*) NULL
;
3846 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3848 window
= GetConnectWidget()->window
;
3851 gdk_window_warp_pointer( window
, x
, y
);
3855 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3857 if (!m_widget
) return;
3858 if (!m_widget
->window
) return;
3862 wxapp_install_idle_handler();
3864 wxRect
myRect(0,0,0,0);
3865 if (m_wxwindow
&& rect
)
3867 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3868 m_wxwindow
->allocation
.height
));
3869 myRect
.Intersect(*rect
);
3870 if (!myRect
.width
|| !myRect
.height
)
3871 // nothing to do, rectangle is empty
3876 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3880 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3881 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3885 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3886 m_clearRegion
.Clear();
3887 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3895 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3896 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3900 GdkRectangle gdk_rect
;
3901 gdk_rect
.x
= rect
->x
;
3902 gdk_rect
.y
= rect
->y
;
3903 gdk_rect
.width
= rect
->width
;
3904 gdk_rect
.height
= rect
->height
;
3905 gtk_widget_draw( m_widget
, &gdk_rect
);
3912 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3913 m_updateRegion
.Clear();
3914 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3918 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3926 GdkRectangle gdk_rect
;
3927 gdk_rect
.x
= rect
->x
;
3928 gdk_rect
.y
= rect
->y
;
3929 gdk_rect
.width
= rect
->width
;
3930 gdk_rect
.height
= rect
->height
;
3931 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3935 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3941 void wxWindowGTK::Update()
3946 void wxWindowGTK::GtkUpdate()
3949 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3950 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3952 if (!m_updateRegion
.IsEmpty())
3953 GtkSendPaintEvents();
3957 void wxWindowGTK::GtkSendPaintEvents()
3962 m_clearRegion
.Clear();
3964 m_updateRegion
.Clear();
3968 // Clip to paint region in wxClientDC
3969 m_clipPaintRegion
= TRUE
;
3971 // widget to draw on
3972 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3974 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3976 // find ancestor from which to steal background
3977 wxWindow
*parent
= GetParent();
3978 while (parent
&& !parent
->IsTopLevel())
3979 parent
= parent
->GetParent();
3981 parent
= (wxWindow
*)this;
3983 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3985 wxRegionIterator
upd( m_updateRegion
);
3989 rect
.x
= upd
.GetX();
3990 rect
.y
= upd
.GetY();
3991 rect
.width
= upd
.GetWidth();
3992 rect
.height
= upd
.GetHeight();
3994 gtk_paint_flat_box( parent
->m_widget
->style
,
3996 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
4011 wxWindowDC
dc( (wxWindow
*)this );
4012 dc
.SetClippingRegion( m_updateRegion
);
4014 wxEraseEvent
erase_event( GetId(), &dc
);
4015 erase_event
.SetEventObject( this );
4017 GetEventHandler()->ProcessEvent(erase_event
);
4020 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4022 wxWindowDC
dc( (wxWindow
*)this );
4023 if (m_clearRegion
.IsEmpty())
4024 dc
.SetClippingRegion( m_updateRegion
);
4026 dc
.SetClippingRegion( m_clearRegion
);
4028 wxEraseEvent
erase_event( GetId(), &dc
);
4029 erase_event
.SetEventObject( this );
4031 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4035 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
4036 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4038 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
4040 wxRegionIterator
upd( m_clearRegion
);
4043 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
4044 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
4048 m_clearRegion
.Clear();
4052 wxNcPaintEvent
nc_paint_event( GetId() );
4053 nc_paint_event
.SetEventObject( this );
4054 GetEventHandler()->ProcessEvent( nc_paint_event
);
4056 wxPaintEvent
paint_event( GetId() );
4057 paint_event
.SetEventObject( this );
4058 GetEventHandler()->ProcessEvent( paint_event
);
4060 m_clipPaintRegion
= FALSE
;
4062 #ifndef __WXUNIVERSAL__
4064 // The following code will result in all window-less widgets
4065 // being redrawn because the wxWidgets class is allowed to
4066 // paint over the window-less widgets.
4068 GList
*children
= pizza
->children
;
4071 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
4072 children
= children
->next
;
4074 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
4075 GTK_WIDGET_DRAWABLE (child
->widget
))
4077 // Get intersection of widget area and update region
4078 wxRegion
region( m_updateRegion
);
4080 GdkEventExpose gdk_event
;
4081 gdk_event
.type
= GDK_EXPOSE
;
4082 gdk_event
.window
= pizza
->bin_window
;
4083 gdk_event
.count
= 0;
4085 wxRegionIterator
upd( m_updateRegion
);
4089 rect
.x
= upd
.GetX();
4090 rect
.y
= upd
.GetY();
4091 rect
.width
= upd
.GetWidth();
4092 rect
.height
= upd
.GetHeight();
4094 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4096 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4106 m_updateRegion
.Clear();
4109 void wxWindowGTK::ClearBackground()
4111 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4114 if (m_wxwindow
&& m_wxwindow
->window
)
4116 m_clearRegion
.Clear();
4117 wxSize
size( GetClientSize() );
4118 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4120 // Better do this in idle?
4127 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4129 wxWindowBase::DoSetToolTip(tip
);
4132 m_tooltip
->Apply( (wxWindow
*)this );
4135 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4137 wxString
tmp( tip
);
4138 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4140 #endif // wxUSE_TOOLTIPS
4142 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4144 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4146 if (!wxWindowBase::SetBackgroundColour(colour
))
4151 // We need the pixel value e.g. for background clearing.
4152 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4155 // apply style change (forceStyle=true so that new style is applied
4156 // even if the bg colour changed from valid to wxNullColour)
4157 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4158 ApplyWidgetStyle(true);
4163 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4165 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4167 if (!wxWindowBase::SetForegroundColour(colour
))
4174 // We need the pixel value e.g. for background clearing.
4175 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4178 // apply style change (forceStyle=true so that new style is applied
4179 // even if the bg colour changed from valid to wxNullColour):
4180 ApplyWidgetStyle(true);
4186 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4188 return gtk_widget_get_pango_context( m_widget
);
4191 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4194 m_x11Context
= pango_x_get_context( gdk_display
);
4196 return m_x11Context
;
4200 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4202 // do we need to apply any changes at all?
4205 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4210 GtkRcStyle
*style
= gtk_rc_style_new();
4216 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4218 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4219 style
->fontset_name
= g_strdup(xfontname
.c_str());
4223 if ( m_foregroundColour
.Ok() )
4225 GdkColor
*fg
= m_foregroundColour
.GetColor();
4227 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4228 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4230 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4231 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4233 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4234 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4237 if ( m_backgroundColour
.Ok() )
4239 GdkColor
*bg
= m_backgroundColour
.GetColor();
4241 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4242 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4243 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4244 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4246 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4247 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4248 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4249 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4251 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4252 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4253 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4254 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4256 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4257 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4258 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4259 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4265 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4267 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4270 DoApplyWidgetStyle(style
);
4271 gtk_rc_style_unref(style
);
4274 // Style change may affect GTK+'s size calculation:
4275 InvalidateBestSize();
4278 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4281 gtk_widget_modify_style(m_wxwindow
, style
);
4282 gtk_widget_modify_style(m_widget
, style
);
4285 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4287 wxWindowBase::SetBackgroundStyle(style
);
4289 if (style
== wxBG_STYLE_CUSTOM
)
4291 GdkWindow
*window
= (GdkWindow
*) NULL
;
4293 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4295 window
= GetConnectWidget()->window
;
4299 // Make sure GDK/X11 doesn't refresh the window
4301 gdk_window_set_back_pixmap( window
, None
, False
);
4303 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4306 m_needsStyleChange
= false;
4309 // Do in OnIdle, because the window is not yet available
4310 m_needsStyleChange
= true;
4312 // Don't apply widget style, or we get a grey background
4316 // apply style change (forceStyle=true so that new style is applied
4317 // even if the bg colour changed from valid to wxNullColour):
4318 ApplyWidgetStyle(true);
4323 //-----------------------------------------------------------------------------
4324 // Pop-up menu stuff
4325 //-----------------------------------------------------------------------------
4327 #if wxUSE_MENUS_NATIVE
4330 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4332 *is_waiting
= FALSE
;
4335 void SetInvokingWindow( wxMenu
*menu
, wxWindow
* win
)
4337 menu
->SetInvokingWindow( win
);
4339 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4342 wxMenuItem
*menuitem
= node
->GetData();
4343 if (menuitem
->IsSubMenu())
4345 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4348 node
= node
->GetNext();
4352 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4355 gboolean
* WXUNUSED(whatever
),
4357 gpointer user_data
)
4359 // ensure that the menu appears entirely on screen
4361 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4363 wxSize sizeScreen
= wxGetDisplaySize();
4364 wxPoint
*pos
= (wxPoint
*)user_data
;
4366 gint xmax
= sizeScreen
.x
- req
.width
,
4367 ymax
= sizeScreen
.y
- req
.height
;
4369 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4370 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4373 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4375 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4377 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4379 // NOTE: if you change this code, you need to update
4380 // the same code in taskbar.cpp as well. This
4381 // is ugly code duplication, I know,
4383 SetInvokingWindow( menu
, this );
4387 bool is_waiting
= true;
4389 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4391 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4392 (gpointer
)&is_waiting
);
4396 GtkMenuPositionFunc posfunc
;
4397 if ( x
== -1 && y
== -1 )
4399 // use GTK's default positioning algorithm
4405 pos
= ClientToScreen(wxPoint(x
, y
));
4407 posfunc
= wxPopupMenuPositionCallback
;
4411 GTK_MENU(menu
->m_menu
),
4412 (GtkWidget
*) NULL
, // parent menu shell
4413 (GtkWidget
*) NULL
, // parent menu item
4414 posfunc
, // function to position it
4415 userdata
, // client data
4416 0, // button used to activate it
4418 gtk_get_current_event_time()
4420 gs_timeLastClick
// the time of activation
4426 gtk_main_iteration();
4429 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4434 #endif // wxUSE_MENUS_NATIVE
4436 #if wxUSE_DRAG_AND_DROP
4438 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4440 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4442 GtkWidget
*dnd_widget
= GetConnectWidget();
4444 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4446 if (m_dropTarget
) delete m_dropTarget
;
4447 m_dropTarget
= dropTarget
;
4449 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4452 #endif // wxUSE_DRAG_AND_DROP
4454 GtkWidget
* wxWindowGTK::GetConnectWidget()
4456 GtkWidget
*connect_widget
= m_widget
;
4457 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4459 return connect_widget
;
4462 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4465 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4467 return (window
== m_widget
->window
);
4470 bool wxWindowGTK::SetFont( const wxFont
&font
)
4472 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4474 if (!wxWindowBase::SetFont(font
))
4477 // apply style change (forceStyle=true so that new style is applied
4478 // even if the font changed from valid to wxNullFont):
4479 ApplyWidgetStyle(true);
4484 void wxWindowGTK::DoCaptureMouse()
4486 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4488 GdkWindow
*window
= (GdkWindow
*) NULL
;
4490 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4492 window
= GetConnectWidget()->window
;
4494 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4496 wxCursor
* cursor
= & m_cursor
;
4498 cursor
= wxSTANDARD_CURSOR
;
4500 gdk_pointer_grab( window
, FALSE
,
4502 (GDK_BUTTON_PRESS_MASK
|
4503 GDK_BUTTON_RELEASE_MASK
|
4504 GDK_POINTER_MOTION_HINT_MASK
|
4505 GDK_POINTER_MOTION_MASK
),
4507 cursor
->GetCursor(),
4508 (guint32
)GDK_CURRENT_TIME
);
4509 g_captureWindow
= this;
4510 g_captureWindowHasMouse
= TRUE
;
4513 void wxWindowGTK::DoReleaseMouse()
4515 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4517 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4519 g_captureWindow
= (wxWindowGTK
*) NULL
;
4521 GdkWindow
*window
= (GdkWindow
*) NULL
;
4523 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4525 window
= GetConnectWidget()->window
;
4530 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4534 wxWindow
*wxWindowBase::GetCapture()
4536 return (wxWindow
*)g_captureWindow
;
4539 bool wxWindowGTK::IsRetained() const
4544 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4545 int range
, bool refresh
)
4547 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4549 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4551 m_hasScrolling
= TRUE
;
4553 if (orient
== wxHORIZONTAL
)
4555 float fpos
= (float)pos
;
4556 float frange
= (float)range
;
4557 float fthumb
= (float)thumbVisible
;
4558 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4559 if (fpos
< 0.0) fpos
= 0.0;
4561 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4562 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4564 SetScrollPos( orient
, pos
, refresh
);
4568 m_oldHorizontalPos
= fpos
;
4570 m_hAdjust
->lower
= 0.0;
4571 m_hAdjust
->upper
= frange
;
4572 m_hAdjust
->value
= fpos
;
4573 m_hAdjust
->step_increment
= 1.0;
4574 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4575 m_hAdjust
->page_size
= fthumb
;
4579 float fpos
= (float)pos
;
4580 float frange
= (float)range
;
4581 float fthumb
= (float)thumbVisible
;
4582 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4583 if (fpos
< 0.0) fpos
= 0.0;
4585 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4586 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4588 SetScrollPos( orient
, pos
, refresh
);
4592 m_oldVerticalPos
= fpos
;
4594 m_vAdjust
->lower
= 0.0;
4595 m_vAdjust
->upper
= frange
;
4596 m_vAdjust
->value
= fpos
;
4597 m_vAdjust
->step_increment
= 1.0;
4598 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4599 m_vAdjust
->page_size
= fthumb
;
4602 if (orient
== wxHORIZONTAL
)
4603 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4605 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4608 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4610 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4612 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4614 if (orient
== wxHORIZONTAL
)
4616 float fpos
= (float)pos
;
4617 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4618 if (fpos
< 0.0) fpos
= 0.0;
4619 m_oldHorizontalPos
= fpos
;
4621 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4622 m_hAdjust
->value
= fpos
;
4626 float fpos
= (float)pos
;
4627 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4628 if (fpos
< 0.0) fpos
= 0.0;
4629 m_oldVerticalPos
= fpos
;
4631 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4632 m_vAdjust
->value
= fpos
;
4635 if (m_wxwindow
->window
)
4637 if (orient
== wxHORIZONTAL
)
4639 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4640 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4642 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4644 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4645 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4649 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4650 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4652 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4654 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4655 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4660 int wxWindowGTK::GetScrollThumb( int orient
) const
4662 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4664 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4666 if (orient
== wxHORIZONTAL
)
4667 return (int)(m_hAdjust
->page_size
+0.5);
4669 return (int)(m_vAdjust
->page_size
+0.5);
4672 int wxWindowGTK::GetScrollPos( int orient
) const
4674 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4676 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4678 if (orient
== wxHORIZONTAL
)
4679 return (int)(m_hAdjust
->value
+0.5);
4681 return (int)(m_vAdjust
->value
+0.5);
4684 int wxWindowGTK::GetScrollRange( int orient
) const
4686 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4688 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4690 if (orient
== wxHORIZONTAL
)
4691 return (int)(m_hAdjust
->upper
+0.5);
4693 return (int)(m_vAdjust
->upper
+0.5);
4696 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4698 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4700 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4702 // No scrolling requested.
4703 if ((dx
== 0) && (dy
== 0)) return;
4706 if (!m_updateRegion
.IsEmpty())
4708 m_updateRegion
.Offset( dx
, dy
);
4712 GetClientSize( &cw
, &ch
);
4713 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4716 if (!m_clearRegion
.IsEmpty())
4718 m_clearRegion
.Offset( dx
, dy
);
4722 GetClientSize( &cw
, &ch
);
4723 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4727 m_clipPaintRegion
= TRUE
;
4729 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4731 m_clipPaintRegion
= FALSE
;
4735 // Find the wxWindow at the current mouse position, also returning the mouse
4737 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4739 pt
= wxGetMousePosition();
4740 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4744 // Get the current mouse position.
4745 wxPoint
wxGetMousePosition()
4747 /* This crashes when used within wxHelpContext,
4748 so we have to use the X-specific implementation below.
4750 GdkModifierType *mask;
4751 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4753 return wxPoint(x, y);
4757 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4759 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4760 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4761 Window rootReturn
, childReturn
;
4762 int rootX
, rootY
, winX
, winY
;
4763 unsigned int maskReturn
;
4765 XQueryPointer (display
,
4769 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4770 return wxPoint(rootX
, rootY
);
4774 // ----------------------------------------------------------------------------
4776 // ----------------------------------------------------------------------------
4778 class wxWinModule
: public wxModule
4785 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4788 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4790 bool wxWinModule::OnInit()
4792 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4793 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4798 void wxWinModule::OnExit()
4801 gdk_gc_unref( g_eraseGC
);