1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
53 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
69 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
71 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
81 extern GtkContainerClass
*pizza_parent_class
;
84 //-----------------------------------------------------------------------------
85 // documentation on internals
86 //-----------------------------------------------------------------------------
89 I have been asked several times about writing some documentation about
90 the GTK port of wxWindows, especially its internal structures. Obviously,
91 you cannot understand wxGTK without knowing a little about the GTK, but
92 some more information about what the wxWindow, which is the base class
93 for all other window classes, does seems required as well.
97 What does wxWindow do? It contains the common interface for the following
98 jobs of its descendants:
100 1) Define the rudimentary behaviour common to all window classes, such as
101 resizing, intercepting user input (so as to make it possible to use these
102 events for special purposes in a derived class), window names etc.
104 2) Provide the possibility to contain and manage children, if the derived
105 class is allowed to contain children, which holds true for those window
106 classes which do not display a native GTK widget. To name them, these
107 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
108 work classes are a special case and are handled a bit differently from
109 the rest. The same holds true for the wxNotebook class.
111 3) Provide the possibility to draw into a client area of a window. This,
112 too, only holds true for classes that do not display a native GTK widget
115 4) Provide the entire mechanism for scrolling widgets. This actual inter-
116 face for this is usually in wxScrolledWindow, but the GTK implementation
119 5) A multitude of helper or extra methods for special purposes, such as
120 Drag'n'Drop, managing validators etc.
122 6) Display a border (sunken, raised, simple or none).
124 Normally one might expect, that one wxWindows window would always correspond
125 to one GTK widget. Under GTK, there is no such allround widget that has all
126 the functionality. Moreover, the GTK defines a client area as a different
127 widget from the actual widget you are handling. Last but not least some
128 special classes (e.g. wxFrame) handle different categories of widgets and
129 still have the possibility to draw something in the client area.
130 It was therefore required to write a special purpose GTK widget, that would
131 represent a client area in the sense of wxWindows capable to do the jobs
132 2), 3) and 4). I have written this class and it resides in win_gtk.c of
135 All windows must have a widget, with which they interact with other under-
136 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
137 thw wxWindow class has a member variable called m_widget which holds a
138 pointer to this widget. When the window class represents a GTK native widget,
139 this is (in most cases) the only GTK widget the class manages. E.g. the
140 wxStatitText class handles only a GtkLabel widget a pointer to which you
141 can find in m_widget (defined in wxWindow)
143 When the class has a client area for drawing into and for containing children
144 it has to handle the client area widget (of the type GtkPizza, defined in
145 win_gtk.c), but there could be any number of widgets, handled by a class
146 The common rule for all windows is only, that the widget that interacts with
147 the rest of GTK must be referenced in m_widget and all other widgets must be
148 children of this widget on the GTK level. The top-most widget, which also
149 represents the client area, must be in the m_wxwindow field and must be of
152 As I said, the window classes that display a GTK native widget only have
153 one widget, so in the case of e.g. the wxButton class m_widget holds a
154 pointer to a GtkButton widget. But windows with client areas (for drawing
155 and children) have a m_widget field that is a pointer to a GtkScrolled-
156 Window and a m_wxwindow field that is pointer to a GtkPizza and this
157 one is (in the GTK sense) a child of the GtkScrolledWindow.
159 If the m_wxwindow field is set, then all input to this widget is inter-
160 cepted and sent to the wxWindows class. If not, all input to the widget
161 that gets pointed to by m_widget gets intercepted and sent to the class.
165 The design of scrolling in wxWindows is markedly different from that offered
166 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
167 clicking on a scrollbar belonging to scrolled window will inevitably move
168 the window. In wxWindows, the scrollbar will only emit an event, send this
169 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
170 which actually moves the window and its subchildren. Note that GtkPizza
171 memorizes how much it has been scrolled but that wxWindows forgets this
172 so that the two coordinates systems have to be kept in synch. This is done
173 in various places using the pizza->xoffset and pizza->yoffset values.
177 Singularily the most broken code in GTK is the code that is supposes to
178 inform subwindows (child windows) about new positions. Very often, duplicate
179 events are sent without changes in size or position, equally often no
180 events are sent at all (All this is due to a bug in the GtkContainer code
181 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
182 GTK's own system and it simply waits for size events for toplevel windows
183 and then iterates down the respective size events to all window. This has
184 the disadvantage, that windows might get size events before the GTK widget
185 actually has the reported size. This doesn't normally pose any problem, but
186 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
187 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
188 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
189 window that is used for OpenGl output really has that size (as reported by
194 If someone at some point of time feels the immense desire to have a look at,
195 change or attempt to optimse the Refresh() logic, this person will need an
196 intimate understanding of what a "draw" and what an "expose" events are and
197 what there are used for, in particular when used in connection with GTK's
198 own windowless widgets. Beware.
202 Cursors, too, have been a constant source of pleasure. The main difficulty
203 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
204 for the parent. To prevent this from doing too much harm, I use idle time
205 to set the cursor over and over again, starting from the toplevel windows
206 and ending with the youngest generation (speaking of parent and child windows).
207 Also don't forget that cursors (like much else) are connected to GdkWindows,
208 not GtkWidgets and that the "window" field of a GtkWidget might very well
209 point to the GdkWindow of the parent widget (-> "window less widget") and
210 that the two obviously have very different meanings.
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 extern wxList wxPendingDelete
;
219 extern bool g_blockEventsOnDrag
;
220 extern bool g_blockEventsOnScroll
;
221 extern wxCursor g_globalCursor
;
223 static GdkGC
*g_eraseGC
= NULL
;
225 // mouse capture state: the window which has it and if the mouse is currently
227 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
228 static bool g_captureWindowHasMouse
= FALSE
;
230 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
232 // the last window which had the focus - this is normally never NULL (except
233 // if we never had focus at all) as even when g_focusWindow is NULL it still
234 // keeps its previous value
235 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*)NULL
;
237 // the frame that is currently active (i.e. its child has focus). It is
238 // used to generate wxActivateEvents
239 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*)NULL
;
240 static bool g_activeFrameLostFocus
= FALSE
;
242 // if we detect that the app has got/lost the focus, we set this variable to
243 // either TRUE or FALSE and an activate event will be sent during the next
244 // OnIdle() call and it is reset to -1: this value means that we shouldn't
245 // send any activate events at all
246 static int g_sendActivateEvent
= -1;
248 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
249 the last click here */
250 static guint32 gs_timeLastClick
= 0;
252 extern bool g_mainThreadLocked
;
254 //-----------------------------------------------------------------------------
256 //-----------------------------------------------------------------------------
259 #define DISABLE_STYLE_IF_BROKEN_THEME 1
265 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
267 # define DEBUG_MAIN_THREAD
270 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
271 GdkEvent
*WXUNUSED(event
),
272 const wxChar
*WXUNUSED(name
) )
275 static bool s_done = FALSE;
278 wxLog::AddTraceMask("focus");
281 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
287 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
289 // suppress warnings about gtk_debug_focus_in_callback being unused with
294 tmp
+= wxT(" FROM ");
297 wxChar
*s
= new wxChar
[tmp
.Length()+1];
301 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
302 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
307 #define DEBUG_MAIN_THREAD
310 //-----------------------------------------------------------------------------
311 // missing gdk functions
312 //-----------------------------------------------------------------------------
315 gdk_window_warp_pointer (GdkWindow
*window
,
320 GdkWindowPrivate
*priv
;
324 window
= GDK_ROOT_PARENT();
327 if (!GDK_WINDOW_DESTROYED(window
))
329 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
330 None
, /* not source window -> move from anywhere */
331 GDK_WINDOW_XID(window
), /* dest window */
332 0, 0, 0, 0, /* not source window -> move from anywhere */
336 priv
= (GdkWindowPrivate
*) window
;
338 if (!priv
->destroyed
)
340 XWarpPointer (priv
->xdisplay
,
341 None
, /* not source window -> move from anywhere */
342 priv
->xwindow
, /* dest window */
343 0, 0, 0, 0, /* not source window -> move from anywhere */
349 //-----------------------------------------------------------------------------
351 //-----------------------------------------------------------------------------
353 extern void wxapp_install_idle_handler();
354 extern bool g_isIdle
;
356 //-----------------------------------------------------------------------------
357 // local code (see below)
358 //-----------------------------------------------------------------------------
360 // returns the child of win which currently has focus or NULL if not found
362 // Note: can't be static, needed by textctrl.cpp.
363 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
365 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
367 return (wxWindow
*)NULL
;
369 if ( winFocus
== win
)
370 return (wxWindow
*)win
;
372 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
374 node
= node
->GetNext() )
376 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
381 return (wxWindow
*)NULL
;
384 // Returns toplevel grandparent of given window:
385 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
387 wxWindowGTK
*p
= win
;
388 while (p
&& !p
->IsTopLevel())
393 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
395 // wxUniversal widgets draw the borders and scrollbars themselves
396 #ifndef __WXUNIVERSAL__
403 if (win
->m_hasScrolling
)
405 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
407 GtkRequisition vscroll_req
;
408 vscroll_req
.width
= 2;
409 vscroll_req
.height
= 2;
410 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
411 (scroll_window
->vscrollbar
, &vscroll_req
);
413 GtkRequisition hscroll_req
;
414 hscroll_req
.width
= 2;
415 hscroll_req
.height
= 2;
416 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
417 (scroll_window
->hscrollbar
, &hscroll_req
);
419 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
421 if (scroll_window
->vscrollbar_visible
)
423 dw
+= vscroll_req
.width
;
424 dw
+= scroll_class
->scrollbar_spacing
;
427 if (scroll_window
->hscrollbar_visible
)
429 dh
+= hscroll_req
.height
;
430 dh
+= scroll_class
->scrollbar_spacing
;
436 if (GTK_WIDGET_NO_WINDOW (widget
))
438 dx
+= widget
->allocation
.x
;
439 dy
+= widget
->allocation
.y
;
442 if (win
->HasFlag(wxRAISED_BORDER
))
444 gtk_draw_shadow( widget
->style
,
449 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
453 if (win
->HasFlag(wxSUNKEN_BORDER
))
455 gtk_draw_shadow( widget
->style
,
460 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
464 if (win
->HasFlag(wxSIMPLE_BORDER
))
467 gc
= gdk_gc_new( widget
->window
);
468 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
469 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
471 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
475 #endif // __WXUNIVERSAL__
478 //-----------------------------------------------------------------------------
479 // "expose_event" of m_widget
480 //-----------------------------------------------------------------------------
482 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
484 if (gdk_event
->count
> 0) return FALSE
;
486 draw_frame( widget
, win
);
490 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
496 //-----------------------------------------------------------------------------
497 // "draw" of m_widget
498 //-----------------------------------------------------------------------------
502 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
504 draw_frame( widget
, win
);
509 //-----------------------------------------------------------------------------
510 // key code mapping routines
511 //-----------------------------------------------------------------------------
513 static long map_to_unmodified_wx_keysym( GdkEventKey
*event
)
515 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
516 // but only event->keyval which is quite useless to us, so remember
517 // the last character from GDK_KEY_PRESS and reuse it as last resort
519 // NB: should be MT-neutral as always called from main thread only
524 } s_lastKeyPress
= { 0, 0 };
526 KeySym keysym
= event
->keyval
;
532 case GDK_Shift_R
: key_code
= WXK_SHIFT
; break;
534 case GDK_Control_R
: key_code
= WXK_CONTROL
; break;
540 case GDK_Super_R
: key_code
= WXK_ALT
; break;
541 case GDK_Menu
: key_code
= WXK_MENU
; break;
542 case GDK_Help
: key_code
= WXK_HELP
; break;
543 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
544 case GDK_ISO_Left_Tab
:
545 case GDK_Tab
: key_code
= WXK_TAB
; break;
546 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
547 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
548 case GDK_Return
: key_code
= WXK_RETURN
; break;
549 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
550 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
551 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
552 case GDK_Delete
: key_code
= WXK_DELETE
; break;
553 case GDK_Home
: key_code
= WXK_HOME
; break;
554 case GDK_Left
: key_code
= WXK_LEFT
; break;
555 case GDK_Up
: key_code
= WXK_UP
; break;
556 case GDK_Right
: key_code
= WXK_RIGHT
; break;
557 case GDK_Down
: key_code
= WXK_DOWN
; break;
558 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
559 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
560 case GDK_Next
: key_code
= WXK_NEXT
; break;
561 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
562 case GDK_End
: key_code
= WXK_END
; break;
563 case GDK_Begin
: key_code
= WXK_HOME
; break;
564 case GDK_Select
: key_code
= WXK_SELECT
; break;
565 case GDK_Print
: key_code
= WXK_PRINT
; break;
566 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
567 case GDK_Insert
: key_code
= WXK_INSERT
; break;
568 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
570 case GDK_KP_0
: key_code
= WXK_NUMPAD0
; break;
571 case GDK_KP_1
: key_code
= WXK_NUMPAD1
; break;
572 case GDK_KP_2
: key_code
= WXK_NUMPAD2
; break;
573 case GDK_KP_3
: key_code
= WXK_NUMPAD3
; break;
574 case GDK_KP_4
: key_code
= WXK_NUMPAD4
; break;
575 case GDK_KP_5
: key_code
= WXK_NUMPAD5
; break;
576 case GDK_KP_6
: key_code
= WXK_NUMPAD6
; break;
577 case GDK_KP_7
: key_code
= WXK_NUMPAD7
; break;
578 case GDK_KP_8
: key_code
= WXK_NUMPAD8
; break;
579 case GDK_KP_9
: key_code
= WXK_NUMPAD9
; break;
580 case GDK_KP_Space
: key_code
= WXK_NUMPAD_SPACE
; break;
581 case GDK_KP_Tab
: key_code
= WXK_NUMPAD_TAB
; break;
582 case GDK_KP_Enter
: key_code
= WXK_NUMPAD_ENTER
; break;
583 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
584 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
585 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
586 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
587 case GDK_KP_Home
: key_code
= WXK_NUMPAD_HOME
; break;
588 case GDK_KP_Left
: key_code
= WXK_NUMPAD_LEFT
; break;
589 case GDK_KP_Up
: key_code
= WXK_NUMPAD_UP
; break;
590 case GDK_KP_Right
: key_code
= WXK_NUMPAD_RIGHT
; break;
591 case GDK_KP_Down
: key_code
= WXK_NUMPAD_DOWN
; break;
592 case GDK_KP_Prior
: key_code
= WXK_NUMPAD_PRIOR
; break;
593 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
594 case GDK_KP_Next
: key_code
= WXK_NUMPAD_NEXT
; break;
595 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
596 case GDK_KP_End
: key_code
= WXK_NUMPAD_END
; break;
597 case GDK_KP_Begin
: key_code
= WXK_NUMPAD_BEGIN
; break;
598 case GDK_KP_Insert
: key_code
= WXK_NUMPAD_INSERT
; break;
599 case GDK_KP_Delete
: key_code
= WXK_NUMPAD_DELETE
; break;
600 case GDK_KP_Equal
: key_code
= WXK_NUMPAD_EQUAL
; break;
601 case GDK_KP_Multiply
: key_code
= WXK_NUMPAD_MULTIPLY
; break;
602 case GDK_KP_Add
: key_code
= WXK_NUMPAD_ADD
; break;
603 case GDK_KP_Separator
: key_code
= WXK_NUMPAD_SEPARATOR
; break;
604 case GDK_KP_Subtract
: key_code
= WXK_NUMPAD_SUBTRACT
; break;
605 case GDK_KP_Decimal
: key_code
= WXK_NUMPAD_DECIMAL
; break;
606 case GDK_KP_Divide
: key_code
= WXK_NUMPAD_DIVIDE
; break;
608 case GDK_F1
: key_code
= WXK_F1
; break;
609 case GDK_F2
: key_code
= WXK_F2
; break;
610 case GDK_F3
: key_code
= WXK_F3
; break;
611 case GDK_F4
: key_code
= WXK_F4
; break;
612 case GDK_F5
: key_code
= WXK_F5
; break;
613 case GDK_F6
: key_code
= WXK_F6
; break;
614 case GDK_F7
: key_code
= WXK_F7
; break;
615 case GDK_F8
: key_code
= WXK_F8
; break;
616 case GDK_F9
: key_code
= WXK_F9
; break;
617 case GDK_F10
: key_code
= WXK_F10
; break;
618 case GDK_F11
: key_code
= WXK_F11
; break;
619 case GDK_F12
: key_code
= WXK_F12
; break;
622 // do we have the translation?
623 if ( event
->length
== 1 )
625 keysym
= (KeySym
)event
->string
[0];
627 else if ( (keysym
& 0xFF) != keysym
)
629 // non ASCII key, what to do?
631 if ( event
->type
== GDK_KEY_RELEASE
)
633 // reuse the one from the last keypress if any
634 if ( keysym
== s_lastKeyPress
.keysym
)
636 key_code
= s_lastKeyPress
.keycode
;
643 // ignore this one, we don't know it
646 //else: ASCII key, ok
648 guint upper
= gdk_keyval_to_upper( (guint
)keysym
);
649 key_code
= upper
? upper
: keysym
;
651 if ( event
->type
== GDK_KEY_PRESS
)
653 // remember it to be reused below later
654 s_lastKeyPress
.keysym
= keysym
;
655 s_lastKeyPress
.keycode
= key_code
;
663 static long map_to_wx_keysym( GdkEventKey
*event
)
665 KeySym keysym
= event
->keyval
;
670 case GDK_Menu
: key_code
= WXK_MENU
; break;
671 case GDK_Help
: key_code
= WXK_HELP
; break;
672 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
673 case GDK_ISO_Left_Tab
:
674 case GDK_Tab
: key_code
= WXK_TAB
; break;
675 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
676 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
677 case GDK_Return
: key_code
= WXK_RETURN
; break;
678 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
679 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
680 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
681 case GDK_Delete
: key_code
= WXK_DELETE
; break;
682 case GDK_Home
: key_code
= WXK_HOME
; break;
683 case GDK_Left
: key_code
= WXK_LEFT
; break;
684 case GDK_Up
: key_code
= WXK_UP
; break;
685 case GDK_Right
: key_code
= WXK_RIGHT
; break;
686 case GDK_Down
: key_code
= WXK_DOWN
; break;
687 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
688 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
689 case GDK_Next
: key_code
= WXK_NEXT
; break;
690 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
691 case GDK_End
: key_code
= WXK_END
; break;
692 case GDK_Begin
: key_code
= WXK_HOME
; break;
693 case GDK_Select
: key_code
= WXK_SELECT
; break;
694 case GDK_Print
: key_code
= WXK_PRINT
; break;
695 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
696 case GDK_Insert
: key_code
= WXK_INSERT
; break;
697 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
699 case GDK_KP_0
: key_code
= '0'; break;
700 case GDK_KP_1
: key_code
= '1'; break;
701 case GDK_KP_2
: key_code
= '2'; break;
702 case GDK_KP_3
: key_code
= '3'; break;
703 case GDK_KP_4
: key_code
= '4'; break;
704 case GDK_KP_5
: key_code
= '5'; break;
705 case GDK_KP_6
: key_code
= '6'; break;
706 case GDK_KP_7
: key_code
= '7'; break;
707 case GDK_KP_8
: key_code
= '8'; break;
708 case GDK_KP_9
: key_code
= '9'; break;
709 case GDK_KP_Space
: key_code
= ' '; break;
710 case GDK_KP_Tab
: key_code
= WXK_TAB
; break; /* or '\t' ??? */
711 case GDK_KP_Enter
: key_code
= WXK_RETURN
; break; /* or '\r' ??? */
712 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
713 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
714 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
715 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
716 case GDK_KP_Home
: key_code
= WXK_HOME
; break;
717 case GDK_KP_Left
: key_code
= WXK_LEFT
; break;
718 case GDK_KP_Up
: key_code
= WXK_UP
; break;
719 case GDK_KP_Right
: key_code
= WXK_RIGHT
; break;
720 case GDK_KP_Down
: key_code
= WXK_DOWN
; break;
721 case GDK_KP_Prior
: key_code
= WXK_PRIOR
; break;
722 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
723 case GDK_KP_Next
: key_code
= WXK_NEXT
; break;
724 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
725 case GDK_KP_End
: key_code
= WXK_END
; break;
726 case GDK_KP_Begin
: key_code
= WXK_HOME
; break;
727 case GDK_KP_Insert
: key_code
= WXK_INSERT
; break;
728 case GDK_KP_Delete
: key_code
= WXK_DELETE
; break;
729 case GDK_KP_Equal
: key_code
= '='; break;
730 case GDK_KP_Multiply
: key_code
= '*'; break;
731 case GDK_KP_Add
: key_code
= '+'; break;
732 case GDK_KP_Separator
: key_code
= ','; break;
733 case GDK_KP_Subtract
: key_code
= '-'; break;
734 case GDK_KP_Decimal
: key_code
= '.'; break;
735 case GDK_KP_Divide
: key_code
= '/'; break;
737 case GDK_F1
: key_code
= WXK_F1
; break;
738 case GDK_F2
: key_code
= WXK_F2
; break;
739 case GDK_F3
: key_code
= WXK_F3
; break;
740 case GDK_F4
: key_code
= WXK_F4
; break;
741 case GDK_F5
: key_code
= WXK_F5
; break;
742 case GDK_F6
: key_code
= WXK_F6
; break;
743 case GDK_F7
: key_code
= WXK_F7
; break;
744 case GDK_F8
: key_code
= WXK_F8
; break;
745 case GDK_F9
: key_code
= WXK_F9
; break;
746 case GDK_F10
: key_code
= WXK_F10
; break;
747 case GDK_F11
: key_code
= WXK_F11
; break;
748 case GDK_F12
: key_code
= WXK_F12
; break;
750 if (event
->length
== 1)
752 key_code
= (unsigned char)*event
->string
;
754 else if ((keysym
& 0xFF) == keysym
)
756 key_code
= (guint
)keysym
;
763 //-----------------------------------------------------------------------------
764 // "size_request" of m_widget
765 //-----------------------------------------------------------------------------
767 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
770 win
->GetSize( &w
, &h
);
774 requisition
->height
= h
;
775 requisition
->width
= w
;
778 //-----------------------------------------------------------------------------
779 // "expose_event" of m_wxwindow
780 //-----------------------------------------------------------------------------
782 static int gtk_window_expose_callback( GtkWidget
*widget
,
783 GdkEventExpose
*gdk_event
,
789 wxapp_install_idle_handler();
792 if (win->GetName() == wxT("panel"))
794 wxPrintf( wxT("OnExpose from ") );
795 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
796 wxPrintf( win->GetClassInfo()->GetClassName() );
797 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
798 (int)gdk_event->area.y,
799 (int)gdk_event->area.width,
800 (int)gdk_event->area.height );
804 #ifndef __WXUNIVERSAL__
805 GtkPizza
*pizza
= GTK_PIZZA (widget
);
807 if (win
->GetThemeEnabled())
809 wxWindow
*parent
= win
->GetParent();
810 while (parent
&& !parent
->IsTopLevel())
811 parent
= parent
->GetParent();
815 gtk_paint_flat_box (parent
->m_widget
->style
,
826 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
828 gdk_event
->area
.width
,
829 gdk_event
->area
.height
);
831 // Actual redrawing takes place in idle time.
836 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
843 //-----------------------------------------------------------------------------
844 // "event" of m_wxwindow
845 //-----------------------------------------------------------------------------
847 // GTK thinks it is clever and filters out a certain amount of "unneeded"
848 // expose events. We need them, of course, so we override the main event
849 // procedure in GtkWidget by giving our own handler for all system events.
850 // There, we look for expose events ourselves whereas all other events are
853 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
854 GdkEventExpose
*event
,
857 if (event
->type
== GDK_EXPOSE
)
859 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
866 //-----------------------------------------------------------------------------
867 // "draw" of m_wxwindow
868 //-----------------------------------------------------------------------------
872 // This callback is a complete replacement of the gtk_pizza_draw() function,
873 // which is disabled.
875 static void gtk_window_draw_callback( GtkWidget
*widget
,
882 wxapp_install_idle_handler();
884 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
885 // there are no child windows.
886 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
887 (win
->GetChildren().GetCount() == 0))
893 if (win->GetName() == wxT("panel"))
895 wxPrintf( wxT("OnDraw from ") );
896 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
897 wxPrintf( win->GetClassInfo()->GetClassName() );
898 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
905 #ifndef __WXUNIVERSAL__
906 GtkPizza
*pizza
= GTK_PIZZA (widget
);
908 if (win
->GetThemeEnabled())
910 wxWindow
*parent
= win
->GetParent();
911 while (parent
&& !parent
->IsTopLevel())
912 parent
= parent
->GetParent();
916 gtk_paint_flat_box (parent
->m_widget
->style
,
927 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
928 (pizza
->clear_on_draw
))
930 gdk_window_clear_area( pizza
->bin_window
,
931 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
935 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
937 // Actual redrawing takes place in idle time.
941 #ifndef __WXUNIVERSAL__
942 // Redraw child widgets
943 GList
*children
= pizza
->children
;
946 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
947 children
= children
->next
;
949 GdkRectangle child_area
;
950 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
952 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
960 //-----------------------------------------------------------------------------
961 // "key_press_event" from any window
962 //-----------------------------------------------------------------------------
964 // set WXTRACE to this to see the key event codes on the console
965 #define TRACE_KEYS _T("keyevent")
968 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
970 GdkEventKey
*gdk_event
)
972 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
974 wxLogTrace(TRACE_KEYS
, _T("Key %s event: %d => %ld"),
975 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
977 gdk_event
->keyval
, key_code
);
979 // sending unknown key events doesn't really make sense
985 GdkModifierType state
;
986 if (gdk_event
->window
)
987 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
989 event
.SetTimestamp( gdk_event
->time
);
990 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
991 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
992 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
993 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
994 event
.m_keyCode
= key_code
;
995 event
.m_scanCode
= gdk_event
->keyval
;
996 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
997 event
.m_rawFlags
= 0;
1000 event
.SetEventObject( win
);
1005 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1006 GdkEventKey
*gdk_event
,
1012 wxapp_install_idle_handler();
1014 if (!win
->m_hasVMT
) return FALSE
;
1015 if (g_blockEventsOnDrag
) return FALSE
;
1017 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1018 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1020 // unknown key pressed, ignore (the event would be useless anyhow
1024 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1029 wxWindowGTK
*ancestor
= win
;
1032 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1035 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1036 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1039 if (ancestor
->IsTopLevel())
1041 ancestor
= ancestor
->GetParent();
1044 #endif // wxUSE_ACCEL
1046 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1047 will only be sent if it is not in an accelerator table. */
1050 long key_code
= map_to_wx_keysym( gdk_event
);
1054 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1056 // reuse the same event object, just change its type and use the
1057 // translated keycode instead of the raw one
1058 event
.SetEventType(wxEVT_CHAR
);
1059 event
.m_keyCode
= key_code
;
1061 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1065 /* win is a control: tab can be propagated up */
1067 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1068 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1069 // have this style, yet choose not to process this particular TAB in which
1070 // case TAB must still work as a navigational character
1072 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1074 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1076 wxNavigationKeyEvent new_event
;
1077 new_event
.SetEventObject( win
->GetParent() );
1078 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1079 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1080 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1081 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1082 new_event
.SetCurrentFocus( win
);
1083 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1086 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1088 (gdk_event
->keyval
== GDK_Escape
) )
1090 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1091 new_event
.SetEventObject( win
);
1092 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1096 #if 0 // (GTK_MINOR_VERSION > 0)
1097 /* Pressing F10 will activate the menu bar of the top frame. */
1099 (gdk_event
->keyval
== GDK_F10
) )
1101 wxWindowGTK
*ancestor
= win
;
1104 if (wxIsKindOf(ancestor
,wxFrame
))
1106 wxFrame
*frame
= (wxFrame
*) ancestor
;
1107 wxMenuBar
*menubar
= frame
->GetMenuBar();
1110 wxNode
*node
= menubar
->GetMenus().First();
1113 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1114 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1120 ancestor
= ancestor
->GetParent();
1127 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1134 //-----------------------------------------------------------------------------
1135 // "key_release_event" from any window
1136 //-----------------------------------------------------------------------------
1138 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1139 GdkEventKey
*gdk_event
,
1145 wxapp_install_idle_handler();
1150 if (g_blockEventsOnDrag
)
1153 wxKeyEvent
event( wxEVT_KEY_UP
);
1154 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1156 // unknown key pressed, ignore (the event would be useless anyhow
1160 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1163 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1167 // ============================================================================
1169 // ============================================================================
1171 // init wxMouseEvent with the info from gdk_event
1172 #define InitMouseEvent(win, event, gdk_event) \
1174 event.SetTimestamp( gdk_event->time ); \
1175 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1176 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1177 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1178 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1179 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1180 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1181 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1183 wxPoint pt = win->GetClientAreaOrigin(); \
1184 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1185 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1188 // ----------------------------------------------------------------------------
1189 // mouse event processing helper
1190 // ----------------------------------------------------------------------------
1192 static void AdjustEventButtonState(wxMouseEvent
& event
)
1194 // GDK reports the old state of the button for a button press event, but
1195 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1196 // for a LEFT_DOWN event, not FALSE, so we will invert
1197 // left/right/middleDown for the corresponding click events
1199 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1200 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1201 (event
.GetEventType() == wxEVT_LEFT_UP
))
1203 event
.m_leftDown
= !event
.m_leftDown
;
1207 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1208 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1209 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1211 event
.m_middleDown
= !event
.m_middleDown
;
1215 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1216 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1217 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1219 event
.m_rightDown
= !event
.m_rightDown
;
1224 //-----------------------------------------------------------------------------
1225 // "button_press_event"
1226 //-----------------------------------------------------------------------------
1228 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1233 wxapp_install_idle_handler();
1236 wxPrintf( wxT("1) OnButtonPress from ") );
1237 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1238 wxPrintf( win->GetClassInfo()->GetClassName() );
1239 wxPrintf( wxT(".\n") );
1241 if (!win
->m_hasVMT
) return FALSE
;
1242 if (g_blockEventsOnDrag
) return TRUE
;
1243 if (g_blockEventsOnScroll
) return TRUE
;
1245 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1247 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1249 gtk_widget_grab_focus( win
->m_wxwindow
);
1251 wxPrintf( wxT("GrabFocus from ") );
1252 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1253 wxPrintf( win->GetClassInfo()->GetClassName() );
1254 wxPrintf( wxT(".\n") );
1258 wxEventType event_type
= wxEVT_NULL
;
1260 if (gdk_event
->button
== 1)
1262 switch (gdk_event
->type
)
1264 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1265 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1269 else if (gdk_event
->button
== 2)
1271 switch (gdk_event
->type
)
1273 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1274 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1278 else if (gdk_event
->button
== 3)
1280 switch (gdk_event
->type
)
1282 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1283 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1288 if ( event_type
== wxEVT_NULL
)
1290 // unknown mouse button or click type
1294 wxMouseEvent
event( event_type
);
1295 InitMouseEvent( win
, event
, gdk_event
);
1297 AdjustEventButtonState(event
);
1299 // wxListBox actually get mouse events from the item
1301 if (win
->m_isListBox
)
1303 event
.m_x
+= widget
->allocation
.x
;
1304 event
.m_y
+= widget
->allocation
.y
;
1307 // Some control don't have their own X window and thus cannot get
1310 if (!g_captureWindow
)
1312 wxCoord x
= event
.m_x
;
1313 wxCoord y
= event
.m_y
;
1314 if (win
->m_wxwindow
)
1316 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1317 x
+= pizza
->xoffset
;
1318 y
+= pizza
->yoffset
;
1321 wxNode
*node
= win
->GetChildren().First();
1324 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1326 node
= node
->Next();
1327 if (!child
->IsShown())
1330 if (child
->m_isStaticBox
)
1332 // wxStaticBox is transparent in the box itself
1333 int xx1
= child
->m_x
;
1334 int yy1
= child
->m_y
;
1335 int xx2
= child
->m_x
+ child
->m_width
;
1336 int yy2
= child
->m_x
+ child
->m_height
;
1339 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1341 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1343 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1345 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1348 event
.m_x
-= child
->m_x
;
1349 event
.m_y
-= child
->m_y
;
1356 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1357 (child
->m_x
<= x
) &&
1358 (child
->m_y
<= y
) &&
1359 (child
->m_x
+child
->m_width
>= x
) &&
1360 (child
->m_y
+child
->m_height
>= y
))
1363 event
.m_x
-= child
->m_x
;
1364 event
.m_y
-= child
->m_y
;
1371 event
.SetEventObject( win
);
1373 gs_timeLastClick
= gdk_event
->time
;
1376 wxPrintf( wxT("2) OnButtonPress from ") );
1377 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1378 wxPrintf( win->GetClassInfo()->GetClassName() );
1379 wxPrintf( wxT(".\n") );
1382 if (win
->GetEventHandler()->ProcessEvent( event
))
1384 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1391 //-----------------------------------------------------------------------------
1392 // "button_release_event"
1393 //-----------------------------------------------------------------------------
1395 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1400 wxapp_install_idle_handler();
1402 if (!win
->m_hasVMT
) return FALSE
;
1403 if (g_blockEventsOnDrag
) return FALSE
;
1404 if (g_blockEventsOnScroll
) return FALSE
;
1406 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1409 printf( "OnButtonRelease from " );
1410 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1411 printf( win->GetClassInfo()->GetClassName() );
1415 wxEventType event_type
= wxEVT_NULL
;
1417 switch (gdk_event
->button
)
1419 case 1: event_type
= wxEVT_LEFT_UP
; break;
1420 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1421 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1422 default: return FALSE
;
1425 wxMouseEvent
event( event_type
);
1426 InitMouseEvent( win
, event
, gdk_event
);
1428 AdjustEventButtonState(event
);
1430 // wxListBox actually get mouse events from the item
1432 if (win
->m_isListBox
)
1434 event
.m_x
+= widget
->allocation
.x
;
1435 event
.m_y
+= widget
->allocation
.y
;
1438 // Some control don't have their own X window and thus cannot get
1441 if (!g_captureWindow
)
1443 wxCoord x
= event
.m_x
;
1444 wxCoord y
= event
.m_y
;
1445 if (win
->m_wxwindow
)
1447 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1448 x
+= pizza
->xoffset
;
1449 y
+= pizza
->yoffset
;
1452 wxNode
*node
= win
->GetChildren().First();
1455 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1457 node
= node
->Next();
1458 if (!child
->IsShown())
1461 if (child
->m_isStaticBox
)
1463 // wxStaticBox is transparent in the box itself
1464 int xx1
= child
->m_x
;
1465 int yy1
= child
->m_y
;
1466 int xx2
= child
->m_x
+ child
->m_width
;
1467 int yy2
= child
->m_x
+ child
->m_height
;
1470 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1472 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1474 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1476 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1479 event
.m_x
-= child
->m_x
;
1480 event
.m_y
-= child
->m_y
;
1487 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1488 (child
->m_x
<= x
) &&
1489 (child
->m_y
<= y
) &&
1490 (child
->m_x
+child
->m_width
>= x
) &&
1491 (child
->m_y
+child
->m_height
>= y
))
1494 event
.m_x
-= child
->m_x
;
1495 event
.m_y
-= child
->m_y
;
1502 event
.SetEventObject( win
);
1504 if (win
->GetEventHandler()->ProcessEvent( event
))
1506 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1513 //-----------------------------------------------------------------------------
1514 // "motion_notify_event"
1515 //-----------------------------------------------------------------------------
1517 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1518 GdkEventMotion
*gdk_event
,
1524 wxapp_install_idle_handler();
1526 if (!win
->m_hasVMT
) return FALSE
;
1527 if (g_blockEventsOnDrag
) return FALSE
;
1528 if (g_blockEventsOnScroll
) return FALSE
;
1530 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1532 if (gdk_event
->is_hint
)
1536 GdkModifierType state
;
1537 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1543 printf( "OnMotion from " );
1544 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1545 printf( win->GetClassInfo()->GetClassName() );
1549 wxMouseEvent
event( wxEVT_MOTION
);
1550 InitMouseEvent(win
, event
, gdk_event
);
1552 if ( g_captureWindow
)
1554 // synthetize a mouse enter or leave event if needed
1555 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1556 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1557 if ( hasMouse
!= g_captureWindowHasMouse
)
1559 // the mouse changed window
1560 g_captureWindowHasMouse
= hasMouse
;
1562 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1563 : wxEVT_LEAVE_WINDOW
);
1564 InitMouseEvent(win
, event
, gdk_event
);
1565 event
.SetEventObject(win
);
1566 win
->GetEventHandler()->ProcessEvent(event
);
1571 // Some control don't have their own X window and thus cannot get
1574 wxCoord x
= event
.m_x
;
1575 wxCoord y
= event
.m_y
;
1576 if (win
->m_wxwindow
)
1578 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1579 x
+= pizza
->xoffset
;
1580 y
+= pizza
->yoffset
;
1583 wxNode
*node
= win
->GetChildren().First();
1586 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1588 node
= node
->Next();
1589 if (!child
->IsShown())
1592 if (child
->m_isStaticBox
)
1594 // wxStaticBox is transparent in the box itself
1595 int xx1
= child
->m_x
;
1596 int yy1
= child
->m_y
;
1597 int xx2
= child
->m_x
+ child
->m_width
;
1598 int yy2
= child
->m_x
+ child
->m_height
;
1601 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1603 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1605 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1607 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1610 event
.m_x
-= child
->m_x
;
1611 event
.m_y
-= child
->m_y
;
1618 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1619 (child
->m_x
<= x
) &&
1620 (child
->m_y
<= y
) &&
1621 (child
->m_x
+child
->m_width
>= x
) &&
1622 (child
->m_y
+child
->m_height
>= y
))
1625 event
.m_x
-= child
->m_x
;
1626 event
.m_y
-= child
->m_y
;
1633 event
.SetEventObject( win
);
1635 if (win
->GetEventHandler()->ProcessEvent( event
))
1637 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1644 //-----------------------------------------------------------------------------
1646 //-----------------------------------------------------------------------------
1648 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1649 GdkEvent
*WXUNUSED(event
),
1655 wxapp_install_idle_handler();
1657 if (!win
->m_hasVMT
) return FALSE
;
1658 if (g_blockEventsOnDrag
) return FALSE
;
1660 switch ( g_sendActivateEvent
)
1663 // we've got focus from outside, synthetize wxActivateEvent
1664 g_sendActivateEvent
= 1;
1668 // another our window just lost focus, it was already ours before
1669 // - don't send any wxActivateEvent
1670 g_sendActivateEvent
= -1;
1675 g_focusWindow
= win
;
1678 wxLogDebug( wxT("OnSetFocus from %s\n"), win
->GetName().c_str() );
1681 // notify the parent keeping track of focus for the kbd navigation
1682 // purposes that we got it
1683 wxChildFocusEvent
eventFocus(win
);
1684 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1688 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1692 // caret needs to be informed about focus change
1693 wxCaret
*caret
= win
->GetCaret();
1696 caret
->OnSetFocus();
1698 #endif // wxUSE_CARET
1700 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1701 if ( active
!= g_activeFrame
)
1703 if ( g_activeFrame
)
1705 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1706 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1707 event
.SetEventObject(g_activeFrame
);
1708 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1711 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1712 g_activeFrame
= active
;
1713 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1714 event
.SetEventObject(g_activeFrame
);
1715 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1717 g_activeFrameLostFocus
= FALSE
;
1720 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1721 event
.SetEventObject( win
);
1723 if (win
->GetEventHandler()->ProcessEvent( event
))
1725 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1733 //-----------------------------------------------------------------------------
1734 // "focus_out_event"
1735 //-----------------------------------------------------------------------------
1737 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1742 wxapp_install_idle_handler();
1744 if (!win
->m_hasVMT
) return FALSE
;
1745 if (g_blockEventsOnDrag
) return FALSE
;
1748 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1751 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1753 // VZ: commenting this out because it does happen (although not easy
1754 // to reproduce, I only see it when using wxMiniFrame and not
1755 // always) and makes using Mahogany quite annoying
1757 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1758 wxT("unfocusing window that hasn't gained focus properly") )
1761 g_activeFrameLostFocus
= TRUE
;
1764 // if the focus goes out of our app alltogether, OnIdle() will send
1765 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1766 // g_sendActivateEvent to -1
1767 g_sendActivateEvent
= 0;
1769 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1773 g_focusWindow
= (wxWindowGTK
*)NULL
;
1781 // caret needs to be informed about focus change
1782 wxCaret
*caret
= win
->GetCaret();
1785 caret
->OnKillFocus();
1787 #endif // wxUSE_CARET
1789 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1790 event
.SetEventObject( win
);
1792 if (win
->GetEventHandler()->ProcessEvent( event
))
1794 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1801 //-----------------------------------------------------------------------------
1802 // "enter_notify_event"
1803 //-----------------------------------------------------------------------------
1805 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1810 wxapp_install_idle_handler();
1812 if (!win
->m_hasVMT
) return FALSE
;
1813 if (g_blockEventsOnDrag
) return FALSE
;
1815 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1817 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1818 event
.SetTimestamp( gdk_event
->time
);
1819 event
.SetEventObject( win
);
1823 GdkModifierType state
= (GdkModifierType
)0;
1825 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1827 InitMouseEvent(win
, event
, gdk_event
);
1828 wxPoint pt
= win
->GetClientAreaOrigin();
1829 event
.m_x
= x
+ pt
.x
;
1830 event
.m_y
= y
+ pt
.y
;
1832 if (win
->GetEventHandler()->ProcessEvent( event
))
1834 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1841 //-----------------------------------------------------------------------------
1842 // "leave_notify_event"
1843 //-----------------------------------------------------------------------------
1845 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1850 wxapp_install_idle_handler();
1852 if (!win
->m_hasVMT
) return FALSE
;
1853 if (g_blockEventsOnDrag
) return FALSE
;
1855 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1857 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1858 event
.SetTimestamp( gdk_event
->time
);
1859 event
.SetEventObject( win
);
1863 GdkModifierType state
= (GdkModifierType
)0;
1865 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1867 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
1868 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
1869 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
1870 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
1871 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
1872 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
1873 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
1875 wxPoint pt
= win
->GetClientAreaOrigin();
1876 event
.m_x
= x
+ pt
.x
;
1877 event
.m_y
= y
+ pt
.y
;
1879 if (win
->GetEventHandler()->ProcessEvent( event
))
1881 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1888 //-----------------------------------------------------------------------------
1889 // "value_changed" from m_vAdjust
1890 //-----------------------------------------------------------------------------
1892 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1899 wxapp_install_idle_handler();
1901 if (g_blockEventsOnDrag
) return;
1903 if (!win
->m_hasVMT
) return;
1905 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1906 if (fabs(diff
) < 0.2) return;
1908 win
->m_oldVerticalPos
= adjust
->value
;
1910 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1912 int value
= (int)(adjust
->value
+0.5);
1914 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1915 event
.SetEventObject( win
);
1916 win
->GetEventHandler()->ProcessEvent( event
);
1919 //-----------------------------------------------------------------------------
1920 // "value_changed" from m_hAdjust
1921 //-----------------------------------------------------------------------------
1923 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1930 wxapp_install_idle_handler();
1932 if (g_blockEventsOnDrag
) return;
1933 if (!win
->m_hasVMT
) return;
1935 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1936 if (fabs(diff
) < 0.2) return;
1938 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1940 win
->m_oldHorizontalPos
= adjust
->value
;
1942 int value
= (int)(adjust
->value
+0.5);
1944 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1945 event
.SetEventObject( win
);
1946 win
->GetEventHandler()->ProcessEvent( event
);
1949 //-----------------------------------------------------------------------------
1950 // "button_press_event" from scrollbar
1951 //-----------------------------------------------------------------------------
1953 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1954 GdkEventButton
*gdk_event
,
1960 wxapp_install_idle_handler();
1963 g_blockEventsOnScroll
= TRUE
;
1965 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1967 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1973 //-----------------------------------------------------------------------------
1974 // "button_release_event" from scrollbar
1975 //-----------------------------------------------------------------------------
1977 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1978 GdkEventButton
*WXUNUSED(gdk_event
),
1983 // don't test here as we can release the mouse while being over
1984 // a different window than the slider
1986 // if (gdk_event->window != widget->slider) return FALSE;
1988 g_blockEventsOnScroll
= FALSE
;
1990 if (win
->m_isScrolling
)
1992 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1996 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1997 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1999 value
= (int)(win
->m_hAdjust
->value
+0.5);
2002 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2004 value
= (int)(win
->m_vAdjust
->value
+0.5);
2008 wxScrollWinEvent
event( command
, value
, dir
);
2009 event
.SetEventObject( win
);
2010 win
->GetEventHandler()->ProcessEvent( event
);
2013 win
->m_isScrolling
= FALSE
;
2018 // ----------------------------------------------------------------------------
2019 // this wxWindowBase function is implemented here (in platform-specific file)
2020 // because it is static and so couldn't be made virtual
2021 // ----------------------------------------------------------------------------
2023 wxWindow
*wxWindowBase::FindFocus()
2025 // the cast is necessary when we compile in wxUniversal mode
2026 return (wxWindow
*)g_focusWindow
;
2029 //-----------------------------------------------------------------------------
2030 // "realize" from m_widget
2031 //-----------------------------------------------------------------------------
2033 /* We cannot set colours and fonts before the widget has
2034 been realized, so we do this directly after realization. */
2037 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2042 wxapp_install_idle_handler();
2044 if (win
->m_delayedBackgroundColour
)
2045 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2047 if (win
->m_delayedForegroundColour
)
2048 win
->SetForegroundColour( win
->GetForegroundColour() );
2050 wxWindowCreateEvent
event( win
);
2051 event
.SetEventObject( win
);
2052 win
->GetEventHandler()->ProcessEvent( event
);
2057 //-----------------------------------------------------------------------------
2059 //-----------------------------------------------------------------------------
2062 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2063 GtkAllocation
*WXUNUSED(alloc
),
2067 wxapp_install_idle_handler();
2069 if (!win
->m_hasScrolling
) return;
2071 int client_width
= 0;
2072 int client_height
= 0;
2073 win
->GetClientSize( &client_width
, &client_height
);
2074 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2077 win
->m_oldClientWidth
= client_width
;
2078 win
->m_oldClientHeight
= client_height
;
2080 if (!win
->m_nativeSizeEvent
)
2082 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2083 event
.SetEventObject( win
);
2084 win
->GetEventHandler()->ProcessEvent( event
);
2090 #define WXUNUSED_UNLESS_XIM(param) param
2092 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2095 /* Resize XIM window */
2098 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2099 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2100 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2103 wxapp_install_idle_handler();
2109 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2113 gdk_window_get_size (widget
->window
, &width
, &height
);
2114 win
->m_icattr
->preedit_area
.width
= width
;
2115 win
->m_icattr
->preedit_area
.height
= height
;
2116 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2121 //-----------------------------------------------------------------------------
2122 // "realize" from m_wxwindow
2123 //-----------------------------------------------------------------------------
2125 /* Initialize XIM support */
2128 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2129 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2132 wxapp_install_idle_handler();
2135 if (win
->m_ic
) return FALSE
;
2136 if (!widget
) return FALSE
;
2137 if (!gdk_im_ready()) return FALSE
;
2139 win
->m_icattr
= gdk_ic_attr_new();
2140 if (!win
->m_icattr
) return FALSE
;
2144 GdkColormap
*colormap
;
2145 GdkICAttr
*attr
= win
->m_icattr
;
2146 unsigned attrmask
= GDK_IC_ALL_REQ
;
2148 GdkIMStyle supported_style
= (GdkIMStyle
)
2149 (GDK_IM_PREEDIT_NONE
|
2150 GDK_IM_PREEDIT_NOTHING
|
2151 GDK_IM_PREEDIT_POSITION
|
2152 GDK_IM_STATUS_NONE
|
2153 GDK_IM_STATUS_NOTHING
);
2155 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2156 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2158 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2159 attr
->client_window
= widget
->window
;
2161 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2162 gtk_widget_get_default_colormap ())
2164 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2165 attr
->preedit_colormap
= colormap
;
2168 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2169 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2170 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2171 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2173 switch (style
& GDK_IM_PREEDIT_MASK
)
2175 case GDK_IM_PREEDIT_POSITION
:
2176 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2178 g_warning ("over-the-spot style requires fontset");
2182 gdk_window_get_size (widget
->window
, &width
, &height
);
2184 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2185 attr
->spot_location
.x
= 0;
2186 attr
->spot_location
.y
= height
;
2187 attr
->preedit_area
.x
= 0;
2188 attr
->preedit_area
.y
= 0;
2189 attr
->preedit_area
.width
= width
;
2190 attr
->preedit_area
.height
= height
;
2191 attr
->preedit_fontset
= widget
->style
->font
;
2196 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2198 if (win
->m_ic
== NULL
)
2199 g_warning ("Can't create input context.");
2202 mask
= gdk_window_get_events (widget
->window
);
2203 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2204 gdk_window_set_events (widget
->window
, mask
);
2206 if (GTK_WIDGET_HAS_FOCUS(widget
))
2207 gdk_im_begin (win
->m_ic
, widget
->window
);
2214 //-----------------------------------------------------------------------------
2215 // InsertChild for wxWindowGTK.
2216 //-----------------------------------------------------------------------------
2218 /* Callback for wxWindowGTK. This very strange beast has to be used because
2219 * C++ has no virtual methods in a constructor. We have to emulate a
2220 * virtual function here as wxNotebook requires a different way to insert
2221 * a child in it. I had opted for creating a wxNotebookPage window class
2222 * which would have made this superfluous (such in the MDI window system),
2223 * but no-one was listening to me... */
2225 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2227 /* the window might have been scrolled already, do we
2228 have to adapt the position */
2229 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2230 child
->m_x
+= pizza
->xoffset
;
2231 child
->m_y
+= pizza
->yoffset
;
2233 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2234 GTK_WIDGET(child
->m_widget
),
2241 //-----------------------------------------------------------------------------
2243 //-----------------------------------------------------------------------------
2245 wxWindow
*wxGetActiveWindow()
2247 // the cast is necessary when we compile in wxUniversal mode
2248 return (wxWindow
*)g_focusWindow
;
2251 //-----------------------------------------------------------------------------
2253 //-----------------------------------------------------------------------------
2255 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2257 #ifdef __WXUNIVERSAL__
2258 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2260 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2261 #endif // __WXUNIVERSAL__/__WXGTK__
2263 void wxWindowGTK::Init()
2269 m_widget
= (GtkWidget
*) NULL
;
2270 m_wxwindow
= (GtkWidget
*) NULL
;
2271 m_focusWidget
= (GtkWidget
*) NULL
;
2281 m_needParent
= TRUE
;
2282 m_isBeingDeleted
= FALSE
;
2285 m_nativeSizeEvent
= FALSE
;
2287 m_hasScrolling
= FALSE
;
2288 m_isScrolling
= FALSE
;
2290 m_hAdjust
= (GtkAdjustment
*) NULL
;
2291 m_vAdjust
= (GtkAdjustment
*) NULL
;
2292 m_oldHorizontalPos
= 0.0;
2293 m_oldVerticalPos
= 0.0;
2296 m_widgetStyle
= (GtkStyle
*) NULL
;
2298 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2300 m_isStaticBox
= FALSE
;
2301 m_isRadioButton
= FALSE
;
2302 m_isListBox
= FALSE
;
2304 m_acceptsFocus
= FALSE
;
2306 m_clipPaintRegion
= FALSE
;
2308 m_cursor
= *wxSTANDARD_CURSOR
;
2310 m_delayedForegroundColour
= FALSE
;
2311 m_delayedBackgroundColour
= FALSE
;
2314 m_ic
= (GdkIC
*) NULL
;
2315 m_icattr
= (GdkICAttr
*) NULL
;
2319 wxWindowGTK::wxWindowGTK()
2324 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2329 const wxString
&name
)
2333 Create( parent
, id
, pos
, size
, style
, name
);
2336 bool wxWindowGTK::Create( wxWindow
*parent
,
2341 const wxString
&name
)
2343 if (!PreCreation( parent
, pos
, size
) ||
2344 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2346 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2350 m_insertCallback
= wxInsertChildInWindow
;
2352 // always needed for background clearing
2353 m_delayedBackgroundColour
= TRUE
;
2355 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2356 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2358 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2360 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2361 scroll_class
->scrollbar_spacing
= 0;
2363 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2365 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2366 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2368 m_wxwindow
= gtk_pizza_new();
2370 #ifndef __WXUNIVERSAL__
2371 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2373 if (HasFlag(wxRAISED_BORDER
))
2375 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2377 else if (HasFlag(wxSUNKEN_BORDER
))
2379 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2381 else if (HasFlag(wxSIMPLE_BORDER
))
2383 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2387 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2389 #endif // __WXUNIVERSAL__
2391 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2393 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2394 m_acceptsFocus
= TRUE
;
2396 // I _really_ don't want scrollbars in the beginning
2397 m_vAdjust
->lower
= 0.0;
2398 m_vAdjust
->upper
= 1.0;
2399 m_vAdjust
->value
= 0.0;
2400 m_vAdjust
->step_increment
= 1.0;
2401 m_vAdjust
->page_increment
= 1.0;
2402 m_vAdjust
->page_size
= 5.0;
2403 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2404 m_hAdjust
->lower
= 0.0;
2405 m_hAdjust
->upper
= 1.0;
2406 m_hAdjust
->value
= 0.0;
2407 m_hAdjust
->step_increment
= 1.0;
2408 m_hAdjust
->page_increment
= 1.0;
2409 m_hAdjust
->page_size
= 5.0;
2410 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2412 // these handlers block mouse events to any window during scrolling such as
2413 // motion events and prevent GTK and wxWindows from fighting over where the
2416 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2417 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2419 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2420 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2422 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2423 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2425 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2426 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2428 // these handlers get notified when screen updates are required either when
2429 // scrolling or when the window size (and therefore scrollbar configuration)
2432 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2433 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2434 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2435 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2437 gtk_widget_show( m_wxwindow
);
2440 m_parent
->DoAddChild( this );
2442 m_focusWidget
= m_wxwindow
;
2451 wxWindowGTK::~wxWindowGTK()
2453 if (g_focusWindow
== this)
2454 g_focusWindow
= NULL
;
2456 if (g_activeFrame
== this)
2457 g_activeFrame
= NULL
;
2459 m_isBeingDeleted
= TRUE
;
2468 m_parent
->RemoveChild( this );
2472 gdk_ic_destroy (m_ic
);
2474 gdk_ic_attr_destroy (m_icattr
);
2479 #if DISABLE_STYLE_IF_BROKEN_THEME
2480 // don't delete if it's a pixmap theme style
2481 if (!m_widgetStyle
->engine_data
)
2482 gtk_style_unref( m_widgetStyle
);
2484 m_widgetStyle
= (GtkStyle
*) NULL
;
2489 gtk_widget_destroy( m_wxwindow
);
2490 m_wxwindow
= (GtkWidget
*) NULL
;
2495 gtk_widget_destroy( m_widget
);
2496 m_widget
= (GtkWidget
*) NULL
;
2500 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2502 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2504 /* this turns -1 into 20 so that a minimal window is
2505 visible even although -1,-1 has been given as the
2506 size of the window. the same trick is used in other
2507 ports and should make debugging easier */
2508 m_width
= WidthDefault(size
.x
);
2509 m_height
= HeightDefault(size
.y
);
2514 /* some reasonable defaults */
2519 m_x
= (gdk_screen_width () - m_width
) / 2;
2520 if (m_x
< 10) m_x
= 10;
2524 m_y
= (gdk_screen_height () - m_height
) / 2;
2525 if (m_y
< 10) m_y
= 10;
2532 void wxWindowGTK::PostCreation()
2534 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2540 // these get reported to wxWindows -> wxPaintEvent
2542 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2544 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2545 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2548 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2549 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2551 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2553 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2554 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2557 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2561 // these are called when the "sunken" or "raised" borders are drawn
2562 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2563 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2566 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2567 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2573 if (m_focusWidget
== NULL
)
2574 m_focusWidget
= m_widget
;
2576 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2577 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2579 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2580 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2582 // connect to the various key and mouse handlers
2584 GtkWidget
*connect_widget
= GetConnectWidget();
2586 ConnectWidget( connect_widget
);
2588 /* We cannot set colours, fonts and cursors before the widget has
2589 been realized, so we do this directly after realization */
2590 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2591 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2595 // Catch native resize events
2596 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2597 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2599 // Initialize XIM support
2600 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2601 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2603 // And resize XIM window
2604 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2605 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2608 if (!GTK_IS_COMBO(m_widget
))
2610 // This is needed if we want to add our windows into native
2611 // GTK control, such as the toolbar. With this callback, the
2612 // toolbar gets to know the correct size (the one set by the
2613 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2614 // when moving to GTK 2.0.
2615 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2616 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2622 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2624 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2625 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2627 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2628 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2630 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2631 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2633 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2634 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2636 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2637 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2639 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2640 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2642 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2643 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2646 bool wxWindowGTK::Destroy()
2648 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2652 return wxWindowBase::Destroy();
2655 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2657 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2660 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2662 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2663 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2666 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2669 if (m_resizing
) return; /* I don't like recursions */
2672 int currentX
, currentY
;
2673 GetPosition(¤tX
, ¤tY
);
2678 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2680 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2682 /* don't set the size for children of wxNotebook, just take the values. */
2690 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2691 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2693 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2694 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2695 if (width
!= -1) m_width
= width
;
2696 if (height
!= -1) m_height
= height
;
2700 m_x
= x
+ pizza
->xoffset
;
2701 m_y
= y
+ pizza
->yoffset
;
2706 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2708 if (width
== -1) m_width
= 80;
2711 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2713 if (height
== -1) m_height
= 26;
2716 int minWidth
= GetMinWidth(),
2717 minHeight
= GetMinHeight(),
2718 maxWidth
= GetMaxWidth(),
2719 maxHeight
= GetMaxHeight();
2721 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2722 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2723 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2724 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2727 int bottom_border
= 0;
2730 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2732 /* the default button has a border around it */
2738 DoMoveWindow( m_x
-border
,
2741 m_height
+border
+bottom_border
);
2746 /* Sometimes the client area changes size without the
2747 whole windows's size changing, but if the whole
2748 windows's size doesn't change, no wxSizeEvent will
2749 normally be sent. Here we add an extra test if
2750 the client test has been changed and this will
2752 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2756 wxPrintf( "OnSize sent from " );
2757 if (GetClassInfo() && GetClassInfo()->GetClassName())
2758 wxPrintf( GetClassInfo()->GetClassName() );
2759 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2762 if (!m_nativeSizeEvent
)
2764 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2765 event
.SetEventObject( this );
2766 GetEventHandler()->ProcessEvent( event
);
2772 void wxWindowGTK::OnInternalIdle()
2774 // Update invalidated regions.
2777 // Synthetize activate events.
2778 if ( g_sendActivateEvent
!= -1 )
2780 bool activate
= g_sendActivateEvent
!= 0;
2783 g_sendActivateEvent
= -1;
2785 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2788 if ( g_activeFrameLostFocus
)
2790 if ( g_activeFrame
)
2792 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2793 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2794 event
.SetEventObject(g_activeFrame
);
2795 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2796 g_activeFrame
= NULL
;
2798 g_activeFrameLostFocus
= FALSE
;
2801 wxCursor cursor
= m_cursor
;
2802 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2806 /* I now set the cursor anew in every OnInternalIdle call
2807 as setting the cursor in a parent window also effects the
2808 windows above so that checking for the current cursor is
2813 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2815 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2817 if (!g_globalCursor
.Ok())
2818 cursor
= *wxSTANDARD_CURSOR
;
2820 window
= m_widget
->window
;
2821 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2822 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2828 GdkWindow
*window
= m_widget
->window
;
2829 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2830 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2838 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2840 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2842 if (width
) (*width
) = m_width
;
2843 if (height
) (*height
) = m_height
;
2846 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2848 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2852 SetSize( width
, height
);
2859 #ifndef __WXUNIVERSAL__
2860 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2862 /* when using GTK 1.2 we set the shadow border size to 2 */
2866 if (HasFlag(wxSIMPLE_BORDER
))
2868 /* when using GTK 1.2 we set the simple border size to 1 */
2872 #endif // __WXUNIVERSAL__
2876 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2878 GtkRequisition vscroll_req
;
2879 vscroll_req
.width
= 2;
2880 vscroll_req
.height
= 2;
2881 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2882 (scroll_window
->vscrollbar
, &vscroll_req
);
2884 GtkRequisition hscroll_req
;
2885 hscroll_req
.width
= 2;
2886 hscroll_req
.height
= 2;
2887 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2888 (scroll_window
->hscrollbar
, &hscroll_req
);
2890 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2892 if (scroll_window
->vscrollbar_visible
)
2894 dw
+= vscroll_req
.width
;
2895 dw
+= scroll_class
->scrollbar_spacing
;
2898 if (scroll_window
->hscrollbar_visible
)
2900 dh
+= hscroll_req
.height
;
2901 dh
+= scroll_class
->scrollbar_spacing
;
2905 SetSize( width
+dw
, height
+dh
);
2909 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2911 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2915 if (width
) (*width
) = m_width
;
2916 if (height
) (*height
) = m_height
;
2923 #ifndef __WXUNIVERSAL__
2924 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2926 /* when using GTK 1.2 we set the shadow border size to 2 */
2930 if (HasFlag(wxSIMPLE_BORDER
))
2932 /* when using GTK 1.2 we set the simple border size to 1 */
2936 #endif // __WXUNIVERSAL__
2940 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2942 GtkRequisition vscroll_req
;
2943 vscroll_req
.width
= 2;
2944 vscroll_req
.height
= 2;
2945 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2946 (scroll_window
->vscrollbar
, &vscroll_req
);
2948 GtkRequisition hscroll_req
;
2949 hscroll_req
.width
= 2;
2950 hscroll_req
.height
= 2;
2951 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2952 (scroll_window
->hscrollbar
, &hscroll_req
);
2954 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2956 if (scroll_window
->vscrollbar_visible
)
2958 dw
+= vscroll_req
.width
;
2959 dw
+= scroll_class
->scrollbar_spacing
;
2962 if (scroll_window
->hscrollbar_visible
)
2964 dh
+= hscroll_req
.height
;
2965 dh
+= scroll_class
->scrollbar_spacing
;
2969 if (width
) (*width
) = m_width
- dw
;
2970 if (height
) (*height
) = m_height
- dh
;
2974 printf( "GetClientSize, name %s ", GetName().c_str() );
2975 if (width) printf( " width = %d", (*width) );
2976 if (height) printf( " height = %d", (*height) );
2981 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2983 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2987 if (m_parent
&& m_parent
->m_wxwindow
)
2989 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2990 dx
= pizza
->xoffset
;
2991 dy
= pizza
->yoffset
;
2994 if (x
) (*x
) = m_x
- dx
;
2995 if (y
) (*y
) = m_y
- dy
;
2998 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3000 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3002 if (!m_widget
->window
) return;
3004 GdkWindow
*source
= (GdkWindow
*) NULL
;
3006 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3008 source
= m_widget
->window
;
3012 gdk_window_get_origin( source
, &org_x
, &org_y
);
3016 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3018 org_x
+= m_widget
->allocation
.x
;
3019 org_y
+= m_widget
->allocation
.y
;
3027 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3029 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3031 if (!m_widget
->window
) return;
3033 GdkWindow
*source
= (GdkWindow
*) NULL
;
3035 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3037 source
= m_widget
->window
;
3041 gdk_window_get_origin( source
, &org_x
, &org_y
);
3045 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3047 org_x
+= m_widget
->allocation
.x
;
3048 org_y
+= m_widget
->allocation
.y
;
3056 bool wxWindowGTK::Show( bool show
)
3058 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3060 if (!wxWindowBase::Show(show
))
3067 gtk_widget_show( m_widget
);
3069 gtk_widget_hide( m_widget
);
3074 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3076 win
->OnParentEnable(enable
);
3078 // Recurse, so that children have the opportunity to Do The Right Thing
3079 // and reset colours that have been messed up by a parent's (really ancestor's)
3081 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3083 node
= node
->GetNext() )
3085 wxWindow
*child
= node
->GetData();
3086 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3087 wxWindowNotifyEnable(child
, enable
);
3091 bool wxWindowGTK::Enable( bool enable
)
3093 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3095 if (!wxWindowBase::Enable(enable
))
3101 gtk_widget_set_sensitive( m_widget
, enable
);
3103 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3105 wxWindowNotifyEnable(this, enable
);
3110 int wxWindowGTK::GetCharHeight() const
3112 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3114 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3116 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3118 return font
->ascent
+ font
->descent
;
3121 int wxWindowGTK::GetCharWidth() const
3123 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3125 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3127 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3129 return gdk_string_width( font
, "H" );
3132 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3136 int *externalLeading
,
3137 const wxFont
*theFont
) const
3139 wxFont fontToUse
= m_font
;
3140 if (theFont
) fontToUse
= *theFont
;
3142 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3144 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3145 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3146 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3147 if (descent
) (*descent
) = font
->descent
;
3148 if (externalLeading
) (*externalLeading
) = 0; // ??
3151 void wxWindowGTK::SetFocus()
3153 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3156 wxPrintf( "SetFocus from " );
3157 if (GetClassInfo() && GetClassInfo()->GetClassName())
3158 wxPrintf( GetClassInfo()->GetClassName() );
3164 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3166 gtk_widget_grab_focus (m_wxwindow
);
3171 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3173 gtk_widget_grab_focus (m_widget
);
3175 else if (GTK_IS_CONTAINER(m_widget
))
3177 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3186 bool wxWindowGTK::AcceptsFocus() const
3188 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3191 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3193 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3195 wxWindowGTK
*oldParent
= m_parent
,
3196 *newParent
= (wxWindowGTK
*)newParentBase
;
3198 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3200 if ( !wxWindowBase::Reparent(newParent
) )
3203 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3205 /* prevent GTK from deleting the widget arbitrarily */
3206 gtk_widget_ref( m_widget
);
3210 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3213 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3217 /* insert GTK representation */
3218 (*(newParent
->m_insertCallback
))(newParent
, this);
3221 /* reverse: prevent GTK from deleting the widget arbitrarily */
3222 gtk_widget_unref( m_widget
);
3227 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3229 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3231 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3233 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3238 /* insert GTK representation */
3239 (*m_insertCallback
)(this, child
);
3242 void wxWindowGTK::Raise()
3244 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3246 if (!m_widget
->window
) return;
3248 gdk_window_raise( m_widget
->window
);
3251 void wxWindowGTK::Lower()
3253 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3255 if (!m_widget
->window
) return;
3257 gdk_window_lower( m_widget
->window
);
3260 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3262 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3264 if (cursor
== m_cursor
)
3268 wxapp_install_idle_handler();
3270 if (cursor
== wxNullCursor
)
3271 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3273 return wxWindowBase::SetCursor( cursor
);
3276 void wxWindowGTK::WarpPointer( int x
, int y
)
3278 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3280 // We provide this function ourselves as it is
3281 // missing in GDK (top of this file).
3283 GdkWindow
*window
= (GdkWindow
*) NULL
;
3285 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3287 window
= GetConnectWidget()->window
;
3290 gdk_window_warp_pointer( window
, x
, y
);
3293 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3295 if (!m_widget
) return;
3296 if (!m_widget
->window
) return;
3299 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3303 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3304 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3308 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3309 m_clearRegion
.Clear();
3310 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3318 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3319 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3323 GdkRectangle gdk_rect
;
3324 gdk_rect
.x
= rect
->x
;
3325 gdk_rect
.y
= rect
->y
;
3326 gdk_rect
.width
= rect
->width
;
3327 gdk_rect
.height
= rect
->height
;
3328 gtk_widget_draw( m_widget
, &gdk_rect
);
3335 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3336 m_updateRegion
.Clear();
3337 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3341 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3349 GdkRectangle gdk_rect
;
3350 gdk_rect
.x
= rect
->x
;
3351 gdk_rect
.y
= rect
->y
;
3352 gdk_rect
.width
= rect
->width
;
3353 gdk_rect
.height
= rect
->height
;
3354 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3358 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3364 void wxWindowGTK::Update()
3367 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3368 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3371 if (!m_updateRegion
.IsEmpty())
3372 GtkSendPaintEvents();
3375 void wxWindowGTK::GtkSendPaintEvents()
3379 m_clearRegion
.Clear();
3380 m_updateRegion
.Clear();
3384 m_clipPaintRegion
= TRUE
;
3386 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3388 wxWindowDC
dc( (wxWindow
*)this );
3389 dc
.SetClippingRegion( m_clearRegion
);
3391 wxEraseEvent
erase_event( GetId(), &dc
);
3392 erase_event
.SetEventObject( this );
3394 if (!GetEventHandler()->ProcessEvent(erase_event
))
3398 g_eraseGC
= gdk_gc_new( GTK_PIZZA(m_wxwindow
)->bin_window
);
3399 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3401 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3403 wxRegionIterator
upd( m_clearRegion
);
3406 gdk_draw_rectangle( GTK_PIZZA(m_wxwindow
)->bin_window
, g_eraseGC
, 1,
3407 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3411 m_clearRegion
.Clear();
3414 wxNcPaintEvent
nc_paint_event( GetId() );
3415 nc_paint_event
.SetEventObject( this );
3416 GetEventHandler()->ProcessEvent( nc_paint_event
);
3418 wxPaintEvent
paint_event( GetId() );
3419 paint_event
.SetEventObject( this );
3420 GetEventHandler()->ProcessEvent( paint_event
);
3422 m_clipPaintRegion
= FALSE
;
3424 #ifndef __WXUNIVERSAL__
3426 // The following code will result in all window-less widgets
3427 // being redrawn because the wxWindows class is allowed to
3428 // paint over the window-less widgets.
3430 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3432 GList
*children
= pizza
->children
;
3435 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3436 children
= children
->next
;
3438 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3439 GTK_WIDGET_DRAWABLE (child
->widget
))
3441 // Get intersection of widget area and update region
3442 wxRegion
region( m_updateRegion
);
3444 GdkEventExpose gdk_event
;
3445 gdk_event
.type
= GDK_EXPOSE
;
3446 gdk_event
.window
= pizza
->bin_window
;
3447 gdk_event
.count
= 0;
3449 wxRegionIterator
upd( m_updateRegion
);
3453 rect
.x
= upd
.GetX();
3454 rect
.y
= upd
.GetY();
3455 rect
.width
= upd
.GetWidth();
3456 rect
.height
= upd
.GetHeight();
3458 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3460 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3470 m_updateRegion
.Clear();
3473 void wxWindowGTK::Clear()
3475 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3477 if (!m_widget
->window
) return;
3479 if (m_wxwindow
&& m_wxwindow
->window
)
3481 gdk_window_clear( m_wxwindow
->window
);
3486 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3488 wxWindowBase::DoSetToolTip(tip
);
3491 m_tooltip
->Apply( (wxWindow
*)this );
3494 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3496 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3498 #endif // wxUSE_TOOLTIPS
3500 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3502 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3504 if (!wxWindowBase::SetBackgroundColour(colour
))
3506 // don't leave if the GTK widget has just
3508 if (!m_delayedBackgroundColour
) return FALSE
;
3511 GdkWindow
*window
= (GdkWindow
*) NULL
;
3513 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3515 window
= GetConnectWidget()->window
;
3519 // indicate that a new style has been set
3520 // but it couldn't get applied as the
3521 // widget hasn't been realized yet.
3522 m_delayedBackgroundColour
= TRUE
;
3527 // We need the pixel value e.g. for background clearing.
3528 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3532 (m_wxwindow
->window
) &&
3533 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3535 /* wxMSW doesn't clear the window here. I don't do that either to
3536 provide compatibility. call Clear() to do the job. */
3538 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3546 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3548 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3550 if (!wxWindowBase::SetForegroundColour(colour
))
3552 // don't leave if the GTK widget has just
3554 if (!m_delayedForegroundColour
) return FALSE
;
3557 GdkWindow
*window
= (GdkWindow
*) NULL
;
3559 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3561 window
= GetConnectWidget()->window
;
3565 // indicate that a new style has been set
3566 // but it couldn't get applied as the
3567 // widget hasn't been realized yet.
3568 m_delayedForegroundColour
= TRUE
;
3576 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3580 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3582 // FIXME: no more klass in 2.0
3584 remake
->klass
= m_widgetStyle
->klass
;
3587 gtk_style_unref( m_widgetStyle
);
3588 m_widgetStyle
= remake
;
3592 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3595 def
= gtk_widget_get_default_style();
3597 m_widgetStyle
= gtk_style_copy( def
);
3599 // FIXME: no more klass in 2.0
3601 m_widgetStyle
->klass
= def
->klass
;
3605 return m_widgetStyle
;
3608 void wxWindowGTK::SetWidgetStyle()
3610 #if DISABLE_STYLE_IF_BROKEN_THEME
3611 if (m_widget
->style
->engine_data
)
3613 static bool s_warningPrinted
= FALSE
;
3614 if (!s_warningPrinted
)
3616 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3617 s_warningPrinted
= TRUE
;
3619 m_widgetStyle
= m_widget
->style
;
3624 GtkStyle
*style
= GetWidgetStyle();
3626 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3628 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3631 if (m_foregroundColour
.Ok())
3633 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3634 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3636 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3637 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3638 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3642 // Try to restore the gtk default style. This is still a little
3643 // oversimplified for what is probably really needed here for controls
3644 // other than buttons, but is better than not being able to (re)set a
3645 // control's foreground colour to *wxBLACK -- RL
3646 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3649 def
= gtk_widget_get_default_style();
3651 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3652 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3653 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3657 if (m_backgroundColour
.Ok())
3659 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3660 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3662 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3663 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3664 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3665 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3666 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3667 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3668 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3669 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3673 // Try to restore the gtk default style. This is still a little
3674 // oversimplified for what is probably really needed here for controls
3675 // other than buttons, but is better than not being able to (re)set a
3676 // control's background colour to default grey and means resetting a
3677 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3679 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3682 def
= gtk_widget_get_default_style();
3684 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3685 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3686 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3687 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3688 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3689 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3690 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3691 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3696 void wxWindowGTK::ApplyWidgetStyle()
3700 //-----------------------------------------------------------------------------
3701 // Pop-up menu stuff
3702 //-----------------------------------------------------------------------------
3704 #if wxUSE_MENUS_NATIVE
3707 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3709 *is_waiting
= FALSE
;
3712 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3714 menu
->SetInvokingWindow( win
);
3715 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3718 wxMenuItem
*menuitem
= node
->GetData();
3719 if (menuitem
->IsSubMenu())
3721 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3724 node
= node
->GetNext();
3728 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3729 // wxPopupMenuPositionCallback()
3731 // should be safe even in the MT case as the user can hardly popup 2 menus
3732 // simultaneously, can he?
3733 static gint gs_pop_x
= 0;
3734 static gint gs_pop_y
= 0;
3736 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3739 gboolean
* WXUNUSED(whatever
),
3741 gpointer
WXUNUSED(user_data
) )
3743 // ensure that the menu appears entirely on screen
3745 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3747 wxSize sizeScreen
= wxGetDisplaySize();
3749 gint xmax
= sizeScreen
.x
- req
.width
,
3750 ymax
= sizeScreen
.y
- req
.height
;
3752 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3753 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3756 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3758 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3760 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3762 SetInvokingWindow( menu
, this );
3768 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3770 bool is_waiting
= TRUE
;
3772 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3774 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3775 (gpointer
)&is_waiting
);
3778 GTK_MENU(menu
->m_menu
),
3779 (GtkWidget
*) NULL
, // parent menu shell
3780 (GtkWidget
*) NULL
, // parent menu item
3781 wxPopupMenuPositionCallback
, // function to position it
3782 NULL
, // client data
3783 0, // button used to activate it
3784 gs_timeLastClick
// the time of activation
3789 while (gtk_events_pending())
3790 gtk_main_iteration();
3796 #endif // wxUSE_MENUS_NATIVE
3798 #if wxUSE_DRAG_AND_DROP
3800 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3802 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3804 GtkWidget
*dnd_widget
= GetConnectWidget();
3806 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3808 if (m_dropTarget
) delete m_dropTarget
;
3809 m_dropTarget
= dropTarget
;
3811 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3814 #endif // wxUSE_DRAG_AND_DROP
3816 GtkWidget
* wxWindowGTK::GetConnectWidget()
3818 GtkWidget
*connect_widget
= m_widget
;
3819 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3821 return connect_widget
;
3824 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3827 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3829 return (window
== m_widget
->window
);
3832 bool wxWindowGTK::SetFont( const wxFont
&font
)
3834 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3836 if (!wxWindowBase::SetFont(font
))
3841 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3842 if ( sysbg
== m_backgroundColour
)
3844 m_backgroundColour
= wxNullColour
;
3846 m_backgroundColour
= sysbg
;
3856 void wxWindowGTK::DoCaptureMouse()
3858 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3860 GdkWindow
*window
= (GdkWindow
*) NULL
;
3862 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3864 window
= GetConnectWidget()->window
;
3866 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3868 wxCursor
* cursor
= & m_cursor
;
3870 cursor
= wxSTANDARD_CURSOR
;
3872 gdk_pointer_grab( window
, FALSE
,
3874 (GDK_BUTTON_PRESS_MASK
|
3875 GDK_BUTTON_RELEASE_MASK
|
3876 GDK_POINTER_MOTION_HINT_MASK
|
3877 GDK_POINTER_MOTION_MASK
),
3879 cursor
->GetCursor(),
3880 (guint32
)GDK_CURRENT_TIME
);
3881 g_captureWindow
= this;
3882 g_captureWindowHasMouse
= TRUE
;
3885 void wxWindowGTK::DoReleaseMouse()
3887 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3889 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3891 g_captureWindow
= (wxWindowGTK
*) NULL
;
3893 GdkWindow
*window
= (GdkWindow
*) NULL
;
3895 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3897 window
= GetConnectWidget()->window
;
3902 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3906 wxWindow
*wxWindowBase::GetCapture()
3908 return (wxWindow
*)g_captureWindow
;
3911 bool wxWindowGTK::IsRetained() const
3916 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3917 int range
, bool refresh
)
3919 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3921 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3923 m_hasScrolling
= TRUE
;
3925 if (orient
== wxHORIZONTAL
)
3927 float fpos
= (float)pos
;
3928 float frange
= (float)range
;
3929 float fthumb
= (float)thumbVisible
;
3930 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3931 if (fpos
< 0.0) fpos
= 0.0;
3933 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3934 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3936 SetScrollPos( orient
, pos
, refresh
);
3940 m_oldHorizontalPos
= fpos
;
3942 m_hAdjust
->lower
= 0.0;
3943 m_hAdjust
->upper
= frange
;
3944 m_hAdjust
->value
= fpos
;
3945 m_hAdjust
->step_increment
= 1.0;
3946 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3947 m_hAdjust
->page_size
= fthumb
;
3951 float fpos
= (float)pos
;
3952 float frange
= (float)range
;
3953 float fthumb
= (float)thumbVisible
;
3954 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3955 if (fpos
< 0.0) fpos
= 0.0;
3957 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
3958 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3960 SetScrollPos( orient
, pos
, refresh
);
3964 m_oldVerticalPos
= fpos
;
3966 m_vAdjust
->lower
= 0.0;
3967 m_vAdjust
->upper
= frange
;
3968 m_vAdjust
->value
= fpos
;
3969 m_vAdjust
->step_increment
= 1.0;
3970 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3971 m_vAdjust
->page_size
= fthumb
;
3974 if (orient
== wxHORIZONTAL
)
3975 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3977 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3980 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3982 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3984 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3986 if (orient
== wxHORIZONTAL
)
3988 float fpos
= (float)pos
;
3989 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3990 if (fpos
< 0.0) fpos
= 0.0;
3991 m_oldHorizontalPos
= fpos
;
3993 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3994 m_hAdjust
->value
= fpos
;
3998 float fpos
= (float)pos
;
3999 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4000 if (fpos
< 0.0) fpos
= 0.0;
4001 m_oldVerticalPos
= fpos
;
4003 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4004 m_vAdjust
->value
= fpos
;
4007 if (m_wxwindow
->window
)
4009 if (orient
== wxHORIZONTAL
)
4011 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4012 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4014 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4016 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4017 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4021 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4022 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4024 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4026 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4027 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4032 int wxWindowGTK::GetScrollThumb( int orient
) const
4034 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4036 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4038 if (orient
== wxHORIZONTAL
)
4039 return (int)(m_hAdjust
->page_size
+0.5);
4041 return (int)(m_vAdjust
->page_size
+0.5);
4044 int wxWindowGTK::GetScrollPos( int orient
) const
4046 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4048 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4050 if (orient
== wxHORIZONTAL
)
4051 return (int)(m_hAdjust
->value
+0.5);
4053 return (int)(m_vAdjust
->value
+0.5);
4056 int wxWindowGTK::GetScrollRange( int orient
) const
4058 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4060 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4062 if (orient
== wxHORIZONTAL
)
4063 return (int)(m_hAdjust
->upper
+0.5);
4065 return (int)(m_vAdjust
->upper
+0.5);
4068 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4070 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4072 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4074 // No scrolling requested.
4075 if ((dx
== 0) && (dy
== 0)) return;
4078 if (!m_updateRegion
.IsEmpty())
4080 m_updateRegion
.Offset( dx
, dy
);
4084 GetClientSize( &cw
, &ch
);
4085 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4088 if (!m_clearRegion
.IsEmpty())
4090 m_clearRegion
.Offset( dx
, dy
);
4094 GetClientSize( &cw
, &ch
);
4095 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4098 m_clipPaintRegion
= TRUE
;
4100 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4102 m_clipPaintRegion
= FALSE
;
4105 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4107 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4108 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4115 // Find the wxWindow at the current mouse position, also returning the mouse
4117 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4119 pt
= wxGetMousePosition();
4120 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4124 // Get the current mouse position.
4125 wxPoint
wxGetMousePosition()
4127 /* This crashes when used within wxHelpContext,
4128 so we have to use the X-specific implementation below.
4130 GdkModifierType *mask;
4131 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4133 return wxPoint(x, y);
4137 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4139 return wxPoint(-999, -999);
4141 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4142 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4143 Window rootReturn
, childReturn
;
4144 int rootX
, rootY
, winX
, winY
;
4145 unsigned int maskReturn
;
4147 XQueryPointer (display
,
4151 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4152 return wxPoint(rootX
, rootY
);
4156 // ----------------------------------------------------------------------------
4158 // ----------------------------------------------------------------------------
4160 class wxWinModule
: public wxModule
4167 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4170 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4172 bool wxWinModule::OnInit()
4174 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4175 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4180 void wxWinModule::OnExit()
4183 gdk_gc_unref( g_eraseGC
);