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