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