ultimatepp/uppsrc/CtrlCore/GtkTop.cpp
2026-01-16 09:11:40 +01:00

298 lines
No EOL
6.5 KiB
C++

#include <CtrlCore/CtrlCore.h>
#ifdef GUI_GTK
namespace Upp {
#define LLOG(x) // DLOG(x)
void TopWindow::SyncSizeHints()
{
GuiLock __;
if(!top)
return;
Size sz0 = GetRect().GetSize();
LLOG("SyncSizeHints sz0: " << sz0 << ", sizeable: " << sizeable << ", min: " << GetMinSize() << ", max: " << GetMaxSize());
Top *top = GetTop();
if(top) {
int mcx = 0;
int mcy = 0;
if(top->csd) {
mcx += csd_border.left + csd_border.right;
mcy += csd_border.top + csd_border.bottom;
if(custom_bar_frame)
mcy += GetCustomTitleBarMetrics().height;
else
mcy += csd_std_header_cy;
}
GdkGeometry m;
m.base_width = sz0.cx;
m.base_height = sz0.cy;
Size minsz = sizeable ? GetMinSize() : sz0;
m.min_width = LSCH(minsz.cx + mcx);
m.min_height = LSCH(minsz.cy + mcy);
Size maxsz = sizeable ? GetMaxSize() : sz0;
m.max_width = LSCH(maxsz.cx + mcx);
m.max_height = LSCH(maxsz.cy + mcy);
gtk_window_set_resizable(gtk(), sizeable);
gtk_window_set_geometry_hints(gtk(), NULL, &m,
GdkWindowHints(GDK_HINT_MIN_SIZE|GDK_HINT_MAX_SIZE|GDK_HINT_BASE_SIZE));
gtk_widget_set_size_request(top->window, m.min_width, m.min_height);
}
SyncCustomBar();
}
void TopWindow::SyncTitle()
{
GuiLock __;
if(GetTop())
gtk_window_set_title(gtk(), FromUnicode(title, CHARSET_UTF8));
}
void TopWindow::SyncCaption()
{
GuiLock __;
SyncTitle();
if(top) {
GList *icons = NULL;
if(gdk_icon.Set(icon))
icons = g_list_append(icons, gdk_icon);
if(gdk_largeicon.Set(largeicon))
icons = g_list_append(icons, gdk_largeicon);
if(icons != NULL) {
gtk_window_set_icon_list(gtk(), icons);
g_list_free(icons);
}
gtk_window_set_decorated(gtk(), !frameless);
gtk_window_set_urgency_hint(gtk(), urgent);
}
}
void TopWindow::CenterRect(Ctrl *owner)
{
GuiLock __;
SetupRect(owner);
if(owner && center == 1 || center == 2) {
Size sz = GetRect().Size();
Rect wr = owner ? owner->GetWorkArea() : Ctrl::GetPrimaryWorkArea();
Rect fm = frameMargins;
Rect r = (center == 1 && owner ? owner->GetRect() : wr)
.CenterRect(sz);
wr.left += fm.left;
wr.right -= fm.right;
wr.top += fm.top;
wr.bottom -= fm.bottom;
if(r.top < wr.top) {
r.top = wr.top;
r.bottom = r.top + sz.cy;
}
if(r.left < wr.left) {
r.left = wr.left;
r.right = r.left + sz.cx;
}
if(r.bottom > wr.bottom) {
r.bottom = wr.bottom;
r.top = r.bottom - sz.cy;
}
if(r.right > wr.right) {
r.right = wr.right;
r.left = r.right - sz.cx;
}
minsize.cx = min(minsize.cx, r.GetWidth());
minsize.cy = min(minsize.cy, r.GetHeight());
SetRect(r);
}
}
gboolean TopWindow::StateEvent(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
{
TopWindow *w = (TopWindow *)user_data;
dword h = event->new_window_state;
int prev = w->state;
if(h & GDK_WINDOW_STATE_FULLSCREEN)
w->state = FULLSCREEN;
else
if(h & GDK_WINDOW_STATE_ICONIFIED)
w->state = MINIMIZED;
else
if(h & GDK_WINDOW_STATE_MAXIMIZED)
w->state = MAXIMIZED;
else {
w->state = OVERLAPPED;
w->overlapped = w->GetRect();
}
LLOG("StateEvent " << prev << " -> " << (int)w->state);
w->topmost = h & GDK_WINDOW_STATE_ABOVE;
w->Layout();
if(prev == MINIMIZED && w->state != MINIMIZED) {
prev_mouse_pos = CurrentMousePos = Null; // we lost the track of mouse, otherwise "minimize" button would render highlighted
if(w->custom_bar_icons)
w->custom_bar_icons->RefreshFrame();
}
return FALSE;
}
void TopWindow::Open(Ctrl *owner)
{
GuiLock __;
LLOG("OPEN " << Name() << " owner: " << UPP::Name(owner));
if(dokeys && (!GUI_AKD_Conservative() || GetAccessKeysDeep() <= 1))
DistributeAccessKeys();
if(fullscreen)
SetRect(GetPrimaryScreenArea());
else
CenterRect(owner);
IgnoreMouseUp();
Create(owner, false);
Top *top = GetTop();
if(top)
g_signal_connect(top->window, "window-state-event", G_CALLBACK(StateEvent), this);
SyncSizeHints();
SyncCaption();
PlaceFocus();
int q = state;
state = OVERLAPPED;
SetMode(q);
SyncTopMost();
}
void TopWindow::Open()
{
Open(GetActiveWindow());
}
void TopWindow::OpenMain()
{
Open(NULL);
}
void TopWindow::SyncTopMost()
{
GuiLock __;
if(top)
gtk_window_set_keep_above(gtk(), topmost);
}
void TopWindow::SetMode(int mode)
{
GuiLock __;
GtkWindow *w = gtk();
if(w)
switch(state) {
case MINIMIZED:
fullscreen = false;
gtk_window_iconify(w);
break;
case MAXIMIZED:
fullscreen = false;
gtk_window_deiconify(w);
gtk_window_maximize(w);
break;
case OVERLAPPED:
fullscreen = false;
gtk_window_deiconify(w);
gtk_window_unmaximize(w);
break;
case FULLSCREEN:
gtk_window_fullscreen(w);
fullscreen = true;
break;
}
}
void TopWindow::Minimize(bool effect)
{
SetMode(MINIMIZED);
}
TopWindow& TopWindow::FullScreen(bool b)
{
SetMode(b ? (int)FULLSCREEN : (int)OVERLAPPED);
return *this;
}
void TopWindow::Maximize(bool effect)
{
SetMode(MAXIMIZED);
}
void TopWindow::Overlap(bool effect)
{
SetMode(OVERLAPPED);
}
TopWindow& TopWindow::TopMost(bool b, bool)
{
GuiLock __;
topmost = b;
SyncTopMost();
return *this;
}
bool TopWindow::IsTopMost() const
{
GuiLock __;
return topmost;
}
void TopWindow::GuiPlatformConstruct()
{
topmost = false;
}
void TopWindow::GuiPlatformDestruct()
{
}
void TopWindow::SerializePlacement(Stream& s, bool reminimize)
{
GuiLock __;
int version = 0;
s / version;
Rect rect = GetRect();
s % overlapped % rect;
bool mn = state == MINIMIZED;
bool mx = state == MAXIMIZED;
s.Pack(mn, mx);
LLOG("TopWindow::SerializePlacement / " << (s.IsStoring() ? "write" : "read"));
LLOG("minimized = " << mn << ", maximized = " << mx);
LLOG("rect = " << rect << ", overlapped = " << overlapped);
if(s.IsLoading()) {
if(mn) rect = overlapped;
Rect limit = GetVirtualWorkArea();
Rect fm = frameMargins;
limit.left += fm.left;
limit.right -= fm.right;
limit.top += fm.top;
limit.bottom -= fm.bottom;
Size sz = min(rect.Size(), limit.Size());
rect = RectC(
minmax(rect.left, limit.left, limit.right - sz.cx),
minmax(rect.top, limit.top, limit.bottom - sz.cy),
sz.cx, sz.cy);
state = OVERLAPPED;
if(mn && reminimize)
state = MINIMIZED;
if(mx)
state = MAXIMIZED;
if(state == OVERLAPPED)
SetRect(rect);
if(IsOpen()) {
if(state == MINIMIZED)
Minimize(false);
if(state == MAXIMIZED)
Maximize(false);
}
}
}
}
#endif