1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #include "wx/minifram.h"
18 #include "wx/settings.h"
19 #include "wx/dcclient.h"
23 #include "wx/gtk/dcclient.h"
26 #include "wx/gtk/private/gtk2-compat.h"
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 extern bool g_blockEventsOnDrag
;
33 extern bool g_blockEventsOnScroll
;
35 //-----------------------------------------------------------------------------
36 // "expose_event" of m_mainWidget
37 //-----------------------------------------------------------------------------
39 // StepColour() it a utility function that simply darkens
40 // or lightens a color, based on the specified percentage
41 static wxColor
StepColour(const wxColor
& c
, int percent
)
43 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
44 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
45 (unsigned char)wxMin((g
*percent
)/100,255),
46 (unsigned char)wxMin((b
*percent
)/100,255));
49 static wxColor
LightContrastColour(const wxColour
& c
)
53 // if the color is especially dark, then
54 // make the contrast even lighter
55 if (c
.Red() < 128 && c
.Green() < 128 && c
.Blue() < 128)
58 return StepColour(c
, amount
);
62 static gboolean
gtk_window_own_expose_callback(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxMiniFrame
* win
)
64 if (!win
->m_hasVMT
|| gdk_event
->count
> 0 ||
65 gdk_event
->window
!= gtk_widget_get_window(widget
))
70 gtk_paint_shadow (gtk_widget_get_style(widget
),
71 gtk_widget_get_window(widget
),
74 NULL
, NULL
, NULL
, // FIXME: No clipping?
76 win
->m_width
, win
->m_height
);
78 int style
= win
->GetWindowStyle();
82 wxDCImpl
*impl
= dc
.GetImpl();
83 wxClientDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxClientDCImpl
);
84 gtk_impl
->m_gdkwindow
= gtk_widget_get_window(widget
); // Hack alert
86 if (style
& wxRESIZE_BORDER
)
88 dc
.SetBrush( *wxGREY_BRUSH
);
89 dc
.SetPen( *wxTRANSPARENT_PEN
);
90 dc
.DrawRectangle( win
->m_width
- 14, win
->m_height
-14, 14, 14 );
93 if (win
->m_miniTitle
&& !win
->GetTitle().empty())
95 dc
.SetFont( *wxSMALL_FONT
);
97 wxBrush
brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) );
99 dc
.SetPen( *wxTRANSPARENT_PEN
);
100 dc
.DrawRectangle( win
->m_miniEdge
-1,
102 win
->m_width
- (2*(win
->m_miniEdge
-1)),
105 dc
.SetTextForeground( *wxWHITE
);
106 dc
.DrawText( win
->GetTitle(), 6, 4 );
108 if (style
& wxCLOSE_BOX
)
109 dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-18, 3, true );
116 //-----------------------------------------------------------------------------
117 // "button_press_event" of m_mainWidget
118 //-----------------------------------------------------------------------------
122 gtk_window_button_press_callback(GtkWidget
* widget
, GdkEventButton
* gdk_event
, wxMiniFrame
* win
)
124 if (!win
->m_hasVMT
|| gdk_event
->window
!= gtk_widget_get_window(widget
))
126 if (g_blockEventsOnDrag
) return TRUE
;
127 if (g_blockEventsOnScroll
) return TRUE
;
129 if (win
->m_isDragging
) return TRUE
;
131 int style
= win
->GetWindowStyle();
133 int y
= (int)gdk_event
->y
;
134 int x
= (int)gdk_event
->x
;
136 if ((style
& wxRESIZE_BORDER
) &&
137 (x
> win
->m_width
-14) && (y
> win
->m_height
-14))
139 GtkWidget
*ancestor
= gtk_widget_get_toplevel( widget
);
141 GdkWindow
*source
= gtk_widget_get_window(widget
);
145 gdk_window_get_origin( source
, &org_x
, &org_y
);
147 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
148 GDK_WINDOW_EDGE_SOUTH_EAST
,
157 if (win
->m_miniTitle
&& (style
& wxCLOSE_BOX
))
159 if ((y
> 3) && (y
< 19) && (x
> win
->m_width
-19) && (x
< win
->m_width
-3))
166 if (y
>= win
->m_miniEdge
+ win
->m_miniTitle
)
169 gdk_window_raise(gtk_widget_get_window(win
->m_widget
));
171 gdk_pointer_grab( gtk_widget_get_window(widget
), false,
173 (GDK_BUTTON_PRESS_MASK
|
174 GDK_BUTTON_RELEASE_MASK
|
175 GDK_POINTER_MOTION_MASK
|
176 GDK_POINTER_MOTION_HINT_MASK
|
177 GDK_BUTTON_MOTION_MASK
|
178 GDK_BUTTON1_MOTION_MASK
),
181 (unsigned int) GDK_CURRENT_TIME
);
188 win
->m_isDragging
= true;
194 //-----------------------------------------------------------------------------
195 // "button_release_event" of m_mainWidget
196 //-----------------------------------------------------------------------------
200 gtk_window_button_release_callback(GtkWidget
* widget
, GdkEventButton
* gdk_event
, wxMiniFrame
* win
)
202 if (!win
->m_hasVMT
|| gdk_event
->window
!= gtk_widget_get_window(widget
))
204 if (g_blockEventsOnDrag
) return TRUE
;
205 if (g_blockEventsOnScroll
) return TRUE
;
206 if (!win
->m_isDragging
) return TRUE
;
208 win
->m_isDragging
= false;
210 int x
= (int)gdk_event
->x
;
211 int y
= (int)gdk_event
->y
;
213 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
216 gdk_window_get_origin(gtk_widget_get_window(widget
), &org_x
, &org_y
);
217 x
+= org_x
- win
->m_diffX
;
218 y
+= org_y
- win
->m_diffY
;
221 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
227 //-----------------------------------------------------------------------------
228 // "leave_notify_event" of m_mainWidget
229 //-----------------------------------------------------------------------------
233 gtk_window_leave_callback(GtkWidget
*widget
,
234 GdkEventCrossing
* gdk_event
,
237 if (!win
->m_hasVMT
) return FALSE
;
238 if (g_blockEventsOnDrag
) return FALSE
;
239 if (gdk_event
->window
!= gtk_widget_get_window(widget
))
242 gdk_window_set_cursor(gtk_widget_get_window(widget
), NULL
);
248 //-----------------------------------------------------------------------------
249 // "motion_notify_event" of m_mainWidget
250 //-----------------------------------------------------------------------------
254 gtk_window_motion_notify_callback( GtkWidget
*widget
, GdkEventMotion
*gdk_event
, wxMiniFrame
*win
)
256 if (!win
->m_hasVMT
|| gdk_event
->window
!= gtk_widget_get_window(widget
))
258 if (g_blockEventsOnDrag
) return TRUE
;
259 if (g_blockEventsOnScroll
) return TRUE
;
261 if (gdk_event
->is_hint
)
265 GdkModifierType state
;
266 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
269 gdk_event
->state
= state
;
272 int style
= win
->GetWindowStyle();
274 int x
= (int)gdk_event
->x
;
275 int y
= (int)gdk_event
->y
;
277 if (!win
->m_isDragging
)
279 if (style
& wxRESIZE_BORDER
)
281 if ((x
> win
->m_width
-14) && (y
> win
->m_height
-14))
282 gdk_window_set_cursor(gtk_widget_get_window(widget
), gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER
));
284 gdk_window_set_cursor(gtk_widget_get_window(widget
), NULL
);
285 win
->GTKUpdateCursor(false);
290 win
->m_oldX
= x
- win
->m_diffX
;
291 win
->m_oldY
= y
- win
->m_diffY
;
295 gdk_window_get_origin(gtk_widget_get_window(widget
), &org_x
, &org_y
);
296 x
+= org_x
- win
->m_diffX
;
297 y
+= org_y
- win
->m_diffY
;
300 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
306 //-----------------------------------------------------------------------------
308 //-----------------------------------------------------------------------------
310 static unsigned char close_bits
[]={
311 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
312 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
313 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
316 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
)
318 bool wxMiniFrame::Create( wxWindow
*parent
, wxWindowID id
, const wxString
&title
,
319 const wxPoint
&pos
, const wxSize
&size
,
320 long style
, const wxString
&name
)
323 if (style
& wxCAPTION
)
326 if (style
& wxRESIZE_BORDER
)
330 m_isDragging
= false;
336 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
338 // Use a GtkEventBox for the title and borders. Using m_widget for this
339 // almost works, except that setting the resize cursor has no effect.
340 GtkWidget
* eventbox
= gtk_event_box_new();
341 gtk_widget_add_events(eventbox
,
342 GDK_POINTER_MOTION_MASK
|
343 GDK_POINTER_MOTION_HINT_MASK
);
344 gtk_widget_show(eventbox
);
345 // Use a GtkAlignment to position m_mainWidget inside the decorations
346 GtkWidget
* alignment
= gtk_alignment_new(0, 0, 1, 1);
347 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment
),
348 m_miniTitle
+ m_miniEdge
, m_miniEdge
, m_miniEdge
, m_miniEdge
);
349 gtk_widget_show(alignment
);
350 // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
351 gtk_widget_reparent(m_mainWidget
, alignment
);
352 gtk_container_add(GTK_CONTAINER(eventbox
), alignment
);
353 gtk_container_add(GTK_CONTAINER(m_widget
), eventbox
);
357 if (style
& wxRESIZE_BORDER
)
358 m_gdkFunc
= GDK_FUNC_RESIZE
;
359 gtk_window_set_default_size(GTK_WINDOW(m_widget
), m_width
, m_height
);
360 m_decorSize
.Set(0, 0);
363 // don't allow sizing smaller than decorations
365 geom
.min_width
= 2 * m_miniEdge
;
366 geom
.min_height
= 2 * m_miniEdge
+ m_miniTitle
;
367 gtk_window_set_geometry_hints(GTK_WINDOW(m_widget
), NULL
, &geom
, GDK_HINT_MIN_SIZE
);
369 if (m_parent
&& (GTK_IS_WINDOW(m_parent
->m_widget
)))
371 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
374 if (m_miniTitle
&& (style
& wxCLOSE_BOX
))
376 wxImage img
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage();
377 img
.Replace(0,0,0,123,123,123);
378 img
.SetMaskColour(123,123,123);
379 m_closeButton
= wxBitmap( img
);
382 /* these are called when the borders are drawn */
383 g_signal_connect_after(eventbox
, "expose_event",
384 G_CALLBACK (gtk_window_own_expose_callback
), this );
386 /* these are required for dragging the mini frame around */
387 g_signal_connect (eventbox
, "button_press_event",
388 G_CALLBACK (gtk_window_button_press_callback
), this);
389 g_signal_connect (eventbox
, "button_release_event",
390 G_CALLBACK (gtk_window_button_release_callback
), this);
391 g_signal_connect (eventbox
, "motion_notify_event",
392 G_CALLBACK (gtk_window_motion_notify_callback
), this);
393 g_signal_connect (eventbox
, "leave_notify_event",
394 G_CALLBACK (gtk_window_leave_callback
), this);
398 void wxMiniFrame::DoGetClientSize(int* width
, int* height
) const
400 wxFrame::DoGetClientSize(width
, height
);
403 *width
-= 2 * m_miniEdge
;
404 if (*width
< 0) *width
= 0;
408 *height
-= m_miniTitle
+ 2 * m_miniEdge
;
409 if (*height
< 0) *height
= 0;
413 // Keep min size at least as large as decorations
414 void wxMiniFrame::DoSetSizeHints(int minW
, int minH
, int maxW
, int maxH
, int incW
, int incH
)
416 const int w
= 2 * m_miniEdge
;
417 const int h
= 2 * m_miniEdge
+ m_miniTitle
;
418 if (minW
< w
) minW
= w
;
419 if (minH
< h
) minH
= h
;
420 wxFrame::DoSetSizeHints(minW
, minH
, maxW
, maxH
, incW
, incH
);
423 void wxMiniFrame::SetTitle( const wxString
&title
)
425 wxFrame::SetTitle( title
);
427 GdkWindow
* window
= gtk_widget_get_window(gtk_bin_get_child(GTK_BIN(m_widget
)));
429 gdk_window_invalidate_rect(window
, NULL
, false);
432 #endif // wxUSE_MINIFRAME