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"
29 #if wxUSE_DRAG_AND_DROP
34 #include "wx/tooltip.h"
42 #include "wx/textctrl.h"
46 #include "wx/statusbr.h"
48 #include "wx/settings.h"
52 #include "wx/thread.h"
57 #include "wx/gtk/private.h"
58 #include <gdk/gdkprivate.h>
59 #include <gdk/gdkkeysyms.h>
63 #include <gtk/gtkprivate.h>
65 #include "wx/gtk/win_gtk.h"
68 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
70 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
79 //-----------------------------------------------------------------------------
80 // documentation on internals
81 //-----------------------------------------------------------------------------
84 I have been asked several times about writing some documentation about
85 the GTK port of wxWindows, especially its internal structures. Obviously,
86 you cannot understand wxGTK without knowing a little about the GTK, but
87 some more information about what the wxWindow, which is the base class
88 for all other window classes, does seems required as well.
92 What does wxWindow do? It contains the common interface for the following
93 jobs of its descendants:
95 1) Define the rudimentary behaviour common to all window classes, such as
96 resizing, intercepting user input (so as to make it possible to use these
97 events for special purposes in a derived class), window names etc.
99 2) Provide the possibility to contain and manage children, if the derived
100 class is allowed to contain children, which holds true for those window
101 classes which do not display a native GTK widget. To name them, these
102 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
103 work classes are a special case and are handled a bit differently from
104 the rest. The same holds true for the wxNotebook class.
106 3) Provide the possibility to draw into a client area of a window. This,
107 too, only holds true for classes that do not display a native GTK widget
110 4) Provide the entire mechanism for scrolling widgets. This actual inter-
111 face for this is usually in wxScrolledWindow, but the GTK implementation
114 5) A multitude of helper or extra methods for special purposes, such as
115 Drag'n'Drop, managing validators etc.
117 6) Display a border (sunken, raised, simple or none).
119 Normally one might expect, that one wxWindows window would always correspond
120 to one GTK widget. Under GTK, there is no such allround widget that has all
121 the functionality. Moreover, the GTK defines a client area as a different
122 widget from the actual widget you are handling. Last but not least some
123 special classes (e.g. wxFrame) handle different categories of widgets and
124 still have the possibility to draw something in the client area.
125 It was therefore required to write a special purpose GTK widget, that would
126 represent a client area in the sense of wxWindows capable to do the jobs
127 2), 3) and 4). I have written this class and it resides in win_gtk.c of
130 All windows must have a widget, with which they interact with other under-
131 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
132 thw wxWindow class has a member variable called m_widget which holds a
133 pointer to this widget. When the window class represents a GTK native widget,
134 this is (in most cases) the only GTK widget the class manages. E.g. the
135 wxStatitText class handles only a GtkLabel widget a pointer to which you
136 can find in m_widget (defined in wxWindow)
138 When the class has a client area for drawing into and for containing children
139 it has to handle the client area widget (of the type GtkPizza, defined in
140 win_gtk.c), but there could be any number of widgets, handled by a class
141 The common rule for all windows is only, that the widget that interacts with
142 the rest of GTK must be referenced in m_widget and all other widgets must be
143 children of this widget on the GTK level. The top-most widget, which also
144 represents the client area, must be in the m_wxwindow field and must be of
147 As I said, the window classes that display a GTK native widget only have
148 one widget, so in the case of e.g. the wxButton class m_widget holds a
149 pointer to a GtkButton widget. But windows with client areas (for drawing
150 and children) have a m_widget field that is a pointer to a GtkScrolled-
151 Window and a m_wxwindow field that is pointer to a GtkPizza and this
152 one is (in the GTK sense) a child of the GtkScrolledWindow.
154 If the m_wxwindow field is set, then all input to this widget is inter-
155 cepted and sent to the wxWindows class. If not, all input to the widget
156 that gets pointed to by m_widget gets intercepted and sent to the class.
160 The design of scrolling in wxWindows is markedly different from that offered
161 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
162 clicking on a scrollbar belonging to scrolled window will inevitably move
163 the window. In wxWindows, the scrollbar will only emit an event, send this
164 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
165 which actually moves the window and its subchildren. Note that GtkPizza
166 memorizes how much it has been scrolled but that wxWindows forgets this
167 so that the two coordinates systems have to be kept in synch. This is done
168 in various places using the pizza->xoffset and pizza->yoffset values.
172 Singularily the most broken code in GTK is the code that is supposes to
173 inform subwindows (child windows) about new positions. Very often, duplicate
174 events are sent without changes in size or position, equally often no
175 events are sent at all (All this is due to a bug in the GtkContainer code
176 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
177 GTK's own system and it simply waits for size events for toplevel windows
178 and then iterates down the respective size events to all window. This has
179 the disadvantage, that windows might get size events before the GTK widget
180 actually has the reported size. This doesn't normally pose any problem, but
181 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
182 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
183 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
184 window that is used for OpenGl output really has that size (as reported by
189 If someone at some point of time feels the immense desire to have a look at,
190 change or attempt to optimse the Refresh() logic, this person will need an
191 intimate understanding of what a "draw" and what an "expose" events are and
192 what there are used for, in particular when used in connection with GTK's
193 own windowless widgets. Beware.
197 Cursors, too, have been a constant source of pleasure. The main difficulty
198 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
199 for the parent. To prevent this from doing too much harm, I use idle time
200 to set the cursor over and over again, starting from the toplevel windows
201 and ending with the youngest generation (speaking of parent and child windows).
202 Also don't forget that cursors (like much else) are connected to GdkWindows,
203 not GtkWidgets and that the "window" field of a GtkWidget might very well
204 point to the GdkWindow of the parent widget (-> "window less widget") and
205 that the two obviously have very different meanings.
209 //-----------------------------------------------------------------------------
211 //-----------------------------------------------------------------------------
213 extern wxList wxPendingDelete
;
214 extern bool g_blockEventsOnDrag
;
215 extern bool g_blockEventsOnScroll
;
216 extern wxCursor g_globalCursor
;
218 static GdkGC
*g_eraseGC
= NULL
;
220 // mouse capture state: the window which has it and if the mouse is currently
222 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
223 static bool g_captureWindowHasMouse
= FALSE
;
225 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
227 // the last window which had the focus - this is normally never NULL (except
228 // if we never had focus at all) as even when g_focusWindow is NULL it still
229 // keeps its previous value
230 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*)NULL
;
232 // the frame that is currently active (i.e. its child has focus). It is
233 // used to generate wxActivateEvents
234 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*)NULL
;
235 static bool g_activeFrameLostFocus
= FALSE
;
237 // if we detect that the app has got/lost the focus, we set this variable to
238 // either TRUE or FALSE and an activate event will be sent during the next
239 // OnIdle() call and it is reset to -1: this value means that we shouldn't
240 // send any activate events at all
241 static int g_sendActivateEvent
= -1;
243 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
244 the last click here */
245 static guint32 gs_timeLastClick
= 0;
247 extern bool g_mainThreadLocked
;
249 //-----------------------------------------------------------------------------
251 //-----------------------------------------------------------------------------
254 #define DISABLE_STYLE_IF_BROKEN_THEME 1
260 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
262 # define DEBUG_MAIN_THREAD
265 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
266 GdkEvent
*WXUNUSED(event
),
267 const wxChar
*WXUNUSED(name
) )
270 static bool s_done = FALSE;
273 wxLog::AddTraceMask("focus");
276 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
282 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
284 // suppress warnings about gtk_debug_focus_in_callback being unused with
289 tmp
+= wxT(" FROM ");
292 wxChar
*s
= new wxChar
[tmp
.Length()+1];
296 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
297 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
302 #define DEBUG_MAIN_THREAD
305 //-----------------------------------------------------------------------------
306 // missing gdk functions
307 //-----------------------------------------------------------------------------
310 gdk_window_warp_pointer (GdkWindow
*window
,
315 GdkWindowPrivate
*priv
;
319 window
= GDK_ROOT_PARENT();
322 if (!GDK_WINDOW_DESTROYED(window
))
324 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
325 None
, /* not source window -> move from anywhere */
326 GDK_WINDOW_XID(window
), /* dest window */
327 0, 0, 0, 0, /* not source window -> move from anywhere */
331 priv
= (GdkWindowPrivate
*) window
;
333 if (!priv
->destroyed
)
335 XWarpPointer (priv
->xdisplay
,
336 None
, /* not source window -> move from anywhere */
337 priv
->xwindow
, /* dest window */
338 0, 0, 0, 0, /* not source window -> move from anywhere */
344 //-----------------------------------------------------------------------------
346 //-----------------------------------------------------------------------------
348 extern void wxapp_install_idle_handler();
349 extern bool g_isIdle
;
351 //-----------------------------------------------------------------------------
352 // local code (see below)
353 //-----------------------------------------------------------------------------
355 // returns the child of win which currently has focus or NULL if not found
357 // Note: can't be static, needed by textctrl.cpp.
358 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
360 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
362 return (wxWindow
*)NULL
;
364 if ( winFocus
== win
)
365 return (wxWindow
*)win
;
367 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
369 node
= node
->GetNext() )
371 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
376 return (wxWindow
*)NULL
;
379 // Returns toplevel grandparent of given window:
380 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
382 wxWindowGTK
*p
= win
;
383 while (p
&& !p
->IsTopLevel())
389 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
391 // wxUniversal widgets draw the borders and scrollbars themselves
392 #ifndef __WXUNIVERSAL__
399 if (win
->m_hasScrolling
)
401 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
403 GtkRequisition vscroll_req
;
404 vscroll_req
.width
= 2;
405 vscroll_req
.height
= 2;
406 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
407 (scroll_window
->vscrollbar
, &vscroll_req
);
409 GtkRequisition hscroll_req
;
410 hscroll_req
.width
= 2;
411 hscroll_req
.height
= 2;
412 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
413 (scroll_window
->hscrollbar
, &hscroll_req
);
415 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
417 if (scroll_window
->vscrollbar_visible
)
419 dw
+= vscroll_req
.width
;
420 dw
+= scroll_class
->scrollbar_spacing
;
423 if (scroll_window
->hscrollbar_visible
)
425 dh
+= hscroll_req
.height
;
426 dh
+= scroll_class
->scrollbar_spacing
;
432 if (GTK_WIDGET_NO_WINDOW (widget
))
434 dx
+= widget
->allocation
.x
;
435 dy
+= widget
->allocation
.y
;
438 if (win
->HasFlag(wxRAISED_BORDER
))
440 gtk_draw_shadow( widget
->style
,
445 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
449 if (win
->HasFlag(wxSUNKEN_BORDER
))
451 gtk_draw_shadow( widget
->style
,
456 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
460 if (win
->HasFlag(wxSIMPLE_BORDER
))
463 gc
= gdk_gc_new( widget
->window
);
464 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
465 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
467 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
471 #endif // __WXUNIVERSAL__
474 //-----------------------------------------------------------------------------
475 // "expose_event" of m_widget
476 //-----------------------------------------------------------------------------
478 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
480 if (gdk_event
->count
> 0) return FALSE
;
482 draw_frame( widget
, win
);
487 //-----------------------------------------------------------------------------
488 // "draw" of m_widget
489 //-----------------------------------------------------------------------------
491 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
493 draw_frame( widget
, win
);
496 //-----------------------------------------------------------------------------
497 // key code mapping routines
498 //-----------------------------------------------------------------------------
500 static long map_to_unmodified_wx_keysym( GdkEventKey
*event
)
502 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
503 // but only event->keyval which is quite useless to us, so remember
504 // the last character from GDK_KEY_PRESS and resue it as last resort
506 // NB: should be MT-neutral as always called from main thread only
511 } s_lastKeyPress
= { 0, 0 };
513 KeySym keysym
= event
->keyval
;
519 case GDK_Shift_R
: key_code
= WXK_SHIFT
; break;
521 case GDK_Control_R
: key_code
= WXK_CONTROL
; break;
527 case GDK_Super_R
: key_code
= WXK_ALT
; break;
528 case GDK_Menu
: key_code
= WXK_MENU
; break;
529 case GDK_Help
: key_code
= WXK_HELP
; break;
530 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
531 case GDK_ISO_Left_Tab
:
532 case GDK_Tab
: key_code
= WXK_TAB
; break;
533 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
534 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
535 case GDK_Return
: key_code
= WXK_RETURN
; break;
536 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
537 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
538 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
539 case GDK_Delete
: key_code
= WXK_DELETE
; break;
540 case GDK_Home
: key_code
= WXK_HOME
; break;
541 case GDK_Left
: key_code
= WXK_LEFT
; break;
542 case GDK_Up
: key_code
= WXK_UP
; break;
543 case GDK_Right
: key_code
= WXK_RIGHT
; break;
544 case GDK_Down
: key_code
= WXK_DOWN
; break;
545 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
546 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
547 case GDK_Next
: key_code
= WXK_NEXT
; break;
548 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
549 case GDK_End
: key_code
= WXK_END
; break;
550 case GDK_Begin
: key_code
= WXK_HOME
; break;
551 case GDK_Select
: key_code
= WXK_SELECT
; break;
552 case GDK_Print
: key_code
= WXK_PRINT
; break;
553 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
554 case GDK_Insert
: key_code
= WXK_INSERT
; break;
555 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
557 case GDK_KP_0
: key_code
= WXK_NUMPAD0
; break;
558 case GDK_KP_1
: key_code
= WXK_NUMPAD1
; break;
559 case GDK_KP_2
: key_code
= WXK_NUMPAD2
; break;
560 case GDK_KP_3
: key_code
= WXK_NUMPAD3
; break;
561 case GDK_KP_4
: key_code
= WXK_NUMPAD4
; break;
562 case GDK_KP_5
: key_code
= WXK_NUMPAD5
; break;
563 case GDK_KP_6
: key_code
= WXK_NUMPAD6
; break;
564 case GDK_KP_7
: key_code
= WXK_NUMPAD7
; break;
565 case GDK_KP_8
: key_code
= WXK_NUMPAD8
; break;
566 case GDK_KP_9
: key_code
= WXK_NUMPAD9
; break;
567 case GDK_KP_Space
: key_code
= WXK_NUMPAD_SPACE
; break;
568 case GDK_KP_Tab
: key_code
= WXK_NUMPAD_TAB
; break;
569 case GDK_KP_Enter
: key_code
= WXK_NUMPAD_ENTER
; break;
570 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
571 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
572 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
573 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
574 case GDK_KP_Home
: key_code
= WXK_NUMPAD_HOME
; break;
575 case GDK_KP_Left
: key_code
= WXK_NUMPAD_LEFT
; break;
576 case GDK_KP_Up
: key_code
= WXK_NUMPAD_UP
; break;
577 case GDK_KP_Right
: key_code
= WXK_NUMPAD_RIGHT
; break;
578 case GDK_KP_Down
: key_code
= WXK_NUMPAD_DOWN
; break;
579 case GDK_KP_Prior
: key_code
= WXK_NUMPAD_PRIOR
; break;
580 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
581 case GDK_KP_Next
: key_code
= WXK_NUMPAD_NEXT
; break;
582 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
583 case GDK_KP_End
: key_code
= WXK_NUMPAD_END
; break;
584 case GDK_KP_Begin
: key_code
= WXK_NUMPAD_BEGIN
; break;
585 case GDK_KP_Insert
: key_code
= WXK_NUMPAD_INSERT
; break;
586 case GDK_KP_Delete
: key_code
= WXK_NUMPAD_DELETE
; break;
587 case GDK_KP_Equal
: key_code
= WXK_NUMPAD_EQUAL
; break;
588 case GDK_KP_Multiply
: key_code
= WXK_NUMPAD_MULTIPLY
; break;
589 case GDK_KP_Add
: key_code
= WXK_NUMPAD_ADD
; break;
590 case GDK_KP_Separator
: key_code
= WXK_NUMPAD_SEPARATOR
; break;
591 case GDK_KP_Subtract
: key_code
= WXK_NUMPAD_SUBTRACT
; break;
592 case GDK_KP_Decimal
: key_code
= WXK_NUMPAD_DECIMAL
; break;
593 case GDK_KP_Divide
: key_code
= WXK_NUMPAD_DIVIDE
; break;
595 case GDK_F1
: key_code
= WXK_F1
; break;
596 case GDK_F2
: key_code
= WXK_F2
; break;
597 case GDK_F3
: key_code
= WXK_F3
; break;
598 case GDK_F4
: key_code
= WXK_F4
; break;
599 case GDK_F5
: key_code
= WXK_F5
; break;
600 case GDK_F6
: key_code
= WXK_F6
; break;
601 case GDK_F7
: key_code
= WXK_F7
; break;
602 case GDK_F8
: key_code
= WXK_F8
; break;
603 case GDK_F9
: key_code
= WXK_F9
; break;
604 case GDK_F10
: key_code
= WXK_F10
; break;
605 case GDK_F11
: key_code
= WXK_F11
; break;
606 case GDK_F12
: key_code
= WXK_F12
; break;
609 // do we have the translation?
610 if ( event
->length
== 1 )
612 keysym
= (KeySym
)event
->string
[0];
614 else if ( (keysym
& 0xFF) != keysym
)
616 // non ASCII key, what to do?
618 if ( event
->type
== GDK_KEY_RELEASE
)
620 // reuse the one from the last keypress if any
621 if ( keysym
== s_lastKeyPress
.keysym
)
623 key_code
= s_lastKeyPress
.keycode
;
630 // ignore this one, we don't know it
633 //else: ASCII key, ok
635 guint upper
= gdk_keyval_to_upper( (guint
)keysym
);
636 key_code
= upper
? upper
: keysym
;
638 if ( event
->type
== GDK_KEY_PRESS
)
640 // remember it to be reused below later
641 s_lastKeyPress
.keysym
= keysym
;
642 s_lastKeyPress
.keycode
= key_code
;
650 static long map_to_wx_keysym( GdkEventKey
*event
)
652 KeySym keysym
= event
->keyval
;
657 case GDK_Menu
: key_code
= WXK_MENU
; break;
658 case GDK_Help
: key_code
= WXK_HELP
; break;
659 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
660 case GDK_ISO_Left_Tab
:
661 case GDK_Tab
: key_code
= WXK_TAB
; break;
662 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
663 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
664 case GDK_Return
: key_code
= WXK_RETURN
; break;
665 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
666 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
667 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
668 case GDK_Delete
: key_code
= WXK_DELETE
; break;
669 case GDK_Home
: key_code
= WXK_HOME
; break;
670 case GDK_Left
: key_code
= WXK_LEFT
; break;
671 case GDK_Up
: key_code
= WXK_UP
; break;
672 case GDK_Right
: key_code
= WXK_RIGHT
; break;
673 case GDK_Down
: key_code
= WXK_DOWN
; break;
674 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
675 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
676 case GDK_Next
: key_code
= WXK_NEXT
; break;
677 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
678 case GDK_End
: key_code
= WXK_END
; break;
679 case GDK_Begin
: key_code
= WXK_HOME
; break;
680 case GDK_Select
: key_code
= WXK_SELECT
; break;
681 case GDK_Print
: key_code
= WXK_PRINT
; break;
682 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
683 case GDK_Insert
: key_code
= WXK_INSERT
; break;
684 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
686 case GDK_KP_0
: key_code
= '0'; break;
687 case GDK_KP_1
: key_code
= '1'; break;
688 case GDK_KP_2
: key_code
= '2'; break;
689 case GDK_KP_3
: key_code
= '3'; break;
690 case GDK_KP_4
: key_code
= '4'; break;
691 case GDK_KP_5
: key_code
= '5'; break;
692 case GDK_KP_6
: key_code
= '6'; break;
693 case GDK_KP_7
: key_code
= '7'; break;
694 case GDK_KP_8
: key_code
= '8'; break;
695 case GDK_KP_9
: key_code
= '9'; break;
696 case GDK_KP_Space
: key_code
= ' '; break;
697 case GDK_KP_Tab
: key_code
= WXK_TAB
; break; /* or '\t' ??? */
698 case GDK_KP_Enter
: key_code
= WXK_RETURN
; break; /* or '\r' ??? */
699 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
700 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
701 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
702 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
703 case GDK_KP_Home
: key_code
= WXK_HOME
; break;
704 case GDK_KP_Left
: key_code
= WXK_LEFT
; break;
705 case GDK_KP_Up
: key_code
= WXK_UP
; break;
706 case GDK_KP_Right
: key_code
= WXK_RIGHT
; break;
707 case GDK_KP_Down
: key_code
= WXK_DOWN
; break;
708 case GDK_KP_Prior
: key_code
= WXK_PRIOR
; break;
709 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
710 case GDK_KP_Next
: key_code
= WXK_NEXT
; break;
711 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
712 case GDK_KP_End
: key_code
= WXK_END
; break;
713 case GDK_KP_Begin
: key_code
= WXK_HOME
; break;
714 case GDK_KP_Insert
: key_code
= WXK_INSERT
; break;
715 case GDK_KP_Delete
: key_code
= WXK_DELETE
; break;
716 case GDK_KP_Equal
: key_code
= '='; break;
717 case GDK_KP_Multiply
: key_code
= '*'; break;
718 case GDK_KP_Add
: key_code
= '+'; break;
719 case GDK_KP_Separator
: key_code
= ','; break;
720 case GDK_KP_Subtract
: key_code
= '-'; break;
721 case GDK_KP_Decimal
: key_code
= '.'; break;
722 case GDK_KP_Divide
: key_code
= '/'; break;
724 case GDK_F1
: key_code
= WXK_F1
; break;
725 case GDK_F2
: key_code
= WXK_F2
; break;
726 case GDK_F3
: key_code
= WXK_F3
; break;
727 case GDK_F4
: key_code
= WXK_F4
; break;
728 case GDK_F5
: key_code
= WXK_F5
; break;
729 case GDK_F6
: key_code
= WXK_F6
; break;
730 case GDK_F7
: key_code
= WXK_F7
; break;
731 case GDK_F8
: key_code
= WXK_F8
; break;
732 case GDK_F9
: key_code
= WXK_F9
; break;
733 case GDK_F10
: key_code
= WXK_F10
; break;
734 case GDK_F11
: key_code
= WXK_F11
; break;
735 case GDK_F12
: key_code
= WXK_F12
; break;
737 if (event
->length
== 1)
739 key_code
= (unsigned char)*event
->string
;
741 else if ((keysym
& 0xFF) == keysym
)
743 key_code
= (guint
)keysym
;
750 //-----------------------------------------------------------------------------
751 // "size_request" of m_widget
752 //-----------------------------------------------------------------------------
754 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
757 win
->GetSize( &w
, &h
);
761 requisition
->height
= h
;
762 requisition
->width
= w
;
765 //-----------------------------------------------------------------------------
766 // "expose_event" of m_wxwindow
767 //-----------------------------------------------------------------------------
769 static int gtk_window_expose_callback( GtkWidget
*widget
,
770 GdkEventExpose
*gdk_event
,
776 wxapp_install_idle_handler();
779 if (win->GetName() == wxT("panel"))
781 wxPrintf( wxT("OnExpose from ") );
782 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
783 wxPrintf( win->GetClassInfo()->GetClassName() );
784 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
785 (int)gdk_event->area.y,
786 (int)gdk_event->area.width,
787 (int)gdk_event->area.height );
791 #ifndef __WXUNIVERSAL__
792 GtkPizza
*pizza
= GTK_PIZZA (widget
);
794 if (win
->GetThemeEnabled())
796 wxWindow
*parent
= win
->GetParent();
797 while (parent
&& !parent
->IsTopLevel())
798 parent
= parent
->GetParent();
802 gtk_paint_flat_box (parent
->m_widget
->style
,
813 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
815 gdk_event
->area
.width
,
816 gdk_event
->area
.height
);
818 // Actual redrawing takes place in idle time.
824 //-----------------------------------------------------------------------------
825 // "event" of m_wxwindow
826 //-----------------------------------------------------------------------------
828 // GTK thinks it is clever and filters out a certain amount of "unneeded"
829 // expose events. We need them, of course, so we override the main event
830 // procedure in GtkWidget by giving our own handler for all system events.
831 // There, we look for expose events ourselves whereas all other events are
834 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
835 GdkEventExpose
*event
,
838 if (event
->type
== GDK_EXPOSE
)
840 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
847 //-----------------------------------------------------------------------------
848 // "draw" of m_wxwindow
849 //-----------------------------------------------------------------------------
851 // This callback is a complete replacement of the gtk_pizza_draw() function,
854 static void gtk_window_draw_callback( GtkWidget
*widget
,
861 wxapp_install_idle_handler();
863 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
864 // there are no child windows.
865 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
866 (win
->GetChildren().GetCount() == 0))
872 if (win->GetName() == wxT("panel"))
874 wxPrintf( wxT("OnDraw from ") );
875 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
876 wxPrintf( win->GetClassInfo()->GetClassName() );
877 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
884 #ifndef __WXUNIVERSAL__
885 GtkPizza
*pizza
= GTK_PIZZA (widget
);
887 if (win
->GetThemeEnabled())
889 wxWindow
*parent
= win
->GetParent();
890 while (parent
&& !parent
->IsTopLevel())
891 parent
= parent
->GetParent();
895 gtk_paint_flat_box (parent
->m_widget
->style
,
906 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
907 (pizza
->clear_on_draw
))
909 gdk_window_clear_area( pizza
->bin_window
,
910 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
914 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
916 // Actual redrawing takes place in idle time.
920 #ifndef __WXUNIVERSAL__
921 // Redraw child widgets
922 GList
*children
= pizza
->children
;
925 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
926 children
= children
->next
;
928 GdkRectangle child_area
;
929 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
931 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
937 //-----------------------------------------------------------------------------
938 // "key_press_event" from any window
939 //-----------------------------------------------------------------------------
941 // turn on to see the key event codes on the console
942 #undef DEBUG_KEY_EVENTS
944 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
945 GdkEventKey
*gdk_event
,
951 wxapp_install_idle_handler();
953 if (!win
->m_hasVMT
) return FALSE
;
954 if (g_blockEventsOnDrag
) return FALSE
;
959 GdkModifierType state
;
960 if (gdk_event
->window
)
961 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
965 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
967 #ifdef DEBUG_KEY_EVENTS
968 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
969 #endif // DEBUG_KEY_EVENTS
971 /* sending unknown key events doesn't really make sense */
975 wxKeyEvent
event( wxEVT_KEY_DOWN
);
976 event
.SetTimestamp( gdk_event
->time
);
977 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
978 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
979 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
980 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
981 event
.m_keyCode
= key_code
;
982 event
.m_scanCode
= gdk_event
->keyval
;
985 event
.SetEventObject( win
);
986 ret
= win
->GetEventHandler()->ProcessEvent( event
);
991 wxWindowGTK
*ancestor
= win
;
994 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
997 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
998 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1001 if (ancestor
->IsTopLevel())
1003 ancestor
= ancestor
->GetParent();
1006 #endif // wxUSE_ACCEL
1008 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1009 will only be sent if it is not in an accelerator table. */
1012 key_code
= map_to_wx_keysym( gdk_event
);
1016 #ifdef DEBUG_KEY_EVENTS
1017 wxPrintf(_T("Char event: %ld\n"), key_code
);
1018 #endif // DEBUG_KEY_EVENTS
1020 // reuse the ame event object, just change its type and use the
1021 // translated keycode instead of the raw one
1022 event
.SetEventType(wxEVT_CHAR
);
1023 event
.m_keyCode
= key_code
;
1025 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1029 /* win is a control: tab can be propagated up */
1031 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1032 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1033 // have this style, yet choose not to process this particular TAB in which
1034 // case TAB must still work as a navigational character
1036 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1038 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1040 wxNavigationKeyEvent new_event
;
1041 new_event
.SetEventObject( win
->GetParent() );
1042 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1043 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1044 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1045 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1046 new_event
.SetCurrentFocus( win
);
1047 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1050 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1052 (gdk_event
->keyval
== GDK_Escape
) )
1054 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1055 new_event
.SetEventObject( win
);
1056 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1060 #if 0 // (GTK_MINOR_VERSION > 0)
1061 /* Pressing F10 will activate the menu bar of the top frame. */
1063 (gdk_event
->keyval
== GDK_F10
) )
1065 wxWindowGTK
*ancestor
= win
;
1068 if (wxIsKindOf(ancestor
,wxFrame
))
1070 wxFrame
*frame
= (wxFrame
*) ancestor
;
1071 wxMenuBar
*menubar
= frame
->GetMenuBar();
1074 wxNode
*node
= menubar
->GetMenus().First();
1077 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1078 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1084 ancestor
= ancestor
->GetParent();
1091 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1098 //-----------------------------------------------------------------------------
1099 // "key_release_event" from any window
1100 //-----------------------------------------------------------------------------
1102 static gint
gtk_window_key_release_callback( GtkWidget
*widget
, GdkEventKey
*gdk_event
, wxWindowGTK
*win
)
1107 wxapp_install_idle_handler();
1109 if (!win
->m_hasVMT
) return FALSE
;
1110 if (g_blockEventsOnDrag
) return FALSE
;
1112 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
1114 #ifdef DEBUG_KEY_EVENTS
1115 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
1116 #endif // DEBUG_KEY_EVENTS
1118 /* sending unknown key events doesn't really make sense */
1119 if (key_code
== 0) return FALSE
;
1123 GdkModifierType state
;
1124 if (gdk_event
->window
)
1125 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1127 wxKeyEvent
event( wxEVT_KEY_UP
);
1128 event
.SetTimestamp( gdk_event
->time
);
1129 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1130 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1131 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1132 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1133 event
.m_keyCode
= key_code
;
1134 event
.m_scanCode
= gdk_event
->keyval
;
1137 event
.SetEventObject( win
);
1139 if (win
->GetEventHandler()->ProcessEvent( event
))
1141 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1148 // ============================================================================
1150 // ============================================================================
1152 // init wxMouseEvent with the info from gdk_event
1153 #define InitMouseEvent(win, event, gdk_event) \
1155 event.SetTimestamp( gdk_event->time ); \
1156 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1157 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1158 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1159 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1160 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1161 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1162 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1164 wxPoint pt = win->GetClientAreaOrigin(); \
1165 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1166 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1169 // ----------------------------------------------------------------------------
1170 // mouse event processing helper
1171 // ----------------------------------------------------------------------------
1173 static void AdjustEventButtonState(wxMouseEvent
& event
)
1175 // GDK reports the old state of the button for a button press event, but
1176 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1177 // for a LEFT_DOWN event, not FALSE, so we will invert
1178 // left/right/middleDown for the corresponding click events
1180 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1181 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1182 (event
.GetEventType() == wxEVT_LEFT_UP
))
1184 event
.m_leftDown
= !event
.m_leftDown
;
1188 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1189 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1190 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1192 event
.m_middleDown
= !event
.m_middleDown
;
1196 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1197 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1198 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1200 event
.m_rightDown
= !event
.m_rightDown
;
1205 //-----------------------------------------------------------------------------
1206 // "button_press_event"
1207 //-----------------------------------------------------------------------------
1209 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1214 wxapp_install_idle_handler();
1217 wxPrintf( wxT("1) OnButtonPress from ") );
1218 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1219 wxPrintf( win->GetClassInfo()->GetClassName() );
1220 wxPrintf( wxT(".\n") );
1222 if (!win
->m_hasVMT
) return FALSE
;
1223 if (g_blockEventsOnDrag
) return TRUE
;
1224 if (g_blockEventsOnScroll
) return TRUE
;
1226 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1228 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1230 gtk_widget_grab_focus( win
->m_wxwindow
);
1232 wxPrintf( wxT("GrabFocus from ") );
1233 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1234 wxPrintf( win->GetClassInfo()->GetClassName() );
1235 wxPrintf( wxT(".\n") );
1239 wxEventType event_type
= wxEVT_NULL
;
1241 if (gdk_event
->button
== 1)
1243 switch (gdk_event
->type
)
1245 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1246 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1250 else if (gdk_event
->button
== 2)
1252 switch (gdk_event
->type
)
1254 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1255 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1259 else if (gdk_event
->button
== 3)
1261 switch (gdk_event
->type
)
1263 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1264 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1269 if ( event_type
== wxEVT_NULL
)
1271 // unknown mouse button or click type
1275 wxMouseEvent
event( event_type
);
1276 InitMouseEvent( win
, event
, gdk_event
);
1278 AdjustEventButtonState(event
);
1280 // wxListBox actually get mouse events from the item
1282 if (win
->m_isListBox
)
1284 event
.m_x
+= widget
->allocation
.x
;
1285 event
.m_y
+= widget
->allocation
.y
;
1288 // Some control don't have their own X window and thus cannot get
1291 if (!g_captureWindow
)
1293 wxCoord x
= event
.m_x
;
1294 wxCoord y
= event
.m_y
;
1295 if (win
->m_wxwindow
)
1297 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1298 x
+= pizza
->xoffset
;
1299 y
+= pizza
->yoffset
;
1302 wxNode
*node
= win
->GetChildren().First();
1305 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1307 node
= node
->Next();
1308 if (!child
->IsShown())
1311 if (child
->m_isStaticBox
)
1313 // wxStaticBox is transparent in the box itself
1314 int xx1
= child
->m_x
;
1315 int yy1
= child
->m_y
;
1316 int xx2
= child
->m_x
+ child
->m_width
;
1317 int yy2
= child
->m_x
+ child
->m_height
;
1320 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1322 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1324 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1326 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1329 event
.m_x
-= child
->m_x
;
1330 event
.m_y
-= child
->m_y
;
1337 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1338 (child
->m_x
<= x
) &&
1339 (child
->m_y
<= y
) &&
1340 (child
->m_x
+child
->m_width
>= x
) &&
1341 (child
->m_y
+child
->m_height
>= y
))
1344 event
.m_x
-= child
->m_x
;
1345 event
.m_y
-= child
->m_y
;
1352 event
.SetEventObject( win
);
1354 gs_timeLastClick
= gdk_event
->time
;
1357 wxPrintf( wxT("2) OnButtonPress from ") );
1358 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1359 wxPrintf( win->GetClassInfo()->GetClassName() );
1360 wxPrintf( wxT(".\n") );
1363 if (win
->GetEventHandler()->ProcessEvent( event
))
1365 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1372 //-----------------------------------------------------------------------------
1373 // "button_release_event"
1374 //-----------------------------------------------------------------------------
1376 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1381 wxapp_install_idle_handler();
1383 if (!win
->m_hasVMT
) return FALSE
;
1384 if (g_blockEventsOnDrag
) return FALSE
;
1385 if (g_blockEventsOnScroll
) return FALSE
;
1387 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1390 printf( "OnButtonRelease from " );
1391 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1392 printf( win->GetClassInfo()->GetClassName() );
1396 wxEventType event_type
= wxEVT_NULL
;
1398 switch (gdk_event
->button
)
1400 case 1: event_type
= wxEVT_LEFT_UP
; break;
1401 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1402 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1403 default: return FALSE
;
1406 wxMouseEvent
event( event_type
);
1407 InitMouseEvent( win
, event
, gdk_event
);
1409 AdjustEventButtonState(event
);
1411 // wxListBox actually get mouse events from the item
1413 if (win
->m_isListBox
)
1415 event
.m_x
+= widget
->allocation
.x
;
1416 event
.m_y
+= widget
->allocation
.y
;
1419 // Some control don't have their own X window and thus cannot get
1422 if (!g_captureWindow
)
1424 wxCoord x
= event
.m_x
;
1425 wxCoord y
= event
.m_y
;
1426 if (win
->m_wxwindow
)
1428 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1429 x
+= pizza
->xoffset
;
1430 y
+= pizza
->yoffset
;
1433 wxNode
*node
= win
->GetChildren().First();
1436 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1438 node
= node
->Next();
1439 if (!child
->IsShown())
1442 if (child
->m_isStaticBox
)
1444 // wxStaticBox is transparent in the box itself
1445 int xx1
= child
->m_x
;
1446 int yy1
= child
->m_y
;
1447 int xx2
= child
->m_x
+ child
->m_width
;
1448 int yy2
= child
->m_x
+ child
->m_height
;
1451 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1453 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1455 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1457 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1460 event
.m_x
-= child
->m_x
;
1461 event
.m_y
-= child
->m_y
;
1468 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1469 (child
->m_x
<= x
) &&
1470 (child
->m_y
<= y
) &&
1471 (child
->m_x
+child
->m_width
>= x
) &&
1472 (child
->m_y
+child
->m_height
>= y
))
1475 event
.m_x
-= child
->m_x
;
1476 event
.m_y
-= child
->m_y
;
1483 event
.SetEventObject( win
);
1485 if (win
->GetEventHandler()->ProcessEvent( event
))
1487 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1494 //-----------------------------------------------------------------------------
1495 // "motion_notify_event"
1496 //-----------------------------------------------------------------------------
1498 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1499 GdkEventMotion
*gdk_event
,
1505 wxapp_install_idle_handler();
1507 if (!win
->m_hasVMT
) return FALSE
;
1508 if (g_blockEventsOnDrag
) return FALSE
;
1509 if (g_blockEventsOnScroll
) return FALSE
;
1511 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1513 if (gdk_event
->is_hint
)
1517 GdkModifierType state
;
1518 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1524 printf( "OnMotion from " );
1525 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1526 printf( win->GetClassInfo()->GetClassName() );
1530 wxMouseEvent
event( wxEVT_MOTION
);
1531 InitMouseEvent(win
, event
, gdk_event
);
1533 if ( g_captureWindow
)
1535 // synthetize a mouse enter or leave event if needed
1536 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1537 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1538 if ( hasMouse
!= g_captureWindowHasMouse
)
1540 // the mouse changed window
1541 g_captureWindowHasMouse
= hasMouse
;
1543 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1544 : wxEVT_LEAVE_WINDOW
);
1545 InitMouseEvent(win
, event
, gdk_event
);
1546 event
.SetEventObject(win
);
1547 win
->GetEventHandler()->ProcessEvent(event
);
1552 // Some control don't have their own X window and thus cannot get
1555 wxCoord x
= event
.m_x
;
1556 wxCoord y
= event
.m_y
;
1557 if (win
->m_wxwindow
)
1559 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1560 x
+= pizza
->xoffset
;
1561 y
+= pizza
->yoffset
;
1564 wxNode
*node
= win
->GetChildren().First();
1567 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1569 node
= node
->Next();
1570 if (!child
->IsShown())
1573 if (child
->m_isStaticBox
)
1575 // wxStaticBox is transparent in the box itself
1576 int xx1
= child
->m_x
;
1577 int yy1
= child
->m_y
;
1578 int xx2
= child
->m_x
+ child
->m_width
;
1579 int yy2
= child
->m_x
+ child
->m_height
;
1582 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1584 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1586 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1588 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1591 event
.m_x
-= child
->m_x
;
1592 event
.m_y
-= child
->m_y
;
1599 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1600 (child
->m_x
<= x
) &&
1601 (child
->m_y
<= y
) &&
1602 (child
->m_x
+child
->m_width
>= x
) &&
1603 (child
->m_y
+child
->m_height
>= y
))
1606 event
.m_x
-= child
->m_x
;
1607 event
.m_y
-= child
->m_y
;
1614 event
.SetEventObject( win
);
1616 if (win
->GetEventHandler()->ProcessEvent( event
))
1618 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1625 //-----------------------------------------------------------------------------
1627 //-----------------------------------------------------------------------------
1629 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1630 GdkEvent
*WXUNUSED(event
),
1636 wxapp_install_idle_handler();
1638 if (!win
->m_hasVMT
) return FALSE
;
1639 if (g_blockEventsOnDrag
) return FALSE
;
1641 switch ( g_sendActivateEvent
)
1644 // we've got focus from outside, synthetize wxActivateEvent
1645 g_sendActivateEvent
= 1;
1649 // another our window just lost focus, it was already ours before
1650 // - don't send any wxActivateEvent
1651 g_sendActivateEvent
= -1;
1656 g_focusWindow
= win
;
1659 wxLogDebug( wxT("OnSetFocus from %s\n"), win
->GetName().c_str() );
1662 // notify the parent keeping track of focus for the kbd navigation
1663 // purposes that we got it
1664 wxChildFocusEvent
eventFocus(win
);
1665 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1669 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1673 // caret needs to be informed about focus change
1674 wxCaret
*caret
= win
->GetCaret();
1677 caret
->OnSetFocus();
1679 #endif // wxUSE_CARET
1681 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1682 if ( active
!= g_activeFrame
)
1684 if ( g_activeFrame
)
1686 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1687 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1688 event
.SetEventObject(g_activeFrame
);
1689 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1692 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1693 g_activeFrame
= active
;
1694 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1695 event
.SetEventObject(g_activeFrame
);
1696 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1698 g_activeFrameLostFocus
= FALSE
;
1701 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1702 event
.SetEventObject( win
);
1704 if (win
->GetEventHandler()->ProcessEvent( event
))
1706 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1714 //-----------------------------------------------------------------------------
1715 // "focus_out_event"
1716 //-----------------------------------------------------------------------------
1718 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1723 wxapp_install_idle_handler();
1725 if (!win
->m_hasVMT
) return FALSE
;
1726 if (g_blockEventsOnDrag
) return FALSE
;
1729 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1732 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1734 // VZ: commenting this out because it does happen (although not easy
1735 // to reproduce, I only see it when using wxMiniFrame and not
1736 // always) and makes using Mahogany quite annoying
1738 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1739 wxT("unfocusing window that hasn't gained focus properly") )
1742 g_activeFrameLostFocus
= TRUE
;
1745 // if the focus goes out of our app alltogether, OnIdle() will send
1746 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1747 // g_sendActivateEvent to -1
1748 g_sendActivateEvent
= 0;
1750 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1754 g_focusWindow
= (wxWindowGTK
*)NULL
;
1762 // caret needs to be informed about focus change
1763 wxCaret
*caret
= win
->GetCaret();
1766 caret
->OnKillFocus();
1768 #endif // wxUSE_CARET
1770 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1771 event
.SetEventObject( win
);
1773 if (win
->GetEventHandler()->ProcessEvent( event
))
1775 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1782 //-----------------------------------------------------------------------------
1783 // "enter_notify_event"
1784 //-----------------------------------------------------------------------------
1786 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1791 wxapp_install_idle_handler();
1793 if (!win
->m_hasVMT
) return FALSE
;
1794 if (g_blockEventsOnDrag
) return FALSE
;
1796 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1798 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1799 event
.SetTimestamp( gdk_event
->time
);
1800 event
.SetEventObject( win
);
1804 GdkModifierType state
= (GdkModifierType
)0;
1806 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1808 InitMouseEvent(win
, event
, gdk_event
);
1809 wxPoint pt
= win
->GetClientAreaOrigin();
1810 event
.m_x
= x
+ pt
.x
;
1811 event
.m_y
= y
+ pt
.y
;
1813 if (win
->GetEventHandler()->ProcessEvent( event
))
1815 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1822 //-----------------------------------------------------------------------------
1823 // "leave_notify_event"
1824 //-----------------------------------------------------------------------------
1826 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1831 wxapp_install_idle_handler();
1833 if (!win
->m_hasVMT
) return FALSE
;
1834 if (g_blockEventsOnDrag
) return FALSE
;
1836 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1838 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1839 event
.SetTimestamp( gdk_event
->time
);
1840 event
.SetEventObject( win
);
1844 GdkModifierType state
= (GdkModifierType
)0;
1846 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1848 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
);
1849 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
);
1850 event
.m_altDown
= (state
& GDK_MOD1_MASK
);
1851 event
.m_metaDown
= (state
& GDK_MOD2_MASK
);
1852 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
);
1853 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
);
1854 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
);
1856 wxPoint pt
= win
->GetClientAreaOrigin();
1857 event
.m_x
= x
+ pt
.x
;
1858 event
.m_y
= y
+ pt
.y
;
1860 if (win
->GetEventHandler()->ProcessEvent( event
))
1862 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1869 //-----------------------------------------------------------------------------
1870 // "value_changed" from m_vAdjust
1871 //-----------------------------------------------------------------------------
1873 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1880 wxapp_install_idle_handler();
1882 if (g_blockEventsOnDrag
) return;
1884 if (!win
->m_hasVMT
) return;
1886 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1887 if (fabs(diff
) < 0.2) return;
1889 win
->m_oldVerticalPos
= adjust
->value
;
1891 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1893 int value
= (int)(adjust
->value
+0.5);
1895 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1896 event
.SetEventObject( win
);
1897 win
->GetEventHandler()->ProcessEvent( event
);
1900 //-----------------------------------------------------------------------------
1901 // "value_changed" from m_hAdjust
1902 //-----------------------------------------------------------------------------
1904 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1911 wxapp_install_idle_handler();
1913 if (g_blockEventsOnDrag
) return;
1914 if (!win
->m_hasVMT
) return;
1916 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1917 if (fabs(diff
) < 0.2) return;
1919 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1921 win
->m_oldHorizontalPos
= adjust
->value
;
1923 int value
= (int)(adjust
->value
+0.5);
1925 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1926 event
.SetEventObject( win
);
1927 win
->GetEventHandler()->ProcessEvent( event
);
1930 //-----------------------------------------------------------------------------
1931 // "button_press_event" from scrollbar
1932 //-----------------------------------------------------------------------------
1934 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1935 GdkEventButton
*gdk_event
,
1941 wxapp_install_idle_handler();
1944 g_blockEventsOnScroll
= TRUE
;
1946 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1948 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1954 //-----------------------------------------------------------------------------
1955 // "button_release_event" from scrollbar
1956 //-----------------------------------------------------------------------------
1958 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1959 GdkEventButton
*WXUNUSED(gdk_event
),
1964 // don't test here as we can release the mouse while being over
1965 // a different window than the slider
1967 // if (gdk_event->window != widget->slider) return FALSE;
1969 g_blockEventsOnScroll
= FALSE
;
1971 if (win
->m_isScrolling
)
1973 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1977 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1978 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1980 value
= (int)(win
->m_hAdjust
->value
+0.5);
1983 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1985 value
= (int)(win
->m_vAdjust
->value
+0.5);
1989 wxScrollWinEvent
event( command
, value
, dir
);
1990 event
.SetEventObject( win
);
1991 win
->GetEventHandler()->ProcessEvent( event
);
1994 win
->m_isScrolling
= FALSE
;
1999 // ----------------------------------------------------------------------------
2000 // this wxWindowBase function is implemented here (in platform-specific file)
2001 // because it is static and so couldn't be made virtual
2002 // ----------------------------------------------------------------------------
2004 wxWindow
*wxWindowBase::FindFocus()
2006 // the cast is necessary when we compile in wxUniversal mode
2007 return (wxWindow
*)g_focusWindow
;
2010 //-----------------------------------------------------------------------------
2011 // "realize" from m_widget
2012 //-----------------------------------------------------------------------------
2014 /* We cannot set colours and fonts before the widget has
2015 been realized, so we do this directly after realization. */
2018 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2023 wxapp_install_idle_handler();
2025 if (win
->m_delayedBackgroundColour
)
2026 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2028 if (win
->m_delayedForegroundColour
)
2029 win
->SetForegroundColour( win
->GetForegroundColour() );
2031 wxWindowCreateEvent
event( win
);
2032 event
.SetEventObject( win
);
2033 win
->GetEventHandler()->ProcessEvent( event
);
2038 //-----------------------------------------------------------------------------
2040 //-----------------------------------------------------------------------------
2043 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2044 GtkAllocation
*WXUNUSED(alloc
),
2048 wxapp_install_idle_handler();
2050 if (!win
->m_hasScrolling
) return;
2052 int client_width
= 0;
2053 int client_height
= 0;
2054 win
->GetClientSize( &client_width
, &client_height
);
2055 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2058 win
->m_oldClientWidth
= client_width
;
2059 win
->m_oldClientHeight
= client_height
;
2061 if (!win
->m_nativeSizeEvent
)
2063 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2064 event
.SetEventObject( win
);
2065 win
->GetEventHandler()->ProcessEvent( event
);
2071 #define WXUNUSED_UNLESS_XIM(param) param
2073 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2076 /* Resize XIM window */
2079 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2080 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2081 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2084 wxapp_install_idle_handler();
2090 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2094 gdk_window_get_size (widget
->window
, &width
, &height
);
2095 win
->m_icattr
->preedit_area
.width
= width
;
2096 win
->m_icattr
->preedit_area
.height
= height
;
2097 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2102 //-----------------------------------------------------------------------------
2103 // "realize" from m_wxwindow
2104 //-----------------------------------------------------------------------------
2106 /* Initialize XIM support */
2109 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2110 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2113 wxapp_install_idle_handler();
2116 if (win
->m_ic
) return FALSE
;
2117 if (!widget
) return FALSE
;
2118 if (!gdk_im_ready()) return FALSE
;
2120 win
->m_icattr
= gdk_ic_attr_new();
2121 if (!win
->m_icattr
) return FALSE
;
2125 GdkColormap
*colormap
;
2126 GdkICAttr
*attr
= win
->m_icattr
;
2127 unsigned attrmask
= GDK_IC_ALL_REQ
;
2129 GdkIMStyle supported_style
= (GdkIMStyle
)
2130 (GDK_IM_PREEDIT_NONE
|
2131 GDK_IM_PREEDIT_NOTHING
|
2132 GDK_IM_PREEDIT_POSITION
|
2133 GDK_IM_STATUS_NONE
|
2134 GDK_IM_STATUS_NOTHING
);
2136 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2137 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2139 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2140 attr
->client_window
= widget
->window
;
2142 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2143 gtk_widget_get_default_colormap ())
2145 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2146 attr
->preedit_colormap
= colormap
;
2149 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2150 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2151 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2152 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2154 switch (style
& GDK_IM_PREEDIT_MASK
)
2156 case GDK_IM_PREEDIT_POSITION
:
2157 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2159 g_warning ("over-the-spot style requires fontset");
2163 gdk_window_get_size (widget
->window
, &width
, &height
);
2165 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2166 attr
->spot_location
.x
= 0;
2167 attr
->spot_location
.y
= height
;
2168 attr
->preedit_area
.x
= 0;
2169 attr
->preedit_area
.y
= 0;
2170 attr
->preedit_area
.width
= width
;
2171 attr
->preedit_area
.height
= height
;
2172 attr
->preedit_fontset
= widget
->style
->font
;
2177 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2179 if (win
->m_ic
== NULL
)
2180 g_warning ("Can't create input context.");
2183 mask
= gdk_window_get_events (widget
->window
);
2184 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2185 gdk_window_set_events (widget
->window
, mask
);
2187 if (GTK_WIDGET_HAS_FOCUS(widget
))
2188 gdk_im_begin (win
->m_ic
, widget
->window
);
2195 //-----------------------------------------------------------------------------
2196 // InsertChild for wxWindowGTK.
2197 //-----------------------------------------------------------------------------
2199 /* Callback for wxWindowGTK. This very strange beast has to be used because
2200 * C++ has no virtual methods in a constructor. We have to emulate a
2201 * virtual function here as wxNotebook requires a different way to insert
2202 * a child in it. I had opted for creating a wxNotebookPage window class
2203 * which would have made this superfluous (such in the MDI window system),
2204 * but no-one was listening to me... */
2206 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2208 /* the window might have been scrolled already, do we
2209 have to adapt the position */
2210 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2211 child
->m_x
+= pizza
->xoffset
;
2212 child
->m_y
+= pizza
->yoffset
;
2214 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2215 GTK_WIDGET(child
->m_widget
),
2222 //-----------------------------------------------------------------------------
2224 //-----------------------------------------------------------------------------
2226 wxWindow
*wxGetActiveWindow()
2228 // the cast is necessary when we compile in wxUniversal mode
2229 return (wxWindow
*)g_focusWindow
;
2232 //-----------------------------------------------------------------------------
2234 //-----------------------------------------------------------------------------
2236 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2238 #ifdef __WXUNIVERSAL__
2239 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2241 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2242 #endif // __WXUNIVERSAL__/__WXGTK__
2244 void wxWindowGTK::Init()
2250 m_widget
= (GtkWidget
*) NULL
;
2251 m_wxwindow
= (GtkWidget
*) NULL
;
2252 m_focusWidget
= (GtkWidget
*) NULL
;
2262 m_needParent
= TRUE
;
2263 m_isBeingDeleted
= FALSE
;
2266 m_nativeSizeEvent
= FALSE
;
2268 m_hasScrolling
= FALSE
;
2269 m_isScrolling
= FALSE
;
2271 m_hAdjust
= (GtkAdjustment
*) NULL
;
2272 m_vAdjust
= (GtkAdjustment
*) NULL
;
2273 m_oldHorizontalPos
= 0.0;
2274 m_oldVerticalPos
= 0.0;
2277 m_widgetStyle
= (GtkStyle
*) NULL
;
2279 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2281 m_isStaticBox
= FALSE
;
2282 m_isRadioButton
= FALSE
;
2283 m_isListBox
= FALSE
;
2285 m_acceptsFocus
= FALSE
;
2287 m_clipPaintRegion
= FALSE
;
2289 m_cursor
= *wxSTANDARD_CURSOR
;
2291 m_delayedForegroundColour
= FALSE
;
2292 m_delayedBackgroundColour
= FALSE
;
2295 m_ic
= (GdkIC
*) NULL
;
2296 m_icattr
= (GdkICAttr
*) NULL
;
2300 wxWindowGTK::wxWindowGTK()
2305 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2310 const wxString
&name
)
2314 Create( parent
, id
, pos
, size
, style
, name
);
2317 bool wxWindowGTK::Create( wxWindow
*parent
,
2322 const wxString
&name
)
2324 if (!PreCreation( parent
, pos
, size
) ||
2325 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2327 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2331 m_insertCallback
= wxInsertChildInWindow
;
2333 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2334 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2336 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2338 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2339 scroll_class
->scrollbar_spacing
= 0;
2341 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2343 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2344 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2346 m_wxwindow
= gtk_pizza_new();
2348 #ifndef __WXUNIVERSAL__
2349 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2351 if (HasFlag(wxRAISED_BORDER
))
2353 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2355 else if (HasFlag(wxSUNKEN_BORDER
))
2357 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2359 else if (HasFlag(wxSIMPLE_BORDER
))
2361 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2365 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2367 #endif // __WXUNIVERSAL__
2369 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2371 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2372 m_acceptsFocus
= TRUE
;
2374 // I _really_ don't want scrollbars in the beginning
2375 m_vAdjust
->lower
= 0.0;
2376 m_vAdjust
->upper
= 1.0;
2377 m_vAdjust
->value
= 0.0;
2378 m_vAdjust
->step_increment
= 1.0;
2379 m_vAdjust
->page_increment
= 1.0;
2380 m_vAdjust
->page_size
= 5.0;
2381 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2382 m_hAdjust
->lower
= 0.0;
2383 m_hAdjust
->upper
= 1.0;
2384 m_hAdjust
->value
= 0.0;
2385 m_hAdjust
->step_increment
= 1.0;
2386 m_hAdjust
->page_increment
= 1.0;
2387 m_hAdjust
->page_size
= 5.0;
2388 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2390 // these handlers block mouse events to any window during scrolling such as
2391 // motion events and prevent GTK and wxWindows from fighting over where the
2394 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2395 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2397 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2398 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2400 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2401 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2403 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2404 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2406 // these handlers get notified when screen updates are required either when
2407 // scrolling or when the window size (and therefore scrollbar configuration)
2410 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2411 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2412 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2413 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2415 gtk_widget_show( m_wxwindow
);
2418 m_parent
->DoAddChild( this );
2420 m_focusWidget
= m_wxwindow
;
2429 wxWindowGTK::~wxWindowGTK()
2431 if (g_focusWindow
== this)
2432 g_focusWindow
= NULL
;
2434 if (g_activeFrame
== this)
2435 g_activeFrame
= NULL
;
2437 m_isBeingDeleted
= TRUE
;
2446 m_parent
->RemoveChild( this );
2450 gdk_ic_destroy (m_ic
);
2452 gdk_ic_attr_destroy (m_icattr
);
2457 #if DISABLE_STYLE_IF_BROKEN_THEME
2458 // don't delete if it's a pixmap theme style
2459 if (!m_widgetStyle
->engine_data
)
2460 gtk_style_unref( m_widgetStyle
);
2462 m_widgetStyle
= (GtkStyle
*) NULL
;
2467 gtk_widget_destroy( m_wxwindow
);
2468 m_wxwindow
= (GtkWidget
*) NULL
;
2473 gtk_widget_destroy( m_widget
);
2474 m_widget
= (GtkWidget
*) NULL
;
2478 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2480 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2482 /* this turns -1 into 20 so that a minimal window is
2483 visible even although -1,-1 has been given as the
2484 size of the window. the same trick is used in other
2485 ports and should make debugging easier */
2486 m_width
= WidthDefault(size
.x
);
2487 m_height
= HeightDefault(size
.y
);
2492 /* some reasonable defaults */
2497 m_x
= (gdk_screen_width () - m_width
) / 2;
2498 if (m_x
< 10) m_x
= 10;
2502 m_y
= (gdk_screen_height () - m_height
) / 2;
2503 if (m_y
< 10) m_y
= 10;
2510 void wxWindowGTK::PostCreation()
2512 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2518 // these get reported to wxWindows -> wxPaintEvent
2520 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2522 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2523 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2526 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2527 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2529 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2531 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2532 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2535 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2539 // these are called when the "sunken" or "raised" borders are drawn */
2540 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2541 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2544 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2545 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2551 if (m_focusWidget
== NULL
)
2552 m_focusWidget
= m_widget
;
2554 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2555 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2557 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2558 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2560 // connect to the various key and mouse handlers
2562 GtkWidget
*connect_widget
= GetConnectWidget();
2564 ConnectWidget( connect_widget
);
2566 /* We cannot set colours, fonts and cursors before the widget has
2567 been realized, so we do this directly after realization */
2568 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2569 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2573 // Catch native resize events
2574 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2575 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2577 // Initialize XIM support
2578 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2579 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2581 // And resize XIM window
2582 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2583 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2586 if (!GTK_IS_COMBO(m_widget
))
2588 // This is needed if we want to add our windows into native
2589 // GTK control, such as the toolbar. With this callback, the
2590 // toolbar gets to know the correct size (the one set by the
2591 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2592 // when moving to GTK 2.0.
2593 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2594 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2600 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2602 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2603 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2605 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2606 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2608 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2609 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2611 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2612 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2614 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2615 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2617 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2618 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2620 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2621 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2624 bool wxWindowGTK::Destroy()
2626 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2630 return wxWindowBase::Destroy();
2633 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2635 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2638 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2640 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2641 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2644 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2647 if (m_resizing
) return; /* I don't like recursions */
2650 int currentX
, currentY
;
2651 GetPosition(¤tX
, ¤tY
);
2656 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2658 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2660 /* don't set the size for children of wxNotebook, just take the values. */
2668 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2669 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2671 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2672 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2673 if (width
!= -1) m_width
= width
;
2674 if (height
!= -1) m_height
= height
;
2678 m_x
= x
+ pizza
->xoffset
;
2679 m_y
= y
+ pizza
->yoffset
;
2684 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2686 if (width
== -1) m_width
= 80;
2689 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2691 if (height
== -1) m_height
= 26;
2694 int minWidth
= GetMinWidth(),
2695 minHeight
= GetMinHeight(),
2696 maxWidth
= GetMaxWidth(),
2697 maxHeight
= GetMaxHeight();
2699 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2700 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2701 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2702 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2705 int bottom_border
= 0;
2707 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2709 /* the default button has a border around it */
2714 DoMoveWindow( m_x
-border
,
2717 m_height
+border
+bottom_border
);
2722 /* Sometimes the client area changes size without the
2723 whole windows's size changing, but if the whole
2724 windows's size doesn't change, no wxSizeEvent will
2725 normally be sent. Here we add an extra test if
2726 the client test has been changed and this will
2728 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2732 wxPrintf( "OnSize sent from " );
2733 if (GetClassInfo() && GetClassInfo()->GetClassName())
2734 wxPrintf( GetClassInfo()->GetClassName() );
2735 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2738 if (!m_nativeSizeEvent
)
2740 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2741 event
.SetEventObject( this );
2742 GetEventHandler()->ProcessEvent( event
);
2748 void wxWindowGTK::OnInternalIdle()
2750 // Update invalidated regions.
2753 // Synthetize activate events.
2754 if ( g_sendActivateEvent
!= -1 )
2756 bool activate
= g_sendActivateEvent
!= 0;
2759 g_sendActivateEvent
= -1;
2761 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2764 if ( g_activeFrameLostFocus
)
2766 if ( g_activeFrame
)
2768 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2769 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2770 event
.SetEventObject(g_activeFrame
);
2771 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2772 g_activeFrame
= NULL
;
2774 g_activeFrameLostFocus
= FALSE
;
2777 wxCursor cursor
= m_cursor
;
2778 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2782 /* I now set the cursor anew in every OnInternalIdle call
2783 as setting the cursor in a parent window also effects the
2784 windows above so that checking for the current cursor is
2789 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2791 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2793 if (!g_globalCursor
.Ok())
2794 cursor
= *wxSTANDARD_CURSOR
;
2796 window
= m_widget
->window
;
2797 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2798 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2804 GdkWindow
*window
= m_widget
->window
;
2805 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2806 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2814 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2816 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2818 if (width
) (*width
) = m_width
;
2819 if (height
) (*height
) = m_height
;
2822 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2824 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2828 SetSize( width
, height
);
2835 #ifndef __WXUNIVERSAL__
2836 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2838 /* when using GTK 1.2 we set the shadow border size to 2 */
2842 if (HasFlag(wxSIMPLE_BORDER
))
2844 /* when using GTK 1.2 we set the simple border size to 1 */
2848 #endif // __WXUNIVERSAL__
2852 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2854 GtkRequisition vscroll_req
;
2855 vscroll_req
.width
= 2;
2856 vscroll_req
.height
= 2;
2857 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2858 (scroll_window
->vscrollbar
, &vscroll_req
);
2860 GtkRequisition hscroll_req
;
2861 hscroll_req
.width
= 2;
2862 hscroll_req
.height
= 2;
2863 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2864 (scroll_window
->hscrollbar
, &hscroll_req
);
2866 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2868 if (scroll_window
->vscrollbar_visible
)
2870 dw
+= vscroll_req
.width
;
2871 dw
+= scroll_class
->scrollbar_spacing
;
2874 if (scroll_window
->hscrollbar_visible
)
2876 dh
+= hscroll_req
.height
;
2877 dh
+= scroll_class
->scrollbar_spacing
;
2881 SetSize( width
+dw
, height
+dh
);
2885 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2887 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2891 if (width
) (*width
) = m_width
;
2892 if (height
) (*height
) = m_height
;
2899 #ifndef __WXUNIVERSAL__
2900 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2902 /* when using GTK 1.2 we set the shadow border size to 2 */
2906 if (HasFlag(wxSIMPLE_BORDER
))
2908 /* when using GTK 1.2 we set the simple border size to 1 */
2912 #endif // __WXUNIVERSAL__
2916 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2918 GtkRequisition vscroll_req
;
2919 vscroll_req
.width
= 2;
2920 vscroll_req
.height
= 2;
2921 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2922 (scroll_window
->vscrollbar
, &vscroll_req
);
2924 GtkRequisition hscroll_req
;
2925 hscroll_req
.width
= 2;
2926 hscroll_req
.height
= 2;
2927 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2928 (scroll_window
->hscrollbar
, &hscroll_req
);
2930 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2932 if (scroll_window
->vscrollbar_visible
)
2934 dw
+= vscroll_req
.width
;
2935 dw
+= scroll_class
->scrollbar_spacing
;
2938 if (scroll_window
->hscrollbar_visible
)
2940 dh
+= hscroll_req
.height
;
2941 dh
+= scroll_class
->scrollbar_spacing
;
2945 if (width
) (*width
) = m_width
- dw
;
2946 if (height
) (*height
) = m_height
- dh
;
2950 printf( "GetClientSize, name %s ", GetName().c_str() );
2951 if (width) printf( " width = %d", (*width) );
2952 if (height) printf( " height = %d", (*height) );
2957 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2959 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2963 if (m_parent
&& m_parent
->m_wxwindow
)
2965 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2966 dx
= pizza
->xoffset
;
2967 dy
= pizza
->yoffset
;
2970 if (x
) (*x
) = m_x
- dx
;
2971 if (y
) (*y
) = m_y
- dy
;
2974 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2976 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2978 if (!m_widget
->window
) return;
2980 GdkWindow
*source
= (GdkWindow
*) NULL
;
2982 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2984 source
= m_widget
->window
;
2988 gdk_window_get_origin( source
, &org_x
, &org_y
);
2992 if (GTK_WIDGET_NO_WINDOW (m_widget
))
2994 org_x
+= m_widget
->allocation
.x
;
2995 org_y
+= m_widget
->allocation
.y
;
3003 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3005 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3007 if (!m_widget
->window
) return;
3009 GdkWindow
*source
= (GdkWindow
*) NULL
;
3011 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3013 source
= m_widget
->window
;
3017 gdk_window_get_origin( source
, &org_x
, &org_y
);
3021 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3023 org_x
+= m_widget
->allocation
.x
;
3024 org_y
+= m_widget
->allocation
.y
;
3032 bool wxWindowGTK::Show( bool show
)
3034 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3036 if (!wxWindowBase::Show(show
))
3043 gtk_widget_show( m_widget
);
3045 gtk_widget_hide( m_widget
);
3050 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3052 win
->OnParentEnable(enable
);
3054 // Recurse, so that children have the opportunity to Do The Right Thing
3055 // and reset colours that have been messed up by a parent's (really ancestor's)
3057 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3059 node
= node
->GetNext() )
3061 wxWindow
*child
= node
->GetData();
3062 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3063 wxWindowNotifyEnable(child
, enable
);
3067 bool wxWindowGTK::Enable( bool enable
)
3069 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3071 if (!wxWindowBase::Enable(enable
))
3077 gtk_widget_set_sensitive( m_widget
, enable
);
3079 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3081 wxWindowNotifyEnable(this, enable
);
3086 int wxWindowGTK::GetCharHeight() const
3088 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3090 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3092 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3094 return font
->ascent
+ font
->descent
;
3097 int wxWindowGTK::GetCharWidth() const
3099 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3101 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3103 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3105 return gdk_string_width( font
, "H" );
3108 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3112 int *externalLeading
,
3113 const wxFont
*theFont
) const
3115 wxFont fontToUse
= m_font
;
3116 if (theFont
) fontToUse
= *theFont
;
3118 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3120 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3121 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3122 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3123 if (descent
) (*descent
) = font
->descent
;
3124 if (externalLeading
) (*externalLeading
) = 0; // ??
3127 void wxWindowGTK::SetFocus()
3129 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3132 wxPrintf( "SetFocus from " );
3133 if (GetClassInfo() && GetClassInfo()->GetClassName())
3134 wxPrintf( GetClassInfo()->GetClassName() );
3140 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3142 gtk_widget_grab_focus (m_wxwindow
);
3147 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3149 gtk_widget_grab_focus (m_widget
);
3151 else if (GTK_IS_CONTAINER(m_widget
))
3153 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3162 bool wxWindowGTK::AcceptsFocus() const
3164 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3167 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3169 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3171 wxWindowGTK
*oldParent
= m_parent
,
3172 *newParent
= (wxWindowGTK
*)newParentBase
;
3174 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3176 if ( !wxWindowBase::Reparent(newParent
) )
3179 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3181 /* prevent GTK from deleting the widget arbitrarily */
3182 gtk_widget_ref( m_widget
);
3186 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3189 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3193 /* insert GTK representation */
3194 (*(newParent
->m_insertCallback
))(newParent
, this);
3197 /* reverse: prevent GTK from deleting the widget arbitrarily */
3198 gtk_widget_unref( m_widget
);
3203 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3205 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3207 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3209 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3214 /* insert GTK representation */
3215 (*m_insertCallback
)(this, child
);
3218 void wxWindowGTK::Raise()
3220 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3222 if (!m_widget
->window
) return;
3224 gdk_window_raise( m_widget
->window
);
3227 void wxWindowGTK::Lower()
3229 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3231 if (!m_widget
->window
) return;
3233 gdk_window_lower( m_widget
->window
);
3236 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3238 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3240 if (cursor
== m_cursor
)
3244 wxapp_install_idle_handler();
3246 if (cursor
== wxNullCursor
)
3247 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3249 return wxWindowBase::SetCursor( cursor
);
3252 void wxWindowGTK::WarpPointer( int x
, int y
)
3254 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3256 // We provide this function ourselves as it is
3257 // missing in GDK (top of this file).
3259 GdkWindow
*window
= (GdkWindow
*) NULL
;
3261 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3263 window
= GetConnectWidget()->window
;
3266 gdk_window_warp_pointer( window
, x
, y
);
3269 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3271 if (!m_widget
) return;
3272 if (!m_widget
->window
) return;
3275 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3279 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3280 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3284 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3285 m_clearRegion
.Clear();
3286 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3294 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3295 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3299 GdkRectangle gdk_rect
;
3300 gdk_rect
.x
= rect
->x
;
3301 gdk_rect
.y
= rect
->y
;
3302 gdk_rect
.width
= rect
->width
;
3303 gdk_rect
.height
= rect
->height
;
3304 gtk_widget_draw( m_widget
, &gdk_rect
);
3311 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3312 m_updateRegion
.Clear();
3313 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3317 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3325 GdkRectangle gdk_rect
;
3326 gdk_rect
.x
= rect
->x
;
3327 gdk_rect
.y
= rect
->y
;
3328 gdk_rect
.width
= rect
->width
;
3329 gdk_rect
.height
= rect
->height
;
3330 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3334 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3340 void wxWindowGTK::Update()
3343 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3344 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3347 if (!m_updateRegion
.IsEmpty())
3348 GtkSendPaintEvents();
3351 void wxWindowGTK::GtkSendPaintEvents()
3355 m_clearRegion
.Clear();
3356 m_updateRegion
.Clear();
3360 m_clipPaintRegion
= TRUE
;
3362 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3364 wxWindowDC
dc( (wxWindow
*)this );
3365 dc
.SetClippingRegion( m_clearRegion
);
3367 wxEraseEvent
erase_event( GetId(), &dc
);
3368 erase_event
.SetEventObject( this );
3370 if (!GetEventHandler()->ProcessEvent(erase_event
))
3372 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3374 wxRegionIterator
upd( m_clearRegion
);
3377 gdk_draw_rectangle( GTK_PIZZA(m_wxwindow
)->bin_window
, g_eraseGC
, 0,
3378 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3382 m_clearRegion
.Clear();
3385 wxNcPaintEvent
nc_paint_event( GetId() );
3386 nc_paint_event
.SetEventObject( this );
3387 GetEventHandler()->ProcessEvent( nc_paint_event
);
3389 wxPaintEvent
paint_event( GetId() );
3390 paint_event
.SetEventObject( this );
3391 GetEventHandler()->ProcessEvent( paint_event
);
3393 m_clipPaintRegion
= FALSE
;
3395 #ifndef __WXUNIVERSAL__
3397 // The following code will result in all window-less widgets
3398 // being redrawn because the wxWindows class is allowed to
3399 // paint over the window-less widgets.
3401 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3403 GList
*children
= pizza
->children
;
3406 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3407 children
= children
->next
;
3409 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3410 GTK_WIDGET_DRAWABLE (child
->widget
))
3412 // Get intersection of widget area and update region
3413 wxRegion
region( m_updateRegion
);
3415 GdkEventExpose gdk_event
;
3416 gdk_event
.type
= GDK_EXPOSE
;
3417 gdk_event
.window
= pizza
->bin_window
;
3418 gdk_event
.count
= 0;
3420 wxRegionIterator
upd( m_updateRegion
);
3424 rect
.x
= upd
.GetX();
3425 rect
.y
= upd
.GetY();
3426 rect
.width
= upd
.GetWidth();
3427 rect
.height
= upd
.GetHeight();
3429 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3431 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3441 m_updateRegion
.Clear();
3444 void wxWindowGTK::Clear()
3446 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3448 if (!m_widget
->window
) return;
3450 if (m_wxwindow
&& m_wxwindow
->window
)
3452 // gdk_window_clear( m_wxwindow->window );
3457 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3459 wxWindowBase::DoSetToolTip(tip
);
3462 m_tooltip
->Apply( (wxWindow
*)this );
3465 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3467 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3469 #endif // wxUSE_TOOLTIPS
3471 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3473 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3475 if (!wxWindowBase::SetBackgroundColour(colour
))
3477 // don't leave if the GTK widget has just
3479 if (!m_delayedBackgroundColour
) return FALSE
;
3482 GdkWindow
*window
= (GdkWindow
*) NULL
;
3484 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3486 window
= GetConnectWidget()->window
;
3490 // indicate that a new style has been set
3491 // but it couldn't get applied as the
3492 // widget hasn't been realized yet.
3493 m_delayedBackgroundColour
= TRUE
;
3497 (m_wxwindow
->window
) &&
3498 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3500 /* wxMSW doesn't clear the window here. I don't do that either to
3501 provide compatibility. call Clear() to do the job. */
3503 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3504 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3512 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3514 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3516 if (!wxWindowBase::SetForegroundColour(colour
))
3518 // don't leave if the GTK widget has just
3520 if (!m_delayedForegroundColour
) return FALSE
;
3523 GdkWindow
*window
= (GdkWindow
*) NULL
;
3525 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3527 window
= GetConnectWidget()->window
;
3531 // indicate that a new style has been set
3532 // but it couldn't get applied as the
3533 // widget hasn't been realized yet.
3534 m_delayedForegroundColour
= TRUE
;
3542 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3546 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3548 // FIXME: no more klass in 2.0
3550 remake
->klass
= m_widgetStyle
->klass
;
3553 gtk_style_unref( m_widgetStyle
);
3554 m_widgetStyle
= remake
;
3558 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3561 def
= gtk_widget_get_default_style();
3563 m_widgetStyle
= gtk_style_copy( def
);
3565 // FIXME: no more klass in 2.0
3567 m_widgetStyle
->klass
= def
->klass
;
3571 return m_widgetStyle
;
3574 void wxWindowGTK::SetWidgetStyle()
3576 #if DISABLE_STYLE_IF_BROKEN_THEME
3577 if (m_widget
->style
->engine_data
)
3579 static bool s_warningPrinted
= FALSE
;
3580 if (!s_warningPrinted
)
3582 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3583 s_warningPrinted
= TRUE
;
3585 m_widgetStyle
= m_widget
->style
;
3590 GtkStyle
*style
= GetWidgetStyle();
3592 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3594 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3597 if (m_foregroundColour
.Ok())
3599 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3600 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3602 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3603 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3604 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3608 // Try to restore the gtk default style. This is still a little
3609 // oversimplified for what is probably really needed here for controls
3610 // other than buttons, but is better than not being able to (re)set a
3611 // control's foreground colour to *wxBLACK -- RL
3612 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3615 def
= gtk_widget_get_default_style();
3617 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3618 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3619 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3623 if (m_backgroundColour
.Ok())
3625 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3626 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3628 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3629 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3630 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3631 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3632 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3633 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3634 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3635 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3639 // Try to restore the gtk default style. This is still a little
3640 // oversimplified for what is probably really needed here for controls
3641 // other than buttons, but is better than not being able to (re)set a
3642 // control's background colour to default grey and means resetting a
3643 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3645 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3648 def
= gtk_widget_get_default_style();
3650 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3651 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3652 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3653 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3654 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3655 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3656 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3657 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3662 void wxWindowGTK::ApplyWidgetStyle()
3666 //-----------------------------------------------------------------------------
3667 // Pop-up menu stuff
3668 //-----------------------------------------------------------------------------
3670 #if wxUSE_MENUS_NATIVE
3673 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3675 *is_waiting
= FALSE
;
3678 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3680 menu
->SetInvokingWindow( win
);
3681 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3684 wxMenuItem
*menuitem
= node
->GetData();
3685 if (menuitem
->IsSubMenu())
3687 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3690 node
= node
->GetNext();
3694 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3695 // wxPopupMenuPositionCallback()
3697 // should be safe even in the MT case as the user can hardly popup 2 menus
3698 // simultaneously, can he?
3699 static gint gs_pop_x
= 0;
3700 static gint gs_pop_y
= 0;
3702 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3705 gboolean
* WXUNUSED(whatever
),
3707 gpointer
WXUNUSED(user_data
) )
3709 // ensure that the menu appears entirely on screen
3711 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3713 wxSize sizeScreen
= wxGetDisplaySize();
3715 gint xmax
= sizeScreen
.x
- req
.width
,
3716 ymax
= sizeScreen
.y
- req
.height
;
3718 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3719 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3722 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3724 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3726 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3728 SetInvokingWindow( menu
, this );
3734 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3736 bool is_waiting
= TRUE
;
3738 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3740 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3741 (gpointer
)&is_waiting
);
3744 GTK_MENU(menu
->m_menu
),
3745 (GtkWidget
*) NULL
, // parent menu shell
3746 (GtkWidget
*) NULL
, // parent menu item
3747 wxPopupMenuPositionCallback
, // function to position it
3748 NULL
, // client data
3749 0, // button used to activate it
3750 gs_timeLastClick
// the time of activation
3755 while (gtk_events_pending())
3756 gtk_main_iteration();
3762 #endif // wxUSE_MENUS_NATIVE
3764 #if wxUSE_DRAG_AND_DROP
3766 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3768 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3770 GtkWidget
*dnd_widget
= GetConnectWidget();
3772 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3774 if (m_dropTarget
) delete m_dropTarget
;
3775 m_dropTarget
= dropTarget
;
3777 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3780 #endif // wxUSE_DRAG_AND_DROP
3782 GtkWidget
* wxWindowGTK::GetConnectWidget()
3784 GtkWidget
*connect_widget
= m_widget
;
3785 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3787 return connect_widget
;
3790 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3793 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3795 return (window
== m_widget
->window
);
3798 bool wxWindowGTK::SetFont( const wxFont
&font
)
3800 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3802 if (!wxWindowBase::SetFont(font
))
3807 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3808 if ( sysbg
== m_backgroundColour
)
3810 m_backgroundColour
= wxNullColour
;
3812 m_backgroundColour
= sysbg
;
3822 void wxWindowGTK::DoCaptureMouse()
3824 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3826 GdkWindow
*window
= (GdkWindow
*) NULL
;
3828 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3830 window
= GetConnectWidget()->window
;
3832 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3834 wxCursor
* cursor
= & m_cursor
;
3836 cursor
= wxSTANDARD_CURSOR
;
3838 gdk_pointer_grab( window
, FALSE
,
3840 (GDK_BUTTON_PRESS_MASK
|
3841 GDK_BUTTON_RELEASE_MASK
|
3842 GDK_POINTER_MOTION_HINT_MASK
|
3843 GDK_POINTER_MOTION_MASK
),
3845 cursor
->GetCursor(),
3846 (guint32
)GDK_CURRENT_TIME
);
3847 g_captureWindow
= this;
3848 g_captureWindowHasMouse
= TRUE
;
3851 void wxWindowGTK::DoReleaseMouse()
3853 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3855 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3857 g_captureWindow
= (wxWindowGTK
*) NULL
;
3859 GdkWindow
*window
= (GdkWindow
*) NULL
;
3861 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3863 window
= GetConnectWidget()->window
;
3868 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3872 wxWindow
*wxWindowBase::GetCapture()
3874 return (wxWindow
*)g_captureWindow
;
3877 bool wxWindowGTK::IsRetained() const
3882 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3883 int range
, bool refresh
)
3885 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3887 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3889 m_hasScrolling
= TRUE
;
3891 if (orient
== wxHORIZONTAL
)
3893 float fpos
= (float)pos
;
3894 float frange
= (float)range
;
3895 float fthumb
= (float)thumbVisible
;
3896 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3897 if (fpos
< 0.0) fpos
= 0.0;
3899 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3900 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3902 SetScrollPos( orient
, pos
, refresh
);
3906 m_oldHorizontalPos
= fpos
;
3908 m_hAdjust
->lower
= 0.0;
3909 m_hAdjust
->upper
= frange
;
3910 m_hAdjust
->value
= fpos
;
3911 m_hAdjust
->step_increment
= 1.0;
3912 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3913 m_hAdjust
->page_size
= fthumb
;
3917 float fpos
= (float)pos
;
3918 float frange
= (float)range
;
3919 float fthumb
= (float)thumbVisible
;
3920 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3921 if (fpos
< 0.0) fpos
= 0.0;
3923 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
3924 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3926 SetScrollPos( orient
, pos
, refresh
);
3930 m_oldVerticalPos
= fpos
;
3932 m_vAdjust
->lower
= 0.0;
3933 m_vAdjust
->upper
= frange
;
3934 m_vAdjust
->value
= fpos
;
3935 m_vAdjust
->step_increment
= 1.0;
3936 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3937 m_vAdjust
->page_size
= fthumb
;
3940 if (orient
== wxHORIZONTAL
)
3941 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3943 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3946 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3948 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3950 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3952 if (orient
== wxHORIZONTAL
)
3954 float fpos
= (float)pos
;
3955 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3956 if (fpos
< 0.0) fpos
= 0.0;
3957 m_oldHorizontalPos
= fpos
;
3959 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3960 m_hAdjust
->value
= fpos
;
3964 float fpos
= (float)pos
;
3965 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
3966 if (fpos
< 0.0) fpos
= 0.0;
3967 m_oldVerticalPos
= fpos
;
3969 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
3970 m_vAdjust
->value
= fpos
;
3973 if (m_wxwindow
->window
)
3975 if (orient
== wxHORIZONTAL
)
3977 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
3978 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
3980 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
3982 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
3983 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
3987 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
3988 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
3990 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
3992 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
3993 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
3998 int wxWindowGTK::GetScrollThumb( int orient
) const
4000 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4002 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4004 if (orient
== wxHORIZONTAL
)
4005 return (int)(m_hAdjust
->page_size
+0.5);
4007 return (int)(m_vAdjust
->page_size
+0.5);
4010 int wxWindowGTK::GetScrollPos( int orient
) const
4012 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4014 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4016 if (orient
== wxHORIZONTAL
)
4017 return (int)(m_hAdjust
->value
+0.5);
4019 return (int)(m_vAdjust
->value
+0.5);
4022 int wxWindowGTK::GetScrollRange( int orient
) const
4024 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4026 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4028 if (orient
== wxHORIZONTAL
)
4029 return (int)(m_hAdjust
->upper
+0.5);
4031 return (int)(m_vAdjust
->upper
+0.5);
4034 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4036 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4038 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4040 // No scrolling requested.
4041 if ((dx
== 0) && (dy
== 0)) return;
4044 if (!m_updateRegion
.IsEmpty())
4046 m_updateRegion
.Offset( dx
, dy
);
4050 GetClientSize( &cw
, &ch
);
4051 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4054 if (!m_clearRegion
.IsEmpty())
4056 m_clearRegion
.Offset( dx
, dy
);
4060 GetClientSize( &cw
, &ch
);
4061 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4064 m_clipPaintRegion
= TRUE
;
4066 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4068 m_clipPaintRegion
= FALSE
;
4071 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, -dx
, -dy
);
4073 GTK_PIZZA(m_wxwindow
)->xoffset
-= dx
;
4074 GTK_PIZZA(m_wxwindow
)->yoffset
-= dy
;
4081 // Find the wxWindow at the current mouse position, also returning the mouse
4083 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4085 pt
= wxGetMousePosition();
4086 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4090 // Get the current mouse position.
4091 wxPoint
wxGetMousePosition()
4093 /* This crashes when used within wxHelpContext,
4094 so we have to use the X-specific implementation below.
4096 GdkModifierType *mask;
4097 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4099 return wxPoint(x, y);
4103 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4105 return wxPoint(-999, -999);
4107 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4108 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4109 Window rootReturn
, childReturn
;
4110 int rootX
, rootY
, winX
, winY
;
4111 unsigned int maskReturn
;
4113 XQueryPointer (display
,
4117 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4118 return wxPoint(rootX
, rootY
);
4122 // ----------------------------------------------------------------------------
4124 // ----------------------------------------------------------------------------
4126 class wxWinModule
: public wxModule
4133 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4136 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4138 bool wxWinModule::OnInit()
4140 g_eraseGC
= gdk_gc_new( GDK_ROOT_PARENT() );
4141 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4146 void wxWinModule::OnExit()
4148 gdk_gc_unref( g_eraseGC
);