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()
3945 // when we call Update() we really want to update the window immediately on
3946 // screen, even if itmeans flushing the entire queue and hence slowing down
3947 // everything -- but it should still be done, it's just that Update() should
3948 // be called very rarely
3952 void wxWindowGTK::GtkUpdate()
3955 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3956 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3958 if (!m_updateRegion
.IsEmpty())
3959 GtkSendPaintEvents();
3963 void wxWindowGTK::GtkSendPaintEvents()
3968 m_clearRegion
.Clear();
3970 m_updateRegion
.Clear();
3974 // Clip to paint region in wxClientDC
3975 m_clipPaintRegion
= TRUE
;
3977 // widget to draw on
3978 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3980 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
3982 // find ancestor from which to steal background
3983 wxWindow
*parent
= IsTopLevel() ? this : GetParent();
3984 while (parent
&& !parent
->IsTopLevel())
3985 parent
= parent
->GetParent();
3987 parent
= (wxWindow
*)this;
3989 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3991 wxRegionIterator
upd( m_updateRegion
);
3995 rect
.x
= upd
.GetX();
3996 rect
.y
= upd
.GetY();
3997 rect
.width
= upd
.GetWidth();
3998 rect
.height
= upd
.GetHeight();
4000 gtk_paint_flat_box( parent
->m_widget
->style
,
4002 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
4017 wxWindowDC
dc( (wxWindow
*)this );
4018 dc
.SetClippingRegion( m_updateRegion
);
4020 wxEraseEvent
erase_event( GetId(), &dc
);
4021 erase_event
.SetEventObject( this );
4023 GetEventHandler()->ProcessEvent(erase_event
);
4026 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4028 wxWindowDC
dc( (wxWindow
*)this );
4029 if (m_clearRegion
.IsEmpty())
4030 dc
.SetClippingRegion( m_updateRegion
);
4032 dc
.SetClippingRegion( m_clearRegion
);
4034 wxEraseEvent
erase_event( GetId(), &dc
);
4035 erase_event
.SetEventObject( this );
4037 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4041 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
4042 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4044 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
4046 wxRegionIterator
upd( m_clearRegion
);
4049 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
4050 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
4054 m_clearRegion
.Clear();
4058 wxNcPaintEvent
nc_paint_event( GetId() );
4059 nc_paint_event
.SetEventObject( this );
4060 GetEventHandler()->ProcessEvent( nc_paint_event
);
4062 wxPaintEvent
paint_event( GetId() );
4063 paint_event
.SetEventObject( this );
4064 GetEventHandler()->ProcessEvent( paint_event
);
4066 m_clipPaintRegion
= FALSE
;
4068 #ifndef __WXUNIVERSAL__
4070 // The following code will result in all window-less widgets
4071 // being redrawn because the wxWidgets class is allowed to
4072 // paint over the window-less widgets.
4074 GList
*children
= pizza
->children
;
4077 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
4078 children
= children
->next
;
4080 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
4081 GTK_WIDGET_DRAWABLE (child
->widget
))
4083 // Get intersection of widget area and update region
4084 wxRegion
region( m_updateRegion
);
4086 GdkEventExpose gdk_event
;
4087 gdk_event
.type
= GDK_EXPOSE
;
4088 gdk_event
.window
= pizza
->bin_window
;
4089 gdk_event
.count
= 0;
4091 wxRegionIterator
upd( m_updateRegion
);
4095 rect
.x
= upd
.GetX();
4096 rect
.y
= upd
.GetY();
4097 rect
.width
= upd
.GetWidth();
4098 rect
.height
= upd
.GetHeight();
4100 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4102 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4112 m_updateRegion
.Clear();
4115 void wxWindowGTK::ClearBackground()
4117 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4120 if (m_wxwindow
&& m_wxwindow
->window
)
4122 m_clearRegion
.Clear();
4123 wxSize
size( GetClientSize() );
4124 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4126 // Better do this in idle?
4133 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4135 wxWindowBase::DoSetToolTip(tip
);
4138 m_tooltip
->Apply( (wxWindow
*)this );
4141 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4143 wxString
tmp( tip
);
4144 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4146 #endif // wxUSE_TOOLTIPS
4148 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4150 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4152 if (!wxWindowBase::SetBackgroundColour(colour
))
4157 // We need the pixel value e.g. for background clearing.
4158 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4161 // apply style change (forceStyle=true so that new style is applied
4162 // even if the bg colour changed from valid to wxNullColour)
4163 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4164 ApplyWidgetStyle(true);
4169 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4171 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4173 if (!wxWindowBase::SetForegroundColour(colour
))
4180 // We need the pixel value e.g. for background clearing.
4181 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4184 // apply style change (forceStyle=true so that new style is applied
4185 // even if the bg colour changed from valid to wxNullColour):
4186 ApplyWidgetStyle(true);
4192 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4194 return gtk_widget_get_pango_context( m_widget
);
4197 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4200 m_x11Context
= pango_x_get_context( gdk_display
);
4202 return m_x11Context
;
4206 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4208 // do we need to apply any changes at all?
4211 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4216 GtkRcStyle
*style
= gtk_rc_style_new();
4222 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4224 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4225 style
->fontset_name
= g_strdup(xfontname
.c_str());
4229 if ( m_foregroundColour
.Ok() )
4231 GdkColor
*fg
= m_foregroundColour
.GetColor();
4233 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4234 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4236 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4237 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4239 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4240 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4243 if ( m_backgroundColour
.Ok() )
4245 GdkColor
*bg
= m_backgroundColour
.GetColor();
4247 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4248 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4249 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4250 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4252 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4253 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4254 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4255 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4257 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4258 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4259 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4260 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4262 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4263 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4264 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4265 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4271 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4273 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4276 DoApplyWidgetStyle(style
);
4277 gtk_rc_style_unref(style
);
4280 // Style change may affect GTK+'s size calculation:
4281 InvalidateBestSize();
4284 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4287 gtk_widget_modify_style(m_wxwindow
, style
);
4288 gtk_widget_modify_style(m_widget
, style
);
4291 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4293 wxWindowBase::SetBackgroundStyle(style
);
4295 if (style
== wxBG_STYLE_CUSTOM
)
4297 GdkWindow
*window
= (GdkWindow
*) NULL
;
4299 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4301 window
= GetConnectWidget()->window
;
4305 // Make sure GDK/X11 doesn't refresh the window
4307 gdk_window_set_back_pixmap( window
, None
, False
);
4309 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4312 m_needsStyleChange
= false;
4315 // Do in OnIdle, because the window is not yet available
4316 m_needsStyleChange
= true;
4318 // Don't apply widget style, or we get a grey background
4322 // apply style change (forceStyle=true so that new style is applied
4323 // even if the bg colour changed from valid to wxNullColour):
4324 ApplyWidgetStyle(true);
4329 //-----------------------------------------------------------------------------
4330 // Pop-up menu stuff
4331 //-----------------------------------------------------------------------------
4333 #if wxUSE_MENUS_NATIVE
4336 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4338 *is_waiting
= FALSE
;
4341 void SetInvokingWindow( wxMenu
*menu
, wxWindow
* win
)
4343 menu
->SetInvokingWindow( win
);
4345 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4348 wxMenuItem
*menuitem
= node
->GetData();
4349 if (menuitem
->IsSubMenu())
4351 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4354 node
= node
->GetNext();
4358 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4361 gboolean
* WXUNUSED(whatever
),
4363 gpointer user_data
)
4365 // ensure that the menu appears entirely on screen
4367 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4369 wxSize sizeScreen
= wxGetDisplaySize();
4370 wxPoint
*pos
= (wxPoint
*)user_data
;
4372 gint xmax
= sizeScreen
.x
- req
.width
,
4373 ymax
= sizeScreen
.y
- req
.height
;
4375 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4376 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4379 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4381 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4383 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4385 // NOTE: if you change this code, you need to update
4386 // the same code in taskbar.cpp as well. This
4387 // is ugly code duplication, I know,
4389 SetInvokingWindow( menu
, this );
4393 bool is_waiting
= true;
4395 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4397 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4398 (gpointer
)&is_waiting
);
4402 GtkMenuPositionFunc posfunc
;
4403 if ( x
== -1 && y
== -1 )
4405 // use GTK's default positioning algorithm
4411 pos
= ClientToScreen(wxPoint(x
, y
));
4413 posfunc
= wxPopupMenuPositionCallback
;
4417 GTK_MENU(menu
->m_menu
),
4418 (GtkWidget
*) NULL
, // parent menu shell
4419 (GtkWidget
*) NULL
, // parent menu item
4420 posfunc
, // function to position it
4421 userdata
, // client data
4422 0, // button used to activate it
4424 gtk_get_current_event_time()
4426 gs_timeLastClick
// the time of activation
4432 gtk_main_iteration();
4435 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4440 #endif // wxUSE_MENUS_NATIVE
4442 #if wxUSE_DRAG_AND_DROP
4444 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4446 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4448 GtkWidget
*dnd_widget
= GetConnectWidget();
4450 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4452 if (m_dropTarget
) delete m_dropTarget
;
4453 m_dropTarget
= dropTarget
;
4455 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4458 #endif // wxUSE_DRAG_AND_DROP
4460 GtkWidget
* wxWindowGTK::GetConnectWidget()
4462 GtkWidget
*connect_widget
= m_widget
;
4463 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4465 return connect_widget
;
4468 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4471 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4473 return (window
== m_widget
->window
);
4476 bool wxWindowGTK::SetFont( const wxFont
&font
)
4478 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4480 if (!wxWindowBase::SetFont(font
))
4483 // apply style change (forceStyle=true so that new style is applied
4484 // even if the font changed from valid to wxNullFont):
4485 ApplyWidgetStyle(true);
4490 void wxWindowGTK::DoCaptureMouse()
4492 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4494 GdkWindow
*window
= (GdkWindow
*) NULL
;
4496 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4498 window
= GetConnectWidget()->window
;
4500 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4502 wxCursor
* cursor
= & m_cursor
;
4504 cursor
= wxSTANDARD_CURSOR
;
4506 gdk_pointer_grab( window
, FALSE
,
4508 (GDK_BUTTON_PRESS_MASK
|
4509 GDK_BUTTON_RELEASE_MASK
|
4510 GDK_POINTER_MOTION_HINT_MASK
|
4511 GDK_POINTER_MOTION_MASK
),
4513 cursor
->GetCursor(),
4514 (guint32
)GDK_CURRENT_TIME
);
4515 g_captureWindow
= this;
4516 g_captureWindowHasMouse
= TRUE
;
4519 void wxWindowGTK::DoReleaseMouse()
4521 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4523 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4525 g_captureWindow
= (wxWindowGTK
*) NULL
;
4527 GdkWindow
*window
= (GdkWindow
*) NULL
;
4529 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4531 window
= GetConnectWidget()->window
;
4536 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4540 wxWindow
*wxWindowBase::GetCapture()
4542 return (wxWindow
*)g_captureWindow
;
4545 bool wxWindowGTK::IsRetained() const
4550 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4551 int range
, bool refresh
)
4553 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4555 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4557 m_hasScrolling
= TRUE
;
4559 if (orient
== wxHORIZONTAL
)
4561 float fpos
= (float)pos
;
4562 float frange
= (float)range
;
4563 float fthumb
= (float)thumbVisible
;
4564 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4565 if (fpos
< 0.0) fpos
= 0.0;
4567 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4568 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4570 SetScrollPos( orient
, pos
, refresh
);
4574 m_oldHorizontalPos
= fpos
;
4576 m_hAdjust
->lower
= 0.0;
4577 m_hAdjust
->upper
= frange
;
4578 m_hAdjust
->value
= fpos
;
4579 m_hAdjust
->step_increment
= 1.0;
4580 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4581 m_hAdjust
->page_size
= fthumb
;
4585 float fpos
= (float)pos
;
4586 float frange
= (float)range
;
4587 float fthumb
= (float)thumbVisible
;
4588 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4589 if (fpos
< 0.0) fpos
= 0.0;
4591 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4592 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4594 SetScrollPos( orient
, pos
, refresh
);
4598 m_oldVerticalPos
= fpos
;
4600 m_vAdjust
->lower
= 0.0;
4601 m_vAdjust
->upper
= frange
;
4602 m_vAdjust
->value
= fpos
;
4603 m_vAdjust
->step_increment
= 1.0;
4604 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4605 m_vAdjust
->page_size
= fthumb
;
4608 if (orient
== wxHORIZONTAL
)
4609 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4611 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4614 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4616 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4618 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4620 if (orient
== wxHORIZONTAL
)
4622 float fpos
= (float)pos
;
4623 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4624 if (fpos
< 0.0) fpos
= 0.0;
4625 m_oldHorizontalPos
= fpos
;
4627 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4628 m_hAdjust
->value
= fpos
;
4632 float fpos
= (float)pos
;
4633 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4634 if (fpos
< 0.0) fpos
= 0.0;
4635 m_oldVerticalPos
= fpos
;
4637 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4638 m_vAdjust
->value
= fpos
;
4641 if (m_wxwindow
->window
)
4643 if (orient
== wxHORIZONTAL
)
4645 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4646 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4648 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4650 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4651 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4655 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4656 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4658 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4660 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4661 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4666 int wxWindowGTK::GetScrollThumb( int orient
) const
4668 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4670 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4672 if (orient
== wxHORIZONTAL
)
4673 return (int)(m_hAdjust
->page_size
+0.5);
4675 return (int)(m_vAdjust
->page_size
+0.5);
4678 int wxWindowGTK::GetScrollPos( int orient
) const
4680 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4682 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4684 if (orient
== wxHORIZONTAL
)
4685 return (int)(m_hAdjust
->value
+0.5);
4687 return (int)(m_vAdjust
->value
+0.5);
4690 int wxWindowGTK::GetScrollRange( int orient
) const
4692 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4694 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4696 if (orient
== wxHORIZONTAL
)
4697 return (int)(m_hAdjust
->upper
+0.5);
4699 return (int)(m_vAdjust
->upper
+0.5);
4702 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4704 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4706 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4708 // No scrolling requested.
4709 if ((dx
== 0) && (dy
== 0)) return;
4712 if (!m_updateRegion
.IsEmpty())
4714 m_updateRegion
.Offset( dx
, dy
);
4718 GetClientSize( &cw
, &ch
);
4719 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4722 if (!m_clearRegion
.IsEmpty())
4724 m_clearRegion
.Offset( dx
, dy
);
4728 GetClientSize( &cw
, &ch
);
4729 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4733 m_clipPaintRegion
= TRUE
;
4735 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4737 m_clipPaintRegion
= FALSE
;
4741 // Find the wxWindow at the current mouse position, also returning the mouse
4743 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4745 pt
= wxGetMousePosition();
4746 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4750 // Get the current mouse position.
4751 wxPoint
wxGetMousePosition()
4753 /* This crashes when used within wxHelpContext,
4754 so we have to use the X-specific implementation below.
4756 GdkModifierType *mask;
4757 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4759 return wxPoint(x, y);
4763 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4765 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4766 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4767 Window rootReturn
, childReturn
;
4768 int rootX
, rootY
, winX
, winY
;
4769 unsigned int maskReturn
;
4771 XQueryPointer (display
,
4775 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4776 return wxPoint(rootX
, rootY
);
4780 // ----------------------------------------------------------------------------
4782 // ----------------------------------------------------------------------------
4784 class wxWinModule
: public wxModule
4791 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4794 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4796 bool wxWinModule::OnInit()
4798 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4799 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4804 void wxWinModule::OnExit()
4807 gdk_gc_unref( g_eraseGC
);