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 resue 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 // turn on to see the key event codes on the console
965 #undef DEBUG_KEY_EVENTS
967 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
968 GdkEventKey
*gdk_event
,
974 wxapp_install_idle_handler();
976 if (!win
->m_hasVMT
) return FALSE
;
977 if (g_blockEventsOnDrag
) return FALSE
;
982 GdkModifierType state
;
983 if (gdk_event
->window
)
984 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
988 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
990 #ifdef DEBUG_KEY_EVENTS
991 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
992 #endif // DEBUG_KEY_EVENTS
994 /* sending unknown key events doesn't really make sense */
998 wxKeyEvent
event( wxEVT_KEY_DOWN
);
999 event
.SetTimestamp( gdk_event
->time
);
1000 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1001 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1002 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1003 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1004 event
.m_keyCode
= key_code
;
1005 event
.m_scanCode
= gdk_event
->keyval
;
1008 event
.SetEventObject( win
);
1009 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1014 wxWindowGTK
*ancestor
= win
;
1017 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1020 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1021 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1024 if (ancestor
->IsTopLevel())
1026 ancestor
= ancestor
->GetParent();
1029 #endif // wxUSE_ACCEL
1031 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1032 will only be sent if it is not in an accelerator table. */
1035 key_code
= map_to_wx_keysym( gdk_event
);
1039 #ifdef DEBUG_KEY_EVENTS
1040 wxPrintf(_T("Char event: %ld\n"), key_code
);
1041 #endif // DEBUG_KEY_EVENTS
1043 // reuse the ame event object, just change its type and use the
1044 // translated keycode instead of the raw one
1045 event
.SetEventType(wxEVT_CHAR
);
1046 event
.m_keyCode
= key_code
;
1048 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1052 /* win is a control: tab can be propagated up */
1054 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1055 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1056 // have this style, yet choose not to process this particular TAB in which
1057 // case TAB must still work as a navigational character
1059 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1061 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1063 wxNavigationKeyEvent new_event
;
1064 new_event
.SetEventObject( win
->GetParent() );
1065 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1066 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1067 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1068 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1069 new_event
.SetCurrentFocus( win
);
1070 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1073 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1075 (gdk_event
->keyval
== GDK_Escape
) )
1077 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1078 new_event
.SetEventObject( win
);
1079 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1083 #if 0 // (GTK_MINOR_VERSION > 0)
1084 /* Pressing F10 will activate the menu bar of the top frame. */
1086 (gdk_event
->keyval
== GDK_F10
) )
1088 wxWindowGTK
*ancestor
= win
;
1091 if (wxIsKindOf(ancestor
,wxFrame
))
1093 wxFrame
*frame
= (wxFrame
*) ancestor
;
1094 wxMenuBar
*menubar
= frame
->GetMenuBar();
1097 wxNode
*node
= menubar
->GetMenus().First();
1100 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1101 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1107 ancestor
= ancestor
->GetParent();
1114 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1121 //-----------------------------------------------------------------------------
1122 // "key_release_event" from any window
1123 //-----------------------------------------------------------------------------
1125 static gint
gtk_window_key_release_callback( GtkWidget
*widget
, GdkEventKey
*gdk_event
, wxWindowGTK
*win
)
1130 wxapp_install_idle_handler();
1132 if (!win
->m_hasVMT
) return FALSE
;
1133 if (g_blockEventsOnDrag
) return FALSE
;
1135 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
1137 #ifdef DEBUG_KEY_EVENTS
1138 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
1139 #endif // DEBUG_KEY_EVENTS
1141 /* sending unknown key events doesn't really make sense */
1142 if (key_code
== 0) return FALSE
;
1146 GdkModifierType state
;
1147 if (gdk_event
->window
)
1148 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1150 wxKeyEvent
event( wxEVT_KEY_UP
);
1151 event
.SetTimestamp( gdk_event
->time
);
1152 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1153 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1154 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1155 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1156 event
.m_keyCode
= key_code
;
1157 event
.m_scanCode
= gdk_event
->keyval
;
1160 event
.SetEventObject( win
);
1162 if (win
->GetEventHandler()->ProcessEvent( event
))
1164 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1171 // ============================================================================
1173 // ============================================================================
1175 // init wxMouseEvent with the info from gdk_event
1176 #define InitMouseEvent(win, event, gdk_event) \
1178 event.SetTimestamp( gdk_event->time ); \
1179 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1180 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1181 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1182 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1183 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1184 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1185 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1187 wxPoint pt = win->GetClientAreaOrigin(); \
1188 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1189 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1192 // ----------------------------------------------------------------------------
1193 // mouse event processing helper
1194 // ----------------------------------------------------------------------------
1196 static void AdjustEventButtonState(wxMouseEvent
& event
)
1198 // GDK reports the old state of the button for a button press event, but
1199 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1200 // for a LEFT_DOWN event, not FALSE, so we will invert
1201 // left/right/middleDown for the corresponding click events
1203 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1204 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1205 (event
.GetEventType() == wxEVT_LEFT_UP
))
1207 event
.m_leftDown
= !event
.m_leftDown
;
1211 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1212 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1213 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1215 event
.m_middleDown
= !event
.m_middleDown
;
1219 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1220 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1221 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1223 event
.m_rightDown
= !event
.m_rightDown
;
1228 //-----------------------------------------------------------------------------
1229 // "button_press_event"
1230 //-----------------------------------------------------------------------------
1232 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1237 wxapp_install_idle_handler();
1240 wxPrintf( wxT("1) OnButtonPress from ") );
1241 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1242 wxPrintf( win->GetClassInfo()->GetClassName() );
1243 wxPrintf( wxT(".\n") );
1245 if (!win
->m_hasVMT
) return FALSE
;
1246 if (g_blockEventsOnDrag
) return TRUE
;
1247 if (g_blockEventsOnScroll
) return TRUE
;
1249 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1251 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1253 gtk_widget_grab_focus( win
->m_wxwindow
);
1255 wxPrintf( wxT("GrabFocus from ") );
1256 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1257 wxPrintf( win->GetClassInfo()->GetClassName() );
1258 wxPrintf( wxT(".\n") );
1262 wxEventType event_type
= wxEVT_NULL
;
1264 if (gdk_event
->button
== 1)
1266 switch (gdk_event
->type
)
1268 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1269 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1273 else if (gdk_event
->button
== 2)
1275 switch (gdk_event
->type
)
1277 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1278 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1282 else if (gdk_event
->button
== 3)
1284 switch (gdk_event
->type
)
1286 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1287 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1292 if ( event_type
== wxEVT_NULL
)
1294 // unknown mouse button or click type
1298 wxMouseEvent
event( event_type
);
1299 InitMouseEvent( win
, event
, gdk_event
);
1301 AdjustEventButtonState(event
);
1303 // wxListBox actually get mouse events from the item
1305 if (win
->m_isListBox
)
1307 event
.m_x
+= widget
->allocation
.x
;
1308 event
.m_y
+= widget
->allocation
.y
;
1311 // Some control don't have their own X window and thus cannot get
1314 if (!g_captureWindow
)
1316 wxCoord x
= event
.m_x
;
1317 wxCoord y
= event
.m_y
;
1318 if (win
->m_wxwindow
)
1320 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1321 x
+= pizza
->xoffset
;
1322 y
+= pizza
->yoffset
;
1325 wxNode
*node
= win
->GetChildren().First();
1328 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1330 node
= node
->Next();
1331 if (!child
->IsShown())
1334 if (child
->m_isStaticBox
)
1336 // wxStaticBox is transparent in the box itself
1337 int xx1
= child
->m_x
;
1338 int yy1
= child
->m_y
;
1339 int xx2
= child
->m_x
+ child
->m_width
;
1340 int yy2
= child
->m_x
+ child
->m_height
;
1343 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1345 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1347 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1349 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1352 event
.m_x
-= child
->m_x
;
1353 event
.m_y
-= child
->m_y
;
1360 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1361 (child
->m_x
<= x
) &&
1362 (child
->m_y
<= y
) &&
1363 (child
->m_x
+child
->m_width
>= x
) &&
1364 (child
->m_y
+child
->m_height
>= y
))
1367 event
.m_x
-= child
->m_x
;
1368 event
.m_y
-= child
->m_y
;
1375 event
.SetEventObject( win
);
1377 gs_timeLastClick
= gdk_event
->time
;
1380 wxPrintf( wxT("2) OnButtonPress from ") );
1381 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1382 wxPrintf( win->GetClassInfo()->GetClassName() );
1383 wxPrintf( wxT(".\n") );
1386 if (win
->GetEventHandler()->ProcessEvent( event
))
1388 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1395 //-----------------------------------------------------------------------------
1396 // "button_release_event"
1397 //-----------------------------------------------------------------------------
1399 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1404 wxapp_install_idle_handler();
1406 if (!win
->m_hasVMT
) return FALSE
;
1407 if (g_blockEventsOnDrag
) return FALSE
;
1408 if (g_blockEventsOnScroll
) return FALSE
;
1410 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1413 printf( "OnButtonRelease from " );
1414 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1415 printf( win->GetClassInfo()->GetClassName() );
1419 wxEventType event_type
= wxEVT_NULL
;
1421 switch (gdk_event
->button
)
1423 case 1: event_type
= wxEVT_LEFT_UP
; break;
1424 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1425 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1426 default: return FALSE
;
1429 wxMouseEvent
event( event_type
);
1430 InitMouseEvent( win
, event
, gdk_event
);
1432 AdjustEventButtonState(event
);
1434 // wxListBox actually get mouse events from the item
1436 if (win
->m_isListBox
)
1438 event
.m_x
+= widget
->allocation
.x
;
1439 event
.m_y
+= widget
->allocation
.y
;
1442 // Some control don't have their own X window and thus cannot get
1445 if (!g_captureWindow
)
1447 wxCoord x
= event
.m_x
;
1448 wxCoord y
= event
.m_y
;
1449 if (win
->m_wxwindow
)
1451 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1452 x
+= pizza
->xoffset
;
1453 y
+= pizza
->yoffset
;
1456 wxNode
*node
= win
->GetChildren().First();
1459 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1461 node
= node
->Next();
1462 if (!child
->IsShown())
1465 if (child
->m_isStaticBox
)
1467 // wxStaticBox is transparent in the box itself
1468 int xx1
= child
->m_x
;
1469 int yy1
= child
->m_y
;
1470 int xx2
= child
->m_x
+ child
->m_width
;
1471 int yy2
= child
->m_x
+ child
->m_height
;
1474 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1476 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1478 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1480 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1483 event
.m_x
-= child
->m_x
;
1484 event
.m_y
-= child
->m_y
;
1491 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1492 (child
->m_x
<= x
) &&
1493 (child
->m_y
<= y
) &&
1494 (child
->m_x
+child
->m_width
>= x
) &&
1495 (child
->m_y
+child
->m_height
>= y
))
1498 event
.m_x
-= child
->m_x
;
1499 event
.m_y
-= child
->m_y
;
1506 event
.SetEventObject( win
);
1508 if (win
->GetEventHandler()->ProcessEvent( event
))
1510 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1517 //-----------------------------------------------------------------------------
1518 // "motion_notify_event"
1519 //-----------------------------------------------------------------------------
1521 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1522 GdkEventMotion
*gdk_event
,
1528 wxapp_install_idle_handler();
1530 if (!win
->m_hasVMT
) return FALSE
;
1531 if (g_blockEventsOnDrag
) return FALSE
;
1532 if (g_blockEventsOnScroll
) return FALSE
;
1534 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1536 if (gdk_event
->is_hint
)
1540 GdkModifierType state
;
1541 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1547 printf( "OnMotion from " );
1548 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1549 printf( win->GetClassInfo()->GetClassName() );
1553 wxMouseEvent
event( wxEVT_MOTION
);
1554 InitMouseEvent(win
, event
, gdk_event
);
1556 if ( g_captureWindow
)
1558 // synthetize a mouse enter or leave event if needed
1559 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1560 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1561 if ( hasMouse
!= g_captureWindowHasMouse
)
1563 // the mouse changed window
1564 g_captureWindowHasMouse
= hasMouse
;
1566 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1567 : wxEVT_LEAVE_WINDOW
);
1568 InitMouseEvent(win
, event
, gdk_event
);
1569 event
.SetEventObject(win
);
1570 win
->GetEventHandler()->ProcessEvent(event
);
1575 // Some control don't have their own X window and thus cannot get
1578 wxCoord x
= event
.m_x
;
1579 wxCoord y
= event
.m_y
;
1580 if (win
->m_wxwindow
)
1582 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1583 x
+= pizza
->xoffset
;
1584 y
+= pizza
->yoffset
;
1587 wxNode
*node
= win
->GetChildren().First();
1590 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1592 node
= node
->Next();
1593 if (!child
->IsShown())
1596 if (child
->m_isStaticBox
)
1598 // wxStaticBox is transparent in the box itself
1599 int xx1
= child
->m_x
;
1600 int yy1
= child
->m_y
;
1601 int xx2
= child
->m_x
+ child
->m_width
;
1602 int yy2
= child
->m_x
+ child
->m_height
;
1605 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1607 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1609 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1611 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1614 event
.m_x
-= child
->m_x
;
1615 event
.m_y
-= child
->m_y
;
1622 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1623 (child
->m_x
<= x
) &&
1624 (child
->m_y
<= y
) &&
1625 (child
->m_x
+child
->m_width
>= x
) &&
1626 (child
->m_y
+child
->m_height
>= y
))
1629 event
.m_x
-= child
->m_x
;
1630 event
.m_y
-= child
->m_y
;
1637 event
.SetEventObject( win
);
1639 if (win
->GetEventHandler()->ProcessEvent( event
))
1641 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1648 //-----------------------------------------------------------------------------
1650 //-----------------------------------------------------------------------------
1652 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1653 GdkEvent
*WXUNUSED(event
),
1659 wxapp_install_idle_handler();
1661 if (!win
->m_hasVMT
) return FALSE
;
1662 if (g_blockEventsOnDrag
) return FALSE
;
1664 switch ( g_sendActivateEvent
)
1667 // we've got focus from outside, synthetize wxActivateEvent
1668 g_sendActivateEvent
= 1;
1672 // another our window just lost focus, it was already ours before
1673 // - don't send any wxActivateEvent
1674 g_sendActivateEvent
= -1;
1679 g_focusWindow
= win
;
1682 wxLogDebug( wxT("OnSetFocus from %s\n"), win
->GetName().c_str() );
1685 // notify the parent keeping track of focus for the kbd navigation
1686 // purposes that we got it
1687 wxChildFocusEvent
eventFocus(win
);
1688 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1692 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1696 // caret needs to be informed about focus change
1697 wxCaret
*caret
= win
->GetCaret();
1700 caret
->OnSetFocus();
1702 #endif // wxUSE_CARET
1704 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1705 if ( active
!= g_activeFrame
)
1707 if ( g_activeFrame
)
1709 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1710 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1711 event
.SetEventObject(g_activeFrame
);
1712 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1715 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1716 g_activeFrame
= active
;
1717 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1718 event
.SetEventObject(g_activeFrame
);
1719 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1721 g_activeFrameLostFocus
= FALSE
;
1724 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1725 event
.SetEventObject( win
);
1727 if (win
->GetEventHandler()->ProcessEvent( event
))
1729 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1737 //-----------------------------------------------------------------------------
1738 // "focus_out_event"
1739 //-----------------------------------------------------------------------------
1741 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1746 wxapp_install_idle_handler();
1748 if (!win
->m_hasVMT
) return FALSE
;
1749 if (g_blockEventsOnDrag
) return FALSE
;
1752 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1755 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1757 // VZ: commenting this out because it does happen (although not easy
1758 // to reproduce, I only see it when using wxMiniFrame and not
1759 // always) and makes using Mahogany quite annoying
1761 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1762 wxT("unfocusing window that hasn't gained focus properly") )
1765 g_activeFrameLostFocus
= TRUE
;
1768 // if the focus goes out of our app alltogether, OnIdle() will send
1769 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1770 // g_sendActivateEvent to -1
1771 g_sendActivateEvent
= 0;
1773 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1777 g_focusWindow
= (wxWindowGTK
*)NULL
;
1785 // caret needs to be informed about focus change
1786 wxCaret
*caret
= win
->GetCaret();
1789 caret
->OnKillFocus();
1791 #endif // wxUSE_CARET
1793 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1794 event
.SetEventObject( win
);
1796 if (win
->GetEventHandler()->ProcessEvent( event
))
1798 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1805 //-----------------------------------------------------------------------------
1806 // "enter_notify_event"
1807 //-----------------------------------------------------------------------------
1809 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1814 wxapp_install_idle_handler();
1816 if (!win
->m_hasVMT
) return FALSE
;
1817 if (g_blockEventsOnDrag
) return FALSE
;
1819 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1821 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1822 event
.SetTimestamp( gdk_event
->time
);
1823 event
.SetEventObject( win
);
1827 GdkModifierType state
= (GdkModifierType
)0;
1829 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1831 InitMouseEvent(win
, event
, gdk_event
);
1832 wxPoint pt
= win
->GetClientAreaOrigin();
1833 event
.m_x
= x
+ pt
.x
;
1834 event
.m_y
= y
+ pt
.y
;
1836 if (win
->GetEventHandler()->ProcessEvent( event
))
1838 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1845 //-----------------------------------------------------------------------------
1846 // "leave_notify_event"
1847 //-----------------------------------------------------------------------------
1849 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1854 wxapp_install_idle_handler();
1856 if (!win
->m_hasVMT
) return FALSE
;
1857 if (g_blockEventsOnDrag
) return FALSE
;
1859 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1861 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1862 event
.SetTimestamp( gdk_event
->time
);
1863 event
.SetEventObject( win
);
1867 GdkModifierType state
= (GdkModifierType
)0;
1869 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1871 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
);
1872 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
);
1873 event
.m_altDown
= (state
& GDK_MOD1_MASK
);
1874 event
.m_metaDown
= (state
& GDK_MOD2_MASK
);
1875 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
);
1876 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
);
1877 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
);
1879 wxPoint pt
= win
->GetClientAreaOrigin();
1880 event
.m_x
= x
+ pt
.x
;
1881 event
.m_y
= y
+ pt
.y
;
1883 if (win
->GetEventHandler()->ProcessEvent( event
))
1885 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1892 //-----------------------------------------------------------------------------
1893 // "value_changed" from m_vAdjust
1894 //-----------------------------------------------------------------------------
1896 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1903 wxapp_install_idle_handler();
1905 if (g_blockEventsOnDrag
) return;
1907 if (!win
->m_hasVMT
) return;
1909 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1910 if (fabs(diff
) < 0.2) return;
1912 win
->m_oldVerticalPos
= adjust
->value
;
1914 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1916 int value
= (int)(adjust
->value
+0.5);
1918 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1919 event
.SetEventObject( win
);
1920 win
->GetEventHandler()->ProcessEvent( event
);
1923 //-----------------------------------------------------------------------------
1924 // "value_changed" from m_hAdjust
1925 //-----------------------------------------------------------------------------
1927 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1934 wxapp_install_idle_handler();
1936 if (g_blockEventsOnDrag
) return;
1937 if (!win
->m_hasVMT
) return;
1939 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1940 if (fabs(diff
) < 0.2) return;
1942 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1944 win
->m_oldHorizontalPos
= adjust
->value
;
1946 int value
= (int)(adjust
->value
+0.5);
1948 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1949 event
.SetEventObject( win
);
1950 win
->GetEventHandler()->ProcessEvent( event
);
1953 //-----------------------------------------------------------------------------
1954 // "button_press_event" from scrollbar
1955 //-----------------------------------------------------------------------------
1957 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1958 GdkEventButton
*gdk_event
,
1964 wxapp_install_idle_handler();
1967 g_blockEventsOnScroll
= TRUE
;
1969 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1971 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1977 //-----------------------------------------------------------------------------
1978 // "button_release_event" from scrollbar
1979 //-----------------------------------------------------------------------------
1981 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1982 GdkEventButton
*WXUNUSED(gdk_event
),
1987 // don't test here as we can release the mouse while being over
1988 // a different window than the slider
1990 // if (gdk_event->window != widget->slider) return FALSE;
1992 g_blockEventsOnScroll
= FALSE
;
1994 if (win
->m_isScrolling
)
1996 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2000 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2001 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2003 value
= (int)(win
->m_hAdjust
->value
+0.5);
2006 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2008 value
= (int)(win
->m_vAdjust
->value
+0.5);
2012 wxScrollWinEvent
event( command
, value
, dir
);
2013 event
.SetEventObject( win
);
2014 win
->GetEventHandler()->ProcessEvent( event
);
2017 win
->m_isScrolling
= FALSE
;
2022 // ----------------------------------------------------------------------------
2023 // this wxWindowBase function is implemented here (in platform-specific file)
2024 // because it is static and so couldn't be made virtual
2025 // ----------------------------------------------------------------------------
2027 wxWindow
*wxWindowBase::FindFocus()
2029 // the cast is necessary when we compile in wxUniversal mode
2030 return (wxWindow
*)g_focusWindow
;
2033 //-----------------------------------------------------------------------------
2034 // "realize" from m_widget
2035 //-----------------------------------------------------------------------------
2037 /* We cannot set colours and fonts before the widget has
2038 been realized, so we do this directly after realization. */
2041 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2046 wxapp_install_idle_handler();
2048 if (win
->m_delayedBackgroundColour
)
2049 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2051 if (win
->m_delayedForegroundColour
)
2052 win
->SetForegroundColour( win
->GetForegroundColour() );
2054 wxWindowCreateEvent
event( win
);
2055 event
.SetEventObject( win
);
2056 win
->GetEventHandler()->ProcessEvent( event
);
2061 //-----------------------------------------------------------------------------
2063 //-----------------------------------------------------------------------------
2066 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2067 GtkAllocation
*WXUNUSED(alloc
),
2071 wxapp_install_idle_handler();
2073 if (!win
->m_hasScrolling
) return;
2075 int client_width
= 0;
2076 int client_height
= 0;
2077 win
->GetClientSize( &client_width
, &client_height
);
2078 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2081 win
->m_oldClientWidth
= client_width
;
2082 win
->m_oldClientHeight
= client_height
;
2084 if (!win
->m_nativeSizeEvent
)
2086 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2087 event
.SetEventObject( win
);
2088 win
->GetEventHandler()->ProcessEvent( event
);
2094 #define WXUNUSED_UNLESS_XIM(param) param
2096 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2099 /* Resize XIM window */
2102 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2103 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2104 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2107 wxapp_install_idle_handler();
2113 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2117 gdk_window_get_size (widget
->window
, &width
, &height
);
2118 win
->m_icattr
->preedit_area
.width
= width
;
2119 win
->m_icattr
->preedit_area
.height
= height
;
2120 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2125 //-----------------------------------------------------------------------------
2126 // "realize" from m_wxwindow
2127 //-----------------------------------------------------------------------------
2129 /* Initialize XIM support */
2132 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2133 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2136 wxapp_install_idle_handler();
2139 if (win
->m_ic
) return FALSE
;
2140 if (!widget
) return FALSE
;
2141 if (!gdk_im_ready()) return FALSE
;
2143 win
->m_icattr
= gdk_ic_attr_new();
2144 if (!win
->m_icattr
) return FALSE
;
2148 GdkColormap
*colormap
;
2149 GdkICAttr
*attr
= win
->m_icattr
;
2150 unsigned attrmask
= GDK_IC_ALL_REQ
;
2152 GdkIMStyle supported_style
= (GdkIMStyle
)
2153 (GDK_IM_PREEDIT_NONE
|
2154 GDK_IM_PREEDIT_NOTHING
|
2155 GDK_IM_PREEDIT_POSITION
|
2156 GDK_IM_STATUS_NONE
|
2157 GDK_IM_STATUS_NOTHING
);
2159 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2160 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2162 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2163 attr
->client_window
= widget
->window
;
2165 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2166 gtk_widget_get_default_colormap ())
2168 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2169 attr
->preedit_colormap
= colormap
;
2172 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2173 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2174 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2175 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2177 switch (style
& GDK_IM_PREEDIT_MASK
)
2179 case GDK_IM_PREEDIT_POSITION
:
2180 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2182 g_warning ("over-the-spot style requires fontset");
2186 gdk_window_get_size (widget
->window
, &width
, &height
);
2188 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2189 attr
->spot_location
.x
= 0;
2190 attr
->spot_location
.y
= height
;
2191 attr
->preedit_area
.x
= 0;
2192 attr
->preedit_area
.y
= 0;
2193 attr
->preedit_area
.width
= width
;
2194 attr
->preedit_area
.height
= height
;
2195 attr
->preedit_fontset
= widget
->style
->font
;
2200 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2202 if (win
->m_ic
== NULL
)
2203 g_warning ("Can't create input context.");
2206 mask
= gdk_window_get_events (widget
->window
);
2207 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2208 gdk_window_set_events (widget
->window
, mask
);
2210 if (GTK_WIDGET_HAS_FOCUS(widget
))
2211 gdk_im_begin (win
->m_ic
, widget
->window
);
2218 //-----------------------------------------------------------------------------
2219 // InsertChild for wxWindowGTK.
2220 //-----------------------------------------------------------------------------
2222 /* Callback for wxWindowGTK. This very strange beast has to be used because
2223 * C++ has no virtual methods in a constructor. We have to emulate a
2224 * virtual function here as wxNotebook requires a different way to insert
2225 * a child in it. I had opted for creating a wxNotebookPage window class
2226 * which would have made this superfluous (such in the MDI window system),
2227 * but no-one was listening to me... */
2229 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2231 /* the window might have been scrolled already, do we
2232 have to adapt the position */
2233 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2234 child
->m_x
+= pizza
->xoffset
;
2235 child
->m_y
+= pizza
->yoffset
;
2237 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2238 GTK_WIDGET(child
->m_widget
),
2245 //-----------------------------------------------------------------------------
2247 //-----------------------------------------------------------------------------
2249 wxWindow
*wxGetActiveWindow()
2251 // the cast is necessary when we compile in wxUniversal mode
2252 return (wxWindow
*)g_focusWindow
;
2255 //-----------------------------------------------------------------------------
2257 //-----------------------------------------------------------------------------
2259 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2261 #ifdef __WXUNIVERSAL__
2262 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2264 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2265 #endif // __WXUNIVERSAL__/__WXGTK__
2267 void wxWindowGTK::Init()
2273 m_widget
= (GtkWidget
*) NULL
;
2274 m_wxwindow
= (GtkWidget
*) NULL
;
2275 m_focusWidget
= (GtkWidget
*) NULL
;
2285 m_needParent
= TRUE
;
2286 m_isBeingDeleted
= FALSE
;
2289 m_nativeSizeEvent
= FALSE
;
2291 m_hasScrolling
= FALSE
;
2292 m_isScrolling
= FALSE
;
2294 m_hAdjust
= (GtkAdjustment
*) NULL
;
2295 m_vAdjust
= (GtkAdjustment
*) NULL
;
2296 m_oldHorizontalPos
= 0.0;
2297 m_oldVerticalPos
= 0.0;
2300 m_widgetStyle
= (GtkStyle
*) NULL
;
2302 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2304 m_isStaticBox
= FALSE
;
2305 m_isRadioButton
= FALSE
;
2306 m_isListBox
= FALSE
;
2308 m_acceptsFocus
= FALSE
;
2310 m_clipPaintRegion
= FALSE
;
2312 m_cursor
= *wxSTANDARD_CURSOR
;
2314 m_delayedForegroundColour
= FALSE
;
2315 m_delayedBackgroundColour
= FALSE
;
2318 m_ic
= (GdkIC
*) NULL
;
2319 m_icattr
= (GdkICAttr
*) NULL
;
2323 wxWindowGTK::wxWindowGTK()
2328 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2333 const wxString
&name
)
2337 Create( parent
, id
, pos
, size
, style
, name
);
2340 bool wxWindowGTK::Create( wxWindow
*parent
,
2345 const wxString
&name
)
2347 if (!PreCreation( parent
, pos
, size
) ||
2348 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2350 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2354 m_insertCallback
= wxInsertChildInWindow
;
2356 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2357 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2359 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2361 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2362 scroll_class
->scrollbar_spacing
= 0;
2364 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2366 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2367 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2369 m_wxwindow
= gtk_pizza_new();
2371 #ifndef __WXUNIVERSAL__
2372 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2374 if (HasFlag(wxRAISED_BORDER
))
2376 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2378 else if (HasFlag(wxSUNKEN_BORDER
))
2380 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2382 else if (HasFlag(wxSIMPLE_BORDER
))
2384 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2388 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2390 #endif // __WXUNIVERSAL__
2392 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2394 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2395 m_acceptsFocus
= TRUE
;
2397 // I _really_ don't want scrollbars in the beginning
2398 m_vAdjust
->lower
= 0.0;
2399 m_vAdjust
->upper
= 1.0;
2400 m_vAdjust
->value
= 0.0;
2401 m_vAdjust
->step_increment
= 1.0;
2402 m_vAdjust
->page_increment
= 1.0;
2403 m_vAdjust
->page_size
= 5.0;
2404 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2405 m_hAdjust
->lower
= 0.0;
2406 m_hAdjust
->upper
= 1.0;
2407 m_hAdjust
->value
= 0.0;
2408 m_hAdjust
->step_increment
= 1.0;
2409 m_hAdjust
->page_increment
= 1.0;
2410 m_hAdjust
->page_size
= 5.0;
2411 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2413 // these handlers block mouse events to any window during scrolling such as
2414 // motion events and prevent GTK and wxWindows from fighting over where the
2417 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2418 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2420 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2421 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2423 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2424 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2426 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2427 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2429 // these handlers get notified when screen updates are required either when
2430 // scrolling or when the window size (and therefore scrollbar configuration)
2433 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2434 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2435 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2436 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2438 gtk_widget_show( m_wxwindow
);
2441 m_parent
->DoAddChild( this );
2443 m_focusWidget
= m_wxwindow
;
2452 wxWindowGTK::~wxWindowGTK()
2454 if (g_focusWindow
== this)
2455 g_focusWindow
= NULL
;
2457 if (g_activeFrame
== this)
2458 g_activeFrame
= NULL
;
2460 m_isBeingDeleted
= TRUE
;
2469 m_parent
->RemoveChild( this );
2473 gdk_ic_destroy (m_ic
);
2475 gdk_ic_attr_destroy (m_icattr
);
2480 #if DISABLE_STYLE_IF_BROKEN_THEME
2481 // don't delete if it's a pixmap theme style
2482 if (!m_widgetStyle
->engine_data
)
2483 gtk_style_unref( m_widgetStyle
);
2485 m_widgetStyle
= (GtkStyle
*) NULL
;
2490 gtk_widget_destroy( m_wxwindow
);
2491 m_wxwindow
= (GtkWidget
*) NULL
;
2496 gtk_widget_destroy( m_widget
);
2497 m_widget
= (GtkWidget
*) NULL
;
2501 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2503 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2505 /* this turns -1 into 20 so that a minimal window is
2506 visible even although -1,-1 has been given as the
2507 size of the window. the same trick is used in other
2508 ports and should make debugging easier */
2509 m_width
= WidthDefault(size
.x
);
2510 m_height
= HeightDefault(size
.y
);
2515 /* some reasonable defaults */
2520 m_x
= (gdk_screen_width () - m_width
) / 2;
2521 if (m_x
< 10) m_x
= 10;
2525 m_y
= (gdk_screen_height () - m_height
) / 2;
2526 if (m_y
< 10) m_y
= 10;
2533 void wxWindowGTK::PostCreation()
2535 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2541 // these get reported to wxWindows -> wxPaintEvent
2543 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2545 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2546 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2549 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2550 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2552 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2554 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2555 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2558 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2562 // these are called when the "sunken" or "raised" borders are drawn
2563 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2564 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2567 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2568 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2574 if (m_focusWidget
== NULL
)
2575 m_focusWidget
= m_widget
;
2577 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2578 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2580 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2581 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2583 // connect to the various key and mouse handlers
2585 GtkWidget
*connect_widget
= GetConnectWidget();
2587 ConnectWidget( connect_widget
);
2589 /* We cannot set colours, fonts and cursors before the widget has
2590 been realized, so we do this directly after realization */
2591 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2592 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2596 // Catch native resize events
2597 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2598 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2600 // Initialize XIM support
2601 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2602 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2604 // And resize XIM window
2605 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2606 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2609 if (!GTK_IS_COMBO(m_widget
))
2611 // This is needed if we want to add our windows into native
2612 // GTK control, such as the toolbar. With this callback, the
2613 // toolbar gets to know the correct size (the one set by the
2614 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2615 // when moving to GTK 2.0.
2616 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2617 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2623 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2625 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2626 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2628 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2629 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2631 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2632 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2634 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2635 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2637 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2638 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2640 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2641 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2643 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2644 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2647 bool wxWindowGTK::Destroy()
2649 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2653 return wxWindowBase::Destroy();
2656 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2658 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2661 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2663 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2664 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2667 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2670 if (m_resizing
) return; /* I don't like recursions */
2673 int currentX
, currentY
;
2674 GetPosition(¤tX
, ¤tY
);
2679 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2681 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2683 /* don't set the size for children of wxNotebook, just take the values. */
2691 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2692 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2694 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2695 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2696 if (width
!= -1) m_width
= width
;
2697 if (height
!= -1) m_height
= height
;
2701 m_x
= x
+ pizza
->xoffset
;
2702 m_y
= y
+ pizza
->yoffset
;
2707 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2709 if (width
== -1) m_width
= 80;
2712 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2714 if (height
== -1) m_height
= 26;
2717 int minWidth
= GetMinWidth(),
2718 minHeight
= GetMinHeight(),
2719 maxWidth
= GetMaxWidth(),
2720 maxHeight
= GetMaxHeight();
2722 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2723 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2724 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2725 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2728 int bottom_border
= 0;
2731 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2733 /* the default button has a border around it */
2739 DoMoveWindow( m_x
-border
,
2742 m_height
+border
+bottom_border
);
2747 /* Sometimes the client area changes size without the
2748 whole windows's size changing, but if the whole
2749 windows's size doesn't change, no wxSizeEvent will
2750 normally be sent. Here we add an extra test if
2751 the client test has been changed and this will
2753 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2757 wxPrintf( "OnSize sent from " );
2758 if (GetClassInfo() && GetClassInfo()->GetClassName())
2759 wxPrintf( GetClassInfo()->GetClassName() );
2760 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2763 if (!m_nativeSizeEvent
)
2765 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2766 event
.SetEventObject( this );
2767 GetEventHandler()->ProcessEvent( event
);
2773 void wxWindowGTK::OnInternalIdle()
2775 // Update invalidated regions.
2778 // Synthetize activate events.
2779 if ( g_sendActivateEvent
!= -1 )
2781 bool activate
= g_sendActivateEvent
!= 0;
2784 g_sendActivateEvent
= -1;
2786 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2789 if ( g_activeFrameLostFocus
)
2791 if ( g_activeFrame
)
2793 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2794 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2795 event
.SetEventObject(g_activeFrame
);
2796 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2797 g_activeFrame
= NULL
;
2799 g_activeFrameLostFocus
= FALSE
;
2802 wxCursor cursor
= m_cursor
;
2803 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2807 /* I now set the cursor anew in every OnInternalIdle call
2808 as setting the cursor in a parent window also effects the
2809 windows above so that checking for the current cursor is
2814 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2816 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2818 if (!g_globalCursor
.Ok())
2819 cursor
= *wxSTANDARD_CURSOR
;
2821 window
= m_widget
->window
;
2822 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2823 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2829 GdkWindow
*window
= m_widget
->window
;
2830 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2831 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2839 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2841 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2843 if (width
) (*width
) = m_width
;
2844 if (height
) (*height
) = m_height
;
2847 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2849 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2853 SetSize( width
, height
);
2860 #ifndef __WXUNIVERSAL__
2861 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2863 /* when using GTK 1.2 we set the shadow border size to 2 */
2867 if (HasFlag(wxSIMPLE_BORDER
))
2869 /* when using GTK 1.2 we set the simple border size to 1 */
2873 #endif // __WXUNIVERSAL__
2877 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2879 GtkRequisition vscroll_req
;
2880 vscroll_req
.width
= 2;
2881 vscroll_req
.height
= 2;
2882 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2883 (scroll_window
->vscrollbar
, &vscroll_req
);
2885 GtkRequisition hscroll_req
;
2886 hscroll_req
.width
= 2;
2887 hscroll_req
.height
= 2;
2888 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2889 (scroll_window
->hscrollbar
, &hscroll_req
);
2891 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2893 if (scroll_window
->vscrollbar_visible
)
2895 dw
+= vscroll_req
.width
;
2896 dw
+= scroll_class
->scrollbar_spacing
;
2899 if (scroll_window
->hscrollbar_visible
)
2901 dh
+= hscroll_req
.height
;
2902 dh
+= scroll_class
->scrollbar_spacing
;
2906 SetSize( width
+dw
, height
+dh
);
2910 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2912 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2916 if (width
) (*width
) = m_width
;
2917 if (height
) (*height
) = m_height
;
2924 #ifndef __WXUNIVERSAL__
2925 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2927 /* when using GTK 1.2 we set the shadow border size to 2 */
2931 if (HasFlag(wxSIMPLE_BORDER
))
2933 /* when using GTK 1.2 we set the simple border size to 1 */
2937 #endif // __WXUNIVERSAL__
2941 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2943 GtkRequisition vscroll_req
;
2944 vscroll_req
.width
= 2;
2945 vscroll_req
.height
= 2;
2946 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2947 (scroll_window
->vscrollbar
, &vscroll_req
);
2949 GtkRequisition hscroll_req
;
2950 hscroll_req
.width
= 2;
2951 hscroll_req
.height
= 2;
2952 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2953 (scroll_window
->hscrollbar
, &hscroll_req
);
2955 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2957 if (scroll_window
->vscrollbar_visible
)
2959 dw
+= vscroll_req
.width
;
2960 dw
+= scroll_class
->scrollbar_spacing
;
2963 if (scroll_window
->hscrollbar_visible
)
2965 dh
+= hscroll_req
.height
;
2966 dh
+= scroll_class
->scrollbar_spacing
;
2970 if (width
) (*width
) = m_width
- dw
;
2971 if (height
) (*height
) = m_height
- dh
;
2975 printf( "GetClientSize, name %s ", GetName().c_str() );
2976 if (width) printf( " width = %d", (*width) );
2977 if (height) printf( " height = %d", (*height) );
2982 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2984 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2988 if (m_parent
&& m_parent
->m_wxwindow
)
2990 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2991 dx
= pizza
->xoffset
;
2992 dy
= pizza
->yoffset
;
2995 if (x
) (*x
) = m_x
- dx
;
2996 if (y
) (*y
) = m_y
- dy
;
2999 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3001 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3003 if (!m_widget
->window
) return;
3005 GdkWindow
*source
= (GdkWindow
*) NULL
;
3007 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3009 source
= m_widget
->window
;
3013 gdk_window_get_origin( source
, &org_x
, &org_y
);
3017 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3019 org_x
+= m_widget
->allocation
.x
;
3020 org_y
+= m_widget
->allocation
.y
;
3028 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3030 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3032 if (!m_widget
->window
) return;
3034 GdkWindow
*source
= (GdkWindow
*) NULL
;
3036 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3038 source
= m_widget
->window
;
3042 gdk_window_get_origin( source
, &org_x
, &org_y
);
3046 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3048 org_x
+= m_widget
->allocation
.x
;
3049 org_y
+= m_widget
->allocation
.y
;
3057 bool wxWindowGTK::Show( bool show
)
3059 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3061 if (!wxWindowBase::Show(show
))
3068 gtk_widget_show( m_widget
);
3070 gtk_widget_hide( m_widget
);
3075 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3077 win
->OnParentEnable(enable
);
3079 // Recurse, so that children have the opportunity to Do The Right Thing
3080 // and reset colours that have been messed up by a parent's (really ancestor's)
3082 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3084 node
= node
->GetNext() )
3086 wxWindow
*child
= node
->GetData();
3087 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3088 wxWindowNotifyEnable(child
, enable
);
3092 bool wxWindowGTK::Enable( bool enable
)
3094 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3096 if (!wxWindowBase::Enable(enable
))
3102 gtk_widget_set_sensitive( m_widget
, enable
);
3104 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3106 wxWindowNotifyEnable(this, enable
);
3111 int wxWindowGTK::GetCharHeight() const
3113 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3115 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3117 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3119 return font
->ascent
+ font
->descent
;
3122 int wxWindowGTK::GetCharWidth() const
3124 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3126 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3128 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3130 return gdk_string_width( font
, "H" );
3133 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3137 int *externalLeading
,
3138 const wxFont
*theFont
) const
3140 wxFont fontToUse
= m_font
;
3141 if (theFont
) fontToUse
= *theFont
;
3143 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3145 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3146 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3147 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3148 if (descent
) (*descent
) = font
->descent
;
3149 if (externalLeading
) (*externalLeading
) = 0; // ??
3152 void wxWindowGTK::SetFocus()
3154 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3157 wxPrintf( "SetFocus from " );
3158 if (GetClassInfo() && GetClassInfo()->GetClassName())
3159 wxPrintf( GetClassInfo()->GetClassName() );
3165 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3167 gtk_widget_grab_focus (m_wxwindow
);
3172 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3174 gtk_widget_grab_focus (m_widget
);
3176 else if (GTK_IS_CONTAINER(m_widget
))
3178 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3187 bool wxWindowGTK::AcceptsFocus() const
3189 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3192 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3194 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3196 wxWindowGTK
*oldParent
= m_parent
,
3197 *newParent
= (wxWindowGTK
*)newParentBase
;
3199 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3201 if ( !wxWindowBase::Reparent(newParent
) )
3204 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3206 /* prevent GTK from deleting the widget arbitrarily */
3207 gtk_widget_ref( m_widget
);
3211 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3214 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3218 /* insert GTK representation */
3219 (*(newParent
->m_insertCallback
))(newParent
, this);
3222 /* reverse: prevent GTK from deleting the widget arbitrarily */
3223 gtk_widget_unref( m_widget
);
3228 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3230 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3232 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3234 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3239 /* insert GTK representation */
3240 (*m_insertCallback
)(this, child
);
3243 void wxWindowGTK::Raise()
3245 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3247 if (!m_widget
->window
) return;
3249 gdk_window_raise( m_widget
->window
);
3252 void wxWindowGTK::Lower()
3254 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3256 if (!m_widget
->window
) return;
3258 gdk_window_lower( m_widget
->window
);
3261 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3263 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3265 if (cursor
== m_cursor
)
3269 wxapp_install_idle_handler();
3271 if (cursor
== wxNullCursor
)
3272 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3274 return wxWindowBase::SetCursor( cursor
);
3277 void wxWindowGTK::WarpPointer( int x
, int y
)
3279 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3281 // We provide this function ourselves as it is
3282 // missing in GDK (top of this file).
3284 GdkWindow
*window
= (GdkWindow
*) NULL
;
3286 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3288 window
= GetConnectWidget()->window
;
3291 gdk_window_warp_pointer( window
, x
, y
);
3294 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3296 if (!m_widget
) return;
3297 if (!m_widget
->window
) return;
3300 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3304 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3305 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3309 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3310 m_clearRegion
.Clear();
3311 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3319 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3320 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3324 GdkRectangle gdk_rect
;
3325 gdk_rect
.x
= rect
->x
;
3326 gdk_rect
.y
= rect
->y
;
3327 gdk_rect
.width
= rect
->width
;
3328 gdk_rect
.height
= rect
->height
;
3329 gtk_widget_draw( m_widget
, &gdk_rect
);
3336 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3337 m_updateRegion
.Clear();
3338 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3342 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3350 GdkRectangle gdk_rect
;
3351 gdk_rect
.x
= rect
->x
;
3352 gdk_rect
.y
= rect
->y
;
3353 gdk_rect
.width
= rect
->width
;
3354 gdk_rect
.height
= rect
->height
;
3355 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3359 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3365 void wxWindowGTK::Update()
3368 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3369 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3372 if (!m_updateRegion
.IsEmpty())
3373 GtkSendPaintEvents();
3376 void wxWindowGTK::GtkSendPaintEvents()
3380 m_clearRegion
.Clear();
3381 m_updateRegion
.Clear();
3385 m_clipPaintRegion
= TRUE
;
3387 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3389 wxWindowDC
dc( (wxWindow
*)this );
3390 dc
.SetClippingRegion( m_clearRegion
);
3392 wxEraseEvent
erase_event( GetId(), &dc
);
3393 erase_event
.SetEventObject( this );
3395 if (!GetEventHandler()->ProcessEvent(erase_event
))
3397 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3399 wxRegionIterator
upd( m_clearRegion
);
3402 gdk_draw_rectangle( GTK_PIZZA(m_wxwindow
)->bin_window
, g_eraseGC
, 0,
3403 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3407 m_clearRegion
.Clear();
3410 wxNcPaintEvent
nc_paint_event( GetId() );
3411 nc_paint_event
.SetEventObject( this );
3412 GetEventHandler()->ProcessEvent( nc_paint_event
);
3414 wxPaintEvent
paint_event( GetId() );
3415 paint_event
.SetEventObject( this );
3416 GetEventHandler()->ProcessEvent( paint_event
);
3418 m_clipPaintRegion
= FALSE
;
3420 #ifndef __WXUNIVERSAL__
3422 // The following code will result in all window-less widgets
3423 // being redrawn because the wxWindows class is allowed to
3424 // paint over the window-less widgets.
3426 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3428 GList
*children
= pizza
->children
;
3431 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3432 children
= children
->next
;
3434 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3435 GTK_WIDGET_DRAWABLE (child
->widget
))
3437 // Get intersection of widget area and update region
3438 wxRegion
region( m_updateRegion
);
3440 GdkEventExpose gdk_event
;
3441 gdk_event
.type
= GDK_EXPOSE
;
3442 gdk_event
.window
= pizza
->bin_window
;
3443 gdk_event
.count
= 0;
3445 wxRegionIterator
upd( m_updateRegion
);
3449 rect
.x
= upd
.GetX();
3450 rect
.y
= upd
.GetY();
3451 rect
.width
= upd
.GetWidth();
3452 rect
.height
= upd
.GetHeight();
3454 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3456 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3466 m_updateRegion
.Clear();
3469 void wxWindowGTK::Clear()
3471 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3473 if (!m_widget
->window
) return;
3475 if (m_wxwindow
&& m_wxwindow
->window
)
3477 // gdk_window_clear( m_wxwindow->window );
3482 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3484 wxWindowBase::DoSetToolTip(tip
);
3487 m_tooltip
->Apply( (wxWindow
*)this );
3490 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3492 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3494 #endif // wxUSE_TOOLTIPS
3496 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3498 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3500 if (!wxWindowBase::SetBackgroundColour(colour
))
3502 // don't leave if the GTK widget has just
3504 if (!m_delayedBackgroundColour
) return FALSE
;
3507 GdkWindow
*window
= (GdkWindow
*) NULL
;
3509 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3511 window
= GetConnectWidget()->window
;
3515 // indicate that a new style has been set
3516 // but it couldn't get applied as the
3517 // widget hasn't been realized yet.
3518 m_delayedBackgroundColour
= TRUE
;
3522 (m_wxwindow
->window
) &&
3523 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3525 /* wxMSW doesn't clear the window here. I don't do that either to
3526 provide compatibility. call Clear() to do the job. */
3528 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3529 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3537 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3539 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3541 if (!wxWindowBase::SetForegroundColour(colour
))
3543 // don't leave if the GTK widget has just
3545 if (!m_delayedForegroundColour
) return FALSE
;
3548 GdkWindow
*window
= (GdkWindow
*) NULL
;
3550 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3552 window
= GetConnectWidget()->window
;
3556 // indicate that a new style has been set
3557 // but it couldn't get applied as the
3558 // widget hasn't been realized yet.
3559 m_delayedForegroundColour
= TRUE
;
3567 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3571 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3573 // FIXME: no more klass in 2.0
3575 remake
->klass
= m_widgetStyle
->klass
;
3578 gtk_style_unref( m_widgetStyle
);
3579 m_widgetStyle
= remake
;
3583 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3586 def
= gtk_widget_get_default_style();
3588 m_widgetStyle
= gtk_style_copy( def
);
3590 // FIXME: no more klass in 2.0
3592 m_widgetStyle
->klass
= def
->klass
;
3596 return m_widgetStyle
;
3599 void wxWindowGTK::SetWidgetStyle()
3601 #if DISABLE_STYLE_IF_BROKEN_THEME
3602 if (m_widget
->style
->engine_data
)
3604 static bool s_warningPrinted
= FALSE
;
3605 if (!s_warningPrinted
)
3607 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3608 s_warningPrinted
= TRUE
;
3610 m_widgetStyle
= m_widget
->style
;
3615 GtkStyle
*style
= GetWidgetStyle();
3617 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3619 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3622 if (m_foregroundColour
.Ok())
3624 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3625 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3627 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3628 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3629 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3633 // Try to restore the gtk default style. This is still a little
3634 // oversimplified for what is probably really needed here for controls
3635 // other than buttons, but is better than not being able to (re)set a
3636 // control's foreground colour to *wxBLACK -- RL
3637 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3640 def
= gtk_widget_get_default_style();
3642 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3643 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3644 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3648 if (m_backgroundColour
.Ok())
3650 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3651 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3653 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3654 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3655 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3656 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3657 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3658 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3659 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3660 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3664 // Try to restore the gtk default style. This is still a little
3665 // oversimplified for what is probably really needed here for controls
3666 // other than buttons, but is better than not being able to (re)set a
3667 // control's background colour to default grey and means resetting a
3668 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3670 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3673 def
= gtk_widget_get_default_style();
3675 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3676 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3677 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3678 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3679 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3680 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3681 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3682 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3687 void wxWindowGTK::ApplyWidgetStyle()
3691 //-----------------------------------------------------------------------------
3692 // Pop-up menu stuff
3693 //-----------------------------------------------------------------------------
3695 #if wxUSE_MENUS_NATIVE
3698 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3700 *is_waiting
= FALSE
;
3703 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3705 menu
->SetInvokingWindow( win
);
3706 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3709 wxMenuItem
*menuitem
= node
->GetData();
3710 if (menuitem
->IsSubMenu())
3712 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3715 node
= node
->GetNext();
3719 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3720 // wxPopupMenuPositionCallback()
3722 // should be safe even in the MT case as the user can hardly popup 2 menus
3723 // simultaneously, can he?
3724 static gint gs_pop_x
= 0;
3725 static gint gs_pop_y
= 0;
3727 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3730 gboolean
* WXUNUSED(whatever
),
3732 gpointer
WXUNUSED(user_data
) )
3734 // ensure that the menu appears entirely on screen
3736 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3738 wxSize sizeScreen
= wxGetDisplaySize();
3740 gint xmax
= sizeScreen
.x
- req
.width
,
3741 ymax
= sizeScreen
.y
- req
.height
;
3743 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3744 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3747 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3749 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3751 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3753 SetInvokingWindow( menu
, this );
3759 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3761 bool is_waiting
= TRUE
;
3763 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3765 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3766 (gpointer
)&is_waiting
);
3769 GTK_MENU(menu
->m_menu
),
3770 (GtkWidget
*) NULL
, // parent menu shell
3771 (GtkWidget
*) NULL
, // parent menu item
3772 wxPopupMenuPositionCallback
, // function to position it
3773 NULL
, // client data
3774 0, // button used to activate it
3775 gs_timeLastClick
// the time of activation
3780 while (gtk_events_pending())
3781 gtk_main_iteration();
3787 #endif // wxUSE_MENUS_NATIVE
3789 #if wxUSE_DRAG_AND_DROP
3791 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3793 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3795 GtkWidget
*dnd_widget
= GetConnectWidget();
3797 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3799 if (m_dropTarget
) delete m_dropTarget
;
3800 m_dropTarget
= dropTarget
;
3802 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3805 #endif // wxUSE_DRAG_AND_DROP
3807 GtkWidget
* wxWindowGTK::GetConnectWidget()
3809 GtkWidget
*connect_widget
= m_widget
;
3810 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3812 return connect_widget
;
3815 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3818 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3820 return (window
== m_widget
->window
);
3823 bool wxWindowGTK::SetFont( const wxFont
&font
)
3825 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3827 if (!wxWindowBase::SetFont(font
))
3832 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3833 if ( sysbg
== m_backgroundColour
)
3835 m_backgroundColour
= wxNullColour
;
3837 m_backgroundColour
= sysbg
;
3847 void wxWindowGTK::DoCaptureMouse()
3849 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3851 GdkWindow
*window
= (GdkWindow
*) NULL
;
3853 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3855 window
= GetConnectWidget()->window
;
3857 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3859 wxCursor
* cursor
= & m_cursor
;
3861 cursor
= wxSTANDARD_CURSOR
;
3863 gdk_pointer_grab( window
, FALSE
,
3865 (GDK_BUTTON_PRESS_MASK
|
3866 GDK_BUTTON_RELEASE_MASK
|
3867 GDK_POINTER_MOTION_HINT_MASK
|
3868 GDK_POINTER_MOTION_MASK
),
3870 cursor
->GetCursor(),
3871 (guint32
)GDK_CURRENT_TIME
);
3872 g_captureWindow
= this;
3873 g_captureWindowHasMouse
= TRUE
;
3876 void wxWindowGTK::DoReleaseMouse()
3878 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3880 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3882 g_captureWindow
= (wxWindowGTK
*) NULL
;
3884 GdkWindow
*window
= (GdkWindow
*) NULL
;
3886 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3888 window
= GetConnectWidget()->window
;
3893 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3897 wxWindow
*wxWindowBase::GetCapture()
3899 return (wxWindow
*)g_captureWindow
;
3902 bool wxWindowGTK::IsRetained() const
3907 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3908 int range
, bool refresh
)
3910 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3912 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3914 m_hasScrolling
= TRUE
;
3916 if (orient
== wxHORIZONTAL
)
3918 float fpos
= (float)pos
;
3919 float frange
= (float)range
;
3920 float fthumb
= (float)thumbVisible
;
3921 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3922 if (fpos
< 0.0) fpos
= 0.0;
3924 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3925 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3927 SetScrollPos( orient
, pos
, refresh
);
3931 m_oldHorizontalPos
= fpos
;
3933 m_hAdjust
->lower
= 0.0;
3934 m_hAdjust
->upper
= frange
;
3935 m_hAdjust
->value
= fpos
;
3936 m_hAdjust
->step_increment
= 1.0;
3937 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3938 m_hAdjust
->page_size
= fthumb
;
3942 float fpos
= (float)pos
;
3943 float frange
= (float)range
;
3944 float fthumb
= (float)thumbVisible
;
3945 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3946 if (fpos
< 0.0) fpos
= 0.0;
3948 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
3949 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3951 SetScrollPos( orient
, pos
, refresh
);
3955 m_oldVerticalPos
= fpos
;
3957 m_vAdjust
->lower
= 0.0;
3958 m_vAdjust
->upper
= frange
;
3959 m_vAdjust
->value
= fpos
;
3960 m_vAdjust
->step_increment
= 1.0;
3961 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3962 m_vAdjust
->page_size
= fthumb
;
3965 if (orient
== wxHORIZONTAL
)
3966 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3968 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3971 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3973 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3975 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3977 if (orient
== wxHORIZONTAL
)
3979 float fpos
= (float)pos
;
3980 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3981 if (fpos
< 0.0) fpos
= 0.0;
3982 m_oldHorizontalPos
= fpos
;
3984 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3985 m_hAdjust
->value
= fpos
;
3989 float fpos
= (float)pos
;
3990 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
3991 if (fpos
< 0.0) fpos
= 0.0;
3992 m_oldVerticalPos
= fpos
;
3994 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
3995 m_vAdjust
->value
= fpos
;
3998 if (m_wxwindow
->window
)
4000 if (orient
== wxHORIZONTAL
)
4002 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4003 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4005 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4007 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4008 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4012 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4013 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4015 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4017 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4018 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4023 int wxWindowGTK::GetScrollThumb( int orient
) const
4025 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4027 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4029 if (orient
== wxHORIZONTAL
)
4030 return (int)(m_hAdjust
->page_size
+0.5);
4032 return (int)(m_vAdjust
->page_size
+0.5);
4035 int wxWindowGTK::GetScrollPos( int orient
) const
4037 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4039 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4041 if (orient
== wxHORIZONTAL
)
4042 return (int)(m_hAdjust
->value
+0.5);
4044 return (int)(m_vAdjust
->value
+0.5);
4047 int wxWindowGTK::GetScrollRange( int orient
) const
4049 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4051 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4053 if (orient
== wxHORIZONTAL
)
4054 return (int)(m_hAdjust
->upper
+0.5);
4056 return (int)(m_vAdjust
->upper
+0.5);
4059 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4061 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4063 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4065 // No scrolling requested.
4066 if ((dx
== 0) && (dy
== 0)) return;
4069 if (!m_updateRegion
.IsEmpty())
4071 m_updateRegion
.Offset( dx
, dy
);
4075 GetClientSize( &cw
, &ch
);
4076 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4079 if (!m_clearRegion
.IsEmpty())
4081 m_clearRegion
.Offset( dx
, dy
);
4085 GetClientSize( &cw
, &ch
);
4086 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4089 m_clipPaintRegion
= TRUE
;
4091 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4093 m_clipPaintRegion
= FALSE
;
4096 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4098 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4099 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4106 // Find the wxWindow at the current mouse position, also returning the mouse
4108 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4110 pt
= wxGetMousePosition();
4111 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4115 // Get the current mouse position.
4116 wxPoint
wxGetMousePosition()
4118 /* This crashes when used within wxHelpContext,
4119 so we have to use the X-specific implementation below.
4121 GdkModifierType *mask;
4122 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4124 return wxPoint(x, y);
4128 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4130 return wxPoint(-999, -999);
4132 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4133 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4134 Window rootReturn
, childReturn
;
4135 int rootX
, rootY
, winX
, winY
;
4136 unsigned int maskReturn
;
4138 XQueryPointer (display
,
4142 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4143 return wxPoint(rootX
, rootY
);
4147 // ----------------------------------------------------------------------------
4149 // ----------------------------------------------------------------------------
4151 class wxWinModule
: public wxModule
4158 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4161 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4163 bool wxWinModule::OnInit()
4165 g_eraseGC
= gdk_gc_new( GDK_ROOT_PARENT() );
4166 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4171 void wxWinModule::OnExit()
4173 gdk_gc_unref( g_eraseGC
);