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