]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/window.cpp
Small testing changes,
[wxWidgets.git] / src / gtk1 / 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 if (!win->m_hasVMT)
616 return;
617
618 win->GetUpdateRegion().Union( gdk_event->area.x,
619 gdk_event->area.y,
620 gdk_event->area.width,
621 gdk_event->area.height );
622
623 /*
624 wxPrintf( "OnExpose from " );
625 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
626 wxPrintf( win->GetClassInfo()->GetClassName() );
627 wxPrintf( " %d %d %d %d\n", (int)gdk_event->area.x,
628 (int)gdk_event->area.y,
629 (int)gdk_event->area.width,
630 (int)gdk_event->area.height );
631 */
632
633 if (gdk_event->count > 0)
634 return;
635
636 wxEraseEvent eevent( win->GetId() );
637 eevent.SetEventObject( win );
638 win->GetEventHandler()->ProcessEvent(eevent);
639
640 wxPaintEvent event( win->GetId() );
641 event.SetEventObject( win );
642 win->GetEventHandler()->ProcessEvent( event );
643
644 win->GetUpdateRegion().Clear();
645 }
646
647 //-----------------------------------------------------------------------------
648 // "draw" of m_wxwindow
649 //-----------------------------------------------------------------------------
650
651 static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget),
652 GdkRectangle *rect, wxWindow *win )
653 {
654 DEBUG_MAIN_THREAD
655
656 if (g_isIdle)
657 wxapp_install_idle_handler();
658
659 if (!win->m_hasVMT)
660 return;
661
662 win->GetUpdateRegion().Union( rect->x, rect->y,
663 rect->width, rect->height );
664
665 /*
666 wxPrintf( "OnDraw from " );
667 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
668 printf( win->GetClassInfo()->GetClassName() );
669 wxPrintf( " %d %d %d %d\n", (int)rect->x,
670 (int)rect->y,
671 (int)rect->width,
672 (int)rect->height );
673 */
674
675 wxEraseEvent eevent( win->GetId() );
676 eevent.SetEventObject( win );
677 win->GetEventHandler()->ProcessEvent(eevent);
678
679 wxPaintEvent event( win->GetId() );
680 event.SetEventObject( win );
681 win->GetEventHandler()->ProcessEvent( event );
682
683 win->GetUpdateRegion().Clear();
684 }
685
686 //-----------------------------------------------------------------------------
687 // "key_press_event" from any window
688 //-----------------------------------------------------------------------------
689
690 static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
691 {
692 DEBUG_MAIN_THREAD
693
694 if (g_isIdle)
695 wxapp_install_idle_handler();
696
697 if (!win->m_hasVMT) return FALSE;
698 if (g_blockEventsOnDrag) return FALSE;
699
700 /*
701 wxString tmp;
702 tmp += (char)gdk_event->keyval;
703 printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
704 printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
705 */
706
707 int x = 0;
708 int y = 0;
709 GdkModifierType state;
710 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
711
712 bool ret = FALSE;
713
714 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
715 /* sending unknown key events doesn't really make sense */
716 if (key_code == 0) return FALSE;
717
718 wxKeyEvent event( wxEVT_KEY_DOWN );
719 event.SetTimestamp( gdk_event->time );
720 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
721 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
722 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
723 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
724 event.m_keyCode = key_code;
725 event.m_scanCode = gdk_event->keyval;
726 event.m_x = x;
727 event.m_y = y;
728 event.SetEventObject( win );
729 ret = win->GetEventHandler()->ProcessEvent( event );
730
731 #if wxUSE_ACCEL
732 if (!ret)
733 {
734 wxWindow *ancestor = win;
735 while (ancestor)
736 {
737 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
738 if (command != -1)
739 {
740 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
741 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
742 break;
743 }
744 if (ancestor->m_isFrame)
745 break;
746 ancestor = ancestor->GetParent();
747 }
748 }
749 #endif // wxUSE_ACCEL
750
751 /* wxMSW doesn't send char events with Alt pressed */
752 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
753 will only be sent if it is not in an accelerator table. */
754 key_code = map_to_wx_keysym( gdk_event->keyval );
755
756 if ( (!ret) &&
757 (key_code != 0))
758 {
759 wxKeyEvent event2( wxEVT_CHAR );
760 event2.SetTimestamp( gdk_event->time );
761 event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
762 event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
763 event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
764 event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
765 event2.m_keyCode = key_code;
766 event2.m_scanCode = gdk_event->keyval;
767 event2.m_x = x;
768 event2.m_y = y;
769 event2.SetEventObject( win );
770 ret = win->GetEventHandler()->ProcessEvent( event2 );
771 }
772
773 /* win is a control: tab can be propagated up */
774 if ( (!ret) &&
775 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
776 (!win->HasFlag(wxTE_PROCESS_TAB)) &&
777 (win->GetParent()) &&
778 (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
779 {
780 wxNavigationKeyEvent new_event;
781 new_event.SetEventObject( win->GetParent() );
782 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
783 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
784 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
785 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
786 new_event.SetCurrentFocus( win );
787 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
788 }
789
790 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
791 if ( (!ret) &&
792 (gdk_event->keyval == GDK_Escape) )
793 {
794 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
795 new_event.SetEventObject( win );
796 ret = win->GetEventHandler()->ProcessEvent( new_event );
797 }
798
799 #if (GTK_MINOR_VERSION > 0)
800 /* Pressing F10 will activate the menu bar of the top frame. */
801 /* Doesn't work. */
802 /*
803 if ( (!ret) &&
804 (gdk_event->keyval == GDK_F10) )
805 {
806 wxWindow *ancestor = win;
807 while (ancestor)
808 {
809 if (wxIsKindOf(ancestor,wxFrame))
810 {
811 wxFrame *frame = (wxFrame*) ancestor;
812 wxMenuBar *menubar = frame->GetMenuBar();
813 if (menubar)
814 {
815 wxNode *node = menubar->GetMenus().First();
816 if (node)
817 {
818 wxMenu *firstMenu = (wxMenu*) node->Data();
819 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
820 ret = TRUE;
821 break;
822 }
823 }
824 }
825 ancestor = ancestor->GetParent();
826 }
827 }
828 */
829 #endif
830
831 if (ret)
832 {
833 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
834 return TRUE;
835 }
836
837 return FALSE;
838 }
839
840 //-----------------------------------------------------------------------------
841 // "key_release_event" from any window
842 //-----------------------------------------------------------------------------
843
844 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
845 {
846 DEBUG_MAIN_THREAD
847
848 if (g_isIdle)
849 wxapp_install_idle_handler();
850
851 if (!win->m_hasVMT) return FALSE;
852 if (g_blockEventsOnDrag) return FALSE;
853
854 /*
855 printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
856 if (gdk_event->state & GDK_SHIFT_MASK)
857 printf( "ShiftDown.\n" );
858 else
859 printf( "ShiftUp.\n" );
860 if (gdk_event->state & GDK_CONTROL_MASK)
861 printf( "ControlDown.\n" );
862 else
863 printf( "ControlUp.\n" );
864 printf( "\n" );
865 */
866
867 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
868
869 /* sending unknown key events doesn't really make sense */
870 if (key_code == 0) return FALSE;
871
872 int x = 0;
873 int y = 0;
874 GdkModifierType state;
875 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
876
877 wxKeyEvent event( wxEVT_KEY_UP );
878 event.SetTimestamp( gdk_event->time );
879 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
880 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
881 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
882 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
883 event.m_keyCode = key_code;
884 event.m_scanCode = gdk_event->keyval;
885 event.m_x = x;
886 event.m_y = y;
887 event.SetEventObject( win );
888
889 if (win->GetEventHandler()->ProcessEvent( event ))
890 {
891 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
892 return TRUE;
893 }
894
895 return FALSE;
896 }
897
898 // ----------------------------------------------------------------------------
899 // mouse event processing helper
900 // ----------------------------------------------------------------------------
901
902 static void AdjustEventButtonState(wxMouseEvent& event)
903 {
904 // GDK reports the old state of the button for a button press event, but
905 // for compatibility with MSW and common sense we want m_leftDown be TRUE
906 // for a LEFT_DOWN event, not FALSE, so we will invert
907 // left/right/middleDown for the corresponding click events
908 switch ( event.GetEventType() )
909 {
910 case wxEVT_LEFT_DOWN:
911 case wxEVT_LEFT_DCLICK:
912 case wxEVT_LEFT_UP:
913 event.m_leftDown = !event.m_leftDown;
914 break;
915
916 case wxEVT_MIDDLE_DOWN:
917 case wxEVT_MIDDLE_DCLICK:
918 case wxEVT_MIDDLE_UP:
919 event.m_middleDown = !event.m_middleDown;
920 break;
921
922 case wxEVT_RIGHT_DOWN:
923 case wxEVT_RIGHT_DCLICK:
924 case wxEVT_RIGHT_UP:
925 event.m_rightDown = !event.m_rightDown;
926 break;
927 }
928 }
929
930 //-----------------------------------------------------------------------------
931 // "button_press_event"
932 //-----------------------------------------------------------------------------
933
934 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
935 {
936 DEBUG_MAIN_THREAD
937
938 if (g_isIdle)
939 wxapp_install_idle_handler();
940
941 /*
942 wxPrintf( wxT("1) OnButtonPress from ") );
943 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
944 wxPrintf( win->GetClassInfo()->GetClassName() );
945 wxPrintf( wxT(".\n") );
946 */
947 if (!win->m_hasVMT) return FALSE;
948 if (g_blockEventsOnDrag) return TRUE;
949 if (g_blockEventsOnScroll) return TRUE;
950
951 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
952
953 if (win->m_wxwindow)
954 {
955 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
956 {
957 gtk_widget_grab_focus (win->m_wxwindow);
958
959 /*
960 wxPrintf( wxT("GrabFocus from ") );
961 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
962 wxPrintf( win->GetClassInfo()->GetClassName() );
963 wxPrintf( wxT(".\n") );
964 */
965
966 }
967 }
968
969 wxEventType event_type = wxEVT_NULL;
970
971 if (gdk_event->button == 1)
972 {
973 switch (gdk_event->type)
974 {
975 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
976 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
977 default: break;
978 }
979 }
980 else if (gdk_event->button == 2)
981 {
982 switch (gdk_event->type)
983 {
984 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
985 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
986 default: break;
987 }
988 }
989 else if (gdk_event->button == 3)
990 {
991 switch (gdk_event->type)
992 {
993 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
994 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
995 default: break;
996 }
997 }
998
999 if ( event_type == wxEVT_NULL )
1000 {
1001 // unknown mouse button or click type
1002 return FALSE;
1003 }
1004
1005 wxMouseEvent event( event_type );
1006 event.SetTimestamp( gdk_event->time );
1007 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1008 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1009 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1010 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1011 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1012 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1013 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1014
1015 event.m_x = (wxCoord)gdk_event->x;
1016 event.m_y = (wxCoord)gdk_event->y;
1017
1018 AdjustEventButtonState(event);
1019
1020 // Some control don't have their own X window and thus cannot get
1021 // any events.
1022
1023 if (!g_captureWindow)
1024 {
1025 wxCoord x = event.m_x;
1026 wxCoord y = event.m_y;
1027 if (win->m_wxwindow)
1028 {
1029 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1030 x += pizza->xoffset;
1031 y += pizza->yoffset;
1032 }
1033
1034 wxNode *node = win->GetChildren().First();
1035 while (node)
1036 {
1037 wxWindow *child = (wxWindow*)node->Data();
1038
1039 node = node->Next();
1040 if (!child->IsShown())
1041 continue;
1042
1043 if (child->m_isStaticBox)
1044 {
1045 // wxStaticBox is transparent in the box itself
1046 int xx1 = child->m_x;
1047 int yy1 = child->m_y;
1048 int xx2 = child->m_x + child->m_width;
1049 int yy2 = child->m_x + child->m_height;
1050
1051 // left
1052 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1053 // right
1054 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1055 // top
1056 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1057 // bottom
1058 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1059 {
1060 win = child;
1061 event.m_x -= child->m_x;
1062 event.m_y -= child->m_y;
1063 break;
1064 }
1065
1066 }
1067 else
1068 {
1069 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1070 (child->m_x <= x) &&
1071 (child->m_y <= y) &&
1072 (child->m_x+child->m_width >= x) &&
1073 (child->m_y+child->m_height >= y))
1074 {
1075 win = child;
1076 event.m_x -= child->m_x;
1077 event.m_y -= child->m_y;
1078 break;
1079 }
1080 }
1081 }
1082 }
1083
1084 event.SetEventObject( win );
1085
1086 gs_timeLastClick = gdk_event->time;
1087
1088 /*
1089 wxPrintf( wxT("2) OnButtonPress from ") );
1090 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1091 wxPrintf( win->GetClassInfo()->GetClassName() );
1092 wxPrintf( wxT(".\n") );
1093 */
1094
1095 if (win->GetEventHandler()->ProcessEvent( event ))
1096 {
1097 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1098 return TRUE;
1099 }
1100
1101 return FALSE;
1102 }
1103
1104 //-----------------------------------------------------------------------------
1105 // "button_release_event"
1106 //-----------------------------------------------------------------------------
1107
1108 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1109 {
1110 DEBUG_MAIN_THREAD
1111
1112 if (g_isIdle)
1113 wxapp_install_idle_handler();
1114
1115 if (!win->m_hasVMT) return FALSE;
1116 if (g_blockEventsOnDrag) return FALSE;
1117 if (g_blockEventsOnScroll) return FALSE;
1118
1119 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1120
1121 /*
1122 printf( "OnButtonRelease from " );
1123 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1124 printf( win->GetClassInfo()->GetClassName() );
1125 printf( ".\n" );
1126 */
1127
1128 wxEventType event_type = wxEVT_NULL;
1129
1130 switch (gdk_event->button)
1131 {
1132 case 1: event_type = wxEVT_LEFT_UP; break;
1133 case 2: event_type = wxEVT_MIDDLE_UP; break;
1134 case 3: event_type = wxEVT_RIGHT_UP; break;
1135 default: return FALSE;
1136 }
1137
1138 wxMouseEvent event( event_type );
1139 event.SetTimestamp( gdk_event->time );
1140 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1141 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1142 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1143 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1144 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1145 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1146 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1147 event.m_x = (wxCoord)gdk_event->x;
1148 event.m_y = (wxCoord)gdk_event->y;
1149
1150 AdjustEventButtonState(event);
1151
1152 // Some control don't have their own X window and thus cannot get
1153 // any events.
1154
1155 if (!g_captureWindow)
1156 {
1157 wxCoord x = event.m_x;
1158 wxCoord y = event.m_y;
1159 if (win->m_wxwindow)
1160 {
1161 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1162 x += pizza->xoffset;
1163 y += pizza->yoffset;
1164 }
1165
1166 wxNode *node = win->GetChildren().First();
1167 while (node)
1168 {
1169 wxWindow *child = (wxWindow*)node->Data();
1170
1171 node = node->Next();
1172 if (!child->IsShown())
1173 continue;
1174
1175 if (child->m_isStaticBox)
1176 {
1177 // wxStaticBox is transparent in the box itself
1178 int xx1 = child->m_x;
1179 int yy1 = child->m_y;
1180 int xx2 = child->m_x + child->m_width;
1181 int yy2 = child->m_x + child->m_height;
1182
1183 // left
1184 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1185 // right
1186 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1187 // top
1188 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1189 // bottom
1190 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1191 {
1192 win = child;
1193 event.m_x -= child->m_x;
1194 event.m_y -= child->m_y;
1195 break;
1196 }
1197
1198 }
1199 else
1200 {
1201 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1202 (child->m_x <= x) &&
1203 (child->m_y <= y) &&
1204 (child->m_x+child->m_width >= x) &&
1205 (child->m_y+child->m_height >= y))
1206 {
1207 win = child;
1208 event.m_x -= child->m_x;
1209 event.m_y -= child->m_y;
1210 break;
1211 }
1212 }
1213 }
1214 }
1215
1216 event.SetEventObject( win );
1217
1218 if (win->GetEventHandler()->ProcessEvent( event ))
1219 {
1220 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1221 return TRUE;
1222 }
1223
1224 return FALSE;
1225 }
1226
1227 //-----------------------------------------------------------------------------
1228 // "motion_notify_event"
1229 //-----------------------------------------------------------------------------
1230
1231 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
1232 {
1233 DEBUG_MAIN_THREAD
1234
1235 if (g_isIdle)
1236 wxapp_install_idle_handler();
1237
1238 if (!win->m_hasVMT) return FALSE;
1239 if (g_blockEventsOnDrag) return FALSE;
1240 if (g_blockEventsOnScroll) return FALSE;
1241
1242 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1243
1244 if (gdk_event->is_hint)
1245 {
1246 int x = 0;
1247 int y = 0;
1248 GdkModifierType state;
1249 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1250 gdk_event->x = x;
1251 gdk_event->y = y;
1252 }
1253
1254 /*
1255 printf( "OnMotion from " );
1256 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1257 printf( win->GetClassInfo()->GetClassName() );
1258 printf( ".\n" );
1259 */
1260
1261 wxMouseEvent event( wxEVT_MOTION );
1262 event.SetTimestamp( gdk_event->time );
1263 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1264 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1265 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1266 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1267 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1268 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1269 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1270
1271 event.m_x = (wxCoord)gdk_event->x;
1272 event.m_y = (wxCoord)gdk_event->y;
1273
1274 // Some control don't have their own X window and thus cannot get
1275 // any events.
1276
1277 if (!g_captureWindow)
1278 {
1279 wxCoord x = event.m_x;
1280 wxCoord y = event.m_y;
1281 if (win->m_wxwindow)
1282 {
1283 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1284 x += pizza->xoffset;
1285 y += pizza->yoffset;
1286 }
1287
1288 wxNode *node = win->GetChildren().First();
1289 while (node)
1290 {
1291 wxWindow *child = (wxWindow*)node->Data();
1292
1293 node = node->Next();
1294 if (!child->IsShown())
1295 continue;
1296
1297 if (child->m_isStaticBox)
1298 {
1299 // wxStaticBox is transparent in the box itself
1300 int xx1 = child->m_x;
1301 int yy1 = child->m_y;
1302 int xx2 = child->m_x + child->m_width;
1303 int yy2 = child->m_x + child->m_height;
1304
1305 // left
1306 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1307 // right
1308 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1309 // top
1310 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1311 // bottom
1312 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1313 {
1314 win = child;
1315 event.m_x -= child->m_x;
1316 event.m_y -= child->m_y;
1317 break;
1318 }
1319
1320 }
1321 else
1322 {
1323 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1324 (child->m_x <= x) &&
1325 (child->m_y <= y) &&
1326 (child->m_x+child->m_width >= x) &&
1327 (child->m_y+child->m_height >= y))
1328 {
1329 win = child;
1330 event.m_x -= child->m_x;
1331 event.m_y -= child->m_y;
1332 break;
1333 }
1334 }
1335 }
1336 }
1337
1338 event.SetEventObject( win );
1339
1340 if (win->GetEventHandler()->ProcessEvent( event ))
1341 {
1342 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1343 return TRUE;
1344 }
1345
1346 return FALSE;
1347 }
1348
1349 //-----------------------------------------------------------------------------
1350 // "focus_in_event"
1351 //-----------------------------------------------------------------------------
1352
1353 static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1354 {
1355 DEBUG_MAIN_THREAD
1356
1357 if (g_isIdle)
1358 wxapp_install_idle_handler();
1359
1360 if (!win->m_hasVMT) return FALSE;
1361 if (g_blockEventsOnDrag) return FALSE;
1362
1363 switch ( g_sendActivateEvent )
1364 {
1365 case -1:
1366 // we've got focus from outside, synthtize wxActivateEvent
1367 g_sendActivateEvent = 1;
1368 break;
1369
1370 case 0:
1371 // another our window just lost focus, it was already ours before
1372 // - don't send any wxActivateEvent
1373 g_sendActivateEvent = -1;
1374 break;
1375 }
1376
1377 g_focusWindow = win;
1378
1379 /*
1380 printf( "OnSetFocus from " );
1381 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1382 printf( win->GetClassInfo()->GetClassName() );
1383 printf( " " );
1384 printf( WXSTRINGCAST win->GetLabel() );
1385 printf( ".\n" );
1386 */
1387
1388 wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
1389 if (panel)
1390 {
1391 panel->SetLastFocus(win);
1392 }
1393
1394 #ifdef HAVE_XIM
1395 if (win->m_ic)
1396 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1397 #endif
1398
1399 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1400 event.SetEventObject( win );
1401
1402 if (win->GetEventHandler()->ProcessEvent( event ))
1403 {
1404 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1405 return TRUE;
1406 }
1407
1408 return FALSE;
1409 }
1410
1411 //-----------------------------------------------------------------------------
1412 // "focus_out_event"
1413 //-----------------------------------------------------------------------------
1414
1415 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1416 {
1417 DEBUG_MAIN_THREAD
1418
1419 if (g_isIdle)
1420 wxapp_install_idle_handler();
1421
1422 if (!win->m_hasVMT) return FALSE;
1423 if (g_blockEventsOnDrag) return FALSE;
1424
1425 // if the focus goes out of our app alltogether, OnIdle() will send
1426 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1427 // g_sendActivateEvent to -1
1428 g_sendActivateEvent = 0;
1429
1430 g_focusWindow = (wxWindow *)NULL;
1431
1432 /*
1433 printf( "OnKillFocus from " );
1434 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1435 printf( win->GetClassInfo()->GetClassName() );
1436 printf( ".\n" );
1437 */
1438
1439 #ifdef HAVE_XIM
1440 if (win->m_ic)
1441 gdk_im_end();
1442 #endif
1443
1444 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1445 event.SetEventObject( win );
1446
1447 if (win->GetEventHandler()->ProcessEvent( event ))
1448 {
1449 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1450 return TRUE;
1451 }
1452
1453 return FALSE;
1454 }
1455
1456 //-----------------------------------------------------------------------------
1457 // "enter_notify_event"
1458 //-----------------------------------------------------------------------------
1459
1460 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1461 {
1462 DEBUG_MAIN_THREAD
1463
1464 if (g_isIdle)
1465 wxapp_install_idle_handler();
1466
1467 if (!win->m_hasVMT) return FALSE;
1468 if (g_blockEventsOnDrag) return FALSE;
1469
1470 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1471
1472 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1473 #if (GTK_MINOR_VERSION > 0)
1474 event.SetTimestamp( gdk_event->time );
1475 #endif
1476 event.SetEventObject( win );
1477
1478 int x = 0;
1479 int y = 0;
1480 GdkModifierType state = (GdkModifierType)0;
1481
1482 gdk_window_get_pointer( widget->window, &x, &y, &state );
1483
1484 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1485 event.m_controlDown = (state & GDK_CONTROL_MASK);
1486 event.m_altDown = (state & GDK_MOD1_MASK);
1487 event.m_metaDown = (state & GDK_MOD2_MASK);
1488 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1489 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1490 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1491
1492 event.m_x = x;
1493 event.m_y = y;
1494
1495 if (win->GetEventHandler()->ProcessEvent( event ))
1496 {
1497 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1498 return TRUE;
1499 }
1500
1501 return FALSE;
1502 }
1503
1504 //-----------------------------------------------------------------------------
1505 // "leave_notify_event"
1506 //-----------------------------------------------------------------------------
1507
1508 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1509 {
1510 DEBUG_MAIN_THREAD
1511
1512 if (g_isIdle)
1513 wxapp_install_idle_handler();
1514
1515 if (!win->m_hasVMT) return FALSE;
1516 if (g_blockEventsOnDrag) return FALSE;
1517
1518 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1519
1520 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1521 #if (GTK_MINOR_VERSION > 0)
1522 event.SetTimestamp( gdk_event->time );
1523 #endif
1524 event.SetEventObject( win );
1525
1526 int x = 0;
1527 int y = 0;
1528 GdkModifierType state = (GdkModifierType)0;
1529
1530 gdk_window_get_pointer( widget->window, &x, &y, &state );
1531
1532 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1533 event.m_controlDown = (state & GDK_CONTROL_MASK);
1534 event.m_altDown = (state & GDK_MOD1_MASK);
1535 event.m_metaDown = (state & GDK_MOD2_MASK);
1536 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1537 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1538 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1539
1540 event.m_x = x;
1541 event.m_y = y;
1542
1543 if (win->GetEventHandler()->ProcessEvent( event ))
1544 {
1545 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1546 return TRUE;
1547 }
1548
1549 return FALSE;
1550 }
1551
1552 //-----------------------------------------------------------------------------
1553 // "value_changed" from m_vAdjust
1554 //-----------------------------------------------------------------------------
1555
1556 static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1557 {
1558 DEBUG_MAIN_THREAD
1559
1560 if (g_isIdle)
1561 wxapp_install_idle_handler();
1562
1563 if (g_blockEventsOnDrag) return;
1564
1565 if (!win->m_hasVMT) return;
1566
1567 float diff = adjust->value - win->m_oldVerticalPos;
1568 if (fabs(diff) < 0.2) return;
1569
1570 win->m_oldVerticalPos = adjust->value;
1571
1572 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1573 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1574
1575 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1576 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1577 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1578 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1579 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1580
1581 int value = (int)(adjust->value+0.5);
1582
1583 wxScrollWinEvent event( command, value, wxVERTICAL );
1584 event.SetEventObject( win );
1585 win->GetEventHandler()->ProcessEvent( event );
1586 }
1587
1588 //-----------------------------------------------------------------------------
1589 // "value_changed" from m_hAdjust
1590 //-----------------------------------------------------------------------------
1591
1592 static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1593 {
1594 DEBUG_MAIN_THREAD
1595
1596 if (g_isIdle)
1597 wxapp_install_idle_handler();
1598
1599 if (g_blockEventsOnDrag) return;
1600 if (!win->m_hasVMT) return;
1601
1602 float diff = adjust->value - win->m_oldHorizontalPos;
1603 if (fabs(diff) < 0.2) return;
1604
1605 win->m_oldHorizontalPos = adjust->value;
1606
1607 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1608 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1609
1610 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1611 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1612 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1613 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1614 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1615
1616 int value = (int)(adjust->value+0.5);
1617
1618 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1619 event.SetEventObject( win );
1620 win->GetEventHandler()->ProcessEvent( event );
1621 }
1622
1623 //-----------------------------------------------------------------------------
1624 // "button_press_event" from scrollbar
1625 //-----------------------------------------------------------------------------
1626
1627 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1628 GdkEventButton *gdk_event,
1629 wxWindow *win)
1630 {
1631 DEBUG_MAIN_THREAD
1632
1633 if (g_isIdle)
1634 wxapp_install_idle_handler();
1635
1636 g_blockEventsOnScroll = TRUE;
1637 win->m_isScrolling = (gdk_event->window == widget->slider);
1638
1639 return FALSE;
1640 }
1641
1642 //-----------------------------------------------------------------------------
1643 // "button_release_event" from scrollbar
1644 //-----------------------------------------------------------------------------
1645
1646 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1647 GdkEventButton *WXUNUSED(gdk_event),
1648 wxWindow *win)
1649 {
1650 DEBUG_MAIN_THREAD
1651
1652 // don't test here as we can release the mouse while being over
1653 // a different window than the slider
1654 //
1655 // if (gdk_event->window != widget->slider) return FALSE;
1656
1657 g_blockEventsOnScroll = FALSE;
1658
1659 if (win->m_isScrolling)
1660 {
1661 wxEventType command = wxEVT_SCROLL_THUMBRELEASE;
1662 int value = -1;
1663 int dir = -1;
1664
1665 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1666 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1667 {
1668 value = (int)(win->m_hAdjust->value+0.5);
1669 dir = wxHORIZONTAL;
1670 }
1671 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1672 {
1673 value = (int)(win->m_vAdjust->value+0.5);
1674 dir = wxVERTICAL;
1675 }
1676
1677 wxScrollWinEvent event( command, value, dir );
1678 event.SetEventObject( win );
1679 win->GetEventHandler()->ProcessEvent( event );
1680 }
1681
1682 win->m_isScrolling = FALSE;
1683
1684 return FALSE;
1685 }
1686
1687 // ----------------------------------------------------------------------------
1688 // this wxWindowBase function is implemented here (in platform-specific file)
1689 // because it is static and so couldn't be made virtual
1690 // ----------------------------------------------------------------------------
1691
1692 wxWindow *wxWindowBase::FindFocus()
1693 {
1694 return g_focusWindow;
1695 }
1696
1697 //-----------------------------------------------------------------------------
1698 // "realize" from m_widget
1699 //-----------------------------------------------------------------------------
1700
1701 /* We cannot set colours and fonts before the widget has
1702 been realized, so we do this directly after realization. */
1703
1704 static gint
1705 gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
1706 {
1707 DEBUG_MAIN_THREAD
1708
1709 if (g_isIdle)
1710 wxapp_install_idle_handler();
1711
1712 if (win->m_delayedBackgroundColour)
1713 win->SetBackgroundColour( win->GetBackgroundColour() );
1714
1715 if (win->m_delayedForegroundColour)
1716 win->SetForegroundColour( win->GetForegroundColour() );
1717
1718 wxWindowCreateEvent event( win );
1719 event.SetEventObject( win );
1720 win->GetEventHandler()->ProcessEvent( event );
1721
1722 return FALSE;
1723 }
1724
1725 //-----------------------------------------------------------------------------
1726 // "size_allocate"
1727 //-----------------------------------------------------------------------------
1728
1729 static
1730 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
1731 GtkAllocation *WXUNUSED(alloc),
1732 wxWindow *win )
1733 {
1734 if (g_isIdle)
1735 wxapp_install_idle_handler();
1736
1737 if (!win->m_hasScrolling) return;
1738
1739 int client_width = 0;
1740 int client_height = 0;
1741 win->GetClientSize( &client_width, &client_height );
1742 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
1743 return;
1744
1745 win->m_oldClientWidth = client_width;
1746 win->m_oldClientHeight = client_height;
1747
1748 if (!win->m_nativeSizeEvent)
1749 {
1750 wxSizeEvent event( win->GetSize(), win->GetId() );
1751 event.SetEventObject( win );
1752 win->GetEventHandler()->ProcessEvent( event );
1753 }
1754 }
1755
1756
1757 #ifdef HAVE_XIM
1758 #define WXUNUSED_UNLESS_XIM(param) param
1759 #else
1760 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
1761 #endif
1762
1763 /* Resize XIM window */
1764
1765 static
1766 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
1767 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1768 wxWindow* WXUNUSED_UNLESS_XIM(win) )
1769 {
1770 if (g_isIdle)
1771 wxapp_install_idle_handler();
1772
1773 #ifdef HAVE_XIM
1774 if (!win->m_ic)
1775 return;
1776
1777 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
1778 {
1779 gint width, height;
1780
1781 gdk_window_get_size (widget->window, &width, &height);
1782 win->m_icattr->preedit_area.width = width;
1783 win->m_icattr->preedit_area.height = height;
1784 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
1785 }
1786 #endif // HAVE_XIM
1787 }
1788
1789 //-----------------------------------------------------------------------------
1790 // "realize" from m_wxwindow
1791 //-----------------------------------------------------------------------------
1792
1793 /* Initialize XIM support */
1794
1795 static gint
1796 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1797 wxWindow * WXUNUSED_UNLESS_XIM(win) )
1798 {
1799 if (g_isIdle)
1800 wxapp_install_idle_handler();
1801
1802 #ifdef HAVE_XIM
1803 if (win->m_ic) return FALSE;
1804 if (!widget) return FALSE;
1805 if (!gdk_im_ready()) return FALSE;
1806
1807 win->m_icattr = gdk_ic_attr_new();
1808 if (!win->m_icattr) return FALSE;
1809
1810 gint width, height;
1811 GdkEventMask mask;
1812 GdkColormap *colormap;
1813 GdkICAttr *attr = win->m_icattr;
1814 unsigned attrmask = GDK_IC_ALL_REQ;
1815 GdkIMStyle style;
1816 GdkIMStyle supported_style = (GdkIMStyle)
1817 (GDK_IM_PREEDIT_NONE |
1818 GDK_IM_PREEDIT_NOTHING |
1819 GDK_IM_PREEDIT_POSITION |
1820 GDK_IM_STATUS_NONE |
1821 GDK_IM_STATUS_NOTHING);
1822
1823 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1824 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
1825
1826 attr->style = style = gdk_im_decide_style (supported_style);
1827 attr->client_window = widget->window;
1828
1829 if ((colormap = gtk_widget_get_colormap (widget)) !=
1830 gtk_widget_get_default_colormap ())
1831 {
1832 attrmask |= GDK_IC_PREEDIT_COLORMAP;
1833 attr->preedit_colormap = colormap;
1834 }
1835
1836 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
1837 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
1838 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
1839 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
1840
1841 switch (style & GDK_IM_PREEDIT_MASK)
1842 {
1843 case GDK_IM_PREEDIT_POSITION:
1844 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1845 {
1846 g_warning ("over-the-spot style requires fontset");
1847 break;
1848 }
1849
1850 gdk_window_get_size (widget->window, &width, &height);
1851
1852 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
1853 attr->spot_location.x = 0;
1854 attr->spot_location.y = height;
1855 attr->preedit_area.x = 0;
1856 attr->preedit_area.y = 0;
1857 attr->preedit_area.width = width;
1858 attr->preedit_area.height = height;
1859 attr->preedit_fontset = widget->style->font;
1860
1861 break;
1862 }
1863
1864 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
1865
1866 if (win->m_ic == NULL)
1867 g_warning ("Can't create input context.");
1868 else
1869 {
1870 mask = gdk_window_get_events (widget->window);
1871 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
1872 gdk_window_set_events (widget->window, mask);
1873
1874 if (GTK_WIDGET_HAS_FOCUS(widget))
1875 gdk_im_begin (win->m_ic, widget->window);
1876 }
1877 #endif
1878
1879 return FALSE;
1880 }
1881
1882 //-----------------------------------------------------------------------------
1883 // InsertChild for wxWindow.
1884 //-----------------------------------------------------------------------------
1885
1886 /* Callback for wxWindow. This very strange beast has to be used because
1887 * C++ has no virtual methods in a constructor. We have to emulate a
1888 * virtual function here as wxNotebook requires a different way to insert
1889 * a child in it. I had opted for creating a wxNotebookPage window class
1890 * which would have made this superfluous (such in the MDI window system),
1891 * but no-one was listening to me... */
1892
1893 static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
1894 {
1895 /* the window might have been scrolled already, do we
1896 have to adapt the position */
1897 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
1898 child->m_x += pizza->xoffset;
1899 child->m_y += pizza->yoffset;
1900
1901 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
1902 GTK_WIDGET(child->m_widget),
1903 child->m_x,
1904 child->m_y,
1905 child->m_width,
1906 child->m_height );
1907 }
1908
1909 //-----------------------------------------------------------------------------
1910 // global functions
1911 //-----------------------------------------------------------------------------
1912
1913 wxWindow* wxGetActiveWindow()
1914 {
1915 return g_focusWindow;
1916 }
1917
1918 //-----------------------------------------------------------------------------
1919 // wxWindow
1920 //-----------------------------------------------------------------------------
1921
1922 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
1923
1924 void wxWindow::Init()
1925 {
1926 // common init
1927 InitBase();
1928
1929 // GTK specific
1930 m_widget = (GtkWidget *) NULL;
1931 m_wxwindow = (GtkWidget *) NULL;
1932
1933 // position/size
1934 m_x = 0;
1935 m_y = 0;
1936 m_width = 0;
1937 m_height = 0;
1938
1939 m_sizeSet = FALSE;
1940 m_hasVMT = FALSE;
1941 m_needParent = TRUE;
1942 m_isBeingDeleted = FALSE;
1943
1944 m_noExpose = FALSE;
1945 m_nativeSizeEvent = FALSE;
1946
1947 m_hasScrolling = FALSE;
1948 m_isScrolling = FALSE;
1949
1950 m_hAdjust = (GtkAdjustment*) NULL;
1951 m_vAdjust = (GtkAdjustment*) NULL;
1952 m_oldHorizontalPos = 0.0;
1953 m_oldVerticalPos = 0.0;
1954
1955 m_resizing = FALSE;
1956 m_widgetStyle = (GtkStyle*) NULL;
1957
1958 m_insertCallback = (wxInsertChildFunction) NULL;
1959
1960 m_isStaticBox = FALSE;
1961 m_isRadioButton = FALSE;
1962 m_isFrame = FALSE;
1963 m_acceptsFocus = FALSE;
1964
1965 m_cursor = *wxSTANDARD_CURSOR;
1966
1967 #ifdef HAVE_XIM
1968 m_ic = (GdkIC*) NULL;
1969 m_icattr = (GdkICAttr*) NULL;
1970 #endif
1971 }
1972
1973 wxWindow::wxWindow()
1974 {
1975 Init();
1976 }
1977
1978 wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
1979 const wxPoint &pos, const wxSize &size,
1980 long style, const wxString &name )
1981 {
1982 Init();
1983
1984 Create( parent, id, pos, size, style, name );
1985 }
1986
1987 bool wxWindow::Create( wxWindow *parent, wxWindowID id,
1988 const wxPoint &pos, const wxSize &size,
1989 long style, const wxString &name )
1990 {
1991 if (!PreCreation( parent, pos, size ) ||
1992 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
1993 {
1994 wxFAIL_MSG( wxT("wxWindow creation failed") );
1995 return FALSE;
1996 }
1997
1998 m_insertCallback = wxInsertChildInWindow;
1999
2000 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2001 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2002
2003 #ifdef __WXDEBUG__
2004 debug_focus_in( m_widget, wxT("wxWindow::m_widget"), name );
2005 #endif
2006
2007 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2008
2009 #ifdef __WXDEBUG__
2010 debug_focus_in( scrolledWindow->hscrollbar, wxT("wxWindow::hsrcollbar"), name );
2011 debug_focus_in( scrolledWindow->vscrollbar, wxT("wxWindow::vsrcollbar"), name );
2012 #endif
2013
2014 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2015 scroll_class->scrollbar_spacing = 0;
2016
2017 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2018
2019 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2020 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2021
2022 m_wxwindow = gtk_pizza_new();
2023
2024 #ifdef __WXDEBUG__
2025 debug_focus_in( m_wxwindow, wxT("wxWindow::m_wxwindow"), name );
2026 #endif
2027
2028 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2029
2030 #if (GTK_MINOR_VERSION > 0)
2031 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2032
2033 if (HasFlag(wxRAISED_BORDER))
2034 {
2035 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2036 }
2037 else if (HasFlag(wxSUNKEN_BORDER))
2038 {
2039 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2040 }
2041 else if (HasFlag(wxSIMPLE_BORDER))
2042 {
2043 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2044 }
2045 else
2046 {
2047 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2048 }
2049 #else // GTK_MINOR_VERSION == 0
2050 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2051
2052 if (HasFlag(wxRAISED_BORDER))
2053 {
2054 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2055 }
2056 else if (HasFlag(wxSUNKEN_BORDER))
2057 {
2058 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2059 }
2060 else
2061 {
2062 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2063 }
2064 #endif // GTK_MINOR_VERSION
2065
2066 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2067 m_acceptsFocus = TRUE;
2068
2069 #if (GTK_MINOR_VERSION == 0)
2070 // shut the viewport up
2071 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2072 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2073 #endif // GTK_MINOR_VERSION == 0
2074
2075 // I _really_ don't want scrollbars in the beginning
2076 m_vAdjust->lower = 0.0;
2077 m_vAdjust->upper = 1.0;
2078 m_vAdjust->value = 0.0;
2079 m_vAdjust->step_increment = 1.0;
2080 m_vAdjust->page_increment = 1.0;
2081 m_vAdjust->page_size = 5.0;
2082 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2083 m_hAdjust->lower = 0.0;
2084 m_hAdjust->upper = 1.0;
2085 m_hAdjust->value = 0.0;
2086 m_hAdjust->step_increment = 1.0;
2087 m_hAdjust->page_increment = 1.0;
2088 m_hAdjust->page_size = 5.0;
2089 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2090
2091 // these handlers block mouse events to any window during scrolling such as
2092 // motion events and prevent GTK and wxWindows from fighting over where the
2093 // slider should be
2094
2095 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2096 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2097
2098 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2099 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2100
2101 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2102 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2103
2104 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2105 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2106
2107 // these handlers get notified when screen updates are required either when
2108 // scrolling or when the window size (and therefore scrollbar configuration)
2109 // has changed
2110
2111 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2112 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2113 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2114 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2115
2116 gtk_widget_show( m_wxwindow );
2117
2118 if (m_parent)
2119 m_parent->DoAddChild( this );
2120
2121 PostCreation();
2122
2123 Show( TRUE );
2124
2125 return TRUE;
2126 }
2127
2128 wxWindow::~wxWindow()
2129 {
2130 m_isBeingDeleted = TRUE;
2131 m_hasVMT = FALSE;
2132
2133 if (m_widget)
2134 Show( FALSE );
2135
2136 DestroyChildren();
2137
2138 if (m_parent)
2139 m_parent->RemoveChild( this );
2140
2141 #ifdef HAVE_XIM
2142 if (m_ic)
2143 gdk_ic_destroy (m_ic);
2144 if (m_icattr)
2145 gdk_ic_attr_destroy (m_icattr);
2146 #endif
2147
2148 if (m_widgetStyle)
2149 {
2150 // don't delete if it's a pixmap theme style
2151 if (!m_widgetStyle->engine_data)
2152 gtk_style_unref( m_widgetStyle );
2153
2154 m_widgetStyle = (GtkStyle*) NULL;
2155 }
2156
2157 if (m_wxwindow)
2158 {
2159 gtk_widget_destroy( m_wxwindow );
2160 m_wxwindow = (GtkWidget*) NULL;
2161 }
2162
2163 if (m_widget)
2164 {
2165 gtk_widget_destroy( m_widget );
2166 m_widget = (GtkWidget*) NULL;
2167 }
2168 }
2169
2170 bool wxWindow::PreCreation( wxWindow *parent, const wxPoint &pos, const wxSize &size )
2171 {
2172 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2173
2174 /* this turns -1 into 20 so that a minimal window is
2175 visible even although -1,-1 has been given as the
2176 size of the window. the same trick is used in other
2177 ports and should make debugging easier */
2178 m_width = WidthDefault(size.x);
2179 m_height = HeightDefault(size.y);
2180
2181 m_x = (int)pos.x;
2182 m_y = (int)pos.y;
2183
2184 /* some reasonable defaults */
2185 if (!parent)
2186 {
2187 if (m_x == -1)
2188 {
2189 m_x = (gdk_screen_width () - m_width) / 2;
2190 if (m_x < 10) m_x = 10;
2191 }
2192 if (m_y == -1)
2193 {
2194 m_y = (gdk_screen_height () - m_height) / 2;
2195 if (m_y < 10) m_y = 10;
2196 }
2197 }
2198
2199 return TRUE;
2200 }
2201
2202 void wxWindow::PostCreation()
2203 {
2204 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2205
2206 if (m_wxwindow)
2207 {
2208 if (!m_noExpose)
2209 {
2210 /* these get reported to wxWindows -> wxPaintEvent */
2211 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2212 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2213
2214 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2215 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2216 }
2217
2218 #if (GTK_MINOR_VERSION > 0)
2219 /* these are called when the "sunken" or "raised" borders are drawn */
2220 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2221 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2222
2223 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2224 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2225 #endif
2226 }
2227
2228 if (m_wxwindow && m_needParent)
2229 {
2230 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
2231 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2232
2233 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
2234 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2235 }
2236 else
2237 {
2238 // For dialogs and frames, we are interested mainly in
2239 // m_widget's focus.
2240
2241 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
2242 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2243
2244 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
2245 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2246 }
2247
2248 GtkWidget *connect_widget = GetConnectWidget();
2249
2250 ConnectWidget( connect_widget );
2251
2252 /* We cannot set colours, fonts and cursors before the widget has
2253 been realized, so we do this directly after realization */
2254 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2255 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2256
2257 if (m_wxwindow)
2258 {
2259 /* Catch native resize events. */
2260 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2261 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2262
2263 /* Initialize XIM support. */
2264 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2265 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2266
2267 /* And resize XIM window. */
2268 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2269 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2270 }
2271
2272 m_hasVMT = TRUE;
2273 }
2274
2275 void wxWindow::ConnectWidget( GtkWidget *widget )
2276 {
2277 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2278 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2279
2280 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2281 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2282
2283 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2284 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2285
2286 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2287 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2288
2289 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2290 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2291
2292 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2293 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2294
2295 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2296 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2297 }
2298
2299 bool wxWindow::Destroy()
2300 {
2301 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2302
2303 m_hasVMT = FALSE;
2304
2305 return wxWindowBase::Destroy();
2306 }
2307
2308 void wxWindow::DoMoveWindow(int x, int y, int width, int height)
2309 {
2310 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2311 }
2312
2313 void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2314 {
2315 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2316 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindow::SetSize requires parent.\n") );
2317
2318 if (m_resizing) return; /* I don't like recursions */
2319 m_resizing = TRUE;
2320
2321 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2322 {
2323 /* don't set the size for children of wxNotebook, just take the values. */
2324 m_x = x;
2325 m_y = y;
2326 m_width = width;
2327 m_height = height;
2328 }
2329 else
2330 {
2331 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2332
2333 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2334 {
2335 if (x != -1) m_x = x + pizza->xoffset;
2336 if (y != -1) m_y = y + pizza->yoffset;
2337 if (width != -1) m_width = width;
2338 if (height != -1) m_height = height;
2339 }
2340 else
2341 {
2342 m_x = x + pizza->xoffset;
2343 m_y = y + pizza->yoffset;
2344 m_width = width;
2345 m_height = height;
2346 }
2347
2348 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2349 {
2350 if (width == -1) m_width = 80;
2351 }
2352
2353 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2354 {
2355 if (height == -1) m_height = 26;
2356 }
2357
2358 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2359 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2360 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2361 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2362
2363 int border = 0;
2364 int bottom_border = 0;
2365
2366 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2367 {
2368 /* the default button has a border around it */
2369 border = 6;
2370 bottom_border = 5;
2371 }
2372
2373 DoMoveWindow( m_x-border,
2374 m_y-border,
2375 m_width+2*border,
2376 m_height+border+bottom_border );
2377 }
2378
2379 if (m_hasScrolling)
2380 {
2381 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2382 }
2383
2384 /*
2385 wxPrintf( "OnSize sent from " );
2386 if (GetClassInfo() && GetClassInfo()->GetClassName())
2387 wxPrintf( GetClassInfo()->GetClassName() );
2388 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2389 */
2390
2391 if (!m_nativeSizeEvent)
2392 {
2393 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2394 event.SetEventObject( this );
2395 GetEventHandler()->ProcessEvent( event );
2396 }
2397
2398 m_resizing = FALSE;
2399 }
2400
2401 void wxWindow::OnInternalIdle()
2402 {
2403 if ( g_sendActivateEvent != -1 )
2404 {
2405 bool activate = g_sendActivateEvent != 0;
2406
2407 // do it only once
2408 g_sendActivateEvent = -1;
2409
2410 wxActivateEvent event(wxEVT_ACTIVATE, activate, GetId());
2411 event.SetEventObject(this);
2412
2413 (void)GetEventHandler()->ProcessEvent(event);
2414 }
2415
2416 wxCursor cursor = m_cursor;
2417 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2418
2419 if (cursor.Ok())
2420 {
2421 /* I now set the cursor anew in every OnInternalIdle call
2422 as setting the cursor in a parent window also effects the
2423 windows above so that checking for the current cursor is
2424 not possible. */
2425
2426 if (m_wxwindow)
2427 {
2428 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2429 if (window)
2430 gdk_window_set_cursor( window, cursor.GetCursor() );
2431
2432 if (!g_globalCursor.Ok())
2433 cursor = *wxSTANDARD_CURSOR;
2434
2435 window = m_widget->window;
2436 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2437 gdk_window_set_cursor( window, cursor.GetCursor() );
2438
2439 }
2440 else
2441 {
2442
2443 GdkWindow *window = m_widget->window;
2444 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2445 gdk_window_set_cursor( window, cursor.GetCursor() );
2446
2447 }
2448 }
2449
2450 UpdateWindowUI();
2451 }
2452
2453 void wxWindow::DoGetSize( int *width, int *height ) const
2454 {
2455 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2456
2457 if (width) (*width) = m_width;
2458 if (height) (*height) = m_height;
2459 }
2460
2461 void wxWindow::DoSetClientSize( int width, int height )
2462 {
2463 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2464
2465 if (!m_wxwindow)
2466 {
2467 SetSize( width, height );
2468 }
2469 else
2470 {
2471 int dw = 0;
2472 int dh = 0;
2473
2474 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2475 {
2476 /* when using GTK 1.2 we set the shadow border size to 2 */
2477 dw += 2 * 2;
2478 dh += 2 * 2;
2479 }
2480 if (HasFlag(wxSIMPLE_BORDER))
2481 {
2482 /* when using GTK 1.2 we set the simple border size to 1 */
2483 dw += 1 * 2;
2484 dh += 1 * 2;
2485 }
2486
2487 if (m_hasScrolling)
2488 {
2489 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2490
2491 GtkRequisition vscroll_req;
2492 vscroll_req.width = 2;
2493 vscroll_req.height = 2;
2494 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->vscrollbar)->klass )->size_request )
2495 (scroll_window->vscrollbar, &vscroll_req );
2496
2497 GtkRequisition hscroll_req;
2498 hscroll_req.width = 2;
2499 hscroll_req.height = 2;
2500 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->hscrollbar)->klass )->size_request )
2501 (scroll_window->hscrollbar, &hscroll_req );
2502
2503 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2504
2505 if (scroll_window->vscrollbar_visible)
2506 {
2507 dw += vscroll_req.width;
2508 dw += scroll_class->scrollbar_spacing;
2509 }
2510
2511 if (scroll_window->hscrollbar_visible)
2512 {
2513 dh += hscroll_req.height;
2514 dh += scroll_class->scrollbar_spacing;
2515 }
2516 }
2517
2518 SetSize( width+dw, height+dh );
2519 }
2520 }
2521
2522 void wxWindow::DoGetClientSize( int *width, int *height ) const
2523 {
2524 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2525
2526 if (!m_wxwindow)
2527 {
2528 if (width) (*width) = m_width;
2529 if (height) (*height) = m_height;
2530 }
2531 else
2532 {
2533 int dw = 0;
2534 int dh = 0;
2535
2536 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2537 {
2538 /* when using GTK 1.2 we set the shadow border size to 2 */
2539 dw += 2 * 2;
2540 dh += 2 * 2;
2541 }
2542 if (HasFlag(wxSIMPLE_BORDER))
2543 {
2544 /* when using GTK 1.2 we set the simple border size to 1 */
2545 dw += 1 * 2;
2546 dh += 1 * 2;
2547 }
2548
2549 if (m_hasScrolling)
2550 {
2551 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2552
2553 GtkRequisition vscroll_req;
2554 vscroll_req.width = 2;
2555 vscroll_req.height = 2;
2556 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->vscrollbar)->klass )->size_request )
2557 (scroll_window->vscrollbar, &vscroll_req );
2558
2559 GtkRequisition hscroll_req;
2560 hscroll_req.width = 2;
2561 hscroll_req.height = 2;
2562 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->hscrollbar)->klass )->size_request )
2563 (scroll_window->hscrollbar, &hscroll_req );
2564
2565 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2566
2567 if (scroll_window->vscrollbar_visible)
2568 {
2569 dw += vscroll_req.width;
2570 dw += scroll_class->scrollbar_spacing;
2571 }
2572
2573 if (scroll_window->hscrollbar_visible)
2574 {
2575 dh += hscroll_req.height;
2576 dh += scroll_class->scrollbar_spacing;
2577 }
2578 }
2579
2580 if (width) (*width) = m_width - dw;
2581 if (height) (*height) = m_height - dh;
2582 }
2583 }
2584
2585 void wxWindow::DoGetPosition( int *x, int *y ) const
2586 {
2587 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2588
2589 int dx = 0;
2590 int dy = 0;
2591 if (m_parent && m_parent->m_wxwindow)
2592 {
2593 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2594 dx = pizza->xoffset;
2595 dy = pizza->yoffset;
2596 }
2597
2598 if (x) (*x) = m_x - dx;
2599 if (y) (*y) = m_y - dy;
2600 }
2601
2602 void wxWindow::DoClientToScreen( int *x, int *y ) const
2603 {
2604 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2605
2606 if (!m_widget->window) return;
2607
2608 GdkWindow *source = (GdkWindow *) NULL;
2609 if (m_wxwindow)
2610 source = GTK_PIZZA(m_wxwindow)->bin_window;
2611 else
2612 source = m_widget->window;
2613
2614 int org_x = 0;
2615 int org_y = 0;
2616 gdk_window_get_origin( source, &org_x, &org_y );
2617
2618 if (!m_wxwindow)
2619 {
2620 if (GTK_WIDGET_NO_WINDOW (m_widget))
2621 {
2622 org_x += m_widget->allocation.x;
2623 org_y += m_widget->allocation.y;
2624 }
2625 }
2626
2627 if (x) *x += org_x;
2628 if (y) *y += org_y;
2629 }
2630
2631 void wxWindow::DoScreenToClient( int *x, int *y ) const
2632 {
2633 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2634
2635 if (!m_widget->window) return;
2636
2637 GdkWindow *source = (GdkWindow *) NULL;
2638 if (m_wxwindow)
2639 source = GTK_PIZZA(m_wxwindow)->bin_window;
2640 else
2641 source = m_widget->window;
2642
2643 int org_x = 0;
2644 int org_y = 0;
2645 gdk_window_get_origin( source, &org_x, &org_y );
2646
2647 if (!m_wxwindow)
2648 {
2649 if (GTK_WIDGET_NO_WINDOW (m_widget))
2650 {
2651 org_x += m_widget->allocation.x;
2652 org_y += m_widget->allocation.y;
2653 }
2654 }
2655
2656 if (x) *x -= org_x;
2657 if (y) *y -= org_y;
2658 }
2659
2660 bool wxWindow::Show( bool show )
2661 {
2662 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2663
2664 if (!wxWindowBase::Show(show))
2665 {
2666 // nothing to do
2667 return FALSE;
2668 }
2669
2670 if (show)
2671 gtk_widget_show( m_widget );
2672 else
2673 gtk_widget_hide( m_widget );
2674
2675 return TRUE;
2676 }
2677
2678 bool wxWindow::Enable( bool enable )
2679 {
2680 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2681
2682 if (!wxWindowBase::Enable(enable))
2683 {
2684 // nothing to do
2685 return FALSE;
2686 }
2687
2688 gtk_widget_set_sensitive( m_widget, enable );
2689 if ( m_wxwindow )
2690 gtk_widget_set_sensitive( m_wxwindow, enable );
2691
2692 return TRUE;
2693 }
2694
2695 int wxWindow::GetCharHeight() const
2696 {
2697 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
2698
2699 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2700
2701 GdkFont *font = m_font.GetInternalFont( 1.0 );
2702
2703 return font->ascent + font->descent;
2704 }
2705
2706 int wxWindow::GetCharWidth() const
2707 {
2708 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
2709
2710 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
2711
2712 GdkFont *font = m_font.GetInternalFont( 1.0 );
2713
2714 return gdk_string_width( font, "H" );
2715 }
2716
2717 void wxWindow::GetTextExtent( const wxString& string,
2718 int *x,
2719 int *y,
2720 int *descent,
2721 int *externalLeading,
2722 const wxFont *theFont ) const
2723 {
2724 wxFont fontToUse = m_font;
2725 if (theFont) fontToUse = *theFont;
2726
2727 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2728
2729 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
2730 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
2731 if (y) (*y) = font->ascent + font->descent;
2732 if (descent) (*descent) = font->descent;
2733 if (externalLeading) (*externalLeading) = 0; // ??
2734 }
2735
2736 void wxWindow::SetFocus()
2737 {
2738 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2739
2740 if (m_wxwindow)
2741 {
2742 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
2743 gtk_widget_grab_focus (m_wxwindow);
2744 return;
2745 }
2746
2747 if (m_widget)
2748 {
2749 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
2750 {
2751 gtk_widget_grab_focus (m_widget);
2752 }
2753 else if (GTK_IS_CONTAINER(m_widget))
2754 {
2755 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
2756 }
2757 else
2758 {
2759 // ?
2760 }
2761 }
2762 }
2763
2764 bool wxWindow::AcceptsFocus() const
2765 {
2766 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
2767 }
2768
2769 bool wxWindow::Reparent( wxWindowBase *newParentBase )
2770 {
2771 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2772
2773 wxWindow *oldParent = m_parent,
2774 *newParent = (wxWindow *)newParentBase;
2775
2776 wxASSERT( GTK_IS_WIDGET(m_widget) );
2777
2778 if ( !wxWindowBase::Reparent(newParent) )
2779 return FALSE;
2780
2781 wxASSERT( GTK_IS_WIDGET(m_widget) );
2782
2783 /* prevent GTK from deleting the widget arbitrarily */
2784 gtk_widget_ref( m_widget );
2785
2786 if (oldParent)
2787 {
2788 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
2789 }
2790
2791 wxASSERT( GTK_IS_WIDGET(m_widget) );
2792
2793 if (newParent)
2794 {
2795 /* insert GTK representation */
2796 (*(newParent->m_insertCallback))(newParent, this);
2797 }
2798
2799 /* reverse: prevent GTK from deleting the widget arbitrarily */
2800 gtk_widget_unref( m_widget );
2801
2802 return TRUE;
2803 }
2804
2805 void wxWindow::DoAddChild(wxWindow *child)
2806 {
2807 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2808
2809 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
2810
2811 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
2812
2813 /* add to list */
2814 AddChild( child );
2815
2816 /* insert GTK representation */
2817 (*m_insertCallback)(this, child);
2818 }
2819
2820 void wxWindow::Raise()
2821 {
2822 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2823
2824 if (!m_widget->window) return;
2825
2826 gdk_window_raise( m_widget->window );
2827 }
2828
2829 void wxWindow::Lower()
2830 {
2831 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2832
2833 if (!m_widget->window) return;
2834
2835 gdk_window_lower( m_widget->window );
2836 }
2837
2838 bool wxWindow::SetCursor( const wxCursor &cursor )
2839 {
2840 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2841
2842 return wxWindowBase::SetCursor( cursor );
2843 }
2844
2845 void wxWindow::WarpPointer( int x, int y )
2846 {
2847 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2848
2849 /* we provide this function ourselves as it is
2850 missing in GDK (top of this file) */
2851
2852 GdkWindow *window = (GdkWindow*) NULL;
2853 if (m_wxwindow)
2854 window = GTK_PIZZA(m_wxwindow)->bin_window;
2855 else
2856 window = GetConnectWidget()->window;
2857
2858 if (window)
2859 gdk_window_warp_pointer( window, x, y );
2860 }
2861
2862 void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
2863 {
2864 if (!m_widget) return;
2865 if (!m_widget->window) return;
2866
2867 if (eraseBackground && m_wxwindow && m_wxwindow->window)
2868 {
2869 if (rect)
2870 {
2871 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
2872 rect->x, rect->y,
2873 rect->width, rect->height );
2874 }
2875 else
2876 {
2877 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
2878 }
2879 }
2880
2881 /* there is no GTK equivalent of "draw only, don't clear" so we
2882 invent our own in the GtkPizza widget */
2883
2884 if (!rect)
2885 {
2886 if (m_wxwindow)
2887 {
2888 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2889 gboolean old_clear = pizza->clear_on_draw;
2890 gtk_pizza_set_clear( pizza, FALSE );
2891
2892 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
2893
2894 gtk_pizza_set_clear( pizza, old_clear );
2895 }
2896 else
2897 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
2898 }
2899 else
2900 {
2901 GdkRectangle gdk_rect;
2902 gdk_rect.x = rect->x;
2903 gdk_rect.y = rect->y;
2904 gdk_rect.width = rect->width;
2905 gdk_rect.height = rect->height;
2906
2907 if (m_wxwindow)
2908 {
2909 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2910 gboolean old_clear = pizza->clear_on_draw;
2911 gtk_pizza_set_clear( pizza, FALSE );
2912
2913 gtk_widget_draw( m_wxwindow, &gdk_rect );
2914
2915 gtk_pizza_set_clear( pizza, old_clear );
2916 }
2917 else
2918 gtk_widget_draw( m_widget, &gdk_rect );
2919 }
2920 }
2921
2922 void wxWindow::Clear()
2923 {
2924 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
2925
2926 if (!m_widget->window) return;
2927
2928 if (m_wxwindow && m_wxwindow->window)
2929 {
2930 // gdk_window_clear( m_wxwindow->window );
2931 }
2932 }
2933
2934 #if wxUSE_TOOLTIPS
2935 void wxWindow::DoSetToolTip( wxToolTip *tip )
2936 {
2937 wxWindowBase::DoSetToolTip(tip);
2938
2939 if (m_tooltip)
2940 m_tooltip->Apply( this );
2941 }
2942
2943 void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
2944 {
2945 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
2946 }
2947 #endif // wxUSE_TOOLTIPS
2948
2949 bool wxWindow::SetBackgroundColour( const wxColour &colour )
2950 {
2951 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
2952
2953 if (!wxWindowBase::SetBackgroundColour(colour))
2954 {
2955 // don't leave if the GTK widget has just
2956 // been realized
2957 if (!m_delayedBackgroundColour) return FALSE;
2958 }
2959
2960 GdkWindow *window = (GdkWindow*) NULL;
2961 if (m_wxwindow)
2962 window = GTK_PIZZA(m_wxwindow)->bin_window;
2963 else
2964 window = GetConnectWidget()->window;
2965
2966 if (!window)
2967 {
2968 // indicate that a new style has been set
2969 // but it couldn't get applied as the
2970 // widget hasn't been realized yet.
2971 m_delayedBackgroundColour = TRUE;
2972 }
2973
2974 if ((m_wxwindow) &&
2975 (m_wxwindow->window) &&
2976 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
2977 {
2978 /* wxMSW doesn't clear the window here. I don't do that either to
2979 provide compatibility. call Clear() to do the job. */
2980
2981 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
2982 gdk_window_set_background( window, m_backgroundColour.GetColor() );
2983 }
2984
2985 ApplyWidgetStyle();
2986
2987 return TRUE;
2988 }
2989
2990 bool wxWindow::SetForegroundColour( const wxColour &colour )
2991 {
2992 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
2993
2994 if (!wxWindowBase::SetForegroundColour(colour))
2995 {
2996 // don't leave if the GTK widget has just
2997 // been realized
2998 if (!m_delayedForegroundColour) return FALSE;
2999 }
3000
3001 GdkWindow *window = (GdkWindow*) NULL;
3002 if (m_wxwindow)
3003 window = GTK_PIZZA(m_wxwindow)->bin_window;
3004 else
3005 window = GetConnectWidget()->window;
3006
3007 if (!window)
3008 {
3009 // indicate that a new style has been set
3010 // but it couldn't get applied as the
3011 // widget hasn't been realized yet.
3012 m_delayedForegroundColour = TRUE;
3013 }
3014
3015 ApplyWidgetStyle();
3016
3017 return TRUE;
3018 }
3019
3020 GtkStyle *wxWindow::GetWidgetStyle()
3021 {
3022 if (m_widgetStyle)
3023 {
3024 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3025 remake->klass = m_widgetStyle->klass;
3026
3027 gtk_style_unref( m_widgetStyle );
3028 m_widgetStyle = remake;
3029 }
3030 else
3031 {
3032 GtkStyle *def = gtk_rc_get_style( m_widget );
3033
3034 if (!def)
3035 def = gtk_widget_get_default_style();
3036
3037 m_widgetStyle = gtk_style_copy( def );
3038 m_widgetStyle->klass = def->klass;
3039 }
3040
3041 return m_widgetStyle;
3042 }
3043
3044 void wxWindow::SetWidgetStyle()
3045 {
3046 if (m_widget->style->engine_data)
3047 {
3048 static bool s_warningPrinted = FALSE;
3049 if (!s_warningPrinted)
3050 {
3051 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3052 s_warningPrinted = TRUE;
3053 }
3054 m_widgetStyle = m_widget->style;
3055 return;
3056 }
3057
3058 GtkStyle *style = GetWidgetStyle();
3059
3060 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3061 {
3062 gdk_font_unref( style->font );
3063 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3064 }
3065
3066 if (m_foregroundColour.Ok())
3067 {
3068 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3069 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3070 {
3071 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3072 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3073 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3074 }
3075 }
3076
3077 if (m_backgroundColour.Ok())
3078 {
3079 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3080 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3081 {
3082 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3083 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3084 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3085 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3086 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3087 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3088 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3089 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3090 }
3091 }
3092 }
3093
3094 void wxWindow::ApplyWidgetStyle()
3095 {
3096 }
3097
3098 //-----------------------------------------------------------------------------
3099 // Pop-up menu stuff
3100 //-----------------------------------------------------------------------------
3101
3102 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3103 {
3104 *is_waiting = FALSE;
3105 }
3106
3107 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
3108 {
3109 menu->SetInvokingWindow( win );
3110 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3111 while (node)
3112 {
3113 wxMenuItem *menuitem = node->GetData();
3114 if (menuitem->IsSubMenu())
3115 {
3116 SetInvokingWindow( menuitem->GetSubMenu(), win );
3117 }
3118
3119 node = node->GetNext();
3120 }
3121 }
3122
3123 static gint gs_pop_x = 0;
3124 static gint gs_pop_y = 0;
3125
3126 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3127 gint *x, gint *y,
3128 wxWindow *win )
3129 {
3130 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3131 *x = gs_pop_x;
3132 *y = gs_pop_y;
3133 }
3134
3135 bool wxWindow::DoPopupMenu( wxMenu *menu, int x, int y )
3136 {
3137 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3138
3139 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3140
3141 SetInvokingWindow( menu, this );
3142
3143 menu->UpdateUI();
3144
3145 gs_pop_x = x;
3146 gs_pop_y = y;
3147
3148 bool is_waiting = TRUE;
3149
3150 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3151 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3152
3153 gtk_menu_popup(
3154 GTK_MENU(menu->m_menu),
3155 (GtkWidget *) NULL, // parent menu shell
3156 (GtkWidget *) NULL, // parent menu item
3157 (GtkMenuPositionFunc) pop_pos_callback,
3158 (gpointer) this, // client data
3159 0, // button used to activate it
3160 gs_timeLastClick // the time of activation
3161 );
3162
3163 while (is_waiting)
3164 {
3165 while (gtk_events_pending())
3166 gtk_main_iteration();
3167 }
3168
3169 return TRUE;
3170 }
3171
3172 #if wxUSE_DRAG_AND_DROP
3173
3174 void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
3175 {
3176 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3177
3178 GtkWidget *dnd_widget = GetConnectWidget();
3179
3180 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3181
3182 if (m_dropTarget) delete m_dropTarget;
3183 m_dropTarget = dropTarget;
3184
3185 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3186 }
3187
3188 #endif // wxUSE_DRAG_AND_DROP
3189
3190 GtkWidget* wxWindow::GetConnectWidget()
3191 {
3192 GtkWidget *connect_widget = m_widget;
3193 if (m_wxwindow) connect_widget = m_wxwindow;
3194
3195 return connect_widget;
3196 }
3197
3198 bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
3199 {
3200 if (m_wxwindow)
3201 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3202
3203 return (window == m_widget->window);
3204 }
3205
3206 bool wxWindow::SetFont( const wxFont &font )
3207 {
3208 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3209
3210 if (!wxWindowBase::SetFont(font))
3211 {
3212 return FALSE;
3213 }
3214
3215 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3216 if ( sysbg == m_backgroundColour )
3217 {
3218 m_backgroundColour = wxNullColour;
3219 ApplyWidgetStyle();
3220 m_backgroundColour = sysbg;
3221 }
3222 else
3223 {
3224 ApplyWidgetStyle();
3225 }
3226
3227 return TRUE;
3228 }
3229
3230 void wxWindow::CaptureMouse()
3231 {
3232 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3233
3234 wxCHECK_RET( g_captureWindow == NULL, wxT("CaptureMouse called twice") );
3235
3236 GdkWindow *window = (GdkWindow*) NULL;
3237 if (m_wxwindow)
3238 window = GTK_PIZZA(m_wxwindow)->bin_window;
3239 else
3240 window = GetConnectWidget()->window;
3241
3242 if (!window) return;
3243
3244 gdk_pointer_grab( window, FALSE,
3245 (GdkEventMask)
3246 (GDK_BUTTON_PRESS_MASK |
3247 GDK_BUTTON_RELEASE_MASK |
3248 GDK_POINTER_MOTION_HINT_MASK |
3249 GDK_POINTER_MOTION_MASK),
3250 (GdkWindow *) NULL,
3251 m_cursor.GetCursor(),
3252 (guint32)GDK_CURRENT_TIME );
3253 g_captureWindow = this;
3254 }
3255
3256 void wxWindow::ReleaseMouse()
3257 {
3258 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3259
3260 wxCHECK_RET( g_captureWindow, wxT("ReleaseMouse called twice") );
3261
3262 GdkWindow *window = (GdkWindow*) NULL;
3263 if (m_wxwindow)
3264 window = GTK_PIZZA(m_wxwindow)->bin_window;
3265 else
3266 window = GetConnectWidget()->window;
3267
3268 if (!window)
3269 return;
3270
3271 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3272 g_captureWindow = (wxWindow*) NULL;
3273 }
3274
3275 bool wxWindow::IsRetained() const
3276 {
3277 return FALSE;
3278 }
3279
3280 void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3281 int range, bool refresh )
3282 {
3283 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3284
3285 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3286
3287 m_hasScrolling = TRUE;
3288
3289 if (orient == wxHORIZONTAL)
3290 {
3291 float fpos = (float)pos;
3292 float frange = (float)range;
3293 float fthumb = (float)thumbVisible;
3294 if (fpos > frange-fthumb) fpos = frange-fthumb;
3295 if (fpos < 0.0) fpos = 0.0;
3296
3297 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3298 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3299 {
3300 SetScrollPos( orient, pos, refresh );
3301 return;
3302 }
3303
3304 m_oldHorizontalPos = fpos;
3305
3306 m_hAdjust->lower = 0.0;
3307 m_hAdjust->upper = frange;
3308 m_hAdjust->value = fpos;
3309 m_hAdjust->step_increment = 1.0;
3310 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3311 m_hAdjust->page_size = fthumb;
3312 }
3313 else
3314 {
3315 float fpos = (float)pos;
3316 float frange = (float)range;
3317 float fthumb = (float)thumbVisible;
3318 if (fpos > frange-fthumb) fpos = frange-fthumb;
3319 if (fpos < 0.0) fpos = 0.0;
3320
3321 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3322 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3323 {
3324 SetScrollPos( orient, pos, refresh );
3325 return;
3326 }
3327
3328 m_oldVerticalPos = fpos;
3329
3330 m_vAdjust->lower = 0.0;
3331 m_vAdjust->upper = frange;
3332 m_vAdjust->value = fpos;
3333 m_vAdjust->step_increment = 1.0;
3334 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3335 m_vAdjust->page_size = fthumb;
3336 }
3337
3338 if (orient == wxHORIZONTAL)
3339 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3340 else
3341 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3342 }
3343
3344 void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3345 {
3346 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3347
3348 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3349
3350 if (orient == wxHORIZONTAL)
3351 {
3352 float fpos = (float)pos;
3353 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3354 if (fpos < 0.0) fpos = 0.0;
3355 m_oldHorizontalPos = fpos;
3356
3357 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3358 m_hAdjust->value = fpos;
3359 }
3360 else
3361 {
3362 float fpos = (float)pos;
3363 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3364 if (fpos < 0.0) fpos = 0.0;
3365 m_oldVerticalPos = fpos;
3366
3367 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3368 m_vAdjust->value = fpos;
3369 }
3370
3371 if (m_wxwindow->window)
3372 {
3373 if (orient == wxHORIZONTAL)
3374 {
3375 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3376 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3377
3378 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3379
3380 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3381 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3382 }
3383 else
3384 {
3385 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3386 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3387
3388 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3389
3390 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3391 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3392 }
3393 }
3394 }
3395
3396 int wxWindow::GetScrollThumb( int orient ) const
3397 {
3398 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3399
3400 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3401
3402 if (orient == wxHORIZONTAL)
3403 return (int)(m_hAdjust->page_size+0.5);
3404 else
3405 return (int)(m_vAdjust->page_size+0.5);
3406 }
3407
3408 int wxWindow::GetScrollPos( int orient ) const
3409 {
3410 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3411
3412 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3413
3414 if (orient == wxHORIZONTAL)
3415 return (int)(m_hAdjust->value+0.5);
3416 else
3417 return (int)(m_vAdjust->value+0.5);
3418 }
3419
3420 int wxWindow::GetScrollRange( int orient ) const
3421 {
3422 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3423
3424 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3425
3426 if (orient == wxHORIZONTAL)
3427 return (int)(m_hAdjust->upper+0.5);
3428 else
3429 return (int)(m_vAdjust->upper+0.5);
3430 }
3431
3432 void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3433 {
3434 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3435
3436 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3437
3438 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3439 }