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