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