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