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