]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/minifram.cpp
Fix memory leak when a spacer is added, and crash when a window is added before wxSiz...
[wxWidgets.git] / src / gtk1 / minifram.cpp
CommitLineData
b2b3ccc5
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: minifram.cpp
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
b2b3ccc5
RR
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "minifram.h"
b2b3ccc5
RR
12#endif
13
14f355c2
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
b2b3ccc5 17#include "wx/minifram.h"
dcf924a3
RR
18
19#if wxUSE_MINIFRAME
20
b2b3ccc5
RR
21#include "wx/dcscreen.h"
22
83624f79
RR
23#include "gtk/gtk.h"
24#include "wx/gtk/win_gtk.h"
fab591c5 25#include "wx/gtk/private.h"
83624f79 26
5e7e9e1b
RR
27#include <gdk/gdk.h>
28#include <gdk/gdkprivate.h>
29#include <gdk/gdkx.h>
32a95f9f 30
acfd422a
RR
31//-----------------------------------------------------------------------------
32// idle system
33//-----------------------------------------------------------------------------
34
35extern void wxapp_install_idle_handler();
36extern bool g_isIdle;
37
32a95f9f
RR
38//-----------------------------------------------------------------------------
39// data
40//-----------------------------------------------------------------------------
41
8480b297
RR
42extern bool g_blockEventsOnDrag;
43extern bool g_blockEventsOnScroll;
c2fa61e8 44extern GtkWidget *wxGetRootWindow();
32a95f9f 45
b2b3ccc5 46//-----------------------------------------------------------------------------
32a95f9f
RR
47// local functions
48//-----------------------------------------------------------------------------
49
50/* draw XOR rectangle when moving mine frame around */
51
52static void DrawFrame( GtkWidget *widget, int x, int y, int w, int h )
53{
c2fa61e8 54 int org_x = 0;
32a95f9f
RR
55 int org_y = 0;
56 gdk_window_get_origin( widget->window, &org_x, &org_y );
57 x += org_x;
58 y += org_y;
59
60 GdkGC *gc = gdk_gc_new( GDK_ROOT_PARENT() );
61 gdk_gc_set_subwindow( gc, GDK_INCLUDE_INFERIORS );
62 gdk_gc_set_function( gc, GDK_INVERT );
c2fa61e8 63
32a95f9f
RR
64 gdk_draw_rectangle( GDK_ROOT_PARENT(), gc, FALSE, x, y, w, h );
65 gdk_gc_unref( gc );
66}
67
68//-----------------------------------------------------------------------------
69// "expose_event" of m_mainWidget
70//-----------------------------------------------------------------------------
71
865bb325 72extern "C" {
32a95f9f
RR
73static void gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxFrame *win )
74{
acfd422a
RR
75 if (g_isIdle) wxapp_install_idle_handler();
76
a2053b27 77 if (!win->m_hasVMT) return;
32a95f9f 78 if (gdk_event->count > 0) return;
c2fa61e8 79
da048e3d 80 GtkPizza *pizza = GTK_PIZZA(widget);
c2fa61e8
RD
81
82 gtk_draw_shadow( widget->style,
da048e3d 83 pizza->bin_window,
f03fc89f
VZ
84 GTK_STATE_NORMAL,
85 GTK_SHADOW_OUT,
86 0, 0,
a2053b27 87 win->m_width, win->m_height );
b9a535f5 88
ba718523 89 if (!win->GetTitle().IsEmpty() &&
c2fa61e8
RD
90 ((win->GetWindowStyle() & wxCAPTION) ||
91 (win->GetWindowStyle() & wxTINY_CAPTION_HORIZ) ||
f03fc89f 92 (win->GetWindowStyle() & wxTINY_CAPTION_VERT)))
b9a535f5 93 {
ba718523
RR
94 wxClientDC dc(win);
95 dc.SetFont( *wxSMALL_FONT );
96 int height = dc.GetCharHeight();
97
da048e3d 98 GdkGC *gc = gdk_gc_new( pizza->bin_window );
b9a535f5 99 gdk_gc_set_foreground( gc, &widget->style->bg[GTK_STATE_SELECTED] );
c2fa61e8
RD
100 gdk_draw_rectangle( pizza->bin_window, gc, TRUE,
101 3,
102 3,
5d5b3a40 103 win->m_width - 7,
ba718523 104 height+1 );
b9a535f5 105 gdk_gc_unref( gc );
ba718523
RR
106
107 // Hack alert
108 dc.m_window = pizza->bin_window;
109 dc.SetTextForeground( *wxWHITE );
110 dc.DrawText( win->GetTitle(), 6, 3 );
b9a535f5 111 }
32a95f9f 112}
865bb325 113}
32a95f9f
RR
114
115//-----------------------------------------------------------------------------
116// "draw" of m_mainWidget
117//-----------------------------------------------------------------------------
118
ba718523 119#ifndef __WXGTK20__
865bb325 120extern "C" {
32a95f9f
RR
121static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxFrame *win )
122{
acfd422a
RR
123 if (g_isIdle) wxapp_install_idle_handler();
124
a2053b27 125 if (!win->m_hasVMT) return;
c2fa61e8 126
da048e3d 127 GtkPizza *pizza = GTK_PIZZA(widget);
c2fa61e8
RD
128
129 gtk_draw_shadow( widget->style,
da048e3d 130 pizza->bin_window,
f03fc89f
VZ
131 GTK_STATE_NORMAL,
132 GTK_SHADOW_OUT,
133 0, 0,
a2053b27 134 win->m_width, win->m_height );
c2fa61e8 135
b9a535f5 136 if (!win->m_title.IsEmpty() &&
c2fa61e8
RD
137 ((win->GetWindowStyle() & wxCAPTION) ||
138 (win->GetWindowStyle() & wxTINY_CAPTION_HORIZ) ||
f03fc89f 139 (win->GetWindowStyle() & wxTINY_CAPTION_VERT)))
b9a535f5 140 {
ba718523
RR
141 wxClientDC dc(win);
142 dc.SetFont( *wxSMALL_FONT );
143 int height = dc.GetCharHeight();
144
da048e3d 145 GdkGC *gc = gdk_gc_new( pizza->bin_window );
b9a535f5 146 gdk_gc_set_foreground( gc, &widget->style->bg[GTK_STATE_SELECTED] );
c2fa61e8
RD
147 gdk_draw_rectangle( pizza->bin_window, gc, TRUE,
148 3,
5d5b3a40
RR
149 3,
150 win->m_width - 7,
ba718523 151 height+1 );
b9a535f5 152 gdk_gc_unref( gc );
ba718523
RR
153
154 // Hack alert
155 dc.m_window = pizza->bin_window;
156 dc.SetTextForeground( *wxWHITE );
157 dc.DrawText( win->GetTitle(), 6, 3 );
b9a535f5 158 }
32a95f9f 159}
865bb325 160}
ba718523 161#endif
32a95f9f
RR
162
163//-----------------------------------------------------------------------------
164// "button_press_event" of m_mainWidget
165//-----------------------------------------------------------------------------
166
865bb325 167extern "C" {
32a95f9f
RR
168static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
169{
acfd422a
RR
170 if (g_isIdle) wxapp_install_idle_handler();
171
a2053b27 172 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
173 if (g_blockEventsOnDrag) return TRUE;
174 if (g_blockEventsOnScroll) return TRUE;
175
176 if (win->m_isDragging) return TRUE;
177
2c990ec0
RR
178 GtkPizza *pizza = GTK_PIZZA(widget);
179 if (gdk_event->window != pizza->bin_window) return TRUE;
ba718523
RR
180
181 wxClientDC dc(win);
182 dc.SetFont( *wxSMALL_FONT );
183 int height = dc.GetCharHeight() + 1;
2c990ec0 184
2c990ec0
RR
185 if (gdk_event->y > height) return TRUE;
186
4dcaf11a 187 gdk_window_raise( win->m_widget->window );
c2fa61e8 188
32a95f9f
RR
189 gdk_pointer_grab( widget->window, FALSE,
190 (GdkEventMask)
191 (GDK_BUTTON_PRESS_MASK |
192 GDK_BUTTON_RELEASE_MASK |
f03fc89f 193 GDK_POINTER_MOTION_MASK |
32a95f9f 194 GDK_POINTER_MOTION_HINT_MASK |
f03fc89f 195 GDK_BUTTON_MOTION_MASK |
32a95f9f
RR
196 GDK_BUTTON1_MOTION_MASK),
197 (GdkWindow *) NULL,
198 (GdkCursor *) NULL,
7941ba11 199 (unsigned int) GDK_CURRENT_TIME );
c2fa61e8 200
32a95f9f
RR
201 win->m_diffX = (int)gdk_event->x;
202 win->m_diffY = (int)gdk_event->y;
a2053b27 203 DrawFrame( widget, 0, 0, win->m_width, win->m_height );
32a95f9f
RR
204 win->m_oldX = 0;
205 win->m_oldY = 0;
c2fa61e8 206
32a95f9f
RR
207 win->m_isDragging = TRUE;
208
209 return TRUE;
210}
865bb325 211}
32a95f9f
RR
212
213//-----------------------------------------------------------------------------
214// "button_release_event" of m_mainWidget
215//-----------------------------------------------------------------------------
216
865bb325 217extern "C" {
32a95f9f
RR
218static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
219{
acfd422a
RR
220 if (g_isIdle) wxapp_install_idle_handler();
221
a2053b27 222 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
223 if (g_blockEventsOnDrag) return TRUE;
224 if (g_blockEventsOnScroll) return TRUE;
225
226 if (!win->m_isDragging) return TRUE;
c2fa61e8 227
32a95f9f 228 win->m_isDragging = FALSE;
c2fa61e8 229
32a95f9f
RR
230 int x = (int)gdk_event->x;
231 int y = (int)gdk_event->y;
c2fa61e8 232
a2053b27 233 DrawFrame( widget, win->m_oldX, win->m_oldY, win->m_width, win->m_height );
13111b2a 234 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
c2fa61e8 235 int org_x = 0;
32a95f9f
RR
236 int org_y = 0;
237 gdk_window_get_origin( widget->window, &org_x, &org_y );
238 x += org_x - win->m_diffX;
239 y += org_y - win->m_diffY;
121a3581
RR
240 win->m_x = x;
241 win->m_y = y;
a2053b27 242 gtk_widget_set_uposition( win->m_widget, x, y );
32a95f9f
RR
243
244 return TRUE;
245}
865bb325 246}
32a95f9f
RR
247
248//-----------------------------------------------------------------------------
249// "motion_notify_event" of m_mainWidget
250//-----------------------------------------------------------------------------
251
865bb325 252extern "C" {
32a95f9f
RR
253static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
254{
acfd422a
RR
255 if (g_isIdle) wxapp_install_idle_handler();
256
a2053b27 257 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
258 if (g_blockEventsOnDrag) return TRUE;
259 if (g_blockEventsOnScroll) return TRUE;
260
261 if (!win->m_isDragging) return TRUE;
c2fa61e8 262
32a95f9f
RR
263 if (gdk_event->is_hint)
264 {
265 int x = 0;
266 int y = 0;
267 GdkModifierType state;
268 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
269 gdk_event->x = x;
270 gdk_event->y = y;
271 gdk_event->state = state;
272 }
273
a2053b27 274 DrawFrame( widget, win->m_oldX, win->m_oldY, win->m_width, win->m_height );
32a95f9f
RR
275 win->m_oldX = (int)gdk_event->x - win->m_diffX;
276 win->m_oldY = (int)gdk_event->y - win->m_diffY;
a2053b27 277 DrawFrame( widget, win->m_oldX, win->m_oldY, win->m_width, win->m_height );
c2fa61e8 278
32a95f9f
RR
279 return TRUE;
280}
865bb325 281}
32a95f9f
RR
282
283//-----------------------------------------------------------------------------
284// "clicked" of X system button
b2b3ccc5
RR
285//-----------------------------------------------------------------------------
286
865bb325 287extern "C" {
b2b3ccc5
RR
288static void gtk_button_clicked_callback( GtkWidget *WXUNUSED(widget), wxMiniFrame *mf )
289{
acfd422a
RR
290 if (g_isIdle) wxapp_install_idle_handler();
291
b2b3ccc5
RR
292 mf->Close();
293}
865bb325 294}
b2b3ccc5
RR
295
296//-----------------------------------------------------------------------------
297// wxMiniFrame
298//-----------------------------------------------------------------------------
299
90350682 300static const char *cross_xpm[] = {
5d5b3a40
RR
301/* columns rows colors chars-per-pixel */
302"5 5 16 1",
303" c Gray0",
304". c #bf0000",
305"X c #00bf00",
306"o c #bfbf00",
307"O c #0000bf",
308"+ c #bf00bf",
309"@ c #00bfbf",
310"# c None",
311"$ c #808080",
312"% c Red",
313"& c Green",
314"* c Yellow",
315"= c Blue",
316"- c Magenta",
317"; c Cyan",
318": c Gray100",
319/* pixels */
320" ### ",
321"# # #",
322"## ##",
323"# # #",
324" ### ",
325};
326
b2b3ccc5
RR
327IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
328
329bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
330 const wxPoint &pos, const wxSize &size,
331 long style, const wxString &name )
332{
2c990ec0 333 style = style | wxCAPTION;
b9a535f5
RR
334
335 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
336 m_miniTitle = 13;
c2fa61e8 337
b2b3ccc5 338 m_miniEdge = 3;
b2b3ccc5
RR
339 m_isDragging = FALSE;
340 m_oldX = -1;
341 m_oldY = -1;
342 m_diffX = 0;
343 m_diffY = 0;
c2fa61e8 344
b2b3ccc5
RR
345 wxFrame::Create( parent, id, title, pos, size, style, name );
346
2c990ec0
RR
347 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
348 {
349 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
350 }
351
b9a535f5
RR
352 if ((style & wxSYSTEM_MENU) &&
353 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
354 {
5d5b3a40 355 GdkBitmap *mask = (GdkBitmap*) NULL;
90350682
VZ
356 GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d
357 (
358 wxGetRootWindow()->window,
359 &mask,
360 NULL,
361 (char **)cross_xpm
362 );
c2fa61e8 363
5d5b3a40
RR
364 GtkWidget *pw = gtk_pixmap_new( pixmap, mask );
365 gdk_bitmap_unref( mask );
366 gdk_pixmap_unref( pixmap );
367 gtk_widget_show( pw );
c2fa61e8 368
5d5b3a40
RR
369 GtkWidget *close_button = gtk_button_new();
370 gtk_container_add( GTK_CONTAINER(close_button), pw );
c2fa61e8
RD
371
372 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
373 close_button,
5d5b3a40 374 size.x-16, 4, 11, 11 );
c2fa61e8 375
b9a535f5 376 gtk_widget_show( close_button );
c2fa61e8 377
b9a535f5
RR
378 gtk_signal_connect( GTK_OBJECT(close_button), "clicked",
379 GTK_SIGNAL_FUNC(gtk_button_clicked_callback), (gpointer*)this );
380 }
c2fa61e8 381
32a95f9f
RR
382 /* these are called when the borders are drawn */
383 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
384 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
b2b3ccc5 385
ba718523 386#ifndef __WXGTK20__
32a95f9f
RR
387 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
388 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
ba718523 389#endif
c2fa61e8 390
32a95f9f
RR
391 /* these are required for dragging the mini frame around */
392 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "button_press_event",
393 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
b2b3ccc5 394
32a95f9f
RR
395 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "button_release_event",
396 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
b2b3ccc5 397
32a95f9f
RR
398 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "motion_notify_event",
399 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
b2b3ccc5 400
32a95f9f 401 return TRUE;
b2b3ccc5 402}
dcf924a3 403
400be137
RR
404void wxMiniFrame::SetTitle( const wxString &title )
405{
406 wxFrame::SetTitle( title );
407
408#ifdef __WXGTK20__
409 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
410#else
411 gtk_widget_draw( m_mainWidget, (GdkRectangle*) NULL );
412#endif
413}
414
dcf924a3 415#endif