1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/gtk/minifram.cpp
4
// Author: Robert Roebling
5
// Id: $Id: minifram.cpp 71894 2012-06-30 20:39:06Z PC $
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"
24
#include "wx/gtk/dc.h"
26
#include "wx/gtk/dcclient.h"
30
#include "wx/gtk/private/gtk2-compat.h"
32
//-----------------------------------------------------------------------------
34
//-----------------------------------------------------------------------------
36
extern bool g_blockEventsOnDrag;
37
extern bool g_blockEventsOnScroll;
39
//-----------------------------------------------------------------------------
40
// "expose_event" of m_mainWidget
41
//-----------------------------------------------------------------------------
43
// StepColour() it a utility function that simply darkens
44
// or lightens a color, based on the specified percentage
45
static wxColor StepColour(const wxColor& c, int percent)
47
int r = c.Red(), g = c.Green(), b = c.Blue();
48
return wxColour((unsigned char)wxMin((r*percent)/100,255),
49
(unsigned char)wxMin((g*percent)/100,255),
50
(unsigned char)wxMin((b*percent)/100,255));
53
static wxColor LightContrastColour(const wxColour& c)
57
// if the color is especially dark, then
58
// make the contrast even lighter
59
if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
62
return StepColour(c, amount);
67
static gboolean draw(GtkWidget* widget, cairo_t* cr, wxMiniFrame* win)
69
static gboolean expose_event(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
73
if (!gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget)))
76
GtkStyleContext* sc = gtk_widget_get_style_context(widget);
77
gtk_style_context_save(sc);
78
gtk_style_context_add_class(sc, GTK_STYLE_CLASS_BUTTON);
79
gtk_render_frame(sc, cr, 0, 0, win->m_width, win->m_height);
80
gtk_style_context_restore(sc);
84
if (!win->m_hasVMT || gdk_event->count > 0 ||
85
gdk_event->window != gtk_widget_get_window(widget))
90
gtk_paint_shadow (gtk_widget_get_style(widget),
91
gtk_widget_get_window(widget),
94
NULL, NULL, NULL, // FIXME: No clipping?
96
win->m_width, win->m_height);
100
wxDCImpl *impl = dc.GetImpl();
101
wxClientDCImpl *gtk_impl = wxDynamicCast( impl, wxClientDCImpl );
102
gtk_impl->m_gdkwindow = gtk_widget_get_window(widget); // Hack alert
105
int style = win->GetWindowStyle();
108
if (style & wxRESIZE_BORDER)
110
dc.SetBrush( *wxGREY_BRUSH );
111
dc.SetPen( *wxTRANSPARENT_PEN );
112
dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
116
if (win->m_miniTitle && !win->GetTitle().empty())
118
dc.SetFont( *wxSMALL_FONT );
120
wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
121
dc.SetBrush( brush );
122
dc.SetPen( *wxTRANSPARENT_PEN );
123
dc.DrawRectangle( win->m_miniEdge-1,
125
win->m_width - (2*(win->m_miniEdge-1)),
128
dc.SetTextForeground( *wxWHITE );
129
dc.DrawText( win->GetTitle(), 6, 4 );
131
if (style & wxCLOSE_BOX)
132
dc.DrawBitmap( win->m_closeButton, win->m_width-18, 3, true );
139
//-----------------------------------------------------------------------------
140
// "button_press_event" of m_mainWidget
141
//-----------------------------------------------------------------------------
145
gtk_window_button_press_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
147
if (!win->m_hasVMT || gdk_event->window != gtk_widget_get_window(widget))
149
if (g_blockEventsOnDrag) return TRUE;
150
if (g_blockEventsOnScroll) return TRUE;
152
if (win->m_isDragging) return TRUE;
154
int style = win->GetWindowStyle();
156
int y = (int)gdk_event->y;
157
int x = (int)gdk_event->x;
160
if ((style & wxRESIZE_BORDER) &&
161
(x > win->m_width-14) && (y > win->m_height-14))
163
GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
165
GdkWindow *source = gtk_widget_get_window(widget);
169
gdk_window_get_origin( source, &org_x, &org_y );
171
gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
172
GDK_WINDOW_EDGE_SOUTH_EAST,
182
if (win->m_miniTitle && (style & wxCLOSE_BOX))
184
if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
191
if (y >= win->m_miniEdge + win->m_miniTitle)
194
gdk_window_raise(gtk_widget_get_window(win->m_widget));
196
gdk_pointer_grab( gtk_widget_get_window(widget), false,
198
(GDK_BUTTON_PRESS_MASK |
199
GDK_BUTTON_RELEASE_MASK |
200
GDK_POINTER_MOTION_MASK |
201
GDK_POINTER_MOTION_HINT_MASK |
202
GDK_BUTTON_MOTION_MASK |
203
GDK_BUTTON1_MOTION_MASK),
206
(unsigned int) GDK_CURRENT_TIME );
213
win->m_isDragging = true;
219
//-----------------------------------------------------------------------------
220
// "button_release_event" of m_mainWidget
221
//-----------------------------------------------------------------------------
225
gtk_window_button_release_callback(GtkWidget* widget, GdkEventButton* gdk_event, wxMiniFrame* win)
227
if (!win->m_hasVMT || gdk_event->window != gtk_widget_get_window(widget))
229
if (g_blockEventsOnDrag) return TRUE;
230
if (g_blockEventsOnScroll) return TRUE;
231
if (!win->m_isDragging) return TRUE;
233
win->m_isDragging = false;
235
int x = (int)gdk_event->x;
236
int y = (int)gdk_event->y;
238
gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
241
gdk_window_get_origin(gtk_widget_get_window(widget), &org_x, &org_y);
242
x += org_x - win->m_diffX;
243
y += org_y - win->m_diffY;
246
gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
252
//-----------------------------------------------------------------------------
253
// "leave_notify_event" of m_mainWidget
254
//-----------------------------------------------------------------------------
258
gtk_window_leave_callback(GtkWidget *widget,
259
GdkEventCrossing* gdk_event,
262
if (!win->m_hasVMT) return FALSE;
263
if (g_blockEventsOnDrag) return FALSE;
264
if (gdk_event->window != gtk_widget_get_window(widget))
267
gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
273
//-----------------------------------------------------------------------------
274
// "motion_notify_event" of m_mainWidget
275
//-----------------------------------------------------------------------------
279
gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
281
if (!win->m_hasVMT || gdk_event->window != gtk_widget_get_window(widget))
283
if (g_blockEventsOnDrag) return TRUE;
284
if (g_blockEventsOnScroll) return TRUE;
286
if (gdk_event->is_hint)
290
GdkModifierType state;
291
gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
294
gdk_event->state = state;
297
int x = (int)gdk_event->x;
298
int y = (int)gdk_event->y;
300
if (!win->m_isDragging)
303
if (win->GetWindowStyle() & wxRESIZE_BORDER)
305
if ((x > win->m_width-14) && (y > win->m_height-14))
306
gdk_window_set_cursor(gtk_widget_get_window(widget), gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER));
308
gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
309
win->GTKUpdateCursor(false);
315
win->m_oldX = x - win->m_diffX;
316
win->m_oldY = y - win->m_diffY;
320
gdk_window_get_origin(gtk_widget_get_window(widget), &org_x, &org_y);
321
x += org_x - win->m_diffX;
322
y += org_y - win->m_diffY;
325
gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
331
//-----------------------------------------------------------------------------
333
//-----------------------------------------------------------------------------
335
static unsigned char close_bits[]={
336
0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
337
0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
338
0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
341
IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
343
bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
344
const wxPoint &pos, const wxSize &size,
345
long style, const wxString &name )
348
if (style & wxCAPTION)
351
if (style & wxRESIZE_BORDER)
355
m_isDragging = false;
361
// don't allow sizing smaller than decorations
362
int minWidth = 2 * m_miniEdge;
363
int minHeight = 2 * m_miniEdge + m_miniTitle;
364
if (m_minWidth < minWidth)
365
m_minWidth = minWidth;
366
if (m_minHeight < minHeight)
367
m_minHeight = minHeight;
369
wxFrame::Create( parent, id, title, pos, size, style, name );
371
// Use a GtkEventBox for the title and borders. Using m_widget for this
372
// almost works, except that setting the resize cursor has no effect.
373
GtkWidget* eventbox = gtk_event_box_new();
374
gtk_widget_add_events(eventbox,
375
GDK_POINTER_MOTION_MASK |
376
GDK_POINTER_MOTION_HINT_MASK);
377
gtk_widget_show(eventbox);
378
// Use a GtkAlignment to position m_mainWidget inside the decorations
379
GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
380
gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
381
m_miniTitle + m_miniEdge, m_miniEdge, m_miniEdge, m_miniEdge);
382
gtk_widget_show(alignment);
383
// The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
384
gtk_widget_reparent(m_mainWidget, alignment);
385
gtk_container_add(GTK_CONTAINER(eventbox), alignment);
386
gtk_container_add(GTK_CONTAINER(m_widget), eventbox);
390
if (style & wxRESIZE_BORDER)
391
m_gdkFunc = GDK_FUNC_RESIZE;
392
gtk_window_set_default_size(GTK_WINDOW(m_widget), m_width, m_height);
393
m_decorSize.Set(0, 0);
396
if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
398
gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
401
if (m_miniTitle && (style & wxCLOSE_BOX))
403
wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
404
img.Replace(0,0,0,123,123,123);
405
img.SetMaskColour(123,123,123);
406
m_closeButton = wxBitmap( img );
409
/* these are called when the borders are drawn */
411
g_signal_connect_after(eventbox, "draw", G_CALLBACK(draw), this);
413
g_signal_connect_after(eventbox, "expose_event", G_CALLBACK(expose_event), this);
416
/* these are required for dragging the mini frame around */
417
g_signal_connect (eventbox, "button_press_event",
418
G_CALLBACK (gtk_window_button_press_callback), this);
419
g_signal_connect (eventbox, "button_release_event",
420
G_CALLBACK (gtk_window_button_release_callback), this);
421
g_signal_connect (eventbox, "motion_notify_event",
422
G_CALLBACK (gtk_window_motion_notify_callback), this);
423
g_signal_connect (eventbox, "leave_notify_event",
424
G_CALLBACK (gtk_window_leave_callback), this);
428
void wxMiniFrame::DoGetClientSize(int* width, int* height) const
430
wxFrame::DoGetClientSize(width, height);
433
*width -= 2 * m_miniEdge;
434
if (*width < 0) *width = 0;
438
*height -= m_miniTitle + 2 * m_miniEdge;
439
if (*height < 0) *height = 0;
443
// Keep min size at least as large as decorations
444
void wxMiniFrame::DoSetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
446
const int w = 2 * m_miniEdge;
447
const int h = 2 * m_miniEdge + m_miniTitle;
448
if (minW < w) minW = w;
449
if (minH < h) minH = h;
450
wxFrame::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH);
453
void wxMiniFrame::SetTitle( const wxString &title )
455
wxFrame::SetTitle( title );
457
GdkWindow* window = gtk_widget_get_window(gtk_bin_get_child(GTK_BIN(m_widget)));
459
gdk_window_invalidate_rect(window, NULL, false);
462
#endif // wxUSE_MINIFRAME