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 GtkPizza
*pizza
= GTK_PIZZA (widget
);
780 if (win
->GetThemeEnabled())
782 wxWindow
*parent
= win
->GetParent();
783 while (parent
&& !parent
->IsTopLevel())
784 parent
= parent
->GetParent();
788 gtk_paint_flat_box (parent
->m_widget
->style
,
798 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
800 gdk_event
->area
.width
,
801 gdk_event
->area
.height
);
803 // Actually send the various events based on the
804 // current update region.
805 if (gdk_event
->count
== 0)
806 win
->GtkSendPaintEvents();
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 GtkPizza
*pizza
= GTK_PIZZA (widget
);
873 if (win
->GetThemeEnabled())
875 wxWindow
*parent
= win
->GetParent();
876 while (parent
&& !parent
->IsTopLevel())
877 parent
= parent
->GetParent();
881 gtk_paint_flat_box (parent
->m_widget
->style
,
892 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
893 (pizza
->clear_on_draw
))
895 gdk_window_clear_area( pizza
->bin_window
,
896 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
899 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
901 // Actually send the various events based on the
902 // current update region.
903 win
->GtkSendPaintEvents();
905 // Redraw child widgets
906 GList
*children
= pizza
->children
;
909 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
910 children
= children
->next
;
912 GdkRectangle child_area
;
913 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
915 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
920 //-----------------------------------------------------------------------------
921 // "key_press_event" from any window
922 //-----------------------------------------------------------------------------
924 // turn on to see the key event codes on the console
925 #undef DEBUG_KEY_EVENTS
927 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
928 GdkEventKey
*gdk_event
,
934 wxapp_install_idle_handler();
936 if (!win
->m_hasVMT
) return FALSE
;
937 if (g_blockEventsOnDrag
) return FALSE
;
942 GdkModifierType state
;
943 if (gdk_event
->window
)
944 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
948 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
950 #ifdef DEBUG_KEY_EVENTS
951 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
952 #endif // DEBUG_KEY_EVENTS
954 /* sending unknown key events doesn't really make sense */
958 wxKeyEvent
event( wxEVT_KEY_DOWN
);
959 event
.SetTimestamp( gdk_event
->time
);
960 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
961 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
962 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
963 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
964 event
.m_keyCode
= key_code
;
965 event
.m_scanCode
= gdk_event
->keyval
;
968 event
.SetEventObject( win
);
969 ret
= win
->GetEventHandler()->ProcessEvent( event
);
974 wxWindowGTK
*ancestor
= win
;
977 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
980 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
981 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
984 if (ancestor
->IsTopLevel())
986 ancestor
= ancestor
->GetParent();
989 #endif // wxUSE_ACCEL
991 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
992 will only be sent if it is not in an accelerator table. */
995 key_code
= map_to_wx_keysym( gdk_event
);
999 #ifdef DEBUG_KEY_EVENTS
1000 wxPrintf(_T("Char event: %ld\n"), key_code
);
1001 #endif // DEBUG_KEY_EVENTS
1003 // reuse the ame event object, just change its type and use the
1004 // translated keycode instead of the raw one
1005 event
.SetEventType(wxEVT_CHAR
);
1006 event
.m_keyCode
= key_code
;
1008 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1012 /* win is a control: tab can be propagated up */
1014 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1015 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1016 // have this style, yet choose not to process this particular TAB in which
1017 // case TAB must still work as a navigational character
1019 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1021 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1023 wxNavigationKeyEvent new_event
;
1024 new_event
.SetEventObject( win
->GetParent() );
1025 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1026 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1027 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1028 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1029 new_event
.SetCurrentFocus( win
);
1030 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1033 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1035 (gdk_event
->keyval
== GDK_Escape
) )
1037 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1038 new_event
.SetEventObject( win
);
1039 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1043 #if 0 // (GTK_MINOR_VERSION > 0)
1044 /* Pressing F10 will activate the menu bar of the top frame. */
1046 (gdk_event
->keyval
== GDK_F10
) )
1048 wxWindowGTK
*ancestor
= win
;
1051 if (wxIsKindOf(ancestor
,wxFrame
))
1053 wxFrame
*frame
= (wxFrame
*) ancestor
;
1054 wxMenuBar
*menubar
= frame
->GetMenuBar();
1057 wxNode
*node
= menubar
->GetMenus().First();
1060 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1061 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1067 ancestor
= ancestor
->GetParent();
1074 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1081 //-----------------------------------------------------------------------------
1082 // "key_release_event" from any window
1083 //-----------------------------------------------------------------------------
1085 static gint
gtk_window_key_release_callback( GtkWidget
*widget
, GdkEventKey
*gdk_event
, wxWindowGTK
*win
)
1090 wxapp_install_idle_handler();
1092 if (!win
->m_hasVMT
) return FALSE
;
1093 if (g_blockEventsOnDrag
) return FALSE
;
1095 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
1097 #ifdef DEBUG_KEY_EVENTS
1098 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
1099 #endif // DEBUG_KEY_EVENTS
1101 /* sending unknown key events doesn't really make sense */
1102 if (key_code
== 0) return FALSE
;
1106 GdkModifierType state
;
1107 if (gdk_event
->window
)
1108 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1110 wxKeyEvent
event( wxEVT_KEY_UP
);
1111 event
.SetTimestamp( gdk_event
->time
);
1112 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1113 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1114 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1115 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1116 event
.m_keyCode
= key_code
;
1117 event
.m_scanCode
= gdk_event
->keyval
;
1120 event
.SetEventObject( win
);
1122 if (win
->GetEventHandler()->ProcessEvent( event
))
1124 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1131 // ============================================================================
1133 // ============================================================================
1135 // init wxMouseEvent with the info from gdk_event
1136 #define InitMouseEvent(win, event, gdk_event) \
1138 event.SetTimestamp( gdk_event->time ); \
1139 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1140 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1141 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1142 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1143 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1144 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1145 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1147 wxPoint pt = win->GetClientAreaOrigin(); \
1148 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1149 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1152 // ----------------------------------------------------------------------------
1153 // mouse event processing helper
1154 // ----------------------------------------------------------------------------
1156 static void AdjustEventButtonState(wxMouseEvent
& event
)
1158 // GDK reports the old state of the button for a button press event, but
1159 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1160 // for a LEFT_DOWN event, not FALSE, so we will invert
1161 // left/right/middleDown for the corresponding click events
1163 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1164 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1165 (event
.GetEventType() == wxEVT_LEFT_UP
))
1167 event
.m_leftDown
= !event
.m_leftDown
;
1171 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1172 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1173 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1175 event
.m_middleDown
= !event
.m_middleDown
;
1179 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1180 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1181 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1183 event
.m_rightDown
= !event
.m_rightDown
;
1188 //-----------------------------------------------------------------------------
1189 // "button_press_event"
1190 //-----------------------------------------------------------------------------
1192 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1197 wxapp_install_idle_handler();
1200 wxPrintf( wxT("1) OnButtonPress from ") );
1201 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1202 wxPrintf( win->GetClassInfo()->GetClassName() );
1203 wxPrintf( wxT(".\n") );
1205 if (!win
->m_hasVMT
) return FALSE
;
1206 if (g_blockEventsOnDrag
) return TRUE
;
1207 if (g_blockEventsOnScroll
) return TRUE
;
1209 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1211 if (win
->m_wxwindow
)
1213 if (GTK_WIDGET_CAN_FOCUS(win
->m_wxwindow
) && !GTK_WIDGET_HAS_FOCUS (win
->m_wxwindow
) )
1215 gtk_widget_grab_focus (win
->m_wxwindow
);
1218 wxPrintf( wxT("GrabFocus from ") );
1219 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1220 wxPrintf( win->GetClassInfo()->GetClassName() );
1221 wxPrintf( wxT(".\n") );
1227 wxEventType event_type
= wxEVT_NULL
;
1229 if (gdk_event
->button
== 1)
1231 switch (gdk_event
->type
)
1233 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1234 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1238 else if (gdk_event
->button
== 2)
1240 switch (gdk_event
->type
)
1242 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1243 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1247 else if (gdk_event
->button
== 3)
1249 switch (gdk_event
->type
)
1251 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1252 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1257 if ( event_type
== wxEVT_NULL
)
1259 // unknown mouse button or click type
1263 wxMouseEvent
event( event_type
);
1264 InitMouseEvent( win
, event
, gdk_event
);
1266 AdjustEventButtonState(event
);
1268 // wxListBox actually get mouse events from the item
1270 if (win
->m_isListBox
)
1272 event
.m_x
+= widget
->allocation
.x
;
1273 event
.m_y
+= widget
->allocation
.y
;
1276 // Some control don't have their own X window and thus cannot get
1279 if (!g_captureWindow
)
1281 wxCoord x
= event
.m_x
;
1282 wxCoord y
= event
.m_y
;
1283 if (win
->m_wxwindow
)
1285 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1286 x
+= pizza
->xoffset
;
1287 y
+= pizza
->yoffset
;
1290 wxNode
*node
= win
->GetChildren().First();
1293 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1295 node
= node
->Next();
1296 if (!child
->IsShown())
1299 if (child
->m_isStaticBox
)
1301 // wxStaticBox is transparent in the box itself
1302 int xx1
= child
->m_x
;
1303 int yy1
= child
->m_y
;
1304 int xx2
= child
->m_x
+ child
->m_width
;
1305 int yy2
= child
->m_x
+ child
->m_height
;
1308 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1310 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1312 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1314 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1317 event
.m_x
-= child
->m_x
;
1318 event
.m_y
-= child
->m_y
;
1325 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1326 (child
->m_x
<= x
) &&
1327 (child
->m_y
<= y
) &&
1328 (child
->m_x
+child
->m_width
>= x
) &&
1329 (child
->m_y
+child
->m_height
>= y
))
1332 event
.m_x
-= child
->m_x
;
1333 event
.m_y
-= child
->m_y
;
1340 event
.SetEventObject( win
);
1342 gs_timeLastClick
= gdk_event
->time
;
1345 wxPrintf( wxT("2) OnButtonPress from ") );
1346 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1347 wxPrintf( win->GetClassInfo()->GetClassName() );
1348 wxPrintf( wxT(".\n") );
1351 if (win
->GetEventHandler()->ProcessEvent( event
))
1353 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1360 //-----------------------------------------------------------------------------
1361 // "button_release_event"
1362 //-----------------------------------------------------------------------------
1364 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1369 wxapp_install_idle_handler();
1371 if (!win
->m_hasVMT
) return FALSE
;
1372 if (g_blockEventsOnDrag
) return FALSE
;
1373 if (g_blockEventsOnScroll
) return FALSE
;
1375 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1378 printf( "OnButtonRelease from " );
1379 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1380 printf( win->GetClassInfo()->GetClassName() );
1384 wxEventType event_type
= wxEVT_NULL
;
1386 switch (gdk_event
->button
)
1388 case 1: event_type
= wxEVT_LEFT_UP
; break;
1389 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1390 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1391 default: return FALSE
;
1394 wxMouseEvent
event( event_type
);
1395 InitMouseEvent( win
, event
, gdk_event
);
1397 AdjustEventButtonState(event
);
1399 // wxListBox actually get mouse events from the item
1401 if (win
->m_isListBox
)
1403 event
.m_x
+= widget
->allocation
.x
;
1404 event
.m_y
+= widget
->allocation
.y
;
1407 // Some control don't have their own X window and thus cannot get
1410 if (!g_captureWindow
)
1412 wxCoord x
= event
.m_x
;
1413 wxCoord y
= event
.m_y
;
1414 if (win
->m_wxwindow
)
1416 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1417 x
+= pizza
->xoffset
;
1418 y
+= pizza
->yoffset
;
1421 wxNode
*node
= win
->GetChildren().First();
1424 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1426 node
= node
->Next();
1427 if (!child
->IsShown())
1430 if (child
->m_isStaticBox
)
1432 // wxStaticBox is transparent in the box itself
1433 int xx1
= child
->m_x
;
1434 int yy1
= child
->m_y
;
1435 int xx2
= child
->m_x
+ child
->m_width
;
1436 int yy2
= child
->m_x
+ child
->m_height
;
1439 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1441 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1443 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1445 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1448 event
.m_x
-= child
->m_x
;
1449 event
.m_y
-= child
->m_y
;
1456 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1457 (child
->m_x
<= x
) &&
1458 (child
->m_y
<= y
) &&
1459 (child
->m_x
+child
->m_width
>= x
) &&
1460 (child
->m_y
+child
->m_height
>= y
))
1463 event
.m_x
-= child
->m_x
;
1464 event
.m_y
-= child
->m_y
;
1471 event
.SetEventObject( win
);
1473 if (win
->GetEventHandler()->ProcessEvent( event
))
1475 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1482 //-----------------------------------------------------------------------------
1483 // "motion_notify_event"
1484 //-----------------------------------------------------------------------------
1486 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1487 GdkEventMotion
*gdk_event
,
1493 wxapp_install_idle_handler();
1495 if (!win
->m_hasVMT
) return FALSE
;
1496 if (g_blockEventsOnDrag
) return FALSE
;
1497 if (g_blockEventsOnScroll
) return FALSE
;
1499 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1501 if (gdk_event
->is_hint
)
1505 GdkModifierType state
;
1506 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1512 printf( "OnMotion from " );
1513 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1514 printf( win->GetClassInfo()->GetClassName() );
1518 wxMouseEvent
event( wxEVT_MOTION
);
1519 InitMouseEvent(win
, event
, gdk_event
);
1521 if ( g_captureWindow
)
1523 // synthetize a mouse enter or leave event if needed
1524 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1525 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1526 if ( hasMouse
!= g_captureWindowHasMouse
)
1528 // the mouse changed window
1529 g_captureWindowHasMouse
= hasMouse
;
1531 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1532 : wxEVT_LEAVE_WINDOW
);
1533 InitMouseEvent(win
, event
, gdk_event
);
1534 event
.SetEventObject(win
);
1535 win
->GetEventHandler()->ProcessEvent(event
);
1540 // Some control don't have their own X window and thus cannot get
1543 wxCoord x
= event
.m_x
;
1544 wxCoord y
= event
.m_y
;
1545 if (win
->m_wxwindow
)
1547 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1548 x
+= pizza
->xoffset
;
1549 y
+= pizza
->yoffset
;
1552 wxNode
*node
= win
->GetChildren().First();
1555 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1557 node
= node
->Next();
1558 if (!child
->IsShown())
1561 if (child
->m_isStaticBox
)
1563 // wxStaticBox is transparent in the box itself
1564 int xx1
= child
->m_x
;
1565 int yy1
= child
->m_y
;
1566 int xx2
= child
->m_x
+ child
->m_width
;
1567 int yy2
= child
->m_x
+ child
->m_height
;
1570 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1572 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1574 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1576 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1579 event
.m_x
-= child
->m_x
;
1580 event
.m_y
-= child
->m_y
;
1587 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1588 (child
->m_x
<= x
) &&
1589 (child
->m_y
<= y
) &&
1590 (child
->m_x
+child
->m_width
>= x
) &&
1591 (child
->m_y
+child
->m_height
>= y
))
1594 event
.m_x
-= child
->m_x
;
1595 event
.m_y
-= child
->m_y
;
1602 event
.SetEventObject( win
);
1604 if (win
->GetEventHandler()->ProcessEvent( event
))
1606 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1613 //-----------------------------------------------------------------------------
1615 //-----------------------------------------------------------------------------
1617 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1618 GdkEvent
*WXUNUSED(event
),
1624 wxapp_install_idle_handler();
1626 if (!win
->m_hasVMT
) return FALSE
;
1627 if (g_blockEventsOnDrag
) return FALSE
;
1629 switch ( g_sendActivateEvent
)
1632 // we've got focus from outside, synthetize wxActivateEvent
1633 g_sendActivateEvent
= 1;
1637 // another our window just lost focus, it was already ours before
1638 // - don't send any wxActivateEvent
1639 g_sendActivateEvent
= -1;
1644 g_focusWindow
= win
;
1647 wxPrintf( "OnSetFocus from " );
1648 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
1649 wxPrintf( win
->GetClassInfo()->GetClassName() );
1653 // notify the parent keeping track of focus for the kbd navigation
1654 // purposes that we got it
1655 wxChildFocusEvent
eventFocus(win
);
1656 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1660 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1664 // caret needs to be informed about focus change
1665 wxCaret
*caret
= win
->GetCaret();
1668 caret
->OnSetFocus();
1670 #endif // wxUSE_CARET
1672 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1673 if ( active
!= g_activeFrame
)
1675 if ( g_activeFrame
)
1677 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1678 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1679 event
.SetEventObject(g_activeFrame
);
1680 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1683 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1684 g_activeFrame
= active
;
1685 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1686 event
.SetEventObject(g_activeFrame
);
1687 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1689 g_activeFrameLostFocus
= FALSE
;
1692 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1693 event
.SetEventObject( win
);
1695 if (win
->GetEventHandler()->ProcessEvent( event
))
1697 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1705 //-----------------------------------------------------------------------------
1706 // "focus_out_event"
1707 //-----------------------------------------------------------------------------
1709 static GtkWidget
*gs_widgetLastFocus
= NULL
;
1711 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEvent
*WXUNUSED(event
), wxWindowGTK
*win
)
1716 wxapp_install_idle_handler();
1718 if (!win
->m_hasVMT
) return FALSE
;
1719 if (g_blockEventsOnDrag
) return FALSE
;
1721 // VZ: this is really weird but GTK+ seems to call us from inside
1722 // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
1723 // this widget and then "focus_in". This is totally unexpected and
1724 // completely breaks wxUniv code so ignore this dummy event (we can't
1725 // be losing focus if we're about to acquire it!)
1726 if ( widget
== gs_widgetLastFocus
)
1728 gs_widgetLastFocus
= NULL
;
1733 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1735 // VZ: commenting this out because it does happen (although not easy
1736 // to reproduce, I only see it when using wxMiniFrame and not
1737 // always) and makes using Mahogany quite annoying
1739 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1740 wxT("unfocusing window that hasn't gained focus properly") )
1743 g_activeFrameLostFocus
= TRUE
;
1746 // if the focus goes out of our app alltogether, OnIdle() will send
1747 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1748 // g_sendActivateEvent to -1
1749 g_sendActivateEvent
= 0;
1751 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1755 g_focusWindow
= (wxWindowGTK
*)NULL
;
1758 wxPrintf( "OnKillFocus from " );
1759 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
1760 wxPrintf( win
->GetClassInfo()->GetClassName() );
1770 // caret needs to be informed about focus change
1771 wxCaret
*caret
= win
->GetCaret();
1774 caret
->OnKillFocus();
1776 #endif // wxUSE_CARET
1778 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1779 event
.SetEventObject( win
);
1781 if (win
->GetEventHandler()->ProcessEvent( event
))
1783 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1790 //-----------------------------------------------------------------------------
1791 // "enter_notify_event"
1792 //-----------------------------------------------------------------------------
1794 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1799 wxapp_install_idle_handler();
1801 if (!win
->m_hasVMT
) return FALSE
;
1802 if (g_blockEventsOnDrag
) return FALSE
;
1804 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1806 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1807 event
.SetTimestamp( gdk_event
->time
);
1808 event
.SetEventObject( win
);
1812 GdkModifierType state
= (GdkModifierType
)0;
1814 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1816 InitMouseEvent(win
, event
, gdk_event
);
1817 wxPoint pt
= win
->GetClientAreaOrigin();
1818 event
.m_x
= x
+ pt
.x
;
1819 event
.m_y
= y
+ pt
.y
;
1821 if (win
->GetEventHandler()->ProcessEvent( event
))
1823 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1830 //-----------------------------------------------------------------------------
1831 // "leave_notify_event"
1832 //-----------------------------------------------------------------------------
1834 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1839 wxapp_install_idle_handler();
1841 if (!win
->m_hasVMT
) return FALSE
;
1842 if (g_blockEventsOnDrag
) return FALSE
;
1844 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1846 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1847 event
.SetTimestamp( gdk_event
->time
);
1848 event
.SetEventObject( win
);
1852 GdkModifierType state
= (GdkModifierType
)0;
1854 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1856 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
);
1857 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
);
1858 event
.m_altDown
= (state
& GDK_MOD1_MASK
);
1859 event
.m_metaDown
= (state
& GDK_MOD2_MASK
);
1860 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
);
1861 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
);
1862 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
);
1864 wxPoint pt
= win
->GetClientAreaOrigin();
1865 event
.m_x
= x
+ pt
.x
;
1866 event
.m_y
= y
+ pt
.y
;
1868 if (win
->GetEventHandler()->ProcessEvent( event
))
1870 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1877 //-----------------------------------------------------------------------------
1878 // "value_changed" from m_vAdjust
1879 //-----------------------------------------------------------------------------
1881 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
, wxWindowGTK
*win
)
1886 wxapp_install_idle_handler();
1888 if (g_blockEventsOnDrag
) return;
1890 if (!win
->m_hasVMT
) return;
1892 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1893 if (fabs(diff
) < 0.2) return;
1895 win
->m_oldVerticalPos
= adjust
->value
;
1897 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1898 GtkRange
*range
= GTK_RANGE( scrolledWindow
->vscrollbar
);
1900 wxEventType command
= wxEVT_SCROLLWIN_THUMBTRACK
;
1901 if (range
->scroll_type
== GTK_SCROLL_STEP_BACKWARD
) command
= wxEVT_SCROLLWIN_LINEUP
;
1902 else if (range
->scroll_type
== GTK_SCROLL_STEP_FORWARD
) command
= wxEVT_SCROLLWIN_LINEDOWN
;
1903 else if (range
->scroll_type
== GTK_SCROLL_PAGE_BACKWARD
) command
= wxEVT_SCROLLWIN_PAGEUP
;
1904 else if (range
->scroll_type
== GTK_SCROLL_PAGE_FORWARD
) command
= wxEVT_SCROLLWIN_PAGEDOWN
;
1906 int value
= (int)(adjust
->value
+0.5);
1908 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1909 event
.SetEventObject( win
);
1910 win
->GetEventHandler()->ProcessEvent( event
);
1913 //-----------------------------------------------------------------------------
1914 // "value_changed" from m_hAdjust
1915 //-----------------------------------------------------------------------------
1917 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
, wxWindowGTK
*win
)
1922 wxapp_install_idle_handler();
1924 if (g_blockEventsOnDrag
) return;
1925 if (!win
->m_hasVMT
) return;
1927 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1928 if (fabs(diff
) < 0.2) return;
1930 win
->m_oldHorizontalPos
= adjust
->value
;
1932 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1933 GtkRange
*range
= GTK_RANGE( scrolledWindow
->hscrollbar
);
1935 wxEventType command
= wxEVT_SCROLLWIN_THUMBTRACK
;
1936 if (range
->scroll_type
== GTK_SCROLL_STEP_BACKWARD
) command
= wxEVT_SCROLLWIN_LINEUP
;
1937 else if (range
->scroll_type
== GTK_SCROLL_STEP_FORWARD
) command
= wxEVT_SCROLLWIN_LINEDOWN
;
1938 else if (range
->scroll_type
== GTK_SCROLL_PAGE_BACKWARD
) command
= wxEVT_SCROLLWIN_PAGEUP
;
1939 else if (range
->scroll_type
== GTK_SCROLL_PAGE_FORWARD
) command
= wxEVT_SCROLLWIN_PAGEDOWN
;
1941 int value
= (int)(adjust
->value
+0.5);
1943 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1944 event
.SetEventObject( win
);
1945 win
->GetEventHandler()->ProcessEvent( event
);
1948 //-----------------------------------------------------------------------------
1949 // "button_press_event" from scrollbar
1950 //-----------------------------------------------------------------------------
1952 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1953 GdkEventButton
*gdk_event
,
1959 wxapp_install_idle_handler();
1962 g_blockEventsOnScroll
= TRUE
;
1963 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1968 //-----------------------------------------------------------------------------
1969 // "button_release_event" from scrollbar
1970 //-----------------------------------------------------------------------------
1972 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1973 GdkEventButton
*WXUNUSED(gdk_event
),
1978 // don't test here as we can release the mouse while being over
1979 // a different window than the slider
1981 // if (gdk_event->window != widget->slider) return FALSE;
1983 g_blockEventsOnScroll
= FALSE
;
1985 if (win
->m_isScrolling
)
1987 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1991 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1992 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1994 value
= (int)(win
->m_hAdjust
->value
+0.5);
1997 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1999 value
= (int)(win
->m_vAdjust
->value
+0.5);
2003 wxScrollWinEvent
event( command
, value
, dir
);
2004 event
.SetEventObject( win
);
2005 win
->GetEventHandler()->ProcessEvent( event
);
2008 win
->m_isScrolling
= FALSE
;
2013 // ----------------------------------------------------------------------------
2014 // this wxWindowBase function is implemented here (in platform-specific file)
2015 // because it is static and so couldn't be made virtual
2016 // ----------------------------------------------------------------------------
2018 wxWindow
*wxWindowBase::FindFocus()
2020 // the cast is necessary when we compile in wxUniversal mode
2021 return (wxWindow
*)g_focusWindow
;
2024 //-----------------------------------------------------------------------------
2025 // "realize" from m_widget
2026 //-----------------------------------------------------------------------------
2028 /* We cannot set colours and fonts before the widget has
2029 been realized, so we do this directly after realization. */
2032 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2037 wxapp_install_idle_handler();
2039 if (win
->m_delayedBackgroundColour
)
2040 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2042 if (win
->m_delayedForegroundColour
)
2043 win
->SetForegroundColour( win
->GetForegroundColour() );
2045 wxWindowCreateEvent
event( win
);
2046 event
.SetEventObject( win
);
2047 win
->GetEventHandler()->ProcessEvent( event
);
2052 //-----------------------------------------------------------------------------
2054 //-----------------------------------------------------------------------------
2057 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2058 GtkAllocation
*WXUNUSED(alloc
),
2062 wxapp_install_idle_handler();
2064 if (!win
->m_hasScrolling
) return;
2066 int client_width
= 0;
2067 int client_height
= 0;
2068 win
->GetClientSize( &client_width
, &client_height
);
2069 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2072 win
->m_oldClientWidth
= client_width
;
2073 win
->m_oldClientHeight
= client_height
;
2075 if (!win
->m_nativeSizeEvent
)
2077 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2078 event
.SetEventObject( win
);
2079 win
->GetEventHandler()->ProcessEvent( event
);
2085 #define WXUNUSED_UNLESS_XIM(param) param
2087 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2090 /* Resize XIM window */
2093 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2094 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2095 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2098 wxapp_install_idle_handler();
2104 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2108 gdk_window_get_size (widget
->window
, &width
, &height
);
2109 win
->m_icattr
->preedit_area
.width
= width
;
2110 win
->m_icattr
->preedit_area
.height
= height
;
2111 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2116 //-----------------------------------------------------------------------------
2117 // "realize" from m_wxwindow
2118 //-----------------------------------------------------------------------------
2120 /* Initialize XIM support */
2123 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2124 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2127 wxapp_install_idle_handler();
2130 if (win
->m_ic
) return FALSE
;
2131 if (!widget
) return FALSE
;
2132 if (!gdk_im_ready()) return FALSE
;
2134 win
->m_icattr
= gdk_ic_attr_new();
2135 if (!win
->m_icattr
) return FALSE
;
2139 GdkColormap
*colormap
;
2140 GdkICAttr
*attr
= win
->m_icattr
;
2141 unsigned attrmask
= GDK_IC_ALL_REQ
;
2143 GdkIMStyle supported_style
= (GdkIMStyle
)
2144 (GDK_IM_PREEDIT_NONE
|
2145 GDK_IM_PREEDIT_NOTHING
|
2146 GDK_IM_PREEDIT_POSITION
|
2147 GDK_IM_STATUS_NONE
|
2148 GDK_IM_STATUS_NOTHING
);
2150 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2151 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2153 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2154 attr
->client_window
= widget
->window
;
2156 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2157 gtk_widget_get_default_colormap ())
2159 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2160 attr
->preedit_colormap
= colormap
;
2163 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2164 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2165 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2166 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2168 switch (style
& GDK_IM_PREEDIT_MASK
)
2170 case GDK_IM_PREEDIT_POSITION
:
2171 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2173 g_warning ("over-the-spot style requires fontset");
2177 gdk_window_get_size (widget
->window
, &width
, &height
);
2179 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2180 attr
->spot_location
.x
= 0;
2181 attr
->spot_location
.y
= height
;
2182 attr
->preedit_area
.x
= 0;
2183 attr
->preedit_area
.y
= 0;
2184 attr
->preedit_area
.width
= width
;
2185 attr
->preedit_area
.height
= height
;
2186 attr
->preedit_fontset
= widget
->style
->font
;
2191 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2193 if (win
->m_ic
== NULL
)
2194 g_warning ("Can't create input context.");
2197 mask
= gdk_window_get_events (widget
->window
);
2198 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2199 gdk_window_set_events (widget
->window
, mask
);
2201 if (GTK_WIDGET_HAS_FOCUS(widget
))
2202 gdk_im_begin (win
->m_ic
, widget
->window
);
2209 //-----------------------------------------------------------------------------
2210 // InsertChild for wxWindowGTK.
2211 //-----------------------------------------------------------------------------
2213 /* Callback for wxWindowGTK. This very strange beast has to be used because
2214 * C++ has no virtual methods in a constructor. We have to emulate a
2215 * virtual function here as wxNotebook requires a different way to insert
2216 * a child in it. I had opted for creating a wxNotebookPage window class
2217 * which would have made this superfluous (such in the MDI window system),
2218 * but no-one was listening to me... */
2220 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2222 /* the window might have been scrolled already, do we
2223 have to adapt the position */
2224 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2225 child
->m_x
+= pizza
->xoffset
;
2226 child
->m_y
+= pizza
->yoffset
;
2228 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2229 GTK_WIDGET(child
->m_widget
),
2236 //-----------------------------------------------------------------------------
2238 //-----------------------------------------------------------------------------
2240 wxWindow
*wxGetActiveWindow()
2242 // the cast is necessary when we compile in wxUniversal mode
2243 return (wxWindow
*)g_focusWindow
;
2246 //-----------------------------------------------------------------------------
2248 //-----------------------------------------------------------------------------
2250 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2252 #ifdef __WXUNIVERSAL__
2253 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2255 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2256 #endif // __WXUNIVERSAL__/__WXGTK__
2258 void wxWindowGTK::Init()
2264 m_widget
= (GtkWidget
*) NULL
;
2265 m_wxwindow
= (GtkWidget
*) NULL
;
2266 m_focusWidget
= (GtkWidget
*) NULL
;
2276 m_needParent
= TRUE
;
2277 m_isBeingDeleted
= FALSE
;
2280 m_nativeSizeEvent
= FALSE
;
2282 m_hasScrolling
= FALSE
;
2283 m_isScrolling
= FALSE
;
2285 m_hAdjust
= (GtkAdjustment
*) NULL
;
2286 m_vAdjust
= (GtkAdjustment
*) NULL
;
2287 m_oldHorizontalPos
= 0.0;
2288 m_oldVerticalPos
= 0.0;
2291 m_widgetStyle
= (GtkStyle
*) NULL
;
2293 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2295 m_isStaticBox
= FALSE
;
2296 m_isRadioButton
= FALSE
;
2297 m_isListBox
= FALSE
;
2299 m_acceptsFocus
= FALSE
;
2301 m_clipPaintRegion
= FALSE
;
2303 m_cursor
= *wxSTANDARD_CURSOR
;
2305 m_delayedForegroundColour
= FALSE
;
2306 m_delayedBackgroundColour
= FALSE
;
2309 m_ic
= (GdkIC
*) NULL
;
2310 m_icattr
= (GdkICAttr
*) NULL
;
2314 wxWindowGTK::wxWindowGTK()
2319 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2324 const wxString
&name
)
2328 Create( parent
, id
, pos
, size
, style
, name
);
2331 bool wxWindowGTK::Create( wxWindow
*parent
,
2336 const wxString
&name
)
2338 if (!PreCreation( parent
, pos
, size
) ||
2339 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2341 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2345 m_insertCallback
= wxInsertChildInWindow
;
2347 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2348 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2350 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2352 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2353 scroll_class
->scrollbar_spacing
= 0;
2355 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2357 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2358 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2360 m_wxwindow
= gtk_pizza_new();
2362 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2364 #ifndef __WXUNIVERSAL__
2365 #if (GTK_MINOR_VERSION > 0)
2366 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2368 if (HasFlag(wxRAISED_BORDER
))
2370 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2372 else if (HasFlag(wxSUNKEN_BORDER
))
2374 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2376 else if (HasFlag(wxSIMPLE_BORDER
))
2378 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2382 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2384 #else // GTK_MINOR_VERSION == 0
2385 GtkViewport
*viewport
= GTK_VIEWPORT(scrolledWindow
->viewport
);
2387 if (HasFlag(wxRAISED_BORDER
))
2389 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_OUT
);
2391 else if (HasFlag(wxSUNKEN_BORDER
))
2393 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_IN
);
2397 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_NONE
);
2399 #endif // GTK_MINOR_VERSION
2400 #endif // __WXUNIVERSAL__
2402 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2403 m_acceptsFocus
= TRUE
;
2405 #if (GTK_MINOR_VERSION == 0)
2406 // shut the viewport up
2407 gtk_viewport_set_hadjustment( viewport
, (GtkAdjustment
*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2408 gtk_viewport_set_vadjustment( viewport
, (GtkAdjustment
*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2409 #endif // GTK_MINOR_VERSION == 0
2411 // I _really_ don't want scrollbars in the beginning
2412 m_vAdjust
->lower
= 0.0;
2413 m_vAdjust
->upper
= 1.0;
2414 m_vAdjust
->value
= 0.0;
2415 m_vAdjust
->step_increment
= 1.0;
2416 m_vAdjust
->page_increment
= 1.0;
2417 m_vAdjust
->page_size
= 5.0;
2418 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2419 m_hAdjust
->lower
= 0.0;
2420 m_hAdjust
->upper
= 1.0;
2421 m_hAdjust
->value
= 0.0;
2422 m_hAdjust
->step_increment
= 1.0;
2423 m_hAdjust
->page_increment
= 1.0;
2424 m_hAdjust
->page_size
= 5.0;
2425 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2427 // these handlers block mouse events to any window during scrolling such as
2428 // motion events and prevent GTK and wxWindows from fighting over where the
2431 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2432 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2434 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2435 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2437 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2438 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2440 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2441 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2443 // these handlers get notified when screen updates are required either when
2444 // scrolling or when the window size (and therefore scrollbar configuration)
2447 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2448 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2449 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2450 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2452 gtk_widget_show( m_wxwindow
);
2455 m_parent
->DoAddChild( this );
2457 m_focusWidget
= m_wxwindow
;
2466 wxWindowGTK::~wxWindowGTK()
2468 if (g_focusWindow
== this)
2469 g_focusWindow
= NULL
;
2471 if (g_activeFrame
== this)
2472 g_activeFrame
= NULL
;
2474 m_isBeingDeleted
= TRUE
;
2483 m_parent
->RemoveChild( this );
2487 gdk_ic_destroy (m_ic
);
2489 gdk_ic_attr_destroy (m_icattr
);
2494 #if DISABLE_STYLE_IF_BROKEN_THEME
2495 // don't delete if it's a pixmap theme style
2496 if (!m_widgetStyle
->engine_data
)
2497 gtk_style_unref( m_widgetStyle
);
2499 m_widgetStyle
= (GtkStyle
*) NULL
;
2504 gtk_widget_destroy( m_wxwindow
);
2505 m_wxwindow
= (GtkWidget
*) NULL
;
2510 gtk_widget_destroy( m_widget
);
2511 m_widget
= (GtkWidget
*) NULL
;
2515 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2517 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2519 /* this turns -1 into 20 so that a minimal window is
2520 visible even although -1,-1 has been given as the
2521 size of the window. the same trick is used in other
2522 ports and should make debugging easier */
2523 m_width
= WidthDefault(size
.x
);
2524 m_height
= HeightDefault(size
.y
);
2529 /* some reasonable defaults */
2534 m_x
= (gdk_screen_width () - m_width
) / 2;
2535 if (m_x
< 10) m_x
= 10;
2539 m_y
= (gdk_screen_height () - m_height
) / 2;
2540 if (m_y
< 10) m_y
= 10;
2547 void wxWindowGTK::PostCreation()
2549 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2555 // these get reported to wxWindows -> wxPaintEvent
2557 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2559 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2560 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2562 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2563 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2565 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2567 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2568 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2572 // these are called when the "sunken" or "raised" borders are drawn */
2573 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2574 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2576 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2577 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2582 if (m_focusWidget
== NULL
)
2583 m_focusWidget
= m_widget
;
2586 if (GetClassInfo() && GetClassInfo()->GetClassName())
2587 wxPrintf( GetClassInfo()->GetClassName() );
2591 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2592 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2594 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2595 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2597 // connect to the various key and mouse handlers
2599 GtkWidget
*connect_widget
= GetConnectWidget();
2601 ConnectWidget( connect_widget
);
2603 /* We cannot set colours, fonts and cursors before the widget has
2604 been realized, so we do this directly after realization */
2605 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2606 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2610 // Catch native resize events
2611 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2612 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2614 // Initialize XIM support
2615 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2616 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2618 // And resize XIM window
2619 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2620 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2623 if (!GTK_IS_COMBO(m_widget
))
2625 // This is needed if we want to add our windows into native
2626 // GTK control, such as the toolbar. With this callback, the
2627 // toolbar gets to know the correct size (the one set by the
2628 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2629 // when moving to GTK 2.0.
2630 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2631 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2637 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2639 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2640 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2642 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2643 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2645 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2646 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2648 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2649 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2651 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2652 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2654 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2655 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2657 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2658 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2661 bool wxWindowGTK::Destroy()
2663 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2667 return wxWindowBase::Destroy();
2670 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2672 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2675 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2677 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2678 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2681 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2684 if (m_resizing
) return; /* I don't like recursions */
2687 int currentX
, currentY
;
2688 GetPosition(¤tX
, ¤tY
);
2693 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2695 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2697 /* don't set the size for children of wxNotebook, just take the values. */
2705 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2707 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2709 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2710 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2711 if (width
!= -1) m_width
= width
;
2712 if (height
!= -1) m_height
= height
;
2716 m_x
= x
+ pizza
->xoffset
;
2717 m_y
= y
+ pizza
->yoffset
;
2722 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2724 if (width
== -1) m_width
= 80;
2727 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2729 if (height
== -1) m_height
= 26;
2732 if ((m_minWidth
!= -1) && (m_width
< m_minWidth
)) m_width
= m_minWidth
;
2733 if ((m_minHeight
!= -1) && (m_height
< m_minHeight
)) m_height
= m_minHeight
;
2734 if ((m_maxWidth
!= -1) && (m_width
> m_maxWidth
)) m_width
= m_maxWidth
;
2735 if ((m_maxHeight
!= -1) && (m_height
> m_maxHeight
)) m_height
= m_maxHeight
;
2738 int bottom_border
= 0;
2740 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2742 /* the default button has a border around it */
2747 DoMoveWindow( m_x
-border
,
2750 m_height
+border
+bottom_border
);
2755 /* Sometimes the client area changes size without the
2756 whole windows's size changing, but if the whole
2757 windows's size doesn't change, no wxSizeEvent will
2758 normally be sent. Here we add an extra test if
2759 the client test has been changed and this will
2761 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2765 wxPrintf( "OnSize sent from " );
2766 if (GetClassInfo() && GetClassInfo()->GetClassName())
2767 wxPrintf( GetClassInfo()->GetClassName() );
2768 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2771 if (!m_nativeSizeEvent
)
2773 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2774 event
.SetEventObject( this );
2775 GetEventHandler()->ProcessEvent( event
);
2781 void wxWindowGTK::OnInternalIdle()
2783 // Update invalidated regions.
2786 // Synthetize activate events.
2787 if ( g_sendActivateEvent
!= -1 )
2789 bool activate
= g_sendActivateEvent
!= 0;
2792 g_sendActivateEvent
= -1;
2794 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2797 if ( g_activeFrameLostFocus
)
2799 if ( g_activeFrame
)
2801 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2802 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2803 event
.SetEventObject(g_activeFrame
);
2804 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2805 g_activeFrame
= NULL
;
2807 g_activeFrameLostFocus
= FALSE
;
2810 wxCursor cursor
= m_cursor
;
2811 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2815 /* I now set the cursor anew in every OnInternalIdle call
2816 as setting the cursor in a parent window also effects the
2817 windows above so that checking for the current cursor is
2822 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2824 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2826 if (!g_globalCursor
.Ok())
2827 cursor
= *wxSTANDARD_CURSOR
;
2829 window
= m_widget
->window
;
2830 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2831 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2837 GdkWindow
*window
= m_widget
->window
;
2838 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2839 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2847 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2849 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2851 if (width
) (*width
) = m_width
;
2852 if (height
) (*height
) = m_height
;
2855 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2857 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2861 SetSize( width
, height
);
2868 #ifndef __WXUNIVERSAL__
2869 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2871 /* when using GTK 1.2 we set the shadow border size to 2 */
2875 if (HasFlag(wxSIMPLE_BORDER
))
2877 /* when using GTK 1.2 we set the simple border size to 1 */
2881 #endif // __WXUNIVERSAL__
2885 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2887 GtkRequisition vscroll_req
;
2888 vscroll_req
.width
= 2;
2889 vscroll_req
.height
= 2;
2890 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2891 (scroll_window
->vscrollbar
, &vscroll_req
);
2893 GtkRequisition hscroll_req
;
2894 hscroll_req
.width
= 2;
2895 hscroll_req
.height
= 2;
2896 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2897 (scroll_window
->hscrollbar
, &hscroll_req
);
2899 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2901 if (scroll_window
->vscrollbar_visible
)
2903 dw
+= vscroll_req
.width
;
2904 dw
+= scroll_class
->scrollbar_spacing
;
2907 if (scroll_window
->hscrollbar_visible
)
2909 dh
+= hscroll_req
.height
;
2910 dh
+= scroll_class
->scrollbar_spacing
;
2914 SetSize( width
+dw
, height
+dh
);
2918 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2920 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2924 if (width
) (*width
) = m_width
;
2925 if (height
) (*height
) = m_height
;
2932 #ifndef __WXUNIVERSAL__
2933 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2935 /* when using GTK 1.2 we set the shadow border size to 2 */
2939 if (HasFlag(wxSIMPLE_BORDER
))
2941 /* when using GTK 1.2 we set the simple border size to 1 */
2945 #endif // __WXUNIVERSAL__
2949 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2951 GtkRequisition vscroll_req
;
2952 vscroll_req
.width
= 2;
2953 vscroll_req
.height
= 2;
2954 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2955 (scroll_window
->vscrollbar
, &vscroll_req
);
2957 GtkRequisition hscroll_req
;
2958 hscroll_req
.width
= 2;
2959 hscroll_req
.height
= 2;
2960 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2961 (scroll_window
->hscrollbar
, &hscroll_req
);
2963 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2965 if (scroll_window
->vscrollbar_visible
)
2967 dw
+= vscroll_req
.width
;
2968 dw
+= scroll_class
->scrollbar_spacing
;
2971 if (scroll_window
->hscrollbar_visible
)
2973 dh
+= hscroll_req
.height
;
2974 dh
+= scroll_class
->scrollbar_spacing
;
2978 if (width
) (*width
) = m_width
- dw
;
2979 if (height
) (*height
) = m_height
- dh
;
2983 printf( "GetClientSize, name %s ", GetName().c_str() );
2984 if (width) printf( " width = %d", (*width) );
2985 if (height) printf( " height = %d", (*height) );
2990 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2992 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2996 if (m_parent
&& m_parent
->m_wxwindow
)
2998 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2999 dx
= pizza
->xoffset
;
3000 dy
= pizza
->yoffset
;
3003 if (x
) (*x
) = m_x
- dx
;
3004 if (y
) (*y
) = m_y
- dy
;
3007 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3009 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3011 if (!m_widget
->window
) return;
3013 GdkWindow
*source
= (GdkWindow
*) NULL
;
3015 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3017 source
= m_widget
->window
;
3021 gdk_window_get_origin( source
, &org_x
, &org_y
);
3025 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3027 org_x
+= m_widget
->allocation
.x
;
3028 org_y
+= m_widget
->allocation
.y
;
3036 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3038 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3040 if (!m_widget
->window
) return;
3042 GdkWindow
*source
= (GdkWindow
*) NULL
;
3044 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3046 source
= m_widget
->window
;
3050 gdk_window_get_origin( source
, &org_x
, &org_y
);
3054 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3056 org_x
+= m_widget
->allocation
.x
;
3057 org_y
+= m_widget
->allocation
.y
;
3065 bool wxWindowGTK::Show( bool show
)
3067 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3069 if (!wxWindowBase::Show(show
))
3076 gtk_widget_show( m_widget
);
3078 gtk_widget_hide( m_widget
);
3083 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3085 win
->OnParentEnable(enable
);
3087 // Recurse, so that children have the opportunity to Do The Right Thing
3088 // and reset colours that have been messed up by a parent's (really ancestor's)
3090 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3092 node
= node
->GetNext() )
3094 wxWindow
*child
= node
->GetData();
3095 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3096 wxWindowNotifyEnable(child
, enable
);
3100 bool wxWindowGTK::Enable( bool enable
)
3102 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3104 if (!wxWindowBase::Enable(enable
))
3110 gtk_widget_set_sensitive( m_widget
, enable
);
3112 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3114 wxWindowNotifyEnable(this, enable
);
3119 int wxWindowGTK::GetCharHeight() const
3121 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3123 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3125 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3127 return font
->ascent
+ font
->descent
;
3130 int wxWindowGTK::GetCharWidth() const
3132 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3134 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3136 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3138 return gdk_string_width( font
, "H" );
3141 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3145 int *externalLeading
,
3146 const wxFont
*theFont
) const
3148 wxFont fontToUse
= m_font
;
3149 if (theFont
) fontToUse
= *theFont
;
3151 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3153 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3154 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3155 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3156 if (descent
) (*descent
) = font
->descent
;
3157 if (externalLeading
) (*externalLeading
) = 0; // ??
3160 void wxWindowGTK::SetFocus()
3162 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3165 wxPrintf( "SetFocus from " );
3166 if (GetClassInfo() && GetClassInfo()->GetClassName())
3167 wxPrintf( GetClassInfo()->GetClassName() );
3173 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3175 // see comment in gtk_window_focus_out_callback()
3176 gs_widgetLastFocus
= m_wxwindow
;
3177 gtk_widget_grab_focus (m_wxwindow
);
3182 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3184 gtk_widget_grab_focus (m_widget
);
3186 else if (GTK_IS_CONTAINER(m_widget
))
3188 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3197 wxPrintf( "SetFocus finished in " );
3198 if (GetClassInfo() && GetClassInfo()->GetClassName())
3199 wxPrintf( GetClassInfo()->GetClassName() );
3205 bool wxWindowGTK::AcceptsFocus() const
3207 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3210 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3212 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3214 wxWindowGTK
*oldParent
= m_parent
,
3215 *newParent
= (wxWindowGTK
*)newParentBase
;
3217 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3219 if ( !wxWindowBase::Reparent(newParent
) )
3222 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3224 /* prevent GTK from deleting the widget arbitrarily */
3225 gtk_widget_ref( m_widget
);
3229 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3232 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3236 /* insert GTK representation */
3237 (*(newParent
->m_insertCallback
))(newParent
, this);
3240 /* reverse: prevent GTK from deleting the widget arbitrarily */
3241 gtk_widget_unref( m_widget
);
3246 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3248 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3250 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3252 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3257 /* insert GTK representation */
3258 (*m_insertCallback
)(this, child
);
3261 void wxWindowGTK::Raise()
3263 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3265 if (!m_widget
->window
) return;
3267 gdk_window_raise( m_widget
->window
);
3270 void wxWindowGTK::Lower()
3272 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3274 if (!m_widget
->window
) return;
3276 gdk_window_lower( m_widget
->window
);
3279 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3281 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3283 if (cursor
== m_cursor
)
3287 wxapp_install_idle_handler();
3289 if (cursor
== wxNullCursor
)
3290 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3292 return wxWindowBase::SetCursor( cursor
);
3295 void wxWindowGTK::WarpPointer( int x
, int y
)
3297 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3299 // We provide this function ourselves as it is
3300 // missing in GDK (top of this file).
3302 GdkWindow
*window
= (GdkWindow
*) NULL
;
3304 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3306 window
= GetConnectWidget()->window
;
3309 gdk_window_warp_pointer( window
, x
, y
);
3312 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3314 if (!m_widget
) return;
3315 if (!m_widget
->window
) return;
3317 // temporarily hide the caret to avoid nasty interactions between caret
3318 // drawing and the window contents redraw
3319 #if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3320 wxCaretSuspend
cs((wxWindow
*)this);
3321 #endif // wxUSE_CARET
3323 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3327 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3328 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3332 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3333 m_clearRegion
.Clear();
3334 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3342 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3343 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3347 GdkRectangle gdk_rect
;
3348 gdk_rect
.x
= rect
->x
;
3349 gdk_rect
.y
= rect
->y
;
3350 gdk_rect
.width
= rect
->width
;
3351 gdk_rect
.height
= rect
->height
;
3352 gtk_widget_draw( m_widget
, &gdk_rect
);
3359 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3360 m_updateRegion
.Clear();
3361 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3365 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3370 void wxWindowGTK::Update()
3372 if (!m_updateRegion
.IsEmpty())
3374 GtkSendPaintEvents();
3378 void wxWindowGTK::GtkSendPaintEvents()
3382 m_clearRegion
.Clear();
3383 m_updateRegion
.Clear();
3387 m_clipPaintRegion
= TRUE
;
3389 if (!m_clearRegion
.IsEmpty())
3391 wxWindowDC
dc( (wxWindow
*)this );
3392 dc
.SetClippingRegion( m_clearRegion
);
3394 wxEraseEvent
erase_event( GetId(), &dc
);
3395 erase_event
.SetEventObject( this );
3397 if (!GetEventHandler()->ProcessEvent(erase_event
))
3399 wxRegionIterator
upd( m_clearRegion
);
3402 gdk_window_clear_area( GTK_PIZZA(m_wxwindow
)->bin_window
,
3403 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3407 m_clearRegion
.Clear();
3410 wxNcPaintEvent
nc_paint_event( GetId() );
3411 nc_paint_event
.SetEventObject( this );
3412 GetEventHandler()->ProcessEvent( nc_paint_event
);
3414 wxPaintEvent
paint_event( GetId() );
3415 paint_event
.SetEventObject( this );
3416 GetEventHandler()->ProcessEvent( paint_event
);
3418 m_clipPaintRegion
= FALSE
;
3420 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3421 if (g_list_length(pizza
->children
) > 0)
3423 // The following code will result in all window-less widgets
3424 // being redrawn because the wxWindows class is allowed to
3425 // paint over the window-less widgets.
3426 GList
*children
= pizza
->children
;
3429 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3430 children
= children
->next
;
3432 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3433 GTK_WIDGET_DRAWABLE (child
->widget
))
3435 // Get intersection of widget area and update region
3436 wxRegion
region( m_updateRegion
);
3437 region
.Intersect( child
->widget
->allocation
.x
,
3438 child
->widget
->allocation
.y
,
3439 child
->widget
->allocation
.width
,
3440 child
->widget
->allocation
.height
);
3442 // Redraw the whole widget anyway
3443 if (!region
.IsEmpty())
3444 gtk_widget_draw( child
->widget
, NULL
);
3449 m_updateRegion
.Clear();
3452 void wxWindowGTK::Clear()
3454 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3456 if (!m_widget
->window
) return;
3458 if (m_wxwindow
&& m_wxwindow
->window
)
3460 // gdk_window_clear( m_wxwindow->window );
3465 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3467 wxWindowBase::DoSetToolTip(tip
);
3470 m_tooltip
->Apply( (wxWindow
*)this );
3473 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3475 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3477 #endif // wxUSE_TOOLTIPS
3479 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3481 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3483 if (!wxWindowBase::SetBackgroundColour(colour
))
3485 // don't leave if the GTK widget has just
3487 if (!m_delayedBackgroundColour
) return FALSE
;
3490 GdkWindow
*window
= (GdkWindow
*) NULL
;
3492 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3494 window
= GetConnectWidget()->window
;
3498 // indicate that a new style has been set
3499 // but it couldn't get applied as the
3500 // widget hasn't been realized yet.
3501 m_delayedBackgroundColour
= TRUE
;
3505 (m_wxwindow
->window
) &&
3506 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3508 /* wxMSW doesn't clear the window here. I don't do that either to
3509 provide compatibility. call Clear() to do the job. */
3511 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3512 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3520 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3522 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3524 if (!wxWindowBase::SetForegroundColour(colour
))
3526 // don't leave if the GTK widget has just
3528 if (!m_delayedForegroundColour
) return FALSE
;
3531 GdkWindow
*window
= (GdkWindow
*) NULL
;
3533 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3535 window
= GetConnectWidget()->window
;
3539 // indicate that a new style has been set
3540 // but it couldn't get applied as the
3541 // widget hasn't been realized yet.
3542 m_delayedForegroundColour
= TRUE
;
3550 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3554 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3556 /* FIXME: is this necessary? */
3557 _G_TYPE_IGC(remake
, GtkObjectClass
) = _G_TYPE_IGC(m_widgetStyle
, GtkObjectClass
);
3559 remake
->klass
= m_widgetStyle
->klass
;
3562 gtk_style_unref( m_widgetStyle
);
3563 m_widgetStyle
= remake
;
3567 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3570 def
= gtk_widget_get_default_style();
3572 m_widgetStyle
= gtk_style_copy( def
);
3574 /* FIXME: is this necessary? */
3575 _G_TYPE_IGC(m_widgetStyle
, GtkObjectClass
) = _G_TYPE_IGC(def
, GtkObjectClass
);
3577 m_widgetStyle
->klass
= def
->klass
;
3581 return m_widgetStyle
;
3584 void wxWindowGTK::SetWidgetStyle()
3586 #if DISABLE_STYLE_IF_BROKEN_THEM
3587 if (m_widget
->style
->engine_data
)
3589 static bool s_warningPrinted
= FALSE
;
3590 if (!s_warningPrinted
)
3592 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3593 s_warningPrinted
= TRUE
;
3595 m_widgetStyle
= m_widget
->style
;
3600 GtkStyle
*style
= GetWidgetStyle();
3602 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3604 gdk_font_unref( style
->font
);
3605 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
3608 if (m_foregroundColour
.Ok())
3610 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3611 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3613 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3614 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3615 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3619 // Try to restore the gtk default style. This is still a little
3620 // oversimplified for what is probably really needed here for controls
3621 // other than buttons, but is better than not being able to (re)set a
3622 // control's foreground colour to *wxBLACK -- RL
3623 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3626 def
= gtk_widget_get_default_style();
3628 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3629 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3630 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3634 if (m_backgroundColour
.Ok())
3636 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3637 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3639 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3640 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3641 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3642 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3643 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3644 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3645 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3646 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3650 // Try to restore the gtk default style. This is still a little
3651 // oversimplified for what is probably really needed here for controls
3652 // other than buttons, but is better than not being able to (re)set a
3653 // control's background colour to default grey and means resetting a
3654 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3656 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3659 def
= gtk_widget_get_default_style();
3661 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3662 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3663 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3664 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3665 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3666 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3667 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3668 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3673 void wxWindowGTK::ApplyWidgetStyle()
3677 //-----------------------------------------------------------------------------
3678 // Pop-up menu stuff
3679 //-----------------------------------------------------------------------------
3681 #if wxUSE_MENUS_NATIVE
3684 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3686 *is_waiting
= FALSE
;
3689 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3691 menu
->SetInvokingWindow( win
);
3692 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3695 wxMenuItem
*menuitem
= node
->GetData();
3696 if (menuitem
->IsSubMenu())
3698 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3701 node
= node
->GetNext();
3705 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3706 // wxPopupMenuPositionCallback()
3708 // should be safe even in the MT case as the user can hardly popup 2 menus
3709 // simultaneously, can he?
3710 static gint gs_pop_x
= 0;
3711 static gint gs_pop_y
= 0;
3713 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3715 gpointer
WXUNUSED(user_data
) )
3717 // ensure that the menu appears entirely on screen
3719 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3721 wxSize sizeScreen
= wxGetDisplaySize();
3723 gint xmax
= sizeScreen
.x
- req
.width
,
3724 ymax
= sizeScreen
.y
- req
.height
;
3726 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3727 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3730 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3732 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3734 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3736 SetInvokingWindow( menu
, this );
3742 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3744 bool is_waiting
= TRUE
;
3746 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3748 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3749 (gpointer
)&is_waiting
);
3752 GTK_MENU(menu
->m_menu
),
3753 (GtkWidget
*) NULL
, // parent menu shell
3754 (GtkWidget
*) NULL
, // parent menu item
3755 wxPopupMenuPositionCallback
, // function to position it
3756 NULL
, // client data
3757 0, // button used to activate it
3758 gs_timeLastClick
// the time of activation
3763 while (gtk_events_pending())
3764 gtk_main_iteration();
3770 #endif // wxUSE_MENUS_NATIVE
3772 #if wxUSE_DRAG_AND_DROP
3774 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3776 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3778 GtkWidget
*dnd_widget
= GetConnectWidget();
3780 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3782 if (m_dropTarget
) delete m_dropTarget
;
3783 m_dropTarget
= dropTarget
;
3785 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3788 #endif // wxUSE_DRAG_AND_DROP
3790 GtkWidget
* wxWindowGTK::GetConnectWidget()
3792 GtkWidget
*connect_widget
= m_widget
;
3793 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3795 return connect_widget
;
3798 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3801 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3803 return (window
== m_widget
->window
);
3806 bool wxWindowGTK::SetFont( const wxFont
&font
)
3808 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3810 if (!wxWindowBase::SetFont(font
))
3815 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3816 if ( sysbg
== m_backgroundColour
)
3818 m_backgroundColour
= wxNullColour
;
3820 m_backgroundColour
= sysbg
;
3830 void wxWindowGTK::DoCaptureMouse()
3832 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3834 GdkWindow
*window
= (GdkWindow
*) NULL
;
3836 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3838 window
= GetConnectWidget()->window
;
3840 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3842 wxCursor
* cursor
= & m_cursor
;
3844 cursor
= wxSTANDARD_CURSOR
;
3846 gdk_pointer_grab( window
, FALSE
,
3848 (GDK_BUTTON_PRESS_MASK
|
3849 GDK_BUTTON_RELEASE_MASK
|
3850 GDK_POINTER_MOTION_HINT_MASK
|
3851 GDK_POINTER_MOTION_MASK
),
3853 cursor
->GetCursor(),
3854 (guint32
)GDK_CURRENT_TIME
);
3855 g_captureWindow
= this;
3856 g_captureWindowHasMouse
= TRUE
;
3859 void wxWindowGTK::DoReleaseMouse()
3861 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3863 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3865 g_captureWindow
= (wxWindowGTK
*) NULL
;
3867 GdkWindow
*window
= (GdkWindow
*) NULL
;
3869 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3871 window
= GetConnectWidget()->window
;
3876 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3880 wxWindow
*wxWindowBase::GetCapture()
3882 return (wxWindow
*)g_captureWindow
;
3885 bool wxWindowGTK::IsRetained() const
3890 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3891 int range
, bool refresh
)
3893 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3895 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3897 m_hasScrolling
= TRUE
;
3899 if (orient
== wxHORIZONTAL
)
3901 float fpos
= (float)pos
;
3902 float frange
= (float)range
;
3903 float fthumb
= (float)thumbVisible
;
3904 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3905 if (fpos
< 0.0) fpos
= 0.0;
3907 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3908 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3910 SetScrollPos( orient
, pos
, refresh
);
3914 m_oldHorizontalPos
= fpos
;
3916 m_hAdjust
->lower
= 0.0;
3917 m_hAdjust
->upper
= frange
;
3918 m_hAdjust
->value
= fpos
;
3919 m_hAdjust
->step_increment
= 1.0;
3920 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3921 m_hAdjust
->page_size
= fthumb
;
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_vAdjust
->upper
) < 0.2) &&
3932 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3934 SetScrollPos( orient
, pos
, refresh
);
3938 m_oldVerticalPos
= fpos
;
3940 m_vAdjust
->lower
= 0.0;
3941 m_vAdjust
->upper
= frange
;
3942 m_vAdjust
->value
= fpos
;
3943 m_vAdjust
->step_increment
= 1.0;
3944 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3945 m_vAdjust
->page_size
= fthumb
;
3948 if (orient
== wxHORIZONTAL
)
3949 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3951 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3954 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3956 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3958 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3960 if (orient
== wxHORIZONTAL
)
3962 float fpos
= (float)pos
;
3963 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3964 if (fpos
< 0.0) fpos
= 0.0;
3965 m_oldHorizontalPos
= fpos
;
3967 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3968 m_hAdjust
->value
= fpos
;
3972 float fpos
= (float)pos
;
3973 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
3974 if (fpos
< 0.0) fpos
= 0.0;
3975 m_oldVerticalPos
= fpos
;
3977 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
3978 m_vAdjust
->value
= fpos
;
3981 if (m_wxwindow
->window
)
3983 if (orient
== wxHORIZONTAL
)
3985 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
3986 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
3988 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
3990 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
3991 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
3995 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
3996 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
3998 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4000 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4001 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4006 int wxWindowGTK::GetScrollThumb( int orient
) const
4008 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4010 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4012 if (orient
== wxHORIZONTAL
)
4013 return (int)(m_hAdjust
->page_size
+0.5);
4015 return (int)(m_vAdjust
->page_size
+0.5);
4018 int wxWindowGTK::GetScrollPos( int orient
) const
4020 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4022 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4024 if (orient
== wxHORIZONTAL
)
4025 return (int)(m_hAdjust
->value
+0.5);
4027 return (int)(m_vAdjust
->value
+0.5);
4030 int wxWindowGTK::GetScrollRange( 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
->upper
+0.5);
4039 return (int)(m_vAdjust
->upper
+0.5);
4042 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4044 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4046 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4048 // No scrolling requested.
4049 if ((dx
== 0) && (dy
== 0)) return;
4051 if (!m_updateRegion
.IsEmpty())
4053 m_updateRegion
.Offset( dx
, dy
);
4057 GetClientSize( &cw
, &ch
);
4058 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4061 if (!m_clearRegion
.IsEmpty())
4063 m_clearRegion
.Offset( dx
, dy
);
4067 GetClientSize( &cw
, &ch
);
4068 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4073 m_clipPaintRegion
= TRUE
;
4075 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4077 m_clipPaintRegion
= FALSE
;
4081 if (m_children
.GetCount() > 0)
4083 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4087 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
4089 pizza
->xoffset
-= dx
;
4090 pizza
->yoffset
-= dy
;
4092 GdkGC
*m_scrollGC
= gdk_gc_new( pizza
->bin_window
);
4093 gdk_gc_set_exposures( m_scrollGC
, TRUE
);
4097 GetClientSize( &cw
, &ch
);
4098 int w
= cw
- abs(dx
);
4099 int h
= ch
- abs(dy
);
4101 if ((h
< 0) || (w
< 0))
4109 if (dx
< 0) s_x
= -dx
;
4110 if (dy
< 0) s_y
= -dy
;
4113 if (dx
> 0) d_x
= dx
;
4114 if (dy
> 0) d_y
= dy
;
4116 gdk_window_copy_area( pizza
->bin_window
, m_scrollGC
, d_x
, d_y
,
4117 pizza
->bin_window
, s_x
, s_y
, w
, h
);
4120 if (dx
< 0) rect
.x
= cw
+dx
; else rect
.x
= 0;
4121 if (dy
< 0) rect
.y
= ch
+dy
; else rect
.y
= 0;
4122 if (dy
!= 0) rect
.width
= cw
; else rect
.width
= abs(dx
);
4123 if (dx
!= 0) rect
.height
= ch
; else rect
.height
= abs(dy
);
4125 Refresh( TRUE
, &rect
);
4128 gdk_gc_unref( m_scrollGC
);
4133 // Find the wxWindow at the current mouse position, also returning the mouse
4135 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4137 pt
= wxGetMousePosition();
4138 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4142 // Get the current mouse position.
4143 wxPoint
wxGetMousePosition()
4145 /* This crashes when used within wxHelpContext,
4146 so we have to use the X-specific implementation below.
4148 GdkModifierType *mask;
4149 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4151 return wxPoint(x, y);
4155 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4157 return wxPoint(-999, -999);
4159 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4160 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4161 Window rootReturn
, childReturn
;
4162 int rootX
, rootY
, winX
, winY
;
4163 unsigned int maskReturn
;
4165 XQueryPointer (display
,
4169 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4170 return wxPoint(rootX
, rootY
);