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