Home » Community » U++ community news and announcements » MILESTONE: gtk3 replaces gtk2 as default linux backend
| MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52902] |
Fri, 10 January 2020 10:38  |
 |
mirek
Messages: 14291 Registered: November 2005
|
Ultimate Member |
|
|
I have reached an important milestone, commiting gtk3 branch (which I have been developing for the last couple of month) into U++ trunk.
This replaces gtk2 as our backend (BTW, small explanation here for future references: U++ is still 'emulated' GUI, with its own set of widgets; we are using gtk just as interface to host system, basically only top-level windows and events. The reason for using gtk3 as backend is mostly for improved integration).
With this backend I have also taken slightly different path for chameleon - we are now using only several basic 'looks' from gtk3 (namely shape of basic buttons, check/option boxes, menu looks, scrollbars, standard font and GUI colors) and generate rest (e.g. comboboxes) as "synthetic" GUI based on these. That should fix many small visual glitches that have plagued U++ in the past, especially with some exotic theming. Plus, unlike gtk2, gtk3 has support for UHD mode, so looks much better on my LCD 
Minimal version required for gtk3 is 3.8 - that accidentally coincides in historic timeline with C++11 support availability; for now however at least 3.22 (~2017) is required for full chameleon support. I also plan to develop some nice new default clean theme to replace that old XP look which was our fallback look for more than 10 years... that will probably be the theme for pre-3.22 gtk3 and definitely for plain X11.
It will take a month or two to mature this, please test & report problems...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Re: MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52914 is a reply to message #52913] |
Sat, 11 January 2020 21:26   |
 |
