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