"Fossies" - the Fresh Open Source Software Archive

Member "gambas-3.16.3/gb.gtk/src/gmainwindow.cpp" (7 Sep 2021, 40873 Bytes) of package /linux/misc/gambas-3.16.3.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gmainwindow.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.16.2_vs_3.16.3.

    1 /***************************************************************************
    2 
    3   gmainwindow.cpp
    4 
    5   (c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
    6 
    7   This program is free software; you can redistribute it and/or modify
    8   it under the terms of the GNU General Public License as published by
    9   the Free Software Foundation; either version 2, or (at your option)
   10   any later version.
   11 
   12   This program is distributed in the hope that it will be useful,
   13   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15   GNU General Public License for more details.
   16 
   17   You should have received a copy of the GNU General Public License
   18   along with this program; if not, write to the Free Software
   19   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   20   MA 02110-1301, USA.
   21 
   22 ***************************************************************************/
   23 
   24 #include <ctype.h>
   25 #include <time.h>
   26 
   27 #include "widgets.h"
   28 
   29 #ifndef GTK3
   30 #include "x11.h"
   31 #include "sm/sm.h"
   32 #endif
   33 
   34 #include "gapplication.h"
   35 #include "gdesktop.h"
   36 #include "gkey.h"
   37 #include "gmenu.h"
   38 #include "gdialog.h"
   39 #include "gmouse.h"
   40 #include "gmainwindow.h"
   41 
   42 //#define DEBUG_RESIZE 1
   43 
   44 GList *gMainWindow::windows = NULL;
   45 gMainWindow *gMainWindow::_active = NULL;
   46 gMainWindow *gMainWindow::_current = NULL;
   47 
   48 
   49 #define CHECK_STATE(_var, _state) \
   50     if (event->changed_mask & _state) \
   51     { \
   52         v = (event->new_window_state & _state) != 0; \
   53         if (v != data->_var) \
   54         { \
   55             data->_var = v; \
   56             has_changed = true; \
   57         } \
   58     }
   59 
   60 static gboolean cb_frame(GtkWidget *widget,GdkEventWindowState *event,gMainWindow *data)
   61 {
   62     bool has_changed = false;
   63     bool v;
   64     
   65     CHECK_STATE(_minimized, GDK_WINDOW_STATE_ICONIFIED);
   66     CHECK_STATE(_maximized, GDK_WINDOW_STATE_MAXIMIZED);
   67     CHECK_STATE(_sticky, GDK_WINDOW_STATE_STICKY);
   68     CHECK_STATE(_fullscreen, GDK_WINDOW_STATE_FULLSCREEN);
   69 
   70     if (event->changed_mask & GDK_WINDOW_STATE_ABOVE)
   71     {
   72         if (event->new_window_state & GDK_WINDOW_STATE_ABOVE)
   73             data->stack = 1;
   74         else if (data->stack == 1)
   75             data->stack = 0;
   76     }
   77     if (event->changed_mask & GDK_WINDOW_STATE_BELOW)
   78     {
   79         if (event->new_window_state & GDK_WINDOW_STATE_BELOW)
   80             data->stack = 2;
   81         else if (data->stack == 2)
   82             data->stack = 0;
   83     }
   84 
   85     if (has_changed)
   86     {
   87         #ifdef DEBUG_RESIZE
   88         fprintf(stderr, "cb_frame: min = %d max = %d fs = %d\n", data->_minimized, data->_maximized, data->_fullscreen);
   89         #endif
   90         data->_csd_w = data->_csd_h = -1;
   91         /*data->calcCsdSize();
   92         data->performArrange();*/
   93     }
   94 
   95     if (event->changed_mask & (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN | GDK_WINDOW_STATE_STICKY | GDK_WINDOW_STATE_ABOVE | GDK_WINDOW_STATE_BELOW))
   96         data->emit(SIGNAL(data->onState));
   97 
   98     return false;
   99 }
  100 
  101 static gboolean cb_show(GtkWidget *widget, gMainWindow *data)
  102 {
  103     if (data->_grab_on_show)
  104     {
  105         data->_grab_on_show = FALSE;
  106         gApplication::grabPopup();
  107     }
  108 
  109     data->emitOpen();
  110 
  111     if (data->_opened)
  112     {
  113         data->performArrange();
  114         #ifdef DEBUG_RESIZE
  115         fprintf(stderr, "cb_show\n");
  116         #endif
  117         data->emitResize();
  118         data->emit(SIGNAL(data->onShow));
  119         data->_not_spontaneous = false;
  120     }
  121     return false;
  122 }
  123 
  124 static gboolean cb_map(GtkWidget *widget, GdkEvent *event, gMainWindow *data)
  125 {
  126     data->_unmap = false;
  127     return cb_show(widget, data);
  128 }
  129 
  130 static gboolean cb_hide(GtkWidget *widget, gMainWindow *data)
  131 {
  132     if (!data->_unmap)
  133     {
  134         data->emit(SIGNAL(data->onHide));
  135         data->_not_spontaneous = false;
  136     }
  137 
  138     return false;
  139     //if (data == gDesktop::activeWindow())
  140     //  gMainWindow::setActiveWindow(NULL);
  141 }
  142 
  143 static gboolean cb_unmap(GtkWidget *widget, GdkEvent *event, gMainWindow *data)
  144 {
  145     bool ret = cb_hide(widget, data);
  146     data->_unmap = true;
  147     return ret;
  148 }
  149 
  150 static gboolean cb_close(GtkWidget *widget,GdkEvent *event, gMainWindow *data)
  151 {
  152     if (!gMainWindow::_current || data == gMainWindow::_current)
  153         data->doClose();
  154 
  155     return true;
  156 }
  157 
  158 static gboolean cb_configure(GtkWidget *widget, GdkEventConfigure *event, gMainWindow *data)
  159 {
  160 #if 0
  161     gint x, y, w, h;
  162 
  163     if (data->_opened)
  164     {
  165         if (data->isTopLevel())
  166         {
  167             gtk_window_get_position(GTK_WINDOW(data->border), &x, &y);
  168         }
  169         else
  170         {
  171             x = event->x;
  172             y = event->y;
  173         }
  174 
  175         #ifdef DEBUG_RESIZE
  176         fprintf(stderr, "cb_configure: %s: (%d %d %d %d) -> (%d/%d %d/%d %d %d) window = %p resized = %d send_event = %d\n", data->name(), data->bufX, data->bufY, data->bufW, data->bufH, x, event->x, y, event->y, event->width, event->height, event->window, data->_event_resized, event->send_event);
  177         #endif
  178 
  179         if (x != data->bufX || y != data->bufY)
  180         {
  181             data->bufX = x;
  182             data->bufY = y;
  183             if (data->onMove) data->onMove(data);
  184         }
  185         
  186         /*#ifdef GTK3
  187         //data->_csd_w = data->_csd_h = -1;
  188         if (data->isTopLevel())
  189             return false;
  190         #endif*/
  191 
  192         w = event->width;
  193         h = event->height;
  194         
  195         if ((w != data->bufW) || (h != data->bufH) || (data->_event_resized) || !event->window)
  196         {
  197             data->_event_resized = false;
  198             data->bufW = w;
  199             data->bufH = h;
  200             #ifdef DEBUG_RESIZE
  201             fprintf(stderr, "cb_configure\n");
  202             #endif
  203             data->emitResize();
  204         }
  205     }
  206 #endif
  207 
  208     int x, y;
  209 
  210     if (!data->isOpened())
  211         return false;
  212 
  213     if (data->isTopLevel())
  214     {
  215         gtk_window_get_position(GTK_WINDOW(data->border), &x, &y);
  216     }
  217     else
  218     {
  219         x = event->x;
  220         y = event->y;
  221     }
  222 
  223     if (x != data->bufX || y != data->bufY)
  224     {
  225         data->bufX = x;
  226         data->bufY = y;
  227         if (data->onMove) data->onMove(data);
  228     }
  229     
  230     #ifdef DEBUG_RESIZE
  231     fprintf(stderr, "cb_configure: %s: (%d %d %d %d) -> (%d/%d %d/%d %d %d) window = %p send_event = %d\n", data->name(), data->bufX, data->bufY, data->bufW, data->bufH, x, event->x, y, event->y, event->width, event->height, event->window, event->send_event);
  232     #endif
  233 
  234     data->calcCsdSize();
  235 
  236     data->bufW = event->width - data->_csd_w;
  237     data->bufH = event->height - data->_csd_h;
  238         
  239     data->emitResize();
  240 
  241     return false;
  242 }
  243 
  244 #ifdef GTK3
  245 static gboolean cb_draw(GtkWidget *wid, cairo_t *cr, gMainWindow *data)
  246 {
  247     if (data->isTransparent())
  248     {
  249         if (data->background() == COLOR_DEFAULT)
  250             gt_cairo_set_source_color(cr, 0XFF000000);
  251         else
  252             gt_cairo_set_source_color(cr, data->background());
  253         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
  254         cairo_paint(cr);
  255     }
  256 
  257     if (data->_picture)
  258     {
  259         cairo_pattern_t *pattern;
  260 
  261         pattern = cairo_pattern_create_for_surface(data->_picture->getSurface());
  262         cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
  263 
  264         cairo_set_source(cr, pattern);
  265         cairo_paint(cr);
  266 
  267         cairo_pattern_destroy(pattern);
  268     }
  269 
  270     return false;
  271 }
  272 #else
  273 static gboolean cb_expose(GtkWidget *wid, GdkEventExpose *e, gMainWindow *data)
  274 {
  275     bool draw_bg = data->isTransparent();
  276     bool draw_pic = data->_picture;
  277 
  278     if (!draw_bg && !draw_pic)
  279         return false;
  280 
  281     cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(wid));
  282 
  283     if (draw_bg)
  284     {
  285         if (data->background() == COLOR_DEFAULT)
  286             gt_cairo_set_source_color(cr, 0xFF000000);
  287         else
  288             gt_cairo_set_source_color(cr, data->background());
  289         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
  290         cairo_paint(cr);
  291     }
  292 
  293     if (draw_pic)
  294     {
  295         cairo_pattern_t *pattern;
  296 
  297         gdk_cairo_region(cr, e->region);
  298         cairo_clip(cr);
  299 
  300         pattern = cairo_pattern_create_for_surface(data->_picture->getSurface());
  301         cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
  302 
  303         cairo_set_source(cr, pattern);
  304         cairo_paint(cr);
  305 
  306         cairo_pattern_destroy(pattern);
  307     }
  308 
  309     cairo_destroy(cr);
  310     return false;
  311 }
  312 #endif
  313 
  314 static gboolean my_key_press_event(GtkWidget *widget, GdkEventKey *event)
  315 {
  316   GtkWindow *window = GTK_WINDOW(widget);
  317   gboolean handled = FALSE;
  318     gboolean propagated = FALSE;
  319     GtkWidget *focus;
  320 
  321     focus = gtk_window_get_focus(window);
  322     if (focus && gtk_widget_get_realized(focus))
  323     {
  324         if (GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
  325         {
  326             propagated = TRUE;
  327             handled = gtk_window_propagate_key_event(window, event);
  328             if (handled)
  329                 return TRUE;
  330         }
  331     }
  332     
  333   /* handle mnemonics and accelerators */
  334   handled = gtk_window_activate_key(window, event);
  335     if (handled)
  336         return TRUE;
  337 
  338     if (!propagated && gtk_widget_get_realized(focus))
  339     {
  340         handled = gtk_window_propagate_key_event(window, event);
  341         if (handled)
  342             return TRUE;
  343     }
  344     
  345   /* Chain up, invokes binding set */
  346     GtkWidgetClass *parent_klass = (GtkWidgetClass*)g_type_class_peek(g_type_parent(GTK_TYPE_WINDOW));
  347   handled = parent_klass->key_press_event(widget, event);
  348 
  349   return handled;
  350 }
  351 
  352 
  353 static gboolean my_key_release_event(GtkWidget *widget, GdkEventKey *event)
  354 {
  355   GtkWindow *window = GTK_WINDOW (widget);
  356   gboolean handled = FALSE;
  357     GtkWidget *focus;
  358 
  359     focus = gtk_window_get_focus(window);
  360     if (focus && !gtk_widget_get_realized(focus))
  361         return handled;
  362     
  363   /* handle focus widget key events */
  364   if (!handled)
  365     handled = gtk_window_propagate_key_event(window, event);
  366 
  367   /* Chain up, invokes binding set */
  368   if (!handled)
  369     {
  370         GtkWidgetClass *parent_klass = (GtkWidgetClass*)g_type_class_peek(g_type_parent(GTK_TYPE_WINDOW));
  371     handled = parent_klass->key_release_event(widget, event);
  372     }
  373 
  374   return handled;
  375 }
  376 
  377 
  378 //-------------------------------------------------------------------------
  379 
  380 void gMainWindow::initialize()
  381 {
  382     //fprintf(stderr, "new window: %p in %p\n", this, parent());
  383 
  384     stack = 0;
  385     accel = NULL;
  386     _default = NULL;
  387     _cancel = NULL;
  388     menuBar = NULL;
  389     _icon = NULL;
  390     _picture = NULL;
  391     focus = 0;
  392     _title = NULL;
  393     _current = NULL;
  394     _resize_last_w = _resize_last_h = -1;
  395     _min_w = _min_h = _default_min_w = _default_min_h = 0;
  396     _csd_w  = _csd_h = -1;
  397 
  398     _opened = false;
  399     _sticky = false;
  400     _persistent = false;
  401     _mask = false;
  402     _masked = false;
  403     _resized = false;
  404     _top_only = false;
  405     _closing = false;
  406     _closed = false;
  407     _not_spontaneous = false;
  408     _skip_taskbar = false;
  409     _xembed = false;
  410     _activate = false;
  411     _hidden = false;
  412     _hideMenuBar = false;
  413     _showMenuBar = true;
  414     _initMenuBar = true;
  415     _popup = false;
  416     _maximized = _minimized = _fullscreen = false;
  417     _transparent = false;
  418     _utility = false;
  419     _no_take_focus = false;
  420     _moved = false;
  421     _resizable = true;
  422     _unmap = false;
  423     _grab_on_show   = false;
  424     _is_window = true;
  425     _no_background = true;
  426     _frame_init = false;
  427     
  428     onOpen = NULL;
  429     onShow = NULL;
  430     onHide = NULL;
  431     onMove = NULL;
  432     onResize = NULL;
  433     onActivate = NULL;
  434     onDeactivate = NULL;
  435     onState = NULL;
  436     onFontChange = NULL;
  437 
  438     accel = gtk_accel_group_new();
  439 }
  440 
  441 void gMainWindow::initWindow()
  442 {
  443     if (!isTopLevel())
  444     {
  445         //g_signal_connect(G_OBJECT(border), "configure-event", G_CALLBACK(cb_configure), (gpointer)this);
  446         g_signal_connect_after(G_OBJECT(border), "map", G_CALLBACK(cb_show), (gpointer)this);
  447         g_signal_connect(G_OBJECT(border),"unmap", G_CALLBACK(cb_hide),(gpointer)this);
  448         //g_signal_connect_after(G_OBJECT(border), "size-allocate", G_CALLBACK(cb_configure), (gpointer)this);
  449         ON_DRAW_BEFORE(widget, this, cb_expose, cb_draw);
  450     }
  451     else
  452     {
  453         //g_signal_connect(G_OBJECT(border),"size-request",G_CALLBACK(cb_realize),(gpointer)this);
  454         //g_signal_connect(G_OBJECT(border), "show", G_CALLBACK(cb_show),(gpointer)this);
  455         g_signal_connect(G_OBJECT(border), "hide", G_CALLBACK(cb_hide),(gpointer)this);
  456         g_signal_connect(G_OBJECT(border), "map-event", G_CALLBACK(cb_map),(gpointer)this);
  457         g_signal_connect(G_OBJECT(border), "unmap-event", G_CALLBACK(cb_unmap),(gpointer)this);
  458         g_signal_connect(G_OBJECT(border), "delete-event", G_CALLBACK(cb_close),(gpointer)this);
  459         g_signal_connect(G_OBJECT(border), "window-state-event", G_CALLBACK(cb_frame),(gpointer)this);
  460 
  461         gtk_widget_add_events(widget, GDK_BUTTON_MOTION_MASK | GDK_STRUCTURE_MASK);
  462         ON_DRAW_BEFORE(widget, this, cb_expose, cb_draw);
  463 
  464         //g_signal_connect(G_OBJECT(border), "configure-event", G_CALLBACK(cb_configure), (gpointer)this);
  465     }
  466 
  467     gtk_widget_add_events(border, GDK_STRUCTURE_MASK);
  468     g_signal_connect(G_OBJECT(border), "configure-event", G_CALLBACK(cb_configure), (gpointer)this);
  469 
  470     /*if (!_frame_init)
  471     {
  472         #if DEBUG_RESIZE
  473         fprintf(stderr, "init cb_resize_frame: %s\n", name());
  474         #endif
  475         g_signal_connect_after(G_OBJECT(frame), "size-allocate", G_CALLBACK(cb_resize_frame), (gpointer)this);
  476         _frame_init = true;
  477     }*/
  478     
  479     gtk_window_add_accel_group(GTK_WINDOW(topLevel()->border), accel);
  480 
  481     have_cursor = true; //parent() == 0 && !_xembed;
  482     setCanFocus(true);
  483     setNoTabFocus(true);
  484 }
  485 
  486 
  487 // workaround GTK+ accelerator management
  488 
  489 static void workaround_accel_management()
  490 {
  491     static bool _init = FALSE;
  492     if (_init)
  493         return;
  494     
  495     GtkWidgetClass *klass = (GtkWidgetClass*)g_type_class_peek(GTK_TYPE_WINDOW);
  496     klass->key_press_event = my_key_press_event;
  497     klass->key_release_event = my_key_release_event;
  498     _init = TRUE;
  499 }
  500 
  501 gMainWindow::gMainWindow() : gContainer(NULL)
  502 {
  503   initialize();
  504 
  505     windows = g_list_append(windows, (gpointer)this);
  506 
  507     border = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  508     workaround_accel_management();
  509 
  510     frame = gtk_fixed_new();
  511     widget = gtk_fixed_new();
  512 
  513     realize();
  514     initWindow();
  515 
  516     gtk_widget_show(frame);
  517     gtk_widget_show(widget);
  518     gtk_window_resize(GTK_WINDOW(border), 1, 1);
  519 }
  520 
  521 gMainWindow::gMainWindow(int plug) : gContainer(NULL)
  522 {
  523   initialize();
  524 
  525     windows = g_list_append(windows, (gpointer)this);
  526 
  527     _xembed = true;
  528 
  529     #ifdef GTK3
  530         border = PLATFORM.CreatePlug(plug);
  531         if (!border)
  532             return;
  533     #else
  534         border = gtk_plug_new(plug);
  535     #endif
  536 
  537     frame = gtk_fixed_new();
  538     widget = gtk_fixed_new();
  539 
  540     realize();
  541     initWindow();
  542 
  543     //gtk_widget_realize(border);
  544     gtk_widget_show(frame);
  545     gtk_widget_show(widget);
  546     gtk_window_resize(GTK_WINDOW(border), 1, 1);
  547     //gtk_widget_set_size_request(border, 1, 1);
  548 }
  549 
  550 gMainWindow::gMainWindow(gContainer *par) : gContainer(par)
  551 {
  552     initialize();
  553 
  554     border = gtk_event_box_new();
  555     frame = gtk_fixed_new();
  556     widget = gtk_fixed_new();
  557 
  558     realize();
  559     initWindow();
  560     
  561     gtk_widget_show(frame);
  562     gtk_widget_show(widget);
  563 }
  564 
  565 gMainWindow::~gMainWindow()
  566 {
  567     //fprintf(stderr, "delete window %p %s\n", this, name());
  568     
  569     if (!border)
  570         return;
  571 
  572     gApplication::handleFocusNow();
  573 
  574     if (_opened)
  575     {
  576         emit(SIGNAL(onClose));
  577         _opened = false;
  578         if (GTK_IS_WINDOW(border) && isModal())
  579             gApplication::exitLoop(this);
  580     }
  581 
  582     gPicture::assign(&_picture);
  583     gPicture::assign(&_icon);
  584     if (_title) g_free(_title);
  585     g_object_unref(accel);
  586 
  587     if (_active == this)
  588         _active = NULL;
  589 
  590     if (gApplication::mainWindow() == this)
  591         gApplication::setMainWindow(NULL);
  592 
  593     windows = g_list_remove(windows, (gpointer)this);
  594 }
  595 
  596 int gMainWindow::getStacking()
  597 {
  598     return stack;
  599 }
  600 
  601 void gMainWindow::setSticky(bool vl)
  602 {
  603     if (!isTopLevel()) return;
  604 
  605     _sticky = vl;
  606 
  607     if (vl) 
  608         gtk_window_stick(GTK_WINDOW(border));
  609     else
  610         gtk_window_unstick(GTK_WINDOW(border));
  611 }
  612 
  613 void gMainWindow::setStacking(int vl)
  614 {
  615   stack=vl;
  616     if (!isTopLevel()) return;
  617 
  618     switch (vl)
  619     {
  620         case 0:
  621             gtk_window_set_keep_below(GTK_WINDOW(border),FALSE);
  622             gtk_window_set_keep_above(GTK_WINDOW(border),FALSE);
  623             break;
  624         case 1:
  625             gtk_window_set_keep_below(GTK_WINDOW(border),FALSE);
  626             gtk_window_set_keep_above(GTK_WINDOW(border),TRUE);
  627             break;
  628         case 2:
  629             gtk_window_set_keep_above(GTK_WINDOW(border),FALSE);
  630             gtk_window_set_keep_below(GTK_WINDOW(border),TRUE);
  631             break;
  632     }
  633 }
  634 
  635 void gMainWindow::setRealBackground(gColor color)
  636 {
  637     if (!_picture)
  638     {
  639         gControl::setRealBackground(color);
  640         gMenu::updateColor(this);
  641     }
  642 }
  643 
  644 void gMainWindow::setRealForeground(gColor color)
  645 {
  646     gControl::setRealForeground(color);
  647     gMenu::updateColor(this);
  648 }
  649 
  650 void gMainWindow::move(int x, int y)
  651 {
  652     if (isTopLevel())
  653     {
  654         if (!_moved && (x || y))
  655             _moved = true;
  656 
  657         if (x == bufX && y == bufY)
  658             return;
  659 
  660         bufX = x;
  661         bufY = y;
  662 
  663         gtk_window_move(GTK_WINDOW(border), x, y);
  664     }
  665     else
  666     {
  667         gContainer::move(x,y);
  668     }
  669 }
  670 
  671 
  672 void gMainWindow::updateSize()
  673 {
  674     if (!isTopLevel() || !isOpened())
  675         return;
  676     
  677     #ifdef DEBUG_RESIZE
  678     fprintf(stderr, "updateSize: %s: %d %d / %d / %d %d\n", name(), width(), height(), isResizable(), _csd_w, _csd_h);
  679     #endif
  680     
  681     if (width() < 1 || height() < 1)
  682     {
  683         if (isVisible())
  684             gtk_widget_hide(border);
  685     }
  686     else
  687     {
  688         setGeometryHints();
  689         if (isResizable())
  690             gtk_window_resize(GTK_WINDOW(border), width(), height());
  691         else
  692         {
  693             //fprintf(stderr, "gMainWindow::updateSize: %s: %d %d\n", name(), width() + Max(_csd_w, 0), height() + Max(_csd_h, 0));
  694             gtk_widget_set_size_request(border, width() + Max(_csd_w, 0), height() + Max(_csd_h, 0));
  695         }
  696 
  697         if (isVisible())
  698             gtk_widget_show(border);
  699     }
  700 }
  701 
  702 bool gMainWindow::resize(int w, int h, bool no_decide)
  703 {
  704     if (!isTopLevel())
  705     {
  706         if (gContainer::resize(w, h, no_decide))
  707             return true;
  708     }
  709     else
  710     {
  711         if (w == bufW && h == bufH)
  712         {
  713             _resized = true;
  714             return true;
  715         }
  716 
  717         bufW = w < 0 ? 0 : w;
  718         bufH = h < 0 ? 0 : h;
  719         
  720         // we check for _resized to ignore the first resize()
  721         if (_resized && _default_min_w <= 0 && _default_min_h <= 0)
  722         {
  723             _default_min_w = w;
  724             _default_min_h = h;
  725         }
  726         
  727         updateSize();
  728     }
  729 
  730     _resized = true;
  731     return false;
  732 }
  733 
  734 bool gMainWindow::emitOpen()
  735 {
  736     //fprintf(stderr, "emit Open: %p (%d %d) %d resizable = %d fullscreen = %d\n", this, width(), height(), _opened, isResizable(), fullscreen());
  737 
  738     if (_opened)
  739         return false;
  740     
  741     _opened = true;
  742     _closed = false;
  743     //_no_resize_event = true; // If the event loop is run during emitOpen(), some spurious configure events are received.
  744 
  745     updateSize();
  746     //performArrange();
  747 
  748     gtk_widget_realize(border);
  749 
  750     emit(SIGNAL(onOpen));
  751     if (_closed)
  752     {
  753         _opened = false;
  754         return true;
  755     }
  756 
  757     //fprintf(stderr, "emit Move & Resize: %p\n", this);
  758     emit(SIGNAL(onMove));
  759     #ifdef DEBUG_RESIZE
  760     fprintf(stderr, "cb_open\n");
  761     #endif
  762     emitResize();
  763 
  764     return false;
  765 }
  766 
  767 void gMainWindow::present()
  768 {
  769     if (_no_take_focus)
  770         gtk_widget_show(GTK_WIDGET(border));
  771     else
  772         gtk_window_present(GTK_WINDOW(border));
  773 
  774     #ifdef GTK3
  775     updateStyleSheet(false);
  776     #endif
  777 }
  778 
  779 void gMainWindow::afterShow()
  780 {
  781     if (_activate)
  782     {
  783         present();
  784         _activate = false;
  785     }
  786 }
  787 
  788 void gMainWindow::setTransientFor()
  789 {
  790     gMainWindow *parent = _current;
  791 
  792     if (!parent)
  793         parent = gApplication::mainWindow();
  794         
  795     if (!parent)
  796         parent = _active;
  797 
  798     if (parent)
  799     {
  800         parent = parent->topLevel();
  801         if (parent != this)
  802         {
  803             //fprintf(stderr, "setTransientFor: %s -> %s\n", name(), parent->name());
  804             gtk_window_set_transient_for(GTK_WINDOW(border), GTK_WINDOW(parent->border));
  805         }
  806     }
  807 }
  808 
  809 void gMainWindow::setVisible(bool vl)
  810 {
  811     if (!vl)
  812         _hidden = true;
  813 
  814     if (vl == isVisible())
  815         return;
  816     
  817     if (!isTopLevel())
  818     {
  819         gContainer::setVisible(vl);
  820         if (vl)
  821             setActiveWindow(this);
  822         return;
  823     }
  824 
  825     if (vl)
  826     {
  827         //bool arr = !isVisible();
  828 
  829         emitOpen();
  830         if (!_opened)
  831             return;
  832 
  833         _not_spontaneous = !isVisible();
  834         _visible = true;
  835         _hidden = false;
  836 
  837         setTransparent(_transparent); // must not call gtk_window_present!
  838 
  839         if (isTopLevel())
  840         {
  841             /*if (!_xembed)
  842             {
  843                 fprintf(stderr, "gtk_window_group_add_window: %p -> %p\n", border, gApplication::currentGroup());
  844                 gtk_window_group_add_window(gApplication::currentGroup(), GTK_WINDOW(border));
  845                 fprintf(stderr, "-> %p\n", gtk_window_get_group(GTK_WINDOW(border)));
  846             }*/
  847 
  848             // Thanks for Ubuntu's GTK+ patching :-(
  849             #ifndef GTK3
  850             //gtk_window_set_has_resize_grip(GTK_WINDOW(border), false);
  851             if (g_object_class_find_property(G_OBJECT_GET_CLASS(border), "has-resize-grip"))
  852                 g_object_set(G_OBJECT(border), "has-resize-grip", false, (char *)NULL);
  853             #endif
  854 
  855             gtk_window_move(GTK_WINDOW(border), bufX, bufY);
  856 
  857             /*if (isPopup())
  858             {
  859                 gtk_widget_show_now(border);
  860                 gtk_widget_grab_focus(border);
  861             }
  862             else
  863             {*/
  864                 present();
  865             //}
  866 
  867             if (!_title || !*_title)
  868                 gtk_window_set_title(GTK_WINDOW(border), gApplication::defaultTitle());
  869 
  870             if (isUtility())
  871             {
  872                 setTransientFor();
  873                 if (!_no_take_focus)
  874                     present();
  875             }
  876 
  877             #ifndef GTK3
  878             if (gApplication::mainWindow() == this)
  879             {
  880                 int desktop = session_manager_get_desktop();
  881                 if (desktop >= 0)
  882                 {
  883                     //fprintf(stderr, "X11_window_set_desktop: %d (%d)\n", desktop, true);
  884                     X11_window_set_desktop((Window)handle(), true, desktop);
  885                     session_manager_set_desktop(-1);
  886                 }
  887             }
  888             #endif
  889         }
  890         else
  891         {
  892             gtk_widget_show(border);
  893             parent()->performArrange();
  894             performArrange();
  895         }
  896 
  897         drawMask();
  898 
  899         if (focus)
  900         {
  901             //fprintf(stderr, "focus = %s\n", focus->name());
  902             focus->setFocus();
  903             focus = NULL;
  904         }
  905         else
  906         {
  907             gControl *ctrl = this;
  908             
  909             for(;;)
  910             {
  911                 ctrl = ctrl->nextFocus();
  912                 if (!ctrl)
  913                     break;
  914                 
  915                 if (ctrl->isReallyVisible() && ctrl->isEnabled() && ctrl->canFocus())
  916                 {
  917                     ctrl->setFocus();
  918                     break;
  919                 }
  920                 
  921                 if (ctrl == this)
  922                     break;
  923             }
  924         }
  925             
  926         if (isSkipTaskBar())
  927             _activate = true;
  928 
  929         /*if (arr)
  930         {
  931                 fprintf(stderr, "#4\n");
  932                 performArrange();
  933         }*/
  934     }
  935     else
  936     {
  937         if (this == _active)
  938             focus = gApplication::activeControl();
  939 
  940         _not_spontaneous = isVisible();
  941         gContainer::setVisible(false);
  942 
  943         if (_popup)
  944             gApplication::exitLoop(this);
  945 
  946         if (gApplication::_button_grab && !gApplication::_button_grab->isReallyVisible())
  947                 gApplication::setButtonGrab(NULL);
  948     }
  949 }
  950 
  951 
  952 void gMainWindow::setMinimized(bool vl)
  953 {
  954     if (!isTopLevel()) return;
  955 
  956     _minimized = vl;
  957     if (vl) gtk_window_iconify(GTK_WINDOW(border));
  958     else    gtk_window_deiconify(GTK_WINDOW(border));
  959 }
  960 
  961 void gMainWindow::setMaximized(bool vl)
  962 {
  963     if (!isTopLevel())
  964         return;
  965 
  966     _maximized = vl;
  967     _csd_w = _csd_h = -1;
  968 
  969     if (vl)
  970         gtk_window_maximize(GTK_WINDOW(border));
  971     else
  972         gtk_window_unmaximize(GTK_WINDOW(border));
  973 }
  974 
  975 void gMainWindow::setFullscreen(bool vl)
  976 {
  977     if (!isTopLevel())
  978         return;
  979 
  980     _fullscreen = vl;
  981     _csd_w = _csd_h = -1;
  982 
  983     if (vl)
  984     {
  985         gtk_window_fullscreen(GTK_WINDOW(border));
  986         if (isVisible())
  987             present();
  988     }
  989     else
  990         gtk_window_unfullscreen(GTK_WINDOW(border));
  991 }
  992 
  993 void gMainWindow::center()
  994 {
  995     if (!isTopLevel()) return;
  996 
  997 #ifdef GTK3
  998 
  999     if (MAIN_platform_is_wayland)
 1000         gtk_window_set_position(GTK_WINDOW(border), GTK_WIN_POS_CENTER_ON_PARENT);
 1001     
 1002 #endif
 1003 
 1004     GdkRectangle rect;
 1005     int x, y;
 1006     
 1007     gtk_widget_realize(border);
 1008     gDesktop::availableGeometry(screen(), &rect);
 1009     
 1010     x = rect.x + (rect.width - width()) / 2;
 1011     y = rect.y + (rect.height - height()) / 2;
 1012 
 1013     move(x, y);
 1014 }
 1015 
 1016 bool gMainWindow::isModal() const
 1017 {
 1018     if (!isTopLevel()) return false;
 1019 
 1020     return gtk_window_get_modal(GTK_WINDOW(border));
 1021 }
 1022 
 1023 void gMainWindow::showModal()
 1024 {
 1025   gMainWindow *save;
 1026 
 1027     if (!isTopLevel()) return;
 1028     if (isModal()) return;
 1029 
 1030     gMouse::finishEvent();
 1031     
 1032     //show();
 1033     setType(GTK_WINDOW_TOPLEVEL);
 1034 
 1035     gtk_window_set_modal(GTK_WINDOW(border), true);
 1036     setTransientFor();
 1037 
 1038     save = _current;
 1039     _current = this;
 1040 
 1041     center();
 1042     show();
 1043     gtk_grab_add(border);
 1044     gApplication::enterLoop(this);
 1045 
 1046     _current = save;
 1047 
 1048     gtk_grab_remove(border);
 1049     gtk_window_set_modal(GTK_WINDOW(border), false);
 1050 
 1051     if (!_persistent)
 1052         destroyNow();
 1053     else
 1054         hide();
 1055 }
 1056 
 1057 void gMainWindow::showPopup(int x, int y)
 1058 {
 1059   gMainWindow *save;
 1060     bool has_border;
 1061     int oldx, oldy;
 1062     GdkWindowTypeHint type;
 1063 
 1064     if (!isTopLevel()) return;
 1065     if (isModal()) return;
 1066 
 1067     gMouse::finishEvent();
 1068 
 1069     //gtk_widget_unrealize(border);
 1070     //((GtkWindow *)border)->type = GTK_WINDOW_POPUP;
 1071     //gtk_widget_realize(border);
 1072 
 1073     oldx = left();
 1074     oldy = top();
 1075 
 1076     _popup = true;
 1077     setType(GTK_WINDOW_POPUP);
 1078     
 1079     has_border = gtk_window_get_decorated(GTK_WINDOW(border));
 1080     type = gtk_window_get_type_hint(GTK_WINDOW(border));
 1081 
 1082     gtk_window_set_decorated(GTK_WINDOW(border), false);
 1083     gtk_window_set_type_hint(GTK_WINDOW(border), GDK_WINDOW_TYPE_HINT_COMBO);
 1084     
 1085     setTransientFor();
 1086 
 1087     gtk_window_resize(GTK_WINDOW(border), bufW, bufH);
 1088   move(x, y);
 1089     //raise();
 1090     setFocus();
 1091 
 1092     save = _current;
 1093     _current = this;
 1094 
 1095     gApplication::enterPopup(this);
 1096 
 1097     _current = save;
 1098     _popup = false;
 1099 
 1100     if (!_persistent)
 1101     {
 1102         destroyNow();
 1103     }
 1104     else
 1105     {
 1106         hide();
 1107 
 1108         gtk_window_set_decorated(GTK_WINDOW(border), has_border);
 1109         gtk_window_set_type_hint(GTK_WINDOW(border), type);
 1110 
 1111         move(oldx, oldy);
 1112     }
 1113 }
 1114 
 1115 void gMainWindow::showActivate()
 1116 {
 1117     bool v = isTopLevel() && isVisible() && !_no_take_focus;
 1118 
 1119     setType(GTK_WINDOW_TOPLEVEL);
 1120 
 1121     if (!_moved)
 1122         center();
 1123     emitOpen();
 1124     if (!_opened)
 1125         return;
 1126     show();
 1127     if (v)
 1128         present();
 1129 }
 1130 
 1131 void gMainWindow::activate()
 1132 {
 1133     if (isTopLevel() && isVisible())
 1134         present();
 1135 }
 1136 
 1137 void gMainWindow::showPopup()
 1138 {
 1139     int x, y;
 1140     gMouse::getScreenPos(&x, &y);
 1141     showPopup(x, y);
 1142 }
 1143 
 1144 void gMainWindow::restack(bool raise)
 1145 {
 1146     if (!isTopLevel())
 1147     {
 1148         gControl::restack(raise);
 1149         return;
 1150     }
 1151     
 1152     if (raise)
 1153         present();
 1154     else
 1155         gdk_window_lower(gtk_widget_get_window(border));
 1156 }
 1157 
 1158 const char* gMainWindow::text()
 1159 {
 1160     return _title;
 1161 }
 1162 
 1163 void gMainWindow::setText(const char *txt)
 1164 {
 1165     if (txt != _title)
 1166     {
 1167         if (_title) 
 1168         {
 1169             g_free(_title);
 1170             _title = NULL;
 1171         }
 1172         
 1173         if (txt && *txt)
 1174             _title = g_strdup(txt);
 1175     }
 1176 
 1177     if (isTopLevel())
 1178         gtk_window_set_title(GTK_WINDOW(border), _title ? _title : "");
 1179 }
 1180 
 1181 bool gMainWindow::hasBorder()
 1182 {
 1183     if (isTopLevel())
 1184         return gtk_window_get_decorated(GTK_WINDOW(border));
 1185     else
 1186         return false;
 1187 }
 1188 
 1189 bool gMainWindow::isResizable()
 1190 {
 1191     if (isTopLevel())
 1192         return _resizable;
 1193     else
 1194         return false;
 1195 }
 1196 
 1197 void gMainWindow::setBorder(bool b)
 1198 {
 1199     if (!isTopLevel())
 1200         return;
 1201 
 1202     gtk_window_set_decorated(GTK_WINDOW(border), b);
 1203 }
 1204 
 1205 void gMainWindow::setResizable(bool b)
 1206 {
 1207     if (!isTopLevel())
 1208         return;
 1209 
 1210     if (b == isResizable())
 1211         return;
 1212 
 1213     _resizable = b;
 1214     updateSize();
 1215 }
 1216 
 1217 void gMainWindow::setSkipTaskBar(bool b)
 1218 {
 1219     if (!isTopLevel()) return;
 1220     _skip_taskbar = b;
 1221     gtk_window_set_skip_taskbar_hint(GTK_WINDOW(border), b);
 1222 }
 1223 
 1224 
 1225 /*gPicture* gMainWindow::icon()
 1226 {
 1227     GdkPixbuf *buf;
 1228     gPicture *pic;
 1229 
 1230     if (!isTopLevel()) return NULL;
 1231 
 1232     buf=gtk_window_get_icon(GTK_WINDOW(border));
 1233     if (!buf) return NULL;
 1234 
 1235     pic=gPicture::fromPixbuf(buf);
 1236 
 1237     return pic;
 1238 }*/
 1239 
 1240 void gMainWindow::setIcon(gPicture *pic)
 1241 {
 1242   gPicture::assign(&_icon, pic);
 1243 
 1244     if (!isTopLevel()) return;
 1245   gtk_window_set_icon(GTK_WINDOW(border), pic ? pic->getPixbuf() : NULL);
 1246 }
 1247 
 1248 
 1249 void gMainWindow::setTopOnly(bool vl)
 1250 {
 1251     if (!isTopLevel()) return;
 1252 
 1253     _top_only = vl;
 1254     gtk_window_set_keep_above (GTK_WINDOW(border), vl);
 1255 }
 1256 
 1257 
 1258 void gMainWindow::setMask(bool vl)
 1259 {
 1260     if (_mask == vl)
 1261         return;
 1262 
 1263     _mask = vl;
 1264     drawMask();
 1265 }
 1266 
 1267 void gMainWindow::setPicture(gPicture *pic)
 1268 {
 1269   gPicture::assign(&_picture, pic);
 1270   drawMask();
 1271 }
 1272 
 1273 void gMainWindow::remap()
 1274 {
 1275     if (!isVisible())
 1276         return;
 1277 
 1278     gtk_widget_unmap(border);
 1279     gtk_widget_map(border);
 1280 
 1281     if (_skip_taskbar) { setSkipTaskBar(false); setSkipTaskBar(true); }
 1282     if (_top_only) { setTopOnly(false); setTopOnly(true); }
 1283     if (_sticky) { setSticky(false); setSticky(true); }
 1284     if (stack) { setStacking(0); setStacking(stack); }
 1285 }
 1286 
 1287 void gMainWindow::drawMask()
 1288 {
 1289     bool do_remap = false;
 1290 
 1291     if (!isVisible())
 1292         return;
 1293 
 1294 #ifdef GTK3
 1295 
 1296     cairo_region_t *mask;
 1297 
 1298     if (_mask && _picture)
 1299         mask = gdk_cairo_region_create_from_surface(_picture->getSurface());
 1300     else
 1301         mask = NULL;
 1302 
 1303     gdk_window_shape_combine_region(gtk_widget_get_window(border), mask, 0, 0);
 1304     if (mask)
 1305         cairo_region_destroy(mask);
 1306 
 1307     refresh();
 1308 
 1309 #else
 1310 
 1311     GdkBitmap *mask = (_mask && _picture) ? _picture->getMask() : NULL;
 1312     do_remap = !mask && _masked;
 1313 
 1314     gdk_window_shape_combine_mask(border->window, mask, 0, 0);
 1315 
 1316 #endif
 1317 
 1318     if (_picture)
 1319     {
 1320         gtk_widget_set_app_paintable(border, TRUE);
 1321         gtk_widget_realize(border);
 1322         gtk_widget_realize(widget);
 1323         // What for??
 1324         /*for (int i = 0; i < controlCount(); i++)
 1325             getControl(i)->refresh();*/
 1326     }
 1327     else if (!_transparent)
 1328     {
 1329         gtk_widget_set_app_paintable(border, FALSE);
 1330         setRealBackground(background());
 1331     }
 1332 
 1333     _masked = mask != NULL;
 1334 
 1335     if (do_remap)
 1336         remap();
 1337     else
 1338     {
 1339         if (!_skip_taskbar)
 1340         {
 1341             setSkipTaskBar(true);
 1342             setSkipTaskBar(false);
 1343         }
 1344     }
 1345 }
 1346 
 1347 int gMainWindow::menuCount()
 1348 {
 1349     if (!menuBar) return 0;
 1350     return gMenu::winChildCount(this);
 1351 }
 1352 
 1353 void gMainWindow::setPersistent(bool vl)
 1354 {
 1355   _persistent = vl;
 1356 }
 1357 
 1358 bool gMainWindow::doClose(bool destroying)
 1359 {
 1360     if (_closing || _closed)
 1361         return false;
 1362 
 1363     if (!isTopLevel())
 1364     {
 1365         if (_opened)
 1366         {
 1367             _closing = true;
 1368             _closed = !onClose(this);
 1369             _closing = false;
 1370             _opened = !_closed;
 1371         }
 1372         else
 1373             _closed = true;
 1374 
 1375         if (_closed)
 1376         {
 1377             if (_persistent || destroying)
 1378                 hide();
 1379             else
 1380                 destroy();
 1381         }
 1382     }
 1383     else
 1384     {
 1385         if (_opened)
 1386         {
 1387             if (isModal() && !gApplication::hasLoop(this))
 1388                 return true;
 1389 
 1390             _closing = true;
 1391             _closed = !onClose(this);
 1392             _closing = false;
 1393             _opened = !_closed;
 1394 
 1395             if (!_opened && isModal())
 1396                 gApplication::exitLoop(this);
 1397         }
 1398 
 1399         if (!_opened) // && !modal())
 1400         {
 1401             if (_active == this)
 1402                 setActiveWindow(NULL);
 1403 
 1404             if (!isModal())
 1405             {
 1406                 if (_persistent || destroying)
 1407                     hide();
 1408                 else
 1409                     destroy();
 1410             }
 1411         }
 1412     }
 1413     
 1414     return _opened;
 1415 }
 1416 
 1417 
 1418 bool gMainWindow::close()
 1419 {
 1420     return doClose();
 1421 }
 1422 
 1423 static void hide_hidden_children(gContainer *cont)
 1424 {
 1425     int i;
 1426     gControl *child;
 1427 
 1428     for (i = 0;; i++)
 1429     {
 1430         child = cont->child(i);
 1431         if (!child)
 1432             break;
 1433         if (!child->isVisible())
 1434             gtk_widget_hide(child->border);
 1435         else if (child->isContainer())
 1436             hide_hidden_children((gContainer *)child);
 1437     }
 1438 }
 1439 
 1440 void gMainWindow::createWindow(GtkWidget *new_border)
 1441 {
 1442     gt_widget_reparent(frame, new_border);
 1443     createBorder(new_border);
 1444     registerControl();
 1445 }
 1446 
 1447 void gMainWindow::reparent(gContainer *newpr, int x, int y)
 1448 {
 1449     int w, h;
 1450     gColor fg, bg;
 1451 
 1452     if (_xembed)
 1453         return;
 1454 
 1455     bg = background();
 1456     fg = foreground();
 1457 
 1458     if (isTopLevel() && newpr)
 1459     {
 1460         gtk_window_remove_accel_group(GTK_WINDOW(topLevel()->border), accel);
 1461 
 1462         createWindow(gtk_event_box_new());
 1463 
 1464         setParent(newpr);
 1465         connectParent();
 1466         borderSignals();
 1467 
 1468         initWindow();
 1469         
 1470         setBackground(bg);
 1471         setForeground(fg);
 1472         setFont(font());
 1473 
 1474         checkMenuBar();
 1475 
 1476         bufX = bufY = 0;
 1477         move(x, y);
 1478 
 1479         gtk_widget_set_size_request(border, width(), height());
 1480 
 1481         // Hidden children are incorrectly shown. Fix that!
 1482         hideHiddenChildren();
 1483     }
 1484     else if ((!isTopLevel() && !newpr)
 1485              || (isTopLevel() && isPopup()))
 1486     {
 1487         gtk_window_remove_accel_group(GTK_WINDOW(topLevel()->border), accel);
 1488         // TODO: test that
 1489         
 1490         createWindow(gtk_window_new(GTK_WINDOW_TOPLEVEL));
 1491 
 1492         if (parent())
 1493         {
 1494             parent()->remove(this);
 1495             parent()->arrange();
 1496             setParent(NULL);
 1497         }
 1498 
 1499         borderSignals();
 1500         initWindow();
 1501         
 1502         setBackground(bg);
 1503         setForeground(fg);
 1504         setFont(font());
 1505         setText(text());
 1506 
 1507         move(x, y);
 1508         w = width();
 1509         h = height();
 1510         bufW = bufH = -1;
 1511         gtk_widget_set_size_request(border, 1, 1);
 1512         resize(w, h);
 1513 
 1514         hideHiddenChildren();
 1515         
 1516         gtk_widget_set_sensitive(frame, FALSE);
 1517         gtk_widget_set_sensitive(frame, TRUE);
 1518 
 1519         _popup = false; //type == GTK_WINDOW_POPUP;
 1520     }
 1521     else
 1522     {
 1523         gContainer::reparent(newpr, x, y);
 1524     }
 1525 }
 1526 
 1527 void gMainWindow::setType(GtkWindowType type)
 1528 {
 1529     int w, h;
 1530     gColor bg, fg;
 1531 
 1532     if (!isTopLevel())
 1533         return;
 1534     if (gtk_window_get_window_type(GTK_WINDOW(border)) == type)
 1535         return;
 1536     
 1537     bg = background();
 1538     fg = foreground();
 1539 
 1540     gtk_window_remove_accel_group(GTK_WINDOW(border), accel);
 1541     // TODO: test that
 1542     
 1543     createWindow(gtk_window_new(type));
 1544 
 1545     initWindow();
 1546     borderSignals();
 1547     setBackground(bg);
 1548     setForeground(fg);
 1549     setFont(font());
 1550 
 1551     w = width();
 1552     h = height();
 1553     bufW = bufH = -1;
 1554     gtk_widget_set_size_request(border, 1, 1);
 1555     resize(w, h);
 1556 
 1557     hideHiddenChildren();
 1558 }
 1559 
 1560 static void fill_children_list(gContainer *cont, GPtrArray *list)
 1561 {
 1562     int i;
 1563     gControl *control;
 1564     
 1565     for (i = 0; i < cont->childCount(); i++)
 1566     {
 1567         control = cont->child(i);
 1568         if (control->isContainer()) // && !control->isWindow())
 1569             fill_children_list((gContainer *)control, list);
 1570         g_ptr_array_add(list, control);
 1571     }
 1572 }
 1573 
 1574 GPtrArray *gMainWindow::getControlList()
 1575 {
 1576     GPtrArray *list = g_ptr_array_new();
 1577     fill_children_list(this, list);
 1578     return list;
 1579 }
 1580 
 1581 gControl *gMainWindow::getControl(const char *name)
 1582 {
 1583     GPtrArray *list = getControlList();
 1584     uint i;
 1585     gControl *ctrl;
 1586 
 1587     for (i = 0; i < list->len; i++)
 1588     {
 1589         ctrl = (gControl *)g_ptr_array_index(list, i);
 1590         if (!ctrl->isDestroyed() && !strcasecmp(ctrl->name(), name))
 1591             break;
 1592         ctrl = NULL;
 1593     }
 1594 
 1595     g_ptr_array_unref(list);
 1596     return ctrl;
 1597 }
 1598 
 1599 int gMainWindow::clientX()
 1600 {
 1601     return 0;
 1602 }
 1603 
 1604 int gMainWindow::containerX()
 1605 {
 1606     return 0;
 1607 }
 1608 
 1609 int gMainWindow::clientY()
 1610 {
 1611     if (isMenuBarVisible())
 1612         return menuBarHeight();
 1613     else
 1614         return 0;
 1615 }
 1616 
 1617 int gMainWindow::containerY()
 1618 {
 1619     return 0;
 1620 }
 1621 
 1622 
 1623 int gMainWindow::clientWidth()
 1624 {
 1625     return width();
 1626 }
 1627 
 1628 
 1629 int gMainWindow::menuBarHeight()
 1630 {
 1631     int h = 0;
 1632 
 1633     if (menuBar)
 1634     {
 1635         //gtk_widget_show(GTK_WIDGET(menuBar));
 1636         //fprintf(stderr, "menuBarHeight: gtk_widget_get_visible: %d\n", gtk_widget_get_visible(GTK_WIDGET(menuBar)));
 1637 #ifdef GTK3
 1638         gtk_widget_get_preferred_height(GTK_WIDGET(menuBar), NULL, &h);
 1639 #else
 1640         GtkRequisition req = { 0, 0 };
 1641         gtk_widget_size_request(GTK_WIDGET(menuBar), &req);
 1642         h = req.height;
 1643 #endif
 1644         //fprintf(stderr, "menuBarHeight: %d\n", h);
 1645     }
 1646 
 1647     return h;
 1648 }
 1649 
 1650 int gMainWindow::clientHeight()
 1651 {
 1652     if (isMenuBarVisible())
 1653         return height() - menuBarHeight();
 1654     else
 1655         return height();
 1656 }
 1657 
 1658 void gMainWindow::setActiveWindow(gControl *control)
 1659 {
 1660     gMainWindow *window = control ? control->window() : NULL;
 1661     gMainWindow *old = _active;
 1662 
 1663     if (window == _active)
 1664         return;
 1665 
 1666     _active = window;
 1667 
 1668     //fprintf(stderr, "setActiveWindow: %p %s\n", _active, _active ? _active->name() : "");
 1669 
 1670     if (old)
 1671         old->emit(SIGNAL(old->onDeactivate));
 1672 
 1673     if (window)
 1674         window->emit(SIGNAL(window->onActivate));
 1675 }
 1676 
 1677 #ifdef GDK_WINDOWING_X11
 1678 bool gMainWindow::isUtility() const
 1679 {
 1680     return _utility;
 1681 }
 1682 
 1683 void gMainWindow::setUtility(bool v)
 1684 {
 1685     bool remap = false;
 1686 
 1687     if (!isTopLevel())
 1688         return;
 1689 
 1690     // TODO: works only if the window is not mapped!
 1691 
 1692     _utility = v;
 1693 #if GTK_CHECK_VERSION(2, 20, 0)
 1694     if (gtk_widget_get_mapped(border))
 1695 #else
 1696     if (GTK_WIDGET_MAPPED(border))
 1697 #endif
 1698     {
 1699         remap = true;
 1700         gtk_widget_unmap(border);
 1701     }
 1702 
 1703     gtk_window_set_type_hint(GTK_WINDOW(border), v ? GDK_WINDOW_TYPE_HINT_DIALOG : GDK_WINDOW_TYPE_HINT_NORMAL);
 1704 
 1705     if (remap)
 1706         gtk_widget_map(border);
 1707 }
 1708 #else
 1709 bool gMainWindow::isUtility()
 1710 {
 1711     return _utility;
 1712 }
 1713 
 1714 void gMainWindow::setUtility(bool v)
 1715 {
 1716     _utility = v;
 1717 }
 1718 #endif
 1719 
 1720 void gMainWindow::configure()
 1721 {
 1722     static bool init = FALSE;
 1723     static GB_FUNCTION _init_menubar_shortcut_func;
 1724 
 1725     int h;
 1726 
 1727     if (bufW < 1 || bufH < 1)
 1728         return;
 1729 
 1730     if (_initMenuBar != isMenuBarVisible())
 1731     {
 1732         _initMenuBar = !_initMenuBar;
 1733 
 1734         if (!init)
 1735         {
 1736             GB.GetFunction(&_init_menubar_shortcut_func, (void *)GB.FindClass("_Gui"), "_InitMenuBarShortcut", NULL, NULL);
 1737             init = TRUE;
 1738         }
 1739 
 1740         GB.Push(1, GB_T_OBJECT, hFree);
 1741         GB.Call(&_init_menubar_shortcut_func, 1, FALSE);
 1742     }
 1743 
 1744     h = menuBarHeight();
 1745 
 1746     #ifdef DEBUG_RESIZE
 1747     fprintf(stderr, "configure: %s: menu = %d h = %d / %d x %d\n", name(), isMenuBarVisible(), h, width(), height());
 1748     #endif
 1749 
 1750     if (isMenuBarVisible())
 1751     {
 1752         gtk_fixed_move(GTK_FIXED(frame), GTK_WIDGET(menuBar), 0, 0);
 1753         if (h > 1)
 1754             gtk_widget_set_size_request(GTK_WIDGET(menuBar), width(), h);
 1755         gtk_fixed_move(GTK_FIXED(frame), widget, 0, h);
 1756         gtk_widget_set_size_request(widget, width(), Max(0, height() - h));
 1757     }
 1758     else
 1759     {
 1760         if (menuBar)
 1761             gtk_fixed_move(GTK_FIXED(frame), GTK_WIDGET(menuBar), -width(), -h);
 1762         gtk_fixed_move(GTK_FIXED(frame), widget, 0, 0);
 1763         gtk_widget_set_size_request(widget, width(), height());
 1764     }
 1765 }
 1766 
 1767 bool gMainWindow::setMenuBarVisible(bool v)
 1768 {
 1769     if (_showMenuBar == v)
 1770         return TRUE;
 1771 
 1772     _showMenuBar = v;
 1773 
 1774     if (!menuBar)
 1775         return TRUE;
 1776 
 1777     configure();
 1778     performArrange();
 1779 
 1780     return FALSE;
 1781 }
 1782 
 1783 bool gMainWindow::isMenuBarVisible()
 1784 {
 1785     //fprintf(stderr, "isMenuBarVisible: %d\n", !!(menuBar && !_hideMenuBar && _showMenuBar));
 1786     return menuBar && !_hideMenuBar && _showMenuBar; //|| (menuBar && GTK_WIDGET_MAPPED(GTK_WIDGET(menuBar)));
 1787 }
 1788 
 1789 void gMainWindow::updateFont()
 1790 {
 1791     gContainer::updateFont();
 1792     gMenu::updateFont(this);
 1793     emit(SIGNAL(onFontChange));
 1794 }
 1795 
 1796 void gMainWindow::checkMenuBar()
 1797 {
 1798     int i;
 1799     gMenu *menu;
 1800 
 1801     //fprintf(stderr, "gMainWindow::checkMenuBar\n");
 1802 
 1803     if (menuBar)
 1804     {
 1805         _hideMenuBar = true;
 1806         for (i = 0;; i++)
 1807         {
 1808             menu = gMenu::winChildMenu(this, i);
 1809             if (!menu)
 1810                 break;
 1811             if (menu->isVisible() && !menu->isSeparator())
 1812             {
 1813                 _hideMenuBar = false;
 1814                 break;
 1815             }
 1816         }
 1817     }
 1818 
 1819     configure();
 1820     performArrange();
 1821 }
 1822 
 1823 void gMainWindow::embedMenuBar(GtkWidget *border)
 1824 {
 1825     if (menuBar)
 1826     {
 1827         g_object_ref(G_OBJECT(menuBar));
 1828 
 1829         if (gtk_widget_get_parent(GTK_WIDGET(menuBar)))
 1830             gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(GTK_WIDGET(menuBar))), GTK_WIDGET(menuBar));
 1831 
 1832         gtk_fixed_put(GTK_FIXED(frame), GTK_WIDGET(menuBar), 0, 0);
 1833 
 1834         g_object_unref(G_OBJECT(menuBar));
 1835 
 1836         gtk_widget_show(GTK_WIDGET(menuBar));
 1837 
 1838         gMenu::updateFont(this);
 1839         gMenu::updateColor(this);
 1840 
 1841         checkMenuBar();
 1842     }
 1843 }
 1844 
 1845 /*bool gMainWindow::getScreenPos(int *x, int *y)
 1846 {
 1847     return gContainer::getScreenPos(x, y);
 1848 }*/
 1849 
 1850 double gMainWindow::opacity()
 1851 {
 1852     if (isTopLevel())
 1853 #if GTK_CHECK_VERSION(3, 8, 0)
 1854         return gtk_widget_get_opacity(border);
 1855 #else
 1856         return gtk_window_get_opacity(GTK_WINDOW(border));
 1857 #endif
 1858     else
 1859         return 1.0;
 1860 }
 1861 
 1862 void gMainWindow::setOpacity(double v)
 1863 {
 1864     if (isTopLevel())
 1865 #if GTK_CHECK_VERSION(3, 8, 0)
 1866         gtk_widget_set_opacity(border, v);
 1867 #else
 1868         gtk_window_set_opacity(GTK_WINDOW(border), v);
 1869 #endif
 1870 }
 1871 
 1872 int gMainWindow::screen()
 1873 {
 1874     gMainWindow *tl = topLevel();
 1875 #if GTK_CHECK_VERSION(3, 22, 0)
 1876     GdkWindow *window = gtk_widget_get_window(tl->border);
 1877     if (window)
 1878         return gt_find_monitor(gdk_display_get_monitor_at_window(gdk_display_get_default(), window));
 1879     else
 1880         return -1;
 1881 #else
 1882     return gdk_screen_get_number(gtk_window_get_screen(GTK_WINDOW(tl->border)));
 1883 #endif
 1884 }
 1885 
 1886 void gMainWindow::emitResize()
 1887 {
 1888     if (bufW == _resize_last_w && bufH == _resize_last_h)
 1889         return;
 1890 
 1891     #ifdef DEBUG_RESIZE
 1892     fprintf(stderr, "emitResize: %s: %d %d\n", name(), bufW, bufH);
 1893     #endif
 1894     _resize_last_w = bufW;
 1895     _resize_last_h = bufH;
 1896     configure();
 1897     performArrange();
 1898     emit(SIGNAL(onResize));
 1899 }
 1900 
 1901 static void emit_resize_later(gMainWindow *window)
 1902 {
 1903     window->emitResize();
 1904 }
 1905 
 1906 void gMainWindow::emitResizeLater()
 1907 {
 1908     GB.Post((GB_CALLBACK)emit_resize_later, (intptr_t)this);
 1909 }
 1910 
 1911 void gMainWindow::setGeometryHints()
 1912 {
 1913     GdkGeometry geometry;
 1914     int min_w, min_h;
 1915     
 1916     if (isTopLevel())
 1917     {
 1918         min_w = _min_w;
 1919         min_h = _min_h;
 1920 
 1921         if (isResizable())
 1922         {
 1923             if (isModal() || isUtility())
 1924             {
 1925                 if (!min_w && !min_h)
 1926                 {
 1927                     min_w = _default_min_w;
 1928                     min_h = _default_min_h;
 1929                 }
 1930             }
 1931 
 1932             geometry.min_width = min_w + Max(_csd_w, 0);
 1933             geometry.min_height = min_h + Max(_csd_h, 0);
 1934             
 1935             geometry.max_width = 32767;
 1936             geometry.max_height = 32767;
 1937         }
 1938         else
 1939         {
 1940             geometry.max_width = geometry.min_width = width() + Max(_csd_w, 0);
 1941             geometry.max_height = geometry.min_height = height() + Max(_csd_h, 0);
 1942         }
 1943 
 1944         #if DEBUG_RESIZE
 1945         fprintf(stderr, "setGeometryHints: %s: min size: %d %d (%d x %d)\n", name(), geometry.min_width, geometry.min_height, width(), height());
 1946         #endif
 1947         gtk_window_set_geometry_hints(GTK_WINDOW(border), NULL, &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
 1948         //gdk_window_set_geometry_hints(gtk_widget_get_window(border), &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_POS));
 1949     }
 1950 }
 1951 
 1952 void gMainWindow::setBackground(gColor vl)
 1953 {
 1954     if (!_transparent)
 1955         gControl::setBackground(vl);
 1956     else
 1957         _bg = vl;
 1958 }
 1959 
 1960 void gMainWindow::setTransparent(bool vl)
 1961 {
 1962     if (!vl)
 1963         return;
 1964 
 1965     _transparent = TRUE;
 1966     
 1967     /*#ifdef GTK3
 1968     if (MAIN_platform_is_wayland)
 1969         return;
 1970     #endif*/
 1971 
 1972     if (!isVisible())
 1973         return;
 1974 
 1975 #ifdef GTK3
 1976     GdkScreen *screen = NULL;
 1977     GdkVisual *visual = NULL;
 1978 
 1979     screen = gtk_widget_get_screen(border);
 1980     visual = gdk_screen_get_rgba_visual(screen);
 1981     if (visual == NULL)
 1982         return;
 1983 #else
 1984     GdkScreen *screen;
 1985     GdkColormap *colormap;
 1986 
 1987     screen = gtk_widget_get_screen(border);
 1988     colormap = gdk_screen_get_rgba_colormap(screen);
 1989     if (colormap == NULL)
 1990         return;
 1991 #endif
 1992 
 1993     gtk_widget_unrealize(border);
 1994 
 1995     gtk_widget_set_app_paintable(border, TRUE);
 1996 
 1997 #ifdef GTK3
 1998     gtk_widget_set_visual(border, visual);
 1999 #else
 2000     gtk_widget_set_colormap(border, colormap);
 2001 #endif
 2002 
 2003     gtk_widget_realize(border);
 2004 
 2005     /*int w = width();
 2006     int h = height();
 2007 
 2008     bufW = w - 1;
 2009     resize(w, h);*/
 2010 
 2011     //gtk_window_present(GTK_WINDOW(border));
 2012     //updateSize();
 2013 }
 2014 
 2015 bool gMainWindow::closeAll()
 2016 {
 2017     int i;
 2018     gMainWindow *win;
 2019 
 2020     for(i = 0; i < count(); i++)
 2021     {
 2022         win = get(i);
 2023         if (!win)
 2024             break;
 2025         if (!win->isTopLevel())
 2026             continue;
 2027         if (win == gApplication::mainWindow())
 2028             continue;
 2029         if (win->close())
 2030             return true;
 2031     }
 2032 
 2033     return false;
 2034 }
 2035 
 2036 void gMainWindow::setNoTakeFocus(bool v)
 2037 {
 2038     _no_take_focus = v;
 2039     if (isTopLevel())
 2040         gtk_window_set_focus_on_map(GTK_WINDOW(border), !_no_take_focus);
 2041 }
 2042 
 2043 void gMainWindow::calcCsdSize()
 2044 {
 2045     GtkAllocation ba;
 2046     GtkAllocation wa;
 2047     
 2048     if (_csd_w >= 0)
 2049         return;
 2050         
 2051     if (!isTopLevel())
 2052     {
 2053         _csd_w = _csd_h = 0;
 2054         return;
 2055     }
 2056         
 2057     gtk_widget_get_allocation(border, &ba);
 2058     gtk_widget_get_allocation(frame, &wa);
 2059     
 2060     if (wa.width == 1 && wa.height == 1)
 2061         return;
 2062 
 2063     //fprintf(stderr, "border: %d %d layout: %d %d\n", ba.width, ba.height, wa.width, wa.height);
 2064     
 2065     _csd_w = ba.width - wa.width;
 2066     _csd_h = ba.height - wa.height;
 2067     #ifdef DEBUG_RESIZE
 2068     fprintf(stderr, "calcCsdSize: %s: csd = %d %d\n", name(), _csd_w, _csd_h);
 2069     #endif
 2070     
 2071     if (!isResizable())
 2072         updateSize();
 2073     else
 2074         setGeometryHints();
 2075 }
 2076 
 2077 void gMainWindow::destroy()
 2078 {
 2079     doClose(true);
 2080     gControl::destroy();
 2081 }
 2082 
 2083 void gMainWindow::setCustomMinimumSize(int w, int h)
 2084 {
 2085     w = Max(0, w);
 2086     h = Max(0, h);
 2087     if (w == _min_w && h == _min_h)
 2088         return;
 2089     _min_w = w;
 2090     _min_h = h;
 2091     updateSize();
 2092 }
 2093 
 2094 void gMainWindow::getCustomMinimumSize(int *w, int *h) const
 2095 {
 2096     *w = _min_w;
 2097     *h = _min_h;
 2098 }
 2099