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