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"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
68 //-----------------------------------------------------------------------------
69 // documentation on internals
70 //-----------------------------------------------------------------------------
73 I have been asked several times about writing some documentation about
74 the GTK port of wxWindows, especially its internal structures. Obviously,
75 you cannot understand wxGTK without knowing a little about the GTK, but
76 some more information about what the wxWindow, which is the base class
77 for all other window classes, does seems required as well.
81 What does wxWindow do? It contains the common interface for the following
82 jobs of its descendants:
84 1) Define the rudimentary behaviour common to all window classes, such as
85 resizing, intercepting user input (so as to make it possible to use these
86 events for special purposes in a derived class), window names etc.
88 2) Provide the possibility to contain and manage children, if the derived
89 class is allowed to contain children, which holds true for those window
90 classes which do not display a native GTK widget. To name them, these
91 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
92 work classes are a special case and are handled a bit differently from
93 the rest. The same holds true for the wxNotebook class.
95 3) Provide the possibility to draw into a client area of a window. This,
96 too, only holds true for classes that do not display a native GTK widget
99 4) Provide the entire mechanism for scrolling widgets. This actual inter-
100 face for this is usually in wxScrolledWindow, but the GTK implementation
103 5) A multitude of helper or extra methods for special purposes, such as
104 Drag'n'Drop, managing validators etc.
106 6) Display a border (sunken, raised, simple or none).
108 Normally one might expect, that one wxWindows window would always correspond
109 to one GTK widget. Under GTK, there is no such allround widget that has all
110 the functionality. Moreover, the GTK defines a client area as a different
111 widget from the actual widget you are handling. Last but not least some
112 special classes (e.g. wxFrame) handle different categories of widgets and
113 still have the possibility to draw something in the client area.
114 It was therefore required to write a special purpose GTK widget, that would
115 represent a client area in the sense of wxWindows capable to do the jobs
116 2), 3) and 4). I have written this class and it resides in win_gtk.c of
119 All windows must have a widget, with which they interact with other under-
120 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
121 thw wxWindow class has a member variable called m_widget which holds a
122 pointer to this widget. When the window class represents a GTK native widget,
123 this is (in most cases) the only GTK widget the class manages. E.g. the
124 wxStatitText class handles only a GtkLabel widget a pointer to which you
125 can find in m_widget (defined in wxWindow)
127 When the class has a client area for drawing into and for containing children
128 it has to handle the client area widget (of the type GtkPizza, defined in
129 win_gtk.c), but there could be any number of widgets, handled by a class
130 The common rule for all windows is only, that the widget that interacts with
131 the rest of GTK must be referenced in m_widget and all other widgets must be
132 children of this widget on the GTK level. The top-most widget, which also
133 represents the client area, must be in the m_wxwindow field and must be of
136 As I said, the window classes that display a GTK native widget only have
137 one widget, so in the case of e.g. the wxButton class m_widget holds a
138 pointer to a GtkButton widget. But windows with client areas (for drawing
139 and children) have a m_widget field that is a pointer to a GtkScrolled-
140 Window and a m_wxwindow field that is pointer to a GtkPizza and this
141 one is (in the GTK sense) a child of the GtkScrolledWindow.
143 If the m_wxwindow field is set, then all input to this widget is inter-
144 cepted and sent to the wxWindows class. If not, all input to the widget
145 that gets pointed to by m_widget gets intercepted and sent to the class.
149 The design of scrolling in wxWindows is markedly different from that offered
150 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
151 clicking on a scrollbar belonging to scrolled window will inevitably move
152 the window. In wxWindows, the scrollbar will only emit an event, send this
153 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
154 which actually moves the window and its subchildren. Note that GtkPizza
155 memorizes how much it has been scrolled but that wxWindows forgets this
156 so that the two coordinates systems have to be kept in synch. This is done
157 in various places using the pizza->xoffset and pizza->yoffset values.
161 Singularily the most broken code in GTK is the code that is supposes to
162 inform subwindows (child windows) about new positions. Very often, duplicate
163 events are sent without changes in size or position, equally often no
164 events are sent at all (All this is due to a bug in the GtkContainer code
165 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
166 GTK's own system and it simply waits for size events for toplevel windows
167 and then iterates down the respective size events to all window. This has
168 the disadvantage, that windows might get size events before the GTK widget
169 actually has the reported size. This doesn't normally pose any problem, but
170 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
171 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
172 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
173 window that is used for OpenGl output really has that size (as reported by
178 If someone at some point of time feels the immense desire to have a look at,
179 change or attempt to optimse the Refresh() logic, this person will need an
180 intimate understanding of what a "draw" and what an "expose" events are and
181 what there are used for, in particular when used in connection with GTK's
182 own windowless widgets. Beware.
186 Cursors, too, have been a constant source of pleasure. The main difficulty
187 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
188 for the parent. To prevent this from doing too much harm, I use idle time
189 to set the cursor over and over again, starting from the toplevel windows
190 and ending with the youngest generation (speaking of parent and child windows).
191 Also don't forget that cursors (like much else) are connected to GdkWindows,
192 not GtkWidgets and that the "window" field of a GtkWidget might very well
193 point to the GdkWindow of the parent widget (-> "window less widget") and
194 that the two obviously have very different meanings.
198 //-----------------------------------------------------------------------------
200 //-----------------------------------------------------------------------------
202 extern wxList wxPendingDelete
;
203 extern bool g_blockEventsOnDrag
;
204 extern bool g_blockEventsOnScroll
;
205 extern wxCursor g_globalCursor
;
207 // mouse capture state: the window which has it and if the mouse is currently
209 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
210 static bool g_captureWindowHasMouse
= FALSE
;
212 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
214 // the last window which had the focus - this is normally never NULL (except
215 // if we never had focus at all) as even when g_focusWindow is NULL it still
216 // keeps its previous value
217 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*)NULL
;
219 // the frame that is currently active (i.e. its child has focus). It is
220 // used to generate wxActivateEvents
221 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*)NULL
;
222 static bool g_activeFrameLostFocus
= FALSE
;
224 // if we detect that the app has got/lost the focus, we set this variable to
225 // either TRUE or FALSE and an activate event will be sent during the next
226 // OnIdle() call and it is reset to -1: this value means that we shouldn't
227 // send any activate events at all
228 static int g_sendActivateEvent
= -1;
230 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
231 the last click here */
232 static guint32 gs_timeLastClick
= 0;
234 extern bool g_mainThreadLocked
;
236 //-----------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
241 #define DISABLE_STYLE_IF_BROKEN_THEME 1
247 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
249 # define DEBUG_MAIN_THREAD
252 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
253 GdkEvent
*WXUNUSED(event
),
254 const wxChar
*WXUNUSED(name
) )
257 static bool s_done = FALSE;
260 wxLog::AddTraceMask("focus");
263 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
269 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
271 // suppress warnings about gtk_debug_focus_in_callback being unused with
276 tmp
+= wxT(" FROM ");
279 wxChar
*s
= new wxChar
[tmp
.Length()+1];
283 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
284 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
289 #define DEBUG_MAIN_THREAD
292 //-----------------------------------------------------------------------------
293 // missing gdk functions
294 //-----------------------------------------------------------------------------
297 gdk_window_warp_pointer (GdkWindow
*window
,
302 GdkWindowPrivate
*priv
;
306 window
= GDK_ROOT_PARENT();
309 if (!GDK_WINDOW_DESTROYED(window
))
311 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
312 None
, /* not source window -> move from anywhere */
313 GDK_WINDOW_XID(window
), /* dest window */
314 0, 0, 0, 0, /* not source window -> move from anywhere */
318 priv
= (GdkWindowPrivate
*) window
;
320 if (!priv
->destroyed
)
322 XWarpPointer (priv
->xdisplay
,
323 None
, /* not source window -> move from anywhere */
324 priv
->xwindow
, /* dest window */
325 0, 0, 0, 0, /* not source window -> move from anywhere */
331 //-----------------------------------------------------------------------------
333 //-----------------------------------------------------------------------------
335 extern void wxapp_install_idle_handler();
336 extern bool g_isIdle
;
338 //-----------------------------------------------------------------------------
339 // local code (see below)
340 //-----------------------------------------------------------------------------
342 // returns the child of win which currently has focus or NULL if not found
344 // Note: can't be static, needed by textctrl.cpp.
345 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
347 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
349 return (wxWindow
*)NULL
;
351 if ( winFocus
== win
)
352 return (wxWindow
*)win
;
354 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
356 node
= node
->GetNext() )
358 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
363 return (wxWindow
*)NULL
;
366 // Returns toplevel grandparent of given window:
367 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
369 wxWindowGTK
*p
= win
;
370 while (p
&& !p
->IsTopLevel())
376 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
378 // wxUniversal widgets draw the borders and scrollbars themselves
379 #ifndef __WXUNIVERSAL__
386 if (win
->m_hasScrolling
)
388 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
390 GtkRequisition vscroll_req
;
391 vscroll_req
.width
= 2;
392 vscroll_req
.height
= 2;
393 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
394 (scroll_window
->vscrollbar
, &vscroll_req
);
396 GtkRequisition hscroll_req
;
397 hscroll_req
.width
= 2;
398 hscroll_req
.height
= 2;
399 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
400 (scroll_window
->hscrollbar
, &hscroll_req
);
402 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
404 if (scroll_window
->vscrollbar_visible
)
406 dw
+= vscroll_req
.width
;
407 dw
+= scroll_class
->scrollbar_spacing
;
410 if (scroll_window
->hscrollbar_visible
)
412 dh
+= hscroll_req
.height
;
413 dh
+= scroll_class
->scrollbar_spacing
;
419 if (GTK_WIDGET_NO_WINDOW (widget
))
421 dx
+= widget
->allocation
.x
;
422 dy
+= widget
->allocation
.y
;
425 if (win
->HasFlag(wxRAISED_BORDER
))
427 gtk_draw_shadow( widget
->style
,
432 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
436 if (win
->HasFlag(wxSUNKEN_BORDER
))
438 gtk_draw_shadow( widget
->style
,
443 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
447 if (win
->HasFlag(wxSIMPLE_BORDER
))
450 gc
= gdk_gc_new( widget
->window
);
451 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
452 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
454 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
458 #endif // __WXUNIVERSAL__
461 //-----------------------------------------------------------------------------
462 // "expose_event" of m_widget
463 //-----------------------------------------------------------------------------
465 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
467 if (gdk_event
->count
> 0) return FALSE
;
469 draw_frame( widget
, win
);
474 //-----------------------------------------------------------------------------
475 // "draw" of m_widget
476 //-----------------------------------------------------------------------------
478 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
480 draw_frame( widget
, win
);
483 //-----------------------------------------------------------------------------
484 // key code mapping routines
485 //-----------------------------------------------------------------------------
487 static long map_to_unmodified_wx_keysym( GdkEventKey
*event
)
489 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
490 // but only event->keyval which is quite useless to us, so remember
491 // the last character from GDK_KEY_PRESS and resue it as last resort
493 // NB: should be MT-neutral as always called from main thread only
498 } s_lastKeyPress
= { 0, 0 };
500 KeySym keysym
= event
->keyval
;
506 case GDK_Shift_R
: key_code
= WXK_SHIFT
; break;
508 case GDK_Control_R
: key_code
= WXK_CONTROL
; break;
514 case GDK_Super_R
: key_code
= WXK_ALT
; break;
515 case GDK_Menu
: key_code
= WXK_MENU
; break;
516 case GDK_Help
: key_code
= WXK_HELP
; break;
517 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
518 case GDK_ISO_Left_Tab
:
519 case GDK_Tab
: key_code
= WXK_TAB
; break;
520 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
521 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
522 case GDK_Return
: key_code
= WXK_RETURN
; break;
523 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
524 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
525 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
526 case GDK_Delete
: key_code
= WXK_DELETE
; break;
527 case GDK_Home
: key_code
= WXK_HOME
; break;
528 case GDK_Left
: key_code
= WXK_LEFT
; break;
529 case GDK_Up
: key_code
= WXK_UP
; break;
530 case GDK_Right
: key_code
= WXK_RIGHT
; break;
531 case GDK_Down
: key_code
= WXK_DOWN
; break;
532 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
533 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
534 case GDK_Next
: key_code
= WXK_NEXT
; break;
535 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
536 case GDK_End
: key_code
= WXK_END
; break;
537 case GDK_Begin
: key_code
= WXK_HOME
; break;
538 case GDK_Select
: key_code
= WXK_SELECT
; break;
539 case GDK_Print
: key_code
= WXK_PRINT
; break;
540 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
541 case GDK_Insert
: key_code
= WXK_INSERT
; break;
542 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
544 case GDK_KP_0
: key_code
= WXK_NUMPAD0
; break;
545 case GDK_KP_1
: key_code
= WXK_NUMPAD1
; break;
546 case GDK_KP_2
: key_code
= WXK_NUMPAD2
; break;
547 case GDK_KP_3
: key_code
= WXK_NUMPAD3
; break;
548 case GDK_KP_4
: key_code
= WXK_NUMPAD4
; break;
549 case GDK_KP_5
: key_code
= WXK_NUMPAD5
; break;
550 case GDK_KP_6
: key_code
= WXK_NUMPAD6
; break;
551 case GDK_KP_7
: key_code
= WXK_NUMPAD7
; break;
552 case GDK_KP_8
: key_code
= WXK_NUMPAD8
; break;
553 case GDK_KP_9
: key_code
= WXK_NUMPAD9
; break;
554 case GDK_KP_Space
: key_code
= WXK_NUMPAD_SPACE
; break;
555 case GDK_KP_Tab
: key_code
= WXK_NUMPAD_TAB
; break;
556 case GDK_KP_Enter
: key_code
= WXK_NUMPAD_ENTER
; break;
557 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
558 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
559 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
560 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
561 case GDK_KP_Home
: key_code
= WXK_NUMPAD_HOME
; break;
562 case GDK_KP_Left
: key_code
= WXK_NUMPAD_LEFT
; break;
563 case GDK_KP_Up
: key_code
= WXK_NUMPAD_UP
; break;
564 case GDK_KP_Right
: key_code
= WXK_NUMPAD_RIGHT
; break;
565 case GDK_KP_Down
: key_code
= WXK_NUMPAD_DOWN
; break;
566 case GDK_KP_Prior
: key_code
= WXK_NUMPAD_PRIOR
; break;
567 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
568 case GDK_KP_Next
: key_code
= WXK_NUMPAD_NEXT
; break;
569 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
570 case GDK_KP_End
: key_code
= WXK_NUMPAD_END
; break;
571 case GDK_KP_Begin
: key_code
= WXK_NUMPAD_BEGIN
; break;
572 case GDK_KP_Insert
: key_code
= WXK_NUMPAD_INSERT
; break;
573 case GDK_KP_Delete
: key_code
= WXK_NUMPAD_DELETE
; break;
574 case GDK_KP_Equal
: key_code
= WXK_NUMPAD_EQUAL
; break;
575 case GDK_KP_Multiply
: key_code
= WXK_NUMPAD_MULTIPLY
; break;
576 case GDK_KP_Add
: key_code
= WXK_NUMPAD_ADD
; break;
577 case GDK_KP_Separator
: key_code
= WXK_NUMPAD_SEPARATOR
; break;
578 case GDK_KP_Subtract
: key_code
= WXK_NUMPAD_SUBTRACT
; break;
579 case GDK_KP_Decimal
: key_code
= WXK_NUMPAD_DECIMAL
; break;
580 case GDK_KP_Divide
: key_code
= WXK_NUMPAD_DIVIDE
; break;
582 case GDK_F1
: key_code
= WXK_F1
; break;
583 case GDK_F2
: key_code
= WXK_F2
; break;
584 case GDK_F3
: key_code
= WXK_F3
; break;
585 case GDK_F4
: key_code
= WXK_F4
; break;
586 case GDK_F5
: key_code
= WXK_F5
; break;
587 case GDK_F6
: key_code
= WXK_F6
; break;
588 case GDK_F7
: key_code
= WXK_F7
; break;
589 case GDK_F8
: key_code
= WXK_F8
; break;
590 case GDK_F9
: key_code
= WXK_F9
; break;
591 case GDK_F10
: key_code
= WXK_F10
; break;
592 case GDK_F11
: key_code
= WXK_F11
; break;
593 case GDK_F12
: key_code
= WXK_F12
; break;
596 // do we have the translation?
597 if ( event
->length
== 1 )
599 keysym
= (KeySym
)event
->string
[0];
601 else if ( (keysym
& 0xFF) != keysym
)
603 // non ASCII key, what to do?
605 if ( event
->type
== GDK_KEY_RELEASE
)
607 // reuse the one from the last keypress if any
608 if ( keysym
== s_lastKeyPress
.keysym
)
610 key_code
= s_lastKeyPress
.keycode
;
617 // ignore this one, we don't know it
620 //else: ASCII key, ok
622 guint upper
= gdk_keyval_to_upper( (guint
)keysym
);
623 key_code
= upper
? upper
: keysym
;
625 if ( event
->type
== GDK_KEY_PRESS
)
627 // remember it to be reused below later
628 s_lastKeyPress
.keysym
= keysym
;
629 s_lastKeyPress
.keycode
= key_code
;
637 static long map_to_wx_keysym( GdkEventKey
*event
)
639 KeySym keysym
= event
->keyval
;
644 case GDK_Menu
: key_code
= WXK_MENU
; break;
645 case GDK_Help
: key_code
= WXK_HELP
; break;
646 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
647 case GDK_ISO_Left_Tab
:
648 case GDK_Tab
: key_code
= WXK_TAB
; break;
649 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
650 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
651 case GDK_Return
: key_code
= WXK_RETURN
; break;
652 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
653 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
654 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
655 case GDK_Delete
: key_code
= WXK_DELETE
; break;
656 case GDK_Home
: key_code
= WXK_HOME
; break;
657 case GDK_Left
: key_code
= WXK_LEFT
; break;
658 case GDK_Up
: key_code
= WXK_UP
; break;
659 case GDK_Right
: key_code
= WXK_RIGHT
; break;
660 case GDK_Down
: key_code
= WXK_DOWN
; break;
661 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
662 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
663 case GDK_Next
: key_code
= WXK_NEXT
; break;
664 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
665 case GDK_End
: key_code
= WXK_END
; break;
666 case GDK_Begin
: key_code
= WXK_HOME
; break;
667 case GDK_Select
: key_code
= WXK_SELECT
; break;
668 case GDK_Print
: key_code
= WXK_PRINT
; break;
669 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
670 case GDK_Insert
: key_code
= WXK_INSERT
; break;
671 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
673 case GDK_KP_0
: key_code
= '0'; break;
674 case GDK_KP_1
: key_code
= '1'; break;
675 case GDK_KP_2
: key_code
= '2'; break;
676 case GDK_KP_3
: key_code
= '3'; break;
677 case GDK_KP_4
: key_code
= '4'; break;
678 case GDK_KP_5
: key_code
= '5'; break;
679 case GDK_KP_6
: key_code
= '6'; break;
680 case GDK_KP_7
: key_code
= '7'; break;
681 case GDK_KP_8
: key_code
= '8'; break;
682 case GDK_KP_9
: key_code
= '9'; break;
683 case GDK_KP_Space
: key_code
= ' '; break;
684 case GDK_KP_Tab
: key_code
= WXK_TAB
; break; /* or '\t' ??? */
685 case GDK_KP_Enter
: key_code
= WXK_RETURN
; break; /* or '\r' ??? */
686 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
687 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
688 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
689 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
690 case GDK_KP_Home
: key_code
= WXK_HOME
; break;
691 case GDK_KP_Left
: key_code
= WXK_LEFT
; break;
692 case GDK_KP_Up
: key_code
= WXK_UP
; break;
693 case GDK_KP_Right
: key_code
= WXK_RIGHT
; break;
694 case GDK_KP_Down
: key_code
= WXK_DOWN
; break;
695 case GDK_KP_Prior
: key_code
= WXK_PRIOR
; break;
696 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
697 case GDK_KP_Next
: key_code
= WXK_NEXT
; break;
698 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
699 case GDK_KP_End
: key_code
= WXK_END
; break;
700 case GDK_KP_Begin
: key_code
= WXK_HOME
; break;
701 case GDK_KP_Insert
: key_code
= WXK_INSERT
; break;
702 case GDK_KP_Delete
: key_code
= WXK_DELETE
; break;
703 case GDK_KP_Equal
: key_code
= '='; break;
704 case GDK_KP_Multiply
: key_code
= '*'; break;
705 case GDK_KP_Add
: key_code
= '+'; break;
706 case GDK_KP_Separator
: key_code
= ','; break;
707 case GDK_KP_Subtract
: key_code
= '-'; break;
708 case GDK_KP_Decimal
: key_code
= '.'; break;
709 case GDK_KP_Divide
: key_code
= '/'; break;
711 case GDK_F1
: key_code
= WXK_F1
; break;
712 case GDK_F2
: key_code
= WXK_F2
; break;
713 case GDK_F3
: key_code
= WXK_F3
; break;
714 case GDK_F4
: key_code
= WXK_F4
; break;
715 case GDK_F5
: key_code
= WXK_F5
; break;
716 case GDK_F6
: key_code
= WXK_F6
; break;
717 case GDK_F7
: key_code
= WXK_F7
; break;
718 case GDK_F8
: key_code
= WXK_F8
; break;
719 case GDK_F9
: key_code
= WXK_F9
; break;
720 case GDK_F10
: key_code
= WXK_F10
; break;
721 case GDK_F11
: key_code
= WXK_F11
; break;
722 case GDK_F12
: key_code
= WXK_F12
; break;
724 if (event
->length
== 1)
726 key_code
= (unsigned char)*event
->string
;
728 else if ((keysym
& 0xFF) == keysym
)
730 key_code
= (guint
)keysym
;
737 //-----------------------------------------------------------------------------
738 // "size_request" of m_widget
739 //-----------------------------------------------------------------------------
741 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
744 win
->GetSize( &w
, &h
);
748 requisition
->height
= h
;
749 requisition
->width
= w
;
752 //-----------------------------------------------------------------------------
753 // "expose_event" of m_wxwindow
754 //-----------------------------------------------------------------------------
756 static int gtk_window_expose_callback( GtkWidget
*widget
,
757 GdkEventExpose
*gdk_event
,
763 wxapp_install_idle_handler();
766 if (win->GetName() == wxT("panel"))
768 wxPrintf( wxT("OnExpose from ") );
769 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
770 wxPrintf( win->GetClassInfo()->GetClassName() );
771 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
772 (int)gdk_event->area.y,
773 (int)gdk_event->area.width,
774 (int)gdk_event->area.height );
778 #ifndef __WXUNIVERSAL__
779 GtkPizza
*pizza
= GTK_PIZZA (widget
);
781 if (win
->GetThemeEnabled())
783 wxWindow
*parent
= win
->GetParent();
784 while (parent
&& !parent
->IsTopLevel())
785 parent
= parent
->GetParent();
789 gtk_paint_flat_box (parent
->m_widget
->style
,
800 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
802 gdk_event
->area
.width
,
803 gdk_event
->area
.height
);
805 // Actual redrawing takes place in idle time.
811 //-----------------------------------------------------------------------------
812 // "event" of m_wxwindow
813 //-----------------------------------------------------------------------------
815 // GTK thinks it is clever and filters out a certain amount of "unneeded"
816 // expose events. We need them, of course, so we override the main event
817 // procedure in GtkWidget by giving our own handler for all system events.
818 // There, we look for expose events ourselves whereas all other events are
821 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
822 GdkEventExpose
*event
,
825 if (event
->type
== GDK_EXPOSE
)
827 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
834 //-----------------------------------------------------------------------------
835 // "draw" of m_wxwindow
836 //-----------------------------------------------------------------------------
838 // This callback is a complete replacement of the gtk_pizza_draw() function,
841 static void gtk_window_draw_callback( GtkWidget
*widget
,
848 wxapp_install_idle_handler();
850 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
851 // there are no child windows.
852 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
853 (win
->GetChildren().GetCount() == 0))
859 if (win->GetName() == wxT("panel"))
861 wxPrintf( wxT("OnDraw from ") );
862 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
863 wxPrintf( win->GetClassInfo()->GetClassName() );
864 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
871 #ifndef __WXUNIVERSAL__
872 GtkPizza
*pizza
= GTK_PIZZA (widget
);
874 if (win
->GetThemeEnabled())
876 wxWindow
*parent
= win
->GetParent();
877 while (parent
&& !parent
->IsTopLevel())
878 parent
= parent
->GetParent();
882 gtk_paint_flat_box (parent
->m_widget
->style
,
893 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
894 (pizza
->clear_on_draw
))
896 gdk_window_clear_area( pizza
->bin_window
,
897 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
901 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
903 // Actual redrawing takes place in idle time.
907 #ifndef __WXUNIVERSAL__
908 // Redraw child widgets
909 GList
*children
= pizza
->children
;
912 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
913 children
= children
->next
;
915 GdkRectangle child_area
;
916 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
918 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
924 //-----------------------------------------------------------------------------
925 // "key_press_event" from any window
926 //-----------------------------------------------------------------------------
928 // turn on to see the key event codes on the console
929 #undef DEBUG_KEY_EVENTS
931 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
932 GdkEventKey
*gdk_event
,
938 wxapp_install_idle_handler();
940 if (!win
->m_hasVMT
) return FALSE
;
941 if (g_blockEventsOnDrag
) return FALSE
;
946 GdkModifierType state
;
947 if (gdk_event
->window
)
948 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
952 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
954 #ifdef DEBUG_KEY_EVENTS
955 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
956 #endif // DEBUG_KEY_EVENTS
958 /* sending unknown key events doesn't really make sense */
962 wxKeyEvent
event( wxEVT_KEY_DOWN
);
963 event
.SetTimestamp( gdk_event
->time
);
964 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
965 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
966 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
967 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
968 event
.m_keyCode
= key_code
;
969 event
.m_scanCode
= gdk_event
->keyval
;
972 event
.SetEventObject( win
);
973 ret
= win
->GetEventHandler()->ProcessEvent( event
);
978 wxWindowGTK
*ancestor
= win
;
981 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
984 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
985 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
988 if (ancestor
->IsTopLevel())
990 ancestor
= ancestor
->GetParent();
993 #endif // wxUSE_ACCEL
995 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
996 will only be sent if it is not in an accelerator table. */
999 key_code
= map_to_wx_keysym( gdk_event
);
1003 #ifdef DEBUG_KEY_EVENTS
1004 wxPrintf(_T("Char event: %ld\n"), key_code
);
1005 #endif // DEBUG_KEY_EVENTS
1007 // reuse the ame event object, just change its type and use the
1008 // translated keycode instead of the raw one
1009 event
.SetEventType(wxEVT_CHAR
);
1010 event
.m_keyCode
= key_code
;
1012 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1016 /* win is a control: tab can be propagated up */
1018 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1019 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1020 // have this style, yet choose not to process this particular TAB in which
1021 // case TAB must still work as a navigational character
1023 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1025 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1027 wxNavigationKeyEvent new_event
;
1028 new_event
.SetEventObject( win
->GetParent() );
1029 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1030 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1031 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1032 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1033 new_event
.SetCurrentFocus( win
);
1034 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1037 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1039 (gdk_event
->keyval
== GDK_Escape
) )
1041 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1042 new_event
.SetEventObject( win
);
1043 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1047 #if 0 // (GTK_MINOR_VERSION > 0)
1048 /* Pressing F10 will activate the menu bar of the top frame. */
1050 (gdk_event
->keyval
== GDK_F10
) )
1052 wxWindowGTK
*ancestor
= win
;
1055 if (wxIsKindOf(ancestor
,wxFrame
))
1057 wxFrame
*frame
= (wxFrame
*) ancestor
;
1058 wxMenuBar
*menubar
= frame
->GetMenuBar();
1061 wxNode
*node
= menubar
->GetMenus().First();
1064 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1065 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1071 ancestor
= ancestor
->GetParent();
1078 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1085 //-----------------------------------------------------------------------------
1086 // "key_release_event" from any window
1087 //-----------------------------------------------------------------------------
1089 static gint
gtk_window_key_release_callback( GtkWidget
*widget
, GdkEventKey
*gdk_event
, wxWindowGTK
*win
)
1094 wxapp_install_idle_handler();
1096 if (!win
->m_hasVMT
) return FALSE
;
1097 if (g_blockEventsOnDrag
) return FALSE
;
1099 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
1101 #ifdef DEBUG_KEY_EVENTS
1102 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
1103 #endif // DEBUG_KEY_EVENTS
1105 /* sending unknown key events doesn't really make sense */
1106 if (key_code
== 0) return FALSE
;
1110 GdkModifierType state
;
1111 if (gdk_event
->window
)
1112 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1114 wxKeyEvent
event( wxEVT_KEY_UP
);
1115 event
.SetTimestamp( gdk_event
->time
);
1116 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1117 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1118 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1119 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1120 event
.m_keyCode
= key_code
;
1121 event
.m_scanCode
= gdk_event
->keyval
;
1124 event
.SetEventObject( win
);
1126 if (win
->GetEventHandler()->ProcessEvent( event
))
1128 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1135 // ============================================================================
1137 // ============================================================================
1139 // init wxMouseEvent with the info from gdk_event
1140 #define InitMouseEvent(win, event, gdk_event) \
1142 event.SetTimestamp( gdk_event->time ); \
1143 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1144 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1145 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1146 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1147 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1148 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1149 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1151 wxPoint pt = win->GetClientAreaOrigin(); \
1152 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1153 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1156 // ----------------------------------------------------------------------------
1157 // mouse event processing helper
1158 // ----------------------------------------------------------------------------
1160 static void AdjustEventButtonState(wxMouseEvent
& event
)
1162 // GDK reports the old state of the button for a button press event, but
1163 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1164 // for a LEFT_DOWN event, not FALSE, so we will invert
1165 // left/right/middleDown for the corresponding click events
1167 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1168 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1169 (event
.GetEventType() == wxEVT_LEFT_UP
))
1171 event
.m_leftDown
= !event
.m_leftDown
;
1175 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1176 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1177 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1179 event
.m_middleDown
= !event
.m_middleDown
;
1183 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1184 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1185 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1187 event
.m_rightDown
= !event
.m_rightDown
;
1192 //-----------------------------------------------------------------------------
1193 // "button_press_event"
1194 //-----------------------------------------------------------------------------
1196 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1201 wxapp_install_idle_handler();
1204 wxPrintf( wxT("1) OnButtonPress from ") );
1205 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1206 wxPrintf( win->GetClassInfo()->GetClassName() );
1207 wxPrintf( wxT(".\n") );
1209 if (!win
->m_hasVMT
) return FALSE
;
1210 if (g_blockEventsOnDrag
) return TRUE
;
1211 if (g_blockEventsOnScroll
) return TRUE
;
1213 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1215 if (win
->m_wxwindow
)
1217 if (GTK_WIDGET_CAN_FOCUS(win
->m_wxwindow
) && !GTK_WIDGET_HAS_FOCUS (win
->m_wxwindow
) )
1219 gtk_widget_grab_focus (win
->m_wxwindow
);
1222 wxPrintf( wxT("GrabFocus from ") );
1223 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1224 wxPrintf( win->GetClassInfo()->GetClassName() );
1225 wxPrintf( wxT(".\n") );
1231 wxEventType event_type
= wxEVT_NULL
;
1233 if (gdk_event
->button
== 1)
1235 switch (gdk_event
->type
)
1237 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1238 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1242 else if (gdk_event
->button
== 2)
1244 switch (gdk_event
->type
)
1246 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1247 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1251 else if (gdk_event
->button
== 3)
1253 switch (gdk_event
->type
)
1255 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1256 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1261 if ( event_type
== wxEVT_NULL
)
1263 // unknown mouse button or click type
1267 wxMouseEvent
event( event_type
);
1268 InitMouseEvent( win
, event
, gdk_event
);
1270 AdjustEventButtonState(event
);
1272 // wxListBox actually get mouse events from the item
1274 if (win
->m_isListBox
)
1276 event
.m_x
+= widget
->allocation
.x
;
1277 event
.m_y
+= widget
->allocation
.y
;
1280 // Some control don't have their own X window and thus cannot get
1283 if (!g_captureWindow
)
1285 wxCoord x
= event
.m_x
;
1286 wxCoord y
= event
.m_y
;
1287 if (win
->m_wxwindow
)
1289 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1290 x
+= pizza
->xoffset
;
1291 y
+= pizza
->yoffset
;
1294 wxNode
*node
= win
->GetChildren().First();
1297 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1299 node
= node
->Next();
1300 if (!child
->IsShown())
1303 if (child
->m_isStaticBox
)
1305 // wxStaticBox is transparent in the box itself
1306 int xx1
= child
->m_x
;
1307 int yy1
= child
->m_y
;
1308 int xx2
= child
->m_x
+ child
->m_width
;
1309 int yy2
= child
->m_x
+ child
->m_height
;
1312 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1314 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1316 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1318 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1321 event
.m_x
-= child
->m_x
;
1322 event
.m_y
-= child
->m_y
;
1329 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1330 (child
->m_x
<= x
) &&
1331 (child
->m_y
<= y
) &&
1332 (child
->m_x
+child
->m_width
>= x
) &&
1333 (child
->m_y
+child
->m_height
>= y
))
1336 event
.m_x
-= child
->m_x
;
1337 event
.m_y
-= child
->m_y
;
1344 event
.SetEventObject( win
);
1346 gs_timeLastClick
= gdk_event
->time
;
1349 wxPrintf( wxT("2) OnButtonPress from ") );
1350 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1351 wxPrintf( win->GetClassInfo()->GetClassName() );
1352 wxPrintf( wxT(".\n") );
1355 if (win
->GetEventHandler()->ProcessEvent( event
))
1357 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1364 //-----------------------------------------------------------------------------
1365 // "button_release_event"
1366 //-----------------------------------------------------------------------------
1368 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1373 wxapp_install_idle_handler();
1375 if (!win
->m_hasVMT
) return FALSE
;
1376 if (g_blockEventsOnDrag
) return FALSE
;
1377 if (g_blockEventsOnScroll
) return FALSE
;
1379 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1382 printf( "OnButtonRelease from " );
1383 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1384 printf( win->GetClassInfo()->GetClassName() );
1388 wxEventType event_type
= wxEVT_NULL
;
1390 switch (gdk_event
->button
)
1392 case 1: event_type
= wxEVT_LEFT_UP
; break;
1393 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1394 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1395 default: return FALSE
;
1398 wxMouseEvent
event( event_type
);
1399 InitMouseEvent( win
, event
, gdk_event
);
1401 AdjustEventButtonState(event
);
1403 // wxListBox actually get mouse events from the item
1405 if (win
->m_isListBox
)
1407 event
.m_x
+= widget
->allocation
.x
;
1408 event
.m_y
+= widget
->allocation
.y
;
1411 // Some control don't have their own X window and thus cannot get
1414 if (!g_captureWindow
)
1416 wxCoord x
= event
.m_x
;
1417 wxCoord y
= event
.m_y
;
1418 if (win
->m_wxwindow
)
1420 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1421 x
+= pizza
->xoffset
;
1422 y
+= pizza
->yoffset
;
1425 wxNode
*node
= win
->GetChildren().First();
1428 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1430 node
= node
->Next();
1431 if (!child
->IsShown())
1434 if (child
->m_isStaticBox
)
1436 // wxStaticBox is transparent in the box itself
1437 int xx1
= child
->m_x
;
1438 int yy1
= child
->m_y
;
1439 int xx2
= child
->m_x
+ child
->m_width
;
1440 int yy2
= child
->m_x
+ child
->m_height
;
1443 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1445 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1447 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1449 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1452 event
.m_x
-= child
->m_x
;
1453 event
.m_y
-= child
->m_y
;
1460 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1461 (child
->m_x
<= x
) &&
1462 (child
->m_y
<= y
) &&
1463 (child
->m_x
+child
->m_width
>= x
) &&
1464 (child
->m_y
+child
->m_height
>= y
))
1467 event
.m_x
-= child
->m_x
;
1468 event
.m_y
-= child
->m_y
;
1475 event
.SetEventObject( win
);
1477 if (win
->GetEventHandler()->ProcessEvent( event
))
1479 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1486 //-----------------------------------------------------------------------------
1487 // "motion_notify_event"
1488 //-----------------------------------------------------------------------------
1490 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1491 GdkEventMotion
*gdk_event
,
1497 wxapp_install_idle_handler();
1499 if (!win
->m_hasVMT
) return FALSE
;
1500 if (g_blockEventsOnDrag
) return FALSE
;
1501 if (g_blockEventsOnScroll
) return FALSE
;
1503 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1505 if (gdk_event
->is_hint
)
1509 GdkModifierType state
;
1510 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1516 printf( "OnMotion from " );
1517 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1518 printf( win->GetClassInfo()->GetClassName() );
1522 wxMouseEvent
event( wxEVT_MOTION
);
1523 InitMouseEvent(win
, event
, gdk_event
);
1525 if ( g_captureWindow
)
1527 // synthetize a mouse enter or leave event if needed
1528 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1529 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1530 if ( hasMouse
!= g_captureWindowHasMouse
)
1532 // the mouse changed window
1533 g_captureWindowHasMouse
= hasMouse
;
1535 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1536 : wxEVT_LEAVE_WINDOW
);
1537 InitMouseEvent(win
, event
, gdk_event
);
1538 event
.SetEventObject(win
);
1539 win
->GetEventHandler()->ProcessEvent(event
);
1544 // Some control don't have their own X window and thus cannot get
1547 wxCoord x
= event
.m_x
;
1548 wxCoord y
= event
.m_y
;
1549 if (win
->m_wxwindow
)
1551 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1552 x
+= pizza
->xoffset
;
1553 y
+= pizza
->yoffset
;
1556 wxNode
*node
= win
->GetChildren().First();
1559 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1561 node
= node
->Next();
1562 if (!child
->IsShown())
1565 if (child
->m_isStaticBox
)
1567 // wxStaticBox is transparent in the box itself
1568 int xx1
= child
->m_x
;
1569 int yy1
= child
->m_y
;
1570 int xx2
= child
->m_x
+ child
->m_width
;
1571 int yy2
= child
->m_x
+ child
->m_height
;
1574 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1576 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1578 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1580 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1583 event
.m_x
-= child
->m_x
;
1584 event
.m_y
-= child
->m_y
;
1591 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1592 (child
->m_x
<= x
) &&
1593 (child
->m_y
<= y
) &&
1594 (child
->m_x
+child
->m_width
>= x
) &&
1595 (child
->m_y
+child
->m_height
>= y
))
1598 event
.m_x
-= child
->m_x
;
1599 event
.m_y
-= child
->m_y
;
1606 event
.SetEventObject( win
);
1608 if (win
->GetEventHandler()->ProcessEvent( event
))
1610 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1617 //-----------------------------------------------------------------------------
1619 //-----------------------------------------------------------------------------
1621 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1622 GdkEvent
*WXUNUSED(event
),
1628 wxapp_install_idle_handler();
1630 if (!win
->m_hasVMT
) return FALSE
;
1631 if (g_blockEventsOnDrag
) return FALSE
;
1633 switch ( g_sendActivateEvent
)
1636 // we've got focus from outside, synthetize wxActivateEvent
1637 g_sendActivateEvent
= 1;
1641 // another our window just lost focus, it was already ours before
1642 // - don't send any wxActivateEvent
1643 g_sendActivateEvent
= -1;
1648 g_focusWindow
= win
;
1651 wxPrintf( "OnSetFocus from " );
1652 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
1653 wxPrintf( win
->GetClassInfo()->GetClassName() );
1657 // notify the parent keeping track of focus for the kbd navigation
1658 // purposes that we got it
1659 wxChildFocusEvent
eventFocus(win
);
1660 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1664 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1668 // caret needs to be informed about focus change
1669 wxCaret
*caret
= win
->GetCaret();
1672 caret
->OnSetFocus();
1674 #endif // wxUSE_CARET
1676 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1677 if ( active
!= g_activeFrame
)
1679 if ( g_activeFrame
)
1681 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1682 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1683 event
.SetEventObject(g_activeFrame
);
1684 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1687 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1688 g_activeFrame
= active
;
1689 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1690 event
.SetEventObject(g_activeFrame
);
1691 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1693 g_activeFrameLostFocus
= FALSE
;
1696 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1697 event
.SetEventObject( win
);
1699 if (win
->GetEventHandler()->ProcessEvent( event
))
1701 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1709 //-----------------------------------------------------------------------------
1710 // "focus_out_event"
1711 //-----------------------------------------------------------------------------
1713 static GtkWidget
*gs_widgetLastFocus
= NULL
;
1715 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEvent
*WXUNUSED(event
), wxWindowGTK
*win
)
1720 wxapp_install_idle_handler();
1722 if (!win
->m_hasVMT
) return FALSE
;
1723 if (g_blockEventsOnDrag
) return FALSE
;
1725 // VZ: this is really weird but GTK+ seems to call us from inside
1726 // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
1727 // this widget and then "focus_in". This is totally unexpected and
1728 // completely breaks wxUniv code so ignore this dummy event (we can't
1729 // be losing focus if we're about to acquire it!)
1730 if ( widget
== gs_widgetLastFocus
)
1732 gs_widgetLastFocus
= NULL
;
1737 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1739 // VZ: commenting this out because it does happen (although not easy
1740 // to reproduce, I only see it when using wxMiniFrame and not
1741 // always) and makes using Mahogany quite annoying
1743 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1744 wxT("unfocusing window that hasn't gained focus properly") )
1747 g_activeFrameLostFocus
= TRUE
;
1750 // if the focus goes out of our app alltogether, OnIdle() will send
1751 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1752 // g_sendActivateEvent to -1
1753 g_sendActivateEvent
= 0;
1755 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1759 g_focusWindow
= (wxWindowGTK
*)NULL
;
1762 wxPrintf( "OnKillFocus from " );
1763 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
1764 wxPrintf( win
->GetClassInfo()->GetClassName() );
1774 // caret needs to be informed about focus change
1775 wxCaret
*caret
= win
->GetCaret();
1778 caret
->OnKillFocus();
1780 #endif // wxUSE_CARET
1782 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1783 event
.SetEventObject( win
);
1785 if (win
->GetEventHandler()->ProcessEvent( event
))
1787 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1794 //-----------------------------------------------------------------------------
1795 // "enter_notify_event"
1796 //-----------------------------------------------------------------------------
1798 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1803 wxapp_install_idle_handler();
1805 if (!win
->m_hasVMT
) return FALSE
;
1806 if (g_blockEventsOnDrag
) return FALSE
;
1808 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1810 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1811 event
.SetTimestamp( gdk_event
->time
);
1812 event
.SetEventObject( win
);
1816 GdkModifierType state
= (GdkModifierType
)0;
1818 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1820 InitMouseEvent(win
, event
, gdk_event
);
1821 wxPoint pt
= win
->GetClientAreaOrigin();
1822 event
.m_x
= x
+ pt
.x
;
1823 event
.m_y
= y
+ pt
.y
;
1825 if (win
->GetEventHandler()->ProcessEvent( event
))
1827 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1834 //-----------------------------------------------------------------------------
1835 // "leave_notify_event"
1836 //-----------------------------------------------------------------------------
1838 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1843 wxapp_install_idle_handler();
1845 if (!win
->m_hasVMT
) return FALSE
;
1846 if (g_blockEventsOnDrag
) return FALSE
;
1848 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1850 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1851 event
.SetTimestamp( gdk_event
->time
);
1852 event
.SetEventObject( win
);
1856 GdkModifierType state
= (GdkModifierType
)0;
1858 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1860 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
);
1861 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
);
1862 event
.m_altDown
= (state
& GDK_MOD1_MASK
);
1863 event
.m_metaDown
= (state
& GDK_MOD2_MASK
);
1864 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
);
1865 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
);
1866 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
);
1868 wxPoint pt
= win
->GetClientAreaOrigin();
1869 event
.m_x
= x
+ pt
.x
;
1870 event
.m_y
= y
+ pt
.y
;
1872 if (win
->GetEventHandler()->ProcessEvent( event
))
1874 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1881 //-----------------------------------------------------------------------------
1882 // "value_changed" from m_vAdjust
1883 //-----------------------------------------------------------------------------
1885 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
, wxWindowGTK
*win
)
1890 wxapp_install_idle_handler();
1892 if (g_blockEventsOnDrag
) return;
1894 if (!win
->m_hasVMT
) return;
1896 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1897 if (fabs(diff
) < 0.2) return;
1899 win
->m_oldVerticalPos
= adjust
->value
;
1901 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1902 GtkRange
*range
= GTK_RANGE( scrolledWindow
->vscrollbar
);
1904 wxEventType command
= wxEVT_SCROLLWIN_THUMBTRACK
;
1905 if (range
->scroll_type
== GTK_SCROLL_STEP_BACKWARD
) command
= wxEVT_SCROLLWIN_LINEUP
;
1906 else if (range
->scroll_type
== GTK_SCROLL_STEP_FORWARD
) command
= wxEVT_SCROLLWIN_LINEDOWN
;
1907 else if (range
->scroll_type
== GTK_SCROLL_PAGE_BACKWARD
) command
= wxEVT_SCROLLWIN_PAGEUP
;
1908 else if (range
->scroll_type
== GTK_SCROLL_PAGE_FORWARD
) command
= wxEVT_SCROLLWIN_PAGEDOWN
;
1910 int value
= (int)(adjust
->value
+0.5);
1912 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1913 event
.SetEventObject( win
);
1914 win
->GetEventHandler()->ProcessEvent( event
);
1917 //-----------------------------------------------------------------------------
1918 // "value_changed" from m_hAdjust
1919 //-----------------------------------------------------------------------------
1921 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
, wxWindowGTK
*win
)
1926 wxapp_install_idle_handler();
1928 if (g_blockEventsOnDrag
) return;
1929 if (!win
->m_hasVMT
) return;
1931 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1932 if (fabs(diff
) < 0.2) return;
1934 win
->m_oldHorizontalPos
= adjust
->value
;
1936 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1937 GtkRange
*range
= GTK_RANGE( scrolledWindow
->hscrollbar
);
1939 wxEventType command
= wxEVT_SCROLLWIN_THUMBTRACK
;
1940 if (range
->scroll_type
== GTK_SCROLL_STEP_BACKWARD
) command
= wxEVT_SCROLLWIN_LINEUP
;
1941 else if (range
->scroll_type
== GTK_SCROLL_STEP_FORWARD
) command
= wxEVT_SCROLLWIN_LINEDOWN
;
1942 else if (range
->scroll_type
== GTK_SCROLL_PAGE_BACKWARD
) command
= wxEVT_SCROLLWIN_PAGEUP
;
1943 else if (range
->scroll_type
== GTK_SCROLL_PAGE_FORWARD
) command
= wxEVT_SCROLLWIN_PAGEDOWN
;
1945 int value
= (int)(adjust
->value
+0.5);
1947 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1948 event
.SetEventObject( win
);
1949 win
->GetEventHandler()->ProcessEvent( event
);
1952 //-----------------------------------------------------------------------------
1953 // "button_press_event" from scrollbar
1954 //-----------------------------------------------------------------------------
1956 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1957 GdkEventButton
*gdk_event
,
1963 wxapp_install_idle_handler();
1966 g_blockEventsOnScroll
= TRUE
;
1967 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1972 //-----------------------------------------------------------------------------
1973 // "button_release_event" from scrollbar
1974 //-----------------------------------------------------------------------------
1976 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1977 GdkEventButton
*WXUNUSED(gdk_event
),
1982 // don't test here as we can release the mouse while being over
1983 // a different window than the slider
1985 // if (gdk_event->window != widget->slider) return FALSE;
1987 g_blockEventsOnScroll
= FALSE
;
1989 if (win
->m_isScrolling
)
1991 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1995 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1996 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1998 value
= (int)(win
->m_hAdjust
->value
+0.5);
2001 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2003 value
= (int)(win
->m_vAdjust
->value
+0.5);
2007 wxScrollWinEvent
event( command
, value
, dir
);
2008 event
.SetEventObject( win
);
2009 win
->GetEventHandler()->ProcessEvent( event
);
2012 win
->m_isScrolling
= FALSE
;
2017 // ----------------------------------------------------------------------------
2018 // this wxWindowBase function is implemented here (in platform-specific file)
2019 // because it is static and so couldn't be made virtual
2020 // ----------------------------------------------------------------------------
2022 wxWindow
*wxWindowBase::FindFocus()
2024 // the cast is necessary when we compile in wxUniversal mode
2025 return (wxWindow
*)g_focusWindow
;
2028 //-----------------------------------------------------------------------------
2029 // "realize" from m_widget
2030 //-----------------------------------------------------------------------------
2032 /* We cannot set colours and fonts before the widget has
2033 been realized, so we do this directly after realization. */
2036 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2041 wxapp_install_idle_handler();
2043 if (win
->m_delayedBackgroundColour
)
2044 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2046 if (win
->m_delayedForegroundColour
)
2047 win
->SetForegroundColour( win
->GetForegroundColour() );
2049 wxWindowCreateEvent
event( win
);
2050 event
.SetEventObject( win
);
2051 win
->GetEventHandler()->ProcessEvent( event
);
2056 //-----------------------------------------------------------------------------
2058 //-----------------------------------------------------------------------------
2061 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2062 GtkAllocation
*WXUNUSED(alloc
),
2066 wxapp_install_idle_handler();
2068 if (!win
->m_hasScrolling
) return;
2070 int client_width
= 0;
2071 int client_height
= 0;
2072 win
->GetClientSize( &client_width
, &client_height
);
2073 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2076 win
->m_oldClientWidth
= client_width
;
2077 win
->m_oldClientHeight
= client_height
;
2079 if (!win
->m_nativeSizeEvent
)
2081 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2082 event
.SetEventObject( win
);
2083 win
->GetEventHandler()->ProcessEvent( event
);
2089 #define WXUNUSED_UNLESS_XIM(param) param
2091 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2094 /* Resize XIM window */
2097 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2098 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2099 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2102 wxapp_install_idle_handler();
2108 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2112 gdk_window_get_size (widget
->window
, &width
, &height
);
2113 win
->m_icattr
->preedit_area
.width
= width
;
2114 win
->m_icattr
->preedit_area
.height
= height
;
2115 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2120 //-----------------------------------------------------------------------------
2121 // "realize" from m_wxwindow
2122 //-----------------------------------------------------------------------------
2124 /* Initialize XIM support */
2127 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2128 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2131 wxapp_install_idle_handler();
2134 if (win
->m_ic
) return FALSE
;
2135 if (!widget
) return FALSE
;
2136 if (!gdk_im_ready()) return FALSE
;
2138 win
->m_icattr
= gdk_ic_attr_new();
2139 if (!win
->m_icattr
) return FALSE
;
2143 GdkColormap
*colormap
;
2144 GdkICAttr
*attr
= win
->m_icattr
;
2145 unsigned attrmask
= GDK_IC_ALL_REQ
;
2147 GdkIMStyle supported_style
= (GdkIMStyle
)
2148 (GDK_IM_PREEDIT_NONE
|
2149 GDK_IM_PREEDIT_NOTHING
|
2150 GDK_IM_PREEDIT_POSITION
|
2151 GDK_IM_STATUS_NONE
|
2152 GDK_IM_STATUS_NOTHING
);
2154 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2155 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2157 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2158 attr
->client_window
= widget
->window
;
2160 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2161 gtk_widget_get_default_colormap ())
2163 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2164 attr
->preedit_colormap
= colormap
;
2167 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2168 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2169 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2170 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2172 switch (style
& GDK_IM_PREEDIT_MASK
)
2174 case GDK_IM_PREEDIT_POSITION
:
2175 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2177 g_warning ("over-the-spot style requires fontset");
2181 gdk_window_get_size (widget
->window
, &width
, &height
);
2183 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2184 attr
->spot_location
.x
= 0;
2185 attr
->spot_location
.y
= height
;
2186 attr
->preedit_area
.x
= 0;
2187 attr
->preedit_area
.y
= 0;
2188 attr
->preedit_area
.width
= width
;
2189 attr
->preedit_area
.height
= height
;
2190 attr
->preedit_fontset
= widget
->style
->font
;
2195 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2197 if (win
->m_ic
== NULL
)
2198 g_warning ("Can't create input context.");
2201 mask
= gdk_window_get_events (widget
->window
);
2202 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2203 gdk_window_set_events (widget
->window
, mask
);
2205 if (GTK_WIDGET_HAS_FOCUS(widget
))
2206 gdk_im_begin (win
->m_ic
, widget
->window
);
2213 //-----------------------------------------------------------------------------
2214 // InsertChild for wxWindowGTK.
2215 //-----------------------------------------------------------------------------
2217 /* Callback for wxWindowGTK. This very strange beast has to be used because
2218 * C++ has no virtual methods in a constructor. We have to emulate a
2219 * virtual function here as wxNotebook requires a different way to insert
2220 * a child in it. I had opted for creating a wxNotebookPage window class
2221 * which would have made this superfluous (such in the MDI window system),
2222 * but no-one was listening to me... */
2224 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2226 /* the window might have been scrolled already, do we
2227 have to adapt the position */
2228 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2229 child
->m_x
+= pizza
->xoffset
;
2230 child
->m_y
+= pizza
->yoffset
;
2232 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2233 GTK_WIDGET(child
->m_widget
),
2240 //-----------------------------------------------------------------------------
2242 //-----------------------------------------------------------------------------
2244 wxWindow
*wxGetActiveWindow()
2246 // the cast is necessary when we compile in wxUniversal mode
2247 return (wxWindow
*)g_focusWindow
;
2250 //-----------------------------------------------------------------------------
2252 //-----------------------------------------------------------------------------
2254 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2256 #ifdef __WXUNIVERSAL__
2257 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2259 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2260 #endif // __WXUNIVERSAL__/__WXGTK__
2262 void wxWindowGTK::Init()
2268 m_widget
= (GtkWidget
*) NULL
;
2269 m_wxwindow
= (GtkWidget
*) NULL
;
2270 m_focusWidget
= (GtkWidget
*) NULL
;
2280 m_needParent
= TRUE
;
2281 m_isBeingDeleted
= FALSE
;
2284 m_nativeSizeEvent
= FALSE
;
2286 m_hasScrolling
= FALSE
;
2287 m_isScrolling
= FALSE
;
2289 m_hAdjust
= (GtkAdjustment
*) NULL
;
2290 m_vAdjust
= (GtkAdjustment
*) NULL
;
2291 m_oldHorizontalPos
= 0.0;
2292 m_oldVerticalPos
= 0.0;
2295 m_widgetStyle
= (GtkStyle
*) NULL
;
2297 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2299 m_isStaticBox
= FALSE
;
2300 m_isRadioButton
= FALSE
;
2301 m_isListBox
= FALSE
;
2303 m_acceptsFocus
= FALSE
;
2305 m_clipPaintRegion
= FALSE
;
2307 m_cursor
= *wxSTANDARD_CURSOR
;
2309 m_delayedForegroundColour
= FALSE
;
2310 m_delayedBackgroundColour
= FALSE
;
2313 m_ic
= (GdkIC
*) NULL
;
2314 m_icattr
= (GdkICAttr
*) NULL
;
2318 wxWindowGTK::wxWindowGTK()
2323 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2328 const wxString
&name
)
2332 Create( parent
, id
, pos
, size
, style
, name
);
2335 bool wxWindowGTK::Create( wxWindow
*parent
,
2340 const wxString
&name
)
2342 if (!PreCreation( parent
, pos
, size
) ||
2343 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2345 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2349 m_insertCallback
= wxInsertChildInWindow
;
2351 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2352 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2354 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2356 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2357 scroll_class
->scrollbar_spacing
= 0;
2359 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2361 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2362 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2364 m_wxwindow
= gtk_pizza_new();
2366 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2368 #ifndef __WXUNIVERSAL__
2369 #if (GTK_MINOR_VERSION > 0)
2370 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2372 if (HasFlag(wxRAISED_BORDER
))
2374 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2376 else if (HasFlag(wxSUNKEN_BORDER
))
2378 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2380 else if (HasFlag(wxSIMPLE_BORDER
))
2382 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2386 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2388 #else // GTK_MINOR_VERSION == 0
2389 GtkViewport
*viewport
= GTK_VIEWPORT(scrolledWindow
->viewport
);
2391 if (HasFlag(wxRAISED_BORDER
))
2393 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_OUT
);
2395 else if (HasFlag(wxSUNKEN_BORDER
))
2397 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_IN
);
2401 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_NONE
);
2403 #endif // GTK_MINOR_VERSION
2404 #endif // __WXUNIVERSAL__
2406 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2407 m_acceptsFocus
= TRUE
;
2409 #if (GTK_MINOR_VERSION == 0)
2410 // shut the viewport up
2411 gtk_viewport_set_hadjustment( viewport
, (GtkAdjustment
*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2412 gtk_viewport_set_vadjustment( viewport
, (GtkAdjustment
*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2413 #endif // GTK_MINOR_VERSION == 0
2415 // I _really_ don't want scrollbars in the beginning
2416 m_vAdjust
->lower
= 0.0;
2417 m_vAdjust
->upper
= 1.0;
2418 m_vAdjust
->value
= 0.0;
2419 m_vAdjust
->step_increment
= 1.0;
2420 m_vAdjust
->page_increment
= 1.0;
2421 m_vAdjust
->page_size
= 5.0;
2422 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2423 m_hAdjust
->lower
= 0.0;
2424 m_hAdjust
->upper
= 1.0;
2425 m_hAdjust
->value
= 0.0;
2426 m_hAdjust
->step_increment
= 1.0;
2427 m_hAdjust
->page_increment
= 1.0;
2428 m_hAdjust
->page_size
= 5.0;
2429 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2431 // these handlers block mouse events to any window during scrolling such as
2432 // motion events and prevent GTK and wxWindows from fighting over where the
2435 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2436 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2438 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2439 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2441 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2442 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2444 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2445 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2447 // these handlers get notified when screen updates are required either when
2448 // scrolling or when the window size (and therefore scrollbar configuration)
2451 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2452 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2453 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2454 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2456 gtk_widget_show( m_wxwindow
);
2459 m_parent
->DoAddChild( this );
2461 m_focusWidget
= m_wxwindow
;
2470 wxWindowGTK::~wxWindowGTK()
2472 if (g_focusWindow
== this)
2473 g_focusWindow
= NULL
;
2475 if (g_activeFrame
== this)
2476 g_activeFrame
= NULL
;
2478 m_isBeingDeleted
= TRUE
;
2487 m_parent
->RemoveChild( this );
2491 gdk_ic_destroy (m_ic
);
2493 gdk_ic_attr_destroy (m_icattr
);
2498 #if DISABLE_STYLE_IF_BROKEN_THEME
2499 // don't delete if it's a pixmap theme style
2500 if (!m_widgetStyle
->engine_data
)
2501 gtk_style_unref( m_widgetStyle
);
2503 m_widgetStyle
= (GtkStyle
*) NULL
;
2508 gtk_widget_destroy( m_wxwindow
);
2509 m_wxwindow
= (GtkWidget
*) NULL
;
2514 gtk_widget_destroy( m_widget
);
2515 m_widget
= (GtkWidget
*) NULL
;
2519 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2521 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2523 /* this turns -1 into 20 so that a minimal window is
2524 visible even although -1,-1 has been given as the
2525 size of the window. the same trick is used in other
2526 ports and should make debugging easier */
2527 m_width
= WidthDefault(size
.x
);
2528 m_height
= HeightDefault(size
.y
);
2533 /* some reasonable defaults */
2538 m_x
= (gdk_screen_width () - m_width
) / 2;
2539 if (m_x
< 10) m_x
= 10;
2543 m_y
= (gdk_screen_height () - m_height
) / 2;
2544 if (m_y
< 10) m_y
= 10;
2551 void wxWindowGTK::PostCreation()
2553 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2559 // these get reported to wxWindows -> wxPaintEvent
2561 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2563 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2564 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2566 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2567 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2569 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2571 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2572 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2576 // these are called when the "sunken" or "raised" borders are drawn */
2577 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2578 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2580 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2581 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2586 if (m_focusWidget
== NULL
)
2587 m_focusWidget
= m_widget
;
2590 if (GetClassInfo() && GetClassInfo()->GetClassName())
2591 wxPrintf( GetClassInfo()->GetClassName() );
2595 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2596 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2598 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2599 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2601 // connect to the various key and mouse handlers
2603 GtkWidget
*connect_widget
= GetConnectWidget();
2605 ConnectWidget( connect_widget
);
2607 /* We cannot set colours, fonts and cursors before the widget has
2608 been realized, so we do this directly after realization */
2609 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2610 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2614 // Catch native resize events
2615 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2616 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2618 // Initialize XIM support
2619 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2620 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2622 // And resize XIM window
2623 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2624 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2627 if (!GTK_IS_COMBO(m_widget
))
2629 // This is needed if we want to add our windows into native
2630 // GTK control, such as the toolbar. With this callback, the
2631 // toolbar gets to know the correct size (the one set by the
2632 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2633 // when moving to GTK 2.0.
2634 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2635 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2641 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2643 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2644 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2646 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2647 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2649 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2650 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2652 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2653 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2655 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2656 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2658 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2659 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2661 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2662 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2665 bool wxWindowGTK::Destroy()
2667 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2671 return wxWindowBase::Destroy();
2674 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2676 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2679 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2681 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2682 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2685 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2688 if (m_resizing
) return; /* I don't like recursions */
2691 int currentX
, currentY
;
2692 GetPosition(¤tX
, ¤tY
);
2697 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2699 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2701 /* don't set the size for children of wxNotebook, just take the values. */
2709 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2711 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2713 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2714 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2715 if (width
!= -1) m_width
= width
;
2716 if (height
!= -1) m_height
= height
;
2720 m_x
= x
+ pizza
->xoffset
;
2721 m_y
= y
+ pizza
->yoffset
;
2726 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2728 if (width
== -1) m_width
= 80;
2731 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2733 if (height
== -1) m_height
= 26;
2736 int minWidth
= GetMinWidth(),
2737 minHeight
= GetMinHeight(),
2738 maxWidth
= GetMaxWidth(),
2739 maxHeight
= GetMaxHeight();
2741 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2742 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2743 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2744 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2747 int bottom_border
= 0;
2749 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2751 /* the default button has a border around it */
2756 DoMoveWindow( m_x
-border
,
2759 m_height
+border
+bottom_border
);
2764 /* Sometimes the client area changes size without the
2765 whole windows's size changing, but if the whole
2766 windows's size doesn't change, no wxSizeEvent will
2767 normally be sent. Here we add an extra test if
2768 the client test has been changed and this will
2770 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2774 wxPrintf( "OnSize sent from " );
2775 if (GetClassInfo() && GetClassInfo()->GetClassName())
2776 wxPrintf( GetClassInfo()->GetClassName() );
2777 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2780 if (!m_nativeSizeEvent
)
2782 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2783 event
.SetEventObject( this );
2784 GetEventHandler()->ProcessEvent( event
);
2790 void wxWindowGTK::OnInternalIdle()
2792 // Update invalidated regions.
2795 // Synthetize activate events.
2796 if ( g_sendActivateEvent
!= -1 )
2798 bool activate
= g_sendActivateEvent
!= 0;
2801 g_sendActivateEvent
= -1;
2803 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2806 if ( g_activeFrameLostFocus
)
2808 if ( g_activeFrame
)
2810 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2811 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2812 event
.SetEventObject(g_activeFrame
);
2813 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2814 g_activeFrame
= NULL
;
2816 g_activeFrameLostFocus
= FALSE
;
2819 wxCursor cursor
= m_cursor
;
2820 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2824 /* I now set the cursor anew in every OnInternalIdle call
2825 as setting the cursor in a parent window also effects the
2826 windows above so that checking for the current cursor is
2831 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2833 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2835 if (!g_globalCursor
.Ok())
2836 cursor
= *wxSTANDARD_CURSOR
;
2838 window
= m_widget
->window
;
2839 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2840 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2846 GdkWindow
*window
= m_widget
->window
;
2847 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2848 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2856 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2858 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2860 if (width
) (*width
) = m_width
;
2861 if (height
) (*height
) = m_height
;
2864 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2866 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2870 SetSize( width
, height
);
2877 #ifndef __WXUNIVERSAL__
2878 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2880 /* when using GTK 1.2 we set the shadow border size to 2 */
2884 if (HasFlag(wxSIMPLE_BORDER
))
2886 /* when using GTK 1.2 we set the simple border size to 1 */
2890 #endif // __WXUNIVERSAL__
2894 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2896 GtkRequisition vscroll_req
;
2897 vscroll_req
.width
= 2;
2898 vscroll_req
.height
= 2;
2899 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2900 (scroll_window
->vscrollbar
, &vscroll_req
);
2902 GtkRequisition hscroll_req
;
2903 hscroll_req
.width
= 2;
2904 hscroll_req
.height
= 2;
2905 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2906 (scroll_window
->hscrollbar
, &hscroll_req
);
2908 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2910 if (scroll_window
->vscrollbar_visible
)
2912 dw
+= vscroll_req
.width
;
2913 dw
+= scroll_class
->scrollbar_spacing
;
2916 if (scroll_window
->hscrollbar_visible
)
2918 dh
+= hscroll_req
.height
;
2919 dh
+= scroll_class
->scrollbar_spacing
;
2923 SetSize( width
+dw
, height
+dh
);
2927 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2929 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2933 if (width
) (*width
) = m_width
;
2934 if (height
) (*height
) = m_height
;
2941 #ifndef __WXUNIVERSAL__
2942 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2944 /* when using GTK 1.2 we set the shadow border size to 2 */
2948 if (HasFlag(wxSIMPLE_BORDER
))
2950 /* when using GTK 1.2 we set the simple border size to 1 */
2954 #endif // __WXUNIVERSAL__
2958 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2960 GtkRequisition vscroll_req
;
2961 vscroll_req
.width
= 2;
2962 vscroll_req
.height
= 2;
2963 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2964 (scroll_window
->vscrollbar
, &vscroll_req
);
2966 GtkRequisition hscroll_req
;
2967 hscroll_req
.width
= 2;
2968 hscroll_req
.height
= 2;
2969 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2970 (scroll_window
->hscrollbar
, &hscroll_req
);
2972 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2974 if (scroll_window
->vscrollbar_visible
)
2976 dw
+= vscroll_req
.width
;
2977 dw
+= scroll_class
->scrollbar_spacing
;
2980 if (scroll_window
->hscrollbar_visible
)
2982 dh
+= hscroll_req
.height
;
2983 dh
+= scroll_class
->scrollbar_spacing
;
2987 if (width
) (*width
) = m_width
- dw
;
2988 if (height
) (*height
) = m_height
- dh
;
2992 printf( "GetClientSize, name %s ", GetName().c_str() );
2993 if (width) printf( " width = %d", (*width) );
2994 if (height) printf( " height = %d", (*height) );
2999 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3001 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3005 if (m_parent
&& m_parent
->m_wxwindow
)
3007 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3008 dx
= pizza
->xoffset
;
3009 dy
= pizza
->yoffset
;
3012 if (x
) (*x
) = m_x
- dx
;
3013 if (y
) (*y
) = m_y
- dy
;
3016 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3018 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3020 if (!m_widget
->window
) return;
3022 GdkWindow
*source
= (GdkWindow
*) NULL
;
3024 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3026 source
= m_widget
->window
;
3030 gdk_window_get_origin( source
, &org_x
, &org_y
);
3034 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3036 org_x
+= m_widget
->allocation
.x
;
3037 org_y
+= m_widget
->allocation
.y
;
3045 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3047 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3049 if (!m_widget
->window
) return;
3051 GdkWindow
*source
= (GdkWindow
*) NULL
;
3053 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3055 source
= m_widget
->window
;
3059 gdk_window_get_origin( source
, &org_x
, &org_y
);
3063 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3065 org_x
+= m_widget
->allocation
.x
;
3066 org_y
+= m_widget
->allocation
.y
;
3074 bool wxWindowGTK::Show( bool show
)
3076 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3078 if (!wxWindowBase::Show(show
))
3085 gtk_widget_show( m_widget
);
3087 gtk_widget_hide( m_widget
);
3092 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3094 win
->OnParentEnable(enable
);
3096 // Recurse, so that children have the opportunity to Do The Right Thing
3097 // and reset colours that have been messed up by a parent's (really ancestor's)
3099 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3101 node
= node
->GetNext() )
3103 wxWindow
*child
= node
->GetData();
3104 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3105 wxWindowNotifyEnable(child
, enable
);
3109 bool wxWindowGTK::Enable( bool enable
)
3111 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3113 if (!wxWindowBase::Enable(enable
))
3119 gtk_widget_set_sensitive( m_widget
, enable
);
3121 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3123 wxWindowNotifyEnable(this, enable
);
3128 int wxWindowGTK::GetCharHeight() const
3130 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3132 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3134 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3136 return font
->ascent
+ font
->descent
;
3139 int wxWindowGTK::GetCharWidth() const
3141 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3143 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3145 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3147 return gdk_string_width( font
, "H" );
3150 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3154 int *externalLeading
,
3155 const wxFont
*theFont
) const
3157 wxFont fontToUse
= m_font
;
3158 if (theFont
) fontToUse
= *theFont
;
3160 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3162 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3163 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3164 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3165 if (descent
) (*descent
) = font
->descent
;
3166 if (externalLeading
) (*externalLeading
) = 0; // ??
3169 void wxWindowGTK::SetFocus()
3171 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3174 wxPrintf( "SetFocus from " );
3175 if (GetClassInfo() && GetClassInfo()->GetClassName())
3176 wxPrintf( GetClassInfo()->GetClassName() );
3182 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3184 // see comment in gtk_window_focus_out_callback()
3185 gs_widgetLastFocus
= m_wxwindow
;
3186 gtk_widget_grab_focus (m_wxwindow
);
3191 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3193 gtk_widget_grab_focus (m_widget
);
3195 else if (GTK_IS_CONTAINER(m_widget
))
3197 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3206 wxPrintf( "SetFocus finished in " );
3207 if (GetClassInfo() && GetClassInfo()->GetClassName())
3208 wxPrintf( GetClassInfo()->GetClassName() );
3214 bool wxWindowGTK::AcceptsFocus() const
3216 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3219 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3221 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3223 wxWindowGTK
*oldParent
= m_parent
,
3224 *newParent
= (wxWindowGTK
*)newParentBase
;
3226 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3228 if ( !wxWindowBase::Reparent(newParent
) )
3231 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3233 /* prevent GTK from deleting the widget arbitrarily */
3234 gtk_widget_ref( m_widget
);
3238 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3241 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3245 /* insert GTK representation */
3246 (*(newParent
->m_insertCallback
))(newParent
, this);
3249 /* reverse: prevent GTK from deleting the widget arbitrarily */
3250 gtk_widget_unref( m_widget
);
3255 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3257 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3259 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3261 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3266 /* insert GTK representation */
3267 (*m_insertCallback
)(this, child
);
3270 void wxWindowGTK::Raise()
3272 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3274 if (!m_widget
->window
) return;
3276 gdk_window_raise( m_widget
->window
);
3279 void wxWindowGTK::Lower()
3281 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3283 if (!m_widget
->window
) return;
3285 gdk_window_lower( m_widget
->window
);
3288 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3290 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3292 if (cursor
== m_cursor
)
3296 wxapp_install_idle_handler();
3298 if (cursor
== wxNullCursor
)
3299 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3301 return wxWindowBase::SetCursor( cursor
);
3304 void wxWindowGTK::WarpPointer( int x
, int y
)
3306 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3308 // We provide this function ourselves as it is
3309 // missing in GDK (top of this file).
3311 GdkWindow
*window
= (GdkWindow
*) NULL
;
3313 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3315 window
= GetConnectWidget()->window
;
3318 gdk_window_warp_pointer( window
, x
, y
);
3321 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3323 if (!m_widget
) return;
3324 if (!m_widget
->window
) return;
3326 // temporarily hide the caret to avoid nasty interactions between caret
3327 // drawing and the window contents redraw
3328 #if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3329 wxCaretSuspend
cs((wxWindow
*)this);
3330 #endif // wxUSE_CARET
3332 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3336 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3337 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3341 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3342 m_clearRegion
.Clear();
3343 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3351 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3352 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3356 GdkRectangle gdk_rect
;
3357 gdk_rect
.x
= rect
->x
;
3358 gdk_rect
.y
= rect
->y
;
3359 gdk_rect
.width
= rect
->width
;
3360 gdk_rect
.height
= rect
->height
;
3361 gtk_widget_draw( m_widget
, &gdk_rect
);
3368 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3369 m_updateRegion
.Clear();
3370 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3374 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3379 void wxWindowGTK::Update()
3381 if (!m_updateRegion
.IsEmpty())
3383 GtkSendPaintEvents();
3387 void wxWindowGTK::GtkSendPaintEvents()
3391 m_clearRegion
.Clear();
3392 m_updateRegion
.Clear();
3396 m_clipPaintRegion
= TRUE
;
3398 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3400 wxWindowDC
dc( (wxWindow
*)this );
3401 dc
.SetClippingRegion( m_clearRegion
);
3403 wxEraseEvent
erase_event( GetId(), &dc
);
3404 erase_event
.SetEventObject( this );
3406 if (!GetEventHandler()->ProcessEvent(erase_event
))
3408 wxRegionIterator
upd( m_clearRegion
);
3411 gdk_window_clear_area( GTK_PIZZA(m_wxwindow
)->bin_window
,
3412 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3416 m_clearRegion
.Clear();
3419 wxNcPaintEvent
nc_paint_event( GetId() );
3420 nc_paint_event
.SetEventObject( this );
3421 GetEventHandler()->ProcessEvent( nc_paint_event
);
3423 wxPaintEvent
paint_event( GetId() );
3424 paint_event
.SetEventObject( this );
3425 GetEventHandler()->ProcessEvent( paint_event
);
3427 m_clipPaintRegion
= FALSE
;
3429 #ifndef __WXUNIVERSAL__
3430 // The following code will result in all window-less widgets
3431 // being redrawn because the wxWindows class is allowed to
3432 // paint over the window-less widgets.
3434 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3436 GList
*children
= pizza
->children
;
3439 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3440 children
= children
->next
;
3442 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3443 GTK_WIDGET_DRAWABLE (child
->widget
))
3445 // Get intersection of widget area and update region
3446 wxRegion
region( m_updateRegion
);
3448 GdkEventExpose gdk_event
;
3449 gdk_event
.type
= GDK_EXPOSE
;
3450 gdk_event
.window
= pizza
->bin_window
;
3451 gdk_event
.count
= 0;
3453 wxRegionIterator
upd( m_updateRegion
);
3457 rect
.x
= upd
.GetX();
3458 rect
.y
= upd
.GetY();
3459 rect
.width
= upd
.GetWidth();
3460 rect
.height
= upd
.GetHeight();
3462 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3464 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3473 m_updateRegion
.Clear();
3476 void wxWindowGTK::Clear()
3478 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3480 if (!m_widget
->window
) return;
3482 if (m_wxwindow
&& m_wxwindow
->window
)
3484 // gdk_window_clear( m_wxwindow->window );
3489 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3491 wxWindowBase::DoSetToolTip(tip
);
3494 m_tooltip
->Apply( (wxWindow
*)this );
3497 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3499 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3501 #endif // wxUSE_TOOLTIPS
3503 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3505 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3507 if (!wxWindowBase::SetBackgroundColour(colour
))
3509 // don't leave if the GTK widget has just
3511 if (!m_delayedBackgroundColour
) return FALSE
;
3514 GdkWindow
*window
= (GdkWindow
*) NULL
;
3516 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3518 window
= GetConnectWidget()->window
;
3522 // indicate that a new style has been set
3523 // but it couldn't get applied as the
3524 // widget hasn't been realized yet.
3525 m_delayedBackgroundColour
= TRUE
;
3529 (m_wxwindow
->window
) &&
3530 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3532 /* wxMSW doesn't clear the window here. I don't do that either to
3533 provide compatibility. call Clear() to do the job. */
3535 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3536 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3544 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3546 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3548 if (!wxWindowBase::SetForegroundColour(colour
))
3550 // don't leave if the GTK widget has just
3552 if (!m_delayedForegroundColour
) return FALSE
;
3555 GdkWindow
*window
= (GdkWindow
*) NULL
;
3557 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3559 window
= GetConnectWidget()->window
;
3563 // indicate that a new style has been set
3564 // but it couldn't get applied as the
3565 // widget hasn't been realized yet.
3566 m_delayedForegroundColour
= TRUE
;
3574 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3578 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3580 /* FIXME: is this necessary? */
3581 _G_TYPE_IGC(remake
, GtkObjectClass
) = _G_TYPE_IGC(m_widgetStyle
, GtkObjectClass
);
3583 remake
->klass
= m_widgetStyle
->klass
;
3586 gtk_style_unref( m_widgetStyle
);
3587 m_widgetStyle
= remake
;
3591 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3594 def
= gtk_widget_get_default_style();
3596 m_widgetStyle
= gtk_style_copy( def
);
3598 /* FIXME: is this necessary? */
3599 _G_TYPE_IGC(m_widgetStyle
, GtkObjectClass
) = _G_TYPE_IGC(def
, GtkObjectClass
);
3601 m_widgetStyle
->klass
= def
->klass
;
3605 return m_widgetStyle
;
3608 void wxWindowGTK::SetWidgetStyle()
3610 #if DISABLE_STYLE_IF_BROKEN_THEME
3611 if (m_widget
->style
->engine_data
)
3613 static bool s_warningPrinted
= FALSE
;
3614 if (!s_warningPrinted
)
3616 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3617 s_warningPrinted
= TRUE
;
3619 m_widgetStyle
= m_widget
->style
;
3624 GtkStyle
*style
= GetWidgetStyle();
3626 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3628 gdk_font_unref( style
->font
);
3629 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
3632 if (m_foregroundColour
.Ok())
3634 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3635 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3637 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3638 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3639 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3643 // Try to restore the gtk default style. This is still a little
3644 // oversimplified for what is probably really needed here for controls
3645 // other than buttons, but is better than not being able to (re)set a
3646 // control's foreground colour to *wxBLACK -- RL
3647 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3650 def
= gtk_widget_get_default_style();
3652 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3653 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3654 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3658 if (m_backgroundColour
.Ok())
3660 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3661 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3663 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3664 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3665 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3666 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3667 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3668 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3669 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3670 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3674 // Try to restore the gtk default style. This is still a little
3675 // oversimplified for what is probably really needed here for controls
3676 // other than buttons, but is better than not being able to (re)set a
3677 // control's background colour to default grey and means resetting a
3678 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3680 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3683 def
= gtk_widget_get_default_style();
3685 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3686 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3687 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3688 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3689 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3690 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3691 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3692 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3697 void wxWindowGTK::ApplyWidgetStyle()
3701 //-----------------------------------------------------------------------------
3702 // Pop-up menu stuff
3703 //-----------------------------------------------------------------------------
3705 #if wxUSE_MENUS_NATIVE
3708 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3710 *is_waiting
= FALSE
;
3713 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3715 menu
->SetInvokingWindow( win
);
3716 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3719 wxMenuItem
*menuitem
= node
->GetData();
3720 if (menuitem
->IsSubMenu())
3722 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3725 node
= node
->GetNext();
3729 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3730 // wxPopupMenuPositionCallback()
3732 // should be safe even in the MT case as the user can hardly popup 2 menus
3733 // simultaneously, can he?
3734 static gint gs_pop_x
= 0;
3735 static gint gs_pop_y
= 0;
3737 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3739 gpointer
WXUNUSED(user_data
) )
3741 // ensure that the menu appears entirely on screen
3743 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3745 wxSize sizeScreen
= wxGetDisplaySize();
3747 gint xmax
= sizeScreen
.x
- req
.width
,
3748 ymax
= sizeScreen
.y
- req
.height
;
3750 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3751 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3754 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3756 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3758 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3760 SetInvokingWindow( menu
, this );
3766 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3768 bool is_waiting
= TRUE
;
3770 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3772 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3773 (gpointer
)&is_waiting
);
3776 GTK_MENU(menu
->m_menu
),
3777 (GtkWidget
*) NULL
, // parent menu shell
3778 (GtkWidget
*) NULL
, // parent menu item
3779 wxPopupMenuPositionCallback
, // function to position it
3780 NULL
, // client data
3781 0, // button used to activate it
3782 gs_timeLastClick
// the time of activation
3787 while (gtk_events_pending())
3788 gtk_main_iteration();
3794 #endif // wxUSE_MENUS_NATIVE
3796 #if wxUSE_DRAG_AND_DROP
3798 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3800 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3802 GtkWidget
*dnd_widget
= GetConnectWidget();
3804 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3806 if (m_dropTarget
) delete m_dropTarget
;
3807 m_dropTarget
= dropTarget
;
3809 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3812 #endif // wxUSE_DRAG_AND_DROP
3814 GtkWidget
* wxWindowGTK::GetConnectWidget()
3816 GtkWidget
*connect_widget
= m_widget
;
3817 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3819 return connect_widget
;
3822 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3825 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3827 return (window
== m_widget
->window
);
3830 bool wxWindowGTK::SetFont( const wxFont
&font
)
3832 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3834 if (!wxWindowBase::SetFont(font
))
3839 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3840 if ( sysbg
== m_backgroundColour
)
3842 m_backgroundColour
= wxNullColour
;
3844 m_backgroundColour
= sysbg
;
3854 void wxWindowGTK::DoCaptureMouse()
3856 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3858 GdkWindow
*window
= (GdkWindow
*) NULL
;
3860 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3862 window
= GetConnectWidget()->window
;
3864 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3866 wxCursor
* cursor
= & m_cursor
;
3868 cursor
= wxSTANDARD_CURSOR
;
3870 gdk_pointer_grab( window
, FALSE
,
3872 (GDK_BUTTON_PRESS_MASK
|
3873 GDK_BUTTON_RELEASE_MASK
|
3874 GDK_POINTER_MOTION_HINT_MASK
|
3875 GDK_POINTER_MOTION_MASK
),
3877 cursor
->GetCursor(),
3878 (guint32
)GDK_CURRENT_TIME
);
3879 g_captureWindow
= this;
3880 g_captureWindowHasMouse
= TRUE
;
3883 void wxWindowGTK::DoReleaseMouse()
3885 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3887 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3889 g_captureWindow
= (wxWindowGTK
*) NULL
;
3891 GdkWindow
*window
= (GdkWindow
*) NULL
;
3893 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3895 window
= GetConnectWidget()->window
;
3900 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3904 wxWindow
*wxWindowBase::GetCapture()
3906 return (wxWindow
*)g_captureWindow
;
3909 bool wxWindowGTK::IsRetained() const
3914 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3915 int range
, bool refresh
)
3917 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3919 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3921 m_hasScrolling
= TRUE
;
3923 if (orient
== wxHORIZONTAL
)
3925 float fpos
= (float)pos
;
3926 float frange
= (float)range
;
3927 float fthumb
= (float)thumbVisible
;
3928 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3929 if (fpos
< 0.0) fpos
= 0.0;
3931 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3932 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3934 SetScrollPos( orient
, pos
, refresh
);
3938 m_oldHorizontalPos
= fpos
;
3940 m_hAdjust
->lower
= 0.0;
3941 m_hAdjust
->upper
= frange
;
3942 m_hAdjust
->value
= fpos
;
3943 m_hAdjust
->step_increment
= 1.0;
3944 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3945 m_hAdjust
->page_size
= fthumb
;
3949 float fpos
= (float)pos
;
3950 float frange
= (float)range
;
3951 float fthumb
= (float)thumbVisible
;
3952 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3953 if (fpos
< 0.0) fpos
= 0.0;
3955 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
3956 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3958 SetScrollPos( orient
, pos
, refresh
);
3962 m_oldVerticalPos
= fpos
;
3964 m_vAdjust
->lower
= 0.0;
3965 m_vAdjust
->upper
= frange
;
3966 m_vAdjust
->value
= fpos
;
3967 m_vAdjust
->step_increment
= 1.0;
3968 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3969 m_vAdjust
->page_size
= fthumb
;
3972 if (orient
== wxHORIZONTAL
)
3973 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3975 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3978 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3980 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3982 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3984 if (orient
== wxHORIZONTAL
)
3986 float fpos
= (float)pos
;
3987 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3988 if (fpos
< 0.0) fpos
= 0.0;
3989 m_oldHorizontalPos
= fpos
;
3991 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3992 m_hAdjust
->value
= fpos
;
3996 float fpos
= (float)pos
;
3997 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
3998 if (fpos
< 0.0) fpos
= 0.0;
3999 m_oldVerticalPos
= fpos
;
4001 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4002 m_vAdjust
->value
= fpos
;
4005 if (m_wxwindow
->window
)
4007 if (orient
== wxHORIZONTAL
)
4009 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4010 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4012 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4014 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4015 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4019 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4020 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4022 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4024 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4025 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4030 int wxWindowGTK::GetScrollThumb( int orient
) const
4032 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4034 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4036 if (orient
== wxHORIZONTAL
)
4037 return (int)(m_hAdjust
->page_size
+0.5);
4039 return (int)(m_vAdjust
->page_size
+0.5);
4042 int wxWindowGTK::GetScrollPos( int orient
) const
4044 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4046 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4048 if (orient
== wxHORIZONTAL
)
4049 return (int)(m_hAdjust
->value
+0.5);
4051 return (int)(m_vAdjust
->value
+0.5);
4054 int wxWindowGTK::GetScrollRange( int orient
) const
4056 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4058 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4060 if (orient
== wxHORIZONTAL
)
4061 return (int)(m_hAdjust
->upper
+0.5);
4063 return (int)(m_vAdjust
->upper
+0.5);
4066 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4068 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4070 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4072 // No scrolling requested.
4073 if ((dx
== 0) && (dy
== 0)) return;
4075 if (!m_updateRegion
.IsEmpty())
4077 m_updateRegion
.Offset( dx
, dy
);
4081 GetClientSize( &cw
, &ch
);
4082 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4085 if (!m_clearRegion
.IsEmpty())
4087 m_clearRegion
.Offset( dx
, dy
);
4091 GetClientSize( &cw
, &ch
);
4092 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4097 m_clipPaintRegion
= TRUE
;
4099 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4101 m_clipPaintRegion
= FALSE
;
4105 if (m_children
.GetCount() > 0)
4107 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4111 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
4113 pizza
->xoffset
-= dx
;
4114 pizza
->yoffset
-= dy
;
4116 GdkGC
*m_scrollGC
= gdk_gc_new( pizza
->bin_window
);
4117 gdk_gc_set_exposures( m_scrollGC
, TRUE
);
4121 GetClientSize( &cw
, &ch
);
4122 int w
= cw
- abs(dx
);
4123 int h
= ch
- abs(dy
);
4125 if ((h
< 0) || (w
< 0))
4133 if (dx
< 0) s_x
= -dx
;
4134 if (dy
< 0) s_y
= -dy
;
4137 if (dx
> 0) d_x
= dx
;
4138 if (dy
> 0) d_y
= dy
;
4140 gdk_window_copy_area( pizza
->bin_window
, m_scrollGC
, d_x
, d_y
,
4141 pizza
->bin_window
, s_x
, s_y
, w
, h
);
4144 if (dx
< 0) rect
.x
= cw
+dx
; else rect
.x
= 0;
4145 if (dy
< 0) rect
.y
= ch
+dy
; else rect
.y
= 0;
4146 if (dy
!= 0) rect
.width
= cw
; else rect
.width
= abs(dx
);
4147 if (dx
!= 0) rect
.height
= ch
; else rect
.height
= abs(dy
);
4149 Refresh( TRUE
, &rect
);
4152 gdk_gc_unref( m_scrollGC
);
4157 // Find the wxWindow at the current mouse position, also returning the mouse
4159 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4161 pt
= wxGetMousePosition();
4162 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4166 // Get the current mouse position.
4167 wxPoint
wxGetMousePosition()
4169 /* This crashes when used within wxHelpContext,
4170 so we have to use the X-specific implementation below.
4172 GdkModifierType *mask;
4173 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4175 return wxPoint(x, y);
4179 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4181 return wxPoint(-999, -999);
4183 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4184 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4185 Window rootReturn
, childReturn
;
4186 int rootX
, rootY
, winX
, winY
;
4187 unsigned int maskReturn
;
4189 XQueryPointer (display
,
4193 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4194 return wxPoint(rootX
, rootY
);