Klugier
Messages: 1117 Registered: September 2012 Location: Poland, Kraków
|
Senior Contributor |
|
|
Hello Mirek,
While compiling new version I see a lot of warnings that should be eliminated:
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp: In function 'void Upp::_DBG_Ungrab()':
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:24:37: warning: 'void gdk_pointer_ungrab(guint32)' is deprecated: Use 'gdk_device_ungrab' instead [-Wdeprecated-declarations]
24 | gdk_pointer_ungrab(GDK_CURRENT_TIME);
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:50,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkmain.h:100:15: note: declared here
100 | void gdk_pointer_ungrab (guint32 time_);
| ^~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:24:37: warning: 'void gdk_pointer_ungrab(guint32)' is deprecated: Use 'gdk_device_ungrab' instead [-Wdeprecated-declarations]
24 | gdk_pointer_ungrab(GDK_CURRENT_TIME);
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:50,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkmain.h:100:15: note: declared here
100 | void gdk_pointer_ungrab (guint32 time_);
| ^~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp: In static member function 'static void Upp::Ctrl::PanicMsgBox(const char*, const char*)':
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:30:28: warning: 'gboolean gdk_pointer_is_grabbed()' is deprecated: Use 'gdk_display_device_is_grabbed' instead [-Wdeprecated-declarations]
30 | if(gdk_pointer_is_grabbed())
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:50,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkmain.h:104:15: note: declared here
104 | gboolean gdk_pointer_is_grabbed (void);
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:30:28: warning: 'gboolean gdk_pointer_is_grabbed()' is deprecated: Use 'gdk_display_device_is_grabbed' instead [-Wdeprecated-declarations]
30 | if(gdk_pointer_is_grabbed())
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:50,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkmain.h:104:15: note: declared here
104 | gboolean gdk_pointer_is_grabbed (void);
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:31:33: warning: 'void gdk_pointer_ungrab(guint32)' is deprecated: Use 'gdk_device_ungrab' instead [-Wdeprecated-declarations]
31 | gdk_pointer_ungrab(CurrentTime);
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:50,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkmain.h:100:15: note: declared here
100 | void gdk_pointer_ungrab (guint32 time_);
| ^~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:31:33: warning: 'void gdk_pointer_ungrab(guint32)' is deprecated: Use 'gdk_device_ungrab' instead [-Wdeprecated-declarations]
31 | gdk_pointer_ungrab(CurrentTime);
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:50,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkmain.h:100:15: note: declared here
100 | void gdk_pointer_ungrab (guint32 time_);
| ^~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp: In function 'void Upp::InitGtkApp(int, char**, const char**)':
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:70:61: warning: 'void gdk_threads_set_lock_functions(GCallback, GCallback)' is deprecated [-Wdeprecated-declarations]
70 | gdk_threads_set_lock_functions(EnterGuiMutex, LeaveGuiMutex);
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:61,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkthreads.h:50:10: note: declared here
50 | void gdk_threads_set_lock_functions (GCallback enter_fn,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:70:61: warning: 'void gdk_threads_set_lock_functions(GCallback, GCallback)' is deprecated [-Wdeprecated-declarations]
70 | gdk_threads_set_lock_functions(EnterGuiMutex, LeaveGuiMutex);
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:61,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkthreads.h:50:10: note: declared here
50 | void gdk_threads_set_lock_functions (GCallback enter_fn,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:71:19: warning: 'void gdk_threads_init()' is deprecated [-Wdeprecated-declarations]
71 | gdk_threads_init();
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:61,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkthreads.h:44:10: note: declared here
44 | void gdk_threads_init (void);
| ^~~~~~~~~~~~~~~~
In file included from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:522:
/home/klugier/upp/uppsrc/CtrlCore/GtkApp.cpp:71:19: warning: 'void gdk_threads_init()' is deprecated [-Wdeprecated-declarations]
71 | gdk_threads_init();
| ^
In file included from /usr/include/gtk-3.0/gdk/gdk.h:61,
from /usr/include/gtk-3.0/gtk/gtk.h:30,
from /home/klugier/upp/uppsrc/CtrlCore/Gtk.h:12,
from /home/klugier/upp/uppsrc/CtrlCore/CtrlCore.h:49,
from /home/klugier/upp/uppsrc/CtrlCore/SystemDraw.cpp:1,
from /home/klugier/upp.out/CtrlCore/GCC.Blitz.Gui.Mt.Shared/$blitz.cpp:3:
/usr/include/gtk-3.0/gdk/gdkthreads.h:44:10: note: declared here
44 | void gdk_threads_init (void);
| ^~~~~~~~~~~~~~~~
CtrlCore: 61 file(s) built in (0:05.19), 85 msecs / file, duration = 12061 msecs, parallelization 61%
ide: 64 file(s) built in (0:34.03), 531 msecs / file, duration = 39637 msecs, parallelization 24%
Linking...
/home/klugier/upp/theide (13145136 B) linked in (0:00.95)
Moreover, the tooltip text is not visible on Manjaro KDE. I also agree that there is a problem with the scrollbars - they are not emulated ideally.

Sincerely,
Klugier
U++ - one framework to rule them all.
|
|
|
|
|
|
| Re: MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52916 is a reply to message #52914] |
Sun, 12 January 2020 13:36   |
 |
mirek
Messages: 14291 Registered: November 2005
|
Ultimate Member |
|
|
Klugier wrote on Sat, 11 January 2020 21:26Hello Mirek,
While compiling new version I see a lot of warnings that should be eliminated:
Well, most important warnings of those are about gtk3 more or less dropping support for multithreading - if remember some history of U++, we were at phase where the only thread eligible to do GUI was the main thread, then we went to some limited possibility to do things from other threads. If other thread was to do something in GUI, you had to PostCallback.
Interestingly, gtk just went in the exactly opposite direction - doing some GUI stuff from other threads is now deprecated and dropped in gtk4 and the recommend approach is to use their's PostCallback equivalent.
Now I have some ideas how to deal with it, but it will take some time.
(Plus of course there are some easier warnings to fixe, 'todo').
Quote:
Moreover, the tooltip text is not visible on Manjaro KDE. I also agree that there is a problem with the scrollbars - they are not emulated ideally.
Can you post tooltip screenshot? If not, can you describe colors?
Scrollbars I can fix. Would be nice to know which engine is that though...
Mirek
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Re: MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52930 is a reply to message #52926] |
Tue, 14 January 2020 09:21   |
Tom1
Messages: 1319 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
My OpenGL (GLCtrl) based applications now crash on startup. I did a full rebuild, but still the result is this:
tom@tom-LM-WMV:~/upp.out/program52/CLANG.Gui.Shared$ ./GLModeler
(GLModeler:5955): Gtk-ERROR **: 10:07:31.280: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported
Trace/breakpoint trap (core dumped)
tom@tom-LM-WMV:~/upp.out/program52/CLANG.Gui.Shared$
Here's the backtrace:
/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
g_log_writer_default () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
g_log_structured_array () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
g_log_structured_standard () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
/usr/lib/x86_64-linux-gnu/libgtk-3.so.0
g_option_context_parse () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
gtk_parse_args () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
gtk_init_check () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
gtk_init () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
Upp::InitGtkApp (argc=1, argv=0x7fffffffe448, envptr=0x7fffffffe458) at /home/tom/upp.src/uppsrc/CtrlCore/GtkApp.cpp:74
main (argc=1, argv=0x7fffffffe448, envptr=0x7fffffffe458) at /mnt/hgfs/program52/GLModeler/GLModeler.cpp:3
Am I doing something wrong here? (I have not changed anything in my code and it used to work on Linux. It still works on Windows.)
Best regards,
Tom
|
|
|
|
| Re: MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52932 is a reply to message #52930] |
Tue, 14 January 2020 11:36   |
 |
mirek
Messages: 14291 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Tue, 14 January 2020 09:21Hi,
My OpenGL (GLCtrl) based applications now crash on startup. I did a full rebuild, but still the result is this:
tom@tom-LM-WMV:~/upp.out/program52/CLANG.Gui.Shared$ ./GLModeler
(GLModeler:5955): Gtk-ERROR **: 10:07:31.280: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported
Trace/breakpoint trap (core dumped)
tom@tom-LM-WMV:~/upp.out/program52/CLANG.Gui.Shared$
Here's the backtrace:
/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
g_log_writer_default () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
g_log_structured_array () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
g_log_structured_standard () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
/usr/lib/x86_64-linux-gnu/libgtk-3.so.0
g_option_context_parse () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
gtk_parse_args () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
gtk_init_check () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
gtk_init () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
Upp::InitGtkApp (argc=1, argv=0x7fffffffe448, envptr=0x7fffffffe458) at /home/tom/upp.src/uppsrc/CtrlCore/GtkApp.cpp:74
main (argc=1, argv=0x7fffffffe448, envptr=0x7fffffffe458) at /mnt/hgfs/program52/GLModeler/GLModeler.cpp:3
Am I doing something wrong here? (I have not changed anything in my code and it used to work on Linux. It still works on Windows.)
Best regards,
Tom
Can you retry now? I have removed dependency on gtkglext, which we are not using anyway.
If it still does not work, do non-GL examples work for you?
Mirek
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Re: MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52944 is a reply to message #52943] |
Thu, 16 January 2020 11:18   |
 |
mirek
Messages: 14291 Registered: November 2005
|
Ultimate Member |
|
|
mr_ped wrote on Thu, 16 January 2020 11:05This sounds like lot of fun.
I guess dropping support for status icons in Gtk is legitimate option, as that's how the Gnome authors envision it and how they want it.
But as a KDE user, I would prefer if there were still APIs and tools in U++ to handle status icons normally.
But U++ is GTK3 based now, so ... I don't know. Maybe the X11 without GTK branch only to keep them supported and GTK3 branch to ignore any U++ API calls?
Seems quite awkward situation to me, I definitely like existence of status icons in the task bar in my desktop environment, and if some app is overusing it, I can uninstall the particular app. But I don't understand Gnome design decisions for many years, so this is just another one, I simply think completely differently about my computer "desk".
No worries, I have kept it with warnings disabled. Perhaps in future, if they decide to drop it, I can switch to X11 implementation, which is possible even with gtk3 backend. For now, problem solved.
(And yes, it is idiotic decision on gtk3 part. If they present it as multi-platform toolkit, they should care about more than Gnome).
Mirek
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Re: MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52953 is a reply to message #52902] |
Mon, 20 January 2020 20:51   |
 |
amrein
Messages: 278 Registered: August 2008 Location: France
|
Experienced Member |
|
|
All POSIX OS have pkg-config in their repository. You must install pkg-config manually (using the distro package manager) as it's not installed by default when you install other devel packages. If so, this dependency need to be added in docs.
The main idea of using pkg-config is to have dynamic cflags and libs on any POSIX OS I guess.
So for me, the best strategy would be to add LDLIBS in Makefile using pkg-config (after CINC and at link time):
CINC = -I./ `pkg-config --cflags freetype2` `pkg-config --cflags x11` `pkg-config --cflags fontconfig` `pkg-config --cflags xcb` `pkg-config --cflags expat` `pkg-config --cflags libpng` `pkg-config --cflags xinerama` `pkg-config --cflags xrender` `pkg-config --cflags xft` `pkg-config --cflags xdmpc` `pkg-config --cflags xext` `pkg-config --cflags gtk+-3.0` `pkg-config --cflags libnotify`
LDLIBS = `pkg-config --libs freetype2` `pkg-config --libs x11` `pkg-config --libs fontconfig` `pkg-config --libs xcb` `pkg-config --libs expat` `pkg-config --libs libpng` `pkg-config --libs xinerama` `pkg-config --libs xrender` `pkg-config --libs xft` `pkg-config --libs xdmpc` `pkg-config --libs xext` `pkg-config --libs gtk+-3.0` `pkg-config --libs libnotify` -lbz2 -lpthread -ldl -lrt -lz
...
$(OutDir_plugin_bmp)BmpReg.o \
$(OutDir_plugin_bmp)bmp.a \
$(OutDir_RichText)RichText.a \
$(LDLIBS) -Wl,--end-group
That way, it easier for external script like domake to change Makefiles configuration dynamically using its own CINC and LDLIBS.
Note: It would be even more fun to use Flags to switch Makefile from one configuration to another but my investigation in this area showed several flows because of POSIX gmake differences between OS.
[Updated on: Mon, 20 January 2020 21:02] Report message to a moderator
|
|
|
|
|
|
| Re: MILESTONE: gtk3 replaces gtk2 as default linux backend [message #52955 is a reply to message #52954] |
Tue, 21 January 2020 10:32   |
 |
amrein
Messages: 278 Registered: August 2008 Location: France
|
Experienced Member |
|
|
Example on Fedora:
$ lsb_release -sir
Fedora 31
$ rpm -q --whatrequires pkg-config
no package requires pkg-config
$ rpm -qa | grep devel | wc -l
114
So on a full Fedora installation with all U++ dependencies installed and much more... not a single package requires pkg-config.
So no, you need to manually install pkg-config on most POSIX OS. It's not more complicated than installing other U++ build dependencies.
[Updated on: Tue, 21 January 2020 10:33] Report message to a moderator
|
|
|
|
|
|
Goto Forum:
Current Time: Sun May 10 16:47:34 GMT+2 2026
Total time taken to generate the page: 0.01764 seconds
|