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