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