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