]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/window.cpp
moved knd handling logic from wxPanel to wxControlContainer (sorry for
[wxWidgets.git] / src / gtk / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "window.h"
13 #endif
14
15 #ifdef __VMS
16 #define XWarpPointer XWARPPOINTER
17 #endif
18
19 #include "wx/defs.h"
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
22 #include "wx/frame.h"
23 #include "wx/app.h"
24 #include "wx/layout.h"
25 #include "wx/utils.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28
29 #if wxUSE_DRAG_AND_DROP
30 #include "wx/dnd.h"
31 #endif
32
33 #if wxUSE_TOOLTIPS
34 #include "wx/tooltip.h"
35 #endif
36
37 #if wxUSE_CARET
38 #include "wx/caret.h"
39 #endif // wxUSE_CARET
40
41 #if wxUSE_TEXTCTRL
42 #include "wx/textctrl.h"
43 #endif
44
45 #include "wx/menu.h"
46 #include "wx/statusbr.h"
47 #include "wx/intl.h"
48 #include "wx/settings.h"
49 #include "wx/log.h"
50
51 #ifdef __WXDEBUG__
52 #include "wx/thread.h"
53 #endif
54
55 #include <math.h>
56
57 #include <gdk/gdk.h>
58 #include <gtk/gtk.h>
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
61 #include <gdk/gdkx.h>
62
63 #include <gtk/gtk.h>
64 #include <gtk/gtkprivate.h>
65
66 #include "wx/gtk/win_gtk.h"
67
68 //-----------------------------------------------------------------------------
69 // documentation on internals
70 //-----------------------------------------------------------------------------
71
72 /*
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.
78
79 I)
80
81 What does wxWindow do? It contains the common interface for the following
82 jobs of its descendants:
83
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.
87
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.
94
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
97 as above.
98
99 4) Provide the entire mechanism for scrolling widgets. This actual inter-
100 face for this is usually in wxScrolledWindow, but the GTK implementation
101 is in this class.
102
103 5) A multitude of helper or extra methods for special purposes, such as
104 Drag'n'Drop, managing validators etc.
105
106 6) Display a border (sunken, raised, simple or none).
107
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
117 this directory.
118
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)
126
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
134 the type GtkPizza.
135
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.
142
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.
146
147 II)
148
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.
158
159 III)
160
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
174 GTK).
175
176 IV)
177
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.
183
184 V)
185
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.
195
196 */
197
198 //-----------------------------------------------------------------------------
199 // data
200 //-----------------------------------------------------------------------------
201
202 extern wxList wxPendingDelete;
203 extern bool g_blockEventsOnDrag;
204 extern bool g_blockEventsOnScroll;
205 extern wxCursor g_globalCursor;
206
207 // mouse capture state: the window which has it and if the mouse is currently
208 // inside it
209 static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
210 static bool g_captureWindowHasMouse = FALSE;
211
212 /* extern */ wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
213
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;
218
219 // if we detect that the app has got/lost the focus, we set this variable to
220 // either TRUE or FALSE and an activate event will be sent during the next
221 // OnIdle() call and it is reset to -1: this value means that we shouldn't
222 // send any activate events at all
223 static int g_sendActivateEvent = -1;
224
225 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
226 the last click here */
227 static guint32 gs_timeLastClick = 0;
228
229 extern bool g_mainThreadLocked;
230
231 //-----------------------------------------------------------------------------
232 // debug
233 //-----------------------------------------------------------------------------
234
235 #ifndef __WXGTK20__
236 #define DISABLE_STYLE_IF_BROKEN_THEME 1
237 #endif
238
239 #ifdef __WXDEBUG__
240
241 #if wxUSE_THREADS
242 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
243 #else
244 # define DEBUG_MAIN_THREAD
245 #endif
246
247 static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
248 GdkEvent *WXUNUSED(event),
249 const wxChar *WXUNUSED(name) )
250 {
251 /*
252 static bool s_done = FALSE;
253 if ( !s_done )
254 {
255 wxLog::AddTraceMask("focus");
256 s_done = TRUE;
257 }
258 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
259 */
260
261 return FALSE;
262 }
263
264 void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
265 {
266 // suppress warnings about gtk_debug_focus_in_callback being unused with
267 // this "if ( 0 )"
268 if ( 0 )
269 {
270 wxString tmp = name;
271 tmp += wxT(" FROM ");
272 tmp += window;
273
274 wxChar *s = new wxChar[tmp.Length()+1];
275
276 wxStrcpy( s, tmp );
277
278 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
279 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
280 }
281 }
282
283 #else
284 #define DEBUG_MAIN_THREAD
285 #endif // Debug
286
287 //-----------------------------------------------------------------------------
288 // missing gdk functions
289 //-----------------------------------------------------------------------------
290
291 void
292 gdk_window_warp_pointer (GdkWindow *window,
293 gint x,
294 gint y)
295 {
296 #ifndef __WXGTK20__
297 GdkWindowPrivate *priv;
298 #endif
299
300 if (!window)
301 window = GDK_ROOT_PARENT();
302
303 #ifdef __WXGTK20__
304 if (!GDK_WINDOW_DESTROYED(window))
305 {
306 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
307 None, /* not source window -> move from anywhere */
308 GDK_WINDOW_XID(window), /* dest window */
309 0, 0, 0, 0, /* not source window -> move from anywhere */
310 x, y );
311 }
312 #else
313 priv = (GdkWindowPrivate*) window;
314
315 if (!priv->destroyed)
316 {
317 XWarpPointer (priv->xdisplay,
318 None, /* not source window -> move from anywhere */
319 priv->xwindow, /* dest window */
320 0, 0, 0, 0, /* not source window -> move from anywhere */
321 x, y );
322 }
323 #endif
324 }
325
326 //-----------------------------------------------------------------------------
327 // idle system
328 //-----------------------------------------------------------------------------
329
330 extern void wxapp_install_idle_handler();
331 extern bool g_isIdle;
332
333 //-----------------------------------------------------------------------------
334 // local code (see below)
335 //-----------------------------------------------------------------------------
336
337 // returns the child of win which currently has focus or NULL if not found
338 //
339 // Note: can't be static, needed by textctrl.cpp.
340 wxWindow *wxFindFocusedChild(wxWindowGTK *win)
341 {
342 wxWindow *winFocus = wxWindowGTK::FindFocus();
343 if ( !winFocus )
344 return (wxWindow *)NULL;
345
346 if ( winFocus == win )
347 return (wxWindow *)win;
348
349 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
350 node;
351 node = node->GetNext() )
352 {
353 wxWindow *child = wxFindFocusedChild(node->GetData());
354 if ( child )
355 return child;
356 }
357
358 return (wxWindow *)NULL;
359 }
360
361 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
362 {
363 // wxUniversal widgets draw the borders and scrollbars themselves
364 #ifndef __WXUNIVERSAL__
365 if (!win->m_hasVMT)
366 return;
367
368 int dw = 0;
369 int dh = 0;
370
371 if (win->m_hasScrolling)
372 {
373 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
374
375 GtkRequisition vscroll_req;
376 vscroll_req.width = 2;
377 vscroll_req.height = 2;
378 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
379 (scroll_window->vscrollbar, &vscroll_req );
380
381 GtkRequisition hscroll_req;
382 hscroll_req.width = 2;
383 hscroll_req.height = 2;
384 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
385 (scroll_window->hscrollbar, &hscroll_req );
386
387 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
388
389 if (scroll_window->vscrollbar_visible)
390 {
391 dw += vscroll_req.width;
392 dw += scroll_class->scrollbar_spacing;
393 }
394
395 if (scroll_window->hscrollbar_visible)
396 {
397 dh += hscroll_req.height;
398 dh += scroll_class->scrollbar_spacing;
399 }
400 }
401
402 int dx = 0;
403 int dy = 0;
404 if (GTK_WIDGET_NO_WINDOW (widget))
405 {
406 dx += widget->allocation.x;
407 dy += widget->allocation.y;
408 }
409
410 if (win->HasFlag(wxRAISED_BORDER))
411 {
412 gtk_draw_shadow( widget->style,
413 widget->window,
414 GTK_STATE_NORMAL,
415 GTK_SHADOW_OUT,
416 dx, dy,
417 widget->allocation.width-dw, widget->allocation.height-dh );
418 return;
419 }
420
421 if (win->HasFlag(wxSUNKEN_BORDER))
422 {
423 gtk_draw_shadow( widget->style,
424 widget->window,
425 GTK_STATE_NORMAL,
426 GTK_SHADOW_IN,
427 dx, dy,
428 widget->allocation.width-dw, widget->allocation.height-dh );
429 return;
430 }
431
432 if (win->HasFlag(wxSIMPLE_BORDER))
433 {
434 GdkGC *gc;
435 gc = gdk_gc_new( widget->window );
436 gdk_gc_set_foreground( gc, &widget->style->black );
437 gdk_draw_rectangle( widget->window, gc, FALSE,
438 dx, dy,
439 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
440 gdk_gc_unref( gc );
441 return;
442 }
443 #endif // __WXUNIVERSAL__
444 }
445
446 //-----------------------------------------------------------------------------
447 // "expose_event" of m_widget
448 //-----------------------------------------------------------------------------
449
450 gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
451 {
452 if (gdk_event->count > 0) return FALSE;
453
454 draw_frame( widget, win );
455
456 return TRUE;
457 }
458
459 //-----------------------------------------------------------------------------
460 // "draw" of m_widget
461 //-----------------------------------------------------------------------------
462
463 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
464 {
465 draw_frame( widget, win );
466 }
467
468 //-----------------------------------------------------------------------------
469 // key code mapping routines
470 //-----------------------------------------------------------------------------
471
472 static long map_to_unmodified_wx_keysym( GdkEventKey *event )
473 {
474 KeySym keysym = event->keyval;
475 guint key_code = 0;
476
477 switch (keysym)
478 {
479 case GDK_Shift_L:
480 case GDK_Shift_R: key_code = WXK_SHIFT; break;
481 case GDK_Control_L:
482 case GDK_Control_R: key_code = WXK_CONTROL; break;
483 case GDK_Meta_L:
484 case GDK_Meta_R:
485 case GDK_Alt_L:
486 case GDK_Alt_R:
487 case GDK_Super_L:
488 case GDK_Super_R: key_code = WXK_ALT; break;
489 case GDK_Menu: key_code = WXK_MENU; break;
490 case GDK_Help: key_code = WXK_HELP; break;
491 case GDK_BackSpace: key_code = WXK_BACK; break;
492 case GDK_ISO_Left_Tab:
493 case GDK_Tab: key_code = WXK_TAB; break;
494 case GDK_Linefeed: key_code = WXK_RETURN; break;
495 case GDK_Clear: key_code = WXK_CLEAR; break;
496 case GDK_Return: key_code = WXK_RETURN; break;
497 case GDK_Pause: key_code = WXK_PAUSE; break;
498 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
499 case GDK_Escape: key_code = WXK_ESCAPE; break;
500 case GDK_Delete: key_code = WXK_DELETE; break;
501 case GDK_Home: key_code = WXK_HOME; break;
502 case GDK_Left: key_code = WXK_LEFT; break;
503 case GDK_Up: key_code = WXK_UP; break;
504 case GDK_Right: key_code = WXK_RIGHT; break;
505 case GDK_Down: key_code = WXK_DOWN; break;
506 case GDK_Prior: key_code = WXK_PRIOR; break;
507 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
508 case GDK_Next: key_code = WXK_NEXT; break;
509 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
510 case GDK_End: key_code = WXK_END; break;
511 case GDK_Begin: key_code = WXK_HOME; break;
512 case GDK_Select: key_code = WXK_SELECT; break;
513 case GDK_Print: key_code = WXK_PRINT; break;
514 case GDK_Execute: key_code = WXK_EXECUTE; break;
515 case GDK_Insert: key_code = WXK_INSERT; break;
516 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
517
518 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
519 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
520 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
521 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
522 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
523 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
524 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
525 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
526 case GDK_KP_8: key_code = WXK_NUMPAD8; break;
527 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
528 case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
529 case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
530 case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
531 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
532 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
533 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
534 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
535 case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
536 case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
537 case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
538 case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
539 case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
540 case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
541 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
542 case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
543 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
544 case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
545 case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
546 case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
547 case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
548 case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
549 case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
550 case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
551 case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
552 case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
553 case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
554 case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break;
555
556 case GDK_F1: key_code = WXK_F1; break;
557 case GDK_F2: key_code = WXK_F2; break;
558 case GDK_F3: key_code = WXK_F3; break;
559 case GDK_F4: key_code = WXK_F4; break;
560 case GDK_F5: key_code = WXK_F5; break;
561 case GDK_F6: key_code = WXK_F6; break;
562 case GDK_F7: key_code = WXK_F7; break;
563 case GDK_F8: key_code = WXK_F8; break;
564 case GDK_F9: key_code = WXK_F9; break;
565 case GDK_F10: key_code = WXK_F10; break;
566 case GDK_F11: key_code = WXK_F11; break;
567 case GDK_F12: key_code = WXK_F12; break;
568 default:
569 {
570 if (event->length == 1)
571 {
572 key_code = toupper( (unsigned char)*event->string );
573 }
574 else if ((keysym & 0xFF) == keysym)
575 {
576 guint upper = gdk_keyval_to_upper( (guint)keysym );
577 keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */
578 key_code = (guint)keysym;
579 }
580 }
581 }
582
583 return (key_code);
584 }
585
586 static long map_to_wx_keysym( GdkEventKey *event )
587 {
588 KeySym keysym = event->keyval;
589 guint key_code = 0;
590
591 switch (keysym)
592 {
593 case GDK_Menu: key_code = WXK_MENU; break;
594 case GDK_Help: key_code = WXK_HELP; break;
595 case GDK_BackSpace: key_code = WXK_BACK; break;
596 case GDK_ISO_Left_Tab:
597 case GDK_Tab: key_code = WXK_TAB; break;
598 case GDK_Linefeed: key_code = WXK_RETURN; break;
599 case GDK_Clear: key_code = WXK_CLEAR; break;
600 case GDK_Return: key_code = WXK_RETURN; break;
601 case GDK_Pause: key_code = WXK_PAUSE; break;
602 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
603 case GDK_Escape: key_code = WXK_ESCAPE; break;
604 case GDK_Delete: key_code = WXK_DELETE; break;
605 case GDK_Home: key_code = WXK_HOME; break;
606 case GDK_Left: key_code = WXK_LEFT; break;
607 case GDK_Up: key_code = WXK_UP; break;
608 case GDK_Right: key_code = WXK_RIGHT; break;
609 case GDK_Down: key_code = WXK_DOWN; break;
610 case GDK_Prior: key_code = WXK_PRIOR; break;
611 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
612 case GDK_Next: key_code = WXK_NEXT; break;
613 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
614 case GDK_End: key_code = WXK_END; break;
615 case GDK_Begin: key_code = WXK_HOME; break;
616 case GDK_Select: key_code = WXK_SELECT; break;
617 case GDK_Print: key_code = WXK_PRINT; break;
618 case GDK_Execute: key_code = WXK_EXECUTE; break;
619 case GDK_Insert: key_code = WXK_INSERT; break;
620 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
621
622 case GDK_KP_0: key_code = '0'; break;
623 case GDK_KP_1: key_code = '1'; break;
624 case GDK_KP_2: key_code = '2'; break;
625 case GDK_KP_3: key_code = '3'; break;
626 case GDK_KP_4: key_code = '4'; break;
627 case GDK_KP_5: key_code = '5'; break;
628 case GDK_KP_6: key_code = '6'; break;
629 case GDK_KP_7: key_code = '7'; break;
630 case GDK_KP_8: key_code = '8'; break;
631 case GDK_KP_9: key_code = '9'; break;
632 case GDK_KP_Space: key_code = ' '; break;
633 case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
634 case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
635 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
636 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
637 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
638 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
639 case GDK_KP_Home: key_code = WXK_HOME; break;
640 case GDK_KP_Left: key_code = WXK_LEFT; break;
641 case GDK_KP_Up: key_code = WXK_UP; break;
642 case GDK_KP_Right: key_code = WXK_RIGHT; break;
643 case GDK_KP_Down: key_code = WXK_DOWN; break;
644 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
645 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
646 case GDK_KP_Next: key_code = WXK_NEXT; break;
647 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
648 case GDK_KP_End: key_code = WXK_END; break;
649 case GDK_KP_Begin: key_code = WXK_HOME; break;
650 case GDK_KP_Insert: key_code = WXK_INSERT; break;
651 case GDK_KP_Delete: key_code = WXK_DELETE; break;
652 case GDK_KP_Equal: key_code = '='; break;
653 case GDK_KP_Multiply: key_code = '*'; break;
654 case GDK_KP_Add: key_code = '+'; break;
655 case GDK_KP_Separator: key_code = ','; break;
656 case GDK_KP_Subtract: key_code = '-'; break;
657 case GDK_KP_Decimal: key_code = '.'; break;
658 case GDK_KP_Divide: key_code = '/'; break;
659
660 case GDK_F1: key_code = WXK_F1; break;
661 case GDK_F2: key_code = WXK_F2; break;
662 case GDK_F3: key_code = WXK_F3; break;
663 case GDK_F4: key_code = WXK_F4; break;
664 case GDK_F5: key_code = WXK_F5; break;
665 case GDK_F6: key_code = WXK_F6; break;
666 case GDK_F7: key_code = WXK_F7; break;
667 case GDK_F8: key_code = WXK_F8; break;
668 case GDK_F9: key_code = WXK_F9; break;
669 case GDK_F10: key_code = WXK_F10; break;
670 case GDK_F11: key_code = WXK_F11; break;
671 case GDK_F12: key_code = WXK_F12; break;
672 default:
673 {
674 if (event->length == 1)
675 {
676 key_code = (unsigned char)*event->string;
677 }
678 else if ((keysym & 0xFF) == keysym)
679 {
680 key_code = (guint)keysym;
681 }
682 }
683 }
684
685 return (key_code);
686 }
687
688 //-----------------------------------------------------------------------------
689 // "size_request" of m_widget
690 //-----------------------------------------------------------------------------
691
692 static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win )
693 {
694 int w,h;
695 win->GetSize( &w, &h );
696 if (w < 2) w = 2;
697 if (h < 2) h = 2;
698
699 requisition->height = h;
700 requisition->width = w;
701 }
702
703 //-----------------------------------------------------------------------------
704 // "expose_event" of m_wxwindow
705 //-----------------------------------------------------------------------------
706
707 static int gtk_window_expose_callback( GtkWidget *widget,
708 GdkEventExpose *gdk_event,
709 wxWindow *win )
710 {
711 DEBUG_MAIN_THREAD
712
713 if (g_isIdle)
714 wxapp_install_idle_handler();
715
716 /*
717 if (win->GetName() == wxT("panel"))
718 {
719 wxPrintf( wxT("OnExpose from ") );
720 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
721 wxPrintf( win->GetClassInfo()->GetClassName() );
722 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
723 (int)gdk_event->area.y,
724 (int)gdk_event->area.width,
725 (int)gdk_event->area.height );
726 }
727 */
728
729 GtkPizza *pizza = GTK_PIZZA (widget);
730
731 if (win->GetThemeEnabled())
732 {
733 wxWindow *parent = win->GetParent();
734 while (parent && !parent->IsTopLevel())
735 parent = parent->GetParent();
736 if (!parent)
737 parent = win;
738
739 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
740 GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
741 }
742
743 win->GetUpdateRegion().Union( gdk_event->area.x,
744 gdk_event->area.y,
745 gdk_event->area.width,
746 gdk_event->area.height );
747
748 if (gdk_event->count == 0)
749 {
750 win->m_clipPaintRegion = TRUE;
751
752 wxWindowDC dc(win);
753 dc.SetClippingRegion(win->GetUpdateRegion());
754 wxEraseEvent eevent( win->GetId(), &dc );
755 eevent.SetEventObject( win );
756 #if 1
757 (void)win->GetEventHandler()->ProcessEvent(eevent);
758 #else // 0
759 if (!win->GetEventHandler()->ProcessEvent(eevent))
760 {
761 wxClientDC dc( win );
762 dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
763 dc.SetPen( *wxTRANSPARENT_PEN );
764
765 wxRegionIterator upd( win->GetUpdateRegion() );
766 while (upd)
767 {
768 dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
769 upd ++;
770 }
771 }
772 #endif // 1/0
773
774 wxNcPaintEvent eventNc( win->GetId() );
775 eventNc.SetEventObject( win );
776 win->GetEventHandler()->ProcessEvent( eventNc );
777
778 wxPaintEvent event( win->GetId() );
779 event.SetEventObject( win );
780 win->GetEventHandler()->ProcessEvent( event );
781
782 win->GetUpdateRegion().Clear();
783
784 win->m_clipPaintRegion = FALSE;
785 }
786
787 /* The following code will result in all window-less widgets
788 being redrawn if the wxWindows class is given a chance to
789 paint *anything* because it will then be allowed to paint
790 over the window-less widgets */
791 GList *children = pizza->children;
792 while (children)
793 {
794 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
795 children = children->next;
796
797 GdkEventExpose child_event = *gdk_event;
798
799 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
800 GTK_WIDGET_DRAWABLE (child->widget) /* &&
801 gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ )
802 {
803 child_event.area.x = child->widget->allocation.x;
804 child_event.area.y = child->widget->allocation.y;
805 child_event.area.width = child->widget->allocation.width;
806 child_event.area.height = child->widget->allocation.height;
807 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
808 }
809 }
810
811 return TRUE;
812 }
813
814 //-----------------------------------------------------------------------------
815 // "event" of m_wxwindow
816 //-----------------------------------------------------------------------------
817
818 /* GTK thinks it is clever and filters out a certain amount of "unneeded"
819 expose events. We need them, of course, so we override the main event
820 procedure in GtkWidget by giving our own handler for all system events.
821 There, we look for expose events ourselves whereas all other events are
822 handled normally. */
823
824 gint gtk_window_event_event_callback( GtkWidget *widget,
825 GdkEventExpose *event,
826 wxWindow *win )
827 {
828 if (event->type == GDK_EXPOSE)
829 {
830 gint ret = gtk_window_expose_callback( widget, event, win );
831 return ret;
832 }
833
834 return FALSE;
835 }
836
837 //-----------------------------------------------------------------------------
838 // "draw" of m_wxwindow
839 //-----------------------------------------------------------------------------
840
841 /* This callback is a complete replacement of the gtk_pizza_draw() function,
842 which disabled. */
843
844 static void gtk_window_draw_callback( GtkWidget *widget,
845 GdkRectangle *rect,
846 wxWindow *win )
847 {
848 DEBUG_MAIN_THREAD
849
850 if (g_isIdle)
851 wxapp_install_idle_handler();
852
853 if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
854 (win->GetChildren().GetCount() == 0))
855 {
856 return;
857 }
858
859 /*
860 if (win->GetName() == wxT("panel"))
861 {
862 wxPrintf( wxT("OnDraw from ") );
863 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
864 wxPrintf( win->GetClassInfo()->GetClassName() );
865 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
866 (int)rect->y,
867 (int)rect->width,
868 (int)rect->height );
869 }
870 */
871
872 GtkPizza *pizza = GTK_PIZZA (widget);
873
874 if (win->GetThemeEnabled())
875 {
876 wxWindow *parent = win->GetParent();
877 while (parent && !parent->IsTopLevel())
878 parent = parent->GetParent();
879 if (!parent)
880 parent = win;
881
882 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
883 GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
884 }
885
886
887 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
888 (pizza->clear_on_draw))
889 {
890 gdk_window_clear_area( pizza->bin_window,
891 rect->x, rect->y, rect->width, rect->height);
892 }
893
894 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
895
896 win->m_clipPaintRegion = TRUE;
897
898 wxWindowDC dc(win);
899 dc.SetClippingRegion(win->GetUpdateRegion());
900 wxEraseEvent eevent( win->GetId(), &dc );
901 eevent.SetEventObject( win );
902
903 #if 1
904 (void)win->GetEventHandler()->ProcessEvent(eevent);
905 #else
906 if (!win->GetEventHandler()->ProcessEvent(eevent))
907 {
908 if (!win->GetEventHandler()->ProcessEvent(eevent))
909 {
910 wxClientDC dc( win );
911 dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
912 dc.SetPen( *wxTRANSPARENT_PEN );
913
914 wxRegionIterator upd( win->GetUpdateRegion() );
915 while (upd)
916 {
917 dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
918 upd ++;
919 }
920 }
921 }
922 #endif
923
924 wxNcPaintEvent eventNc( win->GetId() );
925 eventNc.SetEventObject( win );
926 win->GetEventHandler()->ProcessEvent( eventNc );
927
928 wxPaintEvent event( win->GetId() );
929 event.SetEventObject( win );
930 win->GetEventHandler()->ProcessEvent( event );
931
932 win->GetUpdateRegion().Clear();
933
934 win->m_clipPaintRegion = FALSE;
935
936
937 GList *children = pizza->children;
938 while (children)
939 {
940 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
941 children = children->next;
942
943 GdkRectangle child_area;
944 if (gtk_widget_intersect (child->widget, rect, &child_area))
945 {
946 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
947 }
948 }
949 }
950
951 //-----------------------------------------------------------------------------
952 // "key_press_event" from any window
953 //-----------------------------------------------------------------------------
954
955 static gint gtk_window_key_press_callback( GtkWidget *widget,
956 GdkEventKey *gdk_event,
957 wxWindow *win )
958 {
959 DEBUG_MAIN_THREAD
960
961 if (g_isIdle)
962 wxapp_install_idle_handler();
963
964 if (!win->m_hasVMT) return FALSE;
965 if (g_blockEventsOnDrag) return FALSE;
966
967
968 /*
969 wxString tmp;
970 tmp += (char)gdk_event->keyval;
971 printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
972 printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
973 */
974
975 int x = 0;
976 int y = 0;
977 GdkModifierType state;
978 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
979
980 bool ret = FALSE;
981
982 long key_code = map_to_unmodified_wx_keysym( gdk_event );
983 /* sending unknown key events doesn't really make sense */
984 if (key_code == 0) return FALSE;
985
986 wxKeyEvent event( wxEVT_KEY_DOWN );
987 event.SetTimestamp( gdk_event->time );
988 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
989 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
990 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
991 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
992 event.m_keyCode = key_code;
993 event.m_scanCode = gdk_event->keyval;
994 event.m_x = x;
995 event.m_y = y;
996 event.SetEventObject( win );
997 ret = win->GetEventHandler()->ProcessEvent( event );
998
999 #if wxUSE_ACCEL
1000 if (!ret)
1001 {
1002 wxWindowGTK *ancestor = win;
1003 while (ancestor)
1004 {
1005 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1006 if (command != -1)
1007 {
1008 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1009 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
1010 break;
1011 }
1012 if (ancestor->IsTopLevel())
1013 break;
1014 ancestor = ancestor->GetParent();
1015 }
1016 }
1017 #endif // wxUSE_ACCEL
1018
1019 /* wxMSW doesn't send char events with Alt pressed */
1020 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1021 will only be sent if it is not in an accelerator table. */
1022 key_code = map_to_wx_keysym( gdk_event );
1023
1024 if ( (!ret) &&
1025 (key_code != 0))
1026 {
1027 wxKeyEvent event2( wxEVT_CHAR );
1028 event2.SetTimestamp( gdk_event->time );
1029 event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1030 event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1031 event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1032 event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1033 event2.m_keyCode = key_code;
1034 event2.m_scanCode = gdk_event->keyval;
1035 event2.m_x = x;
1036 event2.m_y = y;
1037 event2.SetEventObject( win );
1038 ret = win->GetEventHandler()->ProcessEvent( event2 );
1039 }
1040
1041 /* win is a control: tab can be propagated up */
1042 if ( (!ret) &&
1043 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1044 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1045 // have this style, yet choose not to process this particular TAB in which
1046 // case TAB must still work as a navigational character
1047 #if 0
1048 (!win->HasFlag(wxTE_PROCESS_TAB)) &&
1049 #endif // 0
1050 (win->GetParent()) &&
1051 (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1052 {
1053 wxNavigationKeyEvent new_event;
1054 new_event.SetEventObject( win->GetParent() );
1055 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1056 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1057 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1058 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1059 new_event.SetCurrentFocus( win );
1060 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1061 }
1062
1063 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1064 if ( (!ret) &&
1065 (gdk_event->keyval == GDK_Escape) )
1066 {
1067 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
1068 new_event.SetEventObject( win );
1069 ret = win->GetEventHandler()->ProcessEvent( new_event );
1070 }
1071
1072 #if (GTK_MINOR_VERSION > 0)
1073 /* Pressing F10 will activate the menu bar of the top frame. */
1074 /* Doesn't work. */
1075 /*
1076 if ( (!ret) &&
1077 (gdk_event->keyval == GDK_F10) )
1078 {
1079 wxWindowGTK *ancestor = win;
1080 while (ancestor)
1081 {
1082 if (wxIsKindOf(ancestor,wxFrame))
1083 {
1084 wxFrame *frame = (wxFrame*) ancestor;
1085 wxMenuBar *menubar = frame->GetMenuBar();
1086 if (menubar)
1087 {
1088 wxNode *node = menubar->GetMenus().First();
1089 if (node)
1090 {
1091 wxMenu *firstMenu = (wxMenu*) node->Data();
1092 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
1093 ret = TRUE;
1094 break;
1095 }
1096 }
1097 }
1098 ancestor = ancestor->GetParent();
1099 }
1100 }
1101 */
1102 #endif
1103
1104 if (ret)
1105 {
1106 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1107 return TRUE;
1108 }
1109
1110 return FALSE;
1111 }
1112
1113 //-----------------------------------------------------------------------------
1114 // "key_release_event" from any window
1115 //-----------------------------------------------------------------------------
1116
1117 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
1118 {
1119 DEBUG_MAIN_THREAD
1120
1121 if (g_isIdle)
1122 wxapp_install_idle_handler();
1123
1124 if (!win->m_hasVMT) return FALSE;
1125 if (g_blockEventsOnDrag) return FALSE;
1126
1127 /*
1128 printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
1129 if (gdk_event->state & GDK_SHIFT_MASK)
1130 printf( "ShiftDown.\n" );
1131 else
1132 printf( "ShiftUp.\n" );
1133 if (gdk_event->state & GDK_CONTROL_MASK)
1134 printf( "ControlDown.\n" );
1135 else
1136 printf( "ControlUp.\n" );
1137 printf( "\n" );
1138 */
1139
1140 long key_code = map_to_unmodified_wx_keysym( gdk_event );
1141
1142 /* sending unknown key events doesn't really make sense */
1143 if (key_code == 0) return FALSE;
1144
1145 int x = 0;
1146 int y = 0;
1147 GdkModifierType state;
1148 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1149
1150 wxKeyEvent event( wxEVT_KEY_UP );
1151 event.SetTimestamp( gdk_event->time );
1152 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1153 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1154 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1155 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1156 event.m_keyCode = key_code;
1157 event.m_scanCode = gdk_event->keyval;
1158 event.m_x = x;
1159 event.m_y = y;
1160 event.SetEventObject( win );
1161
1162 if (win->GetEventHandler()->ProcessEvent( event ))
1163 {
1164 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1165 return TRUE;
1166 }
1167
1168 return FALSE;
1169 }
1170
1171 // ----------------------------------------------------------------------------
1172 // mouse event processing helper
1173 // ----------------------------------------------------------------------------
1174
1175 static void AdjustEventButtonState(wxMouseEvent& event)
1176 {
1177 // GDK reports the old state of the button for a button press event, but
1178 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1179 // for a LEFT_DOWN event, not FALSE, so we will invert
1180 // left/right/middleDown for the corresponding click events
1181
1182 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1183 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1184 (event.GetEventType() == wxEVT_LEFT_UP))
1185 {
1186 event.m_leftDown = !event.m_leftDown;
1187 return;
1188 }
1189
1190 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1191 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1192 (event.GetEventType() == wxEVT_MIDDLE_UP))
1193 {
1194 event.m_middleDown = !event.m_middleDown;
1195 return;
1196 }
1197
1198 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1199 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1200 (event.GetEventType() == wxEVT_RIGHT_UP))
1201 {
1202 event.m_rightDown = !event.m_rightDown;
1203 return;
1204 }
1205 }
1206
1207 //-----------------------------------------------------------------------------
1208 // "button_press_event"
1209 //-----------------------------------------------------------------------------
1210
1211 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1212 {
1213 DEBUG_MAIN_THREAD
1214
1215 if (g_isIdle)
1216 wxapp_install_idle_handler();
1217
1218 /*
1219 wxPrintf( wxT("1) OnButtonPress from ") );
1220 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1221 wxPrintf( win->GetClassInfo()->GetClassName() );
1222 wxPrintf( wxT(".\n") );
1223 */
1224 if (!win->m_hasVMT) return FALSE;
1225 if (g_blockEventsOnDrag) return TRUE;
1226 if (g_blockEventsOnScroll) return TRUE;
1227
1228 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1229
1230 if (win->m_wxwindow)
1231 {
1232 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
1233 {
1234 gtk_widget_grab_focus (win->m_wxwindow);
1235
1236 /*
1237 wxPrintf( wxT("GrabFocus from ") );
1238 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1239 wxPrintf( win->GetClassInfo()->GetClassName() );
1240 wxPrintf( wxT(".\n") );
1241 */
1242
1243 }
1244 }
1245
1246 wxEventType event_type = wxEVT_NULL;
1247
1248 if (gdk_event->button == 1)
1249 {
1250 switch (gdk_event->type)
1251 {
1252 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1253 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1254 default: break;
1255 }
1256 }
1257 else if (gdk_event->button == 2)
1258 {
1259 switch (gdk_event->type)
1260 {
1261 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1262 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1263 default: break;
1264 }
1265 }
1266 else if (gdk_event->button == 3)
1267 {
1268 switch (gdk_event->type)
1269 {
1270 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1271 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1272 default: break;
1273 }
1274 }
1275
1276 if ( event_type == wxEVT_NULL )
1277 {
1278 // unknown mouse button or click type
1279 return FALSE;
1280 }
1281
1282 wxMouseEvent event( event_type );
1283 event.SetTimestamp( gdk_event->time );
1284 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1285 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1286 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1287 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1288 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1289 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1290 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1291
1292 event.m_x = (wxCoord)gdk_event->x;
1293 event.m_y = (wxCoord)gdk_event->y;
1294
1295 AdjustEventButtonState(event);
1296
1297 // Some control don't have their own X window and thus cannot get
1298 // any events.
1299
1300 if (!g_captureWindow)
1301 {
1302 wxCoord x = event.m_x;
1303 wxCoord y = event.m_y;
1304 if (win->m_wxwindow)
1305 {
1306 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1307 x += pizza->xoffset;
1308 y += pizza->yoffset;
1309 }
1310
1311 wxNode *node = win->GetChildren().First();
1312 while (node)
1313 {
1314 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1315
1316 node = node->Next();
1317 if (!child->IsShown())
1318 continue;
1319
1320 if (child->m_isStaticBox)
1321 {
1322 // wxStaticBox is transparent in the box itself
1323 int xx1 = child->m_x;
1324 int yy1 = child->m_y;
1325 int xx2 = child->m_x + child->m_width;
1326 int yy2 = child->m_x + child->m_height;
1327
1328 // left
1329 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1330 // right
1331 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1332 // top
1333 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1334 // bottom
1335 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1336 {
1337 win = child;
1338 event.m_x -= child->m_x;
1339 event.m_y -= child->m_y;
1340 break;
1341 }
1342
1343 }
1344 else
1345 {
1346 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1347 (child->m_x <= x) &&
1348 (child->m_y <= y) &&
1349 (child->m_x+child->m_width >= x) &&
1350 (child->m_y+child->m_height >= y))
1351 {
1352 win = child;
1353 event.m_x -= child->m_x;
1354 event.m_y -= child->m_y;
1355 break;
1356 }
1357 }
1358 }
1359 }
1360
1361 event.SetEventObject( win );
1362
1363 gs_timeLastClick = gdk_event->time;
1364
1365 /*
1366 wxPrintf( wxT("2) OnButtonPress from ") );
1367 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1368 wxPrintf( win->GetClassInfo()->GetClassName() );
1369 wxPrintf( wxT(".\n") );
1370 */
1371
1372 if (win->GetEventHandler()->ProcessEvent( event ))
1373 {
1374 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1375 return TRUE;
1376 }
1377
1378 return FALSE;
1379 }
1380
1381 //-----------------------------------------------------------------------------
1382 // "button_release_event"
1383 //-----------------------------------------------------------------------------
1384
1385 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1386 {
1387 DEBUG_MAIN_THREAD
1388
1389 if (g_isIdle)
1390 wxapp_install_idle_handler();
1391
1392 if (!win->m_hasVMT) return FALSE;
1393 if (g_blockEventsOnDrag) return FALSE;
1394 if (g_blockEventsOnScroll) return FALSE;
1395
1396 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1397
1398 /*
1399 printf( "OnButtonRelease from " );
1400 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1401 printf( win->GetClassInfo()->GetClassName() );
1402 printf( ".\n" );
1403 */
1404
1405 wxEventType event_type = wxEVT_NULL;
1406
1407 switch (gdk_event->button)
1408 {
1409 case 1: event_type = wxEVT_LEFT_UP; break;
1410 case 2: event_type = wxEVT_MIDDLE_UP; break;
1411 case 3: event_type = wxEVT_RIGHT_UP; break;
1412 default: return FALSE;
1413 }
1414
1415 wxMouseEvent event( event_type );
1416 event.SetTimestamp( gdk_event->time );
1417 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1418 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1419 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1420 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1421 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1422 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1423 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1424 event.m_x = (wxCoord)gdk_event->x;
1425 event.m_y = (wxCoord)gdk_event->y;
1426
1427 AdjustEventButtonState(event);
1428
1429 // Some control don't have their own X window and thus cannot get
1430 // any events.
1431
1432 if (!g_captureWindow)
1433 {
1434 wxCoord x = event.m_x;
1435 wxCoord y = event.m_y;
1436 if (win->m_wxwindow)
1437 {
1438 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1439 x += pizza->xoffset;
1440 y += pizza->yoffset;
1441 }
1442
1443 wxNode *node = win->GetChildren().First();
1444 while (node)
1445 {
1446 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1447
1448 node = node->Next();
1449 if (!child->IsShown())
1450 continue;
1451
1452 if (child->m_isStaticBox)
1453 {
1454 // wxStaticBox is transparent in the box itself
1455 int xx1 = child->m_x;
1456 int yy1 = child->m_y;
1457 int xx2 = child->m_x + child->m_width;
1458 int yy2 = child->m_x + child->m_height;
1459
1460 // left
1461 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1462 // right
1463 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1464 // top
1465 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1466 // bottom
1467 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1468 {
1469 win = child;
1470 event.m_x -= child->m_x;
1471 event.m_y -= child->m_y;
1472 break;
1473 }
1474
1475 }
1476 else
1477 {
1478 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1479 (child->m_x <= x) &&
1480 (child->m_y <= y) &&
1481 (child->m_x+child->m_width >= x) &&
1482 (child->m_y+child->m_height >= y))
1483 {
1484 win = child;
1485 event.m_x -= child->m_x;
1486 event.m_y -= child->m_y;
1487 break;
1488 }
1489 }
1490 }
1491 }
1492
1493 event.SetEventObject( win );
1494
1495 if (win->GetEventHandler()->ProcessEvent( event ))
1496 {
1497 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1498 return TRUE;
1499 }
1500
1501 return FALSE;
1502 }
1503
1504 // ============================================================================
1505 // the mouse events
1506 // ============================================================================
1507
1508 // init wxMouseEvent with the info from gdk_event
1509 #define InitMouseEvent(event, gdk_event) \
1510 event.SetTimestamp( gdk_event->time ); \
1511 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1512 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1513 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1514 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1515 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1516 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1517 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1518 \
1519 event.m_x = (wxCoord)gdk_event->x; \
1520 event.m_y = (wxCoord)gdk_event->y \
1521
1522 //-----------------------------------------------------------------------------
1523 // "motion_notify_event"
1524 //-----------------------------------------------------------------------------
1525
1526 static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1527 GdkEventMotion *gdk_event,
1528 wxWindowGTK *win )
1529 {
1530 DEBUG_MAIN_THREAD
1531
1532 if (g_isIdle)
1533 wxapp_install_idle_handler();
1534
1535 if (!win->m_hasVMT) return FALSE;
1536 if (g_blockEventsOnDrag) return FALSE;
1537 if (g_blockEventsOnScroll) return FALSE;
1538
1539 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1540
1541 if (gdk_event->is_hint)
1542 {
1543 int x = 0;
1544 int y = 0;
1545 GdkModifierType state;
1546 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1547 gdk_event->x = x;
1548 gdk_event->y = y;
1549 }
1550
1551 /*
1552 printf( "OnMotion from " );
1553 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1554 printf( win->GetClassInfo()->GetClassName() );
1555 printf( ".\n" );
1556 */
1557
1558 wxMouseEvent event( wxEVT_MOTION );
1559 InitMouseEvent(event, gdk_event);
1560
1561 if ( g_captureWindow )
1562 {
1563 // synthetize a mouse enter or leave event if needed
1564 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1565 bool hasMouse = winUnderMouse == gdk_event->window;
1566 if ( hasMouse != g_captureWindowHasMouse )
1567 {
1568 // the mouse changed window
1569 g_captureWindowHasMouse = hasMouse;
1570
1571 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1572 : wxEVT_LEAVE_WINDOW);
1573 InitMouseEvent(event, gdk_event);
1574 event.SetEventObject(win);
1575 win->GetEventHandler()->ProcessEvent(event);
1576 }
1577 }
1578 else // no capture
1579 {
1580 // Some control don't have their own X window and thus cannot get
1581 // any events.
1582
1583 wxCoord x = event.m_x;
1584 wxCoord y = event.m_y;
1585 if (win->m_wxwindow)
1586 {
1587 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1588 x += pizza->xoffset;
1589 y += pizza->yoffset;
1590 }
1591
1592 wxNode *node = win->GetChildren().First();
1593 while (node)
1594 {
1595 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1596
1597 node = node->Next();
1598 if (!child->IsShown())
1599 continue;
1600
1601 if (child->m_isStaticBox)
1602 {
1603 // wxStaticBox is transparent in the box itself
1604 int xx1 = child->m_x;
1605 int yy1 = child->m_y;
1606 int xx2 = child->m_x + child->m_width;
1607 int yy2 = child->m_x + child->m_height;
1608
1609 // left
1610 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1611 // right
1612 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1613 // top
1614 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1615 // bottom
1616 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1617 {
1618 win = child;
1619 event.m_x -= child->m_x;
1620 event.m_y -= child->m_y;
1621 break;
1622 }
1623
1624 }
1625 else
1626 {
1627 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1628 (child->m_x <= x) &&
1629 (child->m_y <= y) &&
1630 (child->m_x+child->m_width >= x) &&
1631 (child->m_y+child->m_height >= y))
1632 {
1633 win = child;
1634 event.m_x -= child->m_x;
1635 event.m_y -= child->m_y;
1636 break;
1637 }
1638 }
1639 }
1640 }
1641
1642 event.SetEventObject( win );
1643
1644 if (win->GetEventHandler()->ProcessEvent( event ))
1645 {
1646 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1647 return TRUE;
1648 }
1649
1650 return FALSE;
1651 }
1652
1653 //-----------------------------------------------------------------------------
1654 // "focus_in_event"
1655 //-----------------------------------------------------------------------------
1656
1657 static gint gtk_window_focus_in_callback( GtkWidget *widget,
1658 GdkEvent *WXUNUSED(event),
1659 wxWindow *win )
1660 {
1661 DEBUG_MAIN_THREAD
1662
1663 if (g_isIdle)
1664 wxapp_install_idle_handler();
1665
1666 if (!win->m_hasVMT) return FALSE;
1667 if (g_blockEventsOnDrag) return FALSE;
1668
1669 switch ( g_sendActivateEvent )
1670 {
1671 case -1:
1672 // we've got focus from outside, synthtize wxActivateEvent
1673 g_sendActivateEvent = 1;
1674 break;
1675
1676 case 0:
1677 // another our window just lost focus, it was already ours before
1678 // - don't send any wxActivateEvent
1679 g_sendActivateEvent = -1;
1680 break;
1681 }
1682
1683 g_focusWindowLast =
1684 g_focusWindow = win;
1685
1686 /*
1687 printf( "OnSetFocus from " );
1688 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1689 printf( win->GetClassInfo()->GetClassName() );
1690 printf( " " );
1691 printf( WXSTRINGCAST win->GetLabel() );
1692 printf( ".\n" );
1693 */
1694
1695 // notify the parent keeping track of focus for the kbd navigation
1696 // purposes that we got it
1697 wxChildFocusEvent eventFocus(this);
1698 (void)GetEventHandler()->ProcessEvent(eventFocus);
1699
1700 #ifdef HAVE_XIM
1701 if (win->m_ic)
1702 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1703 #endif
1704
1705 #if wxUSE_CARET
1706 // caret needs to be informed about focus change
1707 wxCaret *caret = win->GetCaret();
1708 if ( caret )
1709 {
1710 caret->OnSetFocus();
1711 }
1712 #endif // wxUSE_CARET
1713
1714 #if wxUSE_TEXTCTRL
1715 // If it's a wxTextCtrl don't send the event as it will be done
1716 // after the control gets to process it.
1717 wxTextCtrl *ctrl = wxDynamicCast(win, wxTextCtrl);
1718 if ( ctrl )
1719 {
1720 return FALSE;
1721 }
1722 #endif
1723
1724 if (win->IsTopLevel())
1725 {
1726 wxActivateEvent event( wxEVT_ACTIVATE, TRUE, win->GetId() );
1727 event.SetEventObject( win );
1728
1729 // ignore return value
1730 win->GetEventHandler()->ProcessEvent( event );
1731 }
1732
1733 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1734 event.SetEventObject( win );
1735
1736 if (win->GetEventHandler()->ProcessEvent( event ))
1737 {
1738 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1739 return TRUE;
1740 }
1741
1742
1743 return FALSE;
1744 }
1745
1746 //-----------------------------------------------------------------------------
1747 // "focus_out_event"
1748 //-----------------------------------------------------------------------------
1749
1750 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
1751 {
1752 DEBUG_MAIN_THREAD
1753
1754 if (g_isIdle)
1755 wxapp_install_idle_handler();
1756
1757 if (!win->m_hasVMT) return FALSE;
1758 if (g_blockEventsOnDrag) return FALSE;
1759
1760 // if the focus goes out of our app alltogether, OnIdle() will send
1761 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1762 // g_sendActivateEvent to -1
1763 g_sendActivateEvent = 0;
1764
1765 wxWindowGTK *winFocus = wxFindFocusedChild(win);
1766 if ( winFocus )
1767 win = winFocus;
1768
1769 g_focusWindow = (wxWindowGTK *)NULL;
1770
1771 /*
1772 printf( "OnKillFocus from " );
1773 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1774 printf( win->GetClassInfo()->GetClassName() );
1775 printf( ".\n" );
1776 */
1777
1778 #ifdef HAVE_XIM
1779 if (win->m_ic)
1780 gdk_im_end();
1781 #endif
1782
1783 #if wxUSE_CARET
1784 // caret needs to be informed about focus change
1785 wxCaret *caret = win->GetCaret();
1786 if ( caret )
1787 {
1788 caret->OnKillFocus();
1789 }
1790 #endif // wxUSE_CARET
1791
1792 #if wxUSE_TEXTCTRL
1793 // If it's a wxTextCtrl don't send the event as it will be done
1794 // after the control gets to process it.
1795 wxTextCtrl *ctrl = wxDynamicCast(win, wxTextCtrl);
1796 if ( ctrl )
1797 {
1798 return FALSE;
1799 }
1800 #endif
1801
1802 if (win->IsTopLevel())
1803 {
1804 wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() );
1805 event.SetEventObject( win );
1806
1807 // ignore return value
1808 win->GetEventHandler()->ProcessEvent( event );
1809 }
1810
1811 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1812 event.SetEventObject( win );
1813
1814 if (win->GetEventHandler()->ProcessEvent( event ))
1815 {
1816 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1817 return TRUE;
1818 }
1819
1820 return FALSE;
1821 }
1822
1823 //-----------------------------------------------------------------------------
1824 // "enter_notify_event"
1825 //-----------------------------------------------------------------------------
1826
1827 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1828 {
1829 DEBUG_MAIN_THREAD
1830
1831 if (g_isIdle)
1832 wxapp_install_idle_handler();
1833
1834 if (!win->m_hasVMT) return FALSE;
1835 if (g_blockEventsOnDrag) return FALSE;
1836
1837 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1838
1839 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1840 #if (GTK_MINOR_VERSION > 0)
1841 event.SetTimestamp( gdk_event->time );
1842 #endif
1843 event.SetEventObject( win );
1844
1845 int x = 0;
1846 int y = 0;
1847 GdkModifierType state = (GdkModifierType)0;
1848
1849 gdk_window_get_pointer( widget->window, &x, &y, &state );
1850
1851 InitMouseEvent(event, gdk_event);
1852
1853 event.m_x = x;
1854 event.m_y = y;
1855
1856 if (win->GetEventHandler()->ProcessEvent( event ))
1857 {
1858 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1859 return TRUE;
1860 }
1861
1862 return FALSE;
1863 }
1864
1865 //-----------------------------------------------------------------------------
1866 // "leave_notify_event"
1867 //-----------------------------------------------------------------------------
1868
1869 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1870 {
1871 DEBUG_MAIN_THREAD
1872
1873 if (g_isIdle)
1874 wxapp_install_idle_handler();
1875
1876 if (!win->m_hasVMT) return FALSE;
1877 if (g_blockEventsOnDrag) return FALSE;
1878
1879 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1880
1881 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1882 #if (GTK_MINOR_VERSION > 0)
1883 event.SetTimestamp( gdk_event->time );
1884 #endif
1885 event.SetEventObject( win );
1886
1887 int x = 0;
1888 int y = 0;
1889 GdkModifierType state = (GdkModifierType)0;
1890
1891 gdk_window_get_pointer( widget->window, &x, &y, &state );
1892
1893 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1894 event.m_controlDown = (state & GDK_CONTROL_MASK);
1895 event.m_altDown = (state & GDK_MOD1_MASK);
1896 event.m_metaDown = (state & GDK_MOD2_MASK);
1897 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1898 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1899 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1900
1901 event.m_x = x;
1902 event.m_y = y;
1903
1904 if (win->GetEventHandler()->ProcessEvent( event ))
1905 {
1906 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1907 return TRUE;
1908 }
1909
1910 return FALSE;
1911 }
1912
1913 //-----------------------------------------------------------------------------
1914 // "value_changed" from m_vAdjust
1915 //-----------------------------------------------------------------------------
1916
1917 static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
1918 {
1919 DEBUG_MAIN_THREAD
1920
1921 if (g_isIdle)
1922 wxapp_install_idle_handler();
1923
1924 if (g_blockEventsOnDrag) return;
1925
1926 if (!win->m_hasVMT) return;
1927
1928 float diff = adjust->value - win->m_oldVerticalPos;
1929 if (fabs(diff) < 0.2) return;
1930
1931 win->m_oldVerticalPos = adjust->value;
1932
1933 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1934 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1935
1936 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1937 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1938 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1939 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1940 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1941
1942 int value = (int)(adjust->value+0.5);
1943
1944 wxScrollWinEvent event( command, value, wxVERTICAL );
1945 event.SetEventObject( win );
1946 win->GetEventHandler()->ProcessEvent( event );
1947 }
1948
1949 //-----------------------------------------------------------------------------
1950 // "value_changed" from m_hAdjust
1951 //-----------------------------------------------------------------------------
1952
1953 static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
1954 {
1955 DEBUG_MAIN_THREAD
1956
1957 if (g_isIdle)
1958 wxapp_install_idle_handler();
1959
1960 if (g_blockEventsOnDrag) return;
1961 if (!win->m_hasVMT) return;
1962
1963 float diff = adjust->value - win->m_oldHorizontalPos;
1964 if (fabs(diff) < 0.2) return;
1965
1966 win->m_oldHorizontalPos = adjust->value;
1967
1968 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1969 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1970
1971 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1972 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1973 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1974 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1975 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1976
1977 int value = (int)(adjust->value+0.5);
1978
1979 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1980 event.SetEventObject( win );
1981 win->GetEventHandler()->ProcessEvent( event );
1982 }
1983
1984 //-----------------------------------------------------------------------------
1985 // "button_press_event" from scrollbar
1986 //-----------------------------------------------------------------------------
1987
1988 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1989 GdkEventButton *gdk_event,
1990 wxWindowGTK *win)
1991 {
1992 DEBUG_MAIN_THREAD
1993
1994 if (g_isIdle)
1995 wxapp_install_idle_handler();
1996
1997
1998 g_blockEventsOnScroll = TRUE;
1999 win->m_isScrolling = (gdk_event->window == widget->slider);
2000
2001 return FALSE;
2002 }
2003
2004 //-----------------------------------------------------------------------------
2005 // "button_release_event" from scrollbar
2006 //-----------------------------------------------------------------------------
2007
2008 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
2009 GdkEventButton *WXUNUSED(gdk_event),
2010 wxWindowGTK *win)
2011 {
2012 DEBUG_MAIN_THREAD
2013
2014 // don't test here as we can release the mouse while being over
2015 // a different window than the slider
2016 //
2017 // if (gdk_event->window != widget->slider) return FALSE;
2018
2019 g_blockEventsOnScroll = FALSE;
2020
2021 if (win->m_isScrolling)
2022 {
2023 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2024 int value = -1;
2025 int dir = -1;
2026
2027 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2028 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2029 {
2030 value = (int)(win->m_hAdjust->value+0.5);
2031 dir = wxHORIZONTAL;
2032 }
2033 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2034 {
2035 value = (int)(win->m_vAdjust->value+0.5);
2036 dir = wxVERTICAL;
2037 }
2038
2039 wxScrollWinEvent event( command, value, dir );
2040 event.SetEventObject( win );
2041 win->GetEventHandler()->ProcessEvent( event );
2042 }
2043
2044 win->m_isScrolling = FALSE;
2045
2046 return FALSE;
2047 }
2048
2049 // ----------------------------------------------------------------------------
2050 // this wxWindowBase function is implemented here (in platform-specific file)
2051 // because it is static and so couldn't be made virtual
2052 // ----------------------------------------------------------------------------
2053
2054 wxWindow *wxWindowBase::FindFocus()
2055 {
2056 // the cast is necessary when we compile in wxUniversal mode
2057 return (wxWindow *)g_focusWindow;
2058 }
2059
2060 //-----------------------------------------------------------------------------
2061 // "realize" from m_widget
2062 //-----------------------------------------------------------------------------
2063
2064 /* We cannot set colours and fonts before the widget has
2065 been realized, so we do this directly after realization. */
2066
2067 static gint
2068 gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
2069 {
2070 DEBUG_MAIN_THREAD
2071
2072 if (g_isIdle)
2073 wxapp_install_idle_handler();
2074
2075 if (win->m_delayedBackgroundColour)
2076 win->SetBackgroundColour( win->GetBackgroundColour() );
2077
2078 if (win->m_delayedForegroundColour)
2079 win->SetForegroundColour( win->GetForegroundColour() );
2080
2081 wxWindowCreateEvent event( win );
2082 event.SetEventObject( win );
2083 win->GetEventHandler()->ProcessEvent( event );
2084
2085 return FALSE;
2086 }
2087
2088 //-----------------------------------------------------------------------------
2089 // "size_allocate"
2090 //-----------------------------------------------------------------------------
2091
2092 static
2093 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2094 GtkAllocation *WXUNUSED(alloc),
2095 wxWindow *win )
2096 {
2097 if (g_isIdle)
2098 wxapp_install_idle_handler();
2099
2100 if (!win->m_hasScrolling) return;
2101
2102 int client_width = 0;
2103 int client_height = 0;
2104 win->GetClientSize( &client_width, &client_height );
2105 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2106 return;
2107
2108 win->m_oldClientWidth = client_width;
2109 win->m_oldClientHeight = client_height;
2110
2111 if (!win->m_nativeSizeEvent)
2112 {
2113 wxSizeEvent event( win->GetSize(), win->GetId() );
2114 event.SetEventObject( win );
2115 win->GetEventHandler()->ProcessEvent( event );
2116 }
2117 }
2118
2119
2120 #ifdef HAVE_XIM
2121 #define WXUNUSED_UNLESS_XIM(param) param
2122 #else
2123 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2124 #endif
2125
2126 /* Resize XIM window */
2127
2128 static
2129 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2130 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
2131 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
2132 {
2133 if (g_isIdle)
2134 wxapp_install_idle_handler();
2135
2136 #ifdef HAVE_XIM
2137 if (!win->m_ic)
2138 return;
2139
2140 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2141 {
2142 gint width, height;
2143
2144 gdk_window_get_size (widget->window, &width, &height);
2145 win->m_icattr->preedit_area.width = width;
2146 win->m_icattr->preedit_area.height = height;
2147 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2148 }
2149 #endif // HAVE_XIM
2150 }
2151
2152 //-----------------------------------------------------------------------------
2153 // "realize" from m_wxwindow
2154 //-----------------------------------------------------------------------------
2155
2156 /* Initialize XIM support */
2157
2158 static gint
2159 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2160 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
2161 {
2162 if (g_isIdle)
2163 wxapp_install_idle_handler();
2164
2165 #ifdef HAVE_XIM
2166 if (win->m_ic) return FALSE;
2167 if (!widget) return FALSE;
2168 if (!gdk_im_ready()) return FALSE;
2169
2170 win->m_icattr = gdk_ic_attr_new();
2171 if (!win->m_icattr) return FALSE;
2172
2173 gint width, height;
2174 GdkEventMask mask;
2175 GdkColormap *colormap;
2176 GdkICAttr *attr = win->m_icattr;
2177 unsigned attrmask = GDK_IC_ALL_REQ;
2178 GdkIMStyle style;
2179 GdkIMStyle supported_style = (GdkIMStyle)
2180 (GDK_IM_PREEDIT_NONE |
2181 GDK_IM_PREEDIT_NOTHING |
2182 GDK_IM_PREEDIT_POSITION |
2183 GDK_IM_STATUS_NONE |
2184 GDK_IM_STATUS_NOTHING);
2185
2186 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2187 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2188
2189 attr->style = style = gdk_im_decide_style (supported_style);
2190 attr->client_window = widget->window;
2191
2192 if ((colormap = gtk_widget_get_colormap (widget)) !=
2193 gtk_widget_get_default_colormap ())
2194 {
2195 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2196 attr->preedit_colormap = colormap;
2197 }
2198
2199 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2200 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2201 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2202 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2203
2204 switch (style & GDK_IM_PREEDIT_MASK)
2205 {
2206 case GDK_IM_PREEDIT_POSITION:
2207 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2208 {
2209 g_warning ("over-the-spot style requires fontset");
2210 break;
2211 }
2212
2213 gdk_window_get_size (widget->window, &width, &height);
2214
2215 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2216 attr->spot_location.x = 0;
2217 attr->spot_location.y = height;
2218 attr->preedit_area.x = 0;
2219 attr->preedit_area.y = 0;
2220 attr->preedit_area.width = width;
2221 attr->preedit_area.height = height;
2222 attr->preedit_fontset = widget->style->font;
2223
2224 break;
2225 }
2226
2227 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2228
2229 if (win->m_ic == NULL)
2230 g_warning ("Can't create input context.");
2231 else
2232 {
2233 mask = gdk_window_get_events (widget->window);
2234 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2235 gdk_window_set_events (widget->window, mask);
2236
2237 if (GTK_WIDGET_HAS_FOCUS(widget))
2238 gdk_im_begin (win->m_ic, widget->window);
2239 }
2240 #endif // HAVE_XIM
2241
2242 return FALSE;
2243 }
2244
2245 //-----------------------------------------------------------------------------
2246 // InsertChild for wxWindowGTK.
2247 //-----------------------------------------------------------------------------
2248
2249 /* Callback for wxWindowGTK. This very strange beast has to be used because
2250 * C++ has no virtual methods in a constructor. We have to emulate a
2251 * virtual function here as wxNotebook requires a different way to insert
2252 * a child in it. I had opted for creating a wxNotebookPage window class
2253 * which would have made this superfluous (such in the MDI window system),
2254 * but no-one was listening to me... */
2255
2256 static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
2257 {
2258 /* the window might have been scrolled already, do we
2259 have to adapt the position */
2260 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2261 child->m_x += pizza->xoffset;
2262 child->m_y += pizza->yoffset;
2263
2264 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2265 GTK_WIDGET(child->m_widget),
2266 child->m_x,
2267 child->m_y,
2268 child->m_width,
2269 child->m_height );
2270 }
2271
2272 //-----------------------------------------------------------------------------
2273 // global functions
2274 //-----------------------------------------------------------------------------
2275
2276 wxWindow *wxGetActiveWindow()
2277 {
2278 // the cast is necessary when we compile in wxUniversal mode
2279 return (wxWindow *)g_focusWindow;
2280 }
2281
2282 //-----------------------------------------------------------------------------
2283 // wxWindowGTK
2284 //-----------------------------------------------------------------------------
2285
2286 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2287 // method
2288 #ifdef __WXUNIVERSAL__
2289 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2290 #else // __WXGTK__
2291 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2292 #endif // __WXUNIVERSAL__/__WXGTK__
2293
2294 void wxWindowGTK::Init()
2295 {
2296 // common init
2297 InitBase();
2298
2299 // GTK specific
2300 m_widget = (GtkWidget *) NULL;
2301 m_wxwindow = (GtkWidget *) NULL;
2302
2303 // position/size
2304 m_x = 0;
2305 m_y = 0;
2306 m_width = 0;
2307 m_height = 0;
2308
2309 m_sizeSet = FALSE;
2310 m_hasVMT = FALSE;
2311 m_needParent = TRUE;
2312 m_isBeingDeleted = FALSE;
2313
2314 m_noExpose = FALSE;
2315 m_nativeSizeEvent = FALSE;
2316
2317 m_hasScrolling = FALSE;
2318 m_isScrolling = FALSE;
2319
2320 m_hAdjust = (GtkAdjustment*) NULL;
2321 m_vAdjust = (GtkAdjustment*) NULL;
2322 m_oldHorizontalPos = 0.0;
2323 m_oldVerticalPos = 0.0;
2324
2325 m_resizing = FALSE;
2326 m_widgetStyle = (GtkStyle*) NULL;
2327
2328 m_insertCallback = (wxInsertChildFunction) NULL;
2329
2330 m_isStaticBox = FALSE;
2331 m_isRadioButton = FALSE;
2332 m_isFrame = FALSE;
2333 m_acceptsFocus = FALSE;
2334
2335 m_clipPaintRegion = FALSE;
2336
2337 m_cursor = *wxSTANDARD_CURSOR;
2338
2339 m_delayedForegroundColour = FALSE;
2340 m_delayedBackgroundColour = FALSE;
2341
2342 #ifdef HAVE_XIM
2343 m_ic = (GdkIC*) NULL;
2344 m_icattr = (GdkICAttr*) NULL;
2345 #endif
2346 }
2347
2348 wxWindowGTK::wxWindowGTK()
2349 {
2350 Init();
2351 }
2352
2353 wxWindowGTK::wxWindowGTK( wxWindow *parent,
2354 wxWindowID id,
2355 const wxPoint &pos,
2356 const wxSize &size,
2357 long style,
2358 const wxString &name )
2359 {
2360 Init();
2361
2362 Create( parent, id, pos, size, style, name );
2363 }
2364
2365 bool wxWindowGTK::Create( wxWindow *parent,
2366 wxWindowID id,
2367 const wxPoint &pos,
2368 const wxSize &size,
2369 long style,
2370 const wxString &name )
2371 {
2372 if (!PreCreation( parent, pos, size ) ||
2373 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2374 {
2375 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2376 return FALSE;
2377 }
2378
2379 m_insertCallback = wxInsertChildInWindow;
2380
2381 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2382 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2383
2384 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2385
2386 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2387 scroll_class->scrollbar_spacing = 0;
2388
2389 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2390
2391 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2392 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2393
2394 m_wxwindow = gtk_pizza_new();
2395
2396 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2397
2398 #ifndef __WXUNIVERSAL__
2399 #if (GTK_MINOR_VERSION > 0)
2400 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2401
2402 if (HasFlag(wxRAISED_BORDER))
2403 {
2404 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2405 }
2406 else if (HasFlag(wxSUNKEN_BORDER))
2407 {
2408 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2409 }
2410 else if (HasFlag(wxSIMPLE_BORDER))
2411 {
2412 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2413 }
2414 else
2415 {
2416 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2417 }
2418 #else // GTK_MINOR_VERSION == 0
2419 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2420
2421 if (HasFlag(wxRAISED_BORDER))
2422 {
2423 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2424 }
2425 else if (HasFlag(wxSUNKEN_BORDER))
2426 {
2427 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2428 }
2429 else
2430 {
2431 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2432 }
2433 #endif // GTK_MINOR_VERSION
2434 #endif // __WXUNIVERSAL__
2435
2436 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2437 m_acceptsFocus = TRUE;
2438
2439 #if (GTK_MINOR_VERSION == 0)
2440 // shut the viewport up
2441 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2442 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2443 #endif // GTK_MINOR_VERSION == 0
2444
2445 // I _really_ don't want scrollbars in the beginning
2446 m_vAdjust->lower = 0.0;
2447 m_vAdjust->upper = 1.0;
2448 m_vAdjust->value = 0.0;
2449 m_vAdjust->step_increment = 1.0;
2450 m_vAdjust->page_increment = 1.0;
2451 m_vAdjust->page_size = 5.0;
2452 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2453 m_hAdjust->lower = 0.0;
2454 m_hAdjust->upper = 1.0;
2455 m_hAdjust->value = 0.0;
2456 m_hAdjust->step_increment = 1.0;
2457 m_hAdjust->page_increment = 1.0;
2458 m_hAdjust->page_size = 5.0;
2459 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2460
2461 // these handlers block mouse events to any window during scrolling such as
2462 // motion events and prevent GTK and wxWindows from fighting over where the
2463 // slider should be
2464
2465 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2466 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2467
2468 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2469 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2470
2471 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2472 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2473
2474 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2475 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2476
2477 // these handlers get notified when screen updates are required either when
2478 // scrolling or when the window size (and therefore scrollbar configuration)
2479 // has changed
2480
2481 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2482 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2483 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2484 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2485
2486 gtk_widget_show( m_wxwindow );
2487
2488 if (m_parent)
2489 m_parent->DoAddChild( this );
2490
2491 PostCreation();
2492
2493 Show( TRUE );
2494
2495 return TRUE;
2496 }
2497
2498 wxWindowGTK::~wxWindowGTK()
2499 {
2500 if (g_focusWindow == this)
2501 g_focusWindow = NULL;
2502
2503 m_isBeingDeleted = TRUE;
2504 m_hasVMT = FALSE;
2505
2506 if (m_widget)
2507 Show( FALSE );
2508
2509 DestroyChildren();
2510
2511 if (m_parent)
2512 m_parent->RemoveChild( this );
2513
2514 #ifdef HAVE_XIM
2515 if (m_ic)
2516 gdk_ic_destroy (m_ic);
2517 if (m_icattr)
2518 gdk_ic_attr_destroy (m_icattr);
2519 #endif
2520
2521 if (m_widgetStyle)
2522 {
2523 #if DISABLE_STYLE_IF_BROKEN_THEME
2524 // don't delete if it's a pixmap theme style
2525 if (!m_widgetStyle->engine_data)
2526 gtk_style_unref( m_widgetStyle );
2527 #endif
2528 m_widgetStyle = (GtkStyle*) NULL;
2529 }
2530
2531 if (m_wxwindow)
2532 {
2533 gtk_widget_destroy( m_wxwindow );
2534 m_wxwindow = (GtkWidget*) NULL;
2535 }
2536
2537 if (m_widget)
2538 {
2539 gtk_widget_destroy( m_widget );
2540 m_widget = (GtkWidget*) NULL;
2541 }
2542 }
2543
2544 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2545 {
2546 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2547
2548 /* this turns -1 into 20 so that a minimal window is
2549 visible even although -1,-1 has been given as the
2550 size of the window. the same trick is used in other
2551 ports and should make debugging easier */
2552 m_width = WidthDefault(size.x);
2553 m_height = HeightDefault(size.y);
2554
2555 m_x = (int)pos.x;
2556 m_y = (int)pos.y;
2557
2558 /* some reasonable defaults */
2559 if (!parent)
2560 {
2561 if (m_x == -1)
2562 {
2563 m_x = (gdk_screen_width () - m_width) / 2;
2564 if (m_x < 10) m_x = 10;
2565 }
2566 if (m_y == -1)
2567 {
2568 m_y = (gdk_screen_height () - m_height) / 2;
2569 if (m_y < 10) m_y = 10;
2570 }
2571 }
2572
2573 return TRUE;
2574 }
2575
2576 void wxWindowGTK::PostCreation()
2577 {
2578 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2579
2580 if (m_wxwindow)
2581 {
2582 if (!m_noExpose)
2583 {
2584 /* these get reported to wxWindows -> wxPaintEvent */
2585
2586 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2587
2588 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2589 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2590
2591 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2592 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2593
2594 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2595 {
2596 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2597 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2598 }
2599 }
2600
2601 #if (GTK_MINOR_VERSION > 0)
2602 /* these are called when the "sunken" or "raised" borders are drawn */
2603 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2604 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2605
2606 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2607 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2608 #endif
2609 }
2610
2611 if (m_wxwindow && m_needParent)
2612 {
2613 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
2614 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2615
2616 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
2617 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2618 }
2619 else
2620 {
2621 // For dialogs and frames, we are interested mainly in
2622 // m_widget's focus.
2623
2624 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
2625 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2626
2627 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
2628 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2629 }
2630
2631 GtkWidget *connect_widget = GetConnectWidget();
2632
2633 ConnectWidget( connect_widget );
2634
2635 /* We cannot set colours, fonts and cursors before the widget has
2636 been realized, so we do this directly after realization */
2637 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2638 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2639
2640 if (m_wxwindow)
2641 {
2642 // Catch native resize events
2643 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2644 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2645
2646 // Initialize XIM support
2647 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2648 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2649
2650 // And resize XIM window
2651 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2652 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2653 }
2654
2655 if (!GTK_IS_COMBO(m_widget))
2656 {
2657 // This is needed if we want to add our windows into native
2658 // GTK control, such as the toolbar. With this callback, the
2659 // toolbar gets to know the correct size (the one set by the
2660 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2661 // when moving to GTK 2.0.
2662 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2663 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2664 }
2665
2666 m_hasVMT = TRUE;
2667 }
2668
2669 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2670 {
2671 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2672 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2673
2674 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2675 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2676
2677 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2678 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2679
2680 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2681 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2682
2683 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2684 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2685
2686 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2687 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2688
2689 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2690 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2691 }
2692
2693 bool wxWindowGTK::Destroy()
2694 {
2695 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2696
2697 m_hasVMT = FALSE;
2698
2699 return wxWindowBase::Destroy();
2700 }
2701
2702 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
2703 {
2704 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2705 }
2706
2707 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2708 {
2709 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2710 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
2711
2712 /*
2713 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2714 */
2715
2716 if (m_resizing) return; /* I don't like recursions */
2717 m_resizing = TRUE;
2718
2719 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2720 {
2721 /* don't set the size for children of wxNotebook, just take the values. */
2722 m_x = x;
2723 m_y = y;
2724 m_width = width;
2725 m_height = height;
2726 }
2727 else
2728 {
2729 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2730
2731 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2732 {
2733 if (x != -1) m_x = x + pizza->xoffset;
2734 if (y != -1) m_y = y + pizza->yoffset;
2735 if (width != -1) m_width = width;
2736 if (height != -1) m_height = height;
2737 }
2738 else
2739 {
2740 m_x = x + pizza->xoffset;
2741 m_y = y + pizza->yoffset;
2742 m_width = width;
2743 m_height = height;
2744 }
2745
2746 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2747 {
2748 if (width == -1) m_width = 80;
2749 }
2750
2751 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2752 {
2753 if (height == -1) m_height = 26;
2754 }
2755
2756 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2757 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2758 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2759 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2760
2761 int border = 0;
2762 int bottom_border = 0;
2763
2764 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2765 {
2766 /* the default button has a border around it */
2767 border = 6;
2768 bottom_border = 5;
2769 }
2770
2771 DoMoveWindow( m_x-border,
2772 m_y-border,
2773 m_width+2*border,
2774 m_height+border+bottom_border );
2775 }
2776
2777 if (m_hasScrolling)
2778 {
2779 /* Sometimes the client area changes size without the
2780 whole windows's size changing, but if the whole
2781 windows's size doesn't change, no wxSizeEvent will
2782 normally be sent. Here we add an extra test if
2783 the client test has been changed and this will
2784 be used then. */
2785 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2786 }
2787
2788 /*
2789 wxPrintf( "OnSize sent from " );
2790 if (GetClassInfo() && GetClassInfo()->GetClassName())
2791 wxPrintf( GetClassInfo()->GetClassName() );
2792 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2793 */
2794
2795 if (!m_nativeSizeEvent)
2796 {
2797 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2798 event.SetEventObject( this );
2799 GetEventHandler()->ProcessEvent( event );
2800 }
2801
2802 m_resizing = FALSE;
2803 }
2804
2805 void wxWindowGTK::OnInternalIdle()
2806 {
2807 if ( g_sendActivateEvent != -1 )
2808 {
2809 bool activate = g_sendActivateEvent != 0;
2810
2811 // do it only once
2812 g_sendActivateEvent = -1;
2813
2814 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
2815
2816 wxActivateEvent event(wxEVT_ACTIVATE_APP, activate, GetId());
2817 event.SetEventObject(this);
2818
2819 (void)GetEventHandler()->ProcessEvent(event);
2820 }
2821
2822 wxCursor cursor = m_cursor;
2823 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2824
2825 if (cursor.Ok())
2826 {
2827 /* I now set the cursor anew in every OnInternalIdle call
2828 as setting the cursor in a parent window also effects the
2829 windows above so that checking for the current cursor is
2830 not possible. */
2831
2832 if (m_wxwindow)
2833 {
2834 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2835 if (window)
2836 gdk_window_set_cursor( window, cursor.GetCursor() );
2837
2838 if (!g_globalCursor.Ok())
2839 cursor = *wxSTANDARD_CURSOR;
2840
2841 window = m_widget->window;
2842 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2843 gdk_window_set_cursor( window, cursor.GetCursor() );
2844
2845 }
2846 else
2847 {
2848
2849 GdkWindow *window = m_widget->window;
2850 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2851 gdk_window_set_cursor( window, cursor.GetCursor() );
2852
2853 }
2854 }
2855
2856 UpdateWindowUI();
2857 }
2858
2859 void wxWindowGTK::DoGetSize( int *width, int *height ) const
2860 {
2861 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2862
2863 if (width) (*width) = m_width;
2864 if (height) (*height) = m_height;
2865 }
2866
2867 void wxWindowGTK::DoSetClientSize( int width, int height )
2868 {
2869 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2870
2871 if (!m_wxwindow)
2872 {
2873 SetSize( width, height );
2874 }
2875 else
2876 {
2877 int dw = 0;
2878 int dh = 0;
2879
2880 #ifndef __WXUNIVERSAL__
2881 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2882 {
2883 /* when using GTK 1.2 we set the shadow border size to 2 */
2884 dw += 2 * 2;
2885 dh += 2 * 2;
2886 }
2887 if (HasFlag(wxSIMPLE_BORDER))
2888 {
2889 /* when using GTK 1.2 we set the simple border size to 1 */
2890 dw += 1 * 2;
2891 dh += 1 * 2;
2892 }
2893 #endif // __WXUNIVERSAL__
2894
2895 if (m_hasScrolling)
2896 {
2897 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2898
2899 GtkRequisition vscroll_req;
2900 vscroll_req.width = 2;
2901 vscroll_req.height = 2;
2902 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2903 (scroll_window->vscrollbar, &vscroll_req );
2904
2905 GtkRequisition hscroll_req;
2906 hscroll_req.width = 2;
2907 hscroll_req.height = 2;
2908 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2909 (scroll_window->hscrollbar, &hscroll_req );
2910
2911 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2912
2913 if (scroll_window->vscrollbar_visible)
2914 {
2915 dw += vscroll_req.width;
2916 dw += scroll_class->scrollbar_spacing;
2917 }
2918
2919 if (scroll_window->hscrollbar_visible)
2920 {
2921 dh += hscroll_req.height;
2922 dh += scroll_class->scrollbar_spacing;
2923 }
2924 }
2925
2926 SetSize( width+dw, height+dh );
2927 }
2928 }
2929
2930 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
2931 {
2932 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2933
2934 if (!m_wxwindow)
2935 {
2936 if (width) (*width) = m_width;
2937 if (height) (*height) = m_height;
2938 }
2939 else
2940 {
2941 int dw = 0;
2942 int dh = 0;
2943
2944 #ifndef __WXUNIVERSAL__
2945 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2946 {
2947 /* when using GTK 1.2 we set the shadow border size to 2 */
2948 dw += 2 * 2;
2949 dh += 2 * 2;
2950 }
2951 if (HasFlag(wxSIMPLE_BORDER))
2952 {
2953 /* when using GTK 1.2 we set the simple border size to 1 */
2954 dw += 1 * 2;
2955 dh += 1 * 2;
2956 }
2957 #endif // __WXUNIVERSAL__
2958
2959 if (m_hasScrolling)
2960 {
2961 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2962
2963 GtkRequisition vscroll_req;
2964 vscroll_req.width = 2;
2965 vscroll_req.height = 2;
2966 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2967 (scroll_window->vscrollbar, &vscroll_req );
2968
2969 GtkRequisition hscroll_req;
2970 hscroll_req.width = 2;
2971 hscroll_req.height = 2;
2972 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2973 (scroll_window->hscrollbar, &hscroll_req );
2974
2975 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2976
2977 if (scroll_window->vscrollbar_visible)
2978 {
2979 dw += vscroll_req.width;
2980 dw += scroll_class->scrollbar_spacing;
2981 }
2982
2983 if (scroll_window->hscrollbar_visible)
2984 {
2985 dh += hscroll_req.height;
2986 dh += scroll_class->scrollbar_spacing;
2987 }
2988 }
2989
2990 if (width) (*width) = m_width - dw;
2991 if (height) (*height) = m_height - dh;
2992 }
2993
2994 /*
2995 printf( "GetClientSize, name %s ", GetName().c_str() );
2996 if (width) printf( " width = %d", (*width) );
2997 if (height) printf( " height = %d", (*height) );
2998 printf( "\n" );
2999 */
3000 }
3001
3002 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3003 {
3004 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3005
3006 int dx = 0;
3007 int dy = 0;
3008 if (m_parent && m_parent->m_wxwindow)
3009 {
3010 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3011 dx = pizza->xoffset;
3012 dy = pizza->yoffset;
3013 }
3014
3015 if (x) (*x) = m_x - dx;
3016 if (y) (*y) = m_y - dy;
3017 }
3018
3019 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3020 {
3021 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3022
3023 if (!m_widget->window) return;
3024
3025 GdkWindow *source = (GdkWindow *) NULL;
3026 if (m_wxwindow)
3027 source = GTK_PIZZA(m_wxwindow)->bin_window;
3028 else
3029 source = m_widget->window;
3030
3031 int org_x = 0;
3032 int org_y = 0;
3033 gdk_window_get_origin( source, &org_x, &org_y );
3034
3035 if (!m_wxwindow)
3036 {
3037 if (GTK_WIDGET_NO_WINDOW (m_widget))
3038 {
3039 org_x += m_widget->allocation.x;
3040 org_y += m_widget->allocation.y;
3041 }
3042 }
3043
3044 if (x) *x += org_x;
3045 if (y) *y += org_y;
3046 }
3047
3048 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3049 {
3050 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3051
3052 if (!m_widget->window) return;
3053
3054 GdkWindow *source = (GdkWindow *) NULL;
3055 if (m_wxwindow)
3056 source = GTK_PIZZA(m_wxwindow)->bin_window;
3057 else
3058 source = m_widget->window;
3059
3060 int org_x = 0;
3061 int org_y = 0;
3062 gdk_window_get_origin( source, &org_x, &org_y );
3063
3064 if (!m_wxwindow)
3065 {
3066 if (GTK_WIDGET_NO_WINDOW (m_widget))
3067 {
3068 org_x += m_widget->allocation.x;
3069 org_y += m_widget->allocation.y;
3070 }
3071 }
3072
3073 if (x) *x -= org_x;
3074 if (y) *y -= org_y;
3075 }
3076
3077 bool wxWindowGTK::Show( bool show )
3078 {
3079 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3080
3081 if (!wxWindowBase::Show(show))
3082 {
3083 // nothing to do
3084 return FALSE;
3085 }
3086
3087 if (show)
3088 gtk_widget_show( m_widget );
3089 else
3090 gtk_widget_hide( m_widget );
3091
3092 return TRUE;
3093 }
3094
3095 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3096 {
3097 win->OnParentEnable(enable);
3098
3099 // Recurse, so that children have the opportunity to Do The Right Thing
3100 // and reset colours that have been messed up by a parent's (really ancestor's)
3101 // Enable call
3102 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
3103 node;
3104 node = node->GetNext() )
3105 {
3106 wxWindow *child = node->GetData();
3107 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3108 wxWindowNotifyEnable(child, enable);
3109 }
3110 }
3111
3112 bool wxWindowGTK::Enable( bool enable )
3113 {
3114 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3115
3116 if (!wxWindowBase::Enable(enable))
3117 {
3118 // nothing to do
3119 return FALSE;
3120 }
3121
3122 gtk_widget_set_sensitive( m_widget, enable );
3123 if ( m_wxwindow )
3124 gtk_widget_set_sensitive( m_wxwindow, enable );
3125
3126 wxWindowNotifyEnable(this, enable);
3127
3128 return TRUE;
3129 }
3130
3131 int wxWindowGTK::GetCharHeight() const
3132 {
3133 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3134
3135 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
3136
3137 GdkFont *font = m_font.GetInternalFont( 1.0 );
3138
3139 return font->ascent + font->descent;
3140 }
3141
3142 int wxWindowGTK::GetCharWidth() const
3143 {
3144 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3145
3146 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
3147
3148 GdkFont *font = m_font.GetInternalFont( 1.0 );
3149
3150 return gdk_string_width( font, "H" );
3151 }
3152
3153 void wxWindowGTK::GetTextExtent( const wxString& string,
3154 int *x,
3155 int *y,
3156 int *descent,
3157 int *externalLeading,
3158 const wxFont *theFont ) const
3159 {
3160 wxFont fontToUse = m_font;
3161 if (theFont) fontToUse = *theFont;
3162
3163 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3164
3165 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3166 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
3167 if (y) (*y) = font->ascent + font->descent;
3168 if (descent) (*descent) = font->descent;
3169 if (externalLeading) (*externalLeading) = 0; // ??
3170 }
3171
3172 void wxWindowGTK::SetFocus()
3173 {
3174 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3175
3176 if (m_wxwindow)
3177 {
3178 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3179 gtk_widget_grab_focus (m_wxwindow);
3180 return;
3181 }
3182
3183 if (m_widget)
3184 {
3185 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3186 {
3187 gtk_widget_grab_focus (m_widget);
3188 }
3189 else if (GTK_IS_CONTAINER(m_widget))
3190 {
3191 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3192 }
3193 else
3194 {
3195 // ?
3196 }
3197 }
3198 }
3199
3200 bool wxWindowGTK::AcceptsFocus() const
3201 {
3202 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3203 }
3204
3205 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3206 {
3207 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3208
3209 wxWindowGTK *oldParent = m_parent,
3210 *newParent = (wxWindowGTK *)newParentBase;
3211
3212 wxASSERT( GTK_IS_WIDGET(m_widget) );
3213
3214 if ( !wxWindowBase::Reparent(newParent) )
3215 return FALSE;
3216
3217 wxASSERT( GTK_IS_WIDGET(m_widget) );
3218
3219 /* prevent GTK from deleting the widget arbitrarily */
3220 gtk_widget_ref( m_widget );
3221
3222 if (oldParent)
3223 {
3224 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3225 }
3226
3227 wxASSERT( GTK_IS_WIDGET(m_widget) );
3228
3229 if (newParent)
3230 {
3231 /* insert GTK representation */
3232 (*(newParent->m_insertCallback))(newParent, this);
3233 }
3234
3235 /* reverse: prevent GTK from deleting the widget arbitrarily */
3236 gtk_widget_unref( m_widget );
3237
3238 return TRUE;
3239 }
3240
3241 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3242 {
3243 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3244
3245 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3246
3247 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3248
3249 /* add to list */
3250 AddChild( child );
3251
3252 /* insert GTK representation */
3253 (*m_insertCallback)(this, child);
3254 }
3255
3256 void wxWindowGTK::Raise()
3257 {
3258 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3259
3260 if (!m_widget->window) return;
3261
3262 gdk_window_raise( m_widget->window );
3263 }
3264
3265 void wxWindowGTK::Lower()
3266 {
3267 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3268
3269 if (!m_widget->window) return;
3270
3271 gdk_window_lower( m_widget->window );
3272 }
3273
3274 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3275 {
3276 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3277
3278 if (cursor == m_cursor)
3279 return FALSE;
3280
3281 if (g_isIdle)
3282 wxapp_install_idle_handler();
3283
3284 if (cursor == wxNullCursor)
3285 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3286 else
3287 return wxWindowBase::SetCursor( cursor );
3288 }
3289
3290 void wxWindowGTK::WarpPointer( int x, int y )
3291 {
3292 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3293
3294 /* we provide this function ourselves as it is
3295 missing in GDK (top of this file) */
3296
3297 GdkWindow *window = (GdkWindow*) NULL;
3298 if (m_wxwindow)
3299 window = GTK_PIZZA(m_wxwindow)->bin_window;
3300 else
3301 window = GetConnectWidget()->window;
3302
3303 if (window)
3304 gdk_window_warp_pointer( window, x, y );
3305 }
3306
3307 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3308 {
3309 if (!m_widget) return;
3310 if (!m_widget->window) return;
3311
3312 // temporarily hide the caret to avoid nasty interactions between caret
3313 // drawing and the window contents redraw
3314 #if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3315 wxCaretSuspend cs((wxWindow *)this);
3316 #endif // wxUSE_CARET
3317
3318 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3319 {
3320 if (rect)
3321 {
3322 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3323 rect->x, rect->y,
3324 rect->width, rect->height );
3325 }
3326 else
3327 {
3328 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
3329 }
3330 }
3331
3332 /* there is no GTK equivalent of "draw only, don't clear" so we
3333 invent our own in the GtkPizza widget */
3334
3335 if (!rect)
3336 {
3337 if (m_wxwindow)
3338 {
3339
3340 /*
3341 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3342 gboolean old_clear = pizza->clear_on_draw;
3343 gtk_pizza_set_clear( pizza, FALSE );
3344 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
3345 gtk_pizza_set_clear( pizza, old_clear );
3346 */
3347 GdkEventExpose gdk_event;
3348 gdk_event.type = GDK_EXPOSE;
3349 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3350 gdk_event.count = 0;
3351 gdk_event.area.x = 0;
3352 gdk_event.area.y = 0;
3353 gdk_event.area.width = m_wxwindow->allocation.width;
3354 gdk_event.area.height = m_wxwindow->allocation.height;
3355 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
3356 }
3357 else
3358 {
3359 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3360 }
3361 }
3362 else
3363 {
3364
3365 if (m_wxwindow)
3366 {
3367 /*
3368 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3369 gboolean old_clear = pizza->clear_on_draw;
3370 gtk_pizza_set_clear( pizza, FALSE );
3371
3372 GdkRectangle gdk_rect;
3373 gdk_rect.x = rect->x;
3374 gdk_rect.y = rect->y;
3375 gdk_rect.width = rect->width;
3376 gdk_rect.height = rect->height;
3377 gtk_widget_draw( m_wxwindow, &gdk_rect );
3378 gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
3379
3380 gtk_pizza_set_clear( pizza, old_clear );
3381 */
3382 GdkEventExpose gdk_event;
3383 gdk_event.type = GDK_EXPOSE;
3384 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3385 gdk_event.count = 0;
3386 gdk_event.area.x = rect->x;
3387 gdk_event.area.y = rect->y;
3388 gdk_event.area.width = rect->width;
3389 gdk_event.area.height = rect->height;
3390 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
3391 }
3392 else
3393 {
3394 GdkRectangle gdk_rect;
3395 gdk_rect.x = rect->x;
3396 gdk_rect.y = rect->y;
3397 gdk_rect.width = rect->width;
3398 gdk_rect.height = rect->height;
3399 gtk_widget_draw( m_widget, &gdk_rect );
3400 }
3401 }
3402 }
3403
3404 void wxWindowGTK::Clear()
3405 {
3406 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3407
3408 if (!m_widget->window) return;
3409
3410 if (m_wxwindow && m_wxwindow->window)
3411 {
3412 // gdk_window_clear( m_wxwindow->window );
3413 }
3414 }
3415
3416 #if wxUSE_TOOLTIPS
3417 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
3418 {
3419 wxWindowBase::DoSetToolTip(tip);
3420
3421 if (m_tooltip)
3422 m_tooltip->Apply( (wxWindow *)this );
3423 }
3424
3425 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3426 {
3427 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
3428 }
3429 #endif // wxUSE_TOOLTIPS
3430
3431 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
3432 {
3433 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3434
3435 if (!wxWindowBase::SetBackgroundColour(colour))
3436 {
3437 // don't leave if the GTK widget has just
3438 // been realized
3439 if (!m_delayedBackgroundColour) return FALSE;
3440 }
3441
3442 GdkWindow *window = (GdkWindow*) NULL;
3443 if (m_wxwindow)
3444 window = GTK_PIZZA(m_wxwindow)->bin_window;
3445 else
3446 window = GetConnectWidget()->window;
3447
3448 if (!window)
3449 {
3450 // indicate that a new style has been set
3451 // but it couldn't get applied as the
3452 // widget hasn't been realized yet.
3453 m_delayedBackgroundColour = TRUE;
3454 }
3455
3456 if ((m_wxwindow) &&
3457 (m_wxwindow->window) &&
3458 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
3459 {
3460 /* wxMSW doesn't clear the window here. I don't do that either to
3461 provide compatibility. call Clear() to do the job. */
3462
3463 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3464 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3465 }
3466
3467 ApplyWidgetStyle();
3468
3469 return TRUE;
3470 }
3471
3472 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
3473 {
3474 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3475
3476 if (!wxWindowBase::SetForegroundColour(colour))
3477 {
3478 // don't leave if the GTK widget has just
3479 // been realized
3480 if (!m_delayedForegroundColour) return FALSE;
3481 }
3482
3483 GdkWindow *window = (GdkWindow*) NULL;
3484 if (m_wxwindow)
3485 window = GTK_PIZZA(m_wxwindow)->bin_window;
3486 else
3487 window = GetConnectWidget()->window;
3488
3489 if (!window)
3490 {
3491 // indicate that a new style has been set
3492 // but it couldn't get applied as the
3493 // widget hasn't been realized yet.
3494 m_delayedForegroundColour = TRUE;
3495 }
3496
3497 ApplyWidgetStyle();
3498
3499 return TRUE;
3500 }
3501
3502 GtkStyle *wxWindowGTK::GetWidgetStyle()
3503 {
3504 if (m_widgetStyle)
3505 {
3506 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3507 #ifdef __WXGTK20__
3508 /* FIXME: is this necessary? */
3509 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3510 #else
3511 remake->klass = m_widgetStyle->klass;
3512 #endif
3513
3514 gtk_style_unref( m_widgetStyle );
3515 m_widgetStyle = remake;
3516 }
3517 else
3518 {
3519 GtkStyle *def = gtk_rc_get_style( m_widget );
3520
3521 if (!def)
3522 def = gtk_widget_get_default_style();
3523
3524 m_widgetStyle = gtk_style_copy( def );
3525 #ifdef __WXGTK20__
3526 /* FIXME: is this necessary? */
3527 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3528 #else
3529 m_widgetStyle->klass = def->klass;
3530 #endif
3531 }
3532
3533 return m_widgetStyle;
3534 }
3535
3536 void wxWindowGTK::SetWidgetStyle()
3537 {
3538 #if DISABLE_STYLE_IF_BROKEN_THEM
3539 if (m_widget->style->engine_data)
3540 {
3541 static bool s_warningPrinted = FALSE;
3542 if (!s_warningPrinted)
3543 {
3544 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3545 s_warningPrinted = TRUE;
3546 }
3547 m_widgetStyle = m_widget->style;
3548 return;
3549 }
3550 #endif
3551
3552 GtkStyle *style = GetWidgetStyle();
3553
3554 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3555 {
3556 gdk_font_unref( style->font );
3557 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3558 }
3559
3560 if (m_foregroundColour.Ok())
3561 {
3562 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3563 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3564 {
3565 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3566 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3567 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3568 }
3569 else
3570 {
3571 // Try to restore the gtk default style. This is still a little
3572 // oversimplified for what is probably really needed here for controls
3573 // other than buttons, but is better than not being able to (re)set a
3574 // control's foreground colour to *wxBLACK -- RL
3575 GtkStyle *def = gtk_rc_get_style( m_widget );
3576
3577 if (!def)
3578 def = gtk_widget_get_default_style();
3579
3580 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3581 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3582 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3583 }
3584 }
3585
3586 if (m_backgroundColour.Ok())
3587 {
3588 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3589 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3590 {
3591 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3592 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3593 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3594 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3595 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3596 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3597 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3598 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3599 }
3600 else
3601 {
3602 // Try to restore the gtk default style. This is still a little
3603 // oversimplified for what is probably really needed here for controls
3604 // other than buttons, but is better than not being able to (re)set a
3605 // control's background colour to default grey and means resetting a
3606 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3607 // behavior -- RL
3608 GtkStyle *def = gtk_rc_get_style( m_widget );
3609
3610 if (!def)
3611 def = gtk_widget_get_default_style();
3612
3613 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3614 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3615 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3616 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3617 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3618 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3619 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3620 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3621 }
3622 }
3623 }
3624
3625 void wxWindowGTK::ApplyWidgetStyle()
3626 {
3627 }
3628
3629 //-----------------------------------------------------------------------------
3630 // Pop-up menu stuff
3631 //-----------------------------------------------------------------------------
3632
3633 #if wxUSE_MENUS_NATIVE
3634
3635 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3636 {
3637 *is_waiting = FALSE;
3638 }
3639
3640 static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
3641 {
3642 menu->SetInvokingWindow( win );
3643 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3644 while (node)
3645 {
3646 wxMenuItem *menuitem = node->GetData();
3647 if (menuitem->IsSubMenu())
3648 {
3649 SetInvokingWindow( menuitem->GetSubMenu(), win );
3650 }
3651
3652 node = node->GetNext();
3653 }
3654 }
3655
3656 static gint gs_pop_x = 0;
3657 static gint gs_pop_y = 0;
3658
3659 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3660 gint *x, gint *y,
3661 wxWindowGTK *win )
3662 {
3663 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3664 *x = gs_pop_x;
3665 *y = gs_pop_y;
3666 }
3667
3668 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
3669 {
3670 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3671
3672 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3673
3674 SetInvokingWindow( menu, this );
3675
3676 menu->UpdateUI();
3677
3678 gs_pop_x = x;
3679 gs_pop_y = y;
3680
3681 bool is_waiting = TRUE;
3682
3683 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3684 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3685
3686 gtk_menu_popup(
3687 GTK_MENU(menu->m_menu),
3688 (GtkWidget *) NULL, // parent menu shell
3689 (GtkWidget *) NULL, // parent menu item
3690 (GtkMenuPositionFunc) pop_pos_callback,
3691 (gpointer) this, // client data
3692 0, // button used to activate it
3693 gs_timeLastClick // the time of activation
3694 );
3695
3696 while (is_waiting)
3697 {
3698 while (gtk_events_pending())
3699 gtk_main_iteration();
3700 }
3701
3702 return TRUE;
3703 }
3704
3705 #endif // wxUSE_MENUS_NATIVE
3706
3707 #if wxUSE_DRAG_AND_DROP
3708
3709 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
3710 {
3711 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3712
3713 GtkWidget *dnd_widget = GetConnectWidget();
3714
3715 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3716
3717 if (m_dropTarget) delete m_dropTarget;
3718 m_dropTarget = dropTarget;
3719
3720 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3721 }
3722
3723 #endif // wxUSE_DRAG_AND_DROP
3724
3725 GtkWidget* wxWindowGTK::GetConnectWidget()
3726 {
3727 GtkWidget *connect_widget = m_widget;
3728 if (m_wxwindow) connect_widget = m_wxwindow;
3729
3730 return connect_widget;
3731 }
3732
3733 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
3734 {
3735 if (m_wxwindow)
3736 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3737
3738 return (window == m_widget->window);
3739 }
3740
3741 bool wxWindowGTK::SetFont( const wxFont &font )
3742 {
3743 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3744
3745 if (!wxWindowBase::SetFont(font))
3746 {
3747 return FALSE;
3748 }
3749
3750 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3751 if ( sysbg == m_backgroundColour )
3752 {
3753 m_backgroundColour = wxNullColour;
3754 ApplyWidgetStyle();
3755 m_backgroundColour = sysbg;
3756 }
3757 else
3758 {
3759 ApplyWidgetStyle();
3760 }
3761
3762 return TRUE;
3763 }
3764
3765 void wxWindowGTK::CaptureMouse()
3766 {
3767 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3768
3769 GdkWindow *window = (GdkWindow*) NULL;
3770 if (m_wxwindow)
3771 window = GTK_PIZZA(m_wxwindow)->bin_window;
3772 else
3773 window = GetConnectWidget()->window;
3774
3775 wxCHECK_RET( window, _T("CaptureMouse() failed") );
3776
3777 wxCursor* cursor = & m_cursor;
3778 if (!cursor->Ok())
3779 cursor = wxSTANDARD_CURSOR;
3780
3781 gdk_pointer_grab( window, FALSE,
3782 (GdkEventMask)
3783 (GDK_BUTTON_PRESS_MASK |
3784 GDK_BUTTON_RELEASE_MASK |
3785 GDK_POINTER_MOTION_HINT_MASK |
3786 GDK_POINTER_MOTION_MASK),
3787 (GdkWindow *) NULL,
3788 cursor->GetCursor(),
3789 (guint32)GDK_CURRENT_TIME );
3790 g_captureWindow = this;
3791 g_captureWindowHasMouse = TRUE;
3792 }
3793
3794 void wxWindowGTK::ReleaseMouse()
3795 {
3796 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3797
3798 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
3799
3800 GdkWindow *window = (GdkWindow*) NULL;
3801 if (m_wxwindow)
3802 window = GTK_PIZZA(m_wxwindow)->bin_window;
3803 else
3804 window = GetConnectWidget()->window;
3805
3806 if (!window)
3807 return;
3808
3809 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3810 g_captureWindow = (wxWindowGTK*) NULL;
3811 }
3812
3813 /* static */
3814 wxWindow *wxWindowBase::GetCapture()
3815 {
3816 return (wxWindow *)g_captureWindow;
3817 }
3818
3819 bool wxWindowGTK::IsRetained() const
3820 {
3821 return FALSE;
3822 }
3823
3824 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
3825 int range, bool refresh )
3826 {
3827 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3828
3829 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3830
3831 m_hasScrolling = TRUE;
3832
3833 if (orient == wxHORIZONTAL)
3834 {
3835 float fpos = (float)pos;
3836 float frange = (float)range;
3837 float fthumb = (float)thumbVisible;
3838 if (fpos > frange-fthumb) fpos = frange-fthumb;
3839 if (fpos < 0.0) fpos = 0.0;
3840
3841 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3842 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3843 {
3844 SetScrollPos( orient, pos, refresh );
3845 return;
3846 }
3847
3848 m_oldHorizontalPos = fpos;
3849
3850 m_hAdjust->lower = 0.0;
3851 m_hAdjust->upper = frange;
3852 m_hAdjust->value = fpos;
3853 m_hAdjust->step_increment = 1.0;
3854 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3855 m_hAdjust->page_size = fthumb;
3856 }
3857 else
3858 {
3859 float fpos = (float)pos;
3860 float frange = (float)range;
3861 float fthumb = (float)thumbVisible;
3862 if (fpos > frange-fthumb) fpos = frange-fthumb;
3863 if (fpos < 0.0) fpos = 0.0;
3864
3865 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3866 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3867 {
3868 SetScrollPos( orient, pos, refresh );
3869 return;
3870 }
3871
3872 m_oldVerticalPos = fpos;
3873
3874 m_vAdjust->lower = 0.0;
3875 m_vAdjust->upper = frange;
3876 m_vAdjust->value = fpos;
3877 m_vAdjust->step_increment = 1.0;
3878 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3879 m_vAdjust->page_size = fthumb;
3880 }
3881
3882 if (orient == wxHORIZONTAL)
3883 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3884 else
3885 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3886 }
3887
3888 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3889 {
3890 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3891
3892 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3893
3894 if (orient == wxHORIZONTAL)
3895 {
3896 float fpos = (float)pos;
3897 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3898 if (fpos < 0.0) fpos = 0.0;
3899 m_oldHorizontalPos = fpos;
3900
3901 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3902 m_hAdjust->value = fpos;
3903 }
3904 else
3905 {
3906 float fpos = (float)pos;
3907 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3908 if (fpos < 0.0) fpos = 0.0;
3909 m_oldVerticalPos = fpos;
3910
3911 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3912 m_vAdjust->value = fpos;
3913 }
3914
3915 if (m_wxwindow->window)
3916 {
3917 if (orient == wxHORIZONTAL)
3918 {
3919 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3920 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3921
3922 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3923
3924 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3925 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3926 }
3927 else
3928 {
3929 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3930 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3931
3932 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3933
3934 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3935 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3936 }
3937 }
3938 }
3939
3940 int wxWindowGTK::GetScrollThumb( int orient ) const
3941 {
3942 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3943
3944 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3945
3946 if (orient == wxHORIZONTAL)
3947 return (int)(m_hAdjust->page_size+0.5);
3948 else
3949 return (int)(m_vAdjust->page_size+0.5);
3950 }
3951
3952 int wxWindowGTK::GetScrollPos( int orient ) const
3953 {
3954 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3955
3956 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3957
3958 if (orient == wxHORIZONTAL)
3959 return (int)(m_hAdjust->value+0.5);
3960 else
3961 return (int)(m_vAdjust->value+0.5);
3962 }
3963
3964 int wxWindowGTK::GetScrollRange( int orient ) const
3965 {
3966 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3967
3968 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3969
3970 if (orient == wxHORIZONTAL)
3971 return (int)(m_hAdjust->upper+0.5);
3972 else
3973 return (int)(m_vAdjust->upper+0.5);
3974 }
3975
3976 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3977 {
3978 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3979
3980 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3981
3982 if ((dx == 0) && (dy == 0)) return;
3983
3984 m_clipPaintRegion = TRUE;
3985 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3986 m_clipPaintRegion = FALSE;
3987
3988 /*
3989 if (m_children.GetCount() > 0)
3990 {
3991 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3992 }
3993 else
3994 {
3995 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3996
3997 pizza->xoffset -= dx;
3998 pizza->yoffset -= dy;
3999
4000 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
4001 gdk_gc_set_exposures( m_scrollGC, TRUE );
4002
4003 int cw = 0;
4004 int ch = 0;
4005 GetClientSize( &cw, &ch );
4006 int w = cw - abs(dx);
4007 int h = ch - abs(dy);
4008
4009 if ((h < 0) || (w < 0))
4010 {
4011 Refresh();
4012 }
4013 else
4014 {
4015 int s_x = 0;
4016 int s_y = 0;
4017 if (dx < 0) s_x = -dx;
4018 if (dy < 0) s_y = -dy;
4019 int d_x = 0;
4020 int d_y = 0;
4021 if (dx > 0) d_x = dx;
4022 if (dy > 0) d_y = dy;
4023
4024 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
4025 pizza->bin_window, s_x, s_y, w, h );
4026
4027 wxRect rect;
4028 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
4029 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
4030 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
4031 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
4032
4033 Refresh( TRUE, &rect );
4034 }
4035
4036 gdk_gc_unref( m_scrollGC );
4037 }
4038 */
4039 }
4040
4041 // Find the wxWindow at the current mouse position, also returning the mouse
4042 // position.
4043 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4044 {
4045 pt = wxGetMousePosition();
4046 wxWindow* found = wxFindWindowAtPoint(pt);
4047 return found;
4048 }
4049
4050 // Get the current mouse position.
4051 wxPoint wxGetMousePosition()
4052 {
4053 /* This crashes when used within wxHelpContext,
4054 so we have to use the X-specific implementation below.
4055 gint x, y;
4056 GdkModifierType *mask;
4057 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4058
4059 return wxPoint(x, y);
4060 */
4061
4062 int x, y;
4063 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4064 if (!windowAtPtr)
4065 return wxPoint(-999, -999);
4066
4067 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
4068 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4069 Window rootReturn, childReturn;
4070 int rootX, rootY, winX, winY;
4071 unsigned int maskReturn;
4072
4073 XQueryPointer (display,
4074 rootWindow,
4075 &rootReturn,
4076 &childReturn,
4077 &rootX, &rootY, &winX, &winY, &maskReturn);
4078 return wxPoint(rootX, rootY);
4079
4080 }
4081