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