]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/window.cpp
compilation fix
[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 // if we detect that the app has got/lost the focus, we set this variable to
220 // either TRUE or FALSE and an activate event will be sent during the next
221 // OnIdle() call and it is reset to -1: this value means that we shouldn't
222 // send any activate events at all
223 static int g_sendActivateEvent = -1;
224
225 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
226 the last click here */
227 static guint32 gs_timeLastClick = 0;
228
229 extern bool g_mainThreadLocked;
230
231 //-----------------------------------------------------------------------------
232 // debug
233 //-----------------------------------------------------------------------------
234
235 #ifndef __WXGTK20__
236 #define DISABLE_STYLE_IF_BROKEN_THEME 1
237 #endif
238
239 #ifdef __WXDEBUG__
240
241 #if wxUSE_THREADS
242 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
243 #else
244 # define DEBUG_MAIN_THREAD
245 #endif
246
247 static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
248 GdkEvent *WXUNUSED(event),
249 const wxChar *WXUNUSED(name) )
250 {
251 /*
252 static bool s_done = FALSE;
253 if ( !s_done )
254 {
255 wxLog::AddTraceMask("focus");
256 s_done = TRUE;
257 }
258 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
259 */
260
261 return FALSE;
262 }
263
264 void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
265 {
266 // suppress warnings about gtk_debug_focus_in_callback being unused with
267 // this "if ( 0 )"
268 if ( 0 )
269 {
270 wxString tmp = name;
271 tmp += wxT(" FROM ");
272 tmp += window;
273
274 wxChar *s = new wxChar[tmp.Length()+1];
275
276 wxStrcpy( s, tmp );
277
278 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
279 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
280 }
281 }
282
283 #else
284 #define DEBUG_MAIN_THREAD
285 #endif // Debug
286
287 //-----------------------------------------------------------------------------
288 // missing gdk functions
289 //-----------------------------------------------------------------------------
290
291 void
292 gdk_window_warp_pointer (GdkWindow *window,
293 gint x,
294 gint y)
295 {
296 #ifndef __WXGTK20__
297 GdkWindowPrivate *priv;
298 #endif
299
300 if (!window)
301 window = GDK_ROOT_PARENT();
302
303 #ifdef __WXGTK20__
304 if (!GDK_WINDOW_DESTROYED(window))
305 {
306 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
307 None, /* not source window -> move from anywhere */
308 GDK_WINDOW_XID(window), /* dest window */
309 0, 0, 0, 0, /* not source window -> move from anywhere */
310 x, y );
311 }
312 #else
313 priv = (GdkWindowPrivate*) window;
314
315 if (!priv->destroyed)
316 {
317 XWarpPointer (priv->xdisplay,
318 None, /* not source window -> move from anywhere */
319 priv->xwindow, /* dest window */
320 0, 0, 0, 0, /* not source window -> move from anywhere */
321 x, y );
322 }
323 #endif
324 }
325
326 //-----------------------------------------------------------------------------
327 // idle system
328 //-----------------------------------------------------------------------------
329
330 extern void wxapp_install_idle_handler();
331 extern bool g_isIdle;
332
333 //-----------------------------------------------------------------------------
334 // local code (see below)
335 //-----------------------------------------------------------------------------
336
337 // returns the child of win which currently has focus or NULL if not found
338 //
339 // Note: can't be static, needed by textctrl.cpp.
340 wxWindow *wxFindFocusedChild(wxWindowGTK *win)
341 {
342 wxWindow *winFocus = wxWindowGTK::FindFocus();
343 if ( !winFocus )
344 return (wxWindow *)NULL;
345
346 if ( winFocus == win )
347 return (wxWindow *)win;
348
349 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
350 node;
351 node = node->GetNext() )
352 {
353 wxWindow *child = wxFindFocusedChild(node->GetData());
354 if ( child )
355 return child;
356 }
357
358 return (wxWindow *)NULL;
359 }
360
361 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
362 {
363 // wxUniversal widgets draw the borders and scrollbars themselves
364 #ifndef __WXUNIVERSAL__
365 if (!win->m_hasVMT)
366 return;
367
368 int dw = 0;
369 int dh = 0;
370
371 if (win->m_hasScrolling)
372 {
373 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
374
375 GtkRequisition vscroll_req;
376 vscroll_req.width = 2;
377 vscroll_req.height = 2;
378 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
379 (scroll_window->vscrollbar, &vscroll_req );
380
381 GtkRequisition hscroll_req;
382 hscroll_req.width = 2;
383 hscroll_req.height = 2;
384 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
385 (scroll_window->hscrollbar, &hscroll_req );
386
387 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
388
389 if (scroll_window->vscrollbar_visible)
390 {
391 dw += vscroll_req.width;
392 dw += scroll_class->scrollbar_spacing;
393 }
394
395 if (scroll_window->hscrollbar_visible)
396 {
397 dh += hscroll_req.height;
398 dh += scroll_class->scrollbar_spacing;
399 }
400 }
401
402 int dx = 0;
403 int dy = 0;
404 if (GTK_WIDGET_NO_WINDOW (widget))
405 {
406 dx += widget->allocation.x;
407 dy += widget->allocation.y;
408 }
409
410 if (win->HasFlag(wxRAISED_BORDER))
411 {
412 gtk_draw_shadow( widget->style,
413 widget->window,
414 GTK_STATE_NORMAL,
415 GTK_SHADOW_OUT,
416 dx, dy,
417 widget->allocation.width-dw, widget->allocation.height-dh );
418 return;
419 }
420
421 if (win->HasFlag(wxSUNKEN_BORDER))
422 {
423 gtk_draw_shadow( widget->style,
424 widget->window,
425 GTK_STATE_NORMAL,
426 GTK_SHADOW_IN,
427 dx, dy,
428 widget->allocation.width-dw, widget->allocation.height-dh );
429 return;
430 }
431
432 if (win->HasFlag(wxSIMPLE_BORDER))
433 {
434 GdkGC *gc;
435 gc = gdk_gc_new( widget->window );
436 gdk_gc_set_foreground( gc, &widget->style->black );
437 gdk_draw_rectangle( widget->window, gc, FALSE,
438 dx, dy,
439 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
440 gdk_gc_unref( gc );
441 return;
442 }
443 #endif // __WXUNIVERSAL__
444 }
445
446 //-----------------------------------------------------------------------------
447 // "expose_event" of m_widget
448 //-----------------------------------------------------------------------------
449
450 gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
451 {
452 if (gdk_event->count > 0) return FALSE;
453
454 draw_frame( widget, win );
455
456 return TRUE;
457 }
458
459 //-----------------------------------------------------------------------------
460 // "draw" of m_widget
461 //-----------------------------------------------------------------------------
462
463 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
464 {
465 draw_frame( widget, win );
466 }
467
468 //-----------------------------------------------------------------------------
469 // key code mapping routines
470 //-----------------------------------------------------------------------------
471
472 static long map_to_unmodified_wx_keysym( GdkEventKey *event )
473 {
474 KeySym keysym = event->keyval;
475 guint key_code = 0;
476
477 switch (keysym)
478 {
479 case GDK_Shift_L:
480 case GDK_Shift_R: key_code = WXK_SHIFT; break;
481 case GDK_Control_L:
482 case GDK_Control_R: key_code = WXK_CONTROL; break;
483 case GDK_Meta_L:
484 case GDK_Meta_R:
485 case GDK_Alt_L:
486 case GDK_Alt_R:
487 case GDK_Super_L:
488 case GDK_Super_R: key_code = WXK_ALT; break;
489 case GDK_Menu: key_code = WXK_MENU; break;
490 case GDK_Help: key_code = WXK_HELP; break;
491 case GDK_BackSpace: key_code = WXK_BACK; break;
492 case GDK_ISO_Left_Tab:
493 case GDK_Tab: key_code = WXK_TAB; break;
494 case GDK_Linefeed: key_code = WXK_RETURN; break;
495 case GDK_Clear: key_code = WXK_CLEAR; break;
496 case GDK_Return: key_code = WXK_RETURN; break;
497 case GDK_Pause: key_code = WXK_PAUSE; break;
498 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
499 case GDK_Escape: key_code = WXK_ESCAPE; break;
500 case GDK_Delete: key_code = WXK_DELETE; break;
501 case GDK_Home: key_code = WXK_HOME; break;
502 case GDK_Left: key_code = WXK_LEFT; break;
503 case GDK_Up: key_code = WXK_UP; break;
504 case GDK_Right: key_code = WXK_RIGHT; break;
505 case GDK_Down: key_code = WXK_DOWN; break;
506 case GDK_Prior: key_code = WXK_PRIOR; break;
507 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
508 case GDK_Next: key_code = WXK_NEXT; break;
509 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
510 case GDK_End: key_code = WXK_END; break;
511 case GDK_Begin: key_code = WXK_HOME; break;
512 case GDK_Select: key_code = WXK_SELECT; break;
513 case GDK_Print: key_code = WXK_PRINT; break;
514 case GDK_Execute: key_code = WXK_EXECUTE; break;
515 case GDK_Insert: key_code = WXK_INSERT; break;
516 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
517
518 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
519 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
520 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
521 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
522 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
523 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
524 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
525 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
526 case GDK_KP_8: key_code = WXK_NUMPAD8; break;
527 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
528 case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
529 case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
530 case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
531 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
532 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
533 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
534 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
535 case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
536 case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
537 case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
538 case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
539 case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
540 case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
541 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
542 case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
543 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
544 case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
545 case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
546 case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
547 case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
548 case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
549 case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
550 case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
551 case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
552 case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
553 case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
554 case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break;
555
556 case GDK_F1: key_code = WXK_F1; break;
557 case GDK_F2: key_code = WXK_F2; break;
558 case GDK_F3: key_code = WXK_F3; break;
559 case GDK_F4: key_code = WXK_F4; break;
560 case GDK_F5: key_code = WXK_F5; break;
561 case GDK_F6: key_code = WXK_F6; break;
562 case GDK_F7: key_code = WXK_F7; break;
563 case GDK_F8: key_code = WXK_F8; break;
564 case GDK_F9: key_code = WXK_F9; break;
565 case GDK_F10: key_code = WXK_F10; break;
566 case GDK_F11: key_code = WXK_F11; break;
567 case GDK_F12: key_code = WXK_F12; break;
568 default:
569 {
570 if (event->length == 1)
571 {
572 key_code = toupper( (unsigned char)*event->string );
573 }
574 else if ((keysym & 0xFF) == keysym)
575 {
576 guint upper = gdk_keyval_to_upper( (guint)keysym );
577 keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */
578 key_code = (guint)keysym;
579 }
580 }
581 }
582
583 return (key_code);
584 }
585
586 static long map_to_wx_keysym( GdkEventKey *event )
587 {
588 KeySym keysym = event->keyval;
589 guint key_code = 0;
590
591 switch (keysym)
592 {
593 case GDK_Menu: key_code = WXK_MENU; break;
594 case GDK_Help: key_code = WXK_HELP; break;
595 case GDK_BackSpace: key_code = WXK_BACK; break;
596 case GDK_ISO_Left_Tab:
597 case GDK_Tab: key_code = WXK_TAB; break;
598 case GDK_Linefeed: key_code = WXK_RETURN; break;
599 case GDK_Clear: key_code = WXK_CLEAR; break;
600 case GDK_Return: key_code = WXK_RETURN; break;
601 case GDK_Pause: key_code = WXK_PAUSE; break;
602 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
603 case GDK_Escape: key_code = WXK_ESCAPE; break;
604 case GDK_Delete: key_code = WXK_DELETE; break;
605 case GDK_Home: key_code = WXK_HOME; break;
606 case GDK_Left: key_code = WXK_LEFT; break;
607 case GDK_Up: key_code = WXK_UP; break;
608 case GDK_Right: key_code = WXK_RIGHT; break;
609 case GDK_Down: key_code = WXK_DOWN; break;
610 case GDK_Prior: key_code = WXK_PRIOR; break;
611 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
612 case GDK_Next: key_code = WXK_NEXT; break;
613 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
614 case GDK_End: key_code = WXK_END; break;
615 case GDK_Begin: key_code = WXK_HOME; break;
616 case GDK_Select: key_code = WXK_SELECT; break;
617 case GDK_Print: key_code = WXK_PRINT; break;
618 case GDK_Execute: key_code = WXK_EXECUTE; break;
619 case GDK_Insert: key_code = WXK_INSERT; break;
620 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
621
622 case GDK_KP_0: key_code = '0'; break;
623 case GDK_KP_1: key_code = '1'; break;
624 case GDK_KP_2: key_code = '2'; break;
625 case GDK_KP_3: key_code = '3'; break;
626 case GDK_KP_4: key_code = '4'; break;
627 case GDK_KP_5: key_code = '5'; break;
628 case GDK_KP_6: key_code = '6'; break;
629 case GDK_KP_7: key_code = '7'; break;
630 case GDK_KP_8: key_code = '8'; break;
631 case GDK_KP_9: key_code = '9'; break;
632 case GDK_KP_Space: key_code = ' '; break;
633 case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
634 case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
635 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
636 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
637 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
638 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
639 case GDK_KP_Home: key_code = WXK_HOME; break;
640 case GDK_KP_Left: key_code = WXK_LEFT; break;
641 case GDK_KP_Up: key_code = WXK_UP; break;
642 case GDK_KP_Right: key_code = WXK_RIGHT; break;
643 case GDK_KP_Down: key_code = WXK_DOWN; break;
644 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
645 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
646 case GDK_KP_Next: key_code = WXK_NEXT; break;
647 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
648 case GDK_KP_End: key_code = WXK_END; break;
649 case GDK_KP_Begin: key_code = WXK_HOME; break;
650 case GDK_KP_Insert: key_code = WXK_INSERT; break;
651 case GDK_KP_Delete: key_code = WXK_DELETE; break;
652 case GDK_KP_Equal: key_code = '='; break;
653 case GDK_KP_Multiply: key_code = '*'; break;
654 case GDK_KP_Add: key_code = '+'; break;
655 case GDK_KP_Separator: key_code = ','; break;
656 case GDK_KP_Subtract: key_code = '-'; break;
657 case GDK_KP_Decimal: key_code = '.'; break;
658 case GDK_KP_Divide: key_code = '/'; break;
659
660 case GDK_F1: key_code = WXK_F1; break;
661 case GDK_F2: key_code = WXK_F2; break;
662 case GDK_F3: key_code = WXK_F3; break;
663 case GDK_F4: key_code = WXK_F4; break;
664 case GDK_F5: key_code = WXK_F5; break;
665 case GDK_F6: key_code = WXK_F6; break;
666 case GDK_F7: key_code = WXK_F7; break;
667 case GDK_F8: key_code = WXK_F8; break;
668 case GDK_F9: key_code = WXK_F9; break;
669 case GDK_F10: key_code = WXK_F10; break;
670 case GDK_F11: key_code = WXK_F11; break;
671 case GDK_F12: key_code = WXK_F12; break;
672 default:
673 {
674 if (event->length == 1)
675 {
676 key_code = (unsigned char)*event->string;
677 }
678 else if ((keysym & 0xFF) == keysym)
679 {
680 key_code = (guint)keysym;
681 }
682 }
683 }
684
685 return (key_code);
686 }
687
688 //-----------------------------------------------------------------------------
689 // "size_request" of m_widget
690 //-----------------------------------------------------------------------------
691
692 static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win )
693 {
694 int w,h;
695 win->GetSize( &w, &h );
696 if (w < 2) w = 2;
697 if (h < 2) h = 2;
698
699 requisition->height = h;
700 requisition->width = w;
701 }
702
703 //-----------------------------------------------------------------------------
704 // "expose_event" of m_wxwindow
705 //-----------------------------------------------------------------------------
706
707 static int gtk_window_expose_callback( GtkWidget *widget,
708 GdkEventExpose *gdk_event,
709 wxWindow *win )
710 {
711 DEBUG_MAIN_THREAD
712
713 if (g_isIdle)
714 wxapp_install_idle_handler();
715
716 /*
717 if (win->GetName() == wxT("panel"))
718 {
719 wxPrintf( wxT("OnExpose from ") );
720 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
721 wxPrintf( win->GetClassInfo()->GetClassName() );
722 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
723 (int)gdk_event->area.y,
724 (int)gdk_event->area.width,
725 (int)gdk_event->area.height );
726 }
727 */
728
729 GtkPizza *pizza = GTK_PIZZA (widget);
730
731 if (win->GetThemeEnabled())
732 {
733 wxWindow *parent = win->GetParent();
734 while (parent && !parent->IsTopLevel())
735 parent = parent->GetParent();
736 if (!parent)
737 parent = win;
738
739 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
740 GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
741 }
742
743 win->GetUpdateRegion().Union( gdk_event->area.x,
744 gdk_event->area.y,
745 gdk_event->area.width,
746 gdk_event->area.height );
747
748 if (gdk_event->count == 0)
749 {
750 win->m_clipPaintRegion = TRUE;
751
752 wxWindowDC dc(win);
753 dc.SetClippingRegion(win->GetUpdateRegion());
754 wxEraseEvent eevent( win->GetId(), &dc );
755 eevent.SetEventObject( win );
756 #if 1
757 (void)win->GetEventHandler()->ProcessEvent(eevent);
758 #else // 0
759 if (!win->GetEventHandler()->ProcessEvent(eevent))
760 {
761 wxClientDC dc( win );
762 dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
763 dc.SetPen( *wxTRANSPARENT_PEN );
764
765 wxRegionIterator upd( win->GetUpdateRegion() );
766 while (upd)
767 {
768 dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
769 upd ++;
770 }
771 }
772 #endif // 1/0
773
774 wxNcPaintEvent eventNc( win->GetId() );
775 eventNc.SetEventObject( win );
776 win->GetEventHandler()->ProcessEvent( eventNc );
777
778 wxPaintEvent event( win->GetId() );
779 event.SetEventObject( win );
780 win->GetEventHandler()->ProcessEvent( event );
781
782 win->GetUpdateRegion().Clear();
783
784 win->m_clipPaintRegion = FALSE;
785 }
786
787 /* The following code will result in all window-less widgets
788 being redrawn if the wxWindows class is given a chance to
789 paint *anything* because it will then be allowed to paint
790 over the window-less widgets */
791 GList *children = pizza->children;
792 while (children)
793 {
794 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
795 children = children->next;
796
797 GdkEventExpose child_event = *gdk_event;
798
799 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
800 GTK_WIDGET_DRAWABLE (child->widget) /* &&
801 gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ )
802 {
803 child_event.area.x = child->widget->allocation.x;
804 child_event.area.y = child->widget->allocation.y;
805 child_event.area.width = child->widget->allocation.width;
806 child_event.area.height = child->widget->allocation.height;
807 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
808 }
809 }
810
811 return TRUE;
812 }
813
814 //-----------------------------------------------------------------------------
815 // "event" of m_wxwindow
816 //-----------------------------------------------------------------------------
817
818 /* GTK thinks it is clever and filters out a certain amount of "unneeded"
819 expose events. We need them, of course, so we override the main event
820 procedure in GtkWidget by giving our own handler for all system events.
821 There, we look for expose events ourselves whereas all other events are
822 handled normally. */
823
824 gint gtk_window_event_event_callback( GtkWidget *widget,
825 GdkEventExpose *event,
826 wxWindow *win )
827 {
828 if (event->type == GDK_EXPOSE)
829 {
830 gint ret = gtk_window_expose_callback( widget, event, win );
831 return ret;
832 }
833
834 return FALSE;
835 }
836
837 //-----------------------------------------------------------------------------
838 // "draw" of m_wxwindow
839 //-----------------------------------------------------------------------------
840
841 /* This callback is a complete replacement of the gtk_pizza_draw() function,
842 which disabled. */
843
844 static void gtk_window_draw_callback( GtkWidget *widget,
845 GdkRectangle *rect,
846 wxWindow *win )
847 {
848 DEBUG_MAIN_THREAD
849
850 if (g_isIdle)
851 wxapp_install_idle_handler();
852
853 if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
854 (win->GetChildren().GetCount() == 0))
855 {
856 return;
857 }
858
859 /*
860 if (win->GetName() == wxT("panel"))
861 {
862 wxPrintf( wxT("OnDraw from ") );
863 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
864 wxPrintf( win->GetClassInfo()->GetClassName() );
865 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
866 (int)rect->y,
867 (int)rect->width,
868 (int)rect->height );
869 }
870 */
871
872 GtkPizza *pizza = GTK_PIZZA (widget);
873
874 if (win->GetThemeEnabled())
875 {
876 wxWindow *parent = win->GetParent();
877 while (parent && !parent->IsTopLevel())
878 parent = parent->GetParent();
879 if (!parent)
880 parent = win;
881
882 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
883 GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
884 }
885
886
887 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
888 (pizza->clear_on_draw))
889 {
890 gdk_window_clear_area( pizza->bin_window,
891 rect->x, rect->y, rect->width, rect->height);
892 }
893
894 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
895
896 win->m_clipPaintRegion = TRUE;
897
898 wxWindowDC dc(win);
899 dc.SetClippingRegion(win->GetUpdateRegion());
900 wxEraseEvent eevent( win->GetId(), &dc );
901 eevent.SetEventObject( win );
902
903 #if 1
904 (void)win->GetEventHandler()->ProcessEvent(eevent);
905 #else
906 if (!win->GetEventHandler()->ProcessEvent(eevent))
907 {
908 if (!win->GetEventHandler()->ProcessEvent(eevent))
909 {
910 wxClientDC dc( win );
911 dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
912 dc.SetPen( *wxTRANSPARENT_PEN );
913
914 wxRegionIterator upd( win->GetUpdateRegion() );
915 while (upd)
916 {
917 dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
918 upd ++;
919 }
920 }
921 }
922 #endif
923
924 wxNcPaintEvent eventNc( win->GetId() );
925 eventNc.SetEventObject( win );
926 win->GetEventHandler()->ProcessEvent( eventNc );
927
928 wxPaintEvent event( win->GetId() );
929 event.SetEventObject( win );
930 win->GetEventHandler()->ProcessEvent( event );
931
932 win->GetUpdateRegion().Clear();
933
934 win->m_clipPaintRegion = FALSE;
935
936
937 GList *children = pizza->children;
938 while (children)
939 {
940 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
941 children = children->next;
942
943 GdkRectangle child_area;
944 if (gtk_widget_intersect (child->widget, rect, &child_area))
945 {
946 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
947 }
948 }
949 }
950
951 //-----------------------------------------------------------------------------
952 // "key_press_event" from any window
953 //-----------------------------------------------------------------------------
954
955 static gint gtk_window_key_press_callback( GtkWidget *widget,
956 GdkEventKey *gdk_event,
957 wxWindow *win )
958 {
959 DEBUG_MAIN_THREAD
960
961 if (g_isIdle)
962 wxapp_install_idle_handler();
963
964 if (!win->m_hasVMT) return FALSE;
965 if (g_blockEventsOnDrag) return FALSE;
966
967
968 /*
969 wxString tmp;
970 tmp += (char)gdk_event->keyval;
971 printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
972 printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
973 */
974
975 int x = 0;
976 int y = 0;
977 GdkModifierType state;
978 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
979
980 bool ret = FALSE;
981
982 long key_code = map_to_unmodified_wx_keysym( gdk_event );
983 /* sending unknown key events doesn't really make sense */
984 if (key_code == 0) return FALSE;
985
986 wxKeyEvent event( wxEVT_KEY_DOWN );
987 event.SetTimestamp( gdk_event->time );
988 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
989 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
990 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
991 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
992 event.m_keyCode = key_code;
993 event.m_scanCode = gdk_event->keyval;
994 event.m_x = x;
995 event.m_y = y;
996 event.SetEventObject( win );
997 ret = win->GetEventHandler()->ProcessEvent( event );
998
999 #if wxUSE_ACCEL
1000 if (!ret)
1001 {
1002 wxWindowGTK *ancestor = win;
1003 while (ancestor)
1004 {
1005 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1006 if (command != -1)
1007 {
1008 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1009 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
1010 break;
1011 }
1012 if (ancestor->IsTopLevel())
1013 break;
1014 ancestor = ancestor->GetParent();
1015 }
1016 }
1017 #endif // wxUSE_ACCEL
1018
1019 /* wxMSW doesn't send char events with Alt pressed */
1020 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1021 will only be sent if it is not in an accelerator table. */
1022 key_code = map_to_wx_keysym( gdk_event );
1023
1024 if ( (!ret) &&
1025 (key_code != 0))
1026 {
1027 wxKeyEvent event2( wxEVT_CHAR );
1028 event2.SetTimestamp( gdk_event->time );
1029 event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1030 event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1031 event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1032 event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1033 event2.m_keyCode = key_code;
1034 event2.m_scanCode = gdk_event->keyval;
1035 event2.m_x = x;
1036 event2.m_y = y;
1037 event2.SetEventObject( win );
1038 ret = win->GetEventHandler()->ProcessEvent( event2 );
1039 }
1040
1041 /* win is a control: tab can be propagated up */
1042 if ( (!ret) &&
1043 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1044 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1045 // have this style, yet choose not to process this particular TAB in which
1046 // case TAB must still work as a navigational character
1047 #if 0
1048 (!win->HasFlag(wxTE_PROCESS_TAB)) &&
1049 #endif // 0
1050 (win->GetParent()) &&
1051 (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1052 {
1053 wxNavigationKeyEvent new_event;
1054 new_event.SetEventObject( win->GetParent() );
1055 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1056 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1057 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1058 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1059 new_event.SetCurrentFocus( win );
1060 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1061 }
1062
1063 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1064 if ( (!ret) &&
1065 (gdk_event->keyval == GDK_Escape) )
1066 {
1067 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
1068 new_event.SetEventObject( win );
1069 ret = win->GetEventHandler()->ProcessEvent( new_event );
1070 }
1071
1072 #if (GTK_MINOR_VERSION > 0)
1073 /* Pressing F10 will activate the menu bar of the top frame. */
1074 /* Doesn't work. */
1075 /*
1076 if ( (!ret) &&
1077 (gdk_event->keyval == GDK_F10) )
1078 {
1079 wxWindowGTK *ancestor = win;
1080 while (ancestor)
1081 {
1082 if (wxIsKindOf(ancestor,wxFrame))
1083 {
1084 wxFrame *frame = (wxFrame*) ancestor;
1085 wxMenuBar *menubar = frame->GetMenuBar();
1086 if (menubar)
1087 {
1088 wxNode *node = menubar->GetMenus().First();
1089 if (node)
1090 {
1091 wxMenu *firstMenu = (wxMenu*) node->Data();
1092 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
1093 ret = TRUE;
1094 break;
1095 }
1096 }
1097 }
1098 ancestor = ancestor->GetParent();
1099 }
1100 }
1101 */
1102 #endif
1103
1104 if (ret)
1105 {
1106 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1107 return TRUE;
1108 }
1109
1110 return FALSE;
1111 }
1112
1113 //-----------------------------------------------------------------------------
1114 // "key_release_event" from any window
1115 //-----------------------------------------------------------------------------
1116
1117 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
1118 {
1119 DEBUG_MAIN_THREAD
1120
1121 if (g_isIdle)
1122 wxapp_install_idle_handler();
1123
1124 if (!win->m_hasVMT) return FALSE;
1125 if (g_blockEventsOnDrag) return FALSE;
1126
1127 /*
1128 printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
1129 if (gdk_event->state & GDK_SHIFT_MASK)
1130 printf( "ShiftDown.\n" );
1131 else
1132 printf( "ShiftUp.\n" );
1133 if (gdk_event->state & GDK_CONTROL_MASK)
1134 printf( "ControlDown.\n" );
1135 else
1136 printf( "ControlUp.\n" );
1137 printf( "\n" );
1138 */
1139
1140 long key_code = map_to_unmodified_wx_keysym( gdk_event );
1141
1142 /* sending unknown key events doesn't really make sense */
1143 if (key_code == 0) return FALSE;
1144
1145 int x = 0;
1146 int y = 0;
1147 GdkModifierType state;
1148 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1149
1150 wxKeyEvent event( wxEVT_KEY_UP );
1151 event.SetTimestamp( gdk_event->time );
1152 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1153 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1154 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1155 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1156 event.m_keyCode = key_code;
1157 event.m_scanCode = gdk_event->keyval;
1158 event.m_x = x;
1159 event.m_y = y;
1160 event.SetEventObject( win );
1161
1162 if (win->GetEventHandler()->ProcessEvent( event ))
1163 {
1164 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1165 return TRUE;
1166 }
1167
1168 return FALSE;
1169 }
1170
1171 // ----------------------------------------------------------------------------
1172 // mouse event processing helper
1173 // ----------------------------------------------------------------------------
1174
1175 static void AdjustEventButtonState(wxMouseEvent& event)
1176 {
1177 // GDK reports the old state of the button for a button press event, but
1178 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1179 // for a LEFT_DOWN event, not FALSE, so we will invert
1180 // left/right/middleDown for the corresponding click events
1181
1182 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1183 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1184 (event.GetEventType() == wxEVT_LEFT_UP))
1185 {
1186 event.m_leftDown = !event.m_leftDown;
1187 return;
1188 }
1189
1190 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1191 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1192 (event.GetEventType() == wxEVT_MIDDLE_UP))
1193 {
1194 event.m_middleDown = !event.m_middleDown;
1195 return;
1196 }
1197
1198 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1199 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1200 (event.GetEventType() == wxEVT_RIGHT_UP))
1201 {
1202 event.m_rightDown = !event.m_rightDown;
1203 return;
1204 }
1205 }
1206
1207 //-----------------------------------------------------------------------------
1208 // "button_press_event"
1209 //-----------------------------------------------------------------------------
1210
1211 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1212 {
1213 DEBUG_MAIN_THREAD
1214
1215 if (g_isIdle)
1216 wxapp_install_idle_handler();
1217
1218 /*
1219 wxPrintf( wxT("1) OnButtonPress from ") );
1220 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1221 wxPrintf( win->GetClassInfo()->GetClassName() );
1222 wxPrintf( wxT(".\n") );
1223 */
1224 if (!win->m_hasVMT) return FALSE;
1225 if (g_blockEventsOnDrag) return TRUE;
1226 if (g_blockEventsOnScroll) return TRUE;
1227
1228 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1229
1230 if (win->m_wxwindow)
1231 {
1232 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
1233 {
1234 gtk_widget_grab_focus (win->m_wxwindow);
1235
1236 /*
1237 wxPrintf( wxT("GrabFocus from ") );
1238 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1239 wxPrintf( win->GetClassInfo()->GetClassName() );
1240 wxPrintf( wxT(".\n") );
1241 */
1242
1243 }
1244 }
1245
1246 wxEventType event_type = wxEVT_NULL;
1247
1248 if (gdk_event->button == 1)
1249 {
1250 switch (gdk_event->type)
1251 {
1252 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1253 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1254 default: break;
1255 }
1256 }
1257 else if (gdk_event->button == 2)
1258 {
1259 switch (gdk_event->type)
1260 {
1261 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1262 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1263 default: break;
1264 }
1265 }
1266 else if (gdk_event->button == 3)
1267 {
1268 switch (gdk_event->type)
1269 {
1270 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1271 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1272 default: break;
1273 }
1274 }
1275
1276 if ( event_type == wxEVT_NULL )
1277 {
1278 // unknown mouse button or click type
1279 return FALSE;
1280 }
1281
1282 wxMouseEvent event( event_type );
1283 event.SetTimestamp( gdk_event->time );
1284 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1285 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1286 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1287 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1288 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1289 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1290 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1291
1292 event.m_x = (wxCoord)gdk_event->x;
1293 event.m_y = (wxCoord)gdk_event->y;
1294
1295 AdjustEventButtonState(event);
1296
1297 // Some control don't have their own X window and thus cannot get
1298 // any events.
1299
1300 if (!g_captureWindow)
1301 {
1302 wxCoord x = event.m_x;
1303 wxCoord y = event.m_y;
1304 if (win->m_wxwindow)
1305 {
1306 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1307 x += pizza->xoffset;
1308 y += pizza->yoffset;
1309 }
1310
1311 wxNode *node = win->GetChildren().First();
1312 while (node)
1313 {
1314 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1315
1316 node = node->Next();
1317 if (!child->IsShown())
1318 continue;
1319
1320 if (child->m_isStaticBox)
1321 {
1322 // wxStaticBox is transparent in the box itself
1323 int xx1 = child->m_x;
1324 int yy1 = child->m_y;
1325 int xx2 = child->m_x + child->m_width;
1326 int yy2 = child->m_x + child->m_height;
1327
1328 // left
1329 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1330 // right
1331 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1332 // top
1333 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1334 // bottom
1335 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1336 {
1337 win = child;
1338 event.m_x -= child->m_x;
1339 event.m_y -= child->m_y;
1340 break;
1341 }
1342
1343 }
1344 else
1345 {
1346 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1347 (child->m_x <= x) &&
1348 (child->m_y <= y) &&
1349 (child->m_x+child->m_width >= x) &&
1350 (child->m_y+child->m_height >= y))
1351 {
1352 win = child;
1353 event.m_x -= child->m_x;
1354 event.m_y -= child->m_y;
1355 break;
1356 }
1357 }
1358 }
1359 }
1360
1361 event.SetEventObject( win );
1362
1363 gs_timeLastClick = gdk_event->time;
1364
1365 /*
1366 wxPrintf( wxT("2) OnButtonPress from ") );
1367 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1368 wxPrintf( win->GetClassInfo()->GetClassName() );
1369 wxPrintf( wxT(".\n") );
1370 */
1371
1372 if (win->GetEventHandler()->ProcessEvent( event ))
1373 {
1374 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1375 return TRUE;
1376 }
1377
1378 return FALSE;
1379 }
1380
1381 //-----------------------------------------------------------------------------
1382 // "button_release_event"
1383 //-----------------------------------------------------------------------------
1384
1385 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1386 {
1387 DEBUG_MAIN_THREAD
1388
1389 if (g_isIdle)
1390 wxapp_install_idle_handler();
1391
1392 if (!win->m_hasVMT) return FALSE;
1393 if (g_blockEventsOnDrag) return FALSE;
1394 if (g_blockEventsOnScroll) return FALSE;
1395
1396 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1397
1398 /*
1399 printf( "OnButtonRelease from " );
1400 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1401 printf( win->GetClassInfo()->GetClassName() );
1402 printf( ".\n" );
1403 */
1404
1405 wxEventType event_type = wxEVT_NULL;
1406
1407 switch (gdk_event->button)
1408 {
1409 case 1: event_type = wxEVT_LEFT_UP; break;
1410 case 2: event_type = wxEVT_MIDDLE_UP; break;
1411 case 3: event_type = wxEVT_RIGHT_UP; break;
1412 default: return FALSE;
1413 }
1414
1415 wxMouseEvent event( event_type );
1416 event.SetTimestamp( gdk_event->time );
1417 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1418 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1419 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1420 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1421 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1422 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1423 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1424 event.m_x = (wxCoord)gdk_event->x;
1425 event.m_y = (wxCoord)gdk_event->y;
1426
1427 AdjustEventButtonState(event);
1428
1429 // Some control don't have their own X window and thus cannot get
1430 // any events.
1431
1432 if (!g_captureWindow)
1433 {
1434 wxCoord x = event.m_x;
1435 wxCoord y = event.m_y;
1436 if (win->m_wxwindow)
1437 {
1438 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1439 x += pizza->xoffset;
1440 y += pizza->yoffset;
1441 }
1442
1443 wxNode *node = win->GetChildren().First();
1444 while (node)
1445 {
1446 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1447
1448 node = node->Next();
1449 if (!child->IsShown())
1450 continue;
1451
1452 if (child->m_isStaticBox)
1453 {
1454 // wxStaticBox is transparent in the box itself
1455 int xx1 = child->m_x;
1456 int yy1 = child->m_y;
1457 int xx2 = child->m_x + child->m_width;
1458 int yy2 = child->m_x + child->m_height;
1459
1460 // left
1461 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1462 // right
1463 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1464 // top
1465 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1466 // bottom
1467 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1468 {
1469 win = child;
1470 event.m_x -= child->m_x;
1471 event.m_y -= child->m_y;
1472 break;
1473 }
1474
1475 }
1476 else
1477 {
1478 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1479 (child->m_x <= x) &&
1480 (child->m_y <= y) &&
1481 (child->m_x+child->m_width >= x) &&
1482 (child->m_y+child->m_height >= y))
1483 {
1484 win = child;
1485 event.m_x -= child->m_x;
1486 event.m_y -= child->m_y;
1487 break;
1488 }
1489 }
1490 }
1491 }
1492
1493 event.SetEventObject( win );
1494
1495 if (win->GetEventHandler()->ProcessEvent( event ))
1496 {
1497 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1498 return TRUE;
1499 }
1500
1501 return FALSE;
1502 }
1503
1504 // ============================================================================
1505 // the mouse events
1506 // ============================================================================
1507
1508 // init wxMouseEvent with the info from gdk_event
1509 #define InitMouseEvent(event, gdk_event) \
1510 event.SetTimestamp( gdk_event->time ); \
1511 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1512 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1513 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1514 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1515 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1516 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1517 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1518 \
1519 event.m_x = (wxCoord)gdk_event->x; \
1520 event.m_y = (wxCoord)gdk_event->y \
1521
1522 //-----------------------------------------------------------------------------
1523 // "motion_notify_event"
1524 //-----------------------------------------------------------------------------
1525
1526 static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1527 GdkEventMotion *gdk_event,
1528 wxWindowGTK *win )
1529 {
1530 DEBUG_MAIN_THREAD
1531
1532 if (g_isIdle)
1533 wxapp_install_idle_handler();
1534
1535 if (!win->m_hasVMT) return FALSE;
1536 if (g_blockEventsOnDrag) return FALSE;
1537 if (g_blockEventsOnScroll) return FALSE;
1538
1539 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1540
1541 if (gdk_event->is_hint)
1542 {
1543 int x = 0;
1544 int y = 0;
1545 GdkModifierType state;
1546 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1547 gdk_event->x = x;
1548 gdk_event->y = y;
1549 }
1550
1551 /*
1552 printf( "OnMotion from " );
1553 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1554 printf( win->GetClassInfo()->GetClassName() );
1555 printf( ".\n" );
1556 */
1557
1558 wxMouseEvent event( wxEVT_MOTION );
1559 InitMouseEvent(event, gdk_event);
1560
1561 if ( g_captureWindow )
1562 {
1563 // synthetize a mouse enter or leave event if needed
1564 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1565 bool hasMouse = winUnderMouse == gdk_event->window;
1566 if ( hasMouse != g_captureWindowHasMouse )
1567 {
1568 // the mouse changed window
1569 g_captureWindowHasMouse = hasMouse;
1570
1571 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1572 : wxEVT_LEAVE_WINDOW);
1573 InitMouseEvent(event, gdk_event);
1574 event.SetEventObject(win);
1575 win->GetEventHandler()->ProcessEvent(event);
1576 }
1577 }
1578 else // no capture
1579 {
1580 // Some control don't have their own X window and thus cannot get
1581 // any events.
1582
1583 wxCoord x = event.m_x;
1584 wxCoord y = event.m_y;
1585 if (win->m_wxwindow)
1586 {
1587 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1588 x += pizza->xoffset;
1589 y += pizza->yoffset;
1590 }
1591
1592 wxNode *node = win->GetChildren().First();
1593 while (node)
1594 {
1595 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1596
1597 node = node->Next();
1598 if (!child->IsShown())
1599 continue;
1600
1601 if (child->m_isStaticBox)
1602 {
1603 // wxStaticBox is transparent in the box itself
1604 int xx1 = child->m_x;
1605 int yy1 = child->m_y;
1606 int xx2 = child->m_x + child->m_width;
1607 int yy2 = child->m_x + child->m_height;
1608
1609 // left
1610 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1611 // right
1612 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1613 // top
1614 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1615 // bottom
1616 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1617 {
1618 win = child;
1619 event.m_x -= child->m_x;
1620 event.m_y -= child->m_y;
1621 break;
1622 }
1623
1624 }
1625 else
1626 {
1627 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1628 (child->m_x <= x) &&
1629 (child->m_y <= y) &&
1630 (child->m_x+child->m_width >= x) &&
1631 (child->m_y+child->m_height >= y))
1632 {
1633 win = child;
1634 event.m_x -= child->m_x;
1635 event.m_y -= child->m_y;
1636 break;
1637 }
1638 }
1639 }
1640 }
1641
1642 event.SetEventObject( win );
1643
1644 if (win->GetEventHandler()->ProcessEvent( event ))
1645 {
1646 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1647 return TRUE;
1648 }
1649
1650 return FALSE;
1651 }
1652
1653 //-----------------------------------------------------------------------------
1654 // "focus_in_event"
1655 //-----------------------------------------------------------------------------
1656
1657 static gint gtk_window_focus_in_callback( GtkWidget *widget,
1658 GdkEvent *WXUNUSED(event),
1659 wxWindow *win )
1660 {
1661 DEBUG_MAIN_THREAD
1662
1663 if (g_isIdle)
1664 wxapp_install_idle_handler();
1665
1666 if (!win->m_hasVMT) return FALSE;
1667 if (g_blockEventsOnDrag) return FALSE;
1668
1669 switch ( g_sendActivateEvent )
1670 {
1671 case -1:
1672 // we've got focus from outside, synthetize wxActivateEvent
1673 g_sendActivateEvent = 1;
1674 break;
1675
1676 case 0:
1677 // another our window just lost focus, it was already ours before
1678 // - don't send any wxActivateEvent
1679 g_sendActivateEvent = -1;
1680 break;
1681 }
1682
1683 g_focusWindowLast =
1684 g_focusWindow = win;
1685
1686 #if 0
1687 wxPrintf( "OnSetFocus from " );
1688 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1689 wxPrintf( win->GetClassInfo()->GetClassName() );
1690 wxPrintf( ".\n" );
1691 #endif
1692
1693 // notify the parent keeping track of focus for the kbd navigation
1694 // purposes that we got it
1695 wxChildFocusEvent eventFocus(win);
1696 (void)win->GetEventHandler()->ProcessEvent(eventFocus);
1697
1698 #ifdef HAVE_XIM
1699 if (win->m_ic)
1700 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1701 #endif
1702
1703 #if wxUSE_CARET
1704 // caret needs to be informed about focus change
1705 wxCaret *caret = win->GetCaret();
1706 if ( caret )
1707 {
1708 caret->OnSetFocus();
1709 }
1710 #endif // wxUSE_CARET
1711
1712 if (win->IsTopLevel())
1713 {
1714 wxActivateEvent event( wxEVT_ACTIVATE, TRUE, win->GetId() );
1715 event.SetEventObject( win );
1716
1717 // ignore return value
1718 win->GetEventHandler()->ProcessEvent( event );
1719 }
1720
1721 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1722 event.SetEventObject( win );
1723
1724 if (win->GetEventHandler()->ProcessEvent( event ))
1725 {
1726 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1727 return TRUE;
1728 }
1729
1730
1731 return FALSE;
1732 }
1733
1734 //-----------------------------------------------------------------------------
1735 // "focus_out_event"
1736 //-----------------------------------------------------------------------------
1737
1738 static GtkWidget *gs_widgetLastFocus = NULL;
1739
1740 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
1741 {
1742 DEBUG_MAIN_THREAD
1743
1744 if (g_isIdle)
1745 wxapp_install_idle_handler();
1746
1747 if (!win->m_hasVMT) return FALSE;
1748 if (g_blockEventsOnDrag) return FALSE;
1749
1750 // VZ: this is really weird but GTK+ seems to call us from inside
1751 // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
1752 // this widget and then "focus_in". This is totally unexpected and
1753 // completely breaks wxUniv code so ignore this dummy event (we can't
1754 // be losing focus if we're about to acquire it!)
1755 if ( widget == gs_widgetLastFocus )
1756 {
1757 gs_widgetLastFocus = NULL;
1758
1759 return FALSE;
1760 }
1761
1762 // if the focus goes out of our app alltogether, OnIdle() will send
1763 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1764 // g_sendActivateEvent to -1
1765 g_sendActivateEvent = 0;
1766
1767 wxWindowGTK *winFocus = wxFindFocusedChild(win);
1768 if ( winFocus )
1769 win = winFocus;
1770
1771 g_focusWindow = (wxWindowGTK *)NULL;
1772
1773 #if 0
1774 wxPrintf( "OnKillFocus from " );
1775 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1776 wxPrintf( win->GetClassInfo()->GetClassName() );
1777 wxPrintf( ".\n" );
1778 #endif
1779
1780 #ifdef HAVE_XIM
1781 if (win->m_ic)
1782 gdk_im_end();
1783 #endif
1784
1785 #if wxUSE_CARET
1786 // caret needs to be informed about focus change
1787 wxCaret *caret = win->GetCaret();
1788 if ( caret )
1789 {
1790 caret->OnKillFocus();
1791 }
1792 #endif // wxUSE_CARET
1793
1794 if (win->IsTopLevel())
1795 {
1796 wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() );
1797 event.SetEventObject( win );
1798
1799 // ignore return value
1800 win->GetEventHandler()->ProcessEvent( event );
1801 }
1802
1803 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1804 event.SetEventObject( win );
1805
1806 if (win->GetEventHandler()->ProcessEvent( event ))
1807 {
1808 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1809 return TRUE;
1810 }
1811
1812 return FALSE;
1813 }
1814
1815 //-----------------------------------------------------------------------------
1816 // "enter_notify_event"
1817 //-----------------------------------------------------------------------------
1818
1819 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1820 {
1821 DEBUG_MAIN_THREAD
1822
1823 if (g_isIdle)
1824 wxapp_install_idle_handler();
1825
1826 if (!win->m_hasVMT) return FALSE;
1827 if (g_blockEventsOnDrag) return FALSE;
1828
1829 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1830
1831 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1832 event.SetTimestamp( gdk_event->time );
1833 event.SetEventObject( win );
1834
1835 int x = 0;
1836 int y = 0;
1837 GdkModifierType state = (GdkModifierType)0;
1838
1839 gdk_window_get_pointer( widget->window, &x, &y, &state );
1840
1841 InitMouseEvent(event, gdk_event);
1842
1843 event.m_x = x;
1844 event.m_y = y;
1845
1846 if (win->GetEventHandler()->ProcessEvent( event ))
1847 {
1848 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1849 return TRUE;
1850 }
1851
1852 return FALSE;
1853 }
1854
1855 //-----------------------------------------------------------------------------
1856 // "leave_notify_event"
1857 //-----------------------------------------------------------------------------
1858
1859 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1860 {
1861 DEBUG_MAIN_THREAD
1862
1863 if (g_isIdle)
1864 wxapp_install_idle_handler();
1865
1866 if (!win->m_hasVMT) return FALSE;
1867 if (g_blockEventsOnDrag) return FALSE;
1868
1869 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1870
1871 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1872 event.SetTimestamp( gdk_event->time );
1873 event.SetEventObject( win );
1874
1875 int x = 0;
1876 int y = 0;
1877 GdkModifierType state = (GdkModifierType)0;
1878
1879 gdk_window_get_pointer( widget->window, &x, &y, &state );
1880
1881 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1882 event.m_controlDown = (state & GDK_CONTROL_MASK);
1883 event.m_altDown = (state & GDK_MOD1_MASK);
1884 event.m_metaDown = (state & GDK_MOD2_MASK);
1885 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1886 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1887 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1888
1889 event.m_x = x;
1890 event.m_y = 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_isFrame = FALSE;
2322 m_acceptsFocus = FALSE;
2323
2324 m_clipPaintRegion = FALSE;
2325
2326 m_cursor = *wxSTANDARD_CURSOR;
2327
2328 m_delayedForegroundColour = FALSE;
2329 m_delayedBackgroundColour = FALSE;
2330
2331 #ifdef HAVE_XIM
2332 m_ic = (GdkIC*) NULL;
2333 m_icattr = (GdkICAttr*) NULL;
2334 #endif
2335 }
2336
2337 wxWindowGTK::wxWindowGTK()
2338 {
2339 Init();
2340 }
2341
2342 wxWindowGTK::wxWindowGTK( wxWindow *parent,
2343 wxWindowID id,
2344 const wxPoint &pos,
2345 const wxSize &size,
2346 long style,
2347 const wxString &name )
2348 {
2349 Init();
2350
2351 Create( parent, id, pos, size, style, name );
2352 }
2353
2354 bool wxWindowGTK::Create( wxWindow *parent,
2355 wxWindowID id,
2356 const wxPoint &pos,
2357 const wxSize &size,
2358 long style,
2359 const wxString &name )
2360 {
2361 if (!PreCreation( parent, pos, size ) ||
2362 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2363 {
2364 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2365 return FALSE;
2366 }
2367
2368 m_insertCallback = wxInsertChildInWindow;
2369
2370 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2371 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2372
2373 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2374
2375 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2376 scroll_class->scrollbar_spacing = 0;
2377
2378 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2379
2380 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2381 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2382
2383 m_wxwindow = gtk_pizza_new();
2384
2385 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2386
2387 #ifndef __WXUNIVERSAL__
2388 #if (GTK_MINOR_VERSION > 0)
2389 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2390
2391 if (HasFlag(wxRAISED_BORDER))
2392 {
2393 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2394 }
2395 else if (HasFlag(wxSUNKEN_BORDER))
2396 {
2397 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2398 }
2399 else if (HasFlag(wxSIMPLE_BORDER))
2400 {
2401 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2402 }
2403 else
2404 {
2405 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2406 }
2407 #else // GTK_MINOR_VERSION == 0
2408 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2409
2410 if (HasFlag(wxRAISED_BORDER))
2411 {
2412 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2413 }
2414 else if (HasFlag(wxSUNKEN_BORDER))
2415 {
2416 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2417 }
2418 else
2419 {
2420 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2421 }
2422 #endif // GTK_MINOR_VERSION
2423 #endif // __WXUNIVERSAL__
2424
2425 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2426 m_acceptsFocus = TRUE;
2427
2428 #if (GTK_MINOR_VERSION == 0)
2429 // shut the viewport up
2430 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2431 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2432 #endif // GTK_MINOR_VERSION == 0
2433
2434 // I _really_ don't want scrollbars in the beginning
2435 m_vAdjust->lower = 0.0;
2436 m_vAdjust->upper = 1.0;
2437 m_vAdjust->value = 0.0;
2438 m_vAdjust->step_increment = 1.0;
2439 m_vAdjust->page_increment = 1.0;
2440 m_vAdjust->page_size = 5.0;
2441 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2442 m_hAdjust->lower = 0.0;
2443 m_hAdjust->upper = 1.0;
2444 m_hAdjust->value = 0.0;
2445 m_hAdjust->step_increment = 1.0;
2446 m_hAdjust->page_increment = 1.0;
2447 m_hAdjust->page_size = 5.0;
2448 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2449
2450 // these handlers block mouse events to any window during scrolling such as
2451 // motion events and prevent GTK and wxWindows from fighting over where the
2452 // slider should be
2453
2454 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2455 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2456
2457 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2458 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2459
2460 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2461 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2462
2463 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2464 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2465
2466 // these handlers get notified when screen updates are required either when
2467 // scrolling or when the window size (and therefore scrollbar configuration)
2468 // has changed
2469
2470 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2471 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2472 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2473 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2474
2475 gtk_widget_show( m_wxwindow );
2476
2477 if (m_parent)
2478 m_parent->DoAddChild( this );
2479
2480 m_focusWidget = m_wxwindow;
2481
2482 PostCreation();
2483
2484 Show( TRUE );
2485
2486 return TRUE;
2487 }
2488
2489 wxWindowGTK::~wxWindowGTK()
2490 {
2491 if (g_focusWindow == this)
2492 g_focusWindow = NULL;
2493
2494 m_isBeingDeleted = TRUE;
2495 m_hasVMT = FALSE;
2496
2497 if (m_widget)
2498 Show( FALSE );
2499
2500 DestroyChildren();
2501
2502 if (m_parent)
2503 m_parent->RemoveChild( this );
2504
2505 #ifdef HAVE_XIM
2506 if (m_ic)
2507 gdk_ic_destroy (m_ic);
2508 if (m_icattr)
2509 gdk_ic_attr_destroy (m_icattr);
2510 #endif
2511
2512 if (m_widgetStyle)
2513 {
2514 #if DISABLE_STYLE_IF_BROKEN_THEME
2515 // don't delete if it's a pixmap theme style
2516 if (!m_widgetStyle->engine_data)
2517 gtk_style_unref( m_widgetStyle );
2518 #endif
2519 m_widgetStyle = (GtkStyle*) NULL;
2520 }
2521
2522 if (m_wxwindow)
2523 {
2524 gtk_widget_destroy( m_wxwindow );
2525 m_wxwindow = (GtkWidget*) NULL;
2526 }
2527
2528 if (m_widget)
2529 {
2530 gtk_widget_destroy( m_widget );
2531 m_widget = (GtkWidget*) NULL;
2532 }
2533 }
2534
2535 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2536 {
2537 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2538
2539 /* this turns -1 into 20 so that a minimal window is
2540 visible even although -1,-1 has been given as the
2541 size of the window. the same trick is used in other
2542 ports and should make debugging easier */
2543 m_width = WidthDefault(size.x);
2544 m_height = HeightDefault(size.y);
2545
2546 m_x = (int)pos.x;
2547 m_y = (int)pos.y;
2548
2549 /* some reasonable defaults */
2550 if (!parent)
2551 {
2552 if (m_x == -1)
2553 {
2554 m_x = (gdk_screen_width () - m_width) / 2;
2555 if (m_x < 10) m_x = 10;
2556 }
2557 if (m_y == -1)
2558 {
2559 m_y = (gdk_screen_height () - m_height) / 2;
2560 if (m_y < 10) m_y = 10;
2561 }
2562 }
2563
2564 return TRUE;
2565 }
2566
2567 void wxWindowGTK::PostCreation()
2568 {
2569 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2570
2571 if (m_wxwindow)
2572 {
2573 if (!m_noExpose)
2574 {
2575 // these get reported to wxWindows -> wxPaintEvent
2576
2577 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2578
2579 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2580 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2581
2582 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2583 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2584
2585 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2586 {
2587 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2588 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2589 }
2590 }
2591
2592 // these are called when the "sunken" or "raised" borders are drawn */
2593 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2594 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2595
2596 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2597 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2598 }
2599
2600 // focus handling
2601
2602 if (m_focusWidget == NULL)
2603 m_focusWidget = m_widget;
2604
2605 #if 0
2606 if (GetClassInfo() && GetClassInfo()->GetClassName())
2607 wxPrintf( GetClassInfo()->GetClassName() );
2608 wxPrintf( ".\n" );
2609 #endif
2610
2611 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2612 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2613
2614 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
2615 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2616
2617 // connect to the various key and mouse handlers
2618
2619 GtkWidget *connect_widget = GetConnectWidget();
2620
2621 ConnectWidget( connect_widget );
2622
2623 /* We cannot set colours, fonts and cursors before the widget has
2624 been realized, so we do this directly after realization */
2625 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2626 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2627
2628 if (m_wxwindow)
2629 {
2630 // Catch native resize events
2631 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2632 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2633
2634 // Initialize XIM support
2635 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2636 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2637
2638 // And resize XIM window
2639 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2640 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2641 }
2642
2643 if (!GTK_IS_COMBO(m_widget))
2644 {
2645 // This is needed if we want to add our windows into native
2646 // GTK control, such as the toolbar. With this callback, the
2647 // toolbar gets to know the correct size (the one set by the
2648 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2649 // when moving to GTK 2.0.
2650 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2651 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2652 }
2653
2654 m_hasVMT = TRUE;
2655 }
2656
2657 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2658 {
2659 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2660 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2661
2662 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2663 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2664
2665 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2666 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2667
2668 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2669 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2670
2671 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2672 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2673
2674 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2675 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2676
2677 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2678 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2679 }
2680
2681 bool wxWindowGTK::Destroy()
2682 {
2683 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2684
2685 m_hasVMT = FALSE;
2686
2687 return wxWindowBase::Destroy();
2688 }
2689
2690 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
2691 {
2692 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2693 }
2694
2695 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2696 {
2697 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2698 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
2699
2700 /*
2701 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2702 */
2703
2704 if (m_resizing) return; /* I don't like recursions */
2705 m_resizing = TRUE;
2706
2707 int currentX, currentY;
2708 GetPosition(&currentX, &currentY);
2709 if (x == -1)
2710 x = currentX;
2711 if (y == -1)
2712 y = currentY;
2713 AdjustForParentClientOrigin(x, y, sizeFlags);
2714
2715 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2716 {
2717 /* don't set the size for children of wxNotebook, just take the values. */
2718 m_x = x;
2719 m_y = y;
2720 m_width = width;
2721 m_height = height;
2722 }
2723 else
2724 {
2725 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2726
2727 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2728 {
2729 if (x != -1) m_x = x + pizza->xoffset;
2730 if (y != -1) m_y = y + pizza->yoffset;
2731 if (width != -1) m_width = width;
2732 if (height != -1) m_height = height;
2733 }
2734 else
2735 {
2736 m_x = x + pizza->xoffset;
2737 m_y = y + pizza->yoffset;
2738 m_width = width;
2739 m_height = height;
2740 }
2741
2742 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2743 {
2744 if (width == -1) m_width = 80;
2745 }
2746
2747 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2748 {
2749 if (height == -1) m_height = 26;
2750 }
2751
2752 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2753 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2754 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2755 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2756
2757 int border = 0;
2758 int bottom_border = 0;
2759
2760 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2761 {
2762 /* the default button has a border around it */
2763 border = 6;
2764 bottom_border = 5;
2765 }
2766
2767 DoMoveWindow( m_x-border,
2768 m_y-border,
2769 m_width+2*border,
2770 m_height+border+bottom_border );
2771 }
2772
2773 if (m_hasScrolling)
2774 {
2775 /* Sometimes the client area changes size without the
2776 whole windows's size changing, but if the whole
2777 windows's size doesn't change, no wxSizeEvent will
2778 normally be sent. Here we add an extra test if
2779 the client test has been changed and this will
2780 be used then. */
2781 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2782 }
2783
2784 /*
2785 wxPrintf( "OnSize sent from " );
2786 if (GetClassInfo() && GetClassInfo()->GetClassName())
2787 wxPrintf( GetClassInfo()->GetClassName() );
2788 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2789 */
2790
2791 if (!m_nativeSizeEvent)
2792 {
2793 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2794 event.SetEventObject( this );
2795 GetEventHandler()->ProcessEvent( event );
2796 }
2797
2798 m_resizing = FALSE;
2799 }
2800
2801 void wxWindowGTK::OnInternalIdle()
2802 {
2803 if ( g_sendActivateEvent != -1 )
2804 {
2805 bool activate = g_sendActivateEvent != 0;
2806
2807 // do it only once
2808 g_sendActivateEvent = -1;
2809
2810 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
2811 }
2812
2813 wxCursor cursor = m_cursor;
2814 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2815
2816 if (cursor.Ok())
2817 {
2818 /* I now set the cursor anew in every OnInternalIdle call
2819 as setting the cursor in a parent window also effects the
2820 windows above so that checking for the current cursor is
2821 not possible. */
2822
2823 if (m_wxwindow)
2824 {
2825 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2826 if (window)
2827 gdk_window_set_cursor( window, cursor.GetCursor() );
2828
2829 if (!g_globalCursor.Ok())
2830 cursor = *wxSTANDARD_CURSOR;
2831
2832 window = m_widget->window;
2833 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2834 gdk_window_set_cursor( window, cursor.GetCursor() );
2835
2836 }
2837 else
2838 {
2839
2840 GdkWindow *window = m_widget->window;
2841 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2842 gdk_window_set_cursor( window, cursor.GetCursor() );
2843
2844 }
2845 }
2846
2847 UpdateWindowUI();
2848 }
2849
2850 void wxWindowGTK::DoGetSize( int *width, int *height ) const
2851 {
2852 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2853
2854 if (width) (*width) = m_width;
2855 if (height) (*height) = m_height;
2856 }
2857
2858 void wxWindowGTK::DoSetClientSize( int width, int height )
2859 {
2860 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2861
2862 if (!m_wxwindow)
2863 {
2864 SetSize( width, height );
2865 }
2866 else
2867 {
2868 int dw = 0;
2869 int dh = 0;
2870
2871 #ifndef __WXUNIVERSAL__
2872 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2873 {
2874 /* when using GTK 1.2 we set the shadow border size to 2 */
2875 dw += 2 * 2;
2876 dh += 2 * 2;
2877 }
2878 if (HasFlag(wxSIMPLE_BORDER))
2879 {
2880 /* when using GTK 1.2 we set the simple border size to 1 */
2881 dw += 1 * 2;
2882 dh += 1 * 2;
2883 }
2884 #endif // __WXUNIVERSAL__
2885
2886 if (m_hasScrolling)
2887 {
2888 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2889
2890 GtkRequisition vscroll_req;
2891 vscroll_req.width = 2;
2892 vscroll_req.height = 2;
2893 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2894 (scroll_window->vscrollbar, &vscroll_req );
2895
2896 GtkRequisition hscroll_req;
2897 hscroll_req.width = 2;
2898 hscroll_req.height = 2;
2899 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2900 (scroll_window->hscrollbar, &hscroll_req );
2901
2902 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2903
2904 if (scroll_window->vscrollbar_visible)
2905 {
2906 dw += vscroll_req.width;
2907 dw += scroll_class->scrollbar_spacing;
2908 }
2909
2910 if (scroll_window->hscrollbar_visible)
2911 {
2912 dh += hscroll_req.height;
2913 dh += scroll_class->scrollbar_spacing;
2914 }
2915 }
2916
2917 SetSize( width+dw, height+dh );
2918 }
2919 }
2920
2921 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
2922 {
2923 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2924
2925 if (!m_wxwindow)
2926 {
2927 if (width) (*width) = m_width;
2928 if (height) (*height) = m_height;
2929 }
2930 else
2931 {
2932 int dw = 0;
2933 int dh = 0;
2934
2935 #ifndef __WXUNIVERSAL__
2936 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2937 {
2938 /* when using GTK 1.2 we set the shadow border size to 2 */
2939 dw += 2 * 2;
2940 dh += 2 * 2;
2941 }
2942 if (HasFlag(wxSIMPLE_BORDER))
2943 {
2944 /* when using GTK 1.2 we set the simple border size to 1 */
2945 dw += 1 * 2;
2946 dh += 1 * 2;
2947 }
2948 #endif // __WXUNIVERSAL__
2949
2950 if (m_hasScrolling)
2951 {
2952 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2953
2954 GtkRequisition vscroll_req;
2955 vscroll_req.width = 2;
2956 vscroll_req.height = 2;
2957 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2958 (scroll_window->vscrollbar, &vscroll_req );
2959
2960 GtkRequisition hscroll_req;
2961 hscroll_req.width = 2;
2962 hscroll_req.height = 2;
2963 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2964 (scroll_window->hscrollbar, &hscroll_req );
2965
2966 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2967
2968 if (scroll_window->vscrollbar_visible)
2969 {
2970 dw += vscroll_req.width;
2971 dw += scroll_class->scrollbar_spacing;
2972 }
2973
2974 if (scroll_window->hscrollbar_visible)
2975 {
2976 dh += hscroll_req.height;
2977 dh += scroll_class->scrollbar_spacing;
2978 }
2979 }
2980
2981 if (width) (*width) = m_width - dw;
2982 if (height) (*height) = m_height - dh;
2983 }
2984
2985 /*
2986 printf( "GetClientSize, name %s ", GetName().c_str() );
2987 if (width) printf( " width = %d", (*width) );
2988 if (height) printf( " height = %d", (*height) );
2989 printf( "\n" );
2990 */
2991 }
2992
2993 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
2994 {
2995 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2996
2997 int dx = 0;
2998 int dy = 0;
2999 if (m_parent && m_parent->m_wxwindow)
3000 {
3001 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3002 dx = pizza->xoffset;
3003 dy = pizza->yoffset;
3004 }
3005
3006 int nx = m_x - dx;
3007 int ny = m_y - dy;
3008
3009 if ( !IsTopLevel() && m_parent )
3010 {
3011 // We may be faking the client origin. So a window that's really at (0,
3012 // 30) may appear (to wxWin apps) to be at (0, 0).
3013 wxPoint pt(m_parent->GetClientAreaOrigin());
3014 nx -= pt.x;
3015 ny -= pt.y;
3016 }
3017
3018 if (x) (*x) = nx;
3019 if (y) (*y) = ny;
3020 }
3021
3022 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3023 {
3024 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3025
3026 if (!m_widget->window) return;
3027
3028 GdkWindow *source = (GdkWindow *) NULL;
3029 if (m_wxwindow)
3030 source = GTK_PIZZA(m_wxwindow)->bin_window;
3031 else
3032 source = m_widget->window;
3033
3034 int org_x = 0;
3035 int org_y = 0;
3036 gdk_window_get_origin( source, &org_x, &org_y );
3037
3038 if (!m_wxwindow)
3039 {
3040 if (GTK_WIDGET_NO_WINDOW (m_widget))
3041 {
3042 org_x += m_widget->allocation.x;
3043 org_y += m_widget->allocation.y;
3044 }
3045 }
3046
3047 if (x) *x += org_x;
3048 if (y) *y += org_y;
3049 }
3050
3051 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3052 {
3053 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3054
3055 if (!m_widget->window) return;
3056
3057 GdkWindow *source = (GdkWindow *) NULL;
3058 if (m_wxwindow)
3059 source = GTK_PIZZA(m_wxwindow)->bin_window;
3060 else
3061 source = m_widget->window;
3062
3063 int org_x = 0;
3064 int org_y = 0;
3065 gdk_window_get_origin( source, &org_x, &org_y );
3066
3067 if (!m_wxwindow)
3068 {
3069 if (GTK_WIDGET_NO_WINDOW (m_widget))
3070 {
3071 org_x += m_widget->allocation.x;
3072 org_y += m_widget->allocation.y;
3073 }
3074 }
3075
3076 if (x) *x -= org_x;
3077 if (y) *y -= org_y;
3078 }
3079
3080 bool wxWindowGTK::Show( bool show )
3081 {
3082 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3083
3084 if (!wxWindowBase::Show(show))
3085 {
3086 // nothing to do
3087 return FALSE;
3088 }
3089
3090 if (show)
3091 gtk_widget_show( m_widget );
3092 else
3093 gtk_widget_hide( m_widget );
3094
3095 return TRUE;
3096 }
3097
3098 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3099 {
3100 win->OnParentEnable(enable);
3101
3102 // Recurse, so that children have the opportunity to Do The Right Thing
3103 // and reset colours that have been messed up by a parent's (really ancestor's)
3104 // Enable call
3105 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
3106 node;
3107 node = node->GetNext() )
3108 {
3109 wxWindow *child = node->GetData();
3110 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3111 wxWindowNotifyEnable(child, enable);
3112 }
3113 }
3114
3115 bool wxWindowGTK::Enable( bool enable )
3116 {
3117 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3118
3119 if (!wxWindowBase::Enable(enable))
3120 {
3121 // nothing to do
3122 return FALSE;
3123 }
3124
3125 gtk_widget_set_sensitive( m_widget, enable );
3126 if ( m_wxwindow )
3127 gtk_widget_set_sensitive( m_wxwindow, enable );
3128
3129 wxWindowNotifyEnable(this, enable);
3130
3131 return TRUE;
3132 }
3133
3134 int wxWindowGTK::GetCharHeight() const
3135 {
3136 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3137
3138 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
3139
3140 GdkFont *font = m_font.GetInternalFont( 1.0 );
3141
3142 return font->ascent + font->descent;
3143 }
3144
3145 int wxWindowGTK::GetCharWidth() const
3146 {
3147 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3148
3149 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
3150
3151 GdkFont *font = m_font.GetInternalFont( 1.0 );
3152
3153 return gdk_string_width( font, "H" );
3154 }
3155
3156 void wxWindowGTK::GetTextExtent( const wxString& string,
3157 int *x,
3158 int *y,
3159 int *descent,
3160 int *externalLeading,
3161 const wxFont *theFont ) const
3162 {
3163 wxFont fontToUse = m_font;
3164 if (theFont) fontToUse = *theFont;
3165
3166 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3167
3168 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3169 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
3170 if (y) (*y) = font->ascent + font->descent;
3171 if (descent) (*descent) = font->descent;
3172 if (externalLeading) (*externalLeading) = 0; // ??
3173 }
3174
3175 void wxWindowGTK::SetFocus()
3176 {
3177 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3178
3179 if (m_wxwindow)
3180 {
3181 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3182 {
3183 // see comment in gtk_window_focus_out_callback()
3184 gs_widgetLastFocus = m_wxwindow;
3185 gtk_widget_grab_focus (m_wxwindow);
3186 }
3187 }
3188 else if (m_widget)
3189 {
3190 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3191 {
3192 gtk_widget_grab_focus (m_widget);
3193 }
3194 else if (GTK_IS_CONTAINER(m_widget))
3195 {
3196 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3197 }
3198 else
3199 {
3200 // ?
3201 }
3202 }
3203 }
3204
3205 bool wxWindowGTK::AcceptsFocus() const
3206 {
3207 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3208 }
3209
3210 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3211 {
3212 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3213
3214 wxWindowGTK *oldParent = m_parent,
3215 *newParent = (wxWindowGTK *)newParentBase;
3216
3217 wxASSERT( GTK_IS_WIDGET(m_widget) );
3218
3219 if ( !wxWindowBase::Reparent(newParent) )
3220 return FALSE;
3221
3222 wxASSERT( GTK_IS_WIDGET(m_widget) );
3223
3224 /* prevent GTK from deleting the widget arbitrarily */
3225 gtk_widget_ref( m_widget );
3226
3227 if (oldParent)
3228 {
3229 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3230 }
3231
3232 wxASSERT( GTK_IS_WIDGET(m_widget) );
3233
3234 if (newParent)
3235 {
3236 /* insert GTK representation */
3237 (*(newParent->m_insertCallback))(newParent, this);
3238 }
3239
3240 /* reverse: prevent GTK from deleting the widget arbitrarily */
3241 gtk_widget_unref( m_widget );
3242
3243 return TRUE;
3244 }
3245
3246 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3247 {
3248 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3249
3250 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3251
3252 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3253
3254 /* add to list */
3255 AddChild( child );
3256
3257 /* insert GTK representation */
3258 (*m_insertCallback)(this, child);
3259 }
3260
3261 void wxWindowGTK::Raise()
3262 {
3263 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3264
3265 if (!m_widget->window) return;
3266
3267 gdk_window_raise( m_widget->window );
3268 }
3269
3270 void wxWindowGTK::Lower()
3271 {
3272 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3273
3274 if (!m_widget->window) return;
3275
3276 gdk_window_lower( m_widget->window );
3277 }
3278
3279 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3280 {
3281 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3282
3283 if (cursor == m_cursor)
3284 return FALSE;
3285
3286 if (g_isIdle)
3287 wxapp_install_idle_handler();
3288
3289 if (cursor == wxNullCursor)
3290 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3291 else
3292 return wxWindowBase::SetCursor( cursor );
3293 }
3294
3295 void wxWindowGTK::WarpPointer( int x, int y )
3296 {
3297 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3298
3299 /* we provide this function ourselves as it is
3300 missing in GDK (top of this file) */
3301
3302 GdkWindow *window = (GdkWindow*) NULL;
3303 if (m_wxwindow)
3304 window = GTK_PIZZA(m_wxwindow)->bin_window;
3305 else
3306 window = GetConnectWidget()->window;
3307
3308 if (window)
3309 gdk_window_warp_pointer( window, x, y );
3310 }
3311
3312 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3313 {
3314 if (!m_widget) return;
3315 if (!m_widget->window) return;
3316
3317 // temporarily hide the caret to avoid nasty interactions between caret
3318 // drawing and the window contents redraw
3319 #if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3320 wxCaretSuspend cs((wxWindow *)this);
3321 #endif // wxUSE_CARET
3322
3323 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3324 {
3325 if (rect)
3326 {
3327 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3328 rect->x, rect->y,
3329 rect->width, rect->height );
3330 }
3331 else
3332 {
3333 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
3334 }
3335 }
3336
3337 /* there is no GTK equivalent of "draw only, don't clear" so we
3338 invent our own in the GtkPizza widget */
3339
3340 if (!rect)
3341 {
3342 if (m_wxwindow)
3343 {
3344
3345 /*
3346 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3347 gboolean old_clear = pizza->clear_on_draw;
3348 gtk_pizza_set_clear( pizza, FALSE );
3349 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
3350 gtk_pizza_set_clear( pizza, old_clear );
3351 */
3352 GdkEventExpose gdk_event;
3353 gdk_event.type = GDK_EXPOSE;
3354 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3355 gdk_event.count = 0;
3356 gdk_event.area.x = 0;
3357 gdk_event.area.y = 0;
3358 gdk_event.area.width = m_wxwindow->allocation.width;
3359 gdk_event.area.height = m_wxwindow->allocation.height;
3360 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
3361 }
3362 else
3363 {
3364 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3365 }
3366 }
3367 else
3368 {
3369
3370 if (m_wxwindow)
3371 {
3372 /*
3373 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3374 gboolean old_clear = pizza->clear_on_draw;
3375 gtk_pizza_set_clear( pizza, FALSE );
3376
3377 GdkRectangle gdk_rect;
3378 gdk_rect.x = rect->x;
3379 gdk_rect.y = rect->y;
3380 gdk_rect.width = rect->width;
3381 gdk_rect.height = rect->height;
3382 gtk_widget_draw( m_wxwindow, &gdk_rect );
3383 gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
3384
3385 gtk_pizza_set_clear( pizza, old_clear );
3386 */
3387 GdkEventExpose gdk_event;
3388 gdk_event.type = GDK_EXPOSE;
3389 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3390 gdk_event.count = 0;
3391 gdk_event.area.x = rect->x;
3392 gdk_event.area.y = rect->y;
3393 gdk_event.area.width = rect->width;
3394 gdk_event.area.height = rect->height;
3395 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
3396 }
3397 else
3398 {
3399 GdkRectangle gdk_rect;
3400 gdk_rect.x = rect->x;
3401 gdk_rect.y = rect->y;
3402 gdk_rect.width = rect->width;
3403 gdk_rect.height = rect->height;
3404 gtk_widget_draw( m_widget, &gdk_rect );
3405 }
3406 }
3407 }
3408
3409 void wxWindowGTK::Clear()
3410 {
3411 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3412
3413 if (!m_widget->window) return;
3414
3415 if (m_wxwindow && m_wxwindow->window)
3416 {
3417 // gdk_window_clear( m_wxwindow->window );
3418 }
3419 }
3420
3421 #if wxUSE_TOOLTIPS
3422 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
3423 {
3424 wxWindowBase::DoSetToolTip(tip);
3425
3426 if (m_tooltip)
3427 m_tooltip->Apply( (wxWindow *)this );
3428 }
3429
3430 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3431 {
3432 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
3433 }
3434 #endif // wxUSE_TOOLTIPS
3435
3436 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
3437 {
3438 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3439
3440 if (!wxWindowBase::SetBackgroundColour(colour))
3441 {
3442 // don't leave if the GTK widget has just
3443 // been realized
3444 if (!m_delayedBackgroundColour) return FALSE;
3445 }
3446
3447 GdkWindow *window = (GdkWindow*) NULL;
3448 if (m_wxwindow)
3449 window = GTK_PIZZA(m_wxwindow)->bin_window;
3450 else
3451 window = GetConnectWidget()->window;
3452
3453 if (!window)
3454 {
3455 // indicate that a new style has been set
3456 // but it couldn't get applied as the
3457 // widget hasn't been realized yet.
3458 m_delayedBackgroundColour = TRUE;
3459 }
3460
3461 if ((m_wxwindow) &&
3462 (m_wxwindow->window) &&
3463 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
3464 {
3465 /* wxMSW doesn't clear the window here. I don't do that either to
3466 provide compatibility. call Clear() to do the job. */
3467
3468 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3469 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3470 }
3471
3472 ApplyWidgetStyle();
3473
3474 return TRUE;
3475 }
3476
3477 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
3478 {
3479 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3480
3481 if (!wxWindowBase::SetForegroundColour(colour))
3482 {
3483 // don't leave if the GTK widget has just
3484 // been realized
3485 if (!m_delayedForegroundColour) return FALSE;
3486 }
3487
3488 GdkWindow *window = (GdkWindow*) NULL;
3489 if (m_wxwindow)
3490 window = GTK_PIZZA(m_wxwindow)->bin_window;
3491 else
3492 window = GetConnectWidget()->window;
3493
3494 if (!window)
3495 {
3496 // indicate that a new style has been set
3497 // but it couldn't get applied as the
3498 // widget hasn't been realized yet.
3499 m_delayedForegroundColour = TRUE;
3500 }
3501
3502 ApplyWidgetStyle();
3503
3504 return TRUE;
3505 }
3506
3507 GtkStyle *wxWindowGTK::GetWidgetStyle()
3508 {
3509 if (m_widgetStyle)
3510 {
3511 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3512 #ifdef __WXGTK20__
3513 /* FIXME: is this necessary? */
3514 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3515 #else
3516 remake->klass = m_widgetStyle->klass;
3517 #endif
3518
3519 gtk_style_unref( m_widgetStyle );
3520 m_widgetStyle = remake;
3521 }
3522 else
3523 {
3524 GtkStyle *def = gtk_rc_get_style( m_widget );
3525
3526 if (!def)
3527 def = gtk_widget_get_default_style();
3528
3529 m_widgetStyle = gtk_style_copy( def );
3530 #ifdef __WXGTK20__
3531 /* FIXME: is this necessary? */
3532 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3533 #else
3534 m_widgetStyle->klass = def->klass;
3535 #endif
3536 }
3537
3538 return m_widgetStyle;
3539 }
3540
3541 void wxWindowGTK::SetWidgetStyle()
3542 {
3543 #if DISABLE_STYLE_IF_BROKEN_THEM
3544 if (m_widget->style->engine_data)
3545 {
3546 static bool s_warningPrinted = FALSE;
3547 if (!s_warningPrinted)
3548 {
3549 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3550 s_warningPrinted = TRUE;
3551 }
3552 m_widgetStyle = m_widget->style;
3553 return;
3554 }
3555 #endif
3556
3557 GtkStyle *style = GetWidgetStyle();
3558
3559 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3560 {
3561 gdk_font_unref( style->font );
3562 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3563 }
3564
3565 if (m_foregroundColour.Ok())
3566 {
3567 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3568 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3569 {
3570 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3571 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3572 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3573 }
3574 else
3575 {
3576 // Try to restore the gtk default style. This is still a little
3577 // oversimplified for what is probably really needed here for controls
3578 // other than buttons, but is better than not being able to (re)set a
3579 // control's foreground colour to *wxBLACK -- RL
3580 GtkStyle *def = gtk_rc_get_style( m_widget );
3581
3582 if (!def)
3583 def = gtk_widget_get_default_style();
3584
3585 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3586 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3587 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3588 }
3589 }
3590
3591 if (m_backgroundColour.Ok())
3592 {
3593 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3594 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3595 {
3596 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3597 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3598 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3599 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3600 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3601 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3602 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3603 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3604 }
3605 else
3606 {
3607 // Try to restore the gtk default style. This is still a little
3608 // oversimplified for what is probably really needed here for controls
3609 // other than buttons, but is better than not being able to (re)set a
3610 // control's background colour to default grey and means resetting a
3611 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3612 // behavior -- RL
3613 GtkStyle *def = gtk_rc_get_style( m_widget );
3614
3615 if (!def)
3616 def = gtk_widget_get_default_style();
3617
3618 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3619 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3620 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3621 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3622 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3623 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3624 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3625 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3626 }
3627 }
3628 }
3629
3630 void wxWindowGTK::ApplyWidgetStyle()
3631 {
3632 }
3633
3634 //-----------------------------------------------------------------------------
3635 // Pop-up menu stuff
3636 //-----------------------------------------------------------------------------
3637
3638 #if wxUSE_MENUS_NATIVE
3639
3640 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3641 {
3642 *is_waiting = FALSE;
3643 }
3644
3645 static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
3646 {
3647 menu->SetInvokingWindow( win );
3648 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3649 while (node)
3650 {
3651 wxMenuItem *menuitem = node->GetData();
3652 if (menuitem->IsSubMenu())
3653 {
3654 SetInvokingWindow( menuitem->GetSubMenu(), win );
3655 }
3656
3657 node = node->GetNext();
3658 }
3659 }
3660
3661 static gint gs_pop_x = 0;
3662 static gint gs_pop_y = 0;
3663
3664 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3665 gint *x, gint *y,
3666 wxWindowGTK *win )
3667 {
3668 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3669 *x = gs_pop_x;
3670 *y = gs_pop_y;
3671 }
3672
3673 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
3674 {
3675 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3676
3677 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3678
3679 SetInvokingWindow( menu, this );
3680
3681 menu->UpdateUI();
3682
3683 gs_pop_x = x;
3684 gs_pop_y = y;
3685
3686 bool is_waiting = TRUE;
3687
3688 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3689 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3690
3691 gtk_menu_popup(
3692 GTK_MENU(menu->m_menu),
3693 (GtkWidget *) NULL, // parent menu shell
3694 (GtkWidget *) NULL, // parent menu item
3695 (GtkMenuPositionFunc) pop_pos_callback,
3696 (gpointer) this, // client data
3697 0, // button used to activate it
3698 gs_timeLastClick // the time of activation
3699 );
3700
3701 while (is_waiting)
3702 {
3703 while (gtk_events_pending())
3704 gtk_main_iteration();
3705 }
3706
3707 return TRUE;
3708 }
3709
3710 #endif // wxUSE_MENUS_NATIVE
3711
3712 #if wxUSE_DRAG_AND_DROP
3713
3714 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
3715 {
3716 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3717
3718 GtkWidget *dnd_widget = GetConnectWidget();
3719
3720 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3721
3722 if (m_dropTarget) delete m_dropTarget;
3723 m_dropTarget = dropTarget;
3724
3725 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3726 }
3727
3728 #endif // wxUSE_DRAG_AND_DROP
3729
3730 GtkWidget* wxWindowGTK::GetConnectWidget()
3731 {
3732 GtkWidget *connect_widget = m_widget;
3733 if (m_wxwindow) connect_widget = m_wxwindow;
3734
3735 return connect_widget;
3736 }
3737
3738 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
3739 {
3740 if (m_wxwindow)
3741 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3742
3743 return (window == m_widget->window);
3744 }
3745
3746 bool wxWindowGTK::SetFont( const wxFont &font )
3747 {
3748 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3749
3750 if (!wxWindowBase::SetFont(font))
3751 {
3752 return FALSE;
3753 }
3754
3755 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3756 if ( sysbg == m_backgroundColour )
3757 {
3758 m_backgroundColour = wxNullColour;
3759 ApplyWidgetStyle();
3760 m_backgroundColour = sysbg;
3761 }
3762 else
3763 {
3764 ApplyWidgetStyle();
3765 }
3766
3767 return TRUE;
3768 }
3769
3770 void wxWindowGTK::CaptureMouse()
3771 {
3772 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3773
3774 GdkWindow *window = (GdkWindow*) NULL;
3775 if (m_wxwindow)
3776 window = GTK_PIZZA(m_wxwindow)->bin_window;
3777 else
3778 window = GetConnectWidget()->window;
3779
3780 wxCHECK_RET( window, _T("CaptureMouse() failed") );
3781
3782 wxCursor* cursor = & m_cursor;
3783 if (!cursor->Ok())
3784 cursor = wxSTANDARD_CURSOR;
3785
3786 gdk_pointer_grab( window, FALSE,
3787 (GdkEventMask)
3788 (GDK_BUTTON_PRESS_MASK |
3789 GDK_BUTTON_RELEASE_MASK |
3790 GDK_POINTER_MOTION_HINT_MASK |
3791 GDK_POINTER_MOTION_MASK),
3792 (GdkWindow *) NULL,
3793 cursor->GetCursor(),
3794 (guint32)GDK_CURRENT_TIME );
3795 g_captureWindow = this;
3796 g_captureWindowHasMouse = TRUE;
3797 }
3798
3799 void wxWindowGTK::ReleaseMouse()
3800 {
3801 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3802
3803 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
3804
3805 GdkWindow *window = (GdkWindow*) NULL;
3806 if (m_wxwindow)
3807 window = GTK_PIZZA(m_wxwindow)->bin_window;
3808 else
3809 window = GetConnectWidget()->window;
3810
3811 if (!window)
3812 return;
3813
3814 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3815 g_captureWindow = (wxWindowGTK*) NULL;
3816 }
3817
3818 /* static */
3819 wxWindow *wxWindowBase::GetCapture()
3820 {
3821 return (wxWindow *)g_captureWindow;
3822 }
3823
3824 bool wxWindowGTK::IsRetained() const
3825 {
3826 return FALSE;
3827 }
3828
3829 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
3830 int range, bool refresh )
3831 {
3832 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3833
3834 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3835
3836 m_hasScrolling = TRUE;
3837
3838 if (orient == wxHORIZONTAL)
3839 {
3840 float fpos = (float)pos;
3841 float frange = (float)range;
3842 float fthumb = (float)thumbVisible;
3843 if (fpos > frange-fthumb) fpos = frange-fthumb;
3844 if (fpos < 0.0) fpos = 0.0;
3845
3846 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3847 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3848 {
3849 SetScrollPos( orient, pos, refresh );
3850 return;
3851 }
3852
3853 m_oldHorizontalPos = fpos;
3854
3855 m_hAdjust->lower = 0.0;
3856 m_hAdjust->upper = frange;
3857 m_hAdjust->value = fpos;
3858 m_hAdjust->step_increment = 1.0;
3859 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3860 m_hAdjust->page_size = fthumb;
3861 }
3862 else
3863 {
3864 float fpos = (float)pos;
3865 float frange = (float)range;
3866 float fthumb = (float)thumbVisible;
3867 if (fpos > frange-fthumb) fpos = frange-fthumb;
3868 if (fpos < 0.0) fpos = 0.0;
3869
3870 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3871 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3872 {
3873 SetScrollPos( orient, pos, refresh );
3874 return;
3875 }
3876
3877 m_oldVerticalPos = fpos;
3878
3879 m_vAdjust->lower = 0.0;
3880 m_vAdjust->upper = frange;
3881 m_vAdjust->value = fpos;
3882 m_vAdjust->step_increment = 1.0;
3883 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3884 m_vAdjust->page_size = fthumb;
3885 }
3886
3887 if (orient == wxHORIZONTAL)
3888 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3889 else
3890 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3891 }
3892
3893 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3894 {
3895 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3896
3897 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3898
3899 if (orient == wxHORIZONTAL)
3900 {
3901 float fpos = (float)pos;
3902 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3903 if (fpos < 0.0) fpos = 0.0;
3904 m_oldHorizontalPos = fpos;
3905
3906 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3907 m_hAdjust->value = fpos;
3908 }
3909 else
3910 {
3911 float fpos = (float)pos;
3912 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3913 if (fpos < 0.0) fpos = 0.0;
3914 m_oldVerticalPos = fpos;
3915
3916 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3917 m_vAdjust->value = fpos;
3918 }
3919
3920 if (m_wxwindow->window)
3921 {
3922 if (orient == wxHORIZONTAL)
3923 {
3924 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3925 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3926
3927 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3928
3929 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3930 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3931 }
3932 else
3933 {
3934 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3935 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3936
3937 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3938
3939 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3940 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3941 }
3942 }
3943 }
3944
3945 int wxWindowGTK::GetScrollThumb( int orient ) const
3946 {
3947 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3948
3949 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3950
3951 if (orient == wxHORIZONTAL)
3952 return (int)(m_hAdjust->page_size+0.5);
3953 else
3954 return (int)(m_vAdjust->page_size+0.5);
3955 }
3956
3957 int wxWindowGTK::GetScrollPos( int orient ) const
3958 {
3959 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3960
3961 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3962
3963 if (orient == wxHORIZONTAL)
3964 return (int)(m_hAdjust->value+0.5);
3965 else
3966 return (int)(m_vAdjust->value+0.5);
3967 }
3968
3969 int wxWindowGTK::GetScrollRange( int orient ) const
3970 {
3971 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3972
3973 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3974
3975 if (orient == wxHORIZONTAL)
3976 return (int)(m_hAdjust->upper+0.5);
3977 else
3978 return (int)(m_vAdjust->upper+0.5);
3979 }
3980
3981 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3982 {
3983 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3984
3985 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3986
3987 if ((dx == 0) && (dy == 0)) return;
3988
3989 m_clipPaintRegion = TRUE;
3990 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3991 m_clipPaintRegion = FALSE;
3992
3993 /*
3994 if (m_children.GetCount() > 0)
3995 {
3996 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3997 }
3998 else
3999 {
4000 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
4001
4002 pizza->xoffset -= dx;
4003 pizza->yoffset -= dy;
4004
4005 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
4006 gdk_gc_set_exposures( m_scrollGC, TRUE );
4007
4008 int cw = 0;
4009 int ch = 0;
4010 GetClientSize( &cw, &ch );
4011 int w = cw - abs(dx);
4012 int h = ch - abs(dy);
4013
4014 if ((h < 0) || (w < 0))
4015 {
4016 Refresh();
4017 }
4018 else
4019 {
4020 int s_x = 0;
4021 int s_y = 0;
4022 if (dx < 0) s_x = -dx;
4023 if (dy < 0) s_y = -dy;
4024 int d_x = 0;
4025 int d_y = 0;
4026 if (dx > 0) d_x = dx;
4027 if (dy > 0) d_y = dy;
4028
4029 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
4030 pizza->bin_window, s_x, s_y, w, h );
4031
4032 wxRect rect;
4033 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
4034 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
4035 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
4036 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
4037
4038 Refresh( TRUE, &rect );
4039 }
4040
4041 gdk_gc_unref( m_scrollGC );
4042 }
4043 */
4044 }
4045
4046 // Find the wxWindow at the current mouse position, also returning the mouse
4047 // position.
4048 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4049 {
4050 pt = wxGetMousePosition();
4051 wxWindow* found = wxFindWindowAtPoint(pt);
4052 return found;
4053 }
4054
4055 // Get the current mouse position.
4056 wxPoint wxGetMousePosition()
4057 {
4058 /* This crashes when used within wxHelpContext,
4059 so we have to use the X-specific implementation below.
4060 gint x, y;
4061 GdkModifierType *mask;
4062 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4063
4064 return wxPoint(x, y);
4065 */
4066
4067 int x, y;
4068 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4069 if (!windowAtPtr)
4070 return wxPoint(-999, -999);
4071
4072 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
4073 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4074 Window rootReturn, childReturn;
4075 int rootX, rootY, winX, winY;
4076 unsigned int maskReturn;
4077
4078 XQueryPointer (display,
4079 rootWindow,
4080 &rootReturn,
4081 &childReturn,
4082 &rootX, &rootY, &winX, &winY, &maskReturn);
4083 return wxPoint(rootX, rootY);
4084
4085 }
4086