summaryrefslogtreecommitdiffstats
path: root/twin
diff options
context:
space:
mode:
Diffstat (limited to 'twin')
-rw-r--r--twin/CMakeLists.txt72
-rw-r--r--twin/COMPLIANCE247
-rw-r--r--twin/CONFIGURING73
-rw-r--r--twin/HACKING174
-rw-r--r--twin/KWinInterface.h50
-rw-r--r--twin/LICENSE21
-rw-r--r--twin/Makefile.am38
-rw-r--r--twin/NEWCOLORSCHEME.README44
-rw-r--r--twin/README206
-rw-r--r--twin/activation.cpp1005
-rw-r--r--twin/atoms.cpp111
-rw-r--r--twin/atoms.h57
-rw-r--r--twin/bridge.cpp206
-rw-r--r--twin/bridge.h75
-rw-r--r--twin/client.cpp3078
-rw-r--r--twin/client.h1006
-rw-r--r--twin/clients/CMakeLists.txt20
-rw-r--r--twin/clients/Makefile.am8
-rw-r--r--twin/clients/PORTING159
-rw-r--r--twin/clients/REQUIREMENTS_FOR_CVS20
-rw-r--r--twin/clients/b2/CMakeLists.txt37
-rw-r--r--twin/clients/b2/Makefile.am23
-rw-r--r--twin/clients/b2/b2.desktop7
-rw-r--r--twin/clients/b2/b2client.cpp1454
-rw-r--r--twin/clients/b2/b2client.h167
-rw-r--r--twin/clients/b2/bitmaps.h98
-rw-r--r--twin/clients/b2/config/CMakeLists.txt29
-rw-r--r--twin/clients/b2/config/Makefile.am16
-rw-r--r--twin/clients/b2/config/config.cpp165
-rw-r--r--twin/clients/b2/config/config.h50
-rw-r--r--twin/clients/default/CMakeLists.txt32
-rw-r--r--twin/clients/default/Makefile.am14
-rw-r--r--twin/clients/default/config/CMakeLists.txt29
-rw-r--r--twin/clients/default/config/Makefile.am16
-rw-r--r--twin/clients/default/config/config.cpp131
-rw-r--r--twin/clients/default/config/config.h49
-rw-r--r--twin/clients/default/kdedefault.cpp1069
-rw-r--r--twin/clients/default/kdedefault.h103
-rw-r--r--twin/clients/keramik/CMakeLists.txt54
-rw-r--r--twin/clients/keramik/Makefile.am44
-rw-r--r--twin/clients/keramik/config/CMakeLists.txt29
-rw-r--r--twin/clients/keramik/config/Makefile.am13
-rw-r--r--twin/clients/keramik/config/config.cpp110
-rw-r--r--twin/clients/keramik/config/config.h58
-rw-r--r--twin/clients/keramik/config/keramikconfig.ui76
-rw-r--r--twin/clients/keramik/embedtool.cpp230
-rw-r--r--twin/clients/keramik/keramik.cpp1854
-rw-r--r--twin/clients/keramik/keramik.desktop31
-rw-r--r--twin/clients/keramik/keramik.h202
-rw-r--r--twin/clients/keramik/pics/border-left.pngbin0 -> 139 bytes
-rw-r--r--twin/clients/keramik/pics/border-right.pngbin0 -> 142 bytes
-rw-r--r--twin/clients/keramik/pics/bottom-center.pngbin0 -> 149 bytes
-rw-r--r--twin/clients/keramik/pics/bottom-left.pngbin0 -> 158 bytes
-rw-r--r--twin/clients/keramik/pics/bottom-right.pngbin0 -> 160 bytes
-rw-r--r--twin/clients/keramik/pics/caption-large-center.pngbin0 -> 176 bytes
-rw-r--r--twin/clients/keramik/pics/caption-large-left.pngbin0 -> 394 bytes
-rw-r--r--twin/clients/keramik/pics/caption-large-right.pngbin0 -> 498 bytes
-rw-r--r--twin/clients/keramik/pics/caption-small-center.pngbin0 -> 177 bytes
-rw-r--r--twin/clients/keramik/pics/caption-small-left.pngbin0 -> 425 bytes
-rw-r--r--twin/clients/keramik/pics/caption-small-right.pngbin0 -> 504 bytes
-rw-r--r--twin/clients/keramik/pics/grabbar-center.pngbin0 -> 167 bytes
-rw-r--r--twin/clients/keramik/pics/grabbar-left.pngbin0 -> 211 bytes
-rw-r--r--twin/clients/keramik/pics/grabbar-right.pngbin0 -> 208 bytes
-rw-r--r--twin/clients/keramik/pics/titlebar-center.pngbin0 -> 160 bytes
-rw-r--r--twin/clients/keramik/pics/titlebar-left.pngbin0 -> 240 bytes
-rw-r--r--twin/clients/keramik/pics/titlebar-right.pngbin0 -> 288 bytes
-rw-r--r--twin/clients/keramik/pics/titlebutton-round-huge.pngbin0 -> 7868 bytes
-rw-r--r--twin/clients/keramik/pics/titlebutton-round-large.pngbin0 -> 4380 bytes
-rw-r--r--twin/clients/keramik/pics/titlebutton-round.pngbin0 -> 1789 bytes
-rw-r--r--twin/clients/keramik/pics/titlebutton-square-huge.pngbin0 -> 4656 bytes
-rw-r--r--twin/clients/keramik/pics/titlebutton-square-large.pngbin0 -> 2725 bytes
-rw-r--r--twin/clients/keramik/pics/titlebutton-square.pngbin0 -> 1082 bytes
-rw-r--r--twin/clients/kwmtheme/Makefile.am15
-rw-r--r--twin/clients/kwmtheme/cli_installer/Makefile.am18
-rw-r--r--twin/clients/kwmtheme/cli_installer/main.cpp166
-rw-r--r--twin/clients/kwmtheme/kwmtheme.desktop81
-rw-r--r--twin/clients/kwmtheme/kwmthemeclient.cpp936
-rw-r--r--twin/clients/kwmtheme/kwmthemeclient.h74
-rw-r--r--twin/clients/laptop/CMakeLists.txt35
-rw-r--r--twin/clients/laptop/Makefile.am17
-rw-r--r--twin/clients/laptop/laptop.desktop69
-rw-r--r--twin/clients/laptop/laptopclient.cpp761
-rw-r--r--twin/clients/laptop/laptopclient.h76
-rw-r--r--twin/clients/modernsystem/CMakeLists.txt36
-rw-r--r--twin/clients/modernsystem/Makefile.am19
-rw-r--r--twin/clients/modernsystem/btnhighcolor.h93
-rw-r--r--twin/clients/modernsystem/buttondata.h42
-rw-r--r--twin/clients/modernsystem/config/CMakeLists.txt30
-rw-r--r--twin/clients/modernsystem/config/Makefile.am14
-rw-r--r--twin/clients/modernsystem/config/config.cpp130
-rw-r--r--twin/clients/modernsystem/config/config.h50
-rw-r--r--twin/clients/modernsystem/modernsys.cpp739
-rw-r--r--twin/clients/modernsystem/modernsys.h72
-rw-r--r--twin/clients/modernsystem/modernsystem.desktop69
-rw-r--r--twin/clients/plastik/CMakeLists.txt39
-rw-r--r--twin/clients/plastik/Makefile.am19
-rw-r--r--twin/clients/plastik/config/CMakeLists.txt33
-rw-r--r--twin/clients/plastik/config/Makefile.am14
-rw-r--r--twin/clients/plastik/config/config.cpp123
-rw-r--r--twin/clients/plastik/config/config.h53
-rw-r--r--twin/clients/plastik/config/configdialog.ui119
-rw-r--r--twin/clients/plastik/misc.cpp85
-rw-r--r--twin/clients/plastik/misc.h30
-rw-r--r--twin/clients/plastik/plastik.cpp598
-rw-r--r--twin/clients/plastik/plastik.desktop37
-rw-r--r--twin/clients/plastik/plastik.h127
-rw-r--r--twin/clients/plastik/plastikbutton.cpp629
-rw-r--r--twin/clients/plastik/plastikbutton.h90
-rw-r--r--twin/clients/plastik/plastikclient.cpp529
-rw-r--r--twin/clients/plastik/plastikclient.h73
-rw-r--r--twin/clients/quartz/CMakeLists.txt37
-rw-r--r--twin/clients/quartz/Makefile.am23
-rw-r--r--twin/clients/quartz/config/CMakeLists.txt29
-rw-r--r--twin/clients/quartz/config/Makefile.am16
-rw-r--r--twin/clients/quartz/config/config.cpp104
-rw-r--r--twin/clients/quartz/config/config.h47
-rw-r--r--twin/clients/quartz/quartz.cpp797
-rw-r--r--twin/clients/quartz/quartz.desktop39
-rw-r--r--twin/clients/quartz/quartz.h95
-rw-r--r--twin/clients/redmond/CMakeLists.txt35
-rw-r--r--twin/clients/redmond/Makefile.am17
-rw-r--r--twin/clients/redmond/redmond.cpp699
-rw-r--r--twin/clients/redmond/redmond.desktop19
-rw-r--r--twin/clients/redmond/redmond.h91
-rw-r--r--twin/clients/test/Makefile.am15
-rw-r--r--twin/clients/test/test.cpp343
-rw-r--r--twin/clients/test/test.desktop67
-rw-r--r--twin/clients/test/test.h49
-rw-r--r--twin/clients/web/CMakeLists.txt34
-rw-r--r--twin/clients/web/Makefile.am15
-rw-r--r--twin/clients/web/Web.cpp385
-rw-r--r--twin/clients/web/Web.h87
-rw-r--r--twin/clients/web/WebButton.cpp287
-rw-r--r--twin/clients/web/WebButton.h70
-rw-r--r--twin/clients/web/web.desktop47
-rw-r--r--twin/compton-tde/CMakeLists.txt96
-rw-r--r--twin/compton-tde/c2.c1320
-rw-r--r--twin/compton-tde/c2.h354
-rw-r--r--twin/compton-tde/common.h2586
-rw-r--r--twin/compton-tde/compton.c8066
-rw-r--r--twin/compton-tde/compton.h1345
-rw-r--r--twin/compton-tde/compton_config.h.cmake38
-rw-r--r--twin/compton-tde/dbus.c1200
-rw-r--r--twin/compton-tde/dbus.h252
-rw-r--r--twin/compton-tde/man/compton-tde-trans.1.html897
-rw-r--r--twin/compton-tde/man/compton-tde.1.html1603
-rw-r--r--twin/compton-tde/man/compton-trans.1201
-rw-r--r--twin/compton-tde/man/compton.1904
-rw-r--r--twin/compton-tde/opengl.c1941
-rw-r--r--twin/compton-tde/opengl.h145
-rw-r--r--twin/cr16-app-twin.pngbin0 -> 696 bytes
-rw-r--r--twin/cr32-app-twin.pngbin0 -> 1653 bytes
-rw-r--r--twin/cr48-app-twin.pngbin0 -> 2615 bytes
-rw-r--r--twin/data/CMakeLists.txt58
-rw-r--r--twin/data/Makefile.am25
-rw-r--r--twin/data/fsp_workarounds_1.twinrules80
-rwxr-xr-xtwin/data/pluginlibFix.pl8
-rw-r--r--twin/data/pop.wavbin0 -> 4068 bytes
-rw-r--r--twin/data/twin.upd14
-rw-r--r--twin/data/twin3_plugin.pl8
-rw-r--r--twin/data/twin3_plugin.upd4
-rw-r--r--twin/data/twin_focus1.sh13
-rw-r--r--twin/data/twin_focus1.upd5
-rw-r--r--twin/data/twin_focus2.sh8
-rw-r--r--twin/data/twin_focus2.upd5
-rw-r--r--twin/data/twin_fsp_workarounds_1.upd8
-rw-r--r--twin/data/twiniconify.upd8
-rw-r--r--twin/data/twinsticky.upd8
-rw-r--r--twin/data/twinupdatewindowsettings.upd7
-rw-r--r--twin/data/update_default_rules.cpp56
-rw-r--r--twin/data/update_window_settings.cpp168
-rw-r--r--twin/events.cpp1784
-rw-r--r--twin/eventsrc5918
-rw-r--r--twin/geometry.cpp2649
-rw-r--r--twin/geometrytip.cpp63
-rw-r--r--twin/geometrytip.h34
-rw-r--r--twin/group.cpp1118
-rw-r--r--twin/group.h90
-rw-r--r--twin/kcmtwin/CMakeLists.txt16
-rw-r--r--twin/kcmtwin/Makefile.am3
-rw-r--r--twin/kcmtwin/showdesktop.desktop133
-rw-r--r--twin/kcmtwin/twindecoration/CMakeLists.txt37
-rw-r--r--twin/kcmtwin/twindecoration/Makefile.am18
-rw-r--r--twin/kcmtwin/twindecoration/buttons.cpp883
-rw-r--r--twin/kcmtwin/twindecoration/buttons.h227
-rw-r--r--twin/kcmtwin/twindecoration/pixmaps.h110
-rw-r--r--twin/kcmtwin/twindecoration/preview.cpp507
-rw-r--r--twin/kcmtwin/twindecoration/preview.h150
-rw-r--r--twin/kcmtwin/twindecoration/twindecoration.cpp987
-rw-r--r--twin/kcmtwin/twindecoration/twindecoration.desktop231
-rw-r--r--twin/kcmtwin/twindecoration/twindecoration.h161
-rw-r--r--twin/kcmtwin/twindecoration/twindecorationIface.h44
-rw-r--r--twin/kcmtwin/twinoptions/AUTHORS12
-rw-r--r--twin/kcmtwin/twinoptions/CMakeLists.txt40
-rw-r--r--twin/kcmtwin/twinoptions/ChangeLog51
-rw-r--r--twin/kcmtwin/twinoptions/Makefile.am18
-rw-r--r--twin/kcmtwin/twinoptions/main.cpp296
-rw-r--r--twin/kcmtwin/twinoptions/main.h101
-rw-r--r--twin/kcmtwin/twinoptions/mouse.cpp856
-rw-r--r--twin/kcmtwin/twinoptions/mouse.h137
-rw-r--r--twin/kcmtwin/twinoptions/twinactions.desktop233
-rw-r--r--twin/kcmtwin/twinoptions/twinadvanced.desktop232
-rw-r--r--twin/kcmtwin/twinoptions/twinfocus.desktop222
-rw-r--r--twin/kcmtwin/twinoptions/twinmoving.desktop229
-rw-r--r--twin/kcmtwin/twinoptions/twinoptions.desktop225
-rw-r--r--twin/kcmtwin/twinoptions/twintranslucency.desktop195
-rw-r--r--twin/kcmtwin/twinoptions/windows.cpp1796
-rw-r--r--twin/kcmtwin/twinoptions/windows.h300
-rw-r--r--twin/kcmtwin/twinrules/CMakeLists.txt56
-rw-r--r--twin/kcmtwin/twinrules/Makefile.am29
-rw-r--r--twin/kcmtwin/twinrules/detectwidget.cpp223
-rw-r--r--twin/kcmtwin/twinrules/detectwidget.h86
-rw-r--r--twin/kcmtwin/twinrules/detectwidgetbase.ui218
-rw-r--r--twin/kcmtwin/twinrules/editshortcutbase.ui164
-rw-r--r--twin/kcmtwin/twinrules/kcm.cpp103
-rw-r--r--twin/kcmtwin/twinrules/kcm.h53
-rw-r--r--twin/kcmtwin/twinrules/main.cpp294
-rw-r--r--twin/kcmtwin/twinrules/ruleslist.cpp200
-rw-r--r--twin/kcmtwin/twinrules/ruleslist.h59
-rw-r--r--twin/kcmtwin/twinrules/ruleslistbase.ui91
-rw-r--r--twin/kcmtwin/twinrules/ruleswidget.cpp803
-rw-r--r--twin/kcmtwin/twinrules/ruleswidget.h148
-rw-r--r--twin/kcmtwin/twinrules/ruleswidgetbase.ui2597
-rw-r--r--twin/kcmtwin/twinrules/twinrules.desktop209
-rw-r--r--twin/kcmtwin/twinrules/twinsrc.cpp8
-rw-r--r--twin/killer/CMakeLists.txt28
-rw-r--r--twin/killer/Makefile.am9
-rw-r--r--twin/killer/killer.cpp88
-rw-r--r--twin/killwindow.cpp113
-rw-r--r--twin/killwindow.h35
-rw-r--r--twin/kompmgr/CMakeLists.txt36
-rw-r--r--twin/kompmgr/Makefile.am6
-rw-r--r--twin/kompmgr/configure.in.in8
-rw-r--r--twin/kompmgr/kompmgr.c3960
-rw-r--r--twin/layers.cpp830
-rw-r--r--twin/lib/CMakeLists.txt43
-rw-r--r--twin/lib/Makefile.am20
-rw-r--r--twin/lib/kcommondecoration.cpp991
-rw-r--r--twin/lib/kcommondecoration.h372
-rw-r--r--twin/lib/kdecoration.cpp444
-rw-r--r--twin/lib/kdecoration.h890
-rw-r--r--twin/lib/kdecoration_p.cpp235
-rw-r--r--twin/lib/kdecoration_p.h111
-rw-r--r--twin/lib/kdecoration_plugins_p.cpp199
-rw-r--r--twin/lib/kdecoration_plugins_p.h77
-rw-r--r--twin/lib/kdecorationfactory.cpp85
-rw-r--r--twin/lib/kdecorationfactory.h120
-rw-r--r--twin/main.cpp357
-rw-r--r--twin/main.h40
-rw-r--r--twin/manage.cpp606
-rw-r--r--twin/notifications.cpp147
-rw-r--r--twin/notifications.h69
-rw-r--r--twin/oldheaders/CMakeLists.txt14
-rw-r--r--twin/oldheaders/Makefile.am2
-rw-r--r--twin/oldheaders/client.h4
-rw-r--r--twin/oldheaders/options.h4
-rw-r--r--twin/oldheaders/twinbutton.h4
-rw-r--r--twin/oldheaders/workspace.h4
-rw-r--r--twin/options.cpp421
-rw-r--r--twin/options.h405
-rw-r--r--twin/pics/CMakeLists.txt16
-rw-r--r--twin/pics/Makefile.am9
-rw-r--r--twin/pics/bluesun.pngbin0 -> 2787 bytes
-rw-r--r--twin/pics/close.pngbin0 -> 306 bytes
-rw-r--r--twin/pics/fog-grey.pngbin0 -> 4608 bytes
-rw-r--r--twin/pics/fog.pngbin0 -> 8192 bytes
-rw-r--r--twin/pics/greenie.dim.pngbin0 -> 10027 bytes
-rw-r--r--twin/pics/greenie.light.pngbin0 -> 11672 bytes
-rw-r--r--twin/pics/iconify.pngbin0 -> 277 bytes
-rw-r--r--twin/pics/maximize.pngbin0 -> 283 bytes
-rw-r--r--twin/pics/maximizedown.pngbin0 -> 283 bytes
-rw-r--r--twin/pics/menu.pngbin0 -> 278 bytes
-rw-r--r--twin/pics/pindown.pngbin0 -> 322 bytes
-rw-r--r--twin/pics/pinup.pngbin0 -> 320 bytes
-rw-r--r--twin/pics/unknown.pngbin0 -> 708 bytes
-rw-r--r--twin/placement.cpp817
-rw-r--r--twin/placement.h92
-rw-r--r--twin/plugins.cpp42
-rw-r--r--twin/plugins.h32
-rw-r--r--twin/popupinfo.cpp147
-rw-r--r--twin/popupinfo.h51
-rw-r--r--twin/resumer/CMakeLists.txt28
-rw-r--r--twin/resumer/resumer.cpp79
-rw-r--r--twin/rules.cpp1077
-rw-r--r--twin/rules.h311
-rw-r--r--twin/sm.cpp446
-rw-r--r--twin/sm.h89
-rw-r--r--twin/tabbox.cpp1389
-rw-r--r--twin/tabbox.h116
-rw-r--r--twin/tools/Makefile.am11
-rw-r--r--twin/tools/decobenchmark/Makefile.am9
-rw-r--r--twin/tools/decobenchmark/main.cpp138
-rw-r--r--twin/tools/decobenchmark/main.h51
-rw-r--r--twin/tools/decobenchmark/preview.cpp412
-rw-r--r--twin/tools/decobenchmark/preview.h137
-rw-r--r--twin/tools/test_gravity.cpp99
-rw-r--r--twin/tools/xreply/Makefile2
-rw-r--r--twin/tools/xreply/xreply.c197
-rw-r--r--twin/twin.kcfg86
-rw-r--r--twin/twinbindings.cpp198
-rw-r--r--twin/useractions.cpp1198
-rw-r--r--twin/utils.cpp414
-rw-r--r--twin/utils.h273
-rw-r--r--twin/wm-spec/index.html243
-rw-r--r--twin/wm-spec/x107.html627
-rw-r--r--twin/wm-spec/x208.html225
-rw-r--r--twin/wm-spec/x225.html720
-rw-r--r--twin/wm-spec/x24.html496
-rw-r--r--twin/wm-spec/x340.html182
-rw-r--r--twin/wm-spec/x351.html648
-rw-r--r--twin/wm-spec/x479.html143
-rw-r--r--twin/wm-spec/x483.html166
-rw-r--r--twin/wm-spec/x489.html178
-rw-r--r--twin/wm-spec/x512.html763
-rw-r--r--twin/workspace.cpp3127
-rw-r--r--twin/workspace.h876
316 files changed, 96462 insertions, 0 deletions
diff --git a/twin/CMakeLists.txt b/twin/CMakeLists.txt
new file mode 100644
index 00000000..a20f2c2a
--- /dev/null
+++ b/twin/CMakeLists.txt
@@ -0,0 +1,72 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+project( twin )
+
+add_subdirectory( lib )
+add_subdirectory( killer )
+add_subdirectory( resumer )
+add_subdirectory( kcmtwin )
+add_subdirectory( pics )
+add_subdirectory( clients )
+add_subdirectory( oldheaders )
+add_subdirectory( data )
+tde_conditional_add_subdirectory( WITH_XCOMPOSITE kompmgr )
+tde_conditional_add_subdirectory( WITH_XCOMPOSITE compton-tde )
+
+
+include_directories(
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### headers ###################################
+
+install( FILES KWinInterface.h DESTINATION ${INCLUDE_INSTALL_DIR} )
+
+
+##### other data ################################
+
+tde_install_icons( twin )
+install( FILES eventsrc DESTINATION ${DATA_INSTALL_DIR}/twin )
+install( FILES twin.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+
+
+##### twin (tdeinit) ############################
+
+set( target twin )
+
+set( ${target}_SRCS
+ workspace.cpp client.cpp placement.cpp atoms.cpp
+ utils.cpp layers.cpp main.cpp popupinfo.cpp tabbox.cpp
+ options.cpp plugins.cpp events.cpp KWinInterface.skel
+ killwindow.cpp geometrytip.cpp sm.cpp group.cpp bridge.cpp
+ manage.cpp notifications.cpp activation.cpp useractions.cpp
+ geometry.cpp rules.cpp
+)
+
+tde_add_tdeinit_executable( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdecorations-shared tdeui-shared Xext
+)
+
+##### install import cmake modules ###############
+
+tde_install_export( )
+
diff --git a/twin/COMPLIANCE b/twin/COMPLIANCE
new file mode 100644
index 00000000..c51bfae3
--- /dev/null
+++ b/twin/COMPLIANCE
@@ -0,0 +1,247 @@
+W A R N I N G:
+--------------
+This document is a work in progress and is in no way complete or accurate!
+Its current purpose is in aiding the KWin NetWM audit for a future KWin release.
+
+NetWM Compliance Document:
+==========================
+
+Listed below are all the NetWM (or EWM) hints decided upon on freedesktop.org
+(as of version 1.3draft, Nov 27, 2002) and KWin's current level of
+compliance with the spec. Some parts also involve the pager and clients which
+this document will cater for as well where applicable.
+
+If you modify the level of NetWM compliance (via modification of twin/*,
+tdecore/netwm.* or tdecore/twin.* etc.), or notice any new hints that
+were added after version 1.2, please modify this document appropriately.
+Properties are ordered in the table in the order they are found in the
+specification. To list any important notes regarding a property, just
+add them as follows:
+
+_NET_NUMBER_OF_DESKTOPS root window property done
+ +----------------------------------------------------------------+
+ | This property SHOULD be updated by the Window Manager to |
+ | indicate the number of virtual desktops. KWin DOES update this |
+ | property when the pager changes the number of desktops. |
+ +----------------------------------------------------------------+
+
+If you have any questions regarding the specification, feel free to ask on the KWin
+mailing list <twin@kde.org>, or on the Window Manager Spec list <wm-spec-list@gnome.org>.
+ -- Karol <kszwed@kde.org>
+
+(
+ compliance :
+ - = none,
+ / = partial,
+ + = complete,
+ * = KWin is compliant, but something else needs checking (e.g. Qt)
+ ? = unknown
+)
+
+
+NETWM spec compliance (whole document):
+version 1.2
+======================
+
++ 1.
++ 2.3. Feature not implemented.
++ 2.4. Feature not implemented.
++ 2.5.
++ 2. (rest of the section)
++ 3.1.
+ This property is complete in the sence that all implemented properties
+ are listed here.
+ CHECKME : check it's complete
+/ 3.2.
+ The spec requires that _NET_CLIENT_LIST contains the windows in their
+ initial mapping order, which is currently not true for NET::Desktop
+ windows.
+ Note that xprop lists only first element in WINDOW type properties.
++ 3.3.
+ Note that KWin does not use the virtual root windows technique,
+ so it doesn't set _NET_VIRTUAL_ROOTS at all.
++ 3.4.
+ KWin doesn't implement large desktops, so it ignores
+ the message, and only sets the property to the screen size.
++ 3.5.
+ KWin doesn't implement viewports, so it correctly sets
+ the property to (0,0) pairs and ignores the message.
++ 3.6.
++ 3.7.
++ 3.8.
+ KWin currently extends the message a bit, with data.l[0] being 1 or 2,
+ meaning 'from application'/'from pager', and data.l[1] contains
+ timestamp. This is used for focus stealing prevention purposes, and
+ will be proposed for next version of the spec.
++ 3.9.
++ 3.10.
++ 3.11.
+ KWin doesn't use the virtual roots technique for creating virtual
+ desktops, so it doesn't set the property.
+- 3.12.
+- 3.13.
++ 4.1.
++ 4.2.
++ 4.3.
+ Due to implementation details KWin actually allows moving or resizing
+ by keyboard when requested to be done by mouse, and vice versa.
++ 5.1.
++ 5.2.
++ 5.3.
++ 5.4.
++ 5.5.
+/ 5.6. The handling of _NET_WM_WINDOW_TYPE itself is correct and complete.
+ Supported window types: DESKTOP, DOCK, TOOLBAR, MENU, UTILITY,
+ SPLASH, DIALOG, NORMAL.
+ UTILITY should get better placement.
+ TOOLBAR - many parts in KDE still treat this as "tool" window.
+ - should the decoration be shown for the toolbars?
+ KDE extensions:
+ _KDE_NET_WM_WINDOW_TYPE_TOPMENU - this is used for implementing
+ standalone menubars for applications. Only the menubar
+ that is transient for the currently active window will be shown.
+ See KMenuBar class in libtdeui for details.
+ _KDE_NET_WM_WINDOW_TYPE_OVERRIDE - this seems to mean "this window
+ should be borderless", but it's actually used also for other
+ things, like fullscreen windows. The plan is to get rid of this
+ flawed thing as soon as possible.
+/ 5.7.
+ The handling of _NET_WM_STATE itself is correct and complete.
+ Supported states: MODAL, MAXIMIZED_VERT, MAXIMIZED_HORZ, SHADED,
+ SKIP_TASKBAR, SKIP_PAGER, HIDDEN, ABOVE, BELOW.
+ STICKY is not supported, because KWin doesn't implement viewports.
+ BELOW - in order to make 'allow windows to cover the panel' feature
+ in Kicker work KWin interprets this state a bit differently
+ for DOCK windows. While normal DOCK windows are in their
+ extra layer above normal windows, making them BELOW doesn't
+ move them below normal windows, but only to the same layer, so
+ that windows can hide Kicker, but Kicker can be also raised
+ above the windows. A bit hacky, but it's not really against
+ the spec, and I have no better idea.
+ KDE extensions:
+ _NET_WM_STATE_STAYS_ON_TOP - has the same meaning like ABOVE,
+ and is deprecated in favour of it; it lacks the _KDE prefix
+* 5.8.
+ The handling of _NET_WM_ALLOWED_ACTIONS itself is correct and complete.
+ Supported actions: MOVE, RESIZE, MINIMIZE, SHADE, MAXIMIZE_HORZ,
+ MAXIMIZE_VERT, CHANGE_DESKTOP, CLOSE
+ STICK is not supported, because KWin does not implement viewports.
+ Kicker etc. need to be updated.
++ 5.9.
+* 5.10.
+ Property is not used in KWin.
+ Kicker needs to be checked.
+* 5.11.
+ KWin's handling of the property is correct.
+ Qt should be checked.
++ 5.12.
+- 5.13.
+ Property is not used in KWin, KWin never provides icons for iconified windows.
+ Kicker or its taskbar don't set it either. However, the property is flawed,
+ and should be replaced by manager selection or similar mechanism.
++ 6.1.
++ 6. (rest)
++ 7.4.
+ The urgency hint is mapped to the _NET_WM_DEMANDS_ATTENTION flag.
+* 7.5.
+ Qt often sets maximum size smaller than minimum size. This seems to be caused
+ by delayed layout calculations.
+* 7.6.
+ Kicker should be checked.
+? 7.7.
++ 7. (rest of the section)
+
+ICCCM spec compliance (whole document):
+version 2.0
+======================
+
+/ 1.2.3.
+ KWin uses TWIN_RUNNING atom that's missing the leading underscore.
+ Some parts of KDE perhaps may be missing the leading underscore.
+/ 1.2.6.
+ Should be checked.
++ 1. (rest of the section)
++ 2.8. kmanagerselection.* in tdecore
++ 2. (rest of the section)
+ Not a KWin thing.
+* - patch sent to TT to make TQClipboard sufficiently compliant
++ 3.
+ Feature not supported, obsolete.
++ 4.1.1
++ 4.1.2 (intro)
++ 4.1.2.1
+ Used as a fallback for _NET_WM_NAME.
++ 4.1.2.2
+ Used as a fallback for _NET_WM_ICON_NAME.
+? 4.1.2.3
+? - PSize, PPosition, USize, UPosition
+? - clients - Qt simply sets both
++ - PWinGravity - window geometry constraints have higher priority than gravity
+/ - PBaseSize - PMinSize is not used as a fallback for size increments
++ - (the rest)
+/ 4.1.2.4
++ - input - see 4.1.7
++ - initial_state
++ - icon - feature not supported
++ - window_group
++ - urgency - mapped to _NET_WM_DEMANDS_ATTENTION
+/ 4.1.2.5 - it should be checked it's used correctly in Kicker etc.
+/ 4.1.2.6 - should be checked
+ NETWM section 7.3. is supported too, even though it's a slight ICCCM violation.
++ 4.1.2.7
+- 4.1.2.8
+ See 4.1.8.
++ 4.1.2.9 - handled by Xlib call
++ 4.1.3.1
++ 4.1.3.2
+ Feature not supported (4.1.2.4 - icons)
+* 4.1.4 it should be checked Qt/KDE clients handle this properly
+/ 4.1.5
+ This needs fixing.
++ 4.1.6
++ 4.1.7
+- 4.1.8
+ KWin only installs colormap required by the active window.
+- 4.1.9
+ Feature not supported, except for WM_ICON_NAME as a fallback for _NET_WM_ICON_NAME.
++ 4.1.10
++ 4.1.11
+ Window groups are only used for supporting NETWM section 7.3.
++ 4.2.5
+/ 4.2.7
+ Qt doesn't set revert-to to Parent.
++ 4.2.8.1 frozen clients may be XKill-ed upon a user request though
++ 4.3
+? 4.4
++ 4. (rest of the section)
++ 5.3. not KWin related
++ 5. (rest of the section )
+? 6.1. clients thing
+? 6.2. clients thing - Qt perhaps should force rule 2.
++ 6.3.
+? 6. (rest of the section)
++ 7. - no idea what it is, but it doesn't seem to be KWin related
++ 8.
+
+
+KDE-specific extensions (for completeness):
+
+Property Name Type
+==========================================================================
+_TDE_WM_CHANGE_STATE root window message
+_KDE_NET_SYSTEM_TRAY_WINDOWS root window property
+_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR window property
+_TDE_NET_WM_FRAME_STRUT window property
+_NET_WM_CONTEXT_HELP
+ - Qt extension
+ - has no vendor prefix even though it's not part of the spec
+_NET_WM_STATE_STAYS_ON_TOP
+ - KDE extension
+ - has no vendor prefix even though it's not part of the spec
+ - deprecated in favor of _NET_WM_STATE_KEEP_ABOVE
+_KDE_NET_WM_WINDOW_TYPE_OVERRIDE
+ - window type, makes the window borderless
+ - unclear semantics, used also for fullscreen windows
+ - deprecated in favor of other window types
+
+==========================================================================
diff --git a/twin/CONFIGURING b/twin/CONFIGURING
new file mode 100644
index 00000000..071f9d6d
--- /dev/null
+++ b/twin/CONFIGURING
@@ -0,0 +1,73 @@
+CONTENTS:
+=========
+
+
+1. Pre-configuring window-specific settings
+
+
+
+
+
+1. Pre-configuring window-specific settings
+===========================================
+
+Window-specific settings is a feature of KWin that allows specifying some
+settings only for a specific window or windows. See the Window-specific
+settings section in the KWin configuration and the Special settings
+menu entries in Alt+F3/Advanced menu.
+
+One aspect of window-specific settings is the ability to specify various
+workarounds for (usually broken) applications that otherwise don't work
+properly with KWin. This section describes how to create additional
+window-specific settings that will be automatically used by all users
+without any need of manual configuration.
+
+Example case:
+
+Application FooBar does not specify any maximum size for its main window,
+but when resized to larger size than 1600x1200 it crashes because of a bug.
+Manual configuration of a window-specific setting that avoids this problem
+is opening and activating this window, selecting
+Alt+F3/Advanced/Special window settings, activating tab Workarounds, enabling
+setting Maximum size, changing it to Force and entering "1600,1200" as
+the maximum size, which will make KWin force this size as the maximum size.
+
+To create such window-specific setting automatically without a need of doing
+it manually for every user (for example when doing a large deployment), follow
+these steps:
+
+- Back up your $TDEHOME/share/config/twinrulesrc ($TDEHOME usually being $HOME/.trinity)
+ and remove it
+- Run 'dcop twin default reconfigure'
+- Create manually all window-specific settings that should be included (see above)
+- When done, check in Window-specific settings configuration module
+ (Alt+F3/Configure window behavior/Window-specific settings) that all rules are
+ included
+- Create a copy of $TDEHOME/share/config/twinrulesrc and restore the original one
+- Rename the copy (i.e. the newly created twinrulesrc) to have its unique name
+ (e.g. foobar_fix_maxsize in this example case)
+- Be careful with manual modifications of the file, especially make sure the count=
+ field in the [General] group is updated if needed
+- Create a file for tdeconfig_update like this (named twin_foobar_fix_maxsize.upd
+ in this example):
+
+# twin_foobar_fix_maxsize.upd start #
+Id=foobar_fix_maxsize
+File=twinrules_update
+Group=Dummy
+Options=overwrite
+ScriptArguments=foobar_fix_maxsize
+Script=twin_update_default_rules
+
+# twin_foobar_fix_maxsize.upd end #
+
+- The tdeconfig_file (twin_foobar_fix_maxsize.upd) is to be placed
+ in $TDEDIR/share/apps/tdeconf_update/
+- The file with the window-specific settings (foobar_fix_maxsize) is to be placed
+ in $TDEDIR/share/apps/twin/default_rules/
+
+
+All KDE user accounts should have these new window-specific settings added
+automatically during next KDE startup (or within few seconds if they are active).
+They can be checked again in the Window-specific settings configuration module of KWin.
+
diff --git a/twin/HACKING b/twin/HACKING
new file mode 100644
index 00000000..519322cb
--- /dev/null
+++ b/twin/HACKING
@@ -0,0 +1,174 @@
+Mailing list and bugzilla:
+==========================
+
+The KWin mailing list is twin@kde.org . It's rather low traffic.
+
+The bugs.kde.org product for KWin is 'twin'. Currently the components are 'general' (KWin core),
+'decorations' (decoration plugins), 'compatibility' (problems with non-TDE WMs/apps) and
+'eyecandy' (transparency and similar effects).
+There are also two kcontrol components 'kcmtwindecoration' and 'kcmtwinoptions' related
+to KWin's KControl modules.
+
+
+KWin parts:
+===========
+
+There are four parts of KWin:
+- The KWin core, located in tdebase/twin/*, which implements the actual functionality.
+- The decoration plugins, located in tdebase/twin/clients and tdeartwork/twin-styles, which
+ are responsible for the visual representation of the windows.
+- The libkdecoration library, located in tdebase/twin/lib/*, which is used for communication
+ between the core and the decoration, and also implements some shared functionality
+ for the decorations.
+- KControl modules, located in tdebase/twin/kcmtwin.
+
+
+KWin decorations:
+=================
+
+If you want to develop a decoration plugin for KWin, a HOWTO is available at
+http://www.usermode.org/docs/twintheme.html . It is currently not possible to create
+a new decoration without knowledge of C++, but it should be possible to write a themeable
+decoration (I'm not aware of any such decoration though).
+
+
+Restarting KWin:
+================
+
+Since KWin takes care of focus handling, first killing KWin and then launching new instance
+can cause focus trouble. Therefore it's possible to run 'twin --replace', which will start
+new KWin instance and tell the old one to quit.
+
+
+Handling the case when KWin crashes:
+====================================
+
+Again, without KWin running there may be focus problems. The simplest way to solve them
+is to add the 'Run Command' applet to Kicker - it can receive focus even without KWin running.
+If you can't add the applet or can reach it for some reason, switch to text console, and run
+'DISPLAY=:0 twin --replace' (and then you can run 'twin --replace' again from X).
+
+If KWin is temporarily unusable because of some change and e.g. crashes during startup, it
+is possible to run another window manager, for example Metacity, OpenBox or FVWM (the command
+is similar to restarting KWin, i.e. 'metacity --replace', 'openbox --replace' or 'fvwm -replace').
+
+
+Debugging KWin:
+===============
+
+Focus problems once more. It is not possible to debug KWin in gdb in the X session that KWin is managing,
+because that'd block focus and window operations. It is necessary to switch to a text console
+and attach to the running KWin instance from there, or launch it as 'DISPLAY=:0 gdb twin'.
+
+Since KWin is such an important component of KDE, it is usually better to start another X for development.
+Note that XNest is quite buggy and is therefore not recommended to use.
+
+
+Window manager spec:
+====================
+
+The EWMH window manager specification, also known as NETWM, is located at the freedesktop.org site,
+http://www.freedesktop.org/wiki/Standards_2fwm_2dspec . It defines how the window manager
+communicates information with the applications and other desktop utilities such as the taskbar
+or pager.
+
+
+KWin structure:
+===============
+
+KWin has relatively few classes. The two main classes are Client, which represents windows
+on the screen, and Workspace, which represents the whole screen and manages windows. Both these
+classes are rather large, because they fulfil complicated tasks. In other to reduce size
+of their source files these some functionality is in separate .cpp file grouped by the purpose:
+
+- workspace.* - core of class Workspace
+- client.* - core of class Client
+- activation.cpp - focus handling and window activation
+- events.cpp - event handling is in events.cpp
+- geometry.cpp - geometry-related code
+- layers.cpp - stacking-related code
+- manage.cpp - code dealing with new windows
+- placement.cpp - window placements algorithms
+- rules.cpp - code for window-specific settings
+- sm.cpp - session management code
+- useractions.cpp - handling of the Alt+F3 menu, shortcuts and other user actions
+
+The rest of the files contain additional helper classes:
+
+- atoms.* - so-called atoms (symbolic names for constants in X)
+- bridge.* - communication with the decoration plugin
+- geometrytip.* - window displaying window geometry while moving/resizing
+- group.* - grouping related windows together (warning! This is currently really messy and scary code
+ that should be rewritten).
+- killwindow.* - handling of the Ctrl+Esc feature
+- twinbindings.cpp - KWin's keyboard shortcuts (used by tdebase/kcontrol/keys)
+- notifications.* - for KNotify
+- options.* - all configuration options for KWin are stored in this class
+- plugins.* - loading of the right decoration plugin
+- popupinfo.* - showing temporary information such as virtual desktop name when switching desktops
+- tabbox.* - the Alt+Tab dialog
+- utils.* - various small utility functions/classes
+
+KWin also uses code from tdelibs, specifically files netwm.cpp, netwm.h, netwm_def.h and netwm_p.h
+from tdelibs/tdecore. These files implement support for the EWMH window manager specification,
+originally called NETWM (hence the filenames).
+
+
+Developing KWin:
+================
+
+So, you feel brave, huh? But KWin is not THAT difficult. Some parts, especially the X-related ones,
+can be very complicated, but for many parts even knowledge of X and Xlib is not necessary. Most X
+code is wrapped in helper functions, and I can handle problems there ;) . However, although many
+features don't require touching X/Xlib directly, still X/Xlib may impose their semantics on the way
+things are done. When in doubt, simply ask.
+
+All patches for KWin core should be sent to twin@kde.org for review first. Even seemingly harmless
+changes may have extensive consequences.
+
+Various notes:
+
+- kdDebug has overloaded operator << for the Client class, so you can e.g. use 'kdDebug() << this << endl;'
+in class Client and it will print information about the window.
+
+- KWin itself cannot create any normal windows, because it would have trouble managing its own windows.
+For such cases (which should be rare) a small external helper application is needed (kdialog should often
+do, and for special cases such a utility needs to be written like twin/killer).
+
+
+X documentation:
+================
+
+As already said, many parts of KWin don't need knowledge of Xlib or even how X actually works.
+Some parts do, and it may be also useful to have at least a basic understand for general
+understanding. A reference manual for Xlib can be found e.g.
+at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/xlib.pdf , a tutorial explaining basic can be found
+e.g. at ttp://users.actcom.co.il/~choo/lupg/tutorials/xlib-programming/xlib-programming.html
+(note that you don't need to know that all - e.g. GC's are very rarely needed and the
+section on fonts is today outdated).
+
+
+Coding style:
+=============
+
+There are only three rules for patches for KWin:
+
+- the code should be relatively nice and clean. Seriously. Any messy code can be hard to comprehend,
+but if the code is in a window manager it will be twice as difficult.
+
+- unless the functionality of the code is obvious, there should be either at least a short comment explaining
+what it does, or it should be obvious from the commit log. If there's a hack needed, if there's a potentional
+problem, if something is just a temporary fix, say so. Comments like "this clever trick is necessary"
+don't count. See rule #1 above for reasons. I needed more than two years to understand all of KWin,
+and there were parts I never got and had to rewrite in order to fix a problem with them.
+
+- put matching opening { and closing } in the same column. That's the only formatting rule I ask for.
+I don't really care if they're aligned with the block one level higher or if they're aligned with the block
+they surround like I do (which is the only thing about the "weird coding style in KWin") or if you align them
+with something else, just put them in the same column. If I can handle about half a dozen different formatting
+styles when working on various parts of KDE, this shouldn't be much work for you (and you can do that only
+right before sending the patch). I don't care where you do and don't put spaces or what exactly you call local
+variables, as long as I can read it (trying to make it look like the rest of the code is bonus points though ;) ).
+
+
+twin@kde.org
diff --git a/twin/KWinInterface.h b/twin/KWinInterface.h
new file mode 100644
index 00000000..dbc13288
--- /dev/null
+++ b/twin/KWinInterface.h
@@ -0,0 +1,50 @@
+#ifndef KWIN_INTERFACE_H
+#define KWIN_INTERFACE_H
+
+#include <dcopobject.h>
+
+class KWinInterface : virtual public DCOPObject
+ {
+ K_DCOP
+
+ k_dcop:
+
+ virtual ASYNC cascadeDesktop() = 0;
+ virtual ASYNC unclutterDesktop() = 0;
+ virtual ASYNC reconfigure() = 0;
+ virtual ASYNC killWindowId(unsigned long winId) = 0;
+ virtual ASYNC suspendWindowId(unsigned long winId) = 0;
+ virtual ASYNC resumeWindowId(unsigned long winId) = 0;
+ virtual bool isResumeableWindowID(unsigned long winId) = 0;
+ virtual void refresh() = 0;
+ virtual void doNotManage(TQString)= 0;
+ virtual void showWindowMenuAt(unsigned long winId, int x, int y)= 0;
+ virtual void kDestopResized() = 0;
+ virtual void setDesktopLayout(int orientation, int x, int y)= 0;
+ virtual bool setCurrentDesktop(int)= 0;
+ virtual int currentDesktop() const = 0;
+ virtual void nextDesktop() = 0;
+ virtual void previousDesktop() = 0;
+ virtual void circulateDesktopApplications() = 0;
+ virtual void updateOverlappingShadows(unsigned long window) = 0;
+ virtual void setShadowed(unsigned long window, bool shadowed) = 0;
+
+ // kompmgr stuff
+ virtual void startKompmgr() = 0;
+ virtual void stopKompmgr() = 0;
+ virtual bool kompmgrIsRunning() = 0;
+ virtual void kompmgrReloadSettings() = 0;
+ virtual void setOpacity(unsigned long winId, unsigned int opacityPercent) = 0;
+ virtual void setShadowSize(unsigned long winId, unsigned int shadowSizePercent) = 0;
+ virtual void setUnshadowed(unsigned long winId) = 0;
+
+ k_dcop_signals:
+
+ virtual void kompmgrStarted() = 0;
+ virtual void kompmgrStopped() = 0;
+
+ // never emitted
+ virtual void dcopResetAllClients();
+ };
+
+#endif
diff --git a/twin/LICENSE b/twin/LICENSE
new file mode 100644
index 00000000..2f2e4b2f
--- /dev/null
+++ b/twin/LICENSE
@@ -0,0 +1,21 @@
+Since KDE3.2, KWin is licensed under the terms of the General Public License.
+See file "COPYING" in the toplevel directory for the exact licensing terms.
+
+KWin versions in KDE3.1.x and older used the following license:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/twin/Makefile.am b/twin/Makefile.am
new file mode 100644
index 00000000..02e560d3
--- /dev/null
+++ b/twin/Makefile.am
@@ -0,0 +1,38 @@
+INCLUDES = -I$(srcdir)/lib $(all_includes)
+
+if include_kompmgr
+KOMPMGR=kompmgr
+endif
+
+SUBDIRS = lib . killer kcmtwin pics clients oldheaders data $(KOMPMGR)
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+tdeinit_LTLIBRARIES = twin.la
+
+twin_la_SOURCES = workspace.cpp client.cpp placement.cpp atoms.cpp \
+ utils.cpp layers.cpp main.cpp popupinfo.cpp tabbox.cpp \
+ options.cpp plugins.cpp events.cpp KWinInterface.skel \
+ killwindow.cpp geometrytip.cpp sm.cpp group.cpp bridge.cpp \
+ manage.cpp notifications.cpp activation.cpp useractions.cpp \
+ geometry.cpp rules.cpp
+
+twin_la_LIBADD = $(LIB_TDEUI) lib/libtdecorations.la
+twin_la_LDFLAGS = $(all_libraries) -module -avoid-version
+
+include_HEADERS = KWinInterface.h
+
+KDE_ICON = twin
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) -kaliasLocal *.h *.cpp killer/*.cpp lib/*.cpp -o $(podir)/twin.pot
+
+twin_datadir = $(kde_datadir)/twin
+
+twin_data_DATA= eventsrc
+
+kde_kcfg_DATA = twin.kcfg
+
+include ../admin/Doxyfile.am
diff --git a/twin/NEWCOLORSCHEME.README b/twin/NEWCOLORSCHEME.README
new file mode 100644
index 00000000..ce2ca9bb
--- /dev/null
+++ b/twin/NEWCOLORSCHEME.README
@@ -0,0 +1,44 @@
+KWin can now handle some new color scheme entries in addition to the ones
+handled by KWM. Note that these are suggestions and all the colors may not
+be used by all KWin styles. These all currently go into the [WM] group.
+
+frame, inactiveFrame : Window frame (was fixed to general KDE bg in KWM).
+
+handle, inactiveHandle : Window handles (sometimes called "grips").
+
+activeBackground, inactiveBackground : Tilebars (bad name, but it's what KWM
+uses). This is for styles that use a solid filled rectangle for the titlebar
+such as the standard style and KStep.
+
+activeGroove, inactiveGroove: This is for titlebars that instead of a solid
+rectangle use some sort of groove or small bevels layered on the frame.
+An example of this is System.
+
+activeBlend, inactiveBlend : Titlebar blend for styles that use a rectangle
+titlebar fill.
+
+activeForeground, inactiveForeground : Tilebar text for styles that use a
+rectangle titlebar fill.
+
+activeGrooveText, inactiveGrooveText: Titlebar text for styles that use
+grooved titlebar styles instead of the solid fill. This should contrast with
+the frame color.
+
+activeTitleBtnBg, inactiveTitleButtonBg : Button background color for up and
+down states.
+
+activeTitleBtnBlend, inactiveTitleBtnBlend : Button blend.
+
+activeTitleBtnFg, activeTitleBtnFg : Some style's buttons don't use the
+above button background colors but instead draw the button foreground
+transparently on the frame. The best example of this is the standard KDE
+style. Use this to specify a color for such styles, which should contrast with
+the frame - not the button bg.
+
+activeTitleBtnFullFg, inactiveTitleBtnFullFg: This is for styles that have
+full support for button background settings. Examples are KStep and System.
+This should contrast with the button background.
+
+Daniel M. Duley
+mosfet@kde.org
+mosfet@linuxmandrake.com
diff --git a/twin/README b/twin/README
new file mode 100644
index 00000000..8d61c716
--- /dev/null
+++ b/twin/README
@@ -0,0 +1,206 @@
+- The mailing list for KWin is twin@kde.org (https://mail.kde.org/mailman/listinfo/twin).
+
+- If you want to develop KWin, see file HACKING.
+
+- If you want to check KWin's compliance with specifications, see file COMPLIANCE.
+
+- File CONFIGURATION includes some details on configuring KWin.
+
+- Below is some info for application developers about application interaction
+ with the window manager, but it'd need some cleanup.
+
+
+
+
+
+
+
+
+ This README is meant as an explanation of various window manager related
+mechanisms that application developers need to be aware of. As some of these
+concepts may be difficult to understand for people not having the required
+background knowledge (since sometimes it's difficult even for people who
+do have the knowledge), the mechanisms are first briefly explained, and
+then an example of fixing the various problems is given.
+
+ For comments, questions, suggestions and whatever use the twin@kde.org
+mailing list.
+
+
+Table of contents:
+==================
+
+- Window relations
+ - how to make the window manager know which windows belong together
+- Focus stealing prevention
+ - how to solve cases where focus stealing prevention doesn't work
+ properly automatically
+
+
+
+Window relations:
+=================
+
+(For now, this explanation of window relations is mainly meant for
+focus stealing prevention. To be extended later.)
+
+ All windows created by an application should be organized in a tree
+with the root being the application's main window. Note that this is about
+toplevel windows, not widgets inside the windows. For example, if you
+have KWrite running, with a torn-off toolbar (i.e. a standalone toolbar),
+a file save dialog open, and the file save dialog showing a dialog
+for creating a directory, the window hiearchy should look like this:
+
+
+ KWrite mainwindow
+ / \
+ / \
+ file save dialog torn-off toolbar
+ \
+ \
+ create directory dialog
+
+ Each subwindow (i.e. all except for the KWrite mainwindow) points to its
+main window (which in turn may have another main window, as in the case
+of the file save dialog). When the window manager knows these relations,
+it can better arrange the windows (keeping subwindows above their
+main windows, preventing activation of a main window of a modal dialog,
+and similar). Failing to provide this information to the window manager
+may have various results, for example having dialogs positioned below
+the main window,
+
+The window property used by subwindows to point to their mainwindows is
+called WM_TRANSIENT_FOR. It can be seen by running
+'xprop | grep WM_TRANSIENT_FOR' and clicking on a window. If the property
+is not present, the window does not (claim to) have any mainwindow.
+If the property is present, it's value is the window id of its main window;
+window id of any window can be found out by running 'xwininfo'. A window
+having WM_TRANSIENT_FOR poiting to another window is said to be transient
+for that window.
+
+ In some cases, the WM_TRANSIENT_FOR property may not point to any other
+existing window, having value of 0, or pointing to the screen number
+('xwininfo -root'). These special values mean that the window is transient
+for all other windows in its window group. This should be used only
+in rare cases, everytime a specific main window is known, WM_TRANSIENT_FOR
+should be pointing to it instead of using one of these special values.
+(The explanation why is beyond the scope of this document - just accept it
+as a fact.)
+
+ With Qt, the WM_TRANSIENT_FOR property is set by Qt automatically, based
+on the toplevel widget's parent. If the toplevel widget is of a normal
+type (i.e. not a dialog, toolbar, etc.), Qt doesn't set WM_TRANSIENT_FOR
+on it. For special widgets, such as dialogs, WM_TRANSIENT_FOR is set
+to point to the widget's parent, if it has a specific parent, otherwise
+WM_TRANSIENT_FOR points to the root window.
+
+ As already said above, WM_TRANSIENT_FOR poiting to the root window should
+be usually avoided, so everytime the widget's main widget is known, the widget
+should get it passed as a parent in its constructor.
+(TODO KDialog etc. classes should not have a default argument for the parent
+argument, and comments like 'just pass 0 as the parent' should go.)
+
+
+
+Focus stealing prevention:
+==========================
+
+ Since KDE3.2 KWin has a feature called focus stealing prevention. As the name
+suggests, it prevents unexpected changes of focus. With older versions of KWin,
+if any application opened a new dialog, it became active, and
+if the application's main window was on another virtual desktop, also
+the virtual desktop was changed. This was annoying, and also sometimes led
+to dialogs mistakenly being closed because they received keyboard input that
+was meant for the previously active window.
+
+ The basic principle of focus stealing prevention is that the window with most
+recent user activity wins. Any window of an application will become active
+when being shown only if this application was the most recently used one.
+KWin itself, and some of the related tdecore classes should take care
+of the common cases, so usually there's no need for any special handling
+in applications. Qt/KDE applications, that is. Applications using other
+toolkits should in most cases work fine too. If they don't support
+the window property _NET_WM_USER_TIME, the window manager may fail to detect
+the user timestamp properly, resulting either in other windows becoming active
+while the user works with this application, or this application may sometimes
+steal focus (this second case should be very rare though).
+
+ There are also cases where KDE applications needs special handling. The two
+most common cases are when windows relations are not setup properly to make
+KWin realize that they belong to the same application, and when the user
+activity is not represented by manipulating with the application windows
+themselves.
+
+ Also note that focus stealing prevention implemented in the window manager
+can only help with focus stealing between different applications.
+If an application itself suddenly pops up a dialog, KWin cannot do anything about
+it, and its the application's job to handle this case.
+
+
+Window relations:
+-----------------
+
+ The common case here is when a dialog is shown for an application, but this
+dialog is not provided by the application itself, but by some other process.
+For example, dialogs with warnings about accepted cookies are provided
+by KCookieJar, instead of being shown by Konqueror. In the normal case,
+from KWin's point of view the cookie dialog would be an attempt of another
+application to show a dialog, and KWin wouldn't allow activation of this
+window.
+
+ The solution is to tell the window manager about the relation between
+the Konqueror main window and the cookie dialog, by making the dialog
+point to the mainwindow. Note that this is not special to focus stealing
+prevention, subwindows such as dialogs, toolbars and similar should always
+point to their mainwindow. See the section on window relations for full
+description.
+
+ The WM_TRANSIENT_FOR property that's set on dialogs to point to their
+mainwindow should in the cookie dialog case point to the Konqueror window
+for which it has been shown. This is solved in kcookiejar by including
+the window id in the DCOP call. When the cookie dialog is shown, its
+WM_TRANSIENT_FOR property is manually set using the XSetTransientForHint()
+call (see tdelibs/tdeioslave/http/kcookiejar/kcookiewin.cpp). The arguments
+to XSetTransientForHint() call are the X display (i.e. qt_xdisplay()),
+the window id on which the WM_TRANSIENT_FOR property is to be set
+(i.e. use QWidget::winId()), and the window id of the mainwindow.
+
+
+ Simple short HOWTO:
+
+ To put it simply: Let's say you have a daemon application that has
+DCOP call "showDialog( QString text )", and when this is called, it shows
+a dialog with the given text. This won't work properly with focus stealing
+prevention. The DCOP call should be changed to
+"showDialog( QString text, long id )". The caller should pass something like
+myMainWindow->winId() as the second argument. In the daemon, before
+the dialog is shown, a call to XSetTransientHint() should be added:
+
+ XSetTransientForHint( qt_xdisplay(), dialog->winId(), id_of_mainwindow );
+
+ That's it.
+
+Non-standard user activity:
+---------------------------
+
+ The most common case in KDE will be DCOP calls. For example, KDesktop's DCOP
+call "KDesktopIface popupExecuteCommand". Executing this DCOP call e.g.
+from Konsole as 'dcop kdesktop KDesktopIface popupExecuteCommand" will lead
+to showing the minicli, but the last user activity timestamp gained from events
+sent by X server will be older than user activity timestamp of Konsole, and
+would normally result in minicli not being active. Therefore, before showing
+the minicli, kdesktop needs to call TDEApplication::updateUserTimestamp().
+
+ However, this shouldn't be done with all DCOP calls. If a DCOP call is not
+a result of direct user action, calling TDEApplication::updateUserTimestamp()
+would lead to focus stealing. For example, let's assume for a moment
+that KMail would use this DCOP call in case it detects the modem is not
+connected, allowing to you to start KPPP or whatever tool you use. If KMail
+would be configured to check mail every 10 minutes, this would lead to minicli
+possibly suddenly showing up at every check. Basically, doing the above change
+to kdesktop's minicli means that the popupExecuteCommand() DCOP call is only
+for user scripting. (TODO write about focus transferring?)
+
+ Simply said, TDEApplication::updateUserTimestamp() should be called only
+as a result of user action. Unfortunately, I'm not aware of any universal
+way how to handle this, so every case will have to be considered separately.
diff --git a/twin/activation.cpp b/twin/activation.cpp
new file mode 100644
index 00000000..6f79c47c
--- /dev/null
+++ b/twin/activation.cpp
@@ -0,0 +1,1005 @@
+/*****************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
+Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+You can Freely distribute this program under the GNU General Public
+License. See the file "COPYING" for the exact licensing terms.
+******************************************************************/
+
+/*
+
+ This file contains things relevant to window activation and focus
+ stealing prevention.
+
+*/
+
+#include <tqpopupmenu.h>
+#include <kxerrorhandler.h>
+#include <tdestartupinfo.h>
+#include <kstringhandler.h>
+#include <tdelocale.h>
+
+#include "client.h"
+#include "workspace.h"
+#include <fixx11h.h>
+
+#include "notifications.h"
+#include "atoms.h"
+#include "group.h"
+#include "rules.h"
+
+namespace KWinInternal
+{
+
+/*
+ Prevention of focus stealing:
+
+ KWin tries to prevent unwanted changes of focus, that would result
+ from mapping a new window. Also, some nasty applications may try
+ to force focus change even in cases when ICCCM 4.2.7 doesn't allow it
+ (e.g. they may try to activate their main window because the user
+ definitely "needs" to see something happened - misusing
+ of TQWidget::setActiveWindow() may be such case).
+
+ There are 4 ways how a window may become active:
+ - the user changes the active window (e.g. focus follows mouse, clicking
+ on some window's titlebar) - the change of focus will
+ be done by KWin, so there's nothing to solve in this case
+ - the change of active window will be requested using the _NET_ACTIVE_WINDOW
+ message (handled in RootInfo::changeActiveWindow()) - such requests
+ will be obeyed, because this request is meant mainly for e.g. taskbar
+ asking the WM to change the active window as a result of some user action.
+ Normal applications should use this request only rarely in special cases.
+ See also below the discussion of _NET_ACTIVE_WINDOW_TRANSFER.
+ - the change of active window will be done by performing XSetInputFocus()
+ on a window that's not currently active. ICCCM 4.2.7 describes when
+ the application may perform change of input focus. In order to handle
+ misbehaving applications, KWin will try to detect focus changes to
+ windows that don't belong to currently active application, and restore
+ focus back to the currently active window, instead of activating the window
+ that got focus (unfortunately there's no way to FocusChangeRedirect similar
+ to e.g. SubstructureRedirect, so there will be short time when the focus
+ will be changed). The check itself that's done is
+ Workspace::allowClientActivation() (see below).
+ - a new window will be mapped - this is the most complicated case. If
+ the new window belongs to the currently active application, it may be safely
+ mapped on top and activated. The same if there's no active window,
+ or the active window is the desktop. These checks are done by
+ Workspace::allowClientActivation().
+ Following checks need to compare times. One time is the timestamp
+ of last user action in the currently active window, the other time is
+ the timestamp of the action that originally caused mapping of the new window
+ (e.g. when the application was started). If the first time is newer than
+ the second one, the window will not be activated, as that indicates
+ futher user actions took place after the action leading to this new
+ mapped window. This check is done by Workspace::allowClientActivation().
+ There are several ways how to get the timestamp of action that caused
+ the new mapped window (done in Client::readUserTimeMapTimestamp()) :
+ - the window may have the _NET_WM_USER_TIME property. This way
+ the application may either explicitly request that the window is not
+ activated (by using 0 timestamp), or the property contains the time
+ of last user action in the application.
+ - KWin itself tries to detect time of last user action in every window,
+ by watching KeyPress and ButtonPress events on windows. This way some
+ events may be missed (if they don't propagate to the toplevel window),
+ but it's good as a fallback for applications that don't provide
+ _NET_WM_USER_TIME, and missing some events may at most lead
+ to unwanted focus stealing.
+ - the timestamp may come from application startup notification.
+ Application startup notification, if it exists for the new mapped window,
+ should include time of the user action that caused it.
+ - if there's no timestamp available, it's checked whether the new window
+ belongs to some already running application - if yes, the timestamp
+ will be 0 (i.e. refuse activation)
+ - if the window is from session restored window, the timestamp will
+ be 0 too, unless this application was the active one at the time
+ when the session was saved, in which case the window will be
+ activated if there wasn't any user interaction since the time
+ KWin was started.
+ - as the last resort, the _KDE_NET_USER_CREATION_TIME timestamp
+ is used. For every toplevel window that is created (see CreateNotify
+ handling), this property is set to the at that time current time.
+ Since at this time it's known that the new window doesn't belong
+ to any existing application (better said, the application doesn't
+ have any other window mapped), it is either the very first window
+ of the application, or its the only window of the application
+ that was hidden before. The latter case is handled by removing
+ the property from windows before withdrawing them, making
+ the timestamp empty for next mapping of the window. In the sooner
+ case, the timestamp will be used. This helps in case when
+ an application is launched without application startup notification,
+ it creates its mainwindow, and starts its initialization (that
+ may possibly take long time). The timestamp used will be older
+ than any user action done after launching this application.
+ - if no timestamp is found at all, the window is activated.
+ The check whether two windows belong to the same application (same
+ process) is done in Client::belongToSameApplication(). Not 100% reliable,
+ but hopefully 99,99% reliable.
+
+ As a somewhat special case, window activation is always enabled when
+ session saving is in progress. When session saving, the session
+ manager allows only one application to interact with the user.
+ Not allowing window activation in such case would result in e.g. dialogs
+ not becoming active, so focus stealing prevention would cause here
+ more harm than good.
+
+ Windows that attempted to become active but KWin prevented this will
+ be marked as demanding user attention. They'll get
+ the _NET_WM_STATE_DEMANDS_ATTENTION state, and the taskbar should mark
+ them specially (blink, etc.). The state will be reset when the window
+ eventually really becomes active.
+
+ There are one more ways how a window can become obstrusive, window stealing
+ focus: By showing above the active window, by either raising itself,
+ or by moving itself on the active desktop.
+ - KWin will refuse raising non-active window above the active one,
+ unless they belong to the same application. Applications shouldn't
+ raise their windows anyway (unless the app wants to raise one
+ of its windows above another of its windows).
+ - KWin activates windows moved to the current desktop (as that seems
+ logical from the user's point of view, after sending the window
+ there directly from KWin, or e.g. using pager). This means
+ applications shouldn't send their windows to another desktop
+ (SELI TODO - but what if they do?)
+
+ Special cases I can think of:
+ - konqueror reusing, i.e. kfmclient tells running Konqueror instance
+ to open new window
+ - without focus stealing prevention - no problem
+ - with ASN (application startup notification) - ASN is forwarded,
+ and because it's newer than the instance's user timestamp,
+ it takes precedence
+ - without ASN - user timestamp needs to be reset, otherwise it would
+ be used, and it's old; moreover this new window mustn't be detected
+ as window belonging to already running application, or it wouldn't
+ be activated - see Client::sameAppWindowRoleMatch() for the (rather ugly)
+ hack
+ - konqueror preloading, i.e. window is created in advance, and kfmclient
+ tells this Konqueror instance to show it later
+ - without focus stealing prevention - no problem
+ - with ASN - ASN is forwarded, and because it's newer than the instance's
+ user timestamp, it takes precedence
+ - without ASN - user timestamp needs to be reset, otherwise it would
+ be used, and it's old; also, creation timestamp is changed to
+ the time the instance starts (re-)initializing the window,
+ this ensures creation timestamp will still work somewhat even in this case
+ - KUniqueApplication - when the window is already visible, and the new instance
+ wants it to activate
+ - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
+ - with ASN - ASN is forwarded, and set on the already visible window, KWin
+ treats the window as new with that ASN
+ - without ASN - _NET_ACTIVE_WINDOW as application request is used,
+ and there's no really usable timestamp, only timestamp
+ from the time the (new) application instance was started,
+ so KWin will activate the window *sigh*
+ - the bad thing here is that there's absolutely no chance to recognize
+ the case of starting this KUniqueApp from Konsole (and thus wanting
+ the already visible window to become active) from the case
+ when something started this KUniqueApp without ASN (in which case
+ the already visible window shouldn't become active)
+ - the only solution is using ASN for starting applications, at least silent
+ (i.e. without feedback)
+ - when one application wants to activate another application's window (e.g. KMail
+ activating already running KAddressBook window ?)
+ - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
+ - with ASN - can't be here, it's the KUniqueApp case then
+ - without ASN - _NET_ACTIVE_WINDOW as application request should be used,
+ KWin will activate the new window depending on the timestamp and
+ whether it belongs to the currently active application
+
+ _NET_ACTIVE_WINDOW usage:
+ data.l[0]= 1 ->app request
+ = 2 ->pager request
+ = 0 - backwards compatibility
+ data.l[1]= timestamp
+*/
+
+
+//****************************************
+// Workspace
+//****************************************
+
+
+/*!
+ Informs the workspace about the active client, i.e. the client that
+ has the focus (or None if no client has the focus). This functions
+ is called by the client itself that gets focus. It has no other
+ effect than fixing the focus chain and the return value of
+ activeClient(). And of course, to propagate the active client to the
+ world.
+ */
+void Workspace::setActiveClient( Client* c, allowed_t )
+ {
+ if ( active_client == c )
+ return;
+ if( active_popup && active_popup_client != c && set_active_client_recursion == 0 )
+ closeActivePopup();
+ StackingUpdatesBlocker blocker( this );
+ ++set_active_client_recursion;
+ updateFocusMousePosition( TQCursor::pos());
+ if( active_client != NULL )
+ { // note that this may call setActiveClient( NULL ), therefore the recursion counter
+ active_client->setActive( false, !c || !c->isModal() || c != active_client->transientFor() );
+ }
+ active_client = c;
+ if (set_active_client_recursion == 1)
+ {
+ // Only unset next_active_client if activateClient() wasn't called by
+ // Client::setActive() to set the active window to null before
+ // activating another window.
+ next_active_client = NULL;
+ }
+ Q_ASSERT( c == NULL || c->isActive());
+ if( active_client != NULL )
+ last_active_client = active_client;
+ if ( active_client )
+ {
+ updateFocusChains( active_client, FocusChainMakeFirst );
+ active_client->demandAttention( false );
+ }
+ pending_take_activity = NULL;
+
+ updateCurrentTopMenu();
+ updateToolWindows( false );
+ if( c )
+ disableGlobalShortcutsForClient( c->rules()->checkDisableGlobalShortcuts( false ));
+ else
+ disableGlobalShortcutsForClient( false );
+
+ updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
+
+ rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
+ updateColormap();
+ --set_active_client_recursion;
+ }
+
+/*!
+ Tries to activate the client \a c. This function performs what you
+ expect when clicking the respective entry in a taskbar: showing and
+ raising the client (this may imply switching to the another virtual
+ desktop) and putting the focus onto it. Once X really gave focus to
+ the client window as requested, the client itself will call
+ setActiveClient() and the operation is complete. This may not happen
+ with certain focus policies, though.
+
+ \sa stActiveClient(), requestFocus()
+ */
+void Workspace::activateClient( Client* c, bool force )
+ {
+ if( c == NULL )
+ {
+ focusToNull();
+ setActiveClient( NULL, Allowed );
+ return;
+ }
+ raiseClient( c );
+ if (!c->isOnDesktop(currentDesktop()) )
+ {
+ ++block_focus;
+ setCurrentDesktop( c->desktop() );
+ --block_focus;
+ }
+ if( c->isMinimized())
+ c->unminimize();
+
+// TODO force should perhaps allow this only if the window already contains the mouse
+ if( options->focusPolicyIsReasonable() || force )
+ requestFocus( c, force );
+
+ // Don't update user time for clients that have focus stealing workaround.
+ // As they usually belong to the current active window but fail to provide
+ // this information, updating their user time would make the user time
+ // of the currently active window old, and reject further activation for it.
+ // E.g. typing URL in minicli which will show tdeio_uiserver dialog (with workaround),
+ // and then kdesktop shows dialog about SSL certificate.
+ // This needs also avoiding user creation time in Client::readUserTimeMapTimestamp().
+ if( !c->ignoreFocusStealing())
+ c->updateUserTime();
+ }
+
+/*!
+ Tries to activate the client by asking X for the input focus. This
+ function does not perform any show, raise or desktop switching. See
+ Workspace::activateClient() instead.
+
+ \sa Workspace::activateClient()
+ */
+void Workspace::requestFocus( Client* c, bool force )
+ {
+ takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false);
+ }
+
+void Workspace::takeActivity( Client* c, int flags, bool handled )
+ {
+ // the 'if( c == active_client ) return;' optimization mustn't be done here
+ if (!focusChangeEnabled() && ( c != active_client) )
+ flags &= ~ActivityFocus;
+
+ if ( !c )
+ {
+ focusToNull();
+ return;
+ }
+
+ if( flags & ActivityFocus )
+ {
+ Client* modal = c->findModal();
+ if( modal != NULL && modal != c )
+ {
+ next_active_client = modal;
+ if( !modal->isOnDesktop( c->desktop()))
+ {
+ modal->setDesktop( c->desktop());
+ if( modal->desktop() != c->desktop()) // forced desktop
+ activateClient( modal );
+ }
+ // if the click was inside the window (i.e. handled is set),
+ // but it has a modal, there's no need to use handled mode, because
+ // the modal doesn't get the click anyway
+ // raising of the original window needs to be still done
+ if( flags & ActivityRaise )
+ raiseClient( c );
+ c = modal;
+ handled = false;
+ }
+ cancelDelayFocus();
+ }
+ if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
+ flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced
+ if( c->isShade())
+ {
+ if( c->wantsInput() && ( flags & ActivityFocus ))
+ {
+ // client cannot accept focus, but at least the window should be active (window menu, et. al. )
+ c->setActive( true );
+ focusToNull();
+ }
+ if( c->wantsInput())
+ next_active_client = c;
+ flags &= ~ActivityFocus;
+ handled = false; // no point, can't get clicks
+ }
+ if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed
+ {
+ next_active_client = c;
+ kdWarning( 1212 ) << "takeActivity: not shown" << endl;
+ return;
+ }
+ c->takeActivity( flags, handled, Allowed );
+ if( !c->isOnScreen( active_screen ))
+ active_screen = c->screen();
+ }
+
+void Workspace::handleTakeActivity( Client* c, Time /*timestamp*/, int flags )
+ {
+ if( pending_take_activity != c ) // pending_take_activity is reset when doing restack or activation
+ return;
+ if(( flags & ActivityRaise ) != 0 )
+ raiseClient( c );
+ if(( flags & ActivityFocus ) != 0 && c->isShown( false ))
+ c->takeFocus( Allowed );
+ pending_take_activity = NULL;
+ }
+
+/*!
+ Informs the workspace that the client \a c has been hidden. If it
+ was the active client (or to-become the active client),
+ the workspace activates another one.
+
+ \a c may already be destroyed
+ */
+void Workspace::clientHidden( Client* c )
+ {
+ assert( !c->isShown( true ) || !c->isOnCurrentDesktop());
+ activateNextClient( c );
+ }
+
+// deactivates 'c' and activates next client
+bool Workspace::activateNextClient( Client* c )
+ {
+ // if 'c' is not the active or the to-become active one, do nothing
+ if( !( c == active_client
+ || ( should_get_focus.count() > 0 && c == should_get_focus.last())))
+ return false;
+ closeActivePopup();
+ if( c != NULL )
+ {
+ if( c == active_client )
+ setActiveClient( NULL, Allowed );
+ should_get_focus.remove( c );
+ }
+ if( focusChangeEnabled())
+ {
+ if ( options->focusPolicyIsReasonable())
+ { // search the focus_chain for a client to transfer focus to
+ // if 'c' is transient, transfer focus to the first suitable mainwindow
+ Client* get_focus = NULL;
+ const ClientList mainwindows = ( c != NULL ? c->mainClients() : ClientList());
+ for( ClientList::ConstIterator it = focus_chain[currentDesktop()].fromLast();
+ it != focus_chain[currentDesktop()].end();
+ --it )
+ {
+ if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop())
+ continue;
+ if( options->separateScreenFocus )
+ {
+ if( c != NULL && !(*it)->isOnScreen( c->screen()))
+ continue;
+ if( c == NULL && !(*it)->isOnScreen( activeScreen()))
+ continue;
+ }
+ if( mainwindows.contains( *it ))
+ {
+ get_focus = *it;
+ break;
+ }
+ if( get_focus == NULL )
+ get_focus = *it;
+ }
+ if( get_focus == NULL )
+ get_focus = findDesktop( true, currentDesktop());
+ if( get_focus != NULL )
+ requestFocus( get_focus );
+ else
+ focusToNull();
+ }
+ else
+ return false;
+ }
+ else
+ // if blocking focus, move focus to the desktop later if needed
+ // in order to avoid flickering
+ focusToNull();
+ return true;
+ }
+
+void Workspace::setCurrentScreen( int new_screen )
+ {
+ if (new_screen < 0 || new_screen > numScreens())
+ return;
+ if ( !options->focusPolicyIsReasonable())
+ return;
+ closeActivePopup();
+ Client* get_focus = NULL;
+ for( ClientList::ConstIterator it = focus_chain[currentDesktop()].fromLast();
+ it != focus_chain[currentDesktop()].end();
+ --it )
+ {
+ if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop())
+ continue;
+ if( !(*it)->screen() == new_screen )
+ continue;
+ get_focus = *it;
+ break;
+ }
+ if( get_focus == NULL )
+ get_focus = findDesktop( true, currentDesktop());
+ if( get_focus != NULL && get_focus != mostRecentlyActivatedClient())
+ requestFocus( get_focus );
+ active_screen = new_screen;
+ }
+
+void Workspace::gotFocusIn( const Client* c )
+ {
+ if( should_get_focus.contains( const_cast< Client* >( c )))
+ { // remove also all sooner elements that should have got FocusIn,
+ // but didn't for some reason (and also won't anymore, because they were sooner)
+ while( should_get_focus.first() != c )
+ should_get_focus.pop_front();
+ should_get_focus.pop_front(); // remove 'c'
+ }
+ }
+
+void Workspace::setShouldGetFocus( Client* c )
+ {
+ should_get_focus.append( c );
+ updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
+ }
+
+// focus_in -> the window got FocusIn event
+// session_active -> the window was active when saving session
+bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in )
+ {
+ // options->focusStealingPreventionLevel :
+ // 0 - none - old KWin behaviour, new windows always get focus
+ // 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed
+ // 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed,
+ // this is the default
+ // 3 - high - new window gets focus only if it belongs to the active application,
+ // or when no window is currently active
+ // 4 - extreme - no window gets focus without user intervention
+ if( time == -1U )
+ time = c->userTime();
+ int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
+ if( session_saving && level <= 2 ) // <= normal
+ {
+ return true;
+ }
+ Client* ac = mostRecentlyActivatedClient();
+ if( focus_in )
+ {
+ if( should_get_focus.contains( const_cast< Client* >( c )))
+ return true; // FocusIn was result of KWin's action
+ // Before getting FocusIn, the active Client already
+ // got FocusOut, and therefore got deactivated.
+ ac = last_active_client;
+ }
+ if( time == 0 ) // explicitly asked not to get focus
+ return false;
+ if( level == 0 ) // none
+ return true;
+ if( level == 4 ) // extreme
+ return false;
+ if( !c->isOnCurrentDesktop())
+ return false; // allow only with level == 0
+ if( c->ignoreFocusStealing())
+ return true;
+ if( ac == NULL || ac->isDesktop())
+ {
+// kdDebug( 1212 ) << "Activation: No client active, allowing" << endl;
+ return true; // no active client -> always allow
+ }
+ // TODO window urgency -> return true?
+ if( Client::belongToSameApplication( c, ac, true ))
+ {
+// kdDebug( 1212 ) << "Activation: Belongs to active application" << endl;
+ return true;
+ }
+ if( level == 3 ) // high
+ return false;
+ if( time == -1U ) // no time known
+ {
+// kdDebug( 1212 ) << "Activation: No timestamp at all" << endl;
+ if( level == 1 ) // low
+ return true;
+ // no timestamp at all, don't activate - because there's also creation timestamp
+ // done on CreateNotify, this case should happen only in case application
+ // maps again already used window, i.e. this won't happen after app startup
+ return false;
+ }
+ // level == 2 // normal
+ Time user_time = ac->userTime();
+// kdDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time
+// << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
+ return timestampCompare( time, user_time ) >= 0; // time >= user_time
+ }
+
+// basically the same like allowClientActivation(), this time allowing
+// a window to be fully raised upon its own request (XRaiseWindow),
+// if refused, it will be raised only on top of windows belonging
+// to the same application
+bool Workspace::allowFullClientRaising( const Client* c, Time time )
+ {
+ int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
+ if( session_saving && level <= 2 ) // <= normal
+ {
+ return true;
+ }
+ Client* ac = mostRecentlyActivatedClient();
+ if( level == 0 ) // none
+ return true;
+ if( level == 4 ) // extreme
+ return false;
+ if( ac == NULL || ac->isDesktop())
+ {
+// kdDebug( 1212 ) << "Raising: No client active, allowing" << endl;
+ return true; // no active client -> always allow
+ }
+ if( c->ignoreFocusStealing())
+ return true;
+ // TODO window urgency -> return true?
+ if( Client::belongToSameApplication( c, ac, true ))
+ {
+// kdDebug( 1212 ) << "Raising: Belongs to active application" << endl;
+ return true;
+ }
+ if( level == 3 ) // high
+ return false;
+ Time user_time = ac->userTime();
+// kdDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time
+// << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
+ return timestampCompare( time, user_time ) >= 0; // time >= user_time
+ }
+
+// called from Client after FocusIn that wasn't initiated by KWin and the client
+// wasn't allowed to activate
+void Workspace::restoreFocus()
+ {
+ // this updateXTime() is necessary - as FocusIn events don't have
+ // a timestamp *sigh*, twin's timestamp would be older than the timestamp
+ // that was used by whoever caused the focus change, and therefore
+ // the attempt to restore the focus would fail due to old timestamp
+ updateXTime();
+ if( should_get_focus.count() > 0 )
+ requestFocus( should_get_focus.last());
+ else if( last_active_client )
+ requestFocus( last_active_client );
+ }
+
+void Workspace::clientAttentionChanged( Client* c, bool set )
+ {
+ if( set )
+ {
+ attention_chain.remove( c );
+ attention_chain.prepend( c );
+ }
+ else
+ attention_chain.remove( c );
+ }
+
+// This is used when a client should be shown active immediately after requestFocus(),
+// without waiting for the matching FocusIn that will really make the window the active one.
+// Used only in special cases, e.g. for MouseActivateRaiseandMove with transparent windows,
+bool Workspace::fakeRequestedActivity( Client* c )
+ {
+ if( should_get_focus.count() > 0 && should_get_focus.last() == c )
+ {
+ if( c->isActive())
+ return false;
+ c->setActive( true );
+ return true;
+ }
+ return false;
+ }
+
+void Workspace::unfakeActivity( Client* c )
+ {
+ if( should_get_focus.count() > 0 && should_get_focus.last() == c )
+ { // TODO this will cause flicker, and probably is not needed
+ if( last_active_client != NULL )
+ last_active_client->setActive( true );
+ else
+ c->setActive( false );
+ }
+ }
+
+
+//********************************************
+// Client
+//********************************************
+
+/*!
+ Updates the user time (time of last action in the active window).
+ This is called inside twin for every action with the window
+ that qualifies for user interaction (clicking on it, activate it
+ externally, etc.).
+ */
+void Client::updateUserTime( Time time )
+ { // copied in Group::updateUserTime
+ if( time == CurrentTime )
+ time = GET_QT_X_TIME();
+ if( time != -1U
+ && ( user_time == CurrentTime
+ || timestampCompare( time, user_time ) > 0 )) // time > user_time
+ user_time = time;
+ group()->updateUserTime( user_time );
+ }
+
+Time Client::readUserCreationTime() const
+ {
+ long result = -1; // Time == -1 means none
+ Atom type;
+ int format, status;
+ unsigned long nitems = 0;
+ unsigned long extra = 0;
+ unsigned char *data = 0;
+ KXErrorHandler handler; // ignore errors?
+ status = XGetWindowProperty( tqt_xdisplay(), window(),
+ atoms->kde_net_wm_user_creation_time, 0, 10000, FALSE, XA_CARDINAL,
+ &type, &format, &nitems, &extra, &data );
+ if (status == Success )
+ {
+ if (data && nitems > 0)
+ result = *((long*) data);
+ XFree(data);
+ }
+ return result;
+ }
+
+void Client::demandAttention( bool set )
+ {
+ if( isActive())
+ set = false;
+ if( demands_attention == set )
+ return;
+ demands_attention = set;
+ if( demands_attention )
+ {
+ // Demand attention flag is often set right from manage(), when focus stealing prevention
+ // steps in. At that time the window has no taskbar entry yet, so KNotify cannot place
+ // e.g. the passive popup next to it. So wait up to 1 second for the icon geometry
+ // to be set.
+ // Delayed call to KNotify also solves the problem of having X server grab in manage(),
+ // which may deadlock when KNotify (or TDELauncher when launching KNotify) need to access X.
+ Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther;
+ // Setting the demands attention state needs to be done directly in KWin, because
+ // KNotify would try to set it, resulting in a call to KNotify again, etc.
+ if( Notify::makeDemandAttention( e ))
+ info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
+
+ if( demandAttentionKNotifyTimer == NULL )
+ {
+ demandAttentionKNotifyTimer = new TQTimer( this );
+ connect( demandAttentionKNotifyTimer, TQT_SIGNAL( timeout()), TQT_SLOT( demandAttentionKNotify()));
+ }
+ demandAttentionKNotifyTimer->start( 1000, true );
+ }
+ else
+ info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
+ workspace()->clientAttentionChanged( this, set );
+ }
+
+void Client::demandAttentionKNotify()
+ {
+ Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther;
+ Notify::raise( e, i18n( "Window '%1' demands attention." ).arg( KStringHandler::csqueeze(caption())), this );
+ demandAttentionKNotifyTimer->stop();
+ demandAttentionKNotifyTimer->deleteLater();
+ demandAttentionKNotifyTimer = NULL;
+ }
+
+// TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it
+KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*,
+ // ignore already existing splashes, toolbars, utilities, menus and topmenus,
+ // as the app may show those before the main window
+ !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
+ && Client::belongToSameApplication( cl, value, true ) && cl != value);
+
+Time Client::readUserTimeMapTimestamp( const TDEStartupInfoId* asn_id, const TDEStartupInfoData* asn_data,
+ bool session ) const
+ {
+ Time time = info->userTime();
+// kdDebug( 1212 ) << "User timestamp, initial:" << time << endl;
+ // newer ASN timestamp always replaces user timestamp, unless user timestamp is 0
+ // helps e.g. with konqy reusing
+ if( asn_data != NULL && time != 0 )
+ {
+ // prefer timestamp from ASN id (timestamp from data is obsolete way)
+ if( asn_id->timestamp() != 0
+ && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
+ {
+ time = asn_id->timestamp();
+ }
+ else if( asn_data->timestamp() != -1U
+ && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
+ {
+ time = asn_data->timestamp();
+ }
+ }
+// kdDebug( 1212 ) << "User timestamp, ASN:" << time << endl;
+ if( time == -1U )
+ { // The window doesn't have any timestamp.
+ // If it's the first window for its application
+ // (i.e. there's no other window from the same app),
+ // use the _TDE_NET_WM_USER_CREATION_TIME trick.
+ // Otherwise, refuse activation of a window
+ // from already running application if this application
+ // is not the active one (unless focus stealing prevention is turned off).
+ Client* act = workspace()->mostRecentlyActivatedClient();
+ if( act != NULL && !belongToSameApplication( act, this, true ))
+ {
+ bool first_window = true;
+ if( isTransient())
+ {
+ if( act->hasTransient( this, true ))
+ ; // is transient for currently active window, even though it's not
+ // the same app (e.g. kcookiejar dialog) -> allow activation
+ else if( groupTransient() &&
+ findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
+ ; // standalone transient
+ else
+ first_window = false;
+ }
+ else
+ {
+ if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
+ first_window = false;
+ }
+ // don't refuse if focus stealing prevention is turned off
+ if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 )
+ {
+// kdDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl;
+ return 0; // refuse activation
+ }
+ }
+ // Creation time would just mess things up during session startup,
+ // as possibly many apps are started up at the same time.
+ // If there's no active window yet, no timestamp will be needed,
+ // as plain Workspace::allowClientActivation() will return true
+ // in such case. And if there's already active window,
+ // it's better not to activate the new one.
+ // Unless it was the active window at the time
+ // of session saving and there was no user interaction yet,
+ // this check will be done in manage().
+ if( session )
+ return -1U;
+ if( ignoreFocusStealing() && act != NULL )
+ time = act->userTime();
+ else
+ time = readUserCreationTime();
+ }
+// kdDebug( 1212 ) << "User timestamp, final:" << this << ":" << time << endl;
+ return time;
+ }
+
+Time Client::userTime() const
+ {
+ Time time = user_time;
+ if( time == 0 ) // doesn't want focus after showing
+ return 0;
+ assert( group() != NULL );
+ if( time == -1U
+ || ( group()->userTime() != -1U
+ && timestampCompare( group()->userTime(), time ) > 0 ))
+ time = group()->userTime();
+ return time;
+ }
+
+/*!
+ Sets the client's active state to \a act.
+
+ This function does only change the visual appearance of the client,
+ it does not change the focus setting. Use
+ Workspace::activateClient() or Workspace::requestFocus() instead.
+
+ If a client receives or looses the focus, it calls setActive() on
+ its own.
+
+ */
+void Client::setActive( bool act, bool updateOpacity_)
+ {
+ if ( active == act )
+ return;
+ active = act;
+ workspace()->setActiveClient( act ? this : NULL, Allowed );
+
+ if (updateOpacity_) updateOpacity();
+ if (isModal() && transientFor())
+ {
+ if (!act) transientFor()->updateOpacity();
+ else if (!transientFor()->custom_opacity) transientFor()->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
+ }
+ updateShadowSize();
+
+ if ( active )
+ {
+ Notify::raise( Notify::Activate );
+ if (options->shadowEnabled(true))
+ {
+ if (options->shadowEnabled(false))
+ {
+ // Wait for inactive shadow to expose occluded windows and give
+ // them a chance to redraw before painting the active shadow
+ removeShadow();
+ drawDelayedShadow();
+ if (!isDesktop() &&
+ this != workspace()->topClientOnDesktop(desktop()))
+ // If the newly activated window's isn't the desktop, wait
+ // for its shadow to draw, then redraw any shadows
+ // overlapping it.
+ drawOverlappingShadows(true);
+ }
+ else
+ drawShadow();
+ }
+ }
+ else
+ {
+ removeShadow();
+
+ if (options->shadowEnabled(false))
+ if (this == workspace()->topClientOnDesktop(desktop()))
+ {
+ /* If the newly deactivated window is the top client on the
+ * desktop, then the newly activated window is below it; ensure
+ * that the deactivated window's shadow draws after the
+ * activated window's shadow.
+ */
+ if ((shadowAfterClient = workspace()->activeClient()))
+ drawShadowAfter(shadowAfterClient);
+ }
+ else
+ drawDelayedShadow();
+ }
+
+ if( !active )
+ cancelAutoRaise();
+
+ if( !active && shade_mode == ShadeActivated )
+ setShade( ShadeNormal );
+
+ StackingUpdatesBlocker blocker( workspace());
+ workspace()->updateClientLayer( this ); // active windows may get different layer
+ // TODO optimize? mainClients() may be a bit expensive
+ ClientList mainclients = mainClients();
+ for( ClientList::ConstIterator it = mainclients.begin();
+ it != mainclients.end();
+ ++it )
+ if( (*it)->isFullScreen()) // fullscreens go high even if their transient is active
+ workspace()->updateClientLayer( *it );
+ if( decoration != NULL )
+ decoration->activeChange();
+ updateMouseGrab();
+ updateUrgency(); // demand attention again if it's still urgent
+ }
+
+void Client::startupIdChanged()
+ {
+ TDEStartupInfoId asn_id;
+ TDEStartupInfoData asn_data;
+ bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
+ if( !asn_valid )
+ return;
+ // If the ASN contains desktop, move it to the desktop, otherwise move it to the current
+ // desktop (since the new ASN should make the window act like if it's a new application
+ // launched). However don't affect the window's desktop if it's set to be on all desktops.
+ int desktop = workspace()->currentDesktop();
+ if( asn_data.desktop() != 0 )
+ desktop = asn_data.desktop();
+ if( !isOnAllDesktops())
+ workspace()->sendClientToDesktop( this, desktop, true );
+ if( asn_data.xinerama() != -1 )
+ workspace()->sendClientToScreen( this, asn_data.xinerama());
+ Time timestamp = asn_id.timestamp();
+ if( timestamp == 0 && asn_data.timestamp() != -1U )
+ timestamp = asn_data.timestamp();
+ if( timestamp != 0 )
+ {
+ bool activate = workspace()->allowClientActivation( this, timestamp );
+ if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
+ activate = false; // it was started on different desktop than current one
+ if( activate )
+ workspace()->activateClient( this );
+ else
+ demandAttention();
+ }
+ }
+
+void Client::updateUrgency()
+ {
+ if( urgency )
+ demandAttention();
+ }
+
+void Client::shortcutActivated()
+ {
+ workspace()->activateClient( this, true ); // force
+ }
+
+//****************************************
+// Group
+//****************************************
+
+void Group::startupIdChanged()
+ {
+ TDEStartupInfoId asn_id;
+ TDEStartupInfoData asn_data;
+ bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
+ if( !asn_valid )
+ return;
+ if( asn_id.timestamp() != 0 && user_time != -1U
+ && timestampCompare( asn_id.timestamp(), user_time ) > 0 )
+ {
+ user_time = asn_id.timestamp();
+ }
+ else if( asn_data.timestamp() != -1U && user_time != -1U
+ && timestampCompare( asn_data.timestamp(), user_time ) > 0 )
+ {
+ user_time = asn_data.timestamp();
+ }
+ }
+
+void Group::updateUserTime( Time time )
+ { // copy of Client::updateUserTime
+ if( time == CurrentTime )
+ time = GET_QT_X_TIME();
+ if( time != -1U
+ && ( user_time == CurrentTime
+ || timestampCompare( time, user_time ) > 0 )) // time > user_time
+ user_time = time;
+ }
+
+} // namespace
diff --git a/twin/atoms.cpp b/twin/atoms.cpp
new file mode 100644
index 00000000..840f1be4
--- /dev/null
+++ b/twin/atoms.cpp
@@ -0,0 +1,111 @@
+/*****************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
+Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+You can Freely distribute this program under the GNU General Public
+License. See the file "COPYING" for the exact licensing terms.
+******************************************************************/
+
+
+#include <tqapplication.h>
+#include "atoms.h"
+#include <assert.h>
+
+namespace KWinInternal
+{
+
+Atoms::Atoms()
+ {
+
+ const int max = 50;
+ Atom* atoms[max];
+ char* names[max];
+ Atom atoms_return[max];
+ int n = 0;
+
+ atoms[n] = &twin_running;
+ names[n++] = (char *) "TWIN_RUNNING";
+
+ atoms[n] = &wm_protocols;
+ names[n++] = (char *) "WM_PROTOCOLS";
+
+ atoms[n] = &wm_delete_window;
+ names[n++] = (char *) "WM_DELETE_WINDOW";
+
+ atoms[n] = &wm_take_focus;
+ names[n++] = (char *) "WM_TAKE_FOCUS";
+
+ atoms[n] = &wm_change_state;
+ names[n++] = (char *) "WM_CHANGE_STATE";
+
+ atoms[n] = &wm_client_leader;
+ names[n++] = (char *) "WM_CLIENT_LEADER";
+
+ atoms[n] = &motif_wm_hints;
+ names[n++] = (char *) "_MOTIF_WM_HINTS";
+
+ atoms[n] = &net_wm_context_help;
+ names[n++] = (char *) "_NET_WM_CONTEXT_HELP";
+
+ atoms[n] = &net_wm_ping;
+ names[n++] = (char *) "_NET_WM_PING";
+
+ atoms[n] = &kde_wm_change_state;
+ names[n++] = (char *) "_TDE_WM_CHANGE_STATE";
+
+ atoms[n] = &net_wm_user_time;
+ names[n++] = (char *) "_NET_WM_USER_TIME";
+ atoms[n] = &kde_net_wm_user_creation_time;
+ names[n++] = (char *) "_TDE_NET_WM_USER_CREATION_TIME";
+
+ atoms[n] = &kde_system_tray_embedding;
+ names[n++] = (char*) "_TDE_SYSTEM_TRAY_EMBEDDING";
+
+ atoms[n] = &net_wm_take_activity;
+ names[n++] = (char*) "_NET_WM_TAKE_ACTIVITY";
+
+ atoms[n] = &net_wm_window_opacity;
+ names[n++] = (char*) "_NET_WM_WINDOW_OPACITY";
+
+ atoms[n] = &net_wm_window_shadow;
+ names[n++] = (char*) "_TDE_WM_WINDOW_SHADOW";
+
+ atoms[n] = &net_wm_window_shade;
+ names[n++] = (char*) "_TDE_WM_WINDOW_SHADE";
+
+ atoms[n] = &net_wm_window_shapable;
+ names[n++] = (char*) "_TDE_WM_WINDOW_SHAPABLE";
+
+ atoms[n] = &net_wm_window_decohash;
+ names[n++] = (char*) "_TDE_WM_WINDOW_DECOHASH";
+
+ atoms[n] = &net_wm_system_modal_notification;
+ names[n++] = (char*) "_TDE_WM_MODAL_SYS_NOTIFICATION";
+
+ Atom fake;
+ atoms[n] = &fake;
+ names[n++] = (char *) "_DT_SM_WINDOW_INFO";
+ atoms[n] = &fake;
+ names[n++] = (char *) "_MOTIF_WM_INFO"; // #172028
+
+ atoms[n] = &xdnd_aware;
+ names[n++] = (char*) "XdndAware";
+ atoms[n] = &xdnd_position;
+ names[n++] = (char*) "XdndPosition";
+
+ atoms[n] = &net_frame_extents;
+ names[n++] = (char*) "_NET_FRAME_EXTENTS";
+ atoms[n] = &kde_net_wm_frame_strut;
+ names[n++] = (char*) "_TDE_NET_WM_FRAME_STRUT";
+
+ assert( n <= max );
+
+ XInternAtoms( tqt_xdisplay(), names, n, FALSE, atoms_return );
+ for (int i = 0; i < n; i++ )
+ *atoms[i] = atoms_return[i];
+ }
+
+} // namespace
diff --git a/twin/atoms.h b/twin/atoms.h
new file mode 100644
index 00000000..46dd11f9
--- /dev/null
+++ b/twin/atoms.h
@@ -0,0 +1,57 @@
+/*****************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
+Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+You can Freely distribute this program under the GNU General Public
+License. See the file "COPYING" for the exact licensing terms.
+******************************************************************/
+
+#ifndef KWIN_ATOMS_H
+#define KWIN_ATOMS_H
+#include <X11/Xlib.h>
+
+namespace KWinInternal
+{
+
+class Atoms
+ {
+ public:
+ Atoms();
+
+ Atom twin_running;
+
+ Atom wm_protocols;
+ Atom wm_delete_window;
+ Atom wm_take_focus;
+ Atom wm_change_state;
+ Atom wm_client_leader;
+
+ Atom motif_wm_hints;
+ Atom net_wm_context_help;
+ Atom net_wm_ping;
+ Atom kde_wm_change_state;
+ Atom net_wm_user_time;
+ Atom kde_net_wm_user_creation_time;
+ Atom kde_system_tray_embedding;
+ Atom net_wm_take_activity;
+ Atom net_wm_window_opacity;
+ Atom net_wm_window_shadow;
+ Atom net_wm_window_shade;
+ Atom net_wm_window_shapable;
+ Atom net_wm_window_decohash;
+ Atom net_wm_system_modal_notification;
+ Atom xdnd_aware;
+ Atom xdnd_position;
+ Atom net_frame_extents;
+ Atom kde_net_wm_frame_strut;
+ };
+
+
+extern Atoms* atoms;
+
+} // namespace
+
+#endif
diff --git a/twin/bridge.cpp b/twin/bridge.cpp
new file mode 100644
index 00000000..49840e24
--- /dev/null
+++ b/twin/bridge.cpp
@@ -0,0 +1,206 @@
+/*****************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+You can Freely distribute this program under the GNU General Public
+License. See the file "COPYING" for the exact licensing terms.
+******************************************************************/
+
+#include "bridge.h"
+
+#include "client.h"
+#include "options.h"
+
+namespace KWinInternal
+{
+
+Bridge::Bridge( Client* cl )
+ : c( cl )
+ {
+ }
+
+#define BRIDGE_HELPER( rettype, prototype, args1, args2, cst ) \
+rettype Bridge::prototype ( args1 ) cst \
+ { \
+ return c->prototype( args2 ); \
+ }
+
+BRIDGE_HELPER( bool, isActive,,, const )
+BRIDGE_HELPER( bool, isCloseable,,, const )
+BRIDGE_HELPER( bool, isMaximizable,,, const )
+BRIDGE_HELPER( Bridge::MaximizeMode, maximizeMode,,, const )
+BRIDGE_HELPER( bool, isMinimizable,,, const )
+BRIDGE_HELPER( bool, providesContextHelp,,, const )
+BRIDGE_HELPER( int, desktop,,, const )
+BRIDGE_HELPER( bool, isModal,,, const )
+BRIDGE_HELPER( bool, isShadeable,,, const )
+BRIDGE_HELPER( bool, isShade,,, const )
+BRIDGE_HELPER( bool, keepAbove,,, const )
+BRIDGE_HELPER( bool, keepBelow,,, const )
+BRIDGE_HELPER( bool, isMovable,,, const )
+BRIDGE_HELPER( bool, isResizable,,, const )
+BRIDGE_HELPER( TQString, caption,,, const )
+BRIDGE_HELPER( void, processMousePressEvent, TQMouseEvent* e, e, )
+BRIDGE_HELPER( TQRect, geometry,,, const )
+BRIDGE_HELPER( void, closeWindow,,, )
+BRIDGE_HELPER( void, maximize, MaximizeMode m, m, )
+BRIDGE_HELPER( void, minimize,,, )
+BRIDGE_HELPER( void, showContextHelp,,, )
+BRIDGE_HELPER( void, setDesktop, int desktop, desktop, )
+
+void Bridge::setKeepAbove( bool set )
+ {
+ if( c->keepAbove() != set )
+ c->workspace()->performWindowOperation( c, KeepAboveOp );
+ }
+
+void Bridge::setKeepBelow( bool set )
+ {
+ if( c->keepBelow() != set )
+ c->workspace()->performWindowOperation( c, KeepBelowOp );
+ }
+
+NET::WindowType Bridge::windowType( unsigned long supported_types ) const
+ {
+ return c->windowType( false, supported_types );
+ }
+
+TQIconSet Bridge::icon() const
+ {
+ return TQIconSet( c->miniIcon(), c->icon());
+ }
+
+bool Bridge::isSetShade() const
+ {
+ return c->shadeMode() != ShadeNone;
+ }
+
+void Bridge::showWindowMenu( TQPoint p )
+ {
+ c->workspace()->showWindowMenu( p, c );
+ }
+
+void Bridge::showWindowMenu( const TQRect &p )
+ {
+ c->workspace()->showWindowMenu( p, c );
+ }
+
+void Bridge::performWindowOperation( WindowOperation op )
+ {
+ c->workspace()->performWindowOperation( c, op );
+ }
+
+void Bridge::setMask( const TQRegion& r, int mode )
+ {
+ c->setMask( r, mode );
+ }
+
+bool Bridge::isPreview() const
+ {
+ return false;
+ }
+
+TQRect Bridge::iconGeometry() const
+ {
+ NETRect r = c->info->iconGeometry();
+ return TQRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
+ }
+
+TQWidget* Bridge::workspaceWidget() const
+ {
+ return c->workspace()->desktopWidget();
+ }
+
+WId Bridge::windowId() const
+ {
+ return c->window();
+ }
+
+void Bridge::titlebarDblClickOperation()
+ {
+ c->workspace()->performWindowOperation( c, options->operationTitlebarDblClick());
+ }
+
+void Bridge::titlebarMouseWheelOperation( int delta )
+ {
+ c->performMouseCommand( options->operationTitlebarMouseWheel( delta ), TQCursor::pos());
+ }
+
+void Bridge::setShade( bool set )
+ {
+ c->setShade( set ? ShadeNormal : ShadeNone );
+ }
+
+int Bridge::currentDesktop() const
+ {
+ return c->workspace()->currentDesktop();
+ }
+
+TQWidget* Bridge::initialParentWidget() const
+ {
+ return NULL;
+ }
+
+Qt::WFlags Bridge::initialWFlags() const
+ {
+ return 0;
+ }
+
+void Bridge::helperShowHide( bool show )
+ {
+ if( show )
+ c->rawShow();
+ else
+ c->rawHide();
+ }
+
+TQRegion Bridge::unobscuredRegion( const TQRegion& r ) const
+ {
+ TQRegion reg( r );
+ const ClientList stacking_order = c->workspace()->stackingOrder();
+ ClientList::ConstIterator it = stacking_order.find( c );
+ ++it;
+ for(;
+ it != stacking_order.end();
+ ++it )
+ {
+ if( !(*it)->isShown( true ))
+ continue; // these don't obscure the window
+ if( c->isOnAllDesktops())
+ {
+ if( !(*it)->isOnCurrentDesktop())
+ continue;
+ }
+ else
+ {
+ if( !(*it)->isOnDesktop( c->desktop()))
+ continue;
+ }
+ /* the clients all have their mask-regions in local coords
+ so we have to translate them to a shared coord system
+ we choose ours */
+ int dx = (*it)->x() - c->x();
+ int dy = (*it)->y() - c->y();
+ TQRegion creg = (*it)->mask();
+ creg.translate(dx, dy);
+ reg -= creg;
+ if (reg.isEmpty())
+ {
+ // early out, we are completely obscured
+ break;
+ }
+ }
+ return reg;
+ }
+
+void Bridge::grabXServer( bool grab )
+ {
+ if( grab )
+ KWinInternal::grabXServer();
+ else
+ KWinInternal::ungrabXServer();
+ }
+
+} // namespace
diff --git a/twin/bridge.h b/twin/bridge.h
new file mode 100644
index 00000000..0989a64b
--- /dev/null
+++ b/twin/bridge.h
@@ -0,0 +1,75 @@
+/*****************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+You can Freely distribute this program under the GNU General Public
+License. See the file "COPYING" for the exact licensing terms.
+******************************************************************/
+
+#ifndef KWIN_BRIDGE_H
+#define KWIN_BRIDGE_H
+
+#include <kdecoration_p.h>
+
+namespace KWinInternal
+{
+
+class Client;
+
+class Bridge : public KDecorationBridge
+ {
+ public:
+ Bridge( Client* cl );
+ virtual bool isActive() const;
+ virtual bool isCloseable() const;
+ virtual bool isMaximizable() const;
+ virtual MaximizeMode maximizeMode() const;
+ virtual bool isMinimizable() const;
+ virtual bool providesContextHelp() const;
+ virtual int desktop() const;
+ virtual bool isModal() const;
+ virtual bool isShadeable() const;
+ virtual bool isShade() const;
+ virtual bool isSetShade() const;
+ virtual bool keepAbove() const;
+ virtual bool keepBelow() const;
+ virtual bool isMovable() const;
+ virtual bool isResizable() const;
+ virtual NET::WindowType windowType( unsigned long supported_types ) const;
+ virtual TQIconSet icon() const;
+ virtual TQString caption() const;
+ virtual void processMousePressEvent( TQMouseEvent* );
+ virtual void showWindowMenu( TQPoint );
+ virtual void showWindowMenu( const TQRect & );
+ virtual void performWindowOperation( WindowOperation );
+ virtual void setMask( const TQRegion&, int );
+ virtual bool isPreview() const;
+ virtual TQRect geometry() const;
+ virtual TQRect iconGeometry() const;
+ virtual TQRegion unobscuredRegion( const TQRegion& r ) const;
+ virtual TQWidget* workspaceWidget() const;
+ virtual WId windowId() const;
+ virtual void closeWindow();
+ virtual void maximize( MaximizeMode mode );
+ virtual void minimize();
+ virtual void showContextHelp();
+ virtual void setDesktop( int desktop );
+ virtual void titlebarDblClickOperation();
+ virtual void titlebarMouseWheelOperation( int delta );
+ virtual void setShade( bool set );
+ virtual void setKeepAbove( bool );
+ virtual void setKeepBelow( bool );
+ virtual int currentDesktop() const;
+ virtual TQWidget* initialParentWidget() const;
+ virtual Qt::WFlags initialWFlags() const;
+ virtual void helperShowHide( bool show );
+ virtual void grabXServer( bool grab );
+ private:
+ Client* c;
+ };
+
+} // namespace
+
+#endif
diff --git a/twin/client.cpp b/twin/client.cpp
new file mode 100644
index 00000000..a5b5e808
--- /dev/null
+++ b/twin/client.cpp
@@ -0,0 +1,3078 @@
+/*****************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
+Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+You can Freely distribute this program under the GNU General Public
+License. See the file "COPYING" for the exact licensing terms.
+******************************************************************/
+
+#include "client.h"
+
+#include <math.h>
+
+#include <tqapplication.h>
+#include <tqpainter.h>
+#include <tqdatetime.h>
+#include <tqimage.h>
+#include <tqfile.h>
+#include <kprocess.h>
+#include <unistd.h>
+#include <kstandarddirs.h>
+#include <tqwhatsthis.h>
+#include <twin.h>
+#include <kiconloader.h>
+#include <tdelocale.h>
+#include <stdlib.h>
+
+#include "bridge.h"
+#include "group.h"
+#include "workspace.h"
+#include "atoms.h"
+#include "notifications.h"
+#include "rules.h"
+
+#include <X11/extensions/shape.h>
+
+// put all externs before the namespace statement to allow the linker
+// to resolve them properly
+
+extern Atom tqt_wm_state;
+extern Atom tqt_window_role;
+extern Atom tqt_sm_client_id;
+
+// wait 200 ms before drawing shadow after move/resize
+static const int SHADOW_DELAY = 200;
+
+namespace KWinInternal
+{
+
+/* TODO: Remove this once X has real translucency.
+ *
+ * A list of the regions covered by all shadows and the Clients to which they
+ * belong. Used to redraw shadows when a window overlapping or underlying a
+ * shadow is moved, resized, or hidden.
+ */
+struct ShadowRegion
+ {
+ TQRegion region;
+ Client *client;
+ };
+static TQValueList<ShadowRegion> shadowRegions;
+
+/*
+
+ Creating a client:
+ - only by calling Workspace::createClient()
+ - it creates a new client and calls manage() for it
+
+ Destroying a client:
+ - destroyClient() - only when the window itself has been destroyed
+ - releaseWindow() - the window is kept, only the client itself is destroyed
+
+*/
+
+
+/*!
+ \class Client client.h
+
+ \brief The Client class encapsulates a window decoration frame.
+
+*/
+
+/*!
+ This ctor is "dumb" - it only initializes data. All the real initialization
+ is done in manage().
+ */
+Client::Client( Workspace *ws )
+ : TQObject( NULL ),
+ client( None ),
+ wrapper( None ),
+ frame( None ),
+ decoration( NULL ),
+ wspace( ws ),
+ bridge( new Bridge( this )),
+ move_faked_activity( false ),
+ move_resize_grab_window( None ),
+ transient_for( NULL ),
+ transient_for_id( None ),
+ original_transient_for_id( None ),
+ in_group( NULL ),
+ window_group( None ),
+ in_layer( UnknownLayer ),
+ ping_timer( NULL ),
+ process_killer( NULL ),
+ process_resumer( NULL ),
+ user_time( CurrentTime ), // not known yet
+ allowed_actions( 0 ),
+ postpone_geometry_updates( 0 ),
+ pending_geometry_update( false ),
+ shade_geometry_change( false ),
+ border_left( 0 ),
+ border_right( 0 ),
+ border_top( 0 ),
+ border_bottom( 0 ),
+ opacity_( 0 ),
+ demandAttentionKNotifyTimer( NULL )
+// SELI do all as initialization
+ {
+ autoRaiseTimer = 0;
+ shadeHoverTimer = 0;
+
+ shadowDelayTimer = new TQTimer(this);
+ opacityCache = &activeOpacityCache;
+ shadowAfterClient = NULL;
+ shadowWidget = NULL;
+ shadowMe = true;
+ connect(shadowDelayTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawShadow()));
+
+ // set the initial mapping state
+ mapping_state = WithdrawnState;
+ desk = 0; // no desktop yet
+
+ mode = PositionCenter;
+ buttonDown = FALSE;
+ moveResizeMode = FALSE;
+
+ info = NULL;
+
+ shade_mode = ShadeNone;
+ active = FALSE;
+ deleting = false;
+ keep_above = FALSE;
+ keep_below = FALSE;
+ is_shape = FALSE;
+ motif_noborder = false;
+ motif_may_move = TRUE;
+ motif_may_resize = TRUE;
+ motif_may_close = TRUE;
+ fullscreen_mode = FullScreenNone;
+ skip_taskbar = FALSE;
+ original_skip_taskbar = false;
+ minimized = false;
+ hidden = false;
+ modal = false;
+ noborder = false;
+ user_noborder = false;
+ urgency = false;
+ ignore_focus_stealing = false;
+ demands_attention = false;
+ check_active_modal = false;
+
+ Pdeletewindow = 0;
+ Ptakefocus = 0;
+ Ptakeactivity = 0;
+ Pcontexthelp = 0;
+ Pping = 0;
+ input = FALSE;
+ skip_pager = FALSE;
+
+ max_mode = MaximizeRestore;
+ maxmode_restore = MaximizeRestore;
+
+ cmap = None;
+
+ frame_geometry = TQRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
+ client_size = TQSize( 100, 100 );
+ custom_opacity = false;
+ rule_opacity_active = 0; //translucency rules
+ rule_opacity_inactive = 0; //dito.
+
+ // SELI initialize xsizehints??
+ }
+
+/*!
+ "Dumb" destructor.
+ */
+Client::~Client()
+ {
+ assert(!moveResizeMode);
+ assert( client == None );
+ assert( frame == None && wrapper == None );
+ assert( decoration == NULL );
+ assert( postpone_geometry_updates == 0 );
+ assert( !check_active_modal );
+ delete info;
+ delete bridge;
+ }
+
+// use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
+void Client::deleteClient( Client* c, allowed_t )
+ {
+ delete c;
+ }
+
+/*!
+ Releases the window. The client has done its job and the window is still existing.
+ */
+void Client::releaseWindow( bool on_shutdown )
+ {
+ assert( !deleting );
+ deleting = true;
+ workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
+ StackingUpdatesBlocker blocker( workspace());
+ if (!custom_opacity) setOpacity(FALSE);
+ if (moveResizeMode)
+ leaveMoveResize();
+ removeShadow();
+ drawIntersectingShadows();
+ finishWindowRules();
+ ++postpone_geometry_updates;
+ // grab X during the release to make removing of properties, setting to withdrawn state
+ // and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2)
+ grabXServer();
+ setMappingState( WithdrawnState );
+ setModal( false ); // otherwise its mainwindow wouldn't get focus
+ hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
+ if( !on_shutdown )
+ workspace()->clientHidden( this );
+ XUnmapWindow( tqt_xdisplay(), frameId()); // destroying decoration would cause ugly visual effect
+ destroyDecoration();
+ cleanGrouping();
+ if( !on_shutdown )
+ {
+ workspace()->removeClient( this, Allowed );
+ // only when the window is being unmapped, not when closing down KWin
+ // (NETWM sections 5.5,5.7)
+ info->setDesktop( 0 );
+ desk = 0;
+ info->setState( 0, info->state()); // reset all state flags
+ }
+ XDeleteProperty( tqt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
+ XDeleteProperty( tqt_xdisplay(), client, atoms->net_frame_extents );
+ XDeleteProperty( tqt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
+ XReparentWindow( tqt_xdisplay(), client, workspace()->rootWin(), x(), y());
+ XRemoveFromSaveSet( tqt_xdisplay(), client );
+ XSelectInput( tqt_xdisplay(), client, NoEventMask );
+ if( on_shutdown )
+ { // map the window, so it can be found after another WM is started
+ XMapWindow( tqt_xdisplay(), client );
+ // TODO preserve minimized, shaded etc. state?
+ }
+ else
+ {
+ // Make sure it's not mapped if the app unmapped it (#65279). The app
+ // may do map+unmap before we initially map the window by calling rawShow() from manage().
+ XUnmapWindow( tqt_xdisplay(), client );
+ }
+ client = None;
+ XDestroyWindow( tqt_xdisplay(), wrapper );
+ wrapper = None;
+ XDestroyWindow( tqt_xdisplay(), frame );
+ frame = None;
+ --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
+ checkNonExistentClients();
+ deleteClient( this, Allowed );
+ ungrabXServer();
+ }
+
+// like releaseWindow(), but this one is called when the window has been already destroyed
+// (e.g. the application closed it)
+void Client::destroyClient()
+ {
+ assert( !deleting );
+ deleting = true;
+ workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
+ StackingUpdatesBlocker blocker( workspace());
+ if (moveResizeMode)
+ leaveMoveResize();
+ removeShadow();
+ drawIntersectingShadows();
+ finishWindowRules();
+ ++postpone_geometry_updates;
+ setModal( false );
+ hidden = true; // so that it's not considered visible anymore
+ workspace()->clientHidden( this );
+ destroyDecoration();
+ cleanGrouping();
+ workspace()->removeClient( this, Allowed );
+ client = None; // invalidate
+ XDestroyWindow( tqt_xdisplay(), wrapper );
+ wrapper = None;
+ XDestroyWindow( tqt_xdisplay(), frame );
+ frame = None;
+ --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
+ checkNonExistentClients();
+ deleteClient( this, Allowed );
+ }
+
+void Client::updateDecoration( bool check_workspace_pos, bool force )
+ {
+ if( !force && (( decoration == NULL && noBorder())
+ || ( decoration != NULL && !noBorder())))
+ return;
+ bool do_show = false;
+ postponeGeometryUpdates( true );
+ if( force )
+ destroyDecoration();
+ if( !noBorder())
+ {
+ setMask( TQRegion()); // reset shape mask
+ decoration = workspace()->createDecoration( bridge );
+ // TODO check decoration's minimum size?
+ decoration->init();
+ decoration->widget()->installEventFilter( this );
+ XReparentWindow( tqt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
+ decoration->widget()->lower();
+ decoration->borders( border_left, border_right, border_top, border_bottom );
+ options->onlyDecoTranslucent ?
+ setDecoHashProperty(border_top, border_right, border_bottom, border_left):
+ unsetDecoHashProperty();
+ int save_workarea_diff_x = workarea_diff_x;
+ int save_workarea_diff_y = workarea_diff_y;
+ move( calculateGravitation( false ));
+ plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
+ workarea_diff_x = save_workarea_diff_x;
+ workarea_diff_y = save_workarea_diff_y;
+ do_show = true;
+ }
+ else
+ destroyDecoration();
+ if( check_workspace_pos )
+ checkWorkspacePosition();
+ postponeGeometryUpdates( false );
+ if( do_show )
+ decoration->widget()->show();
+ updateFrameExtents();
+ updateOpacityCache();
+ }
+
+void Client::destroyDecoration()
+ {
+ if( decoration != NULL )
+ {
+ delete decoration;
+ decoration = NULL;
+ TQPoint grav = calculateGravitation( true );
+ border_left = border_right = border_top = border_bottom = 0;
+ setMask( TQRegion()); // reset shape mask
+ int save_workarea_diff_x = workarea_diff_x;
+ int save_workarea_diff_y = workarea_diff_y;
+ plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
+ move( grav );
+ workarea_diff_x = save_workarea_diff_x;
+ workarea_diff_y = save_workarea_diff_y;
+ }
+ }
+
+void Client::checkBorderSizes()
+ {
+ if( decoration == NULL )
+ return;
+ int new_left, new_right, new_top, new_bottom;
+ decoration->borders( new_left, new_right, new_top, new_bottom );
+ if( new_left == border_left && new_right == border_right
+ && new_top == border_top && new_bottom == border_bottom )
+ return;
+ GeometryUpdatesPostponer blocker( this );
+ move( calculateGravitation( true ));
+ border_left = new_left;
+ border_right = new_right;
+ border_top = new_top;
+ border_bottom = new_bottom;
+ if (border_left != new_left ||
+ border_right != new_right ||
+ border_top != new_top ||
+ border_bottom != new_bottom)
+ options->onlyDecoTranslucent ?
+ setDecoHashProperty(new_top, new_right, new_bottom, new_left):
+ unsetDecoHashProperty();
+ move( calculateGravitation( false ));
+ plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
+ checkWorkspacePosition();
+ }
+
+void Client::detectNoBorder()
+ {
+ if( Shape::hasShape( window()))
+ {
+ noborder = true;
+ return;
+ }
+ switch( windowType())
+ {
+ case NET::Desktop :
+ case NET::Dock :
+ case NET::TopMenu :
+ case NET::Splash :
+ noborder = true;
+ break;
+ case NET::Unknown :
+ case NET::Normal :
+ case NET::Toolbar :
+ case NET::Menu :
+ case NET::Dialog :
+ case NET::Utility :
+ noborder = false;
+ break;
+ default:
+ assert( false );
+ }
+ // NET::Override is some strange beast without clear definition, usually
+ // just meaning "noborder", so let's treat it only as such flag, and ignore it as
+ // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
+ if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
+ noborder = true;
+ }
+
+void Client::detectShapable()
+ {
+ if( Shape::hasShape( window()))
+ return;
+ switch( windowType())
+ {
+ case NET::Desktop :
+ case NET::Dock :
+ case NET::TopMenu :
+ case NET::Splash :
+ break;
+ case NET::Unknown :
+ case NET::Normal :
+ case NET::Toolbar :
+ case NET::Menu :
+ case NET::Dialog :
+ case NET::Utility :
+ setShapable(FALSE);
+ break;
+ default:
+ assert( false );
+ }
+ }
+
+void Client::updateFrameExtents()
+ {
+ NETStrut strut;
+ strut.left = border_left;
+ strut.right = border_right;
+ strut.top = border_top;
+ strut.bottom = border_bottom;
+ info->setFrameExtents( strut );
+ }
+
+// Resizes the decoration, and makes sure the decoration widget gets resize event
+// even if the size hasn't changed. This is needed to make sure the decoration
+// re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
+// the decoration may turn on/off some borders, but the actual size
+// of the decoration stays the same).
+void Client::resizeDecoration( const TQSize& s )
+ {
+ if( decoration == NULL )
+ return;
+ TQSize oldsize = decoration->widget()->size();
+ decoration->resize( s );
+ if( oldsize == s )
+ {
+ TQResizeEvent e( s, oldsize );
+ TQApplication::sendEvent( decoration->widget(), &e );
+ }
+ if (!moveResizeMode && options->shadowEnabled(isActive()))
+ {
+ // If the user is manually resizing, let Client::leaveMoveResize()
+ // decide when to redraw the shadow
+ updateOpacityCache();
+ }
+ }
+
+bool Client::noBorder() const
+ {
+ return noborder || isFullScreen() || user_noborder || motif_noborder;
+ }
+
+bool Client::userCanSetNoBorder() const
+ {
+ return !noborder && !isFullScreen() && !isShade();
+ }
+
+bool Client::isUserNoBorder() const
+ {
+ return user_noborder;
+ }
+
+void Client::setUserNoBorder( bool set )
+ {
+ if( !userCanSetNoBorder())
+ return;
+ set = rules()->checkNoBorder( set );
+ if( user_noborder == set )
+ return;
+ user_noborder = set;
+ updateDecoration( true, false );
+ updateWindowRules();
+ }
+
+bool Client::isModalSystemNotification() const
+ {
+ unsigned char *data = 0;
+ Atom actual;
+ int format, result;
+ unsigned long n, left;
+ result = XGetWindowProperty(tqt_xdisplay(), window(), atoms->net_wm_system_modal_notification, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
+ if (result == Success && data != None && format == 32 )
+ {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+void Client::updateShape()
+ {
+ // workaround for #19644 - shaped windows shouldn't have decoration
+ if( shape() && !noBorder())
+ {
+ noborder = true;
+ updateDecoration( true );
+ }
+ updateOpacityCache();
+ if ( shape() )
+ {
+ XShapeCombineShape(tqt_xdisplay(), frameId(), ShapeBounding,
+ clientPos().x(), clientPos().y(),
+ window(), ShapeBounding, ShapeSet);
+ setShapable(TRUE);
+ }
+ // !shape() mask setting is done in setMask() when the decoration
+ // calls it or when the decoration is created/destroyed
+
+ if( Shape::version() >= 0x11 ) // 1.1, has input shape support
+ { // There appears to be no way to find out if a window has input
+ // shape set or not, so always propagate the input shape
+ // (it's the same like the bounding shape by default).
+ // Also, build the shape using a helper window, not directly
+ // in the frame window, because the sequence set-shape-to-frame,
+ // remove-shape-of-client, add-input-shape-of-client has the problem
+ // that after the second step there's a hole in the input shape
+ // until the real shape of the client is added and that can make
+ // the window lose focus (which is a problem with mouse focus policies)
+ static Window helper_window = None;
+ if( helper_window == None )
+ helper_window = XCreateSimpleWindow( tqt_xdisplay(), tqt_xrootwin(),
+ 0, 0, 1, 1, 0, 0, 0 );
+ XResizeWindow( tqt_xdisplay(), helper_window, width(), height());
+ XShapeCombineShape( tqt_xdisplay(), helper_window, ShapeInput, 0, 0,
+ frameId(), ShapeBounding, ShapeSet );
+ XShapeCombineShape( tqt_xdisplay(), helper_window, ShapeInput,
+ clientPos().x(), clientPos().y(),
+ window(), ShapeBounding, ShapeSubtract );
+ XShapeCombineShape( tqt_xdisplay(), helper_window, ShapeInput,
+ clientPos().x(), clientPos().y(),
+ window(), ShapeInput, ShapeUnion );
+ XShapeCombineShape( tqt_xdisplay(), frameId(), ShapeInput, 0, 0,
+ helper_window, ShapeInput, ShapeSet );
+ }
+ }
+
+void Client::setMask( const TQRegion& reg, int mode )
+ {
+ _mask = reg;
+ if( reg.isNull())
+ XShapeCombineMask( tqt_xdisplay(), frameId(), ShapeBounding, 0, 0,
+ None, ShapeSet );
+ else if( mode == X::Unsorted )
+ XShapeCombineRegion( tqt_xdisplay(), frameId(), ShapeBounding, 0, 0,
+ reg.handle(), ShapeSet );
+ else
+ {
+ TQMemArray< TQRect > rects = reg.rects();
+ XRectangle* xrects = new XRectangle[ rects.count() ];
+ for( unsigned int i = 0;
+ i < rects.count();
+ ++i )
+ {
+ xrects[ i ].x = rects[ i ].x();
+ xrects[ i ].y = rects[ i ].y();
+ xrects[ i ].width = rects[ i ].width();
+ xrects[ i ].height = rects[ i ].height();
+ }
+ XShapeCombineRectangles( tqt_xdisplay(), frameId(), ShapeBounding, 0, 0,
+ xrects, rects.count(), ShapeSet, mode );
+ delete[] xrects;
+ }
+ updateShape();
+ }
+
+TQRegion Client::mask() const
+ {
+ if( _mask.isEmpty())
+ return TQRegion( 0, 0, width(), height());
+ return _mask;
+ }
+
+void Client::setShapable(bool b)
+ {
+ long tmp = b?1:0;
+ XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
+ }
+
+void Client::hideClient( bool hide )
+ {
+ if( hidden == hide )
+ return;
+ hidden = hide;
+ updateVisibility();
+ }
+
+/*!
+ Returns whether the window is minimizable or not
+ */
+bool Client::isMinimizable() const
+ {
+ if( isSpecialWindow())
+ return false;
+ if( isModalSystemNotification())
+ return false;
+ if( isTransient())
+ { // #66868 - let other xmms windows be minimized when the mainwindow is minimized
+ bool shown_mainwindow = false;
+ ClientList mainclients = mainClients();
+ for( ClientList::ConstIterator it = mainclients.begin();
+ it != mainclients.end();
+ ++it )
+ {
+ if( (*it)->isShown( true ))
+ shown_mainwindow = true;
+ }
+ if( !shown_mainwindow )
+ return true;
+ }
+ // this is here because kicker's taskbar doesn't provide separate entries
+ // for windows with an explicitly given parent
+ // TODO perhaps this should be redone
+ if( transientFor() != NULL )
+ return false;
+ if( !wantsTabFocus()) // SELI - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
+ return false;
+ return true;
+ }
+
+/*!
+ Returns whether the window is kept above or not
+ */
+bool Client::keepAbove() const
+ {
+ if( isModalSystemNotification())
+ return true;
+ return keep_above;
+ }
+
+/*!
+ Minimizes this client plus its transients
+ */
+void Client::minimize( bool avoid_animation )
+ {
+ if ( !isMinimizable() || isMinimized())
+ return;
+
+ if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
+ info->setState(0, NET::Shaded);
+
+ Notify::raise( Notify::Minimize );
+
+ // SELI mainClients().isEmpty() ??? - and in unminimize() too
+ if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
+ animateMinimizeOrUnminimize( true ); // was visible or shaded
+
+ minimized = true;
+
+ updateVisibility();
+ updateAllowedActions();
+ workspace()->updateMinimizedOfTransients( this );
+ updateWindowRules();
+ workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
+ }
+
+void Client::unminimize( bool avoid_animation )
+ {
+ if (!queryUserSuspendedResume())
+ return;
+
+ if( !isMinimized())
+ return;
+
+ if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
+ info->setState(NET::Shaded, NET::Shaded);
+
+ Notify::raise( Notify::UnMinimize );
+ minimized = false;
+ if( isOnCurrentDesktop() && isShown( true ))
+ {
+ if( mainClients().isEmpty() && !avoid_animation )
+ animateMinimizeOrUnminimize( FALSE );
+ }
+ updateVisibility();
+ updateAllowedActions();
+ workspace()->updateMinimizedOfTransients( this );
+ updateWindowRules();
+ }
+
+extern bool blockAnimation;
+
+void Client::animateMinimizeOrUnminimize( bool minimize )
+ {
+ if ( blockAnimation )
+ return;
+ if ( !options->animateMinimize )
+ return;
+
+ if( decoration != NULL && decoration->animateMinimize( minimize ))
+ return; // decoration did it
+
+ // the function is a bit tricky since it will ensure that an
+ // animation action needs always the same time regardless of the
+ // performance of the machine or the X-Server.
+
+ float lf,rf,tf,bf,step;
+
+ int speed = options->animateMinimizeSpeed;
+ if ( speed > 10 )
+ speed = 10;
+ if ( speed < 0 )
+ speed = 0;
+
+ step = 40. * (11 - speed );
+
+ NETRect r = info->iconGeometry();
+ TQRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
+ if ( !icongeom.isValid() )
+ return;
+
+ TQPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
+
+ TQRect before, after;
+ if ( minimize )
+ {
+ before = TQRect( x(), y(), width(), pm.height() );
+ after = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
+ }
+ else
+ {
+ before = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
+ after = TQRect( x(), y(), width(), pm.height() );
+ }
+
+ lf = (after.left() - before.left())/step;
+ rf = (after.right() - before.right())/step;
+ tf = (after.top() - before.top())/step;
+ bf = (after.bottom() - before.bottom())/step;
+
+ grabXServer();
+
+ TQRect area = before;
+ TQRect area2;
+ TQPixmap pm2;
+
+ TQTime t;
+ t.start();
+ float diff;
+
+ TQPainter p ( workspace()->desktopWidget() );
+ bool need_to_clear = FALSE;
+ TQPixmap pm3;
+ do
+ {
+ if (area2 != area)
+ {
+ pm = animationPixmap( area.width() );
+ pm2 = TQPixmap::grabWindow( tqt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
+ p.drawPixmap( area.x(), area.y(), pm );
+ if ( need_to_clear )
+ {
+ p.drawPixmap( area2.x(), area2.y(), pm3 );
+ need_to_clear = FALSE;
+ }
+ area2 = area;
+ }
+ XFlush(tqt_xdisplay());
+ XSync( tqt_xdisplay(), FALSE );
+ diff = t.elapsed();
+ if (diff > step)
+ diff = step;
+ area.setLeft(before.left() + int(diff*lf));
+ area.setRight(before.right() + int(diff*rf));
+ area.setTop(before.top() + int(diff*tf));
+ area.setBottom(before.bottom() + int(diff*bf));
+ if (area2 != area )
+ {
+ if ( area2.intersects( area ) )
+ p.drawPixmap( area2.x(), area2.y(), pm2 );
+ else
+ { // no overlap, we can clear later to avoid flicker
+ pm3 = pm2;
+ need_to_clear = TRUE;
+ }
+ }
+ } while ( t.elapsed() < step);
+ if (area2 == area || need_to_clear )
+ p.drawPixmap( area2.x(), area2.y(), pm2 );
+
+ p.end();
+ ungrabXServer();
+ }
+
+
+/*!
+ The pixmap shown during (un)minimalization animation
+ */
+TQPixmap Client::animationPixmap( int w )
+ {
+ TQFont font = options->font(isActive());
+ TQFontMetrics fm( font );
+ TQPixmap pm( w, fm.lineSpacing() );
+ pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
+ TQPainter p( &pm );
+ p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
+ p.setFont(options->font(isActive()));
+ p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
+ return pm;
+ }
+
+
+bool Client::isShadeable() const
+ {
+ return !isSpecialWindow() && !noBorder();
+ }
+
+void Client::setShade( ShadeMode mode )
+ {
+ if( !isShadeable())
+ return;
+ if( isModalSystemNotification())
+ return;
+ mode = rules()->checkShade( mode );
+ if( shade_mode == mode )
+ return;
+ bool was_shade = isShade();
+ ShadeMode was_shade_mode = shade_mode;
+ shade_mode = mode;
+ if( was_shade == isShade())
+ {
+ if( decoration != NULL ) // decoration may want to update after e.g. hover-shade changes
+ decoration->shadeChange();
+ return; // no real change in shaded state
+ }
+
+ if( shade_mode == ShadeNormal )
+ {
+ if ( isShown( true ) && isOnCurrentDesktop())
+ Notify::raise( Notify::ShadeUp );
+ }
+ else if( shade_mode == ShadeNone )
+ {
+ if( isShown( true ) && isOnCurrentDesktop())
+ Notify::raise( Notify::ShadeDown );
+ }
+
+ assert( decoration != NULL ); // noborder windows can't be shaded
+ GeometryUpdatesPostponer blocker( this );
+ // decorations may turn off some borders when shaded
+ decoration->borders( border_left, border_right, border_top, border_bottom );
+
+ int as = options->animateShade? 10 : 1;
+// TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
+ if ( isShade())
+ { // shade_mode == ShadeNormal
+ // we're about to shade, texx xcompmgr to prepare
+ long _shade = 1;
+ XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
+ // shade
+ int h = height();
+ shade_geometry_change = true;
+ TQSize s( sizeForClientSize( TQSize( clientSize())));
+ s.setHeight( border_top + border_bottom );
+ XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
+ XUnmapWindow( tqt_xdisplay(), wrapper );
+ XUnmapWindow( tqt_xdisplay(), client );
+ XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
+ //as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
+ //done xcompmgr workaround
+// FRAME repaint( FALSE );
+// bool wasStaticContents = testWFlags( WStaticContents );
+// setWFlags( WStaticContents );
+ int step = TQMAX( 4, QABS( h - s.height() ) / as )+1;
+ do
+ {
+ h -= step;
+ XResizeWindow( tqt_xdisplay(), frameId(), s.width(), h );
+ resizeDecoration( TQSize( s.width(), h ));
+ TQApplication::syncX();
+ } while ( h > s.height() + step );
+// if ( !wasStaticContents )
+// clearWFlags( WStaticContents );
+ plainResize( s );
+ shade_geometry_change = false;
+ if( isActive())
+ {
+ if( was_shade_mode == ShadeHover )
+ workspace()->activateNextClient( this );
+ else
+ workspace()->focusToNull();
+ }
+ // tell xcompmgr shade's done
+ _shade = 2;
+ XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
+ }
+ else
+ {
+ int h = height();
+ shade_geometry_change = true;
+ TQSize s( sizeForClientSize( clientSize()));
+// FRAME bool wasStaticContents = testWFlags( WStaticContents );
+// setWFlags( WStaticContents );
+ int step = TQMAX( 4, QABS( h - s.height() ) / as )+1;
+ do
+ {
+ h += step;
+ XResizeWindow( tqt_xdisplay(), frameId(), s.width(), h );
+ resizeDecoration( TQSize( s.width(), h ));
+ // assume a border
+ // we do not have time to wait for X to send us paint events
+// FRAME repaint( 0, h - step-5, width(), step+5, TRUE);
+ TQApplication::syncX();
+ } while ( h < s.height() - step );
+// if ( !wasStaticContents )
+// clearWFlags( WStaticContents );
+ shade_geometry_change = false;
+ plainResize( s );
+ if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
+ setActive( TRUE );
+ XMapWindow( tqt_xdisplay(), wrapperId());
+ XMapWindow( tqt_xdisplay(), window());
+ XDeleteProperty (tqt_xdisplay(), client, atoms->net_wm_window_shade);
+ if (options->shadowEnabled(false))
+ {
+ for (ClientList::ConstIterator it = transients().begin();
+ it != transients().end(); ++it)
+ {
+ (*it)->removeShadow();
+ (*it)->drawDelayedShadow();
+ }
+ }
+
+ if ( isActive() )
+ workspace()->requestFocus( this );
+ }
+ checkMaximizeGeometry();
+ info->setState( (isShade() && !isMinimized()) ? NET::Shaded : 0, NET::Shaded );
+ info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
+ updateVisibility();
+ updateAllowedActions();
+ workspace()->updateMinimizedOfTransients( this );
+ decoration->shadeChange();
+ updateWindowRules();
+ }
+
+void Client::shadeHover()
+ {
+ setShade( ShadeHover );
+ cancelShadeHover();
+ }
+
+void Client::cancelShadeHover()
+ {
+ delete shadeHoverTimer;
+ shadeHoverTimer = 0;
+ }
+
+void Client::toggleShade()
+ {
+ // if the mode is ShadeHover or ShadeActive, cancel shade too
+ setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
+ }
+
+void Client::updateVisibility()
+ {
+ if( deleting )
+ return;
+ bool show = true;
+ if( hidden )
+ {
+ setMappingState( IconicState );
+ info->setState( NET::Hidden, NET::Hidden );
+ setSkipTaskbar( true, false ); // also hide from taskbar
+ rawHide();
+ show = false;
+ }
+ else
+ {
+ setSkipTaskbar( original_skip_taskbar, false );
+ }
+ if( minimized )
+ {
+ setMappingState( IconicState );
+ info->setState( NET::Hidden, NET::Hidden );
+ rawHide();
+ show = false;
+ }
+ if( show )
+ info->setState( 0, NET::Hidden );
+ if( !isOnCurrentDesktop())
+ {
+ setMappingState( IconicState );
+ rawHide();
+ show = false;
+ }
+ if( show )
+ {
+ bool belongs_to_desktop = false;
+ for( ClientList::ConstIterator it = group()->members().begin();
+ it != group()->members().end();
+ ++it )
+ if( (*it)->isDesktop())
+ {
+ belongs_to_desktop = true;
+ break;
+ }
+ if( !belongs_to_desktop && workspace()->showingDesktop())
+ workspace()->resetShowingDesktop( true );
+ if( isShade())
+ setMappingState( IconicState );
+ else
+ setMappingState( NormalState );
+ rawShow();
+ }
+ }
+
+void Client::setShadowed(bool shadowed)
+{
+ bool wasShadowed;
+
+ wasShadowed = isShadowed();
+ shadowMe = options->shadowEnabled(isActive()) ? shadowed : false;
+
+ if (shadowMe) {
+ if (!wasShadowed)
+ drawShadow();
+ }
+ else {
+ if (wasShadowed) {
+ removeShadow();
+
+ if (!activeOpacityCache.isNull())
+ activeOpacityCache.resize(0);
+ if (!inactiveOpacityCache.isNull())
+ inactiveOpacityCache.resize(0);
+ }
+ }
+}
+
+void Client::updateOpacityCache()
+{
+ if (!activeOpacityCache.isNull())
+ activeOpacityCache.resize(0);
+ if (!inactiveOpacityCache.isNull())
+ inactiveOpacityCache.resize(0);
+
+ if (!moveResizeMode) {
+ // If the user is manually resizing, let Client::finishMoveResize()
+ // decide when to redraw the shadow
+ removeShadow();
+ drawIntersectingShadows();
+ if (options->shadowEnabled(isActive()))
+ drawDelayedShadow();
+ }
+}
+
+/*!
+ Redraw shadows that were previously occluding or occluded by this window,
+ to avoid visual glitches.
+ */
+void Client::drawIntersectingShadows() {
+ //Client *reshadowClient;
+ TQRegion region;
+ //TQPtrList<Client> reshadowClients;
+ TQValueList<Client *> reshadowClients;
+ TQValueListIterator<ShadowRegion> it;
+ TQValueListIterator<Client *> it2;
+
+ if (!options->shadowEnabled(false))
+ // No point in redrawing overlapping/overlapped shadows if only the
+ // active window has a shadow.
+ return;
+
+ region = shapeBoundingRegion;
+
+ // Generate list of Clients whose shadows need to be redrawn. That is,
+ // those that are currently intersecting or intersected by other windows or
+ // shadows.
+ for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
+ if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) &&
+ !(*it).region.intersect(region).isEmpty())
+ reshadowClients.append((*it).client);
+
+ // Redraw shadows for each of the Clients in the list generated above
+ for (it2 = reshadowClients.begin(); it2 != reshadowClients.end();
+ ++it2) {
+ (*it2)->removeShadow();
+ (*it2)->drawDelayedShadow();
+ }
+}
+
+/*!
+ Redraw shadows that are above the current window in the stacking order.
+ Furthermore, redraw them in the same order as they come in the stacking order
+ from bottom to top.
+ */
+void Client::drawOverlappingShadows(bool waitForMe)
+{
+ Client *aClient;
+ TQRegion region;
+ TQValueList<Client *> reshadowClients;
+ ClientList stacking_order;
+ ClientList::ConstIterator it;
+ TQValueListIterator<ShadowRegion> it2;
+ TQValueListIterator<Client *> it3;
+
+ if (!options->shadowEnabled(false))
+ // No point in redrawing overlapping/overlapped shadows if only the
+ // active window has a shadow.
+ return;
+
+ region = shapeBoundingRegion;
+
+ stacking_order = workspace()->stackingOrder();
+ for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
+ // Find the position of this window in the stacking order.
+ if ((*it) == this)
+ break;
+ }
+ ++it;
+ while (it != stacking_order.end()) {
+ if ((*it)->windowType() == NET::Dock) {
+ // This function is only interested in windows whose shadows don't
+ // have weird stacking rules.
+ ++it;
+ continue;
+ }
+
+ // Generate list of Clients whose shadows need to be redrawn. That is,
+ // those that are currently overlapping or overlapped by other windows
+ // or shadows. The list should be in order from bottom to top in the
+ // stacking order.
+ for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) {
+ if ((*it2).client == (*it)) {
+ if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop())
+ && !(*it2).region.intersect(region).isEmpty())
+ reshadowClients.append((*it2).client);
+ }
+ }
+ ++it;
+ }
+
+ // Redraw shadows for each of the Clients in the list generated above
+ for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) {
+ (*it3)->removeShadow();
+ if (it3 == reshadowClients.begin()) {
+ if (waitForMe)
+ (*it3)->drawShadowAfter(this);
+ else
+ (*it3)->drawDelayedShadow();
+ }
+ else {
+ --it3;
+ aClient = (*it3);
+ ++it3;
+ (*it3)->drawShadowAfter(aClient);
+ }
+ }
+}
+
+/*!
+ Draw shadow after some time has elapsed, to give recently exposed windows a
+ chance to repaint before a shadow gradient is drawn over them.
+ */
+void Client::drawDelayedShadow()
+{
+ shadowDelayTimer->stop();
+ shadowDelayTimer->start(SHADOW_DELAY, true);
+}
+
+/*!
+ Draw shadow immediately after the specified Client's shadow finishes drawing.
+ */
+void Client::drawShadowAfter(Client *after)
+{
+ shadowAfterClient = after;
+ connect(after, TQT_SIGNAL(shadowDrawn()), TQT_SLOT(drawShadow()));
+}
+
+/*!
+ Draw a shadow under this window and XShape the shadow accordingly.
+ */
+void Client::drawShadow()
+{
+ Window shadows[2];
+ XRectangle *shapes;
+ int i, count, ordering;
+
+ // If we are waiting for another Client's shadow to be drawn, stop waiting now
+ if (shadowAfterClient != NULL) {
+ disconnect(shadowAfterClient, TQT_SIGNAL(shadowDrawn()), this, TQT_SLOT(drawShadow()));
+ shadowAfterClient = NULL;
+ }
+
+ if (!isOnCurrentDesktop())
+ return;
+
+ /* Store this window's ShapeBoundingRegion even if shadows aren't drawn for
+ * this type of window. Otherwise, drawIntersectingShadows() won't update
+ * properly when this window is moved/resized/hidden/closed.
+ */
+ shapes = XShapeGetRectangles(tqt_xdisplay(), frameId(), ShapeBounding,
+ &count, &ordering);
+ if (!shapes)
+ // XShape extension not supported
+ shapeBoundingRegion = TQRegion(x(), y(), width(), height());
+ else {
+ shapeBoundingRegion = TQRegion();
+ for (i = 0; i < count; i++) {
+ // Translate XShaped window into a TQRegion
+ TQRegion shapeRectangle(shapes[i].x, shapes[i].y, shapes[i].width,
+ shapes[i].height);
+ shapeBoundingRegion += shapeRectangle;
+ }
+ if (isShade())
+ // Since XResize() doesn't change a window's XShape regions, ensure that
+ // shapeBoundingRegion is not taller than the window's shaded height,
+ // or the bottom shadow will appear to be missing
+ shapeBoundingRegion &= TQRegion(0, 0, width(), height());
+ shapeBoundingRegion.translate(x(), y());
+ }
+
+ if (!isShadowed() || hidden || isMinimized() ||
+ maximizeMode() == MaximizeFull ||
+ !options->shadowWindowType(windowType())) {
+ XFree(shapes);
+
+ // Tell whatever Clients are listening that this Client's shadow has been drawn.
+ // It hasn't, but there's no sense waiting for something that won't happen.
+ emit shadowDrawn();
+
+ return;
+ }
+
+ removeShadow();
+
+ TQMemArray<QRgb> pixelData;
+ TQPixmap shadowPixmap;
+ TQRect shadow;
+ TQRegion exposedRegion;
+ ShadowRegion shadowRegion;
+ int thickness, xOffset, yOffset;
+
+ thickness = options->shadowThickness(isActive());
+ xOffset = options->shadowXOffset(isActive());
+ yOffset = options->shadowYOffset(isActive());
+ opacityCache = active? &activeOpacityCache : &inactiveOpacityCache;
+
+ shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset,
+ width() + thickness * 2, height() + thickness * 2);
+ shadowPixmap.resize(shadow.size());
+
+ // Create a fake drop-down shadow effect via blended Xwindows
+ shadowWidget = new TQWidget(0, 0, (WFlags)(WStyle_Customize | WX11BypassWM));
+ shadowWidget->setGeometry(shadow);
+ XSelectInput(tqt_xdisplay(), shadowWidget->winId(),
+ ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
+ shadowWidget->installEventFilter(this);
+
+ if (!shapes) {
+ // XShape extension not supported
+ exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
+ shadow.y(), shadow.width(), shadow.height(), thickness,
+ xOffset, yOffset);
+ shadowRegion.region = exposedRegion;
+ shadowRegion.client = this;
+ shadowRegions.append(shadowRegion);
+
+ if (opacityCache->isNull())
+ imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
+ exposedRegion, thickness,
+ options->shadowOpacity(isActive()));
+ else
+ imposeCachedShadow(shadowPixmap, exposedRegion);
+ }
+ else {
+ TQMemArray<TQRect> exposedRects;
+ TQMemArray<TQRect>::Iterator it, itEnd;
+ XRectangle *shadowShapes;
+
+ exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
+ shadow.y(), shadow.width(), shadow.height(), thickness,
+ xOffset, yOffset);
+ shadowRegion.region = exposedRegion;
+ shadowRegion.client = this;
+ shadowRegions.append(shadowRegion);
+
+ // XShape the shadow
+ exposedRects = exposedRegion.rects();
+ i = 0;
+ itEnd = exposedRects.end();
+ shadowShapes = new XRectangle[exposedRects.count()];
+ for (it = exposedRects.begin(); it != itEnd; ++it) {
+ shadowShapes[i].x = (*it).x();
+ shadowShapes[i].y = (*it).y();
+ shadowShapes[i].width = (*it).width();
+ shadowShapes[i].height = (*it).height();
+ i++;
+ }
+ XShapeCombineRectangles(tqt_xdisplay(), shadowWidget->winId(),
+ ShapeBounding, -x() + thickness - xOffset,
+ -y() + thickness - yOffset, shadowShapes, i, ShapeSet,
+ Unsorted);
+ delete [] shadowShapes;
+
+ if (opacityCache->isNull())
+ imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
+ exposedRegion, thickness,
+ options->shadowOpacity(isActive()));
+ else
+ imposeCachedShadow(shadowPixmap, exposedRegion);
+ }
+
+ XFree(shapes);
+
+ // Set the background pixmap
+ //shadowPixmap.convertFromImage(shadowImage);
+ shadowWidget->setErasePixmap(shadowPixmap);
+
+ // Restack shadows under this window so that shadows drawn for a newly
+ // focused (but not raised) window don't overlap any windows above it.
+ if (isDock()) {
+ ClientList stacking_order = workspace()->stackingOrder();
+ for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
+ if ((*it)->isDesktop())
+ {
+ ++it;
+ shadows[0] = (*it)->frameId();
+ shadows[1] = shadowWidget->winId();
+ }
+ }
+ else {
+ shadows[0] = frameId();
+ if (shadowWidget != NULL)
+ shadows[1] = shadowWidget->winId();
+ }
+
+ XRestackWindows(tqt_xdisplay(), shadows, 2);
+
+ // Don't use TQWidget::show() so we don't confuse QEffects, thus causing
+ // broken focus.
+ XMapWindow(tqt_xdisplay(), shadowWidget->winId());
+
+ // Tell whatever Clients are listening that this Client's shadow has been drawn.
+ emit shadowDrawn();
+}
+
+/*!
+ Remove shadow under this window.
+ */
+void Client::removeShadow()
+{
+ TQValueList<ShadowRegion>::Iterator it;
+
+ shadowDelayTimer->stop();
+
+ if (shadowWidget != NULL) {
+ for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
+ if ((*it).client == this) {
+ shadowRegions.remove(it);
+ break;
+ }
+ delete shadowWidget;
+ shadowWidget = NULL;
+ }
+}
+
+/*!
+ Calculate regions in which the shadow will be visible given the window's
+ origin, height and width and the shadow's thickness, and X- and Y-offsets.
+ */
+TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w,
+ int h, int thickness, int xOffset, int yOffset)
+{
+ TQRegion exposedRegion;
+
+ exposedRegion = TQRegion(x, y, w, h);
+ exposedRegion -= occludedRegion;
+
+ if (thickness > 0) {
+ // Limit exposedRegion to include only where a shadow of the specified
+ // thickness will be drawn
+ TQMemArray<TQRect> occludedRects;
+ TQMemArray<TQRect>::Iterator it, itEnd;
+ TQRegion shadowRegion;
+
+ occludedRects = occludedRegion.rects();
+ itEnd = occludedRects.end();
+ for (it = occludedRects.begin(); it != itEnd; ++it) {
+ // Expand each of the occluded region's shape rectangles to contain
+ // where a shadow of the specified thickness will be drawn. Create
+ // a new TQRegion that contains the expanded occluded region
+ it->setTop(it->top() - thickness + yOffset);
+ it->setLeft(it->left() - thickness + xOffset);
+ it->setRight(it->right() + thickness + xOffset);
+ it->setBottom(it->bottom() + thickness + yOffset);
+ shadowRegion += TQRegion(*it);
+ }
+ exposedRegion -= exposedRegion - shadowRegion;
+ }
+
+ return exposedRegion;
+}
+
+/*!
+ Draw shadow gradient around this window using cached opacity values.
+ */
+void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed)
+{
+ QRgb pixel;
+ double opacity;
+ int red, green, blue, pixelRed, pixelGreen, pixelBlue;
+ int subW, subH, w, h, x, y, zeroX, zeroY;
+ TQImage image;
+ TQMemArray<TQRect>::Iterator it, itEnd;
+ TQMemArray<TQRect> rectangles;
+ TQPixmap subPixmap;
+ Window rootWindow;
+ int thickness, windowX, windowY, xOffset, yOffset;
+
+ rectangles = exposed.rects();
+ rootWindow = tqt_xrootwin();
+ thickness = options->shadowThickness(isActive());
+ windowX = this->x();
+ windowY = this->y();
+ xOffset = options->shadowXOffset(isActive());
+ yOffset = options->shadowYOffset(isActive());
+ options->shadowColour(isActive()).rgb(&red, &green, &blue);
+ w = pixmap.width();
+ h = pixmap.height();
+
+ itEnd = rectangles.end();
+ for (it = rectangles.begin(); it != itEnd; ++it) {
+ subW = (*it).width();
+ subH = (*it).height();
+ subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
+ subW, subH);
+ zeroX = (*it).x() - windowX + thickness - xOffset;
+ zeroY = (*it).y() - windowY + thickness - yOffset;
+ image = subPixmap.convertToImage();
+
+ for (x = 0; x < subW; x++) {
+ for (y = 0; y < subH; y++) {
+ opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x];
+ pixel = image.pixel(x, y);
+ pixelRed = tqRed(pixel);
+ pixelGreen = tqGreen(pixel);
+ pixelBlue = tqBlue(pixel);
+ image.setPixel(x, y,
+ tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
+ (int)(pixelGreen + (green - pixelGreen) * opacity),
+ (int)(pixelBlue + (blue - pixelBlue) * opacity)));
+ }
+ }
+
+ subPixmap.convertFromImage(image);
+ bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
+ }
+}
+
+/*!
+ Draw shadow around this window using calculated opacity values.
+ */
+void Client::imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded,
+ TQRegion exposed, int thickness, double maxOpacity)
+{
+ register int distance, intersectCount, i, j, x, y;
+ QRgb pixel;
+ double decay, factor, opacity;
+ int red, green, blue, pixelRed, pixelGreen, pixelBlue;
+ int halfMaxIntersects, lineIntersects, maxIntersects, maxY;
+ int irBottom, irLeft, irRight, irTop, yIncrement;
+ int subW, subH, w, h, zeroX, zeroY;
+ TQImage image;
+ TQMemArray<TQRect>::Iterator it, itEnd;
+ TQMemArray<TQRect> rectangles;
+ TQPixmap subPixmap;
+ Window rootWindow;
+ int windowX, windowY, xOffset, yOffset;
+
+ rectangles = exposed.rects();
+ rootWindow = tqt_xrootwin();
+ windowX = this->x();
+ windowY = this->y();
+ xOffset = options->shadowXOffset(isActive());
+ yOffset = options->shadowYOffset(isActive());
+ options->shadowColour(isActive()).rgb(&red, &green, &blue);
+ maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1;
+ halfMaxIntersects = maxIntersects / 2;
+ lineIntersects = thickness * 2 + 1;
+ factor = maxIntersects / maxOpacity;
+ decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0);
+ w = pixmap.width();
+ h = pixmap.height();
+ xOffset = options->shadowXOffset(isActive());
+ yOffset = options->shadowYOffset(isActive());
+
+ opacityCache->resize(0);
+ opacityCache->resize(w * h);
+ occluded.translate(-windowX + thickness, -windowY + thickness);
+
+ itEnd = rectangles.end();
+ for (it = rectangles.begin(); it != itEnd; ++it) {
+ subW = (*it).width();
+ subH = (*it).height();
+ subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
+ subW, subH);
+ maxY = subH;
+ zeroX = (*it).x() - windowX + thickness - xOffset;
+ zeroY = (*it).y() - windowY + thickness - yOffset;
+ image = subPixmap.convertToImage();
+
+ intersectCount = 0;
+ opacity = -1;
+ y = 0;
+ yIncrement = 1;
+ for (x = 0; x < subW; x++) {
+ irLeft = zeroX + x - thickness;
+ irRight = zeroX + x + thickness;
+
+ while (y != maxY) {
+ // horizontal row about to leave the intersect region, not
+ // necessarily the top row
+ irTop = zeroY + y - thickness * yIncrement;
+ // horizontal row that just came into the intersect region,
+ // not necessarily the bottom row
+ irBottom = zeroY + y + thickness * yIncrement;
+
+ if (opacity == -1) {
+ // If occluded pixels caused an intersect count to be
+ // skipped, recount it
+ intersectCount = 0;
+
+ for (j = irTop; j != irBottom; j += yIncrement) {
+ // irTop is not necessarily larger than irBottom and
+ // yIncrement isn't necessarily positive
+ for (i = irLeft; i <= irRight; i++) {
+ if (occluded.contains(TQPoint(i, j)))
+ intersectCount++;
+ }
+ }
+ }
+ else {
+ if (intersectCount < 0)
+ intersectCount = 0;
+
+ for (i = irLeft; i <= irRight; i++) {
+ if (occluded.contains(TQPoint(i, irBottom)))
+ intersectCount++;
+ }
+ }
+
+ distance = maxIntersects - intersectCount;
+ opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay);
+
+ (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity;
+ pixel = image.pixel(x, y);
+ pixelRed = tqRed(pixel);
+ pixelGreen = tqGreen(pixel);
+ pixelBlue = tqBlue(pixel);
+ image.setPixel(x, y,
+ tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
+ (int)(pixelGreen + (green - pixelGreen) * opacity),
+ (int)(pixelBlue + (blue - pixelBlue) * opacity)));
+
+ for (i = irLeft; i <= irRight; i++) {
+ if (occluded.contains(TQPoint(i, irTop)))
+ intersectCount--;
+ }
+
+ y += yIncrement;
+ }
+ y -= yIncrement;
+
+ irTop += yIncrement;
+ for (j = irTop; j != irBottom; j += yIncrement) {
+ if (occluded.contains(TQPoint(irLeft, j)))
+ intersectCount--;
+ }
+ irRight++;
+ for (j = irTop; j != irBottom; j += yIncrement) {
+ if (occluded.contains(TQPoint(irRight, j)))
+ intersectCount++;
+ }
+
+ yIncrement *= -1;
+ if (yIncrement < 0)
+ // Scan Y-axis bottom-up for next X-coordinate iteration
+ maxY = -1;
+ else
+ // Scan Y-axis top-down for next X-coordinate iteration
+ maxY = subH;
+ }
+
+ subPixmap.convertFromImage(image);
+ bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
+ }
+}
+
+/*!
+ Sets the client window's mapping state. Possible values are
+ WithdrawnState, IconicState, NormalState.
+ */
+void Client::setMappingState(int s)
+ {
+ assert( client != None );
+ assert( !deleting || s == WithdrawnState );
+ if( mapping_state == s )
+ return;
+ bool was_unmanaged = ( mapping_state == WithdrawnState );
+ mapping_state = s;
+ if( mapping_state == WithdrawnState )
+ {
+ XDeleteProperty( tqt_xdisplay(), window(), tqt_wm_state );
+ return;
+ }
+ assert( s == NormalState || s == IconicState );
+
+ unsigned long data[2];
+ data[0] = (unsigned long) s;
+ data[1] = (unsigned long) None;
+ XChangeProperty(tqt_xdisplay(), window(), tqt_wm_state, tqt_wm_state, 32,
+ PropModeReplace, (unsigned char *)data, 2);
+
+ if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
+ postponeGeometryUpdates( false );
+ }
+
+/*!
+ Reimplemented to map the managed window in the window wrapper.
+ Proper mapping state should be set before showing the client.
+ */
+void Client::rawShow()
+ {
+ if( decoration != NULL )
+ decoration->widget()->show(); // not really necessary, but let it know the state
+ XMapWindow( tqt_xdisplay(), frame );
+ if( !isShade())
+ {
+ XMapWindow( tqt_xdisplay(), wrapper );
+ XMapWindow( tqt_xdisplay(), client );
+ }
+ if (options->shadowEnabled(isActive()))
+ drawDelayedShadow();
+ }
+
+/*!
+ Reimplemented to unmap the managed window in the window wrapper.
+ Also informs the workspace.
+ Proper mapping state should be set before hiding the client.
+*/
+void Client::rawHide()
+ {
+// Here it may look like a race condition, as some other client might try to unmap
+// the window between these two XSelectInput() calls. However, they're supposed to
+// use XWithdrawWindow(), which also sends a synthetic event to the root window,
+// which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
+// will be missed is also very minimal, so I don't think it's needed to grab the server
+// here.
+ removeShadow();
+ drawIntersectingShadows();
+ XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
+ XUnmapWindow( tqt_xdisplay(), frame );
+ XUnmapWindow( tqt_xdisplay(), wrapper );
+ XUnmapWindow( tqt_xdisplay(), client );
+ XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
+ if( decoration != NULL )
+ decoration->widget()->hide(); // not really necessary, but let it know the state
+ workspace()->clientHidden( this );
+ }
+
+void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
+ {
+ XEvent ev;
+ long mask;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = w;
+ ev.xclient.message_type = a;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = protocol;
+ ev.xclient.data.l[1] = GET_QT_X_TIME();
+ ev.xclient.data.l[2] = data1;
+ ev.xclient.data.l[3] = data2;
+ ev.xclient.data.l[4] = data3;
+ mask = 0L;
+ if (w == tqt_xrootwin())
+ mask = SubstructureRedirectMask; /* magic! */
+ XSendEvent(tqt_xdisplay(), w, False, mask, &ev);
+ }
+
+/*
+ Returns whether the window may be closed (have a close button)
+ */
+bool Client::isCloseable() const
+ {
+ if( isModalSystemNotification())
+ return false;
+ return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
+ }
+
+/*!
+ Closes the window by either sending a delete_window message or
+ using XKill.
+ */
+void Client::closeWindow()
+ {
+ if( !isCloseable())
+ return;
+ // Update user time, because the window may create a confirming dialog.
+ updateUserTime();
+ if ( Pdeletewindow )
+ {
+ Notify::raise( Notify::Close );
+ sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
+ pingWindow();
+ }
+ else
+ {
+ // client will not react on wm_delete_window. We have not choice
+ // but destroy his connection to the XServer.
+ killWindow();
+ }
+ }
+
+
+/*!
+ Kills the window via XKill
+ */
+void Client::killWindow()
+ {
+ kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
+ // not sure if we need an Notify::Kill or not.. until then, use
+ // Notify::Close
+ Notify::raise( Notify::Close );
+
+ if( isDialog())
+ Notify::raise( Notify::TransDelete );
+ if( isNormalWindow())
+ Notify::raise( Notify::Delete );
+ killProcess( false );
+ // always kill this client at the server
+ XKillClient(tqt_xdisplay(), window() );
+ destroyClient();
+ }
+
+// send a ping to the window using _NET_WM_PING if possible
+// if it doesn't respond within a reasonable time, it will be
+// killed
+void Client::pingWindow()
+ {
+ if( !Pping )
+ return; // can't ping :(
+ if( options->killPingTimeout == 0 )
+ return; // turned off
+ if( ping_timer != NULL )
+ return; // pinging already
+ ping_timer = new TQTimer( this );
+ connect( ping_timer, TQT_SIGNAL( timeout()), TQT_SLOT( pingTimeout()));
+ ping_timer->start( options->killPingTimeout, true );
+ ping_timestamp = GET_QT_X_TIME();
+ workspace()->sendPingToWindow( window(), ping_timestamp );
+ }
+
+void Client::gotPing( Time timestamp )
+ {
+ // just plain compare is not good enough because of 64bit and truncating and whatnot
+ if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
+ return;
+ delete ping_timer;
+ ping_timer = NULL;
+ if( process_killer != NULL )
+ {
+ process_killer->kill();
+ delete process_killer;
+ process_killer = NULL;
+ }
+ }
+
+void Client::pingTimeout()
+ {
+ kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
+ delete ping_timer;
+ ping_timer = NULL;
+ killProcess( true, ping_timestamp );
+ }
+
+void Client::killProcess( bool ask, Time timestamp )
+ {
+ if( process_killer != NULL )
+ return;
+ Q_ASSERT( !ask || timestamp != CurrentTime );
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return;
+ kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
+ if( !ask )
+ {
+ if( machine != "localhost" )
+ {
+ TDEProcess proc;
+ proc << "xon" << machine << "kill" << pid;
+ proc.start( TDEProcess::DontCare );
+ }
+ else
+ ::kill( pid, SIGTERM );
+ }
+ else
+ { // SELI TODO handle the window created by handler specially (on top,urgent?)
+ process_killer = new TDEProcess( this );
+ *process_killer << TDEStandardDirs::findExe( "twin_killer_helper" )
+ << "--pid" << TQCString().setNum( pid ) << "--hostname" << machine
+ << "--windowname" << caption().utf8()
+ << "--applicationname" << resourceClass()
+ << "--wid" << TQCString().setNum( window())
+ << "--timestamp" << TQCString().setNum( timestamp );
+ connect( process_killer, TQT_SIGNAL( processExited( TDEProcess* )),
+ TQT_SLOT( processKillerExited()));
+ if( !process_killer->start( TDEProcess::NotifyOnExit ))
+ {
+ delete process_killer;
+ process_killer = NULL;
+ return;
+ }
+ }
+ }
+
+bool Client::isSuspendable() const
+ {
+ bool cansuspend = true;
+ if( skipTaskbar() || skipPager() )
+ return false;
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return false;
+ kdDebug( 1212 ) << "Check suspendable process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return false;
+ }
+ else
+ {
+ TQFile procStatFile(TQString("/proc/%1/stat").arg(pid));
+ if (procStatFile.open(IO_ReadOnly))
+ {
+ TQByteArray statRaw = procStatFile.readAll();
+ procStatFile.close();
+ TQString statString(statRaw);
+ TQStringList statFields = TQStringList::split(" ", statString, TRUE);
+ TQString tcomm = statFields[1];
+ TQString state = statFields[2];
+ if( state != "T" )
+ {
+ // Make sure no windows of this process are special
+ for ( ClientList::ConstIterator it = workspace()->clients.begin(); it != workspace()->clients.end(); ++it)
+ {
+ Client* nextclient = *it;
+ pid_t nextpid = nextclient->info->pid();
+ TQCString nextmachine = nextclient->wmClientMachine( true );
+ if( nextpid > 0 && (!nextmachine.isEmpty()))
+ {
+ if( ( nextmachine == "localhost" ) && ( pid == nextpid ) )
+ {
+ if( nextclient->skipTaskbar() || nextclient->skipPager() )
+ cansuspend = false;
+ }
+ }
+ }
+ // Process exception list
+ TQString execname(tcomm);
+ execname.truncate(execname.length()-1);
+ execname = execname.remove(0,1);
+ // FIXME This list should not be hardcoded
+ if( (execname == "kdesktop") || (execname == "kicker") )
+ return false;
+ else
+ return cansuspend;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+bool Client::isResumeable() const
+ {
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return false;
+ kdDebug( 1212 ) << "Check resumeable process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return false;
+ }
+ else
+ {
+ TQFile procStatFile(TQString("/proc/%1/stat").arg(pid));
+ if (procStatFile.open(IO_ReadOnly))
+ {
+ TQByteArray statRaw = procStatFile.readAll();
+ procStatFile.close();
+ TQString statString(statRaw);
+ TQStringList statFields = TQStringList::split(" ", statString, TRUE);
+ TQString tcomm = statFields[1];
+ TQString state = statFields[2];
+ if( state == "T" )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+bool Client::queryUserSuspendedResume()
+ {
+ if (isResumeable())
+ {
+ if (process_resumer != NULL)
+ {
+ return false;
+ }
+ // FIXME We should display a busy cursor until twin_resumer_helper loads
+ process_resumer = new TDEProcess( this );
+ *process_resumer << TDEStandardDirs::findExe( "twin_resumer_helper" )
+ << "--pid" << TQCString().setNum( info->pid() ) << "--hostname" << wmClientMachine( true )
+ << "--windowname" << caption().utf8()
+ << "--applicationname" << resourceClass()
+ << "--wid" << TQCString().setNum( window());
+ connect( process_resumer, TQT_SIGNAL( processExited( TDEProcess* )),
+ TQT_SLOT( processResumerExited()));
+ if( !process_resumer->start( TDEProcess::NotifyOnExit ))
+ {
+ delete process_resumer;
+ process_resumer = NULL;
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+void Client::suspendWindow()
+ {
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return;
+ kdDebug( 1212 ) << "Suspend process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return;
+ }
+ else
+ {
+ for ( ClientList::ConstIterator it = workspace()->clients.begin(); it != workspace()->clients.end(); ++it)
+ {
+ Client* nextclient = *it;
+ pid_t nextpid = nextclient->info->pid();
+ TQCString nextmachine = nextclient->wmClientMachine( true );
+ if( nextpid > 0 && (!nextmachine.isEmpty()))
+ {
+ if( ( nextmachine == "localhost" ) && ( pid == nextpid ) )
+ {
+ TQString newCaption = TQString(readName()).append(" <").append(i18n("Suspended")).append(">");
+ nextclient->info->setVisibleName(newCaption.utf8());
+ nextclient->info->setVisibleIconName(newCaption.utf8());
+ nextclient->minimized_before_suspend = nextclient->isMinimized();
+ nextclient->minimize(true);
+ }
+ }
+ }
+ ::kill( pid, SIGSTOP );
+ }
+ }
+
+void Client::resumeWindow()
+ {
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return;
+ kdDebug( 1212 ) << "Resume process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return;
+ }
+ else
+ {
+ ::kill( pid, SIGCONT );
+ for ( ClientList::ConstIterator it = workspace()->clients.begin(); it != workspace()->clients.end(); ++it)
+ {
+ Client* nextclient = *it;
+ pid_t nextpid = nextclient->info->pid();
+ TQCString nextmachine = nextclient->wmClientMachine( true );
+ if( nextpid > 0 && (!nextmachine.isEmpty()))
+ {
+ if( ( nextmachine == "localhost" ) && ( pid == nextpid ) )
+ {
+ if (!nextclient->minimized_before_suspend)
+ {
+ nextclient->unminimize(true);
+ }
+ nextclient->updateCaption();
+ }
+ }
+ }
+ }
+ }
+
+void Client::processKillerExited()
+ {
+ kdDebug( 1212 ) << "Killer exited" << endl;
+ delete process_killer;
+ process_killer = NULL;
+ }
+
+void Client::processResumerExited()
+ {
+ kdDebug( 1212 ) << "Resumer exited" << endl;
+ // 0 means the user clicked Resume; 2 means that the resumer dialog failed to launch somehow
+ if ((process_resumer->exitStatus() == 0) || (process_resumer->exitStatus() == 2))
+ {
+ resumeWindow();
+ takeFocus( Allowed );
+ }
+ delete process_resumer;
+ process_resumer = NULL;
+ }
+
+void Client::setSkipTaskbar( bool b, bool from_outside )
+ {
+ int was_wants_tab_focus = wantsTabFocus();
+ if( from_outside )
+ {
+ b = rules()->checkSkipTaskbar( b );
+ original_skip_taskbar = b;
+ }
+ if ( b == skipTaskbar() )
+ return;
+ skip_taskbar = b;
+ info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
+ updateWindowRules();
+ if( was_wants_tab_focus != wantsTabFocus())
+ workspace()->updateFocusChains( this,
+ isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
+ }
+
+void Client::setSkipPager( bool b )
+ {
+ b = rules()->checkSkipPager( b );
+ if ( b == skipPager() )
+ return;
+ skip_pager = b;
+ info->setState( b?NET::SkipPager:0, NET::SkipPager );
+ updateWindowRules();
+ }
+
+void Client::setModal( bool m )
+ { // Qt-3.2 can have even modal normal windows :(
+ if( modal == m )
+ return;
+ modal = m;
+ if( !modal )
+ return;
+ // changing modality for a mapped window is weird (?)
+ // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
+ }
+
+void Client::setDesktop( int desktop )
+ {
+ if( desktop != NET::OnAllDesktops ) // do range check
+ desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
+ desktop = rules()->checkDesktop( desktop );
+ if( desk == desktop )
+ return;
+ int was_desk = desk;
+ desk = desktop;
+ info->setDesktop( desktop );
+ if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
+ { // onAllDesktops changed
+ if ( isShown( true ))
+ Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
+ workspace()->updateOnAllDesktopsOfTransients( this );
+ }
+ if( decoration != NULL )
+ decoration->desktopChange();
+ workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
+ updateVisibility();
+ updateWindowRules();
+ }
+
+void Client::setOnAllDesktops( bool b )
+ {
+ if(( b && isOnAllDesktops())
+ || ( !b && !isOnAllDesktops()))
+ return;
+ if( b )
+ setDesktop( NET::OnAllDesktops );
+ else
+ setDesktop( workspace()->currentDesktop());
+ }
+
+bool Client::isOnCurrentDesktop() const
+ {
+ return isOnDesktop( workspace()->currentDesktop());
+ }
+
+int Client::screen() const
+ {
+ if( !options->xineramaEnabled )
+ return 0;
+ return workspace()->screenNumber( geometry().center());
+ }
+
+bool Client::isOnScreen( int screen ) const
+ {
+ if( !options->xineramaEnabled )
+ return screen == 0;
+ return workspace()->screenGeometry( screen ).intersects( geometry());
+ }
+
+// performs activation and/or raising of the window
+void Client::takeActivity( int flags, bool handled, allowed_t )
+ {
+ if( !handled || !Ptakeactivity )
+ {
+ if( flags & ActivityFocus )
+ takeFocus( Allowed );
+ if( flags & ActivityRaise )
+ workspace()->raiseClient( this );
+ return;
+ }
+
+#ifndef NDEBUG
+ static Time previous_activity_timestamp;
+ static Client* previous_client;
+ if( previous_activity_timestamp == GET_QT_X_TIME() && previous_client != this )
+ {
+ kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
+ kdDebug( 1212 ) << kdBacktrace() << endl;
+ }
+ previous_activity_timestamp = GET_QT_X_TIME();
+ previous_client = this;
+#endif
+ workspace()->sendTakeActivity( this, GET_QT_X_TIME(), flags );
+ }
+
+// performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
+void Client::takeFocus( allowed_t )
+ {
+#ifndef NDEBUG
+ static Time previous_focus_timestamp;
+ static Client* previous_client;
+ if( previous_focus_timestamp == GET_QT_X_TIME() && previous_client != this )
+ {
+ kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
+ kdDebug( 1212 ) << kdBacktrace() << endl;
+ }
+ previous_focus_timestamp = GET_QT_X_TIME();
+ previous_client = this;
+#endif
+ if ( rules()->checkAcceptFocus( input ))
+ {
+ XSetInputFocus( tqt_xdisplay(), window(), RevertToPointerRoot, GET_QT_X_TIME() );
+ }
+ if ( Ptakefocus )
+ sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
+ workspace()->setShouldGetFocus( this );
+ }
+
+/*!
+ Returns whether the window provides context help or not. If it does,
+ you should show a help menu item or a help button like '?' and call
+ contextHelp() if this is invoked.
+
+ \sa contextHelp()
+ */
+bool Client::providesContextHelp() const
+ {
+ if (isModalSystemNotification())
+ return false;
+ return Pcontexthelp;
+ }
+
+
+/*!
+ Invokes context help on the window. Only works if the window
+ actually provides context help.
+
+ \sa providesContextHelp()
+ */
+void Client::showContextHelp()
+ {
+ if ( Pcontexthelp )
+ {
+ sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
+ TQWhatsThis::enterWhatsThisMode(); // SELI?
+ }
+ }
+
+
+/*!
+ Fetches the window's caption (WM_NAME property). It will be
+ stored in the client's caption().
+ */
+void Client::fetchName()
+ {
+ setCaption( readName());
+ }
+
+TQString Client::readName() const
+ {
+ if ( info->name() && info->name()[ 0 ] != '\0' )
+ return TQString::fromUtf8( info->name() );
+ else
+ return KWin::readNameProperty( window(), XA_WM_NAME );
+ }
+
+KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
+
+void Client::setCaption( const TQString& s, bool force )
+ {
+ if ( s != cap_normal || force )
+ {
+ bool reset_name = force;
+ for( unsigned int i = 0;
+ i < s.length();
+ ++i )
+ if( !s[ i ].isPrint())
+ s[ i ] = ' ';
+ cap_normal = s;
+ bool was_suffix = ( !cap_suffix.isEmpty());
+ TQString machine_suffix;
+ if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
+ machine_suffix = " <@" + wmClientMachine( true ) + ">";
+ TQString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
+ cap_suffix = machine_suffix + shortcut_suffix;
+ if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
+ {
+ int i = 2;
+ do
+ {
+ cap_suffix = machine_suffix + " <" + TQString::number(i) + ">" + shortcut_suffix;
+ i++;
+ } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
+ info->setVisibleName( caption().utf8() );
+ reset_name = false;
+ }
+ if(( (was_suffix && cap_suffix.isEmpty())
+ || reset_name )) // if it was new window, it may have old value still set, if the window is reused
+ {
+ info->setVisibleName( "" ); // remove
+ info->setVisibleIconName( "" ); // remove
+ }
+ else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
+ info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
+
+ if( isManaged() && decoration != NULL )
+ decoration->captionChange();
+ }
+ }
+
+void Client::updateCaption()
+ {
+ setCaption( cap_normal, true );
+ }
+
+void Client::fetchIconicName()
+ {
+ TQString s;
+ if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
+ s = TQString::fromUtf8( info->iconName() );
+ else
+ s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
+ if ( s != cap_iconic )
+ {
+ bool was_set = !cap_iconic.isEmpty();
+ cap_iconic = s;
+ if( !cap_suffix.isEmpty())
+ {
+ if( !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
+ info->setVisibleIconName( ( s + cap_suffix ).utf8() );
+ else if( was_set )
+ info->setVisibleIconName( "" ); //remove
+ }
+ }
+ }
+
+/*!\reimp
+ */
+TQString Client::caption( bool full ) const
+ {
+ return full ? cap_normal + cap_suffix : cap_normal;
+ }
+
+void Client::getWMHints()
+ {
+ XWMHints *hints = XGetWMHints(tqt_xdisplay(), window() );
+ input = true;
+ window_group = None;
+ urgency = false;
+ if ( hints )
+ {
+ if( hints->flags & InputHint )
+ input = hints->input;
+ if( hints->flags & WindowGroupHint )
+ window_group = hints->window_group;
+ urgency = ( hints->flags & UrgencyHint ) ? true : false; // true/false needed, it's uint bitfield
+ XFree( (char*)hints );
+ }
+ checkGroup();
+ updateUrgency();
+ updateAllowedActions(); // group affects isMinimizable()
+ }
+
+void Client::getMotifHints()
+ {
+ bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
+ Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
+ motif_noborder = mnoborder;
+ if( !hasNETSupport()) // NETWM apps should set type and size constraints
+ {
+ motif_may_resize = mresize; // this should be set using minsize==maxsize, but oh well
+ motif_may_move = mmove;
+ }
+ else
+ motif_may_resize = motif_may_move = true;
+ // mminimize; - ignore, bogus - e.g. shading or sending to another desktop is "minimizing" too
+ // mmaximize; - ignore, bogus - maximizing is basically just resizing
+ motif_may_close = mclose; // motif apps like to crash when they set this hint and WM closes them anyway
+ if( isManaged())
+ updateDecoration( true ); // check if noborder state has changed
+ }
+
+void Client::readIcons( Window win, TQPixmap* icon, TQPixmap* miniicon )
+ {
+ // get the icons, allow scaling
+ if( icon != NULL )
+ *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
+ if( miniicon != NULL )
+ {
+ if( icon == NULL || !icon->isNull())
+ *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
+ else
+ *miniicon = TQPixmap();
+ }
+ }
+
+void Client::getIcons()
+ {
+ // first read icons from the window itself
+ readIcons( window(), &icon_pix, &miniicon_pix );
+ if( icon_pix.isNull())
+ { // then try window group
+ icon_pix = group()->icon();
+ miniicon_pix = group()->miniIcon();
+ }
+ if( icon_pix.isNull() && isTransient())
+ { // then mainclients
+ ClientList mainclients = mainClients();
+ for( ClientList::ConstIterator it = mainclients.begin();
+ it != mainclients.end() && icon_pix.isNull();
+ ++it )
+ {
+ icon_pix = (*it)->icon();
+ miniicon_pix = (*it)->miniIcon();
+ }
+ }
+ if( icon_pix.isNull())
+ { // and if nothing else, load icon from classhint or xapp icon
+ icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
+ miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
+ }
+ if( isManaged() && decoration != NULL )
+ decoration->iconChange();
+ }
+
+void Client::getWindowProtocols()
+ {
+ Atom *p;
+ int i,n;
+
+ Pdeletewindow = 0;
+ Ptakefocus = 0;
+ Ptakeactivity = 0;
+ Pcontexthelp = 0;
+ Pping = 0;
+
+ if (XGetWMProtocols(tqt_xdisplay(), window(), &p, &n))
+ {
+ for (i = 0; i < n; i++)
+ if (p[i] == atoms->wm_delete_window)
+ Pdeletewindow = 1;
+ else if (p[i] == atoms->wm_take_focus)
+ Ptakefocus = 1;
+ else if (p[i] == atoms->net_wm_take_activity)
+ Ptakeactivity = 1;
+ else if (p[i] == atoms->net_wm_context_help)
+ Pcontexthelp = 1;
+ else if (p[i] == atoms->net_wm_ping)
+ Pping = 1;
+ if (n>0)
+ XFree(p);
+ }
+ }
+
+static int nullErrorHandler(Display *, XErrorEvent *)
+ {
+ return 0;
+ }
+
+/*!
+ Returns WM_WINDOW_ROLE property for a given window.
+ */
+TQCString Client::staticWindowRole(WId w)
+ {
+ return getStringProperty(w, tqt_window_role).lower();
+ }
+
+/*!
+ Returns SM_CLIENT_ID property for a given window.
+ */
+TQCString Client::staticSessionId(WId w)
+ {
+ return getStringProperty(w, tqt_sm_client_id);
+ }
+
+/*!
+ Returns WM_COMMAND property for a given window.
+ */
+TQCString Client::staticWmCommand(WId w)
+ {
+ return getStringProperty(w, XA_WM_COMMAND, ' ');
+ }
+
+/*!
+ Returns WM_CLIENT_LEADER property for a given window.
+ */
+Window Client::staticWmClientLeader(WId w)
+ {
+ Atom type;
+ int format, status;
+ unsigned long nitems = 0;
+ unsigned long extra = 0;
+ unsigned char *data = 0;
+ Window result = w;
+ XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
+ status = XGetWindowProperty( tqt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
+ FALSE, XA_WINDOW, &type, &format,
+ &nitems, &extra, &data );
+ XSetErrorHandler(oldHandler);
+ if (status == Success )
+ {
+ if (data && nitems > 0)
+ result = *((Window*) data);
+ XFree(data);
+ }
+ return result;
+ }
+
+
+void Client::getWmClientLeader()
+ {
+ wmClientLeaderWin = staticWmClientLeader(window());
+ }
+
+/*!
+ Returns sessionId for this client,
+ taken either from its window or from the leader window.
+ */
+TQCString Client::sessionId()
+ {
+ TQCString result = staticSessionId(window());
+ if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
+ result = staticSessionId(wmClientLeaderWin);
+ return result;
+ }
+
+/*!
+ Returns command property for this client,
+ taken either from its window or from the leader window.
+ */
+TQCString Client::wmCommand()
+ {
+ TQCString result = staticWmCommand(window());
+ if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
+ result = staticWmCommand(wmClientLeaderWin);
+ return result;
+ }
+
+void Client::getWmClientMachine()
+ {
+ client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
+ if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
+ client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
+ if( client_machine.isEmpty())
+ client_machine = "localhost";
+ }
+
+/*!
+ Returns client machine for this client,
+ taken either from its window or from the leader window.
+*/
+TQCString Client::wmClientMachine( bool use_localhost ) const
+ {
+ TQCString result = client_machine;
+ if( use_localhost )
+ { // special name for the local machine (localhost)
+ if( result != "localhost" && isLocalMachine( result ))
+ result = "localhost";
+ }
+ return result;
+ }
+
+/*!
+ Returns client leader window for this client.
+ Returns the client window itself if no leader window is defined.
+*/
+Window Client::wmClientLeader() const
+ {
+ if (wmClientLeaderWin)
+ return wmClientLeaderWin;
+ return window();
+ }
+
+bool Client::wantsTabFocus() const
+ {
+ return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
+ }
+
+
+bool Client::wantsInput() const
+ {
+ return rules()->checkAcceptFocus( input || Ptakefocus );
+ }
+
+bool Client::isDesktop() const
+ {
+ return windowType() == NET::Desktop;
+ }
+
+bool Client::isDock() const
+ {
+ return windowType() == NET::Dock;
+ }
+
+bool Client::isTopMenu() const
+ {
+ return windowType() == NET::TopMenu;
+ }
+
+
+bool Client::isMenu() const
+ {
+ return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
+ }
+
+bool Client::isToolbar() const
+ {
+ return windowType() == NET::Toolbar;
+ }
+
+bool Client::isSplash() const
+ {
+ return windowType() == NET::Splash;
+ }
+
+bool Client::isUtility() const
+ {
+ return windowType() == NET::Utility;
+ }
+
+bool Client::isDialog() const
+ {
+ return windowType() == NET::Dialog;
+ }
+
+bool Client::isNormalWindow() const
+ {
+ return windowType() == NET::Normal;
+ }
+
+bool Client::isSpecialWindow() const
+ {
+ return isDesktop() || isDock() || isSplash() || isTopMenu()
+ || isToolbar(); // TODO
+ }
+
+NET::WindowType Client::windowType( bool direct, int supported_types ) const
+ {
+ NET::WindowType wt = info->windowType( supported_types );
+ if( direct )
+ return wt;
+ NET::WindowType wt2 = rules()->checkType( wt );
+ if( wt != wt2 )
+ {
+ wt = wt2;
+ info->setWindowType( wt ); // force hint change
+ }
+ // hacks here
+ if( wt == NET::Menu )
+ {
+ // ugly hack to support the times when NET::Menu meant NET::TopMenu
+ // if it's as wide as the screen, not very high and has its upper-left
+ // corner a bit above the screen's upper-left cornet, it's a topmenu
+ if( x() == 0 && y() < 0 && y() > -10 && height() < 100
+ && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
+ wt = NET::TopMenu;
+ }
+ // TODO change this to rule
+ const char* const oo_prefix = "openoffice.org"; // TQCString has no startsWith()
+ // oo_prefix is lowercase, because resourceClass() is forced to be lowercase
+ if( tqstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
+ wt = NET::Normal; // see bug #66065
+ if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
+ wt = isTransient() ? NET::Dialog : NET::Normal;
+ return wt;
+ }
+
+/*!
+ Sets an appropriate cursor shape for the logical mouse position \a m
+
+ */
+void Client::setCursor( Position m )
+ {
+ if( !isResizable() || isShade())
+ {
+ m = PositionCenter;
+ }
+ switch ( m )
+ {
+ case PositionTopLeft:
+ case PositionBottomRight:
+ setCursor( tqsizeFDiagCursor );
+ break;
+ case PositionBottomLeft:
+ case PositionTopRight:
+ setCursor( tqsizeBDiagCursor );
+ break;
+ case PositionTop:
+ case PositionBottom:
+ setCursor( tqsizeVerCursor );
+ break;
+ case PositionLeft:
+ case PositionRight:
+ setCursor( tqsizeHorCursor );
+ break;
+ default:
+ if( buttonDown && isMovable())
+ setCursor( tqsizeAllCursor );
+ else
+ setCursor( tqarrowCursor );
+ break;
+ }
+ }
+
+// TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
+// TRANSLATION: TODO: have a checkCursor() function, which is called both in manage() and in cases where the cursor might change
+void Client::setCursor( const TQCursor& c )
+ {
+ if( c.handle() == cursor.handle())
+ return;
+ cursor = c;
+ if( decoration != NULL )
+ decoration->widget()->setCursor( cursor );
+ XDefineCursor( tqt_xdisplay(), frameId(), cursor.handle());
+ }
+
+Client::Position Client::mousePosition( const TQPoint& p ) const
+ {
+ if( decoration != NULL )
+ return decoration->mousePosition( p );
+ return PositionCenter;
+ }
+
+void Client::updateAllowedActions( bool force )
+ {
+ if( !isManaged() && !force )
+ return;
+ unsigned long old_allowed_actions = allowed_actions;
+ allowed_actions = 0;
+ if( isMovable())
+ allowed_actions |= NET::ActionMove;
+ if( isResizable())
+ allowed_actions |= NET::ActionResize;
+ if( isMinimizable())
+ allowed_actions |= NET::ActionMinimize;
+ if( isShadeable())
+ allowed_actions |= NET::ActionShade;
+ // sticky state not supported
+ if( isMaximizable())
+ allowed_actions |= NET::ActionMax;
+ if( userCanSetFullScreen())
+ allowed_actions |= NET::ActionFullScreen;
+ allowed_actions |= NET::ActionChangeDesktop; // always (pagers shouldn't show Docks etc.)
+ if( isCloseable())
+ allowed_actions |= NET::ActionClose;
+ if( old_allowed_actions == allowed_actions )
+ return;
+ // TODO this could be delayed and compressed - it's only for pagers etc. anyway
+ info->setAllowedActions( allowed_actions );
+ // TODO this should also tell the decoration, so that it can update the buttons
+ }
+
+void Client::autoRaise()
+ {
+ workspace()->raiseClient( this );
+ cancelAutoRaise();
+ }
+
+void Client::cancelAutoRaise()
+ {
+ delete autoRaiseTimer;
+ autoRaiseTimer = 0;
+ }
+
+void Client::setOpacity(bool translucent, uint opacity)
+ {
+ if (isDesktop())
+ return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
+// tqWarning("setting opacity for %d",tqt_xdisplay());
+ //rule out activated translulcency with 100% opacity
+ if (!translucent || opacity == 0xFFFFFFFF)
+ {
+ opacity_ = 0xFFFFFFFF;
+ XDeleteProperty (tqt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
+ XDeleteProperty (tqt_xdisplay(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd
+ }
+ else{
+ if(opacity == opacity_)
+ return;
+ opacity_ = opacity;
+ long data = opacity; // 32bit XChangeProperty needs long
+ XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
+ XChangeProperty(tqt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
+ }
+ }
+
+void Client::setShadowSize(uint shadowSize)
+ {
+ // ignoring all individual settings - if we control a window, we control it's shadow
+ // TODO somehow handle individual settings for docks (besides custom sizes)
+ long data = shadowSize;
+ XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
+ }
+
+void Client::updateOpacity()
+// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
+ {
+ if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
+ return;
+ if (isActive())
+ {
+ if( ruleOpacityActive() )
+ setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
+ else
+ setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
+ if (isBMP())
+ // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
+ {
+ ClientList tmpGroupMembers = group()->members();
+ ClientList activeGroupMembers;
+ activeGroupMembers.append(this);
+ tmpGroupMembers.remove(this);
+ ClientList::Iterator it = tmpGroupMembers.begin();
+ while (it != tmpGroupMembers.end())
+ // search for next attached and not activated client and repeat if found
+ {
+ if ((*it) != this && (*it)->isBMP())
+ // potential "to activate" client found
+ {
+// tqWarning("client found");
+ if ((*it)->touches(this)) // first test, if the new client touches the just activated one
+ {
+// tqWarning("found client touches me");
+ if( ruleOpacityActive() )
+ (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
+ else
+ (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
+// tqWarning("activated, search restarted (1)");
+ (*it)->setShadowSize(options->activeWindowShadowSize);
+ activeGroupMembers.append(*it);
+ tmpGroupMembers.remove(it);
+ it = tmpGroupMembers.begin(); // restart, search next client
+ continue;
+ }
+ else
+ { // pot. client does not touch c, so we have to search if it touches some other activated client
+ bool found = false;
+ for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
+ {
+ if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
+ {
+// tqWarning("found client touches other active client");
+ if( ruleOpacityActive() )
+ (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
+ else
+ (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
+ (*it)->setShadowSize(options->activeWindowShadowSize);
+ activeGroupMembers.append(*it);
+ tmpGroupMembers.remove(it);
+ it = tmpGroupMembers.begin(); // reset potential client search
+ found = true;
+// tqWarning("activated, search restarted (2)");
+ break; // skip this loop
+ }
+ }
+ if (found) continue;
+ }
+ }
+ it++;
+ }
+ }
+ else if (isNormalWindow())
+ // activate dependend minor windows as well
+ {
+ for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
+ if ((*it)->isDialog() || (*it)->isUtility())
+ {
+ if( (*it)->ruleOpacityActive() )
+ (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
+ else
+ (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
+ }
+ }
+ }
+ else
+ {
+ if( ruleOpacityInactive() )
+ setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
+ else
+ setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
+ options->inactiveWindowOpacity);
+ // deactivate dependend minor windows as well
+ if (isBMP())
+ // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
+ {
+ ClientList tmpGroupMembers = group()->members();
+ ClientList inactiveGroupMembers;
+ inactiveGroupMembers.append(this);
+ tmpGroupMembers.remove(this);
+ ClientList::Iterator it = tmpGroupMembers.begin();
+ while ( it != tmpGroupMembers.end() )
+ // search for next attached and not activated client and repeat if found
+ {
+ if ((*it) != this && (*it)->isBMP())
+ // potential "to activate" client found
+ {
+// tqWarning("client found");
+ if ((*it)->touches(this)) // first test, if the new client touches the just activated one
+ {
+// tqWarning("found client touches me");
+ if( (*it)->ruleOpacityInactive() )
+ (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
+ else
+ (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
+ (*it)->setShadowSize(options->inactiveWindowShadowSize);
+// tqWarning("deactivated, search restarted (1)");
+ inactiveGroupMembers.append(*it);
+ tmpGroupMembers.remove(it);
+ it = tmpGroupMembers.begin(); // restart, search next client
+ continue;
+ }
+ else // pot. client does not touch c, so we have to search if it touches some other activated client
+ {
+ bool found = false;
+ for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
+ {
+ if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
+ {
+// tqWarning("found client touches other inactive client");
+ if( (*it)->ruleOpacityInactive() )
+ (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
+ else
+ (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
+ (*it)->setShadowSize(options->inactiveWindowShadowSize);
+// tqWarning("deactivated, search restarted (2)");
+ inactiveGroupMembers.append(*it);
+ tmpGroupMembers.remove(it);
+ it = tmpGroupMembers.begin(); // reset potential client search
+ found = true;
+ break; // skip this loop
+ }
+ }
+ if (found) continue;
+ }
+ }
+ it++;
+ }
+ }
+ else if (isNormalWindow())
+ {
+ for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
+ if ((*it)->isUtility()) //don't deactivate dialogs...
+ {
+ if( (*it)->ruleOpacityInactive() )
+ (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
+ else
+ (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
+ }
+ }
+ }
+ }
+
+void Client::updateShadowSize()
+// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
+ {
+ if (!(isNormalWindow() || isDialog() || isUtility() ))
+ return;
+ if (isActive())
+ setShadowSize(options->activeWindowShadowSize);
+ else
+ setShadowSize(options->inactiveWindowShadowSize);
+ }
+
+uint Client::ruleOpacityInactive()
+ {
+ return rule_opacity_inactive;// != 0 ;
+ }
+
+uint Client::ruleOpacityActive()
+ {
+ return rule_opacity_active;// != 0;
+ }
+
+bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set
+ {
+ unsigned char *data = 0;
+ Atom actual;
+ int format, result;
+ unsigned long n, left;
+ result = XGetWindowProperty(tqt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
+ if (result == Success && data != None && format == 32 )
+ {
+ opacity_ = *reinterpret_cast< long* >( data );
+ custom_opacity = true;
+// setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
+ XFree ((char*)data);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+void Client::setCustomOpacityFlag(bool custom)
+ {
+ custom_opacity = custom;
+ }
+
+uint Client::opacity()
+ {
+ return opacity_;
+ }
+
+int Client::opacityPercentage()
+ {
+ return int(100*((double)opacity_/0xffffffff));
+ }
+
+bool Client::touches(const Client* c)
+// checks if this client borders c, needed to test beep media player window state
+ {
+ if (y() == c->y() + c->height()) // this bottom to c
+ return TRUE;
+ if (y() + height() == c->y()) // this top to c
+ return TRUE;
+ if (x() == c->x() + c->width()) // this right to c
+ return TRUE;
+ if (x() + width() == c->x()) // this left to c
+ return TRUE;
+ return FALSE;
+ }
+
+void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
+{
+ long data = (topHeight < 255 ? topHeight : 255) << 24 |
+ (rightWidth < 255 ? rightWidth : 255) << 16 |
+ (bottomHeight < 255 ? bottomHeight : 255) << 8 |
+ (leftWidth < 255 ? leftWidth : 255);
+ XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
+}
+
+void Client::unsetDecoHashProperty()
+{
+ XDeleteProperty( tqt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
+}
+
+#ifndef NDEBUG
+kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
+ {
+ if( cl == NULL )
+ return stream << "\'NULL_CLIENT\'";
+ return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
+ }
+kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
+ {
+ stream << "LIST:(";
+ bool first = true;
+ for( ClientList::ConstIterator it = list.begin();
+ it != list.end();
+ ++it )
+ {
+ if( !first )
+ stream << ":";
+ first = false;
+ stream << *it;
+ }
+ stream << ")";
+ return stream;
+ }
+kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
+ {
+ stream << "LIST:(";
+ bool first = true;
+ for( ConstClientList::ConstIterator it = list.begin();
+ it != list.end();
+ ++it )
+ {
+ if( !first )
+ stream << ":";
+ first = false;
+ stream << *it;
+ }
+ stream << ")";
+ return stream;
+ }
+#endif
+
+TQPixmap * twin_get_menu_pix_hack()
+ {
+ static TQPixmap p;
+ if ( p.isNull() )
+ p = SmallIcon( "bx2" );
+ return &p;
+ }
+
+} // namespace
+
+#include "client.moc"
diff --git a/twin/client.h b/twin/client.h
new file mode 100644
index 00000000..674251a5
--- /dev/null
+++ b/twin/client.h
@@ -0,0 +1,1006 @@
+/*****************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
+Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+You can Freely distribute this program under the GNU General Public
+License. See the file "COPYING" for the exact licensing terms.
+******************************************************************/
+
+#ifndef KWIN_CLIENT_H
+#define KWIN_CLIENT_H
+
+#include <tqframe.h>
+#include <tqvbox.h>
+#include <tqpixmap.h>
+#include <netwm.h>
+#include <kdebug.h>
+#include <assert.h>
+#include <tdeshortcut.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <fixx11h.h>
+
+#include "utils.h"
+#include "options.h"
+#include "workspace.h"
+#include "kdecoration.h"
+#include "rules.h"
+
+class TQTimer;
+class TDEProcess;
+class TDEStartupInfoData;
+
+namespace KWinInternal
+{
+
+class Workspace;
+class Client;
+class WinInfo;
+class SessionInfo;
+class Bridge;
+
+class Client : public TQObject, public KDecorationDefines
+ {
+ Q_OBJECT
+ public:
+ Client( Workspace *ws );
+ Window window() const;
+ Window frameId() const;
+ Window wrapperId() const;
+ Window decorationId() const;
+
+ Workspace* workspace() const;
+ const Client* transientFor() const;
+ Client* transientFor();
+ bool isTransient() const;
+ bool isModalSystemNotification() const;
+ bool groupTransient() const;
+ bool wasOriginallyGroupTransient() const;
+ ClientList mainClients() const; // call once before loop , is not indirect
+ bool hasTransient( const Client* c, bool indirect ) const;
+ const ClientList& transients() const; // is not indirect
+ void checkTransient( Window w );
+ Client* findModal();
+ const Group* group() const;
+ Group* group();
+ void checkGroup( Group* gr = NULL, bool force = false );
+ void changeClientLeaderGroup( Group* gr );
+ // prefer isXXX() instead
+ NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
+ const WindowRules* rules() const;
+ void removeRule( Rules* r );
+ void setupWindowRules( bool ignore_temporary );
+ void applyWindowRules();
+ void updateWindowRules();
+
+ TQRect geometry() const;
+ TQSize size() const;
+ TQSize minSize() const;
+ TQSize maxSize() const;
+ TQPoint pos() const;
+ TQRect rect() const;
+ int x() const;
+ int y() const;
+ int width() const;
+ int height() const;
+ TQPoint clientPos() const; // inside of geometry()
+ TQSize clientSize() const;
+
+ bool windowEvent( XEvent* e );
+ virtual bool eventFilter( TQObject* o, TQEvent* e );
+
+ bool manage( Window w, bool isMapped );
+
+ void releaseWindow( bool on_shutdown = false );
+
+ enum Sizemode // how to resize the window in order to obey constains (mainly aspect ratios)
+ {
+ SizemodeAny,
+ SizemodeFixedW, // try not to affect width
+ SizemodeFixedH, // try not to affect height
+ SizemodeMax // try not to make it larger in either direction
+ };
+ TQSize adjustedSize( const TQSize&, Sizemode mode = SizemodeAny ) const;
+ TQSize adjustedSize() const;
+
+ TQPixmap icon() const;
+ TQPixmap miniIcon() const;
+
+ bool isActive() const;
+ void setActive( bool, bool updateOpacity = true );
+
+ bool isSuspendable() const;
+ bool isResumeable() const;
+
+ int desktop() const;
+ void setDesktop( int );
+ bool isOnDesktop( int d ) const;
+ bool isOnCurrentDesktop() const;
+ bool isOnAllDesktops() const;
+ void setOnAllDesktops( bool set );
+
+ bool isOnScreen( int screen ) const; // true if it's at least partially there
+ int screen() const; // the screen where the center is
+
+ // !isMinimized() && not hidden, i.e. normally visible on some virtual desktop
+ bool isShown( bool shaded_is_shown ) const;
+
+ bool isShade() const; // true only for ShadeNormal
+ ShadeMode shadeMode() const; // prefer isShade()
+ void setShade( ShadeMode mode );
+ bool isShadeable() const;
+
+ bool isMinimized() const;
+ bool isMaximizable() const;
+ TQRect geometryRestore() const;
+ MaximizeMode maximizeModeRestore() const;
+ MaximizeMode maximizeMode() const;
+ bool isMinimizable() const;
+ void setMaximize( bool vertically, bool horizontally );
+
+ void setFullScreen( bool set, bool user );
+ bool isFullScreen() const;
+ bool isFullScreenable( bool fullscreen_hack = false ) const;
+ bool userCanSetFullScreen() const;
+ TQRect geometryFSRestore() const { return geom_fs_restore; } // only for session saving
+ int fullScreenMode() const { return fullscreen_mode; } // only for session saving
+
+ bool isUserNoBorder() const;
+ void setUserNoBorder( bool set );
+ bool userCanSetNoBorder() const;
+ bool noBorder() const;
+
+ bool skipTaskbar( bool from_outside = false ) const;
+ void setSkipTaskbar( bool set, bool from_outside );
+
+ bool skipPager() const;
+ void setSkipPager( bool );
+
+ bool keepAbove() const;
+ void setKeepAbove( bool );
+ bool keepBelow() const;
+ void setKeepBelow( bool );
+ Layer layer() const;
+ Layer belongsToLayer() const;
+ void invalidateLayer();
+
+ void setModal( bool modal );
+ bool isModal() const;
+
+ // auxiliary functions, depend on the windowType
+ bool wantsTabFocus() const;
+ bool wantsInput() const;
+ bool hasNETSupport() const;
+ bool isMovable() const;
+ bool isDesktop() const;
+ bool isDock() const;
+ bool isToolbar() const;
+ bool isTopMenu() const;
+ bool isMenu() const;
+ bool isNormalWindow() const; // normal as in 'NET::Normal or NET::Unknown non-transient'
+ bool isDialog() const;
+ bool isSplash() const;
+ bool isUtility() const;
+ // returns true for "special" windows and false for windows which are "normal"
+ // (normal=window which has a border, can be moved by the user, can be closed, etc.)
+ // true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
+ // false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
+ bool isSpecialWindow() const;
+
+ bool isResizable() const;
+ bool isCloseable() const; // may be closed by the user (may have a close button)
+
+ void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h)
+ void takeFocus( allowed_t );
+ void demandAttention( bool set = true );
+
+ void setMask( const TQRegion& r, int mode = X::Unsorted );
+ TQRegion mask() const;
+
+ void updateDecoration( bool check_workspace_pos, bool force = false );
+ void checkBorderSizes();
+
+ // drop shadow
+ bool isShadowed() const;
+ void setShadowed(bool shadowed);
+ Window shadowId() const;
+ // Aieee, a friend function! Unpleasant, yes, but it's needed by
+ // raiseClient() to redraw a window's shadow when it is active prior to
+ // being raised.
+ friend void Workspace::raiseClient(Client *);
+ // Wouldn't you know it, friend functions breed. This one's needed to
+ // enable a DCOP function that causes all shadows obscuring a changed
+ // window to be redrawn.
+ friend void Workspace::updateOverlappingShadows(WId);
+
+ // shape extensions
+ bool shape() const;
+ void updateShape();
+
+ void setGeometry( int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet );
+ void setGeometry( const TQRect& r, ForceGeometry_t force = NormalGeometrySet );
+ void move( int x, int y, ForceGeometry_t force = NormalGeometrySet );
+ void move( const TQPoint & p, ForceGeometry_t force = NormalGeometrySet );
+ // plainResize() simply resizes
+ void plainResize( int w, int h, ForceGeometry_t force = NormalGeometrySet );
+ void plainResize( const TQSize& s, ForceGeometry_t force = NormalGeometrySet );
+ // resizeWithChecks() resizes according to gravity, and checks workarea position
+ void resizeWithChecks( int w, int h, ForceGeometry_t force = NormalGeometrySet );
+ void resizeWithChecks( const TQSize& s, ForceGeometry_t force = NormalGeometrySet );
+ void keepInArea( TQRect area, bool partial = false );
+
+ void growHorizontal();
+ void shrinkHorizontal();
+ void growVertical();
+ void shrinkVertical();
+
+ bool providesContextHelp() const;
+ TDEShortcut shortcut() const;
+ void setShortcut( const TQString& cut );
+
+ bool performMouseCommand( Options::MouseCommand, TQPoint globalPos, bool handled = false );
+
+ TQCString windowRole() const;
+ TQCString sessionId();
+ TQCString resourceName() const;
+ TQCString resourceClass() const;
+ TQCString wmCommand();
+ TQCString wmClientMachine( bool use_localhost ) const;
+ Window wmClientLeader() const;
+ pid_t pid() const;
+
+ TQRect adjustedClientArea( const TQRect& desktop, const TQRect& area ) const;
+
+ Colormap colormap() const;
+
+ // updates visibility depending on being shaded, virtual desktop, etc.
+ void updateVisibility();
+ // hides a client - basically like minimize, but without effects, it's simply hidden
+ void hideClient( bool hide );
+
+ TQString caption( bool full = true ) const;
+ void updateCaption();
+
+ void keyPressEvent( uint key_code ); // FRAME ??
+ void updateMouseGrab();
+ Window moveResizeGrabWindow() const;
+
+ const TQPoint calculateGravitation( bool invert, int gravity = 0 ) const; // FRAME public?
+
+ void NETMoveResize( int x_root, int y_root, NET::Direction direction );
+ void NETMoveResizeWindow( int flags, int x, int y, int width, int height );
+ void restackWindow( Window above, int detail, NET::RequestSource source, Time timestamp, bool send_event = false );
+
+ void gotPing( Time timestamp );
+
+ static TQCString staticWindowRole(WId);
+ static TQCString staticSessionId(WId);
+ static TQCString staticWmCommand(WId);
+ static TQCString staticWmClientMachine(WId);
+ static Window staticWmClientLeader(WId);
+
+ void checkWorkspacePosition();
+ void updateUserTime( Time time = CurrentTime );
+ Time userTime() const;
+ bool hasUserTimeSupport() const;
+ bool ignoreFocusStealing() const;
+
+ // does 'delete c;'
+ static void deleteClient( Client* c, allowed_t );
+
+ static bool resourceMatch( const Client* c1, const Client* c2 );
+ static bool belongToSameApplication( const Client* c1, const Client* c2, bool active_hack = false );
+ static void readIcons( Window win, TQPixmap* icon, TQPixmap* miniicon );
+
+ void minimize( bool avoid_animation = false );
+ void unminimize( bool avoid_animation = false );
+ void closeWindow();
+ void killWindow();
+ void suspendWindow();
+ void resumeWindow();
+ bool queryUserSuspendedResume();
+ void maximize( MaximizeMode );
+ void toggleShade();
+ void showContextHelp();
+ void cancelShadeHover();
+ void cancelAutoRaise();
+ void destroyClient();
+ void checkActiveModal();
+ void setOpacity(bool translucent, uint opacity = 0);
+ void setShadowSize(uint shadowSize);
+ void updateOpacity();
+ void updateShadowSize();
+ bool hasCustomOpacity(){return custom_opacity;}
+ void setCustomOpacityFlag(bool custom = true);
+ bool getWindowOpacity();
+ int opacityPercentage();
+ void checkAndSetInitialRuledOpacity();
+ uint ruleOpacityInactive();
+ uint ruleOpacityActive();
+ unsigned int opacity();
+ bool isBMP();
+ void setBMP(bool b);
+ bool touches(const Client* c);
+ void setShapable(bool b);
+ bool hasStrut() const;
+
+ private slots:
+ void autoRaise();
+ void shadeHover();
+ void shortcutActivated();
+ void updateOpacityCache();
+
+
+ private:
+ friend class Bridge; // FRAME
+ virtual void processMousePressEvent( TQMouseEvent* e );
+
+ private: // TODO cleanup the order of things in the .h file
+ // use Workspace::createClient()
+ virtual ~Client(); // use destroyClient() or releaseWindow()
+
+ Position mousePosition( const TQPoint& ) const;
+ void setCursor( Position m );
+ void setCursor( const TQCursor& c );
+
+ void animateMinimizeOrUnminimize( bool minimize );
+ TQPixmap animationPixmap( int w );
+ // transparent stuff
+ void drawbound( const TQRect& geom );
+ void clearbound();
+ void doDrawbound( const TQRect& geom, bool clear );
+
+ // handlers for X11 events
+ bool mapRequestEvent( XMapRequestEvent* e );
+ void unmapNotifyEvent( XUnmapEvent*e );
+ void destroyNotifyEvent( XDestroyWindowEvent*e );
+ void configureRequestEvent( XConfigureRequestEvent* e );
+ void propertyNotifyEvent( XPropertyEvent* e );
+ void clientMessageEvent( XClientMessageEvent* e );
+ void enterNotifyEvent( XCrossingEvent* e );
+ void leaveNotifyEvent( XCrossingEvent* e );
+ void focusInEvent( XFocusInEvent* e );
+ void focusOutEvent( XFocusOutEvent* e );
+
+ bool buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
+ bool buttonReleaseEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
+ bool motionNotifyEvent( Window w, int state, int x, int y, int x_root, int y_root );
+
+ // drop shadows
+ void drawIntersectingShadows();
+ void drawOverlappingShadows(bool waitForMe);
+ TQRegion getExposedRegion(TQRegion occludedRegion, int x, int y,
+ int w, int h, int thickness, int xOffset, int yOffset);
+ void imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed);
+ void imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded,
+ TQRegion exposed, int thickness, double maxOpacity = 0.75);
+
+ void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root );
+
+ private slots:
+ void pingTimeout();
+ void processKillerExited();
+ void processResumerExited();
+ void demandAttentionKNotify();
+ void drawShadow();
+ void drawShadowAfter(Client *after);
+ void drawDelayedShadow();
+ void removeShadow();
+
+ signals:
+ void shadowDrawn();
+
+
+ private:
+ // ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1
+ void setMappingState( int s );
+ int mappingState() const;
+ bool isIconicState() const;
+ bool isNormalState() const;
+ bool isManaged() const; // returns false if this client is not yet managed
+ void updateAllowedActions( bool force = false );
+ TQSize sizeForClientSize( const TQSize&, Sizemode mode = SizemodeAny, bool noframe = false ) const;
+ void changeMaximize( bool horizontal, bool vertical, bool adjust );
+ void checkMaximizeGeometry();
+ int checkFullScreenHack( const TQRect& geom ) const; // 0 - none, 1 - one xinerama screen, 2 - full area
+ void updateFullScreenHack( const TQRect& geom );
+ void getWmNormalHints();
+ void getMotifHints();
+ void getIcons();
+ void getWmClientLeader();
+ void getWmClientMachine();
+ void fetchName();
+ void fetchIconicName();
+ TQString readName() const;
+ void setCaption( const TQString& s, bool force = false );
+ bool hasTransientInternal( const Client* c, bool indirect, ConstClientList& set ) const;
+ void finishWindowRules();
+ void setShortcutInternal( const TDEShortcut& cut );
+
+ void updateWorkareaDiffs();
+ void checkDirection( int new_diff, int old_diff, TQRect& rect, const TQRect& area );
+ static int computeWorkareaDiff( int left, int right, int a_left, int a_right );
+ void configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool );
+ NETExtendedStrut strut() const;
+ int checkShadeGeometry( int w, int h );
+ void postponeGeometryUpdates( bool postpone );
+
+ bool startMoveResize();
+ void finishMoveResize( bool cancel );
+ void leaveMoveResize();
+ void checkUnrestrictedMoveResize();
+ void handleMoveResize( int x, int y, int x_root, int y_root );
+ void positionGeometryTip();
+ void grabButton( int mod );
+ void ungrabButton( int mod );
+ void resetMaximize();
+ void resizeDecoration( const TQSize& s );
+ void setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth);
+ void unsetDecoHashProperty();
+
+ void pingWindow();
+ void killProcess( bool ask, Time timestamp = CurrentTime );
+ void updateUrgency();
+ static void sendClientMessage( Window w, Atom a, Atom protocol,
+ long data1 = 0, long data2 = 0, long data3 = 0 );
+
+ void embedClient( Window w, const XWindowAttributes &attr );
+ void detectNoBorder();
+ void detectShapable();
+ void destroyDecoration();
+ void updateFrameExtents();
+
+ void rawShow(); // just shows it
+ void rawHide(); // just hides it
+
+ Time readUserTimeMapTimestamp( const TDEStartupInfoId* asn_id, const TDEStartupInfoData* asn_data,
+ bool session ) const;
+ Time readUserCreationTime() const;
+ static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
+ void startupIdChanged();
+
+ Window client;
+ Window wrapper;
+ Window frame;
+ KDecoration* decoration;
+ Workspace* wspace;
+ Bridge* bridge;
+ int desk;
+ bool buttonDown;
+ bool moveResizeMode;
+ bool move_faked_activity;
+ Window move_resize_grab_window;
+ bool unrestrictedMoveResize;
+ bool isMove() const
+ {
+ return moveResizeMode && mode == PositionCenter;
+ }
+ bool isResize() const
+ {
+ return moveResizeMode && mode != PositionCenter;
+ }
+
+ Position mode;
+ TQPoint moveOffset;
+ TQPoint invertedMoveOffset;
+ TQRect moveResizeGeom;
+ TQRect initialMoveResizeGeom;
+ XSizeHints xSizeHint;
+ void sendSyntheticConfigureNotify();
+ int mapping_state;
+ void readTransient();
+ Window verifyTransientFor( Window transient_for, bool set );
+ void addTransient( Client* cl );
+ void removeTransient( Client* cl );
+ void removeFromMainClients();
+ void cleanGrouping();
+ void checkGroupTransients();
+ void setTransient( Window new_transient_for_id );
+ Client* transient_for;
+ Window transient_for_id;
+ Window original_transient_for_id;
+ ClientList transients_list; // SELI make this ordered in stacking order?
+ ShadeMode shade_mode;
+ uint active :1;
+ uint deleting : 1; // true when doing cleanup and destroying the client
+ uint keep_above : 1; // NET::KeepAbove (was stays_on_top)
+ uint is_shape :1;
+ uint skip_taskbar :1;
+ uint original_skip_taskbar :1; // unaffected by KWin
+ uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol?
+ uint Ptakefocus :1;// does the window understand the TakeFocus protocol?
+ uint Ptakeactivity : 1; // does it support _NET_WM_TAKE_ACTIVITY
+ uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol?
+ uint Pping : 1; // does it support _NET_WM_PING?
+ uint input :1; // does the window want input in its wm_hints
+ uint skip_pager : 1;
+ uint motif_noborder : 1;
+ uint motif_may_resize : 1;
+ uint motif_may_move :1;
+ uint motif_may_close : 1;
+ uint keep_below : 1; // NET::KeepBelow
+ uint minimized : 1;
+ uint hidden : 1; // forcibly hidden by calling hide()
+ uint modal : 1; // NET::Modal
+ uint noborder : 1;
+ uint user_noborder : 1;
+ uint urgency : 1; // XWMHints, UrgencyHint
+ uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client
+ uint demands_attention : 1;
+ WindowRules client_rules;
+ void getWMHints();
+ void readIcons();
+ void getWindowProtocols();
+ TQPixmap icon_pix;
+ TQPixmap miniicon_pix;
+ TQCursor cursor;
+ // FullScreenHack - non-NETWM fullscreen (noborder,size of desktop)
+ // DON'T reorder - saved to config files !!!
+ enum FullScreenMode { FullScreenNone, FullScreenNormal, FullScreenHack };
+ FullScreenMode fullscreen_mode;
+ MaximizeMode max_mode;
+ TQRect geom_restore;
+ TQRect geom_fs_restore;
+ MaximizeMode maxmode_restore;
+ int workarea_diff_x, workarea_diff_y;
+ WinInfo* info;
+ TQTimer* autoRaiseTimer;
+ TQTimer* shadeHoverTimer;
+ Colormap cmap;
+ TQCString resource_name;
+ TQCString resource_class;
+ TQCString client_machine;
+ TQString cap_normal, cap_iconic, cap_suffix;
+ WId wmClientLeaderWin;
+ TQCString window_role;
+ Group* in_group;
+ Window window_group;
+ Layer in_layer;
+ TQTimer* ping_timer;
+ TDEProcess* process_killer;
+ TDEProcess* process_resumer;
+ Time ping_timestamp;
+ Time user_time;
+ unsigned long allowed_actions;
+ TQRect frame_geometry;
+ TQSize client_size;
+ int postpone_geometry_updates; // >0 - new geometry is remembered, but not actually set
+ bool pending_geometry_update;
+ bool shade_geometry_change;
+ int border_left, border_right, border_top, border_bottom;
+
+ Client* shadowAfterClient;
+ TQWidget* shadowWidget;
+ TQMemArray<double> activeOpacityCache;
+ TQMemArray<double> inactiveOpacityCache;
+ TQMemArray<double>* opacityCache;
+ TQRegion shapeBoundingRegion;
+ TQTimer* shadowDelayTimer;
+ bool shadowMe;
+
+ TQRegion _mask;
+ static bool check_active_modal; // see Client::checkActiveModal()
+ TDEShortcut _shortcut;
+ friend struct FetchNameInternalPredicate;
+ friend struct CheckIgnoreFocusStealingProcedure;
+ friend struct ResetupRulesProcedure;
+ friend class GeometryUpdatesPostponer;
+ void show() { assert( false ); } // SELI remove after Client is no longer TQWidget
+ void hide() { assert( false ); }
+ uint opacity_;
+ uint savedOpacity_;
+ bool custom_opacity;
+ uint rule_opacity_active; //translucency rules
+ uint rule_opacity_inactive; //dto.
+ //int shadeOriginalHeight;
+ bool isBMP_;
+ TQTimer* demandAttentionKNotifyTimer;
+
+ friend bool performTransiencyCheck();
+ bool minimized_before_suspend;
+ };
+
+// helper for Client::postponeGeometryUpdates() being called in pairs (true/false)
+class GeometryUpdatesPostponer
+ {
+ public:
+ GeometryUpdatesPostponer( Client* c )
+ : cl( c ) { cl->postponeGeometryUpdates( true ); }
+ ~GeometryUpdatesPostponer()
+ { cl->postponeGeometryUpdates( false ); }
+ private:
+ Client* cl;
+ };
+
+
+// NET WM Protocol handler class
+class WinInfo : public NETWinInfo
+ {
+ private:
+ typedef KWinInternal::Client Client; // because of NET::Client
+ public:
+ WinInfo( Client* c, Display * display, Window window,
+ Window rwin, const unsigned long pr[], int pr_size );
+ virtual void changeDesktop(int desktop);
+ virtual void changeState( unsigned long state, unsigned long mask );
+ private:
+ Client * m_client;
+ };
+
+inline Window Client::window() const
+ {
+ return client;
+ }
+
+inline Window Client::frameId() const
+ {
+ return frame;
+ }
+
+inline Window Client::wrapperId() const
+ {
+ return wrapper;
+ }
+
+inline Window Client::decorationId() const
+ {
+ return decoration != NULL ? decoration->widget()->winId() : None;
+ }
+
+inline Workspace* Client::workspace() const
+ {
+ return wspace;
+ }
+
+inline const Client* Client::transientFor() const
+ {
+ return transient_for;
+ }
+
+inline Client* Client::transientFor()
+ {
+ return transient_for;
+ }
+
+inline bool Client::groupTransient() const
+ {
+ return transient_for_id == workspace()->rootWin();
+ }
+
+// needed because verifyTransientFor() may set transient_for_id to root window,
+// if the original value has a problem (window doesn't exist, etc.)
+inline bool Client::wasOriginallyGroupTransient() const
+ {
+ return original_transient_for_id == workspace()->rootWin();
+ }
+
+inline bool Client::isTransient() const
+ {
+ return transient_for_id != None;
+ }
+
+inline const ClientList& Client::transients() const
+ {
+ return transients_list;
+ }
+
+inline const Group* Client::group() const
+ {
+ return in_group;
+ }
+
+inline Group* Client::group()
+ {
+ return in_group;
+ }
+
+inline int Client::mappingState() const
+ {
+ return mapping_state;
+ }
+
+inline TQCString Client::resourceName() const
+ {
+ return resource_name; // it is always lowercase
+ }
+
+inline TQCString Client::resourceClass() const
+ {
+ return resource_class; // it is always lowercase
+ }
+
+inline
+bool Client::isMinimized() const
+ {
+ return minimized;
+ }
+
+inline bool Client::isActive() const
+ {
+ return active;
+ }
+
+/*!
+ Returns the virtual desktop within the workspace() the client window
+ is located in, 0 if it isn't located on any special desktop (not mapped yet),
+ or NET::OnAllDesktops. Do not use desktop() directly, use
+ isOnDesktop() instead.
+ */
+inline int Client::desktop() const
+ {
+ return desk;
+ }
+
+inline bool Client::isOnAllDesktops() const
+ {
+ return desk == NET::OnAllDesktops;
+ }
+/*!
+ Returns whether the client is on the virtual desktop \a d.
+ This is always TRUE for onAllDesktops clients.
+ */
+inline bool Client::isOnDesktop( int d ) const
+ {
+ return desk == d || /*desk == 0 ||*/ isOnAllDesktops();
+ }
+
+inline
+bool Client::isShown( bool shaded_is_shown ) const
+ {
+ return !isMinimized() && ( !isShade() || shaded_is_shown ) && !hidden;
+ }
+
+inline
+bool Client::isShade() const
+ {
+ return shade_mode == ShadeNormal;
+ }
+
+inline
+ShadeMode Client::shadeMode() const
+ {
+ return shade_mode;
+ }
+
+inline TQPixmap Client::icon() const
+ {
+ return icon_pix;
+ }
+
+inline TQPixmap Client::miniIcon() const
+ {
+ return miniicon_pix;
+ }
+
+inline TQRect Client::geometryRestore() const
+ {
+ return geom_restore;
+ }
+
+inline Client::MaximizeMode Client::maximizeModeRestore() const
+ {
+ return maxmode_restore;
+ }
+
+inline Client::MaximizeMode Client::maximizeMode() const
+ {
+ return max_mode;
+ }
+
+inline bool Client::skipTaskbar( bool from_outside ) const
+ {
+ return from_outside ? original_skip_taskbar : skip_taskbar;
+ }
+
+inline bool Client::skipPager() const
+ {
+ return skip_pager;
+ }
+
+inline bool Client::keepBelow() const
+ {
+ return keep_below;
+ }
+
+inline bool Client::shape() const
+ {
+ return is_shape;
+ }
+
+
+inline bool Client::isFullScreen() const
+ {
+ return fullscreen_mode != FullScreenNone;
+ }
+
+inline bool Client::isModal() const
+ {
+ return modal;
+ }
+
+inline bool Client::hasNETSupport() const
+ {
+ return info->hasNETSupport();
+ }
+
+inline Colormap Client::colormap() const
+ {
+ return cmap;
+ }
+
+inline pid_t Client::pid() const
+ {
+ return info->pid();
+ }
+
+inline void Client::invalidateLayer()
+ {
+ in_layer = UnknownLayer;
+ }
+
+inline bool Client::isIconicState() const
+ {
+ return mapping_state == IconicState;
+ }
+
+inline bool Client::isNormalState() const
+ {
+ return mapping_state == NormalState;
+ }
+
+inline bool Client::isManaged() const
+ {
+ return mapping_state != WithdrawnState;
+ }
+
+inline TQCString Client::windowRole() const
+ {
+ return window_role;
+ }
+
+inline TQRect Client::geometry() const
+ {
+ return frame_geometry;
+ }
+
+inline TQSize Client::size() const
+ {
+ return frame_geometry.size();
+ }
+
+inline TQPoint Client::pos() const
+ {
+ return frame_geometry.topLeft();
+ }
+
+inline int Client::x() const
+ {
+ return frame_geometry.x();
+ }
+
+inline int Client::y() const
+ {
+ return frame_geometry.y();
+ }
+
+inline int Client::width() const
+ {
+ return frame_geometry.width();
+ }
+
+inline int Client::height() const
+ {
+ return frame_geometry.height();
+ }
+
+inline TQRect Client::rect() const
+ {
+ return TQRect( 0, 0, width(), height());
+ }
+
+inline TQPoint Client::clientPos() const
+ {
+ return TQPoint( border_left, border_top );
+ }
+
+inline TQSize Client::clientSize() const
+ {
+ return client_size;
+ }
+
+inline void Client::setGeometry( const TQRect& r, ForceGeometry_t force )
+ {
+ setGeometry( r.x(), r.y(), r.width(), r.height(), force );
+ }
+
+inline void Client::move( const TQPoint & p, ForceGeometry_t force )
+ {
+ move( p.x(), p.y(), force );
+ }
+
+inline void Client::plainResize( const TQSize& s, ForceGeometry_t force )
+ {
+ plainResize( s.width(), s.height(), force );
+ }
+
+inline bool Client::isShadowed() const
+ {
+ return shadowMe;
+ }
+
+inline Window Client::shadowId() const
+ {
+ return shadowWidget != NULL ? shadowWidget->winId() : None;
+ }
+
+inline void Client::resizeWithChecks( const TQSize& s, ForceGeometry_t force )
+ {
+ resizeWithChecks( s.width(), s.height(), force );
+ }
+
+inline bool Client::hasUserTimeSupport() const
+ {
+ return info->userTime() != -1U;
+ }
+
+inline bool Client::ignoreFocusStealing() const
+ {
+ return ignore_focus_stealing;
+ }
+
+inline const WindowRules* Client::rules() const
+ {
+ return &client_rules;
+ }
+
+KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl ));
+
+inline Window Client::moveResizeGrabWindow() const
+ {
+ return move_resize_grab_window;
+ }
+
+inline TDEShortcut Client::shortcut() const
+ {
+ return _shortcut;
+ }
+
+inline bool Client::isBMP()
+ {
+ return isBMP_;
+ }
+
+inline void Client::setBMP(bool b)
+ {
+ isBMP_ = b;
+ }
+
+inline void Client::removeRule( Rules* rule )
+ {
+ client_rules.remove( rule );
+ }
+
+#ifdef NDEBUG
+inline
+kndbgstream& operator<<( kndbgstream& stream, const Client* ) { return stream; }
+inline
+kndbgstream& operator<<( kndbgstream& stream, const ClientList& ) { return stream; }
+inline
+kndbgstream& operator<<( kndbgstream& stream, const ConstClientList& ) { return stream; }
+#else
+kdbgstream& operator<<( kdbgstream& stream, const Client* );
+kdbgstream& operator<<( kdbgstream& stream, const ClientList& );
+kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& );
+#endif
+
+KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Window, cl->window() == value );
+KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Window, cl->frameId() == value );
+KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Window, cl->wrapperId() == value );
+
+} // namespace
+
+#endif
diff --git a/twin/clients/CMakeLists.txt b/twin/clients/CMakeLists.txt
new file mode 100644
index 00000000..c9a8faf8
--- /dev/null
+++ b/twin/clients/CMakeLists.txt
@@ -0,0 +1,20 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( plastik )
+add_subdirectory( b2 )
+add_subdirectory( default )
+add_subdirectory( keramik )
+add_subdirectory( laptop )
+add_subdirectory( modernsystem )
+add_subdirectory( quartz )
+add_subdirectory( redmond )
+add_subdirectory( web )
diff --git a/twin/clients/Makefile.am b/twin/clients/Makefile.am
new file mode 100644
index 00000000..c62b2101
--- /dev/null
+++ b/twin/clients/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = plastik b2 default keramik laptop modernsystem quartz redmond web
+# need to be ported: kwmtheme (almost done)
+# only for testing: test
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name \*.ui` >> rc.cpp
+ $(XGETTEXT) `find . -name \*.cpp` -o $(podir)/twin_clients.pot
+ -rm rc.cpp
diff --git a/twin/clients/PORTING b/twin/clients/PORTING
new file mode 100644
index 00000000..0c0c1a6e
--- /dev/null
+++ b/twin/clients/PORTING
@@ -0,0 +1,159 @@
+It's suggested you check sources of some KDE CVS decoration if in doubts or in need of an example.
+Also, the API is documented in the .h header files.
+
+Makefile.am:
+- Change twin_ to twin3_ (in LDFLAGS, LIBADD, kde_module_LTLIBRARIES, SOURCES).
+- Make sure LDFLAGS contains $(KDE_PLUGIN) and -module .
+- Add -ltdecorations to LIBADD.
+- Do NOT rename the directory where the .desktop file is installed ( $(kde_datadir)/twin/ ).
+
+.desktop file:
+- Change twin_ to twin3_ in X-TDE-Library.
+
+Sources:
+- There are no twin/something.h includes, and don't use the KWinInternal namespace.
+- Use QToolTip instead of KWinToolTip.
+- Use QButton instead of KWinButton, QToolButton instead of KWinToolButton and QWidget
+ instead of KWinWidgetButton.
+- For tooltips, use simply QToolTip::add().
+- Change Client* to MyClient* (or whatever is your main client class) in your MyButton.
+- Pass parent->widget() to QButton constructor in your MyButton constructor.
+- Make your MyClient class inherit from KDecoration instead of Client.
+- Make MyClient constructor take KDecorationBridge* and KDecorationFactory* as arguments,
+ and pass these arguments to KDecoration constructor.
+- Except for data members initialization, make the constructor empty, move everything
+ to void MyClient::init().
+- As the first thing in init(), call createMainWidget(); if your client class took some
+ flags such as WResizeNoErase, pass them to this function.
+- Then, do 'widget()->installEventFilter( this );'.
+- Implement MyClient::eventFilter() - as MyClient is now no longer QWidget, you need the event
+ filter to call all the functions that used to be called directly. Usually, it's something
+ like:
+=====
+bool MyClient::eventFilter( QObject* o, QEvent* e )
+{
+ if ( o != widget() )
+ return false;
+
+ switch ( e->type() )
+ {
+ case QEvent::Resize:
+ resizeEvent( static_cast< QResizeEvent* >( e ) );
+ return true;
+
+ case QEvent::Paint:
+ paintEvent( static_cast< QPaintEvent* >( e ) );
+ return true;
+
+ case QEvent::MouseButtonDblClick:
+ mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) );
+ return true;
+
+ case QEvent::Wheel:
+ wheelEvent( static_cast< QWheelEvent* >( e ));
+ return true;
+
+ case QEvent::MouseButtonPress:
+ processMousePressEvent( static_cast< QMouseEvent* >( e ) );
+ return true;
+
+ case QEvent::Show:
+ showEvent( static_cast< QShowEvent* >( e ) );
+ return true;
+
+ default:
+ return false;
+ }
+}
+=====
+- In MyClient, 'this' will have to be often replaced with 'widget()', pay special attention
+ to cases where this won't cause compile error (e.g. in connect() calls, which take QObject* ).
+- Also, many calls may need 'widget()->' prepended.
+- Layout is created in init(), so call createLayout() directly there (if it's implemented).
+- Remove calls to Client methods (Client::resizeEvent() and so on).
+- Replace Options:: with KDecorationOptions:: .
+- Replace 'options' with 'options()' in MyClient (which is KDecoration::options()), if often used
+ outside of MyClient, you may want to create (this assumes your code is in its namespace):
+=====
+inline const KDecorationOptions* options() { return KDecoration::options(); }
+=====
+- Options for colors need 'Color' prepended (e.g. 'ColorButtonBg').
+- Replace miniIcon() with getting the right pixmap from icon() (usually
+ 'icon().pixmap( QIconSet::Small, QIconSet::Normal )' ).
+- Replace stickyChange() with desktopChange(), and test isOnAllDesktops().
+- Replace Sticky with OnAllDestops.
+- Replace iconify with minimize.
+- Change activeChange(bool) to activeChange(), and use isActive() to check the state.
+ Similar for desktopChange, captionChange(), iconChange(), maximizeChange().
+- Replace 'contextHelp()' with 'showContextHelp()'.
+- WindowWrapperShowEvent() is gone, simply use showEvent() filtered by the event filter if needed.
+- Change 'animateIconifyOrDeiconify()' to 'animateMinize()', if it's empty, simply remove it.
+ Make sure it doesn't reenter the event loop (no kapp->processEvents()).
+- Buttons should use explicit setCursor() if they don't want cursor set by mousePosition().
+ I.e. usually call setCursor( ArrowCursor ) in your MyButton.
+- In the part where you insert windowWrapper() into the layout, i.e. something like
+=====
+ layout->addWidget( windowWrapper());
+=====
+ replace it with something like
+=====
+ if( isPreview())
+ layout->addWidget( new QLabel( i18n( "<center><b>MyDecoration</b></center>" ), widget()));
+ else
+ layout->addItem( new QSpacerItem( 0, 0 ));
+=====
+- Implement MyClient::minimumSize().
+- Handling maximization - to change vertical or horizontal maximalization, use e.g.
+ 'maximize( maximizeMode() ^ MaximizeVertical', to change normal maximalization, i.e. after
+ left-clicking on the button, use
+ 'maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull );' (which also
+ means that there's also no maximize() slot).
+ Also, if your decoration button has only two visual states representing the maximalization state,
+ it's recommended that it shows the maximized state only for MaximizeFull state.
+- Make sure the decoration matches the window state after init() is finished, that is, that
+ the buttons represent correctly the maximalization, on-all-desktops etc. states. As the
+ simplest solution, you can call maximizeChange(), desktopChange(), etc. at the end
+ of init().
+- Use 'titlebarDblClickOperation()' for performing the application after doubleclicking
+ the titlebar.
+- Implement borders() returning the width of the top,left,right and bottom border. You may
+ check values like 'maximizeMode() == MaximizeFull && !options()->moveResizeMaximizedWindows()'
+ to check whether you can disable some borders completely.
+ Note that your painting code must of course match these sizes.
+- If your code uses XGrabServer() or XUnGrabServer(), replace them with (un)grabXServer().
+- In cases where you call some function from the KDecoration API that can possibly destroy
+ the decoration (e.g. showWindowMenu() or closeWindow()), make sure to use exists() if some more
+ code will follow this call. Refer to showWindowMenu() documentation for an example.
+- Create class MyFactory inheriting from KDecorationFactory, and move the code that was
+ in 'extern "C"' to it: From init() to constructor, from deinit() to destructor, from allocate()
+ or create() to createDecoration(). Pass the KDecorationBridge* argument and 'this' to created
+ MyClient objects. If createDecoration() needs to know the window type (e.g. it used the tool
+ argument), use windowType() similarly like in KDecoration, and pass it the KDecorationBridge*
+ argument.
+- Add something like this:
+=====
+extern "C"
+{
+ KDecorationFactory *create_factory()
+ {
+ return new MyNamespace::MyFactory();
+ }
+}
+=====
+- The reset handling has changed: There's no signal resetClients(), and no
+ slotResetAllClientsDelayed(). If your MyClient has some slotReset(), make it
+ reset( unsigned long ), where the argument is mask of things that have changed ( SettingXYZ ).
+ If you have some global function that handles resetting, make it
+ MyFactory::reset( unsigned long ). Try to minimize the effects of the changed things,
+ e.g. if only the color setting has changed, doing a repaint is often enough, and there's no need
+ to recreate the decorations. If you need to recreate the decorations, return true
+ from MyFactory::reset(), otherwise, you may call resetDecorations() to call reset() in all
+ MyClient instances.
+- Implement resize() to resize the decoration to the given size
+ (usually 'widget()->resize( s );' is enough).
+- Review mousePosition() if it's implemented. Position constants need 'Position' prepended,
+ e.g. Top -> PositionTop.
+- Note that you cannot use "appdata" with TDEStandardDirs, as the decoration will be used
+ also in other applications than twin.
+- Implement all missing pure virtual functions. For mousePosition(), you may call
+ KDecoration::mousePosition() if it's sufficient.
diff --git a/twin/clients/REQUIREMENTS_FOR_CVS b/twin/clients/REQUIREMENTS_FOR_CVS
new file mode 100644
index 00000000..0c8c2a6d
--- /dev/null
+++ b/twin/clients/REQUIREMENTS_FOR_CVS
@@ -0,0 +1,20 @@
+If you are looking to include a C++ KWin style client in CVS make sure you
+follow the following requirements:
+
+A) You must follow the current color scheme for all decorations. *No* fixed
+pixmaps are allowed for the clients. If you wish to draw your decorations
+use as few shades as possible, then use kpixmap2bitmap in tdegraphics
+to convert them into individual bitmaps. Once this is done you can
+draw the bitmaps using a colorgroup with kColorBitmaps.
+
+If your client is just a set of pixmaps that doesn't follow any of the options
+I suggest you make a KWM theme so the user gets those options to
+configure the pixmaps and look. Making a plain pixmapped dedicated style
+makes no sense since it is less configurable than KWM themes and cannot follow
+client plugin options.
+
+B) You must follow at least the color settings in the Options class.
+
+Daniel M. Duley
+mosfet@kde.org
+
diff --git a/twin/clients/b2/CMakeLists.txt b/twin/clients/b2/CMakeLists.txt
new file mode 100644
index 00000000..c7f4bdb9
--- /dev/null
+++ b/twin/clients/b2/CMakeLists.txt
@@ -0,0 +1,37 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( config )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/twin/lib
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES b2.desktop DESTINATION ${DATA_INSTALL_DIR}/twin )
+
+
+##### twin3_b2 (module) #########################
+
+tde_add_kpart( twin3_b2 AUTOMOC
+ SOURCES b2client.cpp
+ LINK tdecorations-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/twin/clients/b2/Makefile.am b/twin/clients/b2/Makefile.am
new file mode 100644
index 00000000..ccd7f39f
--- /dev/null
+++ b/twin/clients/b2/Makefile.am
@@ -0,0 +1,23 @@
+
+INCLUDES = -I$(srcdir)/../../lib $(all_includes)
+
+SUBDIRS = . config
+
+kde_module_LTLIBRARIES = twin3_b2.la
+
+twin3_b2_la_SOURCES = b2client.cpp
+twin3_b2_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+# twin_b2_la_LDFLAGS = $(all_libraries) -avoid-version -module $(KDE_RPATH) $(KDE_MT_LDFLAGS)
+twin3_b2_la_LIBADD = ../../lib/libtdecorations.la
+
+METASOURCES = AUTO
+noinst_HEADERS = b2client.h
+
+lnkdir = $(kde_datadir)/twin/
+lnk_DATA = b2.desktop
+
+EXTRA_DIST = $(lnk_DATA)
+
+###KMAKE-start (don't edit or delete this block)
+
+###KMAKE-end
diff --git a/twin/clients/b2/b2.desktop b/twin/clients/b2/b2.desktop
new file mode 100644
index 00000000..e95f4f72
--- /dev/null
+++ b/twin/clients/b2/b2.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Name=B II
+Name[hi]=बी II
+Name[lo]= B II
+Name[te]=బి II
+Name[th]=ชุดตกแต่ง B II
+X-TDE-Library=twin3_b2
diff --git a/twin/clients/b2/b2client.cpp b/twin/clients/b2/b2client.cpp
new file mode 100644
index 00000000..6a7a8296
--- /dev/null
+++ b/twin/clients/b2/b2client.cpp
@@ -0,0 +1,1454 @@
+/*
+ * B-II KWin Client
+ *
+ * Changes:
+ * Customizable button positions by Karol Szwed <gallium@kde.org>
+ *
+ * Thin frame in fixed size windows, titlebar gradient support, accessibility
+ * improvements, customizable menu double click action and button hover
+ * effects are
+ * Copyright (c) 2003,2004 Luciano Montanaro <mikelima@cirulla.net>
+ */
+
+#include "b2client.h"
+#include <tqapplication.h>
+#include <tqlayout.h>
+#include <tqdrawutil.h>
+#include <kpixmapeffect.h>
+#include <kimageeffect.h>
+#include <kicontheme.h>
+#include <kiconeffect.h>
+#include <kdrawutil.h>
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <tqbitmap.h>
+#include <tqlabel.h>
+#include <tqtooltip.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+namespace B2 {
+
+#include "bitmaps.h"
+
+enum {
+ Norm = 0,
+ Hover, Down, INorm, IHover, IDown,
+ NumStates
+};
+
+enum {
+ P_CLOSE = 0,
+ P_MAX, P_NORMALIZE, P_ICONIFY, P_PINUP, P_MENU, P_HELP, P_SHADE, P_RESIZE,
+ P_NUM_BUTTON_TYPES
+};
+
+#define NUM_PIXMAPS (P_NUM_BUTTON_TYPES * NumStates)
+
+static KPixmap *pixmap[NUM_PIXMAPS];
+
+// active
+#define PIXMAP_A(i) (pixmap[(i) * NumStates + Norm])
+// active, hover
+#define PIXMAP_AH(i) (pixmap[(i) * NumStates + Hover])
+// active, down
+#define PIXMAP_AD(i) (pixmap[(i) * NumStates + Down])
+// inactive
+#define PIXMAP_I(i) (pixmap[(i) * NumStates + INorm])
+// inactive, hover
+#define PIXMAP_IH(i) (pixmap[(i) * NumStates + IHover])
+// inactive, down
+#define PIXMAP_ID(i) (pixmap[(i) * NumStates + IDown])
+
+static KPixmap* titleGradient[2] = {0, 0};
+
+static int thickness = 4; // Frame thickness
+static int buttonSize = 16;
+
+enum DblClickOperation {
+ NoOp = 0,
+ MinimizeOp,
+ ShadeOp,
+ CloseOp
+};
+
+static DblClickOperation menu_dbl_click_op = NoOp;
+
+static bool pixmaps_created = false;
+static bool colored_frame = false;
+static bool do_draw_handle = true;
+static bool drawSmallBorders = false;
+
+// =====================================
+
+extern "C" KDE_EXPORT KDecorationFactory* create_factory()
+{
+ return new B2::B2ClientFactory();
+}
+
+// =====================================
+
+static inline const KDecorationOptions *options()
+{
+ return KDecoration::options();
+}
+
+static void redraw_pixmaps();
+
+static void read_config(B2ClientFactory *f)
+{
+ // Force button size to be in a reasonable range.
+ // If the frame width is large, the button size must be large too.
+ buttonSize = (TQFontMetrics(options()->font(true)).height() + 1) & 0x3e;
+ if (buttonSize < 16) buttonSize = 16;
+
+ TDEConfig conf("twinb2rc");
+ conf.setGroup("General");
+ colored_frame = conf.readBoolEntry("UseTitleBarBorderColors", false);
+ do_draw_handle = conf.readBoolEntry("DrawGrabHandle", true);
+ drawSmallBorders = !options()->moveResizeMaximizedWindows();
+
+ TQString opString = conf.readEntry("MenuButtonDoubleClickOperation", "NoOp");
+ if (opString == "Close") {
+ menu_dbl_click_op = B2::CloseOp;
+ } else if (opString == "Minimize") {
+ menu_dbl_click_op = B2::MinimizeOp;
+ } else if (opString == "Shade") {
+ menu_dbl_click_op = B2::ShadeOp;
+ } else {
+ menu_dbl_click_op = B2::NoOp;
+ }
+
+ switch (options()->preferredBorderSize(f)) {
+ case KDecoration::BorderTiny:
+ thickness = 2;
+ break;
+ case KDecoration::BorderLarge:
+ thickness = 5;
+ break;
+ case KDecoration::BorderVeryLarge:
+ thickness = 8;
+ break;
+ case KDecoration::BorderHuge:
+ thickness = 12;
+ break;
+ case KDecoration::BorderVeryHuge:
+ case KDecoration::BorderOversized:
+ case KDecoration::BorderNormal:
+ default:
+ thickness = 4;
+ }
+}
+
+static void drawB2Rect(KPixmap *pix, const TQColor &primary, bool down)
+{
+ TQPainter p(pix);
+ TQColor hColor = primary.light(150);
+ TQColor lColor = primary.dark(150);
+
+ if (down) tqSwap(hColor, lColor);
+
+ if (TQPixmap::defaultDepth() > 8) {
+ KPixmapEffect::gradient(*pix, hColor, lColor,
+ KPixmapEffect::DiagonalGradient);
+ }
+ else
+ pix->fill(primary);
+ int x2 = pix->width() - 1;
+ int y2 = pix->height() - 1;
+ p.setPen(lColor);
+ p.drawLine(0, 0, x2, 0);
+ p.drawLine(0, 0, 0, y2);
+ p.drawLine(1, x2 - 1, x2 - 1, y2 - 1);
+ p.drawLine(x2 - 1, 1, x2 - 1, y2 - 1);
+ p.setPen(hColor);
+ p.drawRect(1, 1, x2, y2);
+
+}
+
+TQPixmap* twin_get_menu_pix_hack()
+{
+ //return menu_pix; FIXME
+ return PIXMAP_A(P_MENU);
+}
+
+static void create_pixmaps()
+{
+ if (pixmaps_created)
+ return;
+ pixmaps_created = true;
+
+ int i;
+ int bsize = buttonSize - 2;
+ if (bsize < 16) bsize = 16;
+
+ for (i = 0; i < NUM_PIXMAPS; i++) {
+ pixmap[i] = new KPixmap;
+ switch (i / NumStates) {
+ case P_MAX: // will be initialized by copying P_CLOSE
+ case P_RESIZE:
+ break;
+ case P_ICONIFY:
+ pixmap[i]->resize(10, 10); break;
+ case P_SHADE:
+ case P_CLOSE:
+ pixmap[i]->resize(bsize, bsize); break;
+ default:
+ pixmap[i]->resize(16, 16); break;
+ }
+ }
+
+ // there seems to be no way to load X bitmaps from data properly, so
+ // we need to create new ones for each mask :P
+ TQBitmap pinupMask(16, 16, pinup_mask_bits, true);
+ PIXMAP_A(P_PINUP)->setMask(pinupMask);
+ PIXMAP_I(P_PINUP)->setMask(pinupMask);
+ TQBitmap pindownMask(16, 16, pindown_mask_bits, true);
+ PIXMAP_AD(P_PINUP)->setMask(pindownMask);
+ PIXMAP_ID(P_PINUP)->setMask(pindownMask);
+
+ TQBitmap menuMask(16, 16, menu_mask_bits, true);
+ for (i = 0; i < NumStates; i++)
+ pixmap[P_MENU * NumStates + i]->setMask(menuMask);
+
+ TQBitmap helpMask(16, 16, help_mask_bits, true);
+ for (i = 0; i < NumStates; i++)
+ pixmap[P_HELP * NumStates + i]->setMask(helpMask);
+
+ TQBitmap normalizeMask(16, 16, true);
+ // draw normalize icon mask
+ TQPainter mask;
+ mask.begin(&normalizeMask);
+
+ TQBrush one(Qt::color1);
+ mask.fillRect(normalizeMask.width() - 12, normalizeMask.height() - 12,
+ 12, 12, one);
+ mask.fillRect(0, 0, 10, 10, one);
+ mask.end();
+
+ for (i = 0; i < NumStates; i++)
+ pixmap[P_NORMALIZE * NumStates + i]->setMask(normalizeMask);
+
+ TQBitmap shadeMask(bsize, bsize, true);
+ mask.begin(&shadeMask);
+ mask.fillRect(0, 0, bsize, 6, one);
+ mask.end();
+ for (i = 0; i < NumStates; i++)
+ pixmap[P_SHADE * NumStates + i]->setMask(shadeMask);
+
+ titleGradient[0] = 0;
+ titleGradient[1] = 0;
+
+ redraw_pixmaps();
+}
+
+static void delete_pixmaps()
+{
+ for (int i = 0; i < NUM_PIXMAPS; i++) {
+ delete pixmap[i];
+ pixmap[i] = 0;
+ }
+ for (int i = 0; i < 2; i++) {
+ delete titleGradient[i];
+ titleGradient[i] = 0;
+ }
+ pixmaps_created = false;
+}
+
+// =====================================
+
+B2ClientFactory::B2ClientFactory()
+{
+ read_config(this);
+ create_pixmaps();
+}
+
+B2ClientFactory::~B2ClientFactory()
+{
+ delete_pixmaps();
+}
+
+KDecoration *B2ClientFactory::createDecoration(KDecorationBridge *b)
+{
+ return new B2::B2Client(b, this);
+}
+
+bool B2ClientFactory::reset(unsigned long changed)
+{
+ bool needsReset = SettingColors ? true : false;
+ // TODO Do not recreate decorations if it is not needed. Look at
+ // ModernSystem for how to do that
+ read_config(this);
+ if (changed & SettingFont) {
+ delete_pixmaps();
+ create_pixmaps();
+ needsReset = true;
+ }
+ redraw_pixmaps();
+ // For now just return true.
+ return needsReset;
+}
+
+bool B2ClientFactory::supports( Ability ability )
+{
+ switch( ability )
+ {
+ case AbilityAnnounceButtons:
+ case AbilityButtonMenu:
+ case AbilityButtonOnAllDesktops:
+ case AbilityButtonSpacer:
+ case AbilityButtonHelp:
+ case AbilityButtonMinimize:
+ case AbilityButtonMaximize:
+ case AbilityButtonClose:
+ case AbilityButtonAboveOthers:
+ case AbilityButtonBelowOthers:
+ case AbilityButtonShade:
+ case AbilityButtonResize:
+ return true;
+ default:
+ return false;
+ };
+}
+
+TQValueList< B2ClientFactory::BorderSize > B2ClientFactory::borderSizes() const
+{
+ // the list must be sorted
+ return TQValueList< BorderSize >() << BorderTiny << BorderNormal <<
+ BorderLarge << BorderVeryLarge << BorderHuge;
+}
+
+// =====================================
+
+void B2Client::maxButtonClicked()
+{
+ maximize(button[BtnMax]->last_button);
+}
+
+void B2Client::shadeButtonClicked()
+{
+ setShade(!isSetShade());
+}
+
+void B2Client::resizeButtonPressed()
+{
+ performWindowOperation(ResizeOp);
+}
+
+B2Client::B2Client(KDecorationBridge *b, KDecorationFactory *f)
+ : KDecoration(b, f), bar_x_ofs(0), in_unobs(0)
+{
+}
+
+void B2Client::init()
+{
+ const TQString tips[] = {
+ i18n("Menu"),
+ isOnAllDesktops() ?
+ i18n("Not on all desktops") : i18n("On all desktops"),
+ i18n("Minimize"), i18n("Maximize"),
+ i18n("Close"), i18n("Help"),
+ isSetShade() ? i18n("Unshade") : i18n("Shade"),
+ i18n("Resize")
+ };
+
+ // Check this early, otherwise the preview will be rendered badly.
+ resizable = isResizable();
+
+ createMainWidget((WFlags)(WResizeNoErase | WRepaintNoErase));
+ widget()->installEventFilter(this);
+
+ widget()->setBackgroundMode(NoBackground);
+
+ // Set button pointers to NULL so we know what has been created
+ for (int i = 0; i < BtnCount; i++)
+ button[i] = NULL;
+
+ g = new TQGridLayout(widget(), 3, 3);
+ // Left and right border width
+
+ leftSpacer = new TQSpacerItem(thickness, 16,
+ TQSizePolicy::Fixed, TQSizePolicy::Expanding);
+ rightSpacer = new TQSpacerItem(thickness, 16,
+ TQSizePolicy::Fixed, TQSizePolicy::Expanding);
+
+ g->addItem(leftSpacer, 1, 0);
+ g->addItem(rightSpacer, 1, 2);
+
+ // Top border height
+ topSpacer = new TQSpacerItem(10, buttonSize + 4,
+ TQSizePolicy::Expanding, TQSizePolicy::Fixed);
+ g->addItem(topSpacer, 0, 1);
+
+ // Bottom border height.
+ bottomSpacer = new TQSpacerItem(10,
+ thickness + (mustDrawHandle() ? 4 : 0),
+ TQSizePolicy::Expanding, TQSizePolicy::Fixed);
+ g->addItem(bottomSpacer, 2, 1);
+ if (isPreview()) {
+ TQLabel *previewLabel = new TQLabel(
+ i18n("<b><center>B II preview</center></b>"),
+ widget());
+ g->addWidget(previewLabel, 1, 1);
+
+ } else {
+ g->addItem(new TQSpacerItem(0, 0), 1, 1);
+ }
+
+ // titlebar
+ g->setRowSpacing(0, buttonSize + 4);
+
+ titlebar = new B2Titlebar(this);
+ titlebar->setMinimumWidth(buttonSize + 4);
+ titlebar->setFixedHeight(buttonSize + 4);
+
+ TQBoxLayout *titleLayout = new TQBoxLayout(titlebar,
+ TQBoxLayout::LeftToRight, 0, 1, 0);
+ titleLayout->addSpacing(3);
+
+ if (options()->customButtonPositions()) {
+ addButtons(options()->titleButtonsLeft(), tips, titlebar, titleLayout);
+ titleLayout->addItem(titlebar->captionSpacer);
+ addButtons(options()->titleButtonsRight(), tips, titlebar, titleLayout);
+ } else {
+ addButtons("MSH", tips, titlebar, titleLayout);
+ titleLayout->addItem(titlebar->captionSpacer);
+ addButtons("IAX", tips, titlebar, titleLayout);
+ }
+
+ titleLayout->addSpacing(3);
+
+ TQColor c = options()->colorGroup(KDecoration::ColorTitleBar, isActive()).
+ color(TQColorGroup::Button);
+
+ for (int i = 0; i < BtnCount; i++) {
+ if (button[i])
+ button[i]->setBg(c);
+ }
+
+ titlebar->updateGeometry();
+ positionButtons();
+ titlebar->recalcBuffer();
+ titlebar->installEventFilter(this);
+}
+
+bool B2Client::isModalSystemNotification()
+{
+ unsigned char *data = 0;
+ Atom actual;
+ int format, result;
+ unsigned long n, left;
+ Atom kde_wm_system_modal_notification;
+ kde_wm_system_modal_notification = XInternAtom(tqt_xdisplay(), "_TDE_WM_MODAL_SYS_NOTIFICATION", False);
+ result = XGetWindowProperty(tqt_xdisplay(), windowId(), kde_wm_system_modal_notification, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
+ if (result == Success && data != None && format == 32 )
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void B2Client::addButtons(const TQString& s, const TQString tips[],
+ B2Titlebar* tb, TQBoxLayout* titleLayout)
+{
+ if (s.length() <= 0)
+ return;
+
+ for (unsigned int i = 0; i < s.length(); i++) {
+ switch (s[i].latin1()) {
+ case 'M': // Menu button
+ if (!isModalSystemNotification()) {
+ if (!button[BtnMenu]) {
+ button[BtnMenu] = new B2Button(this, tb, tips[BtnMenu],
+ Qt::LeftButton | Qt::RightButton);
+ button[BtnMenu]->setPixmaps(P_MENU);
+ button[BtnMenu]->setUseMiniIcon();
+ connect(button[BtnMenu], TQT_SIGNAL(pressed()),
+ this, TQT_SLOT(menuButtonPressed()));
+ titleLayout->addWidget(button[BtnMenu]);
+ }
+ }
+ break;
+ case 'S': // Sticky button
+ if (!isModalSystemNotification()) {
+ if (!button[BtnSticky]) {
+ button[BtnSticky] = new B2Button(this, tb, tips[BtnSticky]);
+ button[BtnSticky]->setPixmaps(P_PINUP);
+ button[BtnSticky]->setToggle();
+ button[BtnSticky]->setDown(isOnAllDesktops());
+ connect(button[BtnSticky], TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(toggleOnAllDesktops()));
+ titleLayout->addWidget(button[BtnSticky]);
+ }
+ }
+ break;
+ case 'H': // Help button
+ if (providesContextHelp() && (!button[BtnHelp])) {
+ button[BtnHelp] = new B2Button(this, tb, tips[BtnHelp]);
+ button[BtnHelp]->setPixmaps(P_HELP);
+ connect(button[BtnHelp], TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(showContextHelp()));
+ titleLayout->addWidget(button[BtnHelp]);
+ }
+ break;
+ case 'I': // Minimize button
+ if (isMinimizable() && (!button[BtnIconify])) {
+ button[BtnIconify] = new B2Button(this, tb,tips[BtnIconify]);
+ button[BtnIconify]->setPixmaps(P_ICONIFY);
+ connect(button[BtnIconify], TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(minimize()));
+ titleLayout->addWidget(button[BtnIconify]);
+ }
+ break;
+ case 'A': // Maximize button
+ if (isMaximizable() && (!button[BtnMax])) {
+ button[BtnMax] = new B2Button(this, tb, tips[BtnMax],
+ Qt::LeftButton | Qt::MidButton | Qt::RightButton);
+ button[BtnMax]->setPixmaps(maximizeMode() == MaximizeFull ?
+ P_NORMALIZE : P_MAX);
+ connect(button[BtnMax], TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(maxButtonClicked()));
+ titleLayout->addWidget(button[BtnMax]);
+ }
+ break;
+ case 'X': // Close button
+ if (isCloseable() && !button[BtnClose]) {
+ button[BtnClose] = new B2Button(this, tb, tips[BtnClose]);
+ button[BtnClose]->setPixmaps(P_CLOSE);
+ connect(button[BtnClose], TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(closeWindow()));
+ titleLayout->addWidget(button[BtnClose]);
+ }
+ break;
+ case 'L': // Shade button
+ if (isShadeable() && !button[BtnShade]) {
+ button[BtnShade] = new B2Button(this, tb, tips[BtnShade]);
+ button[BtnShade]->setPixmaps(P_SHADE);
+ connect(button[BtnShade], TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(shadeButtonClicked()));
+ titleLayout->addWidget(button[BtnShade]);
+ }
+ break;
+ case 'R': // Resize button
+ if (resizable && !button[BtnResize]) {
+ button[BtnResize] = new B2Button(this, tb, tips[BtnResize]);
+ button[BtnResize]->setPixmaps(P_RESIZE);
+ connect(button[BtnResize], TQT_SIGNAL(pressed()),
+ this, TQT_SLOT(resizeButtonPressed()));
+ titleLayout->addWidget(button[BtnResize]);
+ }
+ break;
+ case '_': // Additional spacing
+ titleLayout->addSpacing(4);
+ break;
+ }
+ }
+}
+
+bool B2Client::mustDrawHandle() const
+{
+ if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
+ return false;
+ } else {
+ return do_draw_handle && resizable;
+ }
+}
+
+void B2Client::iconChange()
+{
+ if (button[BtnMenu])
+ button[BtnMenu]->repaint(false);
+}
+
+// Gallium: New button show/hide magic for customizable
+// button positions.
+void B2Client::calcHiddenButtons()
+{
+ // Hide buttons in this order:
+ // Shade, Sticky, Help, Resize, Maximize, Minimize, Close, Menu
+ B2Button* btnArray[] = {
+ button[BtnShade], button[BtnSticky], button[BtnHelp], button[BtnResize],
+ button[BtnMax], button[BtnIconify], button[BtnClose], button[BtnMenu]
+ };
+ int minWidth = 120;
+ int currentWidth = width();
+ int count = 0;
+ int i;
+
+ // Determine how many buttons we need to hide
+ while (currentWidth < minWidth) {
+ currentWidth += buttonSize + 1; // Allow for spacer (extra 1pix)
+ count++;
+ }
+ // Bound the number of buttons to hide
+ if (count > BtnCount) count = BtnCount;
+
+ // Hide the required buttons
+ for (i = 0; i < count; i++) {
+ if (btnArray[i] && btnArray[i]->isVisible())
+ btnArray[i]->hide();
+ }
+ // Show the rest of the buttons
+ for (i = count; i < BtnCount; i++) {
+ if (btnArray[i] && (!btnArray[i]->isVisible()))
+ btnArray[i]->show();
+ }
+}
+
+void B2Client::resizeEvent(TQResizeEvent * /*e*/)
+{
+ calcHiddenButtons();
+ titlebar->layout()->activate();
+ positionButtons();
+
+ /* may be the resize cut off some space occupied by titlebar, which
+ was moved, so instead of reducing it, we first try to move it */
+ titleMoveAbs(bar_x_ofs);
+
+ doShape();
+ widget()->repaint(); // the frame is misrendered without this
+}
+
+void B2Client::captionChange()
+{
+ positionButtons();
+ titleMoveAbs(bar_x_ofs);
+ doShape();
+ titlebar->recalcBuffer();
+ titlebar->repaint(false);
+}
+
+void B2Client::paintEvent(TQPaintEvent* e)
+{
+ TQPainter p(widget());
+
+ KDecoration::ColorType frameColorGroup = colored_frame ?
+ KDecoration::ColorTitleBar : KDecoration::ColorFrame;
+
+ TQRect t = titlebar->geometry();
+
+ // Frame height, this is used a lot of times
+ int fHeight = height() - t.height();
+
+ // distance from the bottom border - it is different if window is resizable
+ int bb = mustDrawHandle() ? 4 : 0;
+ int bDepth = thickness + bb;
+
+ TQColorGroup fillColor = options()->colorGroup(frameColorGroup, isActive());
+ TQBrush fillBrush(options()->color(frameColorGroup, isActive()));
+
+ // outer frame rect
+ p.drawRect(0, t.bottom() - thickness + 1,
+ width(), fHeight - bb + thickness);
+
+ if (thickness >= 2) {
+ // inner window rect
+ p.drawRect(thickness - 1, t.bottom(),
+ width() - 2 * (thickness - 1), fHeight - bDepth + 2);
+
+ if (thickness >= 3) {
+ // frame shade panel
+ qDrawShadePanel(&p, 1, t.bottom() - thickness + 2,
+ width() - 2, fHeight - 2 - bb + thickness, fillColor, false);
+ if (thickness == 4) {
+ p.setPen(fillColor.background());
+ p.drawRect(thickness - 2, t.bottom() - 1,
+ width() - 2 * (thickness - 2), fHeight + 4 - bDepth);
+ } else if (thickness > 4) {
+ qDrawShadePanel(&p, thickness - 2,
+ t.bottom() - 1, width() - 2 * (thickness - 2),
+ fHeight + 4 - bDepth, fillColor, true);
+ if (thickness >= 5) {
+ // draw frame interior
+ p.fillRect(2, t.bottom() - thickness + 3,
+ width() - 4, thickness - 4, fillBrush);
+ p.fillRect(2, height() - bDepth + 2,
+ width() - 4, thickness - 4, fillBrush);
+ p.fillRect(2, t.bottom() - 1,
+ thickness - 4, fHeight - bDepth + 4, fillBrush);
+ p.fillRect(width() - thickness + 2, t.bottom() - 1,
+ thickness - 4, fHeight - bDepth + 4, fillBrush);
+ }
+ }
+ }
+ }
+
+ // bottom handle rect
+ if (mustDrawHandle()) {
+ p.setPen(Qt::black);
+ int hx = width() - 40;
+ int hw = 40;
+
+ p.drawLine(width() - 1, height() - thickness - 4,
+ width() - 1, height() - 1);
+ p.drawLine(hx, height() - 1, width() - 1, height() - 1);
+ p.drawLine(hx, height() - 4, hx, height() - 1);
+
+ p.fillRect(hx + 1, height() - thickness - 3,
+ hw - 2, thickness + 2, fillBrush);
+
+ p.setPen(fillColor.dark());
+ p.drawLine(width() - 2, height() - thickness - 4,
+ width() - 2, height() - 2);
+ p.drawLine(hx + 1, height() - 2, width() - 2, height() - 2);
+
+ p.setPen(fillColor.light());
+ p.drawLine(hx + 1, height() - thickness - 2,
+ hx + 1, height() - 3);
+ p.drawLine(hx + 1, height() - thickness - 3,
+ width() - 3, height() - thickness - 3);
+ }
+
+ /* OK, we got a paint event, which means parts of us are now visible
+ which were not before. We try the titlebar if it is currently fully
+ obscured, and if yes, try to unobscure it, in the hope that some
+ of the parts which we just painted were in the titlebar area.
+ It can happen, that the titlebar, as it got the FullyObscured event
+ had no chance of becoming partly visible. The problem is, that
+ we now might have the space available, but the titlebar gets no
+ visibilitinotify events until its state changes, so we just try
+ */
+ if (titlebar->isFullyObscured()) {
+ /* We first see, if our repaint contained the titlebar area */
+ TQRegion reg(TQRect(0, 0, width(), buttonSize + 4));
+ reg = reg.intersect(e->region());
+ if (!reg.isEmpty())
+ unobscureTitlebar();
+ }
+}
+
+void B2Client::doShape()
+{
+ TQRect t = titlebar->geometry();
+ TQRegion mask(widget()->rect());
+ // top to the tilebar right
+ if (bar_x_ofs) {
+ // left from bar
+ mask -= TQRect(0, 0, bar_x_ofs, t.height() - thickness);
+ // top left point
+ mask -= TQRect(0, t.height() - thickness, 1, 1);
+ }
+ if (t.right() < width() - 1) {
+ mask -= TQRect(width() - 1,
+ t.height() - thickness, 1, 1); //top right point
+ mask -= TQRect(t.right() + 1, 0,
+ width() - t.right() - 1, t.height() - thickness);
+ }
+ // bottom right point
+ mask -= TQRect(width() - 1, height() - 1, 1, 1);
+ if (mustDrawHandle()) {
+ // bottom left point
+ mask -= TQRect(0, height() - 5, 1, 1);
+ // handle left point
+ mask -= TQRect(width() - 40, height() - 1, 1, 1);
+ // bottom left
+ mask -= TQRect(0, height() - 4, width() - 40, 4);
+ } else {
+ // bottom left point
+ mask -= TQRect(0, height() - 1, 1, 1);
+ }
+
+ setMask(mask);
+}
+
+void B2Client::showEvent(TQShowEvent *)
+{
+ calcHiddenButtons();
+ positionButtons();
+ doShape();
+}
+
+KDecoration::Position B2Client::mousePosition(const TQPoint& p) const
+{
+ const int range = 16;
+ TQRect t = titlebar->geometry();
+ t.setHeight(buttonSize + 4 - thickness);
+ int ly = t.bottom();
+ int lx = t.right();
+ int bb = mustDrawHandle() ? 0 : 5;
+
+ if (p.x() > t.right()) {
+ if (p.y() <= ly + range && p.x() >= width() - range)
+ return PositionTopRight;
+ else if (p.y() <= ly + thickness)
+ return PositionTop;
+ } else if (p.x() < bar_x_ofs) {
+ if (p.y() <= ly + range && p.x() <= range)
+ return PositionTopLeft;
+ else if (p.y() <= ly + thickness)
+ return PositionTop;
+ } else if (p.y() < ly) {
+ if (p.x() > bar_x_ofs + thickness &&
+ p.x() < lx - thickness && p.y() > thickness)
+ return KDecoration::mousePosition(p);
+ if (p.x() > bar_x_ofs + range && p.x() < lx - range)
+ return PositionTop;
+ if (p.y() <= range) {
+ if (p.x() <= bar_x_ofs + range)
+ return PositionTopLeft;
+ else return PositionTopRight;
+ } else {
+ if (p.x() <= bar_x_ofs + range)
+ return PositionLeft;
+ else return PositionRight;
+ }
+ }
+
+ if (p.y() >= height() - 8 + bb) {
+ /* the normal Client:: only wants border of 4 pixels */
+ if (p.x() <= range) return PositionBottomLeft;
+ if (p.x() >= width() - range) return PositionBottomRight;
+ return PositionBottom;
+ }
+
+ return KDecoration::mousePosition(p);
+}
+
+void B2Client::titleMoveAbs(int new_ofs)
+{
+ if (new_ofs < 0) new_ofs = 0;
+ if (new_ofs + titlebar->width() > width()) {
+ new_ofs = width() - titlebar->width();
+ }
+ if (bar_x_ofs != new_ofs) {
+ bar_x_ofs = new_ofs;
+ positionButtons();
+ doShape();
+ widget()->repaint(0, 0, width(), buttonSize + 4, false);
+ titlebar->repaint(false);
+ }
+}
+
+void B2Client::titleMoveRel(int xdiff)
+{
+ titleMoveAbs(bar_x_ofs + xdiff);
+}
+
+void B2Client::desktopChange()
+{
+ bool on = isOnAllDesktops();
+ if (B2Button *b = button[BtnSticky]) {
+ b->setDown(on);
+ TQToolTip::remove(b);
+ TQToolTip::add(b,
+ on ? i18n("Not on all desktops") : i18n("On all desktops"));
+ }
+}
+
+void B2Client::maximizeChange()
+{
+ bool m = maximizeMode() == MaximizeFull;
+ if (button[BtnMax]) {
+ button[BtnMax]->setPixmaps(m ? P_NORMALIZE : P_MAX);
+ button[BtnMax]->repaint();
+ TQToolTip::remove(button[BtnMax]);
+ TQToolTip::add(button[BtnMax],
+ m ? i18n("Restore") : i18n("Maximize"));
+ }
+ bottomSpacer->changeSize(10, thickness + (mustDrawHandle() ? 4 : 0),
+ TQSizePolicy::Expanding, TQSizePolicy::Minimum);
+
+ g->activate();
+ doShape();
+ widget()->repaint(false);
+}
+
+void B2Client::activeChange()
+{
+ widget()->repaint(false);
+ titlebar->repaint(false);
+
+ TQColor c = options()->colorGroup(
+ KDecoration::ColorTitleBar, isActive()).color(TQColorGroup::Button);
+
+ for (int i = 0; i < BtnCount; i++)
+ if (button[i]) {
+ button[i]->setBg(c);
+ button[i]->repaint(false);
+ }
+}
+
+void B2Client::shadeChange()
+{
+ bottomSpacer->changeSize(10, thickness + (mustDrawHandle() ? 4 : 0),
+ TQSizePolicy::Expanding, TQSizePolicy::Minimum);
+ g->activate();
+ doShape();
+ if (B2Button *b = button[BtnShade]) {
+ TQToolTip::remove(b);
+ TQToolTip::add(b, isSetShade() ? i18n("Unshade") : i18n("Shade"));
+ }
+}
+
+TQSize B2Client::minimumSize() const
+{
+ int left, right, top, bottom;
+ borders(left, right, top, bottom);
+ return TQSize(left + right + 2 * buttonSize, top + bottom);
+}
+
+void B2Client::resize(const TQSize& s)
+{
+ widget()->resize(s);
+}
+
+void B2Client::borders(int &left, int &right, int &top, int &bottom) const
+{
+ left = right = thickness;
+ top = buttonSize + 4;
+ bottom = thickness + (mustDrawHandle() ? 4 : 0);
+}
+
+void B2Client::menuButtonPressed()
+{
+ static B2Client *lastClient = NULL;
+
+ bool dbl = (lastClient == this &&
+ time.elapsed() <= TQApplication::doubleClickInterval());
+ lastClient = this;
+ time.start();
+ if (!dbl) {
+ KDecorationFactory* f = factory();
+ TQRect menuRect = button[BtnMenu]->rect();
+ TQPoint menuTop = button[BtnMenu]->mapToGlobal(menuRect.topLeft());
+ TQPoint menuBottom = button[BtnMenu]->mapToGlobal(menuRect.bottomRight());
+ showWindowMenu(TQRect(menuTop, menuBottom));
+ if (!f->exists(this)) // 'this' was destroyed
+ return;
+ button[BtnMenu]->setDown(false);
+ } else {
+ switch (menu_dbl_click_op) {
+ case B2::MinimizeOp:
+ minimize();
+ break;
+ case B2::ShadeOp:
+ setShade(!isSetShade());
+ break;
+ case B2::CloseOp:
+ closeWindow();
+ break;
+ case B2::NoOp:
+ default:
+ break;
+ }
+ }
+}
+
+void B2Client::unobscureTitlebar()
+{
+ /* we just noticed, that we got obscured by other windows
+ so we look at all windows above us (stacking_order) merging their
+ masks, intersecting it with our titlebar area, and see if we can
+ find a place not covered by any window */
+ if (in_unobs) {
+ return;
+ }
+ in_unobs = 1;
+ TQRegion reg(TQRect(0,0,width(), buttonSize + 4));
+ reg = unobscuredRegion(reg);
+ if (!reg.isEmpty()) {
+ // there is at least _one_ pixel from our title area, which is not
+ // obscured, we use the first rect we find
+ // for a first test, we use boundingRect(), later we may refine
+ // to rect(), and search for the nearest, or biggest, or smthg.
+ titleMoveAbs(reg.boundingRect().x());
+ }
+ in_unobs = 0;
+}
+
+static void redraw_pixmaps()
+{
+ int i;
+ TQColorGroup aGrp = options()->colorGroup(KDecoration::ColorButtonBg, true);
+ TQColorGroup iGrp = options()->colorGroup(KDecoration::ColorButtonBg, false);
+
+ // close
+ drawB2Rect(PIXMAP_A(P_CLOSE), aGrp.button(), false);
+ drawB2Rect(PIXMAP_AH(P_CLOSE), aGrp.button(), true);
+ drawB2Rect(PIXMAP_AD(P_CLOSE), aGrp.button(), true);
+
+ drawB2Rect(PIXMAP_I(P_CLOSE), iGrp.button(), false);
+ drawB2Rect(PIXMAP_IH(P_CLOSE), iGrp.button(), true);
+ drawB2Rect(PIXMAP_ID(P_CLOSE), iGrp.button(), true);
+
+ // shade
+ KPixmap thinBox;
+ thinBox.resize(buttonSize - 2, 6);
+ for (i = 0; i < NumStates; i++) {
+ bool is_act = (i < 2);
+ bool is_down = ((i & 1) == 1);
+ KPixmap *pix = pixmap[P_SHADE * NumStates + i];
+ TQColor color = is_act ? aGrp.button() : iGrp.button();
+ drawB2Rect(&thinBox, color, is_down);
+ pix->fill(Qt::black);
+ bitBlt(TQT_TQPAINTDEVICE(pix), 0, 0, TQT_TQPAINTDEVICE(&thinBox),
+ 0, 0, thinBox.width(), thinBox.height(), TQt::CopyROP, true);
+ }
+
+ // maximize
+ for (i = 0; i < NumStates; i++) {
+ *pixmap[P_MAX * NumStates + i] = *pixmap[P_CLOSE * NumStates + i];
+ pixmap[P_MAX * NumStates + i]->detach();
+ }
+
+ // normalize + iconify
+ KPixmap smallBox;
+ smallBox.resize(10, 10);
+ KPixmap largeBox;
+ largeBox.resize(12, 12);
+
+ for (i = 0; i < NumStates; i++) {
+ bool is_act = (i < 3);
+ bool is_down = (i == Down || i == IDown);
+ KPixmap *pix = pixmap[P_NORMALIZE * NumStates + i];
+ drawB2Rect(&smallBox, is_act ? aGrp.button() : iGrp.button(), is_down);
+ drawB2Rect(&largeBox, is_act ? aGrp.button() : iGrp.button(), is_down);
+ pix->fill(options()->color(KDecoration::ColorTitleBar, is_act));
+ bitBlt(TQT_TQPAINTDEVICE(pix), pix->width() - 12, pix->width() - 12, TQT_TQPAINTDEVICE(&largeBox),
+ 0, 0, 12, 12, TQt::CopyROP, true);
+ bitBlt(TQT_TQPAINTDEVICE(pix), 0, 0, TQT_TQPAINTDEVICE(&smallBox), 0, 0, 10, 10, TQt::CopyROP, true);
+
+ bitBlt(TQT_TQPAINTDEVICE(pixmap[P_ICONIFY * NumStates + i]), 0, 0,
+ TQT_TQPAINTDEVICE(&smallBox), 0, 0, 10, 10, TQt::CopyROP, true);
+ }
+
+ // resize
+ for (i = 0; i < NumStates; i++) {
+ bool is_act = (i < 3);
+ bool is_down = (i == Down || i == IDown);
+ *pixmap[P_RESIZE * NumStates + i] = *pixmap[P_CLOSE * NumStates + i];
+ pixmap[P_RESIZE * NumStates + i]->detach();
+ drawB2Rect(&smallBox, is_act ? aGrp.button() : iGrp.button(), is_down);
+ bitBlt(TQT_TQPAINTDEVICE(pixmap[P_RESIZE * NumStates + i]),
+ 0, 0, TQT_TQPAINTDEVICE(&smallBox), 0, 0, 10, 10, TQt::CopyROP, true);
+ }
+
+
+ TQPainter p;
+ // x for close + menu + help
+ for (int j = 0; j < 3; j++) {
+ int pix;
+ unsigned const char *light, *dark;
+ switch (j) {
+ case 0:
+ pix = P_CLOSE; light = close_white_bits; dark = close_dgray_bits;
+ break;
+ case 1:
+ pix = P_MENU; light = menu_white_bits; dark = menu_dgray_bits;
+ break;
+ default:
+ pix = P_HELP; light = help_light_bits; dark = help_dark_bits;
+ break;
+ }
+ int off = (pixmap[pix * NumStates]->width() - 16) / 2;
+ for (i = 0; i < NumStates; i++) {
+ p.begin(pixmap[pix * NumStates + i]);
+ kColorBitmaps(&p, (i < 3) ? aGrp : iGrp, off, off, 16, 16, true,
+ light, NULL, NULL, dark, NULL, NULL);
+ p.end();
+ }
+ }
+
+ // pin
+ for (i = 0; i < NumStates; i++) {
+ bool isDown = (i == Down || i == IDown);
+ unsigned const char *white = isDown ? pindown_white_bits : pinup_white_bits;
+ unsigned const char *gray = isDown ? pindown_gray_bits : pinup_gray_bits;
+ unsigned const char *dgray =isDown ? pindown_dgray_bits : pinup_dgray_bits;
+ p.begin(pixmap[P_PINUP * NumStates + i]);
+ kColorBitmaps(&p, (i < 3) ? aGrp : iGrp, 0, 0, 16, 16, true, white,
+ gray, NULL, dgray, NULL, NULL);
+ p.end();
+ }
+
+ // Apply the hilight effect to the 'Hover' icons
+ TDEIconEffect ie;
+ TQPixmap hilighted;
+ for (i = 0; i < P_NUM_BUTTON_TYPES; i++) {
+ int offset = i * NumStates;
+ hilighted = ie.apply(*pixmap[offset + Norm],
+ TDEIcon::Small, TDEIcon::ActiveState);
+ *pixmap[offset + Hover] = hilighted;
+
+ hilighted = ie.apply(*pixmap[offset + INorm],
+ TDEIcon::Small, TDEIcon::ActiveState);
+ *pixmap[offset + IHover] = hilighted;
+ }
+
+
+ // Create the titlebar gradients
+ if (TQPixmap::defaultDepth() > 8) {
+ TQColor titleColor[4] = {
+ options()->color(KDecoration::ColorTitleBar, true),
+ options()->color(KDecoration::ColorFrame, true),
+
+ options()->color(KDecoration::ColorTitleBlend, false),
+ options()->color(KDecoration::ColorTitleBar, false)
+ };
+
+ if (colored_frame) {
+ titleColor[0] = options()->color(KDecoration::ColorTitleBlend, true);
+ titleColor[1] = options()->color(KDecoration::ColorTitleBar, true);
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (titleColor[2 * i] != titleColor[2 * i + 1]) {
+ if (!titleGradient[i]) {
+ titleGradient[i] = new KPixmap;
+ }
+ titleGradient[i]->resize(64, buttonSize + 3);
+ KPixmapEffect::gradient(*titleGradient[i],
+ titleColor[2 * i], titleColor[2 * i + 1],
+ KPixmapEffect::VerticalGradient);
+ } else {
+ delete titleGradient[i];
+ titleGradient[i] = 0;
+ }
+ }
+ }
+}
+
+void B2Client::positionButtons()
+{
+ TQFontMetrics fm(options()->font(isActive()));
+ TQString cap = caption();
+ if (cap.length() < 5) // make sure the titlebar has sufficiently wide
+ cap = "XXXXX"; // area for dragging the window
+ int textLen = fm.width(cap);
+
+ TQRect t = titlebar->captionSpacer->geometry();
+ int titleWidth = titlebar->width() - t.width() + textLen + 2;
+ if (titleWidth > width()) titleWidth = width();
+
+ titlebar->resize(titleWidth, buttonSize + 4);
+ titlebar->move(bar_x_ofs, 0);
+}
+
+// Transparent bound stuff.
+
+static TQRect *visible_bound;
+static TQPointArray bound_shape;
+
+bool B2Client::drawbound(const TQRect& geom, bool clear)
+{
+ if (clear) {
+ if (!visible_bound) return true;
+ }
+
+ if (!visible_bound) {
+ visible_bound = new TQRect(geom);
+ TQRect t = titlebar->geometry();
+ int frameTop = geom.top() + t.bottom();
+ int barLeft = geom.left() + bar_x_ofs;
+ int barRight = barLeft + t.width() - 1;
+ if (barRight > geom.right()) barRight = geom.right();
+ // line width is 5 pixels, so compensate for the 2 outer pixels (#88657)
+ TQRect g = geom;
+ g.setLeft( g.left() + 2 );
+ g.setTop( g.top() + 2 );
+ g.setRight( g.right() - 2 );
+ g.setBottom( g.bottom() - 2 );
+ frameTop += 2;
+ barLeft += 2;
+ barRight -= 2;
+
+ bound_shape.putPoints(0, 8,
+ g.left(), frameTop,
+ barLeft, frameTop,
+ barLeft, g.top(),
+ barRight, g.top(),
+ barRight, frameTop,
+ g.right(), frameTop,
+ g.right(), g.bottom(),
+ g.left(), g.bottom());
+ } else {
+ *visible_bound = geom;
+ }
+ TQPainter p(workspaceWidget());
+ p.setPen(TQPen(Qt::white, 5));
+ p.setRasterOp(TQt::XorROP);
+ p.drawPolygon(bound_shape);
+
+ if (clear) {
+ delete visible_bound;
+ visible_bound = 0;
+ }
+ return true;
+}
+
+bool B2Client::eventFilter(TQObject *o, TQEvent *e)
+{
+ if (TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(widget()))
+ return false;
+ switch (e->type()) {
+ case TQEvent::Resize:
+ resizeEvent(TQT_TQRESIZEEVENT(e));
+ return true;
+ case TQEvent::Paint:
+ paintEvent(TQT_TQPAINTEVENT(e));
+ return true;
+ case TQEvent::MouseButtonDblClick:
+ titlebar->mouseDoubleClickEvent(TQT_TQMOUSEEVENT(e));
+ return true;
+ case TQEvent::Wheel:
+ titlebar->wheelEvent(TQT_TQWHEELEVENT(e));
+ return true;
+ case TQEvent::MouseButtonPress:
+ processMousePressEvent(TQT_TQMOUSEEVENT(e));
+ return true;
+ case TQEvent::Show:
+ showEvent(TQT_TQSHOWEVENT(e));
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+// =====================================
+
+B2Button::B2Button(B2Client *_client, TQWidget *parent,
+ const TQString& tip, const int realizeBtns)
+ : TQButton(parent, 0), hover(false)
+{
+ setBackgroundMode(NoBackground);
+ setCursor(tqarrowCursor);
+ realizeButtons = realizeBtns;
+ client = _client;
+ useMiniIcon = false;
+ setFixedSize(buttonSize, buttonSize);
+ TQToolTip::add(this, tip);
+}
+
+
+TQSize B2Button::sizeHint() const
+{
+ return TQSize(buttonSize, buttonSize);
+}
+
+TQSizePolicy B2Button::sizePolicy() const
+{
+ return(TQSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Fixed));
+}
+
+void B2Button::drawButton(TQPainter *p)
+{
+ KPixmap* gradient = titleGradient[client->isActive() ? 0 : 1];
+ if (gradient) {
+ p->drawTiledPixmap(0, 0, buttonSize, buttonSize, *gradient, 0, 2);
+ } else {
+ p->fillRect(rect(), bg);
+ }
+ if (useMiniIcon) {
+ TQPixmap miniIcon = client->icon().pixmap(TQIconSet::Small,
+ client->isActive() ? TQIconSet::Normal : TQIconSet::Disabled);
+ p->drawPixmap((width() - miniIcon.width()) / 2,
+ (height() - miniIcon.height()) / 2, miniIcon);
+ } else {
+ int type;
+ if (client->isActive()) {
+ if (isOn() || isDown())
+ type = Down;
+ else if (hover)
+ type = Hover;
+ else
+ type = Norm;
+ } else {
+ if (isOn() || isDown())
+ type = IDown;
+ else if (hover)
+ type = IHover;
+ else
+ type = INorm;
+ }
+ p->drawPixmap((width() - icon[type]->width()) / 2,
+ (height() - icon[type]->height()) / 2, *icon[type]);
+ }
+}
+
+void B2Button::setPixmaps(int button_id)
+{
+ button_id *= NumStates;
+ for (int i = 0; i < NumStates; i++) {
+ icon[i] = B2::pixmap[button_id + i];
+ }
+ repaint(false);
+}
+
+void B2Button::mousePressEvent(TQMouseEvent * e)
+{
+ last_button = e->button();
+ TQMouseEvent me(e->type(), e->pos(), e->globalPos(),
+ (e->button() & realizeButtons) ? Qt::LeftButton : Qt::NoButton,
+ e->state());
+ TQButton::mousePressEvent(&me);
+}
+
+void B2Button::mouseReleaseEvent(TQMouseEvent * e)
+{
+ last_button = e->button();
+ TQMouseEvent me(e->type(), e->pos(), e->globalPos(),
+ (e->button() & realizeButtons) ? Qt::LeftButton : Qt::NoButton,
+ e->state());
+ TQButton::mouseReleaseEvent(&me);
+}
+
+void B2Button::enterEvent(TQEvent *e)
+{
+ hover = true;
+ repaint(false);
+ TQButton::enterEvent(e);
+}
+
+void B2Button::leaveEvent(TQEvent *e)
+{
+ hover = false;
+ repaint(false);
+ TQButton::leaveEvent(e);
+}
+
+// =====================================
+
+B2Titlebar::B2Titlebar(B2Client *parent)
+ : TQWidget(parent->widget(), 0, (WFlags)(WStyle_Customize | WRepaintNoErase)),
+ client(parent),
+ set_x11mask(false), isfullyobscured(false), shift_move(false)
+{
+ setBackgroundMode(NoBackground);
+ captionSpacer = new TQSpacerItem(buttonSize, buttonSize + 4,
+ TQSizePolicy::Expanding, TQSizePolicy::Fixed);
+}
+
+bool B2Titlebar::x11Event(XEvent *e)
+{
+ if (!set_x11mask) {
+ set_x11mask = true;
+ XSelectInput(tqt_xdisplay(), winId(),
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ KeymapStateMask |
+ ButtonMotionMask |
+ EnterWindowMask | LeaveWindowMask |
+ FocusChangeMask |
+ ExposureMask |
+ PropertyChangeMask |
+ StructureNotifyMask | SubstructureRedirectMask |
+ VisibilityChangeMask);
+ }
+ switch (e->type) {
+ case VisibilityNotify:
+ isfullyobscured = false;
+ if (e->xvisibility.state == VisibilityFullyObscured) {
+ isfullyobscured = true;
+ client->unobscureTitlebar();
+ }
+ break;
+ default:
+ break;
+ }
+ return TQWidget::x11Event(e);
+}
+
+void B2Titlebar::drawTitlebar(TQPainter &p, bool state)
+{
+ KPixmap* gradient = titleGradient[state ? 0 : 1];
+
+ TQRect t = rect();
+ // black titlebar frame
+ p.setPen(Qt::black);
+ p.drawLine(0, 0, 0, t.bottom());
+ p.drawLine(0, 0, t.right(), 0);
+ p.drawLine(t.right(), 0, t.right(), t.bottom());
+
+ // titlebar fill
+ const TQColorGroup cg =
+ options()->colorGroup(KDecoration::ColorTitleBar, state);
+ TQBrush brush(cg.background());
+ if (gradient) brush.setPixmap(*gradient);
+ qDrawShadeRect(&p, 1, 1, t.right() - 1, t.height() - 1,
+ cg, false, 1, 0, &brush);
+
+ // and the caption
+ p.setPen(options()->color(KDecoration::ColorFont, state));
+ p.setFont(options()->font(state));
+ t = captionSpacer->geometry();
+ p.drawText(t, AlignLeft | AlignVCenter, client->caption());
+}
+
+void B2Titlebar::recalcBuffer()
+{
+ titleBuffer.resize(width(), height());
+
+ TQPainter p(&titleBuffer);
+ drawTitlebar(p, true);
+ oldTitle = caption();
+}
+
+void B2Titlebar::resizeEvent(TQResizeEvent *)
+{
+ recalcBuffer();
+ repaint(false);
+}
+
+
+void B2Titlebar::paintEvent(TQPaintEvent *)
+{
+ if(client->isActive())
+ bitBlt(TQT_TQPAINTDEVICE(this), 0, 0, TQT_TQPAINTDEVICE(&titleBuffer), 0, 0, titleBuffer.width(),
+ titleBuffer.height(), TQt::CopyROP, true);
+ else {
+ TQPainter p(this);
+ drawTitlebar(p, false);
+ }
+}
+
+void B2Titlebar::mouseDoubleClickEvent(TQMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton && e->y() < height()) {
+ client->titlebarDblClickOperation();
+ }
+}
+
+void B2Titlebar::wheelEvent(TQWheelEvent *e)
+{
+ if (client->isSetShade() || TQT_TQRECT_OBJECT(rect()).contains(e->pos()))
+ client->titlebarMouseWheelOperation( e->delta());
+}
+
+void B2Titlebar::mousePressEvent(TQMouseEvent * e)
+{
+ shift_move = e->state() & ShiftButton;
+ if (shift_move) {
+ moveOffset = e->globalPos();
+ } else {
+ e->ignore();
+ }
+}
+
+void B2Titlebar::mouseReleaseEvent(TQMouseEvent * e)
+{
+ if (shift_move) shift_move = false;
+ else e->ignore();
+}
+
+void B2Titlebar::mouseMoveEvent(TQMouseEvent * e)
+{
+ if (shift_move) {
+ int oldx = mapFromGlobal(moveOffset).x();
+ int xdiff = e->globalPos().x() - moveOffset.x();
+ moveOffset = e->globalPos();
+ if (oldx >= 0 && oldx <= rect().right()) {
+ client->titleMoveRel(xdiff);
+ }
+ } else {
+ e->ignore();
+ }
+}
+
+} // namespace B2
+
+#include "b2client.moc"
+
+// vim: sw=4
+
diff --git a/twin/clients/b2/b2client.h b/twin/clients/b2/b2client.h
new file mode 100644
index 00000000..30220b17
--- /dev/null
+++ b/twin/clients/b2/b2client.h
@@ -0,0 +1,167 @@
+/*
+ * B-II KWin Client
+ *
+ * Changes:
+ * Customizable button positions by Karol Szwed <gallium@kde.org>
+ * Ported to the trinity.2 API by Luciano Montanaro <mikelima@cirulla.net>
+ */
+
+#ifndef __B2CLIENT_H
+#define __B2CLIENT_H
+
+#include <tqvariant.h>
+#include <tqdatetime.h>
+#include <tqbutton.h>
+#include <tqbitmap.h>
+#include <kpixmap.h>
+#include <kdecoration.h>
+#include <kdecorationfactory.h>
+
+class TQSpacerItem;
+class TQBoxLayout;
+class TQGridLayout;
+
+namespace B2 {
+
+class B2Client;
+
+class B2Button : public TQButton
+{
+public:
+ B2Button(B2Client *_client=0, TQWidget *parent=0, const TQString& tip=NULL, const int realizeBtns = Qt::LeftButton);
+ ~B2Button() {};
+
+ void setBg(const TQColor &c){bg = c;}
+ void setPixmaps(KPixmap *pix, KPixmap *pixDown, KPixmap *iPix,
+ KPixmap *iPixDown);
+ void setPixmaps(int button_id);
+ void setToggle(){setToggleType(Toggle);}
+ void setActive(bool on){setOn(on);}
+ void setUseMiniIcon(){useMiniIcon = true;}
+ TQSize sizeHint() const;
+ TQSizePolicy sizePolicy() const;
+protected:
+ virtual void drawButton(TQPainter *p);
+ void drawButtonLabel(TQPainter *){;}
+
+ void mousePressEvent( TQMouseEvent* e );
+ void mouseReleaseEvent( TQMouseEvent* e );
+private:
+ void enterEvent(TQEvent *e);
+ void leaveEvent(TQEvent *e);
+
+ bool useMiniIcon;
+ KPixmap *icon[6];
+ TQColor bg; //only use one color (the rest is pixmap) so forget TQPalette ;)
+
+public:
+ B2Client* client;
+ ButtonState last_button;
+ int realizeButtons;
+ bool hover;
+};
+
+class B2Titlebar : public TQWidget
+{
+ friend class B2Client;
+public:
+ B2Titlebar(B2Client *parent);
+ ~B2Titlebar(){;}
+ bool isFullyObscured() const {return isfullyobscured;}
+ void recalcBuffer();
+ TQSpacerItem *captionSpacer;
+protected:
+ void paintEvent( TQPaintEvent* );
+ bool x11Event(XEvent *e);
+ void mouseDoubleClickEvent( TQMouseEvent * );
+ void wheelEvent(TQWheelEvent *);
+ void mousePressEvent( TQMouseEvent * );
+ void mouseReleaseEvent( TQMouseEvent * );
+ void mouseMoveEvent(TQMouseEvent *);
+ void resizeEvent(TQResizeEvent *ev);
+private:
+ void drawTitlebar(TQPainter &p, bool state);
+
+ B2Client *client;
+ TQString oldTitle;
+ KPixmap titleBuffer;
+ TQPoint moveOffset;
+ bool set_x11mask;
+ bool isfullyobscured;
+ bool shift_move;
+};
+
+class B2Client : public KDecoration
+{
+ Q_OBJECT
+ friend class B2Titlebar;
+public:
+ B2Client(KDecorationBridge *b, KDecorationFactory *f);
+ ~B2Client(){;}
+ void init();
+ void unobscureTitlebar();
+ void titleMoveAbs(int new_ofs);
+ void titleMoveRel(int xdiff);
+ // transparent stuff
+ virtual bool drawbound(const TQRect& geom, bool clear);
+protected:
+ void resizeEvent( TQResizeEvent* );
+ void paintEvent( TQPaintEvent* );
+ void showEvent( TQShowEvent* );
+ void windowWrapperShowEvent( TQShowEvent* );
+ void captionChange();
+ void desktopChange();
+ void shadeChange();
+ void activeChange();
+ void maximizeChange();
+ void iconChange();
+ void doShape();
+ Position mousePosition( const TQPoint& p ) const;
+ void resize(const TQSize&);
+ void borders(int &, int &, int &, int &) const;
+ TQSize minimumSize() const;
+ bool eventFilter(TQObject *, TQEvent *);
+private slots:
+ void menuButtonPressed();
+ //void slotReset();
+ void maxButtonClicked();
+ void shadeButtonClicked();
+ void resizeButtonPressed();
+private:
+ void addButtons(const TQString& s, const TQString tips[],
+ B2Titlebar* tb, TQBoxLayout* titleLayout);
+ void positionButtons();
+ void calcHiddenButtons();
+ bool mustDrawHandle() const;
+ bool isModalSystemNotification();
+
+ enum ButtonType{BtnMenu=0, BtnSticky, BtnIconify, BtnMax, BtnClose,
+ BtnHelp, BtnShade, BtnResize, BtnCount};
+ B2Button* button[BtnCount];
+ TQGridLayout *g;
+ // Border spacers
+ TQSpacerItem *topSpacer;
+ TQSpacerItem *bottomSpacer;
+ TQSpacerItem *leftSpacer;
+ TQSpacerItem *rightSpacer;
+ B2Titlebar *titlebar;
+ int bar_x_ofs;
+ int in_unobs;
+ TQTime time;
+ bool resizable;
+};
+
+class B2ClientFactory : public TQObject, public KDecorationFactory
+{
+public:
+ B2ClientFactory();
+ virtual ~B2ClientFactory();
+ virtual KDecoration *createDecoration(KDecorationBridge *);
+ virtual bool reset(unsigned long changed);
+ virtual bool supports( Ability ability );
+ TQValueList< B2ClientFactory::BorderSize > borderSizes() const;
+};
+
+}
+
+#endif
diff --git a/twin/clients/b2/bitmaps.h b/twin/clients/b2/bitmaps.h
new file mode 100644
index 00000000..2f610f4b
--- /dev/null
+++ b/twin/clients/b2/bitmaps.h
@@ -0,0 +1,98 @@
+#ifndef __STDCLIENT_BITMAPS_H
+#define __STDCLIENT_BITMAPS_H
+
+/**
+ * The standard client has the capability to color it's titlebar buttons
+ * according to the new color scheme. In order to do this it needs a bitmap
+ * for each shade which it draws into a pixmap with the appropriate color.
+ * These are all the bitmaps.
+ */
+
+static const unsigned char close_white_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x02,
+ 0x20, 0x01, 0x40, 0x00, 0x40, 0x00, 0x20, 0x01, 0x10, 0x02, 0x08, 0x04,
+ 0x04, 0x08, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char close_dgray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x18, 0x30, 0x30, 0x18, 0x60, 0x0c,
+ 0xc0, 0x06, 0x80, 0x03, 0x80, 0x03, 0xc0, 0x06, 0x60, 0x0c, 0x30, 0x18,
+ 0x18, 0x30, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char menu_white_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfc, 0x3f, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char menu_dgray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char menu_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfc, 0x3f, 0x04, 0x20, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pindown_white_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03,
+ 0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pindown_gray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+ 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pindown_dgray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20,
+ 0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e,
+ 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pindown_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xf0, 0x3f, 0xf0, 0x3f,
+ 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x0f,
+ 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_white_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11,
+ 0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_gray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_dgray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e,
+ 0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0xc0, 0x31, 0xc0, 0x3f,
+ 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xc0, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char help_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0xe0,0x03,0xf0,0x07,0x70,0x0e,0x60,0x0e,0x00,0x0f,0x80,
+ 0x07,0xc0,0x03,0xc0,0x01,0x80,0x01,0xc0,0x00,0xc0,0x01,0x80,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x4c,0x0b,0x08,0x58,0x65,0x09,0x08,0x90,0x00,0x00,
+ 0x00,0x09,0x04,0x00,0x00,0x72,0x6f,0x6f,0x74,0x00,0x24,0x31,0x24,0x47,0x6b,
+ 0x65,0x44,0x78,0x63 };
+
+static const unsigned char help_dark_bits[] = {
+ 0x00,0x00,0x00,0x00,0xe0,0x03,0x30,0x06,0x30,0x06,0x00,0x06,0x00,0x03,0x80,
+ 0x01,0xc0,0x00,0xc0,0x00,0x00,0x00,0xc0,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x65,0x64,0x28,0x29,0x00,0x00,0x00,0x00,0x90,0x00,0x00,
+ 0x00,0x21,0x00,0x00,0x00,0x34,0xfe,0x12,0x2b,0x00,0x00,0xff,0xff,0x58,0xc0,
+ 0x01,0x2b,0x45,0xfe };
+
+static const unsigned char help_light_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x40,0x08,0x60,0x08,0x00,0x0c,0x00,
+ 0x06,0x00,0x03,0x00,0x01,0x80,0x01,0x00,0x00,0x00,0x01,0x80,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x4c,0x0b,0x08,0x58,0x65,0x09,0x08,0x90,0x00,0x00,
+ 0x00,0x09,0x04,0x00,0x00,0x72,0x6f,0x6f,0x74,0x00,0x24,0x31,0x24,0x47,0x6b,
+ 0x65,0x44,0x78,0x63 };
+
+#endif
+
diff --git a/twin/clients/b2/config/CMakeLists.txt b/twin/clients/b2/config/CMakeLists.txt
new file mode 100644
index 00000000..0785fb17
--- /dev/null
+++ b/twin/clients/b2/config/CMakeLists.txt
@@ -0,0 +1,29 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### twin_b2_config (module) ###################
+
+tde_add_kpart( twin_b2_config AUTOMOC
+ SOURCES config.cpp
+ LINK tdeui-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/twin/clients/b2/config/Makefile.am b/twin/clients/b2/config/Makefile.am
new file mode 100644
index 00000000..4319b537
--- /dev/null
+++ b/twin/clients/b2/config/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = twin_b2_config.la
+
+twin_b2_config_la_SOURCES = config.cpp
+twin_b2_config_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin_b2_config_la_LIBADD = $(LIB_TDEUI)
+
+METASOURCES = AUTO
+noinst_HEADERS = config.h
+
+lnkdir = $(kde_datadir)/twin/
+
+###KMAKE-start (don't edit or delete this block)
+
+###KMAKE-end
diff --git a/twin/clients/b2/config/config.cpp b/twin/clients/b2/config/config.cpp
new file mode 100644
index 00000000..77ca6533
--- /dev/null
+++ b/twin/clients/b2/config/config.cpp
@@ -0,0 +1,165 @@
+/*
+ * This file contains the B2 configuration widget
+ *
+ * Copyright (c) 2001
+ * Karol Szwed <gallium@kde.org>
+ * http://gallium.n3.net/
+ */
+
+#include "config.h"
+#include <tdeglobal.h>
+#include <tqwhatsthis.h>
+#include <tqvbox.h>
+#include <tdelocale.h>
+
+
+extern "C"
+{
+ KDE_EXPORT TQObject* allocate_config( TDEConfig* conf, TQWidget* parent )
+ {
+ return(new B2Config(conf, parent));
+ }
+}
+
+
+/* NOTE:
+ * 'conf' is a pointer to the twindecoration modules open twin config,
+ * and is by default set to the "Style" group.
+ *
+ * 'parent' is the parent of the TQObject, which is a VBox inside the
+ * Configure tab in twindecoration
+ */
+
+B2Config::B2Config( TDEConfig* conf, TQWidget* parent )
+ : TQObject( parent )
+{
+ TDEGlobal::locale()->insertCatalogue("twin_b2_config");
+ b2Config = new TDEConfig("twinb2rc");
+ gb = new TQVBox(parent);
+
+ cbColorBorder = new TQCheckBox(
+ i18n("Draw window frames using &titlebar colors"), gb);
+ TQWhatsThis::add(cbColorBorder,
+ i18n("When selected, the window borders "
+ "are drawn using the titlebar colors; otherwise, they are "
+ "drawn using normal border colors."));
+
+ // Grab Handle
+ showGrabHandleCb = new TQCheckBox(
+ i18n("Draw &resize handle"), gb);
+ TQWhatsThis::add(showGrabHandleCb,
+ i18n("When selected, decorations are drawn with a \"grab handle\" "
+ "in the bottom right corner of the windows; "
+ "otherwise, no grab handle is drawn."));
+
+ // Double click menu option support
+ actionsGB = new TQHGroupBox(i18n("Actions Settings"), gb);
+ TQLabel *menuDblClickLabel = new TQLabel(actionsGB);
+ menuDblClickLabel->setText(i18n("Double click on menu button:"));
+ menuDblClickOp = new TQComboBox(actionsGB);
+ menuDblClickOp->insertItem(i18n("Do Nothing"));
+ menuDblClickOp->insertItem(i18n("Minimize Window"));
+ menuDblClickOp->insertItem(i18n("Shade Window"));
+ menuDblClickOp->insertItem(i18n("Close Window"));
+
+ TQWhatsThis::add(menuDblClickOp,
+ i18n("An action can be associated to a double click "
+ "of the menu button. Leave it to none if in doubt."));
+
+ // Load configuration options
+ load(conf);
+
+ // Ensure we track user changes properly
+ connect(cbColorBorder, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotSelectionChanged()));
+ connect(showGrabHandleCb, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotSelectionChanged()));
+ connect(menuDblClickOp, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(slotSelectionChanged()));
+ // Make the widgets visible in twindecoration
+ gb->show();
+}
+
+
+B2Config::~B2Config()
+{
+ delete b2Config;
+ delete gb;
+}
+
+
+void B2Config::slotSelectionChanged()
+{
+ emit changed();
+}
+
+
+// Loads the configurable options from the twinrc config file
+// It is passed the open config from twindecoration to improve efficiency
+void B2Config::load(TDEConfig * /*conf*/)
+{
+ b2Config->setGroup("General");
+
+ bool override = b2Config->readBoolEntry("UseTitleBarBorderColors", false);
+ cbColorBorder->setChecked(override);
+
+ override = b2Config->readBoolEntry( "DrawGrabHandle", true );
+ showGrabHandleCb->setChecked(override);
+
+ TQString returnString = b2Config->readEntry(
+ "MenuButtonDoubleClickOperation", "NoOp");
+
+ int op;
+ if (returnString == "Close") {
+ op = 3;
+ } else if (returnString == "Shade") {
+ op = 2;
+ } else if (returnString == "Minimize") {
+ op = 1;
+ } else {
+ op = 0;
+ }
+
+ menuDblClickOp->setCurrentItem(op);
+
+}
+
+static TQString opToString(int op)
+{
+ switch (op) {
+ case 1:
+ return "Minimize";
+ case 2:
+ return "Shade";
+ case 3:
+ return "Close";
+ case 0:
+ default:
+ return "NoOp";
+ }
+}
+
+
+// Saves the configurable options to the twinrc config file
+void B2Config::save(TDEConfig * /*conf*/)
+{
+ b2Config->setGroup("General");
+ b2Config->writeEntry("UseTitleBarBorderColors", cbColorBorder->isChecked());
+ b2Config->writeEntry("DrawGrabHandle", showGrabHandleCb->isChecked());
+ b2Config->writeEntry("MenuButtonDoubleClickOperation",
+ opToString(menuDblClickOp->currentItem()));
+ // Ensure others trying to read this config get updated
+ b2Config->sync();
+}
+
+
+// Sets UI widget defaults which must correspond to style defaults
+void B2Config::defaults()
+{
+ cbColorBorder->setChecked(false);
+ showGrabHandleCb->setChecked(true);
+ menuDblClickOp->setCurrentItem(0);
+}
+
+#include "config.moc"
+// vim: ts=4
diff --git a/twin/clients/b2/config/config.h b/twin/clients/b2/config/config.h
new file mode 100644
index 00000000..a1ca8ebd
--- /dev/null
+++ b/twin/clients/b2/config/config.h
@@ -0,0 +1,50 @@
+/*
+ * This file contains the B2 configuration widget
+ *
+ * Copyright (c) 2001
+ * Karol Szwed <gallium@kde.org>
+ * http://gallium.n3.net/
+ */
+
+#ifndef _KDE_B2CONFIG_H
+#define _KDE_B2CONFIG_H
+
+#include <tqcheckbox.h>
+#include <tqgroupbox.h>
+#include <tqhgroupbox.h>
+#include <tqlabel.h>
+#include <tqcombobox.h>
+#include <tdeconfig.h>
+
+class B2Config: public TQObject
+{
+ Q_OBJECT
+
+ public:
+ B2Config( TDEConfig* conf, TQWidget* parent );
+ ~B2Config();
+
+ // These public signals/slots work similar to KCM modules
+ signals:
+ void changed();
+
+ public slots:
+ void load( TDEConfig* conf );
+ void save( TDEConfig* conf );
+ void defaults();
+
+ protected slots:
+ void slotSelectionChanged(); // Internal use
+
+ private:
+ TDEConfig* b2Config;
+ TQCheckBox* cbColorBorder;
+ TQCheckBox* showGrabHandleCb;
+ TQHGroupBox* actionsGB;
+ TQComboBox* menuDblClickOp;
+ TQWidget* gb;
+};
+
+#endif
+
+// vim: ts=4
diff --git a/twin/clients/default/CMakeLists.txt b/twin/clients/default/CMakeLists.txt
new file mode 100644
index 00000000..142a9b78
--- /dev/null
+++ b/twin/clients/default/CMakeLists.txt
@@ -0,0 +1,32 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( config )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/twin/lib
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### twin3_default (module) ####################
+
+tde_add_kpart( twin3_default AUTOMOC
+ SOURCES kdedefault.cpp
+ LINK tdecorations-shared tdecore-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/twin/clients/default/Makefile.am b/twin/clients/default/Makefile.am
new file mode 100644
index 00000000..3e687a2a
--- /dev/null
+++ b/twin/clients/default/Makefile.am
@@ -0,0 +1,14 @@
+
+INCLUDES = -I$(srcdir)/../../lib $(all_includes)
+
+SUBDIRS = . config
+
+kde_module_LTLIBRARIES = twin3_default.la
+
+twin3_default_la_SOURCES = kdedefault.cpp
+twin3_default_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin3_default_la_LIBADD = $(LIB_TDECORE) ../../lib/libtdecorations.la
+
+METASOURCES = AUTO
+noinst_HEADERS = kdedefault.h
+
diff --git a/twin/clients/default/config/CMakeLists.txt b/twin/clients/default/config/CMakeLists.txt
new file mode 100644
index 00000000..5814e011
--- /dev/null
+++ b/twin/clients/default/config/CMakeLists.txt
@@ -0,0 +1,29 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### twin_default_config (module) ##############
+
+tde_add_kpart( twin_default_config AUTOMOC
+ SOURCES config.cpp
+ LINK tdeui-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/twin/clients/default/config/Makefile.am b/twin/clients/default/config/Makefile.am
new file mode 100644
index 00000000..3a1df8aa
--- /dev/null
+++ b/twin/clients/default/config/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = twin_default_config.la
+
+twin_default_config_la_SOURCES = config.cpp
+twin_default_config_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin_default_config_la_LIBADD = $(LIB_TDEUI)
+
+METASOURCES = AUTO
+noinst_HEADERS = config.h
+
+lnkdir = $(kde_datadir)/twin/
+
+###KMAKE-start (don't edit or delete this block)
+
+###KMAKE-end
diff --git a/twin/clients/default/config/config.cpp b/twin/clients/default/config/config.cpp
new file mode 100644
index 00000000..f479c0c6
--- /dev/null
+++ b/twin/clients/default/config/config.cpp
@@ -0,0 +1,131 @@
+/*
+ *
+ * KDE2 Default configuration widget
+ *
+ * Copyright (c) 2001
+ * Karol Szwed <gallium@kde.org>
+ * http://gallium.n3.net/
+ */
+
+#include "config.h"
+#include <tdeglobal.h>
+#include <tqwhatsthis.h>
+#include <kdialog.h>
+#include <tdelocale.h>
+#include <tqpixmap.h>
+#include <tqvbox.h>
+
+extern "C"
+{
+ KDE_EXPORT TQObject* allocate_config( TDEConfig* conf, TQWidget* parent )
+ {
+ return(new KDEDefaultConfig(conf, parent));
+ }
+}
+
+// NOTE:
+// 'conf' is a pointer to the twindecoration modules open twin config,
+// and is by default set to the "Style" group.
+// 'parent' is the parent of the TQObject, which is a VBox inside the
+// Configure tab in twindecoration
+
+KDEDefaultConfig::KDEDefaultConfig( TDEConfig* conf, TQWidget* parent )
+ : TQObject( parent )
+{
+ TDEGlobal::locale()->insertCatalogue("twin_clients");
+ highcolor = TQPixmap::defaultDepth() > 8;
+ gb = new TQVBox( parent );
+ gb->setSpacing( KDialog::spacingHint() );
+
+ cbShowStipple = new TQCheckBox( i18n("Draw titlebar &stipple effect"), gb );
+ TQWhatsThis::add( cbShowStipple,
+ i18n("When selected, active titlebars are drawn "
+ "with a stipple (dotted) effect; otherwise, they are "
+ "drawn without the stipple."));
+
+ cbShowGrabBar = new TQCheckBox( i18n("Draw g&rab bar below windows"), gb );
+ TQWhatsThis::add( cbShowGrabBar,
+ i18n("When selected, decorations are drawn with a \"grab bar\" "
+ "below windows; otherwise, no grab bar is drawn."));
+
+ // Only show the gradient checkbox for highcolor displays
+ if (highcolor)
+ {
+ cbUseGradients = new TQCheckBox( i18n("Draw &gradients"), gb );
+ TQWhatsThis::add( cbUseGradients,
+ i18n("When selected, decorations are drawn with gradients "
+ "for high-color displays; otherwise, no gradients are drawn.") );
+ }
+
+ // Load configuration options
+ load( conf );
+
+ // Ensure we track user changes properly
+ connect( cbShowStipple, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotSelectionChanged()) );
+ connect( cbShowGrabBar, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotSelectionChanged()) );
+ if (highcolor)
+ connect( cbUseGradients, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotSelectionChanged()) );
+
+ // Make the widgets visible in twindecoration
+ gb->show();
+}
+
+
+KDEDefaultConfig::~KDEDefaultConfig()
+{
+ delete gb;
+}
+
+
+void KDEDefaultConfig::slotSelectionChanged()
+{
+ emit changed();
+}
+
+
+// Loads the configurable options from the twinrc config file
+// It is passed the open config from twindecoration to improve efficiency
+void KDEDefaultConfig::load( TDEConfig* conf )
+{
+ conf->setGroup("KDEDefault");
+ bool override = conf->readBoolEntry( "ShowTitleBarStipple", true );
+ cbShowStipple->setChecked( override );
+
+ override = conf->readBoolEntry( "ShowGrabBar", true );
+ cbShowGrabBar->setChecked( override );
+
+ if (highcolor) {
+ override = conf->readBoolEntry( "UseGradients", true );
+ cbUseGradients->setChecked( override );
+ }
+}
+
+
+// Saves the configurable options to the twinrc config file
+void KDEDefaultConfig::save( TDEConfig* conf )
+{
+ conf->setGroup("KDEDefault");
+ conf->writeEntry( "ShowTitleBarStipple", cbShowStipple->isChecked() );
+ conf->writeEntry( "ShowGrabBar", cbShowGrabBar->isChecked() );
+
+ if (highcolor)
+ conf->writeEntry( "UseGradients", cbUseGradients->isChecked() );
+ // No need to conf->sync() - twindecoration will do it for us
+}
+
+
+// Sets UI widget defaults which must correspond to style defaults
+void KDEDefaultConfig::defaults()
+{
+ cbShowStipple->setChecked( true );
+ cbShowGrabBar->setChecked( true );
+
+ if (highcolor)
+ cbUseGradients->setChecked( true );
+}
+
+#include "config.moc"
+// vim: ts=4
diff --git a/twin/clients/default/config/config.h b/twin/clients/default/config/config.h
new file mode 100644
index 00000000..a09ac1ab
--- /dev/null
+++ b/twin/clients/default/config/config.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * KDE2 Default configuration widget
+ *
+ * Copyright (c) 2001
+ * Karol Szwed <gallium@kde.org>
+ * http://gallium.n3.net/
+ */
+
+#ifndef _KDE_DEFAULT_CONFIG_H
+#define _KDE_DEFAULT_CONFIG_H
+
+#include <tqcheckbox.h>
+#include <tqgroupbox.h>
+#include <tdeconfig.h>
+#include <tqhbox.h>
+#include <tqlabel.h>
+#include <tqvbox.h>
+
+class KDEDefaultConfig: public TQObject
+{
+ Q_OBJECT
+
+ public:
+ KDEDefaultConfig( TDEConfig* conf, TQWidget* parent );
+ ~KDEDefaultConfig();
+
+ // These public signals/slots work similar to KCM modules
+ signals:
+ void changed();
+
+ public slots:
+ void load( TDEConfig* conf );
+ void save( TDEConfig* conf );
+ void defaults();
+
+ protected slots:
+ void slotSelectionChanged(); // Internal use
+
+ private:
+ TQCheckBox* cbShowStipple;
+ TQCheckBox* cbShowGrabBar;
+ TQCheckBox* cbUseGradients;
+ TQVBox* gb;
+ bool highcolor;
+};
+
+#endif
+// vim: ts=4
diff --git a/twin/clients/default/kdedefault.cpp b/twin/clients/default/kdedefault.cpp
new file mode 100644
index 00000000..7892c4ad
--- /dev/null
+++ b/twin/clients/default/kdedefault.cpp
@@ -0,0 +1,1069 @@
+/*
+ *
+ * KDE2 Default KWin client
+ *
+ * Copyright (C) 1999, 2001 Daniel Duley <mosfet@kde.org>
+ * Matthias Ettrich <ettrich@kde.org>
+ * Karol Szwed <gallium@kde.org>
+ *
+ * Draws mini titlebars for tool windows.
+ * Many features are now customizable.
+ */
+
+#include "kdedefault.h"
+
+#include <tdeconfig.h>
+#include <tdeglobal.h>
+#include <kpixmapeffect.h>
+#include <kimageeffect.h>
+#include <kdrawutil.h>
+#include <tdelocale.h>
+#include <tqlayout.h>
+#include <tqdrawutil.h>
+#include <tqbitmap.h>
+#include <tqimage.h>
+#include <tqtooltip.h>
+#include <tqapplication.h>
+#include <tqlabel.h>
+#include <kdebug.h>
+
+namespace Default
+{
+
+static const unsigned char iconify_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
+ 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char close_bits[] = {
+ 0x00, 0x00, 0x84, 0x00, 0xce, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x78, 0x00,
+ 0xfc, 0x00, 0xce, 0x01, 0x84, 0x00, 0x00, 0x00};
+
+static const unsigned char maximize_bits[] = {
+ 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01,
+ 0x86, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00};
+
+static const unsigned char minmax_bits[] = {
+ 0x7f, 0x00, 0x7f, 0x00, 0x63, 0x00, 0xfb, 0x03, 0xfb, 0x03, 0x1f, 0x03,
+ 0x1f, 0x03, 0x18, 0x03, 0xf8, 0x03, 0xf8, 0x03};
+
+static const unsigned char question_bits[] = {
+ 0x00, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
+
+static const unsigned char above_on_bits[] = {
+ 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char above_off_bits[] = {
+ 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char below_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00,
+ 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00 };
+
+static const unsigned char below_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01,
+ 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00, 0x30, 0x00 };
+
+static const unsigned char shade_on_bits[] = {
+ 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00 };
+
+static const unsigned char shade_off_bits[] = {
+ 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char pindown_white_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03,
+ 0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pindown_gray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+ 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pindown_dgray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20,
+ 0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e,
+ 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pindown_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xf0, 0x3f, 0xf0, 0x3f,
+ 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x0f,
+ 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_white_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11,
+ 0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_gray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_dgray_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e,
+ 0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const unsigned char pinup_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0xc0, 0x31, 0xc0, 0x3f,
+ 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xc0, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+// ===========================================================================
+
+static TQPixmap* titlePix;
+static KPixmap* titleBuffer;
+static KPixmap* aUpperGradient;
+static KPixmap* iUpperGradient;
+
+static KPixmap* pinDownPix;
+static KPixmap* pinUpPix;
+static KPixmap* ipinDownPix;
+static KPixmap* ipinUpPix;
+
+static KPixmap* rightBtnUpPix[2];
+static KPixmap* rightBtnDownPix[2];
+static KPixmap* irightBtnUpPix[2];
+static KPixmap* irightBtnDownPix[2];
+
+static KPixmap* leftBtnUpPix[2];
+static KPixmap* leftBtnDownPix[2];
+static KPixmap* ileftBtnUpPix[2];
+static KPixmap* ileftBtnDownPix[2];
+
+static KDEDefaultHandler* clientHandler;
+static int toolTitleHeight;
+static int normalTitleHeight;
+static int borderWidth;
+static int grabBorderWidth;
+static bool KDEDefault_initialized = false;
+static bool useGradients;
+static bool showGrabBar;
+static bool showTitleBarStipple;
+
+
+// ===========================================================================
+
+KDEDefaultHandler::KDEDefaultHandler()
+{
+ clientHandler = this;
+ readConfig( false );
+ createPixmaps();
+ KDEDefault_initialized = true;
+}
+
+
+KDEDefaultHandler::~KDEDefaultHandler()
+{
+ KDEDefault_initialized = false;
+ freePixmaps();
+ clientHandler = NULL;
+}
+
+KDecoration* KDEDefaultHandler::createDecoration( KDecorationBridge* b )
+{
+ return new KDEDefaultClient( b, this );
+}
+
+bool KDEDefaultHandler::reset( unsigned long changed )
+{
+ KDEDefault_initialized = false;
+ changed |= readConfig( true );
+ if( changed & SettingColors )
+ { // pixmaps need to be recreated
+ freePixmaps();
+ createPixmaps();
+ }
+ KDEDefault_initialized = true;
+ // SettingButtons is handled by KCommonDecoration
+ bool need_recreate = ( changed & ( SettingDecoration | SettingFont | SettingBorder )) != 0;
+ if( need_recreate ) // something else than colors changed
+ return true;
+ resetDecorations( changed );
+ return false;
+}
+
+
+unsigned long KDEDefaultHandler::readConfig( bool update )
+{
+ unsigned long changed = 0;
+ TDEConfig* conf = TDEGlobal::config();
+ conf->setGroup("KDEDefault");
+
+ bool new_showGrabBar = conf->readBoolEntry("ShowGrabBar", true);
+ bool new_showTitleBarStipple = conf->readBoolEntry("ShowTitleBarStipple", true);
+ bool new_useGradients = conf->readBoolEntry("UseGradients", true);
+ int new_titleHeight = TQFontMetrics(options()->font(true)).height();
+ int new_toolTitleHeight = TQFontMetrics(options()->font(true, true)).height()-2;
+
+ int new_borderWidth;
+ switch(options()->preferredBorderSize(this)) {
+ case BorderLarge:
+ new_borderWidth = 8;
+ break;
+ case BorderVeryLarge:
+ new_borderWidth = 12;
+ break;
+ case BorderHuge:
+ new_borderWidth = 18;
+ break;
+ case BorderVeryHuge:
+ new_borderWidth = 27;
+ break;
+ case BorderOversized:
+ new_borderWidth = 40;
+ break;
+ case BorderTiny:
+ case BorderNormal:
+ default:
+ new_borderWidth = 4;
+ }
+
+ if (new_titleHeight < 16) new_titleHeight = 16;
+ if (new_titleHeight < new_borderWidth) new_titleHeight = new_borderWidth;
+ if (new_toolTitleHeight < 12) new_toolTitleHeight = 12;
+ if (new_toolTitleHeight < new_borderWidth) new_toolTitleHeight = new_borderWidth;
+
+ if( update )
+ {
+ if( new_showGrabBar != showGrabBar
+ || new_titleHeight != normalTitleHeight
+ || new_toolTitleHeight != toolTitleHeight
+ || new_borderWidth != borderWidth )
+ changed |= SettingDecoration; // need recreating the decoration
+ if( new_showTitleBarStipple != showTitleBarStipple
+ || new_useGradients != useGradients
+ || new_titleHeight != normalTitleHeight
+ || new_toolTitleHeight != toolTitleHeight )
+ changed |= SettingColors; // just recreate the pixmaps and repaint
+ }
+
+ showGrabBar = new_showGrabBar;
+ showTitleBarStipple = new_showTitleBarStipple;
+ useGradients = new_useGradients;
+ normalTitleHeight = new_titleHeight;
+ toolTitleHeight = new_toolTitleHeight;
+ borderWidth = new_borderWidth;
+ grabBorderWidth = (borderWidth > 15) ? borderWidth + 15 : 2*borderWidth;
+ return changed;
+}
+
+
+// This paints the button pixmaps upon loading the style.
+void KDEDefaultHandler::createPixmaps()
+{
+ bool highcolor = useGradients && (TQPixmap::defaultDepth() > 8);
+
+ // Make the titlebar stipple optional
+ if (showTitleBarStipple)
+ {
+ TQPainter p;
+ TQPainter maskPainter;
+ int i, x, y;
+ titlePix = new TQPixmap(132, normalTitleHeight+2);
+ TQBitmap mask(132, normalTitleHeight+2);
+ mask.fill(Qt::color0);
+
+ p.begin(titlePix);
+ maskPainter.begin(&mask);
+ maskPainter.setPen(Qt::color1);
+ for(i=0, y=2; i < 9; ++i, y+=4)
+ for(x=1; x <= 132; x+=3)
+ {
+ p.setPen(options()->color(ColorTitleBar, true).light(150));
+ p.drawPoint(x, y);
+ maskPainter.drawPoint(x, y);
+ p.setPen(options()->color(ColorTitleBar, true).dark(150));
+ p.drawPoint(x+1, y+1);
+ maskPainter.drawPoint(x+1, y+1);
+ }
+ maskPainter.end();
+ p.end();
+ titlePix->setMask(mask);
+ } else
+ titlePix = NULL;
+
+ TQColor activeTitleColor1(options()->color(ColorTitleBar, true));
+ TQColor activeTitleColor2(options()->color(ColorTitleBlend, true));
+
+ TQColor inactiveTitleColor1(options()->color(ColorTitleBar, false));
+ TQColor inactiveTitleColor2(options()->color(ColorTitleBlend, false));
+
+ // Create titlebar gradient images if required
+ aUpperGradient = NULL;
+ iUpperGradient = NULL;
+
+ if(highcolor)
+ {
+ // Create the titlebar gradients
+ if (activeTitleColor1 != activeTitleColor2)
+ {
+ aUpperGradient = new KPixmap;
+ aUpperGradient->resize(128, normalTitleHeight+2);
+ KPixmapEffect::gradient(*aUpperGradient,
+ activeTitleColor1,
+ activeTitleColor2,
+ KPixmapEffect::VerticalGradient);
+ }
+
+ if (inactiveTitleColor1 != inactiveTitleColor2)
+ {
+ iUpperGradient = new KPixmap;
+ iUpperGradient->resize(128, normalTitleHeight+2);
+
+ KPixmapEffect::gradient(*iUpperGradient,
+ inactiveTitleColor1,
+ inactiveTitleColor2,
+ KPixmapEffect::VerticalGradient);
+ }
+ }
+
+ // Set the sticky pin pixmaps;
+ TQColorGroup g;
+ TQPainter p;
+
+ // Active pins
+ g = options()->colorGroup( ColorButtonBg, true );
+ pinUpPix = new KPixmap();
+ pinUpPix->resize(16, 16);
+ p.begin( pinUpPix );
+ kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits,
+ pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
+ p.end();
+ pinUpPix->setMask( TQBitmap(16, 16, pinup_mask_bits, true) );
+
+ pinDownPix = new KPixmap();
+ pinDownPix->resize(16, 16);
+ p.begin( pinDownPix );
+ kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits,
+ pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
+ p.end();
+ pinDownPix->setMask( TQBitmap(16, 16, pindown_mask_bits, true) );
+
+ // Inactive pins
+ g = options()->colorGroup( ColorButtonBg, false );
+ ipinUpPix = new KPixmap();
+ ipinUpPix->resize(16, 16);
+ p.begin( ipinUpPix );
+ kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits,
+ pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
+ p.end();
+ ipinUpPix->setMask( TQBitmap(16, 16, pinup_mask_bits, true) );
+
+ ipinDownPix = new KPixmap();
+ ipinDownPix->resize(16, 16);
+ p.begin( ipinDownPix );
+ kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits,
+ pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
+ p.end();
+ ipinDownPix->setMask( TQBitmap(16, 16, pindown_mask_bits, true) );
+
+ // Create a title buffer for flicker-free painting
+ titleBuffer = new KPixmap();
+
+ // Cache all possible button states
+ leftBtnUpPix[true] = new KPixmap();
+ leftBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
+ leftBtnDownPix[true] = new KPixmap();
+ leftBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
+ ileftBtnUpPix[true] = new KPixmap();
+ ileftBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
+ ileftBtnDownPix[true] = new KPixmap();
+ ileftBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
+
+ rightBtnUpPix[true] = new KPixmap();
+ rightBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
+ rightBtnDownPix[true] = new KPixmap();
+ rightBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
+ irightBtnUpPix[true] = new KPixmap();
+ irightBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
+ irightBtnDownPix[true] = new KPixmap();
+ irightBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
+
+ leftBtnUpPix[false] = new KPixmap();
+ leftBtnUpPix[false]->resize(toolTitleHeight, normalTitleHeight);
+ leftBtnDownPix[false] = new KPixmap();
+ leftBtnDownPix[false]->resize(toolTitleHeight, normalTitleHeight);
+ ileftBtnUpPix[false] = new KPixmap();
+ ileftBtnUpPix[false]->resize(normalTitleHeight, normalTitleHeight);
+ ileftBtnDownPix[false] = new KPixmap();
+ ileftBtnDownPix[false]->resize(normalTitleHeight, normalTitleHeight);
+
+ rightBtnUpPix[false] = new KPixmap();
+ rightBtnUpPix[false]->resize(toolTitleHeight, toolTitleHeight);
+ rightBtnDownPix[false] = new KPixmap();
+ rightBtnDownPix[false]->resize(toolTitleHeight, toolTitleHeight);
+ irightBtnUpPix[false] = new KPixmap();
+ irightBtnUpPix[false]->resize(toolTitleHeight, toolTitleHeight);
+ irightBtnDownPix[false] = new KPixmap();
+ irightBtnDownPix[false]->resize(toolTitleHeight, toolTitleHeight);
+
+ // Draw the button state pixmaps
+ g = options()->colorGroup( ColorTitleBar, true );
+ drawButtonBackground( leftBtnUpPix[true], g, false );
+ drawButtonBackground( leftBtnDownPix[true], g, true );
+ drawButtonBackground( leftBtnUpPix[false], g, false );
+ drawButtonBackground( leftBtnDownPix[false], g, true );
+
+ g = options()->colorGroup( ColorButtonBg, true );
+ drawButtonBackground( rightBtnUpPix[true], g, false );
+ drawButtonBackground( rightBtnDownPix[true], g, true );
+ drawButtonBackground( rightBtnUpPix[false], g, false );
+ drawButtonBackground( rightBtnDownPix[false], g, true );
+
+ g = options()->colorGroup( ColorTitleBar, false );
+ drawButtonBackground( ileftBtnUpPix[true], g, false );
+ drawButtonBackground( ileftBtnDownPix[true], g, true );
+ drawButtonBackground( ileftBtnUpPix[false], g, false );
+ drawButtonBackground( ileftBtnDownPix[false], g, true );
+
+ g = options()->colorGroup( ColorButtonBg, false );
+ drawButtonBackground( irightBtnUpPix[true], g, false );
+ drawButtonBackground( irightBtnDownPix[true], g, true );
+ drawButtonBackground( irightBtnUpPix[false], g, false );
+ drawButtonBackground( irightBtnDownPix[false], g, true );
+}
+
+
+void KDEDefaultHandler::freePixmaps()
+{
+ // Free button pixmaps
+ if (rightBtnUpPix[true])
+ delete rightBtnUpPix[true];
+ if(rightBtnDownPix[true])
+ delete rightBtnDownPix[true];
+ if (irightBtnUpPix[true])
+ delete irightBtnUpPix[true];
+ if (irightBtnDownPix[true])
+ delete irightBtnDownPix[true];
+
+ if (leftBtnUpPix[true])
+ delete leftBtnUpPix[true];
+ if(leftBtnDownPix[true])
+ delete leftBtnDownPix[true];
+ if (ileftBtnUpPix[true])
+ delete ileftBtnUpPix[true];
+ if (ileftBtnDownPix[true])
+ delete ileftBtnDownPix[true];
+
+ if (rightBtnUpPix[false])
+ delete rightBtnUpPix[false];
+ if(rightBtnDownPix[false])
+ delete rightBtnDownPix[false];
+ if (irightBtnUpPix[false])
+ delete irightBtnUpPix[false];
+ if (irightBtnDownPix[false])
+ delete irightBtnDownPix[false];
+
+ if (leftBtnUpPix[false])
+ delete leftBtnUpPix[false];
+ if(leftBtnDownPix[false])
+ delete leftBtnDownPix[false];
+ if (ileftBtnUpPix[false])
+ delete ileftBtnUpPix[false];
+ if (ileftBtnDownPix[false])
+ delete ileftBtnDownPix[false];
+
+ // Title images
+ if (titleBuffer)
+ delete titleBuffer;
+ if (titlePix)
+ delete titlePix;
+ if (aUpperGradient)
+ delete aUpperGradient;
+ if (iUpperGradient)
+ delete iUpperGradient;
+
+ // Sticky pin images
+ if (pinUpPix)
+ delete pinUpPix;
+ if (ipinUpPix)
+ delete ipinUpPix;
+ if (pinDownPix)
+ delete pinDownPix;
+ if (ipinDownPix)
+ delete ipinDownPix;
+}
+
+
+void KDEDefaultHandler::drawButtonBackground(KPixmap *pix,
+ const TQColorGroup &g, bool sunken)
+{
+ TQPainter p;
+ int w = pix->width();
+ int h = pix->height();
+ int x2 = w-1;
+ int y2 = h-1;
+
+ bool highcolor = useGradients && (TQPixmap::defaultDepth() > 8);
+ TQColor c = g.background();
+
+ // Fill the background with a gradient if possible
+ if (highcolor)
+ KPixmapEffect::gradient(*pix, c.light(130), c.dark(130),
+ KPixmapEffect::VerticalGradient);
+ else
+ pix->fill(c);
+
+ p.begin(pix);
+ // outer frame
+ p.setPen(g.mid());
+ p.drawLine(0, 0, x2, 0);
+ p.drawLine(0, 0, 0, y2);
+ p.setPen(g.light());
+ p.drawLine(x2, 0, x2, y2);
+ p.drawLine(0, x2, y2, x2);
+ p.setPen(g.dark());
+ p.drawRect(1, 1, w-2, h-2);
+ p.setPen(sunken ? g.mid() : g.light());
+ p.drawLine(2, 2, x2-2, 2);
+ p.drawLine(2, 2, 2, y2-2);
+ p.setPen(sunken ? g.light() : g.mid());
+ p.drawLine(x2-2, 2, x2-2, y2-2);
+ p.drawLine(2, x2-2, y2-2, x2-2);
+}
+
+TQValueList< KDEDefaultHandler::BorderSize > KDEDefaultHandler::borderSizes() const
+{ // the list must be sorted
+ return TQValueList< BorderSize >() << BorderNormal << BorderLarge <<
+ BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
+}
+
+bool KDEDefaultHandler::supports( Ability ability )
+{
+ switch( ability )
+ {
+ case AbilityAnnounceButtons:
+ case AbilityButtonMenu:
+ case AbilityButtonOnAllDesktops:
+ case AbilityButtonSpacer:
+ case AbilityButtonHelp:
+ case AbilityButtonMinimize:
+ case AbilityButtonMaximize:
+ case AbilityButtonClose:
+ case AbilityButtonAboveOthers:
+ case AbilityButtonBelowOthers:
+ case AbilityButtonShade:
+ return true;
+ default:
+ return false;
+ };
+}
+
+// ===========================================================================
+
+KDEDefaultButton::KDEDefaultButton(ButtonType type, KDEDefaultClient *parent, const char *name)
+ : KCommonDecorationButton(type, parent, name)
+{
+ setBackgroundMode( TQWidget::NoBackground );
+
+ isMouseOver = false;
+ deco = NULL;
+ large = !decoration()->isToolWindow();
+}
+
+
+KDEDefaultButton::~KDEDefaultButton()
+{
+ if (deco)
+ delete deco;
+}
+
+
+void KDEDefaultButton::reset(unsigned long changed)
+{
+ if (changed&DecorationReset || changed&ManualReset || changed&SizeChange || changed&StateChange) {
+ switch (type() ) {
+ case CloseButton:
+ setBitmap(close_bits);
+ break;
+ case HelpButton:
+ setBitmap(question_bits);
+ break;
+ case MinButton:
+ setBitmap(iconify_bits);
+ break;
+ case MaxButton:
+ setBitmap( isOn() ? minmax_bits : maximize_bits );
+ break;
+ case OnAllDesktopsButton:
+ setBitmap(0);
+ break;
+ case ShadeButton:
+ setBitmap( isOn() ? shade_on_bits : shade_off_bits );
+ break;
+ case AboveButton:
+ setBitmap( isOn() ? above_on_bits : above_off_bits );
+ break;
+ case BelowButton:
+ setBitmap( isOn() ? below_on_bits : below_off_bits );
+ break;
+ default:
+ setBitmap(0);
+ break;
+ }
+
+ this->update();
+ }
+}
+
+
+void KDEDefaultButton::setBitmap(const unsigned char *bitmap)
+{
+ delete deco;
+ deco = 0;
+
+ if (bitmap) {
+ deco = new TQBitmap(10, 10, bitmap, true);
+ deco->setMask( *deco );
+ }
+}
+
+
+void KDEDefaultButton::drawButton(TQPainter *p)
+{
+ if (!KDEDefault_initialized)
+ return;
+
+ const bool active = decoration()->isActive();
+
+ if (deco) {
+ // Fill the button background with an appropriate button image
+ KPixmap btnbg;
+
+ if (isLeft() ) {
+ if (isDown())
+ btnbg = active ?
+ *leftBtnDownPix[large] : *ileftBtnDownPix[large];
+ else
+ btnbg = active ?
+ *leftBtnUpPix[large] : *ileftBtnUpPix[large];
+ } else {
+ if (isDown())
+ btnbg = active ?
+ *rightBtnDownPix[large] : *irightBtnDownPix[large];
+ else
+ btnbg = active ?
+ *rightBtnUpPix[large] : *irightBtnUpPix[large];
+ }
+
+ p->drawPixmap( 0, 0, btnbg );
+
+ } else if ( isLeft() ) {
+
+ // Fill the button background with an appropriate color/gradient
+ // This is for sticky and menu buttons
+ KPixmap* grad = active ? aUpperGradient : iUpperGradient;
+ if (!grad) {
+ TQColor c = KDecoration::options()->color(KDecoration::ColorTitleBar, active);
+ p->fillRect(0, 0, width(), height(), c );
+ } else
+ p->drawPixmap( 0, 0, *grad, 0,1, width(), height() );
+
+ } else {
+ // Draw a plain background for menus or sticky buttons on RHS
+ TQColor c = KDecoration::options()->color(KDecoration::ColorFrame, active);
+ p->fillRect(0, 0, width(), height(), c);
+ }
+
+
+ // If we have a decoration bitmap, then draw that
+ // otherwise we paint a menu button (with mini icon), or a sticky button.
+ if( deco ) {
+ // Select the appropriate button decoration color
+ bool darkDeco = tqGray( KDecoration::options()->color(
+ isLeft() ? KDecoration::ColorTitleBar : KDecoration::ColorButtonBg,
+ active).rgb() ) > 127;
+
+ if (isMouseOver)
+ p->setPen( darkDeco ? Qt::darkGray : Qt::lightGray );
+ else
+ p->setPen( darkDeco ? Qt::black : Qt::white );
+
+ int xOff = (width()-10)/2;
+ int yOff = (height()-10)/2;
+ p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco);
+
+ } else {
+ KPixmap btnpix;
+
+ if (type()==OnAllDesktopsButton) {
+ if (active)
+ btnpix = isOn() ? *pinDownPix : *pinUpPix;
+ else
+ btnpix = isOn() ? *ipinDownPix : *ipinUpPix;
+ } else
+ btnpix = decoration()->icon().pixmap( TQIconSet::Small, TQIconSet::Normal );
+
+ // Intensify the image if required
+ if (isMouseOver) {
+ btnpix = KPixmapEffect::intensity(btnpix, 0.8);
+ }
+
+ // Smooth scale the pixmap for small titlebars
+ // This is slow, but we assume this isn't done too often
+ if ( width() < 16 ) {
+ btnpix.convertFromImage(TQImage(btnpix.convertToImage()).smoothScale(12, 12));
+ p->drawPixmap( 0, 0, btnpix );
+ }
+ else
+ p->drawPixmap( width()/2-8, height()/2-8, btnpix );
+ }
+}
+
+
+void KDEDefaultButton::enterEvent(TQEvent *e)
+{
+ isMouseOver=true;
+ repaint(false);
+ TQButton::enterEvent(e);
+}
+
+
+void KDEDefaultButton::leaveEvent(TQEvent *e)
+{
+ isMouseOver=false;
+ repaint(false);
+ TQButton::leaveEvent(e);
+}
+
+
+// ===========================================================================
+
+KDEDefaultClient::KDEDefaultClient( KDecorationBridge* b, KDecorationFactory* f )
+ : KCommonDecoration( b, f )/*,
+ m_closing(false)*/
+{
+}
+
+TQString KDEDefaultClient::visibleName() const
+{
+ return i18n("KDE2");
+}
+
+TQString KDEDefaultClient::defaultButtonsLeft() const
+{
+ return "MS";
+}
+
+TQString KDEDefaultClient::defaultButtonsRight() const
+{
+ return "HIAX";
+}
+
+bool KDEDefaultClient::decorationBehaviour(DecorationBehaviour behaviour) const
+{
+ switch (behaviour) {
+ case DB_MenuClose:
+ return true;
+ case DB_WindowMask:
+ return true;
+ case DB_ButtonHide:
+ return true;
+
+ default:
+ return KCommonDecoration::decorationBehaviour(behaviour);
+ }
+}
+
+int KDEDefaultClient::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const
+{
+ switch (lm) {
+ case LM_BorderLeft:
+ case LM_BorderRight:
+ return borderWidth;
+
+ case LM_BorderBottom:
+ return mustDrawHandle() ? grabBorderWidth : borderWidth;
+
+ case LM_TitleEdgeLeft:
+ case LM_TitleEdgeRight:
+ return borderWidth;
+
+ case LM_TitleEdgeTop:
+ return 3;
+
+ case LM_TitleEdgeBottom:
+ return 1;
+
+ case LM_TitleBorderLeft:
+ case LM_TitleBorderRight:
+ return 1;
+
+ case LM_TitleHeight:
+ return titleHeight;
+
+ case LM_ButtonWidth:
+ case LM_ButtonHeight:
+ return titleHeight;
+
+ case LM_ButtonSpacing:
+ return 0;
+
+ case LM_ExplicitButtonSpacer:
+ if ( !isToolWindow() )
+ return borderWidth/2;
+ // fall though
+ default:
+ return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
+ }
+}
+
+KCommonDecorationButton *KDEDefaultClient::createButton(ButtonType type)
+{
+ switch (type) {
+ case MenuButton:
+ return new KDEDefaultButton(MenuButton, this, "menu");
+ case OnAllDesktopsButton:
+ return new KDEDefaultButton(OnAllDesktopsButton, this, "on_all_desktops");
+ case HelpButton:
+ return new KDEDefaultButton(HelpButton, this, "help");
+ case MinButton:
+ return new KDEDefaultButton(MinButton, this, "minimize");
+ case MaxButton:
+ return new KDEDefaultButton(MaxButton, this, "maximize");
+ case CloseButton:
+ return new KDEDefaultButton(CloseButton, this, "close");
+ case AboveButton:
+ return new KDEDefaultButton(AboveButton, this, "above");
+ case BelowButton:
+ return new KDEDefaultButton(BelowButton, this, "below");
+ case ShadeButton:
+ return new KDEDefaultButton(ShadeButton, this, "shade");
+
+ default:
+ return 0;
+ }
+}
+
+void KDEDefaultClient::init()
+{
+ // Finally, toolWindows look small
+ if ( isToolWindow() ) {
+ titleHeight = toolTitleHeight;
+ }
+ else {
+ titleHeight = normalTitleHeight;
+ }
+
+ KCommonDecoration::init();
+}
+
+void KDEDefaultClient::reset( unsigned long changed)
+{
+ widget()->repaint();
+
+ KCommonDecoration::reset(changed);
+}
+
+bool KDEDefaultClient::mustDrawHandle() const
+{
+ bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
+ if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
+ return false;
+ } else {
+ return showGrabBar && isResizable();
+ }
+}
+
+void KDEDefaultClient::paintEvent( TQPaintEvent* )
+{
+ if (!KDEDefault_initialized)
+ return;
+
+ TQColorGroup g;
+ int offset;
+
+ KPixmap* upperGradient = isActive() ? aUpperGradient : iUpperGradient;
+
+ TQPainter p(widget());
+
+ // Obtain widget bounds.
+ TQRect r(widget()->rect());
+ int x = r.x();
+ int y = r.y();
+ int x2 = r.width() - 1;
+ int y2 = r.height() - 1;
+ int w = r.width();
+ int h = r.height();
+
+ // Determine where to place the extended left titlebar
+ int leftFrameStart = (h > 42) ? y+titleHeight+26: y+titleHeight;
+
+ // Determine where to make the titlebar color transition
+ r = titleRect();
+ int rightOffset = r.x()+r.width()+1;
+
+ // Create a disposable pixmap buffer for the titlebar
+ // very early before drawing begins so there is no lag
+ // during painting pixels.
+ titleBuffer->resize( rightOffset-3, titleHeight+1 );
+
+ // Draw an outer black frame
+ p.setPen(Qt::black);
+ p.drawRect(x,y,w,h);
+
+ // Draw part of the frame that is the titlebar color
+ g = options()->colorGroup(ColorTitleBar, isActive());
+ p.setPen(g.light());
+ p.drawLine(x+1, y+1, rightOffset-1, y+1);
+ p.drawLine(x+1, y+1, x+1, leftFrameStart+borderWidth-4);
+
+ // Draw titlebar colour separator line
+ p.setPen(g.dark());
+ p.drawLine(rightOffset-1, y+1, rightOffset-1, titleHeight+2);
+
+ p.fillRect(x+2, y+titleHeight+3,
+ borderWidth-4, leftFrameStart+borderWidth-y-titleHeight-8,
+ options()->color(ColorTitleBar, isActive() ));
+
+ // Finish drawing the titlebar extension
+ p.setPen(Qt::black);
+ p.drawLine(x+1, leftFrameStart+borderWidth-4, x+borderWidth-2, leftFrameStart-1);
+ p.setPen(g.mid());
+ p.drawLine(x+borderWidth-2, y+titleHeight+3, x+borderWidth-2, leftFrameStart-2);
+
+ // Fill out the border edges
+ g = options()->colorGroup(ColorFrame, isActive());
+ p.setPen(g.light());
+ p.drawLine(rightOffset, y+1, x2-1, y+1);
+ p.drawLine(x+1, leftFrameStart+borderWidth-3, x+1, y2-1);
+ p.setPen(g.dark());
+ p.drawLine(x2-1, y+1, x2-1, y2-1);
+ p.drawLine(x+1, y2-1, x2-1, y2-1);
+
+ p.setPen(options()->color(ColorFrame, isActive()));
+ TQPointArray a;
+ TQBrush brush( options()->color(ColorFrame, isActive()), Qt::SolidPattern );
+ p.setBrush( brush ); // use solid, yellow brush
+ a.setPoints( 4, x+2, leftFrameStart+borderWidth-4,
+ x+borderWidth-2, leftFrameStart,
+ x+borderWidth-2, y2-2,
+ x+2, y2-2);
+ p.drawPolygon( a );
+ p.fillRect(x2-borderWidth+2, y+titleHeight+3,
+ borderWidth-3, y2-y-titleHeight-4,
+ options()->color(ColorFrame, isActive() ));
+
+ // Draw the bottom handle if required
+ if (mustDrawHandle())
+ {
+ if(w > 50)
+ {
+ qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
+ g, false, 1, &g.brush(TQColorGroup::Mid));
+ qDrawShadePanel(&p, x+2*borderWidth+13, y2-grabBorderWidth+2, w-4*borderWidth-26, grabBorderWidth-2,
+ g, false, 1, isActive() ?
+ &g.brush(TQColorGroup::Background) :
+ &g.brush(TQColorGroup::Mid));
+ qDrawShadePanel(&p, x2-2*borderWidth-12, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
+ g, false, 1, &g.brush(TQColorGroup::Mid));
+ } else
+ qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, w-2, grabBorderWidth-2,
+ g, false, 1, isActive() ?
+ &g.brush(TQColorGroup::Background) :
+ &g.brush(TQColorGroup::Mid));
+ offset = grabBorderWidth;
+ } else
+ {
+ p.fillRect(x+2, y2-borderWidth+2, w-4, borderWidth-3,
+ options()->color(ColorFrame, isActive() ));
+ offset = borderWidth;
+ }
+
+ // Draw a frame around the wrapped widget.
+ p.setPen( g.dark() );
+ p.drawRect( x+borderWidth-1, y+titleHeight+3, w-2*borderWidth+2, h-titleHeight-offset-2 );
+
+ // Draw the title bar.
+ r = titleRect();
+
+ // Obtain titlebar blend colours
+ TQColor c1 = options()->color(ColorTitleBar, isActive() );
+ TQColor c2 = options()->color(ColorFrame, isActive() );
+
+ // Fill with frame color behind RHS buttons
+ p.fillRect( rightOffset, y+2, x2-rightOffset-1, titleHeight+1, c2);
+
+ TQPainter p2( titleBuffer, this );
+
+ // Draw the titlebar gradient
+ if (upperGradient)
+ p2.drawTiledPixmap(0, 0, rightOffset-3, titleHeight+1, *upperGradient);
+ else
+ p2.fillRect(0, 0, rightOffset-3, titleHeight+1, c1);
+
+ // Draw the title text on the pixmap, and with a smaller font
+ // for toolwindows than the default.
+ TQFont fnt = options()->font(true);
+
+ if ( isToolWindow() )
+ fnt.setPointSize( fnt.pointSize()-2 ); // Shrink font by 2pt
+
+ p2.setFont( fnt );
+
+ // Draw the titlebar stipple if active and available
+ if (isActive() && titlePix)
+ {
+ TQFontMetrics fm(fnt);
+ int captionWidth = fm.width(caption());
+ if (caption().isRightToLeft())
+ p2.drawTiledPixmap( r.x(), 0, r.width()-captionWidth-4,
+ titleHeight+1, *titlePix );
+ else
+ p2.drawTiledPixmap( r.x()+captionWidth+3, 0, r.width()-captionWidth-4,
+ titleHeight+1, *titlePix );
+ }
+
+ p2.setPen( options()->color(ColorFont, isActive()) );
+ p2.drawText(r.x(), 1, r.width()-1, r.height(),
+ (caption().isRightToLeft() ? AlignRight : AlignLeft) | AlignVCenter,
+ caption() );
+
+ bitBlt( widget(), 2, 2, titleBuffer );
+
+ p2.end();
+
+ // Ensure a shaded window has no unpainted areas
+ // Is this still needed?
+#if 1
+ p.setPen(c2);
+ p.drawLine(x+borderWidth, y+titleHeight+4, x2-borderWidth, y+titleHeight+4);
+#endif
+}
+
+TQRegion KDEDefaultClient::cornerShape(WindowCorner corner)
+{
+ switch (corner) {
+ case WC_TopLeft:
+ return TQRect(0, 0, 1, 1);
+
+ case WC_TopRight:
+ return TQRect(width()-1, 0, 1, 1);
+
+ case WC_BottomLeft:
+ return TQRect(0, height()-1, 1, 1);
+
+ case WC_BottomRight:
+ return TQRect(width()-1, height()-1, 1, 1);
+
+ default:
+ return TQRegion();
+ }
+}
+
+} // namespace
+
+// Extended KWin plugin interface
+extern "C" KDE_EXPORT KDecorationFactory* create_factory()
+{
+ return new Default::KDEDefaultHandler();
+}
+
+// vim: ts=4
+// kate: space-indent off; tab-width 4;
diff --git a/twin/clients/default/kdedefault.h b/twin/clients/default/kdedefault.h
new file mode 100644
index 00000000..70b8847f
--- /dev/null
+++ b/twin/clients/default/kdedefault.h
@@ -0,0 +1,103 @@
+/*
+ *
+ * KDE2 Default KWin client
+ *
+ * Copyright (C) 1999, 2001 Daniel Duley <mosfet@kde.org>
+ * Matthias Ettrich <ettrich@kde.org>
+ * Karol Szwed <gallium@kde.org>
+ *
+ * Draws mini titlebars for tool windows.
+ * Many features are now customizable.
+ */
+
+#ifndef _KDE_DEFAULT_H
+#define _KDE_DEFAULT_H
+
+#include <tqbutton.h>
+#include <tqbitmap.h>
+#include <tqdatetime.h>
+#include <kpixmap.h>
+#include <kcommondecoration.h>
+#include <kdecorationfactory.h>
+
+class TQSpacerItem;
+class TQBoxLayout;
+class TQGridLayout;
+
+namespace Default {
+
+class KDEDefaultClient;
+
+class KDEDefaultHandler: public KDecorationFactory
+{
+ public:
+ KDEDefaultHandler();
+ ~KDEDefaultHandler();
+ KDecoration* createDecoration( KDecorationBridge* b );
+ bool reset( unsigned long changed );
+ virtual TQValueList< BorderSize > borderSizes() const;
+ virtual bool supports( Ability ability );
+
+ private:
+ unsigned long readConfig( bool update );
+ void createPixmaps();
+ void freePixmaps();
+ void drawButtonBackground(KPixmap *pix,
+ const TQColorGroup &g, bool sunken);
+};
+
+
+// class KDEDefaultButton : public TQButton, public KDecorationDefines
+class KDEDefaultButton : public KCommonDecorationButton
+{
+ public:
+ KDEDefaultButton(ButtonType type, KDEDefaultClient *parent, const char *name);
+ ~KDEDefaultButton();
+
+ void reset(unsigned long changed);
+
+ void setBitmap(const unsigned char *bitmap);
+
+ protected:
+ void enterEvent(TQEvent *);
+ void leaveEvent(TQEvent *);
+ void drawButton(TQPainter *p);
+ void drawButtonLabel(TQPainter*) {;}
+
+ TQBitmap* deco;
+ bool large;
+ bool isMouseOver;
+};
+
+
+class KDEDefaultClient : public KCommonDecoration
+{
+ public:
+ KDEDefaultClient( KDecorationBridge* b, KDecorationFactory* f );
+ ~KDEDefaultClient() {;}
+
+ virtual TQString visibleName() const;
+ virtual TQString defaultButtonsLeft() const;
+ virtual TQString defaultButtonsRight() const;
+ virtual bool decorationBehaviour(DecorationBehaviour behaviour) const;
+ virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
+ virtual KCommonDecorationButton *createButton(ButtonType type);
+
+ virtual TQRegion cornerShape(WindowCorner corner);
+
+ void init();
+ void reset( unsigned long changed );
+
+ protected:
+ void paintEvent( TQPaintEvent* );
+
+ private:
+ bool mustDrawHandle() const;
+ int titleHeight;
+};
+
+}
+
+#endif
+// vim: ts=4
+// kate: space-indent off; tab-width 4;
diff --git a/twin/clients/keramik/CMakeLists.txt b/twin/clients/keramik/CMakeLists.txt
new file mode 100644
index 00000000..89f563d3
--- /dev/null
+++ b/twin/clients/keramik/CMakeLists.txt
@@ -0,0 +1,54 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( config )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/twin/lib
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES keramik.desktop DESTINATION ${DATA_INSTALL_DIR}/twin )
+
+
+##### twin3_keramik (module) ####################
+
+set_source_files_properties( keramik.cpp
+ PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tiles.h )
+
+tde_add_kpart( twin3_keramik AUTOMOC
+ SOURCES keramik.cpp
+ LINK tdecorations-shared tdeui-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### tiles.h (header) ##########################
+
+file(GLOB _pics "${CMAKE_CURRENT_SOURCE_DIR}/pics/*.png" )
+
+add_custom_command( OUTPUT tiles.h
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/embedtool ${_pics}
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/embedtool ${_pics} )
+
+tde_add_executable( embedtool
+ SOURCES embedtool.cpp
+ LINK ${TQT_LIBRARIES}
+)
diff --git a/twin/clients/keramik/Makefile.am b/twin/clients/keramik/Makefile.am
new file mode 100644
index 00000000..17c1c3f9
--- /dev/null
+++ b/twin/clients/keramik/Makefile.am
@@ -0,0 +1,44 @@
+INCLUDES = -I$(srcdir)/../../lib $(all_includes)
+
+SUBDIRS = . config
+
+noinst_PROGRAMS = embedtool
+
+noinst_HEADERS = tiles.h
+
+embedtool_SOURCES = embedtool.cpp
+embedtool_LDADD = $(LIB_QT)
+embedtool_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+
+kde_module_LTLIBRARIES = twin3_keramik.la
+
+twin3_keramik_la_SOURCES = keramik.cpp
+twin3_keramik_la_COMPILE_FIRST = tiles.h
+twin3_keramik_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin3_keramik_la_LIBADD = $(LIB_TDEUI) ../../lib/libtdecorations.la
+#twin3_keramik_la_LDFLAGS = $(all_libraries) -avoid-version -module $(KDE_RPATH) $(KDE_MT_LDFLAGS)
+
+METASOURCES = AUTO
+noinst_headers = keramik.h tiles.h
+
+lnkdir = $(kde_datadir)/twin
+lnk_DATA = keramik.desktop
+
+EXTRA_DIST = $(lnk_DATA)
+
+tiles.h: pics/caption-large-left.png pics/caption-small-right.png pics/titlebar-center.png \
+ pics/titlebutton-square.png pics/border-left.png pics/caption-large-right.png \
+ pics/grabbar-center.png pics/titlebar-left.png pics/border-right.png \
+ pics/caption-small-center.png pics/grabbar-left.png pics/titlebar-right.png \
+ pics/caption-large-center.png pics/caption-small-left.png pics/grabbar-right.png \
+ pics/titlebutton-round.png pics/bottom-left.png pics/bottom-right.png \
+ pics/bottom-center.png \
+ pics/titlebutton-square-large.png pics/titlebutton-square-huge.png \
+ pics/titlebutton-round-large.png pics/titlebutton-round-huge.png
+
+tiles.h: embedtool
+ pics=`ls $(srcdir)/pics/*.png 2>/dev/null` ;\
+ ./embedtool $$pics
+
+keramik.lo: tiles.h
+
diff --git a/twin/clients/keramik/config/CMakeLists.txt b/twin/clients/keramik/config/CMakeLists.txt
new file mode 100644
index 00000000..7b5bdb33
--- /dev/null
+++ b/twin/clients/keramik/config/CMakeLists.txt
@@ -0,0 +1,29 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### twin_keramik_config (module) ##############
+
+tde_add_kpart( twin_keramik_config AUTOMOC
+ SOURCES config.cpp keramikconfig.ui
+ LINK tdeui-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/twin/clients/keramik/config/Makefile.am b/twin/clients/keramik/config/Makefile.am
new file mode 100644
index 00000000..19ee4f27
--- /dev/null
+++ b/twin/clients/keramik/config/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = twin_keramik_config.la
+
+twin_keramik_config_la_SOURCES = config.cpp keramikconfig.ui
+twin_keramik_config_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin_keramik_config_la_LIBADD = $(LIB_TDEUI)
+
+METASOURCES = AUTO
+noinst_HEADERS = config.h keramikconfig.h
+
+lnkdir = $(kde_datadir)/twin
+
diff --git a/twin/clients/keramik/config/config.cpp b/twin/clients/keramik/config/config.cpp
new file mode 100644
index 00000000..0f3be48c
--- /dev/null
+++ b/twin/clients/keramik/config/config.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * Keramik KWin client configuration module
+ *
+ * Copyright (C) 2002 Fredrik Hglund <fredrik@kde.org>
+ *
+ * Based on the Quartz configuration module,
+ * Copyright (c) 2001 Karol Szwed <gallium@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <tdeglobal.h>
+#include <tdelocale.h>
+
+#include <tqcheckbox.h>
+
+#include "config.h"
+#include "config.moc"
+
+extern "C"
+{
+ KDE_EXPORT TQObject* allocate_config( TDEConfig* conf, TQWidget* parent )
+ {
+ return ( new KeramikConfig( conf, parent ) );
+ }
+}
+
+
+/* NOTE:
+ * 'conf' is a pointer to the twindecoration modules open twin config,
+ * and is by default set to the "Style" group.
+ *
+ * 'parent' is the parent of the TQObject, which is a VBox inside the
+ * Configure tab in twindecoration
+ */
+
+KeramikConfig::KeramikConfig( TDEConfig* conf, TQWidget* parent )
+ : TQObject( parent )
+{
+ TDEGlobal::locale()->insertCatalogue("twin_clients");
+ c = new TDEConfig( "twinkeramikrc" );
+
+ ui = new KeramikConfigUI( parent );
+ connect( ui->showAppIcons, TQT_SIGNAL(clicked()), TQT_SIGNAL(changed()) );
+ connect( ui->smallCaptions, TQT_SIGNAL(clicked()), TQT_SIGNAL(changed()) );
+ connect( ui->largeGrabBars, TQT_SIGNAL(clicked()), TQT_SIGNAL(changed()) );
+ connect( ui->useShadowedText, TQT_SIGNAL(clicked()), TQT_SIGNAL(changed()) );
+
+ load( conf );
+ ui->show();
+}
+
+
+KeramikConfig::~KeramikConfig()
+{
+ delete ui;
+ delete c;
+}
+
+
+// Loads the configurable options from the twinrc config file
+// It is passed the open config from twindecoration to improve efficiency
+void KeramikConfig::load( TDEConfig* )
+{
+ c->setGroup("General");
+ ui->showAppIcons->setChecked( c->readBoolEntry("ShowAppIcons", true) );
+ ui->smallCaptions->setChecked( c->readBoolEntry("SmallCaptionBubbles", false) );
+ ui->largeGrabBars->setChecked( c->readBoolEntry("LargeGrabBars", true) );
+ ui->useShadowedText->setChecked( c->readBoolEntry("UseShadowedText", true) );
+}
+
+
+// Saves the configurable options to the twinrc config file
+void KeramikConfig::save( TDEConfig* )
+{
+ c->setGroup( "General" );
+ c->writeEntry( "ShowAppIcons", ui->showAppIcons->isChecked() );
+ c->writeEntry( "SmallCaptionBubbles", ui->smallCaptions->isChecked() );
+ c->writeEntry( "LargeGrabBars", ui->largeGrabBars->isChecked() );
+ c->writeEntry( "UseShadowedText", ui->useShadowedText->isChecked() );
+ c->sync();
+}
+
+
+// Sets UI widget defaults which must correspond to style defaults
+void KeramikConfig::defaults()
+{
+ ui->showAppIcons->setChecked( true );
+ ui->smallCaptions->setChecked( false );
+ ui->largeGrabBars->setChecked( true );
+ ui->useShadowedText->setChecked( true );
+
+ emit changed();
+}
+
+// vim: set noet ts=4 sw=4:
diff --git a/twin/clients/keramik/config/config.h b/twin/clients/keramik/config/config.h
new file mode 100644
index 00000000..886acb0f
--- /dev/null
+++ b/twin/clients/keramik/config/config.h
@@ -0,0 +1,58 @@
+/*
+ * Keramik KWin client configuration module
+ *
+ * Copyright (C) 2002 Fredrik Hglund <fredrik@kde.org>
+ *
+ * Based on the Quartz configuration module,
+ * Copyright (c) 2001 Karol Szwed <gallium@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KWIN_KERAMIK_CONFIG_H
+#define __KWIN_KERAMIK_CONFIG_H
+
+#include <tdeconfig.h>
+
+#include "keramikconfig.h"
+
+class KeramikConfig: public TQObject
+{
+ Q_OBJECT
+
+
+ public:
+ KeramikConfig( TDEConfig* conf, TQWidget* parent );
+ ~KeramikConfig();
+
+ // These public signals/slots work similar to KCM modules
+ signals:
+ void changed();
+
+ public slots:
+ void load( TDEConfig* conf );
+ void save( TDEConfig* conf );
+ void defaults();
+
+ private:
+ KeramikConfigUI *ui;
+ TDEConfig *c;
+};
+
+
+#endif
+
+// vim: set noet ts=4 sw=4:
diff --git a/twin/clients/keramik/config/keramikconfig.ui b/twin/clients/keramik/config/keramikconfig.ui
new file mode 100644
index 00000000..dda8d5b5
--- /dev/null
+++ b/twin/clients/keramik/config/keramikconfig.ui
@@ -0,0 +1,76 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KeramikConfigUI</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KeramikConfigUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>295</width>
+ <height>104</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Keramik</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>showAppIcons</cstring>
+ </property>
+ <property name="text">
+ <string>Display the window &amp;icon in the caption bubble</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want the window icon to be displayed in the caption bubble next to the titlebar text.</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>smallCaptions</cstring>
+ </property>
+ <property name="text">
+ <string>Draw &amp;small caption bubbles on active windows</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want the caption bubble to have the same size on active windows that it has on inactive ones. This option is useful for laptops or low resolution displays where you want maximize the amount of space available to the window contents.</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>largeGrabBars</cstring>
+ </property>
+ <property name="text">
+ <string>Draw g&amp;rab bars below windows</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want a grab bar to be drawn below windows. When this option is not selected only a thin border will be drawn in its place.</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>useShadowedText</cstring>
+ </property>
+ <property name="text">
+ <string>Use shadowed &amp;text</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want the titlebar text to have a 3D look with a shadow behind it.</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/twin/clients/keramik/embedtool.cpp b/twin/clients/keramik/embedtool.cpp
new file mode 100644
index 00000000..a635c4ee
--- /dev/null
+++ b/twin/clients/keramik/embedtool.cpp
@@ -0,0 +1,230 @@
+/*
+ * Keramik KWin embed tool (version 1.0)
+ *
+ * Copyright (C) 2002 Fredrik H�glund <fredrik@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <tqimage.h>
+#include <tqtextstream.h>
+#include <tqregexp.h>
+#include <tqfile.h>
+#include <tqfileinfo.h>
+#include <tqdatetime.h>
+
+#include <iostream>
+
+static int primes[] = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
+ 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
+ 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
+ 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+ 179, 181, 191, 193, 197, 199, 211, 223, 227, 229
+};
+
+struct EmbedImage {
+ TQString string;
+ int width;
+ int height;
+ bool alpha;
+ TQString name;
+};
+
+class KeramikEmbedder {
+public:
+ KeramikEmbedder();
+ ~KeramikEmbedder();
+
+ void embed( const char * );
+ void writeIndex();
+
+private:
+ TQFile *file;
+ TQPtrList<EmbedImage> *index;
+ TQTextStream stream;
+};
+
+KeramikEmbedder::KeramikEmbedder()
+{
+ TQDateTime date( TQDateTime::currentDateTime() );
+ TQString datestring( date.toString() );
+
+ file = new TQFile( "tiles.h" );
+ file->open( IO_WriteOnly | IO_Truncate );
+
+ stream.setDevice( TQT_TQIODEVICE(file) );
+
+ stream << "/*\n";
+ stream << " * Generated by embedtool 1.0 on " << datestring << endl;
+ stream << " */\n\n";
+
+ stream << "#ifndef __TILES_H\n";
+ stream << "#define __TILES_H\n\n";
+ stream << "#include <tqimage.h>\n";
+ stream << "#include <tqdict.h>\n\n";
+ stream << "namespace Keramik {\n\n";
+
+ index = new TQPtrList<EmbedImage>;
+ index->setAutoDelete( true );
+}
+
+KeramikEmbedder::~KeramikEmbedder()
+{
+ stream << "} // namespace Keramik\n\n";
+ stream << "#endif // __TILES_H\n\n";
+ stream << "// vim: set noet ts=4 sw=4:\n";
+
+ file->close();
+ delete file;
+ delete index;
+}
+
+void KeramikEmbedder::embed( const char *name )
+{
+ TQFileInfo fileinfo( name );
+ TQString basename( fileinfo.baseName() );
+ TQString codename( basename );
+ TQImage image( name );
+
+ codename = codename.replace( TQRegExp("[^a-zA-Z0-9]"), "_" );
+
+ stream << "\tstatic const QRgb " << codename << "_data[] = {" << endl << "\t\t";
+ stream.setf( TQTextStream::hex | TQTextStream::right );
+ stream.fill( '0' );
+
+ int pixels = image.width() * image.height();
+ TQ_UINT32 *data = reinterpret_cast<TQ_UINT32*>( image.bits() );
+ bool hasAlpha = false;
+
+
+ for ( int i = 0, j = 0; i < pixels; i++ ) {
+ if ( tqAlpha( *data ) && tqAlpha( *data ) != 0xff )
+ hasAlpha = true;
+
+ stream << "0x" << qSetW(8) << *(data++);
+
+ if ( i != pixels-1 ) {
+ stream << ',';
+
+ if ( j++ > 4 ) {
+ j = 0;
+ stream << endl << "\t\t";
+ } else
+ stream << ' ';
+ }
+ }
+
+ stream.reset();
+
+ stream << endl << "\t}; // " << codename << "_data" << endl << endl;
+
+ EmbedImage *imginfo = new EmbedImage;
+ imginfo->width = image.width();
+ imginfo->height = image.height();
+ imginfo->alpha = hasAlpha;
+ imginfo->name = codename;
+ imginfo->string = basename;
+ index->append( imginfo );
+}
+
+void KeramikEmbedder::writeIndex()
+{
+ stream << "\tstruct EmbedImage {\n";
+ stream << "\t\tconst char *name;\n";
+ stream << "\t\tint width;\n";
+ stream << "\t\tint height;\n";
+ stream << "\t\tbool alpha;\n";
+ stream << "\t\tconst QRgb *data;\n";
+ stream << "\t};\n\n";
+
+ uint i = 0;
+ stream << "\tstatic const EmbedImage image_db[] = {\n";
+ for ( EmbedImage *image = index->first(); image; image = index->next() )
+ {
+ stream << "\t\t{ \"" << image->string << "\", "
+ << image->width << ", " << image->height <<
+ ", " << (image->alpha ? "true" : "false")
+ << ", " << image->name << "_data }";
+ if ( i++ < index->count() - 1 )
+ stream << ',';
+ stream << endl;
+ }
+ stream << "\t};\n\n";
+
+ uint prime = 0;
+
+ for ( i = 0; i < 50; i++ )
+ if ( (prime = primes[i]) >= index->count() )
+ break;
+
+ stream << "\tclass KeramikImageDb {\n";
+ stream << "\tprivate:\n";
+ stream << "\t\tstatic KeramikImageDb *m_inst;\n";
+ stream << "\t\tTQDict<TQImage> *db;\n\n";
+ stream << "\t\tKeramikImageDb() {\n";
+ stream << "\t\t\tdb = new TQDict<TQImage>( " << prime << " );\n";
+ stream << "\t\t\tdb->setAutoDelete( true );\n\n";
+ stream << "\t\t\tfor ( int i = 0; i < " << index->count() << "; i++ ) {\n";
+ stream << "\t\t\t\tTQImage *img = new TQImage( (uchar*)image_db[i].data,\n";
+ stream << "\t\t\t\t\t\timage_db[i].width, image_db[i].height,\n";
+ stream << "\t\t\t\t\t\t32, NULL, 0, TQImage::LittleEndian );\n\n";
+ stream << "\t\t\t\tif ( image_db[i].alpha )\n";
+ stream << "\t\t\t\t\timg->setAlphaBuffer( true );\n\n";
+ stream << "\t\t\t\tdb->insert( image_db[i].name, img );\n";
+ stream << "\t\t\t}\n";
+ stream << "\t\t}\n\n";
+ stream << "\t\t~KeramikImageDb() {\n";
+ stream << "\t\t\tdelete db;\n";
+ stream << "\t\t}\n\n";
+ stream << "\tpublic:\n";
+ stream << "\t\tstatic KeramikImageDb* instance() {\n";
+ stream << "\t\t\tif ( ! m_inst ) m_inst = new KeramikImageDb;\n";
+ stream << "\t\t\treturn m_inst;\n";
+ stream << "\t\t}\n\n";
+ stream << "\t\tstatic void release() {\n";
+ stream << "\t\t\tif ( m_inst ) delete m_inst;\n";
+ stream << "\t\t\tm_inst = NULL;\n";
+ stream << "\t\t}\n\n";
+ stream << "\t\tTQImage *image( const TQString &name ) const {\n";
+ stream << "\t\t\treturn db->find( name );\n";
+ stream << "\t\t}\n\n";
+ stream << "\t}; // class KeramikImageDb\n\n";
+ stream << "\tKeramikImageDb *KeramikImageDb::m_inst = NULL;\n\n";
+}
+
+int main( int argv, char **argc )
+{
+ if ( argv < 2 ) {
+ std::cout << "Insufficient arguments" << std::endl;
+ return 1;
+ }
+
+ KeramikEmbedder embedder;
+
+ for ( int i = 1; i < argv; i++ )
+ {
+ std::cout << argc[i] << std::endl;
+ embedder.embed( argc[i] );
+ }
+
+ embedder.writeIndex();
+
+ return 0;
+}
+
+// vim: set noet ts=4 sw=4:
+
diff --git a/twin/clients/keramik/keramik.cpp b/twin/clients/keramik/keramik.cpp
new file mode 100644
index 00000000..55eb5787
--- /dev/null
+++ b/twin/clients/keramik/keramik.cpp
@@ -0,0 +1,1854 @@
+/*
+ *
+ * Keramik KWin client (version 0.8)
+ *
+ * Copyright (C) 2002 Fredrik H�lund <fredrik@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <tdeconfig.h>
+#include <tdelocale.h>
+#include <kiconeffect.h>
+
+#include <tqpainter.h>
+#include <tqlayout.h>
+#include <tqbitmap.h>
+#include <tqstyle.h>
+#include <tqtooltip.h>
+#include <tqwidget.h>
+#include <tqlabel.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include "keramik.h"
+#include "keramik.moc"
+
+
+
+// -------------------------------------------------------------------------------------------
+
+static void flip( TQPixmap *&pix )
+{
+ TQPixmap *tmp = new TQPixmap( pix->xForm( TQWMatrix(-1,0,0,1,pix->width(),0) ) );
+ delete pix;
+ pix = tmp;
+}
+
+static void flip( TQBitmap *&pix )
+{
+ TQBitmap *tmp = new TQBitmap( pix->xForm( TQWMatrix(-1,0,0,1,pix->width(),0) ) );
+ delete pix;
+ pix = tmp;
+}
+
+namespace Keramik
+{
+
+ const int buttonMargin = 9; // Margin between the window edge and the buttons
+ const int buttonSpacing = 4; // Spacing between the titlebar buttons
+ const int iconSpacing = 5; // Spacing between the icon and the text label
+
+ // Default button layout
+ const char default_left[] = "M";
+ const char default_right[] = "HIAX";
+
+ // Titlebar button bitmaps
+ const unsigned char menu_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0xf0, 0x07, 0x00,
+ 0xe0, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char on_all_desktops_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char not_on_all_desktops_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char help_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0xf0, 0x07, 0x00, 0x30, 0x06, 0x00, 0x00, 0x07, 0x00, 0x80, 0x03, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char minimize_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char maximize_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char restore_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char close_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x0c, 0x00, 0x70, 0x0e, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00,
+ 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0x70, 0x0e, 0x00, 0x30, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char above_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char above_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
+ 0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char below_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
+ 0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char below_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char shade_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00,
+ 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char shade_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ KeramikHandler *clientHandler = NULL;
+ bool keramik_initialized = false;
+
+
+
+// -------------------------------------------------------------------------------------------
+
+
+
+KeramikHandler::KeramikHandler()
+{
+ for ( int i = 0; i < NumTiles; i++ ) {
+ activeTiles[i] = NULL;
+ inactiveTiles[i] = NULL;
+ }
+
+ settings_cache = NULL;
+
+ imageDb = KeramikImageDb::instance();
+
+ // Create the button deco bitmaps
+ buttonDecos[ Menu ] = new TQBitmap( 17, 17, menu_bits, true );
+ buttonDecos[ OnAllDesktops ] = new TQBitmap( 17, 17, on_all_desktops_bits, true );
+ buttonDecos[ NotOnAllDesktops ] = new TQBitmap( 17, 17, not_on_all_desktops_bits, true );
+ buttonDecos[ Help ] = new TQBitmap( 17, 17, help_bits, true );
+ buttonDecos[ Minimize ] = new TQBitmap( 17, 17, minimize_bits, true );
+ buttonDecos[ Maximize ] = new TQBitmap( 17, 17, maximize_bits, true );
+ buttonDecos[ Restore ] = new TQBitmap( 17, 17, restore_bits, true );
+ buttonDecos[ Close ] = new TQBitmap( 17, 17, close_bits, true );
+ buttonDecos[ AboveOn ] = new TQBitmap( 17, 17, above_on_bits, true );
+ buttonDecos[ AboveOff ] = new TQBitmap( 17, 17, above_off_bits, true );
+ buttonDecos[ BelowOn ] = new TQBitmap( 17, 17, below_on_bits, true );
+ buttonDecos[ BelowOff ] = new TQBitmap( 17, 17, below_off_bits, true );
+ buttonDecos[ ShadeOn ] = new TQBitmap( 17, 17, shade_on_bits, true );
+ buttonDecos[ ShadeOff ] = new TQBitmap( 17, 17, shade_off_bits, true );
+
+ // Selfmask the bitmaps
+ for ( int i = 0; i < NumButtonDecos; i++ )
+ buttonDecos[i]->setMask( *buttonDecos[i] );
+
+ // Flip the bitmaps horizontally in right-to-left mode
+ if ( TQApplication::reverseLayout() ) {
+ for ( int i = 0; i < Help; ++i )
+ ::flip( buttonDecos[i] );
+
+ for ( int i = Help + 1; i < NumButtonDecos; ++i )
+ ::flip( buttonDecos[i] );
+ }
+
+ readConfig();
+ createPixmaps();
+
+ keramik_initialized = true;
+}
+
+
+KeramikHandler::~KeramikHandler()
+{
+ keramik_initialized = false;
+ destroyPixmaps();
+
+ for ( int i = 0; i < NumButtonDecos; i++ )
+ delete buttonDecos[i];
+
+ delete settings_cache;
+
+ KeramikImageDb::release();
+ imageDb = NULL;
+ clientHandler = NULL;
+}
+
+
+void KeramikHandler::createPixmaps()
+{
+ int heightOffset;
+ int widthOffset;
+ switch(options()->preferredBorderSize(this)) {
+ case BorderLarge:
+ widthOffset = 4;
+ heightOffset = 0;
+ break;
+ case BorderVeryLarge:
+ widthOffset = 8;
+ heightOffset = 0;
+ break;
+ case BorderHuge:
+ widthOffset = 14;
+ heightOffset = 0;
+ break;
+ case BorderVeryHuge:
+ widthOffset = 23;
+ heightOffset = 10;
+ break;
+ case BorderOversized:
+ widthOffset = 36;
+ heightOffset = 25;
+ break;
+ case BorderTiny:
+ case BorderNormal:
+ default:
+ widthOffset = 0;
+ heightOffset = 0;
+ }
+ int fontHeight = TQFontMetrics(options()->font(true)).height();
+ if (fontHeight > heightOffset + 20)
+ heightOffset = fontHeight - 20;
+
+ TQString size = (heightOffset < 8) ? "" : (heightOffset < 20) ? "-large" : "-huge";
+
+ TQColor titleColor, captionColor, buttonColor;
+ TQImage *titleCenter = NULL, *captionLeft = NULL,
+ *captionRight = NULL, *captionCenter = NULL;
+
+
+ // Active tiles
+ // -------------------------------------------------------------------------
+ captionColor = KDecoration::options()->color( ColorTitleBar, true );
+ titleColor = KDecoration::options()->color( ColorTitleBlend, true );
+
+ // Load the titlebar corners.
+ activeTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
+ activeTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
+
+ // Load the titlebar center tile image (this will be used as
+ // the background for the caption bubble tiles).
+ titleCenter = loadImage( "titlebar-center", titleColor );
+
+ // Load the small version of the caption bubble corner & center images.
+ captionLeft = loadImage( "caption-small-left", captionColor );
+ captionRight = loadImage( "caption-small-right", captionColor );
+ captionCenter = loadImage( "caption-small-center", captionColor );
+
+ // Create the caption bubble tiles (by blending the images onto the titlebar)
+ activeTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
+ activeTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
+ activeTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
+
+ delete captionLeft;
+ delete captionRight;
+ delete captionCenter;
+
+ // Now do the same with the large version
+ captionLeft = loadImage( "caption-large-left", captionColor );
+ captionRight = loadImage( "caption-large-right", captionColor );
+ captionCenter = loadImage( "caption-large-center", captionColor );
+
+ activeTiles[ CaptionLargeLeft ] = composite( captionLeft, titleCenter );
+ activeTiles[ CaptionLargeRight ] = composite( captionRight, titleCenter );
+ activeTiles[ CaptionLargeCenter ] = composite( captionCenter, titleCenter );
+
+ delete captionLeft;
+ delete captionRight;
+ delete captionCenter;
+
+ // Create the titlebar center tile
+ activeTiles[ TitleCenter ] = new TQPixmap( *titleCenter );
+
+ delete titleCenter;
+
+ // Load the left & right border pixmaps
+ activeTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
+ activeTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
+
+ // Load the bottom grabbar pixmaps
+ if ( largeGrabBars ) {
+ activeTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
+ activeTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
+ activeTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
+ } else {
+ activeTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
+ activeTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
+ activeTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
+ }
+
+ // Inactive tiles
+ // -------------------------------------------------------------------------
+ captionColor = KDecoration::options()->color( ColorTitleBar, false );
+ titleColor = KDecoration::options()->color( ColorTitleBlend, false );
+
+ inactiveTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
+ inactiveTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
+
+ titleCenter = loadImage( "titlebar-center", titleColor );
+
+ captionLeft = loadImage( "caption-small-left", captionColor );
+ captionRight = loadImage( "caption-small-right", captionColor );
+ captionCenter = loadImage( "caption-small-center", captionColor );
+
+ inactiveTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
+ inactiveTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
+ inactiveTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
+
+ delete captionLeft;
+ delete captionRight;
+ delete captionCenter;
+
+ inactiveTiles[ TitleCenter ] = new TQPixmap( *titleCenter );
+
+ delete titleCenter;
+
+ inactiveTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
+ inactiveTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
+
+ if ( largeGrabBars ) {
+ inactiveTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
+ inactiveTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
+ inactiveTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
+ } else {
+ inactiveTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
+ inactiveTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
+ inactiveTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
+ }
+
+ // Buttons
+ // -------------------------------------------------------------------------
+ buttonColor = TQColor(); //KDecoration::options()->color( ButtonBg, true );
+
+ titleButtonRound = loadPixmap( "titlebutton-round"+size, buttonColor );
+ titleButtonSquare = loadPixmap( "titlebutton-square"+size, buttonColor );
+
+
+ // Prepare the tiles for use
+ // -------------------------------------------------------------------------
+ if ( TQApplication::reverseLayout() ) {
+
+ // Fix lighting
+ flip( activeTiles[CaptionSmallLeft], activeTiles[CaptionSmallRight] );
+ flip( inactiveTiles[CaptionSmallLeft], inactiveTiles[CaptionSmallRight] );
+
+ flip( activeTiles[CaptionLargeLeft], activeTiles[CaptionLargeRight] );
+
+ flip( activeTiles[TitleLeft], activeTiles[TitleRight] );
+ flip( inactiveTiles[TitleLeft], inactiveTiles[TitleRight] );
+
+ flip( activeTiles[BorderLeft], activeTiles[BorderRight] );
+ flip( inactiveTiles[BorderLeft], inactiveTiles[BorderRight] );
+
+ flip( activeTiles[GrabBarLeft], activeTiles[GrabBarRight] );
+ flip( inactiveTiles[GrabBarLeft], inactiveTiles[GrabBarRight] );
+
+ ::flip( titleButtonRound );
+ ::flip( titleButtonSquare );
+ }
+
+ // Pretile the center & border tiles for optimal performance
+ pretile( activeTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
+ pretile( activeTiles[ CaptionLargeCenter ], 64, Qt::Horizontal );
+ pretile( activeTiles[ TitleCenter ], 64, Qt::Horizontal );
+ pretile( activeTiles[ GrabBarCenter ], 128, Qt::Horizontal );
+ pretile( activeTiles[ BorderLeft ], 128, Qt::Vertical );
+ pretile( activeTiles[ BorderRight ], 128, Qt::Vertical );
+
+ pretile( inactiveTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
+ pretile( inactiveTiles[ TitleCenter ], 64, Qt::Horizontal );
+ pretile( inactiveTiles[ GrabBarCenter ], 128, Qt::Horizontal );
+ pretile( inactiveTiles[ BorderLeft ], 128, Qt::Vertical );
+ pretile( inactiveTiles[ BorderRight ], 128, Qt::Vertical );
+
+ if (heightOffset > 0) {
+ addHeight (heightOffset, activeTiles[TitleLeft]);
+ addHeight (heightOffset, activeTiles[TitleCenter]);
+ addHeight (heightOffset, activeTiles[TitleRight]);
+ addHeight (heightOffset, activeTiles[CaptionSmallLeft]);
+ addHeight (heightOffset, activeTiles[CaptionSmallCenter]);
+ addHeight (heightOffset, activeTiles[CaptionSmallRight]);
+ addHeight (heightOffset, activeTiles[CaptionLargeLeft]);
+ addHeight (heightOffset, activeTiles[CaptionLargeCenter]);
+ addHeight (heightOffset, activeTiles[CaptionLargeRight]);
+
+ addHeight (heightOffset, inactiveTiles[TitleLeft]);
+ addHeight (heightOffset, inactiveTiles[TitleCenter]);
+ addHeight (heightOffset, inactiveTiles[TitleRight]);
+ addHeight (heightOffset, inactiveTiles[CaptionSmallLeft]);
+ addHeight (heightOffset, inactiveTiles[CaptionSmallCenter]);
+ addHeight (heightOffset, inactiveTiles[CaptionSmallRight]);
+ }
+
+ if (widthOffset > 0) {
+ addWidth (widthOffset, activeTiles[BorderLeft], true, activeTiles[GrabBarCenter]);
+ addWidth (widthOffset, activeTiles[BorderRight], false, activeTiles[GrabBarCenter]);
+ addWidth (widthOffset, inactiveTiles[BorderLeft], true, inactiveTiles[GrabBarCenter]);
+ addWidth (widthOffset, inactiveTiles[BorderRight], false, inactiveTiles[GrabBarCenter]);
+
+ if (largeGrabBars)
+ widthOffset = widthOffset*3/2;
+
+ addHeight (widthOffset, activeTiles[GrabBarLeft]);
+ addHeight (widthOffset, activeTiles[GrabBarCenter]);
+ addHeight (widthOffset, activeTiles[GrabBarRight]);
+ addHeight (widthOffset, inactiveTiles[GrabBarLeft]);
+ addHeight (widthOffset, inactiveTiles[GrabBarCenter]);
+ addHeight (widthOffset, inactiveTiles[GrabBarRight]);
+ }
+}
+
+
+
+void KeramikHandler::destroyPixmaps()
+{
+ for ( int i = 0; i < NumTiles; i++ ) {
+ delete activeTiles[i];
+ delete inactiveTiles[i];
+ activeTiles[i] = NULL;
+ inactiveTiles[i] = NULL;
+ }
+
+ delete titleButtonRound;
+ delete titleButtonSquare;
+}
+
+
+void KeramikHandler::addWidth (int width, TQPixmap *&pix, bool left, TQPixmap *bottomPix) {
+ int w = pix->width()+width;
+ int h = pix->height();
+
+ TQPixmap *tmp = new TQPixmap (w, h);
+ tmp->fill ();
+ TQPainter p;
+ p.begin (tmp);
+
+ for (int i = 0; i < h; i++)
+ p.drawPixmap (0, i, *bottomPix, i%2, 0, w,1);
+
+ if (left)
+ p.drawPixmap(0, 0, *pix);
+ else
+ p.drawPixmap(width, 0, *pix);
+
+ p.end();
+
+ delete pix;
+ pix = tmp;
+}
+
+
+void KeramikHandler::addHeight (int height, TQPixmap *&pix) {
+ int w = pix->width();
+ int h = pix->height()+height;
+
+ TQPixmap *tmp = new TQPixmap (w, h);
+ TQPainter p;
+ p.begin (tmp);
+ if (pix->height() > 10) {
+ p.drawPixmap(0, 0, *pix, 0, 0, w, 11);
+ for (int i = 0; i < height; i+=2)
+ p.drawPixmap(0, 11+i, *pix, 0, 11, w, 2);
+ p.drawPixmap(0, 11+height, *pix, 0, 11, w, -1);
+ }
+ else {
+ int lines = h-3;
+ int factor = pix->height()-3;
+ for (int i = 0; i < lines; i++)
+ p.drawPixmap(0, i, *pix, 0, i*factor/lines, w, 1);
+ p.drawPixmap(0, lines, *pix, 0, factor, w, 3);
+ }
+ p.end();
+
+ delete pix;
+ pix = tmp;
+}
+
+
+void KeramikHandler::flip( TQPixmap *&pix1, TQPixmap *&pix2 )
+{
+ // Flip the pixmaps horizontally
+ TQPixmap *tmp = new TQPixmap( pix1->xForm( TQWMatrix(-1,0,0,1,pix1->width(),0) ) );
+
+ delete pix1;
+ pix1 = new TQPixmap( pix2->xForm( TQWMatrix(-1,0,0,1,pix2->width(),0) ) );
+
+ delete pix2;
+ pix2 = tmp;
+}
+
+
+void KeramikHandler::pretile( TQPixmap *&pix, int size, Qt::Orientation dir )
+{
+ TQPixmap *newpix;
+ TQPainter p;
+
+ if ( dir == Qt::Horizontal )
+ newpix = new TQPixmap( size, pix->height() );
+ else
+ newpix = new TQPixmap( pix->width(), size );
+
+ p.begin( newpix );
+ p.drawTiledPixmap( newpix->rect(), *pix ) ;
+ p.end();
+
+ delete pix;
+ pix = newpix;
+}
+
+
+void KeramikHandler::readConfig()
+{
+ TDEConfig *c = new TDEConfig( "twinkeramikrc" );
+
+ c->setGroup( "General" );
+ showIcons = c->readBoolEntry( "ShowAppIcons", true );
+ shadowedText = c->readBoolEntry( "UseShadowedText", true );
+ smallCaptionBubbles = c->readBoolEntry( "SmallCaptionBubbles", false );
+ largeGrabBars = c->readBoolEntry( "LargeGrabBars", true );
+
+ if ( ! settings_cache ) {
+ settings_cache = new SettingsCache;
+ settings_cache->largeGrabBars = largeGrabBars;
+ settings_cache->smallCaptionBubbles = smallCaptionBubbles;
+ }
+
+ delete c;
+}
+
+
+TQPixmap *KeramikHandler::composite( TQImage *over, TQImage *under )
+{
+ TQImage dest( over->width(), over->height(), 32 );
+ int width = over->width(), height = over->height();
+
+ // Clear the destination image
+ TQ_UINT32 *data = reinterpret_cast<TQ_UINT32*>( dest.bits() );
+ for (int i = 0; i < width * height; i++)
+ *(data++) = 0;
+
+ // Copy the under image (bottom aligned) to the destination image
+ for (int y1 = height - under->height(), y2 = 0; y1 < height; y1++, y2++ )
+ {
+ register TQ_UINT32 *dst = reinterpret_cast<TQ_UINT32*>( dest.scanLine(y1) );
+ register TQ_UINT32 *src = reinterpret_cast<TQ_UINT32*>( under->scanLine(y2) );
+
+ for ( int x = 0; x < width; x++ )
+ *(dst++) = *(src++);
+ }
+
+ // Blend the over image onto the destination
+ register TQ_UINT32 *dst = reinterpret_cast<TQ_UINT32*>( dest.bits() );
+ register TQ_UINT32 *src = reinterpret_cast<TQ_UINT32*>( over->bits() );
+ for ( int i = 0; i < width * height; i++ )
+ {
+ int r1 = tqRed( *dst ), g1 = tqGreen( *dst ), b1 = tqBlue( *dst );
+ int r2 = tqRed( *src ), g2 = tqGreen( *src ), b2 = tqBlue( *src );
+ int a = tqAlpha( *src );
+
+ if ( a == 0xff )
+ *dst = *src;
+
+ else if ( a != 0x00 )
+ *dst = tqRgba( TQ_UINT8( r1 + (((r2 - r1) * a) >> 8) ),
+ TQ_UINT8( g1 + (((g2 - g1) * a) >> 8) ),
+ TQ_UINT8( b1 + (((b2 - b1) * a) >> 8) ),
+ 0xff );
+
+ else if ( tqAlpha(*dst) == 0x00 )
+ *dst = 0;
+
+ src++; dst++;
+ }
+
+ // Create the final pixmap and return it
+ return new TQPixmap( dest );
+}
+
+
+TQImage *KeramikHandler::loadImage( const TQString &name, const TQColor &col )
+{
+ if ( col.isValid() ) {
+ TQImage *img = new TQImage( imageDb->image(name)->copy() );
+ TDEIconEffect::colorize( *img, col, 1.0 );
+ return img;
+ } else
+ return new TQImage( imageDb->image(name)->copy() );
+}
+
+
+TQPixmap *KeramikHandler::loadPixmap( const TQString &name, const TQColor &col )
+{
+ TQImage *img = loadImage( name, col );
+ TQPixmap *pix = new TQPixmap( *img );
+ delete img;
+
+ return pix;
+}
+
+
+bool KeramikHandler::reset( unsigned long changed )
+{
+ keramik_initialized = false;
+
+ bool needHardReset = false;
+ bool pixmapsInvalid = false;
+
+ // Re-read the config file
+ readConfig();
+
+ if ( changed & SettingBorder )
+ {
+ pixmapsInvalid = true;
+ needHardReset = true;
+ }
+ if ( changed & SettingFont )
+ {
+ pixmapsInvalid = true;
+ needHardReset = true;
+ }
+ // Check if the color scheme has changed
+ if ( changed & SettingColors )
+ {
+ pixmapsInvalid = true;
+ }
+ // Check if button positions have changed
+
+ if ( changed & SettingButtons ) {
+ needHardReset = true;
+ }
+
+ // Check if tooltips options have changed
+ if ( changed & SettingTooltips ) {
+ needHardReset = true;
+ }
+
+ if ( (settings_cache->largeGrabBars != largeGrabBars) ) {
+ pixmapsInvalid = true;
+ needHardReset = true;
+ }
+
+ if ( (settings_cache->smallCaptionBubbles != smallCaptionBubbles) ) {
+ needHardReset = true;
+ }
+
+ // Update our config cache
+ settings_cache->largeGrabBars = largeGrabBars;
+ settings_cache->smallCaptionBubbles = smallCaptionBubbles;
+
+ // Do we need to recreate the pixmaps?
+ if ( pixmapsInvalid ) {
+ destroyPixmaps();
+ createPixmaps();
+ }
+
+ keramik_initialized = true;
+
+ // Do we need to "hit the wooden hammer" ?
+ if ( !needHardReset )
+ resetDecorations( changed );
+ return needHardReset;
+}
+
+
+bool KeramikHandler::supports( Ability ability )
+{
+ switch( ability )
+ {
+ case AbilityAnnounceButtons:
+ case AbilityButtonMenu:
+ case AbilityButtonOnAllDesktops:
+ case AbilityButtonSpacer:
+ case AbilityButtonHelp:
+ case AbilityButtonMinimize:
+ case AbilityButtonMaximize:
+ case AbilityButtonClose:
+ case AbilityButtonAboveOthers:
+ case AbilityButtonBelowOthers:
+ case AbilityButtonShade:
+ return true;
+ default:
+ return false;
+ };
+}
+
+
+const TQPixmap *KeramikHandler::tile( TilePixmap tilePix, bool active ) const
+{
+ return ( active ? activeTiles[ tilePix ] : inactiveTiles[ tilePix ] );
+}
+
+KDecoration* KeramikHandler::createDecoration( KDecorationBridge* bridge )
+{
+ return new KeramikClient( bridge, this );
+}
+
+TQValueList< KeramikHandler::BorderSize > KeramikHandler::borderSizes() const
+{ // the list must be sorted
+ return TQValueList< BorderSize >() << BorderNormal << BorderLarge <<
+ BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
+}
+
+
+// -------------------------------------------------------------------------------------------
+
+
+
+KeramikButton::KeramikButton( KeramikClient* c, const char *name, Button btn, const TQString &tip, const int realizeBtns )
+ : TQButton( c->widget(), name ),
+ client( c ), button( btn ), hover( false ), lastbutton( Qt::NoButton )
+{
+ realizeButtons = realizeBtns;
+
+ TQToolTip::add( this, tip ); // FRAME
+ setBackgroundMode( NoBackground );
+ setCursor( tqarrowCursor );
+ int size = clientHandler->roundButton()->height();
+ setFixedSize( size, size );
+
+ setToggleButton( (button == OnAllDesktopsButton) );
+}
+
+
+KeramikButton::~KeramikButton()
+{
+ // Empty.
+}
+
+
+void KeramikButton::enterEvent( TQEvent *e )
+{
+ TQButton::enterEvent( e );
+
+ hover = true;
+ repaint( false );
+}
+
+
+void KeramikButton::leaveEvent( TQEvent *e )
+{
+ TQButton::leaveEvent( e );
+
+ hover = false;
+ repaint( false );
+}
+
+
+void KeramikButton::mousePressEvent( TQMouseEvent *e )
+{
+ lastbutton = e->button();
+ TQMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
+ TQButton::mousePressEvent( &me );
+}
+
+
+void KeramikButton::mouseReleaseEvent( TQMouseEvent *e )
+{
+ lastbutton = e->button();
+ TQMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
+ TQButton::mouseReleaseEvent( &me );
+}
+
+
+void KeramikButton::drawButton( TQPainter *p )
+{
+ const TQPixmap *pix;
+ const TQBitmap *deco;
+ int size = clientHandler->roundButton()->height();
+
+ // Get the bevel from the client handler
+ if ( button == MenuButton || button == OnAllDesktopsButton || button == HelpButton )
+ pix = clientHandler->roundButton();
+ else
+ pix = clientHandler->squareButton();
+
+ // Draw the button background
+ const TQPixmap *background = clientHandler->tile( TitleCenter, client->isActive() );
+ p->drawPixmap( 0, 0, *background,
+ 0, (background->height()-size+1)/2, size, size );
+
+ if ( isDown() ) {
+ // Pressed
+ p->drawPixmap( TQPoint(), *pix, TQStyle::visualRect( TQRect(2*size, 0, size, size), pix->rect() ) );
+ p->translate( TQApplication::reverseLayout() ? -1 : 1, 1 );
+ } else if ( hover )
+ // Mouse over
+ p->drawPixmap( TQPoint(), *pix, TQStyle::visualRect( TQRect(size, 0, size, size), pix->rect() ) );
+ else
+ // Normal
+ p->drawPixmap( TQPoint(), *pix, TQStyle::visualRect( TQRect(0, 0, size, size), pix->rect() ) );
+
+
+ // Draw the button deco on the bevel
+ switch ( button ) {
+ case MenuButton:
+ deco = clientHandler->buttonDeco( Menu );
+ break;
+
+ case OnAllDesktopsButton:
+ deco = clientHandler->buttonDeco( client->isOnAllDesktops() ? NotOnAllDesktops : OnAllDesktops );
+ break;
+
+ case HelpButton:
+ deco = clientHandler->buttonDeco( Help );
+ // The '?' won't be flipped around in the ctor, so we need to
+ // shift it to the right to compensate for the button shadow
+ // being on the left side of the button in RTL mode.
+ if ( TQApplication::reverseLayout() )
+ p->translate( 2, 0 );
+ break;
+
+ case MinButton:
+ deco = clientHandler->buttonDeco( Minimize );
+ break;
+
+ case MaxButton:
+ deco = clientHandler->buttonDeco( client->maximizeMode() == KeramikClient::MaximizeFull ? Restore : Maximize );
+ break;
+
+ case CloseButton:
+ deco = clientHandler->buttonDeco( Close );
+ break;
+
+ case AboveButton:
+ deco = clientHandler->buttonDeco( client->keepAbove() ? AboveOn : AboveOff );
+ break;
+
+ case BelowButton:
+ deco = clientHandler->buttonDeco( client->keepBelow() ? BelowOn : BelowOff );
+ break;
+
+ case ShadeButton:
+ deco = clientHandler->buttonDeco( client->isSetShade() ? ShadeOn : ShadeOff );
+ break;
+
+ default:
+ deco = NULL;
+ }
+
+ p->setPen( Qt::black ); // ### hardcoded color
+ p->drawPixmap( (size-17)/2, (size-17)/2, *deco );
+}
+
+
+
+// ------------------------------------------------------------------------------------------
+
+
+
+KeramikClient::KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory )
+ : KDecoration( bridge, factory ),
+ activeIcon( NULL ), inactiveIcon( NULL ), captionBufferDirty( true ), maskDirty( true )
+{
+}
+
+void KeramikClient::init()
+{
+ connect( this, TQT_SIGNAL( keepAboveChanged( bool )), TQT_SLOT( keepAboveChange( bool )));
+ connect( this, TQT_SIGNAL( keepBelowChanged( bool )), TQT_SLOT( keepBelowChange( bool )));
+
+ createMainWidget( (WFlags)(WStaticContents | WResizeNoErase | WRepaintNoErase) );
+ widget()->installEventFilter( this );
+
+ // Minimize flicker
+ widget()->setBackgroundMode( NoBackground );
+
+ for ( int i=0; i < NumButtons; i++ )
+ button[i] = NULL;
+
+ createLayout();
+}
+
+void KeramikClient::createLayout()
+{
+
+ TQVBoxLayout *mainLayout = new TQVBoxLayout( widget() );
+ TQBoxLayout *titleLayout = new TQBoxLayout( 0, TQBoxLayout::LeftToRight, 0, 0, 0 );
+ TQHBoxLayout *windowLayout = new TQHBoxLayout();
+
+ largeTitlebar = ( !maximizedVertical() && clientHandler->largeCaptionBubbles() );
+ largeCaption = ( isActive() && largeTitlebar );
+
+ int grabBarHeight = clientHandler->grabBarHeight();
+ int topSpacing = ( largeTitlebar ? 4 : 1 );
+ int leftBorderWidth = clientHandler->tile( BorderLeft, true )->width();
+ int rightBorderWidth = clientHandler->tile( BorderRight, true )->width();
+ topSpacer = new TQSpacerItem( 10, topSpacing,
+ TQSizePolicy::Expanding, TQSizePolicy::Minimum );
+
+ mainLayout->addItem( topSpacer );
+
+ mainLayout->addLayout( titleLayout ); // Titlebar
+ mainLayout->addLayout( windowLayout, 1 ); // Left border + window + right border
+ mainLayout->addSpacing( grabBarHeight ); // Bottom grab bar
+
+ titleLayout->setSpacing( buttonSpacing );
+
+ titleLayout->addSpacing( buttonMargin ); // Left button margin
+ addButtons( titleLayout, options()->customButtonPositions() ?
+ options()->titleButtonsLeft() : TQString(default_left) );
+
+ titlebar = new TQSpacerItem( 10, clientHandler->titleBarHeight(largeTitlebar)
+ - topSpacing, TQSizePolicy::Expanding, TQSizePolicy::Minimum );
+ titleLayout->addItem( titlebar );
+
+ titleLayout->addSpacing( buttonSpacing );
+ addButtons( titleLayout, options()->customButtonPositions() ?
+ options()->titleButtonsRight() : TQString(default_right) );
+ titleLayout->addSpacing( buttonMargin - 1 ); // Right button margin
+
+ windowLayout->addSpacing( leftBorderWidth ); // Left border
+ if( isPreview())
+ windowLayout->addWidget( new TQLabel( i18n( "<center><b>Keramik preview</b></center>" ), widget()));
+ else
+ windowLayout->addItem( new TQSpacerItem( 0, 0 )); //no widget in the middle
+ windowLayout->addSpacing( rightBorderWidth ); // Right border
+}
+
+
+KeramikClient::~KeramikClient()
+{
+ delete activeIcon;
+ delete inactiveIcon;
+
+ activeIcon = inactiveIcon = NULL;
+}
+
+
+void KeramikClient::reset( unsigned long )
+{
+ if ( clientHandler->largeCaptionBubbles() && !largeTitlebar )
+ {
+ // We're switching from small caption bubbles to large
+ if ( !maximizedVertical() ) {
+ topSpacer->changeSize( 10, 4, TQSizePolicy::Expanding, TQSizePolicy::Minimum );
+ largeTitlebar = true;
+ largeCaption = isActive();
+
+ widget()->layout()->activate();
+
+ // Compensate for the titlebar size change
+
+ // TODO This is wrong, this may break size increments (see bug #53784).
+ // FRAME
+ widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
+ }
+ }
+ else if ( !clientHandler->largeCaptionBubbles() && largeTitlebar )
+ {
+ // We're switching from large caption bubbles to small
+ topSpacer->changeSize( 10, 1, TQSizePolicy::Expanding, TQSizePolicy::Minimum );
+ largeTitlebar = largeCaption = false;
+
+ widget()->layout()->activate();
+
+ // Compensate for the titlebar size change
+ // FRAME
+ widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
+ }
+
+ calculateCaptionRect();
+
+ captionBufferDirty = maskDirty = true;
+
+ // Only repaint the window if it's visible
+ // (i.e. not minimized and on the current desktop)
+ if ( widget()->isVisible() ) {
+ widget()->repaint( false );
+
+ for ( int i = 0; i < NumButtons; i++ )
+ if ( button[i] ) button[i]->repaint( false );
+ }
+}
+
+bool KeramikClient::isModalSystemNotification()
+{
+ unsigned char *data = 0;
+ Atom actual;
+ int format, result;
+ unsigned long n, left;
+ Atom kde_wm_system_modal_notification;
+ kde_wm_system_modal_notification = XInternAtom(tqt_xdisplay(), "_TDE_WM_MODAL_SYS_NOTIFICATION", False);
+ result = XGetWindowProperty(tqt_xdisplay(), windowId(), kde_wm_system_modal_notification, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
+ if (result == Success && data != None && format == 32 )
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void KeramikClient::addButtons( TQBoxLayout *layout, const TQString &s )
+{
+ for ( uint i=0; i < s.length(); i++ )
+ {
+ switch ( s[i].latin1() )
+ {
+ // Menu button
+ case 'M' :
+ if (!isModalSystemNotification()) {
+ if ( !button[MenuButton] ) {
+ button[MenuButton] = new KeramikButton( this, "menu", MenuButton, i18n("Menu"), Qt::LeftButton|Qt::RightButton );
+ connect( button[MenuButton], TQT_SIGNAL( pressed() ), TQT_SLOT( menuButtonPressed() ) );
+ layout->addWidget( button[MenuButton] );
+ }
+ }
+ break;
+
+ // OnAllDesktops button
+ case 'S' :
+ if (!isModalSystemNotification()) {
+ if ( !button[OnAllDesktopsButton] ) {
+ button[OnAllDesktopsButton] = new KeramikButton( this, "on_all_desktops",
+ OnAllDesktopsButton, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops") );
+ if(isOnAllDesktops())
+ button[OnAllDesktopsButton]->toggle();
+ connect( button[OnAllDesktopsButton], TQT_SIGNAL( clicked() ), TQT_SLOT( toggleOnAllDesktops() ) );
+ layout->addWidget( button[OnAllDesktopsButton] );
+ }
+ }
+ break;
+
+ // Help button
+ case 'H' :
+ if ( !button[HelpButton] && providesContextHelp() ) {
+ button[HelpButton] = new KeramikButton( this, "help", HelpButton, i18n("Help") );
+ connect( button[HelpButton], TQT_SIGNAL( clicked() ), TQT_SLOT( showContextHelp() ) );
+ layout->addWidget( button[HelpButton] );
+ }
+ break;
+
+ // Minimize button
+ case 'I' :
+ if ( !button[MinButton] && isMinimizable() ) {
+ button[MinButton] = new KeramikButton( this, "minimize", MinButton, i18n("Minimize") );
+ connect( button[MinButton], TQT_SIGNAL( clicked() ), TQT_SLOT( minimize() ) );
+ layout->addWidget( button[MinButton] );
+ }
+ break;
+
+ // Maximize button
+ case 'A' :
+ if ( !button[MaxButton] && isMaximizable() ) {
+ button[MaxButton] = new KeramikButton( this, "maximize", MaxButton, i18n("Maximize"), Qt::LeftButton|Qt::MidButton|Qt::RightButton );
+ connect( button[MaxButton], TQT_SIGNAL( clicked() ), TQT_SLOT( slotMaximize() ) );
+ layout->addWidget( button[MaxButton] );
+ }
+ break;
+
+ // Close button
+ case 'X' :
+ if ( !button[CloseButton] && isCloseable() ) {
+ button[CloseButton] = new KeramikButton( this, "close", CloseButton, i18n("Close") );
+ connect( button[CloseButton], TQT_SIGNAL( clicked() ), TQT_SLOT( closeWindow() ) );
+ layout->addWidget( button[CloseButton] );
+ }
+ break;
+
+ // Above button
+ case 'F' :
+ if ( !button[AboveButton]) {
+ button[AboveButton] = new KeramikButton( this, "above", AboveButton, i18n("Keep Above Others") );
+ connect( button[AboveButton], TQT_SIGNAL( clicked() ), TQT_SLOT( slotAbove() ) );
+ layout->addWidget( button[AboveButton] );
+ }
+ break;
+
+ // Below button
+ case 'B' :
+ if ( !button[BelowButton]) {
+ button[BelowButton] = new KeramikButton( this, "below", BelowButton, i18n("Keep Below Others") );
+ connect( button[BelowButton], TQT_SIGNAL( clicked() ), TQT_SLOT( slotBelow() ) );
+ layout->addWidget( button[BelowButton] );
+ }
+ break;
+
+ // Shade button
+ case 'L' :
+ if ( !button[ShadeButton] && isShadeable() ) {
+ button[ShadeButton] = new KeramikButton( this, "shade", ShadeButton,
+ isSetShade() ? i18n("Unshade") : i18n( "Shade" ));
+ connect( button[ShadeButton], TQT_SIGNAL( clicked() ), TQT_SLOT( slotShade() ) );
+ layout->addWidget( button[ShadeButton] );
+ }
+ break;
+
+ // Additional spacing
+ case '_' :
+ layout->addSpacing( buttonSpacing );
+ break;
+ }
+ }
+}
+
+
+void KeramikClient::updateMask()
+{
+ if ( !keramik_initialized )
+ return;
+
+ // To maximize performance this code uses precalculated bounding rects
+ // to set the window mask. This saves us from having to allocate a 1bpp
+ // pixmap, paint the mask on it and then have the X server iterate
+ // over the pixels to compute the bounding rects from it.
+
+ TQRegion r;
+ register int w, y = 0;
+ int nrects;
+
+ if ( TQApplication::reverseLayout() ) {
+
+ // If the caption bubble is visible and extends above the titlebar
+ if ( largeCaption && captionRect.width() >= 25 ) {
+ register int x = captionRect.left();
+ w = captionRect.width();
+ r += TQRegion( x + 11, y++, w - 19, 1 );
+ r += TQRegion( x + 9, y++, w - 15, 1 );
+ r += TQRegion( x + 7, y++, w - 12, 1 );
+ } else {
+ nrects = 8;
+
+ // Do we have a large titlebar with a retracted caption bubble?
+ // (i.e. the style is set to use large caption bubbles, we're
+ // not maximized and not active)
+ if ( largeTitlebar )
+ y = 3;
+ }
+
+ w = width(); // FRAME
+
+ // The rounded titlebar corners
+ r += TQRegion( 9, y++, w - 17, 1 );
+ r += TQRegion( 7, y++, w - 13, 1 );
+ r += TQRegion( 5, y++, w - 9, 1 );
+ r += TQRegion( 4, y++, w - 7, 1 );
+ r += TQRegion( 3, y++, w - 5, 1 );
+ r += TQRegion( 2, y++, w - 4, 1 );
+ r += TQRegion( 1, y++, w - 2, 2 );
+ } else {
+
+ // If the caption bubble is visible and extends above the titlebar
+ if ( largeCaption && captionRect.width() >= 25 ) {
+ nrects = 11;
+ register int x = captionRect.left();
+ w = captionRect.width();
+ r += TQRegion( x + 8, y++, w - 19, 1 );
+ r += TQRegion( x + 6, y++, w - 15, 1 );
+ r += TQRegion( x + 5, y++, w - 12, 1 );
+ } else {
+ nrects = 8;
+
+ // Do we have a large titlebar with a retracted caption bubble?
+ // (i.e. the style is set to use large caption bubbles, we're
+ // not maximized and not active)
+ if ( largeTitlebar )
+ y = 3;
+ }
+
+ w = width(); // FRAME
+
+ // The rounded titlebar corners
+ r += TQRegion( 8, y++, w - 17, 1 );
+ r += TQRegion( 6, y++, w - 13, 1 );
+ r += TQRegion( 4, y++, w - 9, 1 );
+ r += TQRegion( 3, y++, w - 7, 1 );
+ r += TQRegion( 2, y++, w - 5, 1 );
+ r += TQRegion( 2, y++, w - 4, 1 );
+ r += TQRegion( 1, y++, w - 2, 2 );
+ }
+
+ y++;
+
+ // The part of the window below the titlebar
+ r += TQRegion( 0, y, w, height() - y );
+
+ setMask( r, YXBanded );
+
+ maskDirty = false;
+}
+
+
+void KeramikClient::updateCaptionBuffer()
+{
+ if ( !keramik_initialized )
+ return;
+
+ bool active = isActive();
+ TQPixmap *icon = NULL;
+
+ if ( captionBuffer.size() != captionRect.size() )
+ captionBuffer.resize( captionRect.size() );
+
+ if ( captionBuffer.isNull() )
+ return;
+
+ TQPainter p( &captionBuffer );
+
+ // Draw the caption bubble
+ if ( active && largeCaption ) {
+ p.drawPixmap( 0, 0, *clientHandler->tile( CaptionLargeLeft, true ) );
+ p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
+ *clientHandler->tile( CaptionLargeCenter, true ) );
+ p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionLargeRight, true ) );
+ } else {
+ p.drawPixmap( 0, 0, *clientHandler->tile( CaptionSmallLeft, active ) );
+ p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
+ *clientHandler->tile( CaptionSmallCenter, active ) );
+ p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionSmallRight, active ) );
+ }
+
+ if ( clientHandler->showAppIcons() )
+ {
+ if ( active ) {
+ if ( ! activeIcon )
+ activeIcon = new TQPixmap( this->icon().pixmap( TQIconSet::Small, TQIconSet::Normal )); // FRAME
+ icon = activeIcon;
+ } else {
+ if ( ! inactiveIcon ) {
+ TQImage img = this->icon().pixmap( TQIconSet::Small, TQIconSet::Normal ).convertToImage();
+ TDEIconEffect::semiTransparent( img );
+ inactiveIcon = new TQPixmap( img );
+ }
+ icon = inactiveIcon;
+ }
+ }
+
+ p.setFont( options()->font( active ) );
+ int tw = p.fontMetrics().width( caption() ) +
+ ( clientHandler->showAppIcons() ? 16 + iconSpacing : 0 );
+
+ int xpos = TQMAX( (captionRect.width() - tw) / 3, 8 );
+ TQRect tr = TQStyle::visualRect( TQRect(xpos, 1, captionRect.width() - xpos - 10,
+ captionRect.height() - 4), captionBuffer.rect() );
+
+ //p.setPen( Qt::red ); // debug
+ //p.drawRect( tr ); // debug
+
+ // Application icon
+ if ( clientHandler->showAppIcons() )
+ {
+ TQRect iconRect = TQStyle::visualRect( TQRect(tr.x(),
+ 1 + (captionRect.height() - 4 - 16) / 2, 16, 16), tr );
+ TQRect r( icon->rect() );
+ r.moveCenter( iconRect.center() );
+
+ if ( tr.width() > 16 ) {
+ p.drawPixmap( r, *icon );
+ } else {
+ TQRect sr( 0, 0, icon->width(), icon->height() );
+
+ if ( TQApplication::reverseLayout() )
+ sr.addCoords( icon->width() - tr.width(), 0, 0, 0 );
+ else
+ sr.addCoords( 0, 0, -( icon->width() - tr.width() ), 0 );
+
+ p.drawPixmap( r.x() + sr.x(), r.y() + sr.y(), *icon,
+ sr.x(), sr.y(), sr.width(), sr.height() );
+ }
+
+ //p.drawRect( r ); // debug
+
+ if ( TQApplication::reverseLayout() )
+ tr.addCoords( 0, 0, -(16 + iconSpacing), 0 );
+ else
+ tr.addCoords( (16 + iconSpacing), 0, 0, 0 );
+ }
+
+ // Draw the titlebar text
+ int flags = AlignVCenter | SingleLine;
+ flags |= ( TQApplication::reverseLayout() ? AlignRight : AlignLeft );
+
+ if ( clientHandler->useShadowedText() )
+ {
+ p.translate( TQApplication::reverseLayout() ? -1 : 1, 1 );
+ //p.setPen( options()->color(ColorTitleBar, active).dark() );
+ if (tqGray(options()->color(ColorFont, active).rgb()) < 100)
+ p.setPen( TQColor(200,200,200) );
+ else
+ p.setPen( black );
+ p.drawText( tr, flags, caption() );
+ p.translate( TQApplication::reverseLayout() ? 1 : -1, -1 );
+ }
+
+ p.setPen( options()->color( ColorFont, active ) );
+ p.drawText( tr, flags, caption() );
+
+ captionBufferDirty = false;
+}
+
+
+void KeramikClient::calculateCaptionRect()
+{
+ TQFontMetrics fm( options()->font(isActive()) );
+ int cw = fm.width( caption() ) + 95;
+ int titleBaseY = ( largeTitlebar ? 3 : 0 );
+
+ if ( clientHandler->showAppIcons() )
+ cw += 16 + 4; // icon width + space
+
+ cw = TQMIN( cw, titlebar->geometry().width() );
+ captionRect = TQStyle::visualRect( TQRect(titlebar->geometry().x(), (largeCaption ? 0 : titleBaseY),
+ cw, clientHandler->titleBarHeight(largeCaption) ),
+ titlebar->geometry() );
+}
+
+
+void KeramikClient::captionChange()
+{
+ TQRect r( captionRect );
+ calculateCaptionRect();
+
+ if ( r.size() != captionRect.size() )
+ maskDirty = true;
+
+ captionBufferDirty = true;
+
+ widget()->repaint( r | captionRect, false );
+}
+
+
+void KeramikClient::iconChange()
+{
+ if ( clientHandler->showAppIcons() ) {
+
+ // Force updateCaptionBuffer() to recreate the cached icons
+ delete activeIcon;
+
+ delete inactiveIcon;
+
+ activeIcon = inactiveIcon = NULL;
+
+ captionBufferDirty = true;
+ widget()->repaint( captionRect, false );
+ }
+}
+
+
+void KeramikClient::activeChange()
+{
+ bool active = isActive();
+ // Note: It's assumed that the same font will always be used for both active
+ // and inactive windows, since the fonts kcm hasn't supported setting
+ // different fonts for different window states for some time.
+ if ( largeTitlebar ) {
+ largeCaption = ( active && !maximizedVertical() );
+ calculateCaptionRect();
+ maskDirty = true;
+ }
+
+ captionBufferDirty = true;
+
+ widget()->repaint( false );
+
+ for ( int i=0; i < NumButtons; i++ )
+ if ( button[i] ) button[i]->repaint( false );
+}
+
+
+void KeramikClient::maximizeChange()
+{
+ if ( clientHandler->largeCaptionBubbles() )
+ {
+ if ( maximizeMode() & MaximizeVertical ) {
+ // We've been maximized - shrink the titlebar by 3 pixels
+ topSpacer->changeSize( 10, 1, TQSizePolicy::Expanding, TQSizePolicy::Minimum );
+ largeCaption = largeTitlebar = false;
+
+ calculateCaptionRect();
+ captionBufferDirty = maskDirty = true;
+
+ widget()->layout()->activate();
+ widget()->repaint( false );
+ } else if (( maximizeMode() & MaximizeVertical ) == 0 && !largeTitlebar ) {
+ // We've been restored - enlarge the titlebar by 3 pixels
+ topSpacer->changeSize( 10, 4, TQSizePolicy::Expanding, TQSizePolicy::Minimum );
+ largeCaption = largeTitlebar = true;
+
+ calculateCaptionRect();
+ captionBufferDirty = maskDirty = true;
+
+ widget()->layout()->activate();
+ widget()->repaint( false );
+ }
+ }
+
+ if ( button[ MaxButton ] ) {
+ TQToolTip::remove( button[ MaxButton ] );
+ TQToolTip::add( button[ MaxButton ], maximizeMode() == MaximizeFull ? i18n("Restore") : i18n("Maximize") );
+ button[ MaxButton ]->repaint();
+ }
+}
+
+
+void KeramikClient::desktopChange()
+{
+ if ( button[ OnAllDesktopsButton ] )
+ {
+ button[ OnAllDesktopsButton ]->repaint( true );
+ TQToolTip::remove( button[ OnAllDesktopsButton ] );
+ TQToolTip::add( button[ OnAllDesktopsButton ], isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops") );
+ }
+}
+
+
+void KeramikClient::shadeChange()
+{
+ if ( button[ ShadeButton ] )
+ {
+ button[ ShadeButton ]->repaint( true );
+ TQToolTip::remove( button[ ShadeButton ] );
+ TQToolTip::add( button[ ShadeButton ], isSetShade() ? i18n("Unshade") : i18n("Shade") );
+ }
+}
+
+
+void KeramikClient::keepAboveChange( bool )
+{
+ if ( button[ AboveButton ] )
+ button[ AboveButton ]->repaint( true );
+}
+
+
+void KeramikClient::keepBelowChange( bool )
+{
+ if ( button[ BelowButton ] )
+ button[ BelowButton ]->repaint( true );
+}
+
+
+void KeramikClient::menuButtonPressed()
+{
+ TQPoint menuTop ( button[MenuButton]->rect().topLeft() );
+ TQPoint menuBottom ( button[MenuButton]->rect().bottomRight() );
+ menuTop += TQPoint(-6, -3);
+ menuBottom += TQPoint(6, 3);
+ KDecorationFactory* f = factory();
+ showWindowMenu( TQRect( button[MenuButton]->mapToGlobal( menuTop ),
+ button[MenuButton]->mapToGlobal( menuBottom )) );
+ if( !f->exists( this )) // 'this' was destroyed
+ return;
+ button[MenuButton]->setDown(false);
+}
+
+
+void KeramikClient::slotMaximize()
+{
+ maximize( button[ MaxButton ]->lastButton() );
+}
+
+
+void KeramikClient::slotAbove()
+{
+ setKeepAbove( !keepAbove());
+ button[ AboveButton ]->repaint( true );
+}
+
+
+void KeramikClient::slotBelow()
+{
+ setKeepBelow( !keepBelow());
+ button[ BelowButton ]->repaint( true );
+}
+
+
+void KeramikClient::slotShade()
+{
+ setShade( !isSetShade());
+ button[ ShadeButton ]->repaint( true );
+}
+
+
+void KeramikClient::paintEvent( TQPaintEvent *e )
+{
+ if ( !keramik_initialized )
+ return;
+
+ TQPainter p( widget());
+ TQRect updateRect( e->rect() );
+ bool active = isActive();
+
+ int titleBaseY = ( largeTitlebar ? 3 : 0 );
+ int titleBarHeight = clientHandler->titleBarHeight( largeTitlebar );
+ int grabBarHeight = clientHandler->grabBarHeight();
+ int leftBorderWidth = clientHandler->tile( BorderLeft, active )->width();
+ int rightBorderWidth = clientHandler->tile( BorderRight, active )->width();
+
+ if ( maskDirty )
+ updateMask();
+
+ // Titlebar
+ // -----------------------------------------------------------------------
+ if ( updateRect.y() < titleBarHeight )
+ {
+ int titleBarBaseHeight = titleBarHeight - titleBaseY;
+
+ if ( captionBufferDirty )
+ updateCaptionBuffer();
+
+ // Top left corner
+ if ( updateRect.x() < 15 )
+ p.drawPixmap( 0, titleBaseY,
+ *clientHandler->tile( TitleLeft, active ) );
+
+ // Space between the top left corner and the caption bubble
+ if ( updateRect.x() < captionRect.left() && updateRect.right() >= 15 ) {
+ int x1 = TQMAX( 15, updateRect.x() );
+ int x2 = TQMIN( captionRect.left(), updateRect.right() );
+
+ p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
+ *clientHandler->tile( TitleCenter, active ) );
+ }
+
+ // Caption bubble
+ if ( updateRect.x() <= captionRect.right() && updateRect.right() > 15 ) {
+ if ( captionRect.width() >= 25 )
+ p.drawPixmap( captionRect.left(), active ? 0 : titleBaseY, captionBuffer );
+ else
+ p.drawTiledPixmap( captionRect.x(), titleBaseY, captionRect.width(),
+ titleBarBaseHeight, *clientHandler->tile( TitleCenter, active ) );
+ }
+
+ // Space between the caption bubble and the top right corner
+ if ( updateRect.right() > captionRect.right() && updateRect.x() < width() - 15 ) { // FRAME
+ int x1 = TQMAX( captionRect.right() + 1, updateRect.x() );
+ int x2 = TQMIN( width() - 15, updateRect.right() );
+
+ p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
+ *clientHandler->tile( TitleCenter, active ) );
+ }
+
+ // Top right corner
+ if ( updateRect.right() >= width() - 15 )
+ p.drawPixmap( width() - 15, titleBaseY,
+ *clientHandler->tile( TitleRight, active ) );
+ }
+
+ // Borders
+ // -----------------------------------------------------------------------
+ if ( updateRect.bottom() >= titleBarHeight &&
+ updateRect.top() < height() - grabBarHeight )
+ {
+ int top = TQMAX( titleBarHeight, updateRect.top() );
+ int bottom = TQMIN( updateRect.bottom(), height() - grabBarHeight );
+
+ // Left border
+ if ( updateRect.x() < leftBorderWidth )
+ p.drawTiledPixmap( 0, top, leftBorderWidth, bottom - top + 1,
+ *clientHandler->tile( BorderLeft, active ) );
+
+ // Right border
+ if ( e->rect().right() > width() - rightBorderWidth - 1 )
+ p.drawTiledPixmap( width() - rightBorderWidth, top, rightBorderWidth,
+ bottom - top + 1, *clientHandler->tile( BorderRight, active ) );
+ }
+
+ // Bottom grab bar
+ // -----------------------------------------------------------------------
+ if ( updateRect.bottom() >= height() - grabBarHeight ) {
+ // Bottom left corner
+ if ( updateRect.x() < 9 )
+ p.drawPixmap( 0, height() - grabBarHeight,
+ *clientHandler->tile( GrabBarLeft, active ) );
+
+ // Space between the left corner and the right corner
+ if ( updateRect.x() < width() - 9 ) {
+ int x1 = TQMAX( 9, updateRect.x() );
+ int x2 = TQMIN( width() - 9, updateRect.right() );
+
+ p.drawTiledPixmap( x1, height() - grabBarHeight, x2 - x1 + 1,
+ grabBarHeight, *clientHandler->tile( GrabBarCenter, active ) );
+ }
+
+ // Bottom right corner
+ if ( updateRect.right() > width() - 9 )
+ p.drawPixmap( width() - 9, height() - grabBarHeight,
+ *clientHandler->tile( GrabBarRight, active ) );
+ }
+
+ // Extra drawline for the 1 pixel empty space TQLayout leaves when a window is shaded.
+ p.setPen( options()->color( ColorTitleBlend, active ) );
+ p.drawLine( leftBorderWidth, height() - grabBarHeight - 1,
+ width() - rightBorderWidth - 1, height() - grabBarHeight - 1 );
+}
+
+
+void KeramikClient::resizeEvent( TQResizeEvent *e )
+{
+// FRAME Client::resizeEvent( e );
+
+ TQRect r( captionRect );
+ calculateCaptionRect();
+
+ if ( r.size() != captionRect.size() )
+ captionBufferDirty = true;
+
+ maskDirty = true;
+
+ if ( widget()->isVisible() )
+ {
+ widget()->update( widget()->rect() );
+ int dx = 0;
+ int dy = 0;
+
+ if ( e->oldSize().width() != width() )
+ dx = 32 + QABS( e->oldSize().width() - width() );
+
+ if ( e->oldSize().height() != height() )
+ dy = 8 + QABS( e->oldSize().height() - height() );
+
+ if ( dy )
+ widget()->update( 0, height() - dy + 1, width(), dy );
+
+ if ( dx )
+ {
+ widget()->update( width() - dx + 1, 0, dx, height() );
+ widget()->update( TQRect( TQPoint(4,4), titlebar->geometry().bottomLeft() - TQPoint(1,0) ) );
+ widget()->update( TQRect( titlebar->geometry().topRight(), TQPoint( width() - 4,
+ titlebar->geometry().bottom() ) ) );
+ // Titlebar needs no paint event
+ TQApplication::postEvent( this, new TQPaintEvent( titlebar->geometry(), FALSE ) );
+ }
+ }
+}
+
+
+void KeramikClient::mouseDoubleClickEvent( TQMouseEvent *e )
+{
+ if ( e->button() == Qt::LeftButton
+ && TQRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
+ titlebarDblClickOperation();
+}
+
+void KeramikClient::wheelEvent( TQWheelEvent *e )
+{
+ if (isSetShade()
+ || TQRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
+ titlebarMouseWheelOperation( e->delta());
+}
+
+KeramikClient::Position KeramikClient::mousePosition( const TQPoint &p ) const
+{
+ int titleBaseY = (largeTitlebar ? 3 : 0);
+
+ int leftBorder = clientHandler->tile( BorderLeft, true )->width();
+ int rightBorder = width() - clientHandler->tile( BorderRight, true )->width() - 1;
+ int bottomBorder = height() - clientHandler->grabBarHeight() - 1;
+ int bottomCornerSize = 3*clientHandler->tile( BorderRight, true )->width()/2 + 24;
+
+ // Test if the mouse is over the titlebar area
+ if ( p.y() < titleBaseY + 11 ) {
+ // Test for the top left corner
+ if ( p.x() < leftBorder + 11 ) {
+ if ( (p.y() < titleBaseY + 3 && p.x() < leftBorder + 11) ||
+ (p.y() < titleBaseY + 6 && p.x() < leftBorder + 6) ||
+ (p.y() < titleBaseY + 11 && p.x() < leftBorder + 3) )
+ return PositionTopLeft;
+ }
+
+ // Test for the top right corner
+ if ( p.x() > rightBorder - 11 ) {
+ if ( (p.y() < titleBaseY + 3 && p.x() > rightBorder - 11) ||
+ (p.y() < titleBaseY + 6 && p.x() > rightBorder - 6) ||
+ (p.y() < titleBaseY + 11 && p.x() > rightBorder - 3) )
+ return PositionTopRight;
+ }
+
+ // Test for the top border
+ if ( p.y() <= 3 || (p.y() <= titleBaseY+3 &&
+ (p.x() < captionRect.left() || p.x() > captionRect.right()) ) )
+ return PositionTop;
+
+ // The cursor must be over the center of the titlebar.
+ return PositionCenter;
+ }
+
+ // Test the sides
+ else if ( p.y() < bottomBorder ) {
+ // Test for the left side
+ if ( p.x() < leftBorder ) {
+ if ( p.y() < height() - bottomCornerSize )
+ return PositionLeft;
+ else
+ return PositionBottomLeft;
+ }
+
+ // Test for the right side
+ else if ( p.x() > rightBorder ) {
+ if ( p.y() < height() - bottomCornerSize )
+ return PositionRight;
+ else
+ return PositionBottomRight;
+ }
+
+ // The cursor must be over the center of the window
+ return PositionCenter;
+ }
+
+ // Test the grab bar / bottom border
+ else {
+ // Test for the bottom left corner
+ if ( p.x() < bottomCornerSize )
+ return PositionBottomLeft;
+
+ // Test for the bottom right corner
+ else if ( p.x() > width() - bottomCornerSize - 1 )
+ return PositionBottomRight;
+
+ // The cursor must be over the bottom border
+ return PositionBottom;
+ }
+
+ // We should never get here
+ return PositionCenter;
+}
+
+
+void KeramikClient::resize( const TQSize& s )
+{
+ widget()->resize( s );
+}
+
+
+void KeramikClient::borders( int& left, int& right, int& top, int& bottom ) const
+{
+ int titleBarHeight = clientHandler->titleBarHeight( clientHandler->largeCaptionBubbles() );
+ int grabBarHeight = clientHandler->grabBarHeight();
+ int leftBorderWidth = clientHandler->tile( BorderLeft, isActive() )->width();
+ int rightBorderWidth = clientHandler->tile( BorderRight, isActive() )->width();
+
+ left = leftBorderWidth;
+ right = rightBorderWidth;
+ top = titleBarHeight;
+ bottom = grabBarHeight;
+
+ if ( ( maximizeMode() & MaximizeHorizontal ) && !options()->moveResizeMaximizedWindows())
+ left = right = 0;
+ if( maximizeMode() & MaximizeVertical)
+ {
+ top = clientHandler->titleBarHeight( false );
+ if( !options()->moveResizeMaximizedWindows())
+ bottom = 0;
+ }
+}
+
+
+TQSize KeramikClient::minimumSize() const
+{
+ return widget()->minimumSize();
+}
+
+
+bool KeramikClient::eventFilter( TQObject* o, TQEvent* e )
+{
+ if ( TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(widget()) )
+ return false;
+
+ switch ( e->type() )
+ {
+ case TQEvent::Resize:
+ resizeEvent( TQT_TQRESIZEEVENT( e ) );
+ return true;
+
+ case TQEvent::Paint:
+ paintEvent( TQT_TQPAINTEVENT( e ) );
+ return true;
+
+ case TQEvent::MouseButtonDblClick:
+ mouseDoubleClickEvent( TQT_TQMOUSEEVENT( e ) );
+ return true;
+
+ case TQEvent::MouseButtonPress:
+ processMousePressEvent( TQT_TQMOUSEEVENT( e ) );
+ return true;
+
+ case TQEvent::Wheel:
+ wheelEvent( TQT_TQWHEELEVENT( e ));
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+} // namespace Keramik
+
+
+
+// -------------------------------------------------------------------------------------------
+
+
+
+extern "C"
+{
+ KDE_EXPORT KDecorationFactory *create_factory()
+ {
+ Keramik::clientHandler = new Keramik::KeramikHandler();
+ return Keramik::clientHandler;
+ }
+}
+
+
+
+// vim: set noet ts=4 sw=4:
diff --git a/twin/clients/keramik/keramik.desktop b/twin/clients/keramik/keramik.desktop
new file mode 100644
index 00000000..55e7b0d3
--- /dev/null
+++ b/twin/clients/keramik/keramik.desktop
@@ -0,0 +1,31 @@
+[Desktop Entry]
+Name=Keramik
+Name[ar]=قرميدي
+Name[be]=Кераміка
+Name[bn]=কেরামিক
+Name[cs]=Keramika
+Name[eo]=Ceramiko
+Name[fa]=کرامیک
+Name[fy]=Keramyk
+Name[hi]=के-रामिक
+Name[it]=Ceramica
+Name[lo]=ເຄຣາມິກ - K
+Name[lv]=Keramika
+Name[mk]=Керамик
+Name[mn]=Ваар
+Name[nb]=Keramikk
+Name[ne]=केरामिक
+Name[nn]=Keramikk
+Name[pa]=ਕੀਰਾਮਿਕ
+Name[se]=Bálseduodji
+Name[sr]=Керамика
+Name[sr@Latn]=Keramika
+Name[ta]=கெராமிக்
+Name[te]=కెరామిక్
+Name[th]=เครามิก
+Name[uk]=Керамік
+Name[uz]=Keramika
+Name[uz@cyrillic]=Керамика
+Name[vi]=Gốm
+X-TDE-Library=twin3_keramik
+
diff --git a/twin/clients/keramik/keramik.h b/twin/clients/keramik/keramik.h
new file mode 100644
index 00000000..59f9960c
--- /dev/null
+++ b/twin/clients/keramik/keramik.h
@@ -0,0 +1,202 @@
+/*
+ *
+ * Keramik KWin client (version 0.8)
+ *
+ * Copyright (C) 2002 Fredrik H�glund <fredrik@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __KERAMIK_H
+#define __KERAMIK_H
+
+#include <tqbutton.h>
+#include <kdecoration.h>
+#include <kdecorationfactory.h>
+
+#include "tiles.h"
+
+class TQSpacerItem;
+
+namespace Keramik {
+
+ enum TilePixmap { TitleLeft=0, TitleCenter, TitleRight,
+ CaptionSmallLeft, CaptionSmallCenter, CaptionSmallRight,
+ CaptionLargeLeft, CaptionLargeCenter, CaptionLargeRight,
+ GrabBarLeft, GrabBarCenter, GrabBarRight,
+ BorderLeft, BorderRight, NumTiles };
+
+ enum Button { MenuButton=0, OnAllDesktopsButton, HelpButton, MinButton,
+ MaxButton, CloseButton, AboveButton, BelowButton, ShadeButton,
+ NumButtons };
+
+ enum ButtonDeco { Menu=0, OnAllDesktops, NotOnAllDesktops, Help, Minimize, Maximize,
+ Restore, Close, AboveOn, AboveOff, BelowOn, BelowOff, ShadeOn, ShadeOff,
+ NumButtonDecos };
+
+ struct SettingsCache
+ {
+ bool largeGrabBars:1;
+ bool smallCaptionBubbles:1;
+ };
+
+ class KeramikHandler : public KDecorationFactory
+ {
+ public:
+ KeramikHandler();
+ ~KeramikHandler();
+
+ virtual TQValueList< BorderSize > borderSizes() const;
+ virtual bool reset( unsigned long changed );
+ virtual KDecoration* createDecoration( KDecorationBridge* );
+ virtual bool supports( Ability ability );
+
+ bool showAppIcons() const { return showIcons; }
+ bool useShadowedText() const { return shadowedText; }
+ bool largeCaptionBubbles() const { return !smallCaptionBubbles; }
+
+ int titleBarHeight( bool large ) const {
+ return ( large ? activeTiles[CaptionLargeCenter]->height()
+ : activeTiles[CaptionSmallCenter]->height() );
+ }
+
+ int grabBarHeight() const
+ { return activeTiles[GrabBarCenter]->height(); }
+
+ const TQPixmap *roundButton() const { return titleButtonRound; }
+ const TQPixmap *squareButton() const { return titleButtonSquare; }
+ const TQBitmap *buttonDeco( ButtonDeco deco ) const
+ { return buttonDecos[ deco ]; }
+
+ inline const TQPixmap *tile( TilePixmap tilePix, bool active ) const;
+
+ private:
+ void readConfig();
+ void createPixmaps();
+ void destroyPixmaps();
+
+ void addWidth (int width, TQPixmap *&pix, bool left, TQPixmap *bottomPix);
+ void addHeight (int height, TQPixmap *&pix);
+ void flip( TQPixmap *&, TQPixmap *& );
+ void pretile( TQPixmap *&, int, Qt::Orientation );
+ TQPixmap *composite( TQImage *, TQImage * );
+ TQImage *loadImage( const TQString &, const TQColor & );
+ TQPixmap *loadPixmap( const TQString &, const TQColor & );
+
+ bool showIcons:1, shadowedText:1,
+ smallCaptionBubbles:1, largeGrabBars:1;
+ SettingsCache *settings_cache;
+ KeramikImageDb *imageDb;
+
+ TQPixmap *activeTiles[ NumTiles ];
+ TQPixmap *inactiveTiles[ NumTiles ];
+ TQBitmap *buttonDecos[ NumButtonDecos ];
+
+ TQPixmap *titleButtonRound, *titleButtonSquare;
+
+ }; // class KeramikHandler
+
+ class KeramikClient;
+ class KeramikButton : public TQButton
+ {
+ public:
+ KeramikButton( KeramikClient *, const char *, Button, const TQString &, const int realizeBtns = Qt::LeftButton );
+ ~KeramikButton();
+
+ ButtonState lastButton() const { return lastbutton; }
+
+ private:
+ void enterEvent( TQEvent * );
+ void leaveEvent( TQEvent * );
+ void mousePressEvent( TQMouseEvent * );
+ void mouseReleaseEvent( TQMouseEvent * );
+ void drawButton( TQPainter * );
+
+ private:
+ KeramikClient *client;
+ Button button;
+ bool hover;
+ ButtonState lastbutton;
+ int realizeButtons;
+ }; // class KeramikButton
+
+
+ class KeramikClient : public KDecoration
+ {
+ Q_OBJECT
+
+ public:
+
+ KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory );
+ ~KeramikClient();
+ virtual void init();
+ virtual void reset( unsigned long changed );
+ virtual Position mousePosition( const TQPoint& p ) const;
+ virtual void borders( int& left, int& right, int& top, int& bottom ) const;
+ virtual void resize( const TQSize& s );
+ virtual TQSize minimumSize() const;
+ virtual bool eventFilter( TQObject* o, TQEvent* e );
+ virtual void activeChange();
+ virtual void captionChange();
+ virtual void maximizeChange();
+ virtual void desktopChange();
+ virtual void shadeChange();
+
+ private:
+ void createLayout();
+ void addButtons( TQBoxLayout*, const TQString & );
+ void updateMask(); // FRAME
+ void updateCaptionBuffer();
+ void iconChange();
+ void resizeEvent( TQResizeEvent *); // FRAME
+ void paintEvent( TQPaintEvent *); // FRAME
+ void mouseDoubleClickEvent( TQMouseEvent * ); // FRAME
+ void wheelEvent( TQWheelEvent *); //FRAME
+ int width() const { return widget()->width(); }
+ int height() const { return widget()->height(); }
+
+ void calculateCaptionRect();
+
+ inline bool maximizedVertical() const {
+ return ( maximizeMode() & MaximizeVertical );
+ }
+ bool isModalSystemNotification();
+
+ private slots:
+ void menuButtonPressed();
+ void slotMaximize();
+ void slotAbove();
+ void slotBelow();
+ void slotShade();
+ void keepAboveChange( bool );
+ void keepBelowChange( bool );
+
+ private:
+ TQSpacerItem *topSpacer, *titlebar;
+ KeramikButton *button[ NumButtons ];
+ TQRect captionRect;
+ TQPixmap captionBuffer;
+ TQPixmap *activeIcon, *inactiveIcon;
+ bool captionBufferDirty:1, maskDirty:1;
+ bool largeCaption:1, largeTitlebar:1;
+ }; // class KeramikClient
+
+} // namespace Keramik
+
+#endif // ___KERAMIK_H
+
+// vim: set noet ts=4 sw=4:
diff --git a/twin/clients/keramik/pics/border-left.png b/twin/clients/keramik/pics/border-left.png
new file mode 100644
index 00000000..298a0aa9
--- /dev/null
+++ b/twin/clients/keramik/pics/border-left.png
Binary files differ
diff --git a/twin/clients/keramik/pics/border-right.png b/twin/clients/keramik/pics/border-right.png
new file mode 100644
index 00000000..1ca876b0
--- /dev/null
+++ b/twin/clients/keramik/pics/border-right.png
Binary files differ
diff --git a/twin/clients/keramik/pics/bottom-center.png b/twin/clients/keramik/pics/bottom-center.png
new file mode 100644
index 00000000..d6d00253
--- /dev/null
+++ b/twin/clients/keramik/pics/bottom-center.png
Binary files differ
diff --git a/twin/clients/keramik/pics/bottom-left.png b/twin/clients/keramik/pics/bottom-left.png
new file mode 100644
index 00000000..16a2ab98
--- /dev/null
+++ b/twin/clients/keramik/pics/bottom-left.png
Binary files differ
diff --git a/twin/clients/keramik/pics/bottom-right.png b/twin/clients/keramik/pics/bottom-right.png
new file mode 100644
index 00000000..2d404543
--- /dev/null
+++ b/twin/clients/keramik/pics/bottom-right.png
Binary files differ
diff --git a/twin/clients/keramik/pics/caption-large-center.png b/twin/clients/keramik/pics/caption-large-center.png
new file mode 100644
index 00000000..786276b5
--- /dev/null
+++ b/twin/clients/keramik/pics/caption-large-center.png
Binary files differ
diff --git a/twin/clients/keramik/pics/caption-large-left.png b/twin/clients/keramik/pics/caption-large-left.png
new file mode 100644
index 00000000..7d96bdce
--- /dev/null
+++ b/twin/clients/keramik/pics/caption-large-left.png
Binary files differ
diff --git a/twin/clients/keramik/pics/caption-large-right.png b/twin/clients/keramik/pics/caption-large-right.png
new file mode 100644
index 00000000..3055d13a
--- /dev/null
+++ b/twin/clients/keramik/pics/caption-large-right.png
Binary files differ
diff --git a/twin/clients/keramik/pics/caption-small-center.png b/twin/clients/keramik/pics/caption-small-center.png
new file mode 100644
index 00000000..78636dfd
--- /dev/null
+++ b/twin/clients/keramik/pics/caption-small-center.png
Binary files differ
diff --git a/twin/clients/keramik/pics/caption-small-left.png b/twin/clients/keramik/pics/caption-small-left.png
new file mode 100644
index 00000000..cb7e69d7
--- /dev/null
+++ b/twin/clients/keramik/pics/caption-small-left.png
Binary files differ
diff --git a/twin/clients/keramik/pics/caption-small-right.png b/twin/clients/keramik/pics/caption-small-right.png
new file mode 100644
index 00000000..9fc74640
--- /dev/null
+++ b/twin/clients/keramik/pics/caption-small-right.png
Binary files differ
diff --git a/twin/clients/keramik/pics/grabbar-center.png b/twin/clients/keramik/pics/grabbar-center.png
new file mode 100644
index 00000000..b623b5df
--- /dev/null
+++ b/twin/clients/keramik/pics/grabbar-center.png
Binary files differ
diff --git a/twin/clients/keramik/pics/grabbar-left.png b/twin/clients/keramik/pics/grabbar-left.png
new file mode 100644
index 00000000..653f5ccf
--- /dev/null
+++ b/twin/clients/keramik/pics/grabbar-left.png
Binary files differ
diff --git a/twin/clients/keramik/pics/grabbar-right.png b/twin/clients/keramik/pics/grabbar-right.png
new file mode 100644
index 00000000..248d5541
--- /dev/null
+++ b/twin/clients/keramik/pics/grabbar-right.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebar-center.png b/twin/clients/keramik/pics/titlebar-center.png
new file mode 100644
index 00000000..bac31dc5
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebar-center.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebar-left.png b/twin/clients/keramik/pics/titlebar-left.png
new file mode 100644
index 00000000..bc8ee5ca
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebar-left.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebar-right.png b/twin/clients/keramik/pics/titlebar-right.png
new file mode 100644
index 00000000..d34a465f
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebar-right.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebutton-round-huge.png b/twin/clients/keramik/pics/titlebutton-round-huge.png
new file mode 100644
index 00000000..c5ca1934
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebutton-round-huge.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebutton-round-large.png b/twin/clients/keramik/pics/titlebutton-round-large.png
new file mode 100644
index 00000000..9c3267bf
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebutton-round-large.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebutton-round.png b/twin/clients/keramik/pics/titlebutton-round.png
new file mode 100644
index 00000000..dd2369af
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebutton-round.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebutton-square-huge.png b/twin/clients/keramik/pics/titlebutton-square-huge.png
new file mode 100644
index 00000000..a908a9f2
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebutton-square-huge.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebutton-square-large.png b/twin/clients/keramik/pics/titlebutton-square-large.png
new file mode 100644
index 00000000..6e3ada47
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebutton-square-large.png
Binary files differ
diff --git a/twin/clients/keramik/pics/titlebutton-square.png b/twin/clients/keramik/pics/titlebutton-square.png
new file mode 100644
index 00000000..871cf751
--- /dev/null
+++ b/twin/clients/keramik/pics/titlebutton-square.png
Binary files differ
diff --git a/twin/clients/kwmtheme/Makefile.am b/twin/clients/kwmtheme/Makefile.am
new file mode 100644
index 00000000..e9d3c36b
--- /dev/null
+++ b/twin/clients/kwmtheme/Makefile.am
@@ -0,0 +1,15 @@
+SUBDIRS=cli_installer
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = twin3_kwmtheme.la
+
+twin3_kwmtheme_la_SOURCES = kwmthemeclient.cpp
+twin3_kwmtheme_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin3_kwmtheme_la_LIBADD = -ltdecorations
+
+METASOURCES = AUTO
+noinst_HEADERS = kwmthemeclient.h
+
+lnkdir = $(kde_datadir)/twin
+lnk_DATA = kwmtheme.desktop
+
diff --git a/twin/clients/kwmtheme/cli_installer/Makefile.am b/twin/clients/kwmtheme/cli_installer/Makefile.am
new file mode 100644
index 00000000..d9ee417c
--- /dev/null
+++ b/twin/clients/kwmtheme/cli_installer/Makefile.am
@@ -0,0 +1,18 @@
+
+# set the include path for X, qt and KDE
+INCLUDES= $(all_includes)
+
+####### This part is very kwmtheme specific
+# you can add here more. This one gets installed
+bin_PROGRAMS = kwmtheme
+
+# Which sources should be compiled for kwmtheme.
+kwmtheme_SOURCES = main.cpp
+
+# the library search path.
+kwmtheme_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+
+# the libraries to link against. Be aware of the order. First the libraries,
+# that depend on the following ones.
+kwmtheme_LDADD = $(LIB_TDECORE)
+
diff --git a/twin/clients/kwmtheme/cli_installer/main.cpp b/twin/clients/kwmtheme/cli_installer/main.cpp
new file mode 100644
index 00000000..27af172e
--- /dev/null
+++ b/twin/clients/kwmtheme/cli_installer/main.cpp
@@ -0,0 +1,166 @@
+#include <tqfile.h>
+#include <tqdir.h>
+#include <tdeapplication.h>
+#include <ksimpleconfig.h>
+#include <tdeglobal.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <tdecmdlineargs.h>
+#include <tdelocale.h>
+
+static const char description[] =
+ I18N_NOOP("Installs a KWM theme");
+
+static TDECmdLineOptions options[] =
+{
+ { "+[file]", I18N_NOOP("Path to a theme config file"), 0 },
+ TDECmdLineLastOption
+};
+
+void copy(const TQString &src, const TQString &dest)
+{
+ TQFile copyInput(src);
+ TQFile copyOutput(dest);
+ if(!copyInput.open(IO_ReadOnly)){
+ kdWarning() << "Couldn't open " << src << endl;
+ return;
+ }
+ if(!copyOutput.open(IO_WriteOnly)){
+ kdWarning() << "Couldn't open " << dest << endl;
+ copyInput.close();
+ return;
+ }
+ while(!copyInput.atEnd()){
+ copyOutput.putch(copyInput.getch());
+ }
+ copyInput.close();
+ copyOutput.close();
+}
+
+int main(int argc, char **argv)
+{
+ TDECmdLineArgs::init(argc, argv, "kwmtheme", description, "0.1");
+ TDECmdLineArgs::addCmdLineOptions( options );
+ TDEApplication app(argc, argv);
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+ if(!args->count()){
+ kdWarning() << "You need to specify the path to a theme config file!" << endl;
+ return(1);
+ }
+
+ TQString srcStr = TQString(TQFile::decodeName(args->arg(0)));
+ TQFile f(srcStr);
+ TQString tmpStr;
+
+ if(!f.exists()){
+ kdWarning() << "Specified theme config file doesn't exist!" << endl;
+ return(2);
+ }
+
+ TQStringList appDirs = TDEGlobal::dirs()->findDirs("data", "twin");
+ TQString localDirStr = *(appDirs.end());
+ if(localDirStr.isEmpty()){
+ localDirStr = TDEGlobal::dirs()->saveLocation("data", "twin");
+ }
+ localDirStr += "/pics/";
+ if(!TQFile::exists(localDirStr))
+ TQDir().mkdir(localDirStr);
+
+ TQFileInfo fi(f);
+ KSimpleConfig input(fi.absFilePath());
+ srcStr = fi.dirPath(true) + "/";
+ TDEConfig *output = TDEGlobal::config();
+ input.setGroup("Window Border");
+ output->setGroup("General");
+
+ tmpStr = input.readEntry("shapePixmapTop");
+ if(!tmpStr.isEmpty()){
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ }
+ output->writeEntry("wm_top", tmpStr, true, true);
+ tmpStr = input.readEntry("shapePixmapBottom");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("wm_bottom", tmpStr, true, true);
+ tmpStr = input.readEntry("shapePixmapLeft");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("wm_left", tmpStr, true, true);
+ tmpStr = input.readEntry("shapePixmapRight");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("wm_right", tmpStr, true, true);
+ tmpStr = input.readEntry("shapePixmapTopLeft");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("wm_topleft", tmpStr, true, true);
+ tmpStr = input.readEntry("shapePixmapTopRight");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("wm_topright", tmpStr, true, true);
+ tmpStr = input.readEntry("shapePixmapBottomLeft");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("wm_bottomleft", tmpStr, true, true);
+ tmpStr = input.readEntry("shapePixmapBottomRight");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("wm_bottomright", tmpStr, true, true);
+
+
+ input.setGroup("Window Titlebar");
+ output->writeEntry("TitleAlignment", input.readEntry("TitleAlignment"), true, true);
+ output->writeEntry("PixmapUnderTitleText", input.readEntry("PixmapUnderTitleText"), true, true);
+ output->writeEntry("TitleFrameShaded", input.readEntry("TitleFrameShaded"), true, true);
+
+ tmpStr = input.readEntry("MenuButton");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("menu", tmpStr, true, true);
+ tmpStr = input.readEntry("PinUpButton");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("pinup", tmpStr, true, true);
+ tmpStr = input.readEntry("PinDownButton");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("pindown", tmpStr, true, true);
+ tmpStr = input.readEntry("CloseButton");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("close", tmpStr, true, true);
+ tmpStr = input.readEntry("MaximizeButton");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("maximize", tmpStr, true, true);
+ tmpStr = input.readEntry("MaximizeDownButton");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("maximizedown", tmpStr, true, true);
+ tmpStr = input.readEntry("MinimizeButton");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("iconify", tmpStr, true, true);
+ tmpStr = input.readEntry("TitlebarPixmapActive");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("TitlebarPixmapActive", tmpStr, true, true);
+ tmpStr = input.readEntry("TitlebarPixmapInactive");
+ if(!tmpStr.isEmpty())
+ copy(srcStr+tmpStr, localDirStr+tmpStr);
+ output->writeEntry("TitlebarPixmapInactive", tmpStr, true, true);
+
+ input.setGroup("Window Button Layout");
+ output->setGroup("Buttons");
+ output->writeEntry("ButtonA", input.readEntry("ButtonA"), true, true);
+ output->writeEntry("ButtonB", input.readEntry("ButtonB"), true, true);
+ output->writeEntry("ButtonC", input.readEntry("ButtonC"), true, true);
+ output->writeEntry("ButtonD", input.readEntry("ButtonD"), true, true);
+ output->writeEntry("ButtonE", input.readEntry("ButtonE"), true, true);
+ output->writeEntry("ButtonF", input.readEntry("ButtonF"), true, true);
+
+ output->sync();
+
+ return(0);
+}
+
diff --git a/twin/clients/kwmtheme/kwmtheme.desktop b/twin/clients/kwmtheme/kwmtheme.desktop
new file mode 100644
index 00000000..20161827
--- /dev/null
+++ b/twin/clients/kwmtheme/kwmtheme.desktop
@@ -0,0 +1,81 @@
+[Desktop Entry]
+Name=KWM Theme
+Name[af]=KWM Tema
+Name[ar]=سمة KWM
+Name[az]=KWM Örtüsü
+Name[be]=Тэма KWM
+Name[bn]=KWM থীম
+Name[br]=Gwiskad KWM
+Name[bs]=KWM Tema
+Name[ca]=Tema KWM
+Name[cs]=Téma KWM
+Name[csb]=Témë KWM
+Name[cy]=Thema KWM
+Name[da]=KWM-tema
+Name[de]=KWM-Design
+Name[el]=Θέμα KWM
+Name[eo]=KWM-etoso
+Name[es]=Tema de KWM
+Name[et]=KWM teema
+Name[eu]=KWM gaia
+Name[fa]=چهره KWM
+Name[fi]=KWM-teema
+Name[fr]=Thème KWM
+Name[fy]=KWM-tema
+Name[ga]=Téama KWM
+Name[gl]=Tema do KWM
+Name[hi]=केडबल्यूएम प्रसंग
+Name[hr]=KWM tema
+Name[hu]=KWM téma
+Name[id]=Theme KWM
+Name[is]=KWM þema
+Name[it]=Tema KWM
+Name[ja]=KWM テーマ
+Name[ka]=KWM სტილი
+Name[kk]=KWM нақышы
+Name[km]=ស្បែក KWM
+Name[ko]=KWM 테마
+Name[lo]=ແບບຕົວຈັດການຫນ້າຕ່າງ KWM
+Name[lt]=KWM tema
+Name[lv]=KWM Tēma
+Name[mk]=KWM тема
+Name[mn]=KWM-Хэлбэр
+Name[ms]=Temas KWM
+Name[mt]=Tema KWM
+Name[nb]=KWM-tema
+Name[nds]=KWM-Muster
+Name[ne]=KWM विषयवस्तु
+Name[nl]=KWM-thema
+Name[nn]=KWM-tema
+Name[nso]=Molaetsa wa KWM
+Name[oc]=Tema KWM
+Name[pa]=KWM ਸਰੂਪ
+Name[pl]=Motyw KWM
+Name[pt]=Tema KWM
+Name[pt_BR]=Tema KWM
+Name[ro]=Tematică KWM
+Name[ru]=Стиль KWM
+Name[rw]=Insanganyamatsiko KWM
+Name[se]=KWM-fáddá
+Name[sk]=Téma KWM
+Name[sl]=Tema KWM
+Name[sr]=KWM тема
+Name[sr@Latn]=KWM tema
+Name[ss]=Indzikimba ye KWM
+Name[sv]=KWM-tema
+Name[ta]=KWM தலைப்பு
+Name[tg]=Услуби KWM
+Name[th]=ชุดตกแต่งหน้าต่าง KWM
+Name[tr]=KWM Teması
+Name[tt]=KWM Tışlaw
+Name[uk]=Тема KWM
+Name[uz]=KWM mavzusi
+Name[uz@cyrillic]=KWM мавзуси
+Name[ven]=Thero ya KWM
+Name[vi]=Sắc thái KWM
+Name[wa]=Tinme KWM
+Name[xh]=Umxholo we KWM
+Name[zh_CN]=KWM 主题
+Name[zh_TW]=KWM 主題
+Name[zu]=Ingqikithi ye-KWM
+X-TDE-Library=twin3_kwmtheme
diff --git a/twin/clients/kwmtheme/kwmthemeclient.cpp b/twin/clients/kwmtheme/kwmthemeclient.cpp
new file mode 100644
index 00000000..73c8feac
--- /dev/null
+++ b/twin/clients/kwmtheme/kwmthemeclient.cpp
@@ -0,0 +1,936 @@
+#include <tdeconfig.h>
+#include "kwmthemeclient.h"
+#include <tdeglobal.h>
+#include <tqlayout.h>
+#include <tqdrawutil.h>
+#include <tqpainter.h>
+#include <kpixmapeffect.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <tdelocale.h>
+#include <tqbitmap.h>
+#include <tqstyle.h>
+#include <tqlabel.h>
+#include <tqtooltip.h>
+
+namespace KWMTheme {
+
+
+/* static TQPixmap stretchPixmap(TQPixmap& src, bool stretchVert){
+ TQPixmap dest;
+ TQBitmap *srcMask, *destMask;
+ int w, h, w2, h2;
+ TQPainter p;
+
+ if (src.isNull()) return src;
+
+ w = src.width();
+ h = src.height();
+
+ if (stretchVert){
+ w2 = w;
+ for (h2=h; h2<100; h2=h2<<1)
+ ;
+ }
+ else{
+ h2 = h;
+ for (w2=w; w2<100; w2=w2<<1)
+ ;
+ }
+ if (w2==w && h2==h) return src;
+
+ dest = src;
+ dest.resize(w2, h2);
+
+ p.begin(&dest);
+ p.drawTiledPixmap(0, 0, w2, h2, src);
+ p.end();
+
+ srcMask = (TQBitmap*)src.mask();
+ if (srcMask){
+ destMask = (TQBitmap*)dest.mask();
+ p.begin(destMask);
+ p.drawTiledPixmap(0, 0, w2, h2, *srcMask);
+ p.end();
+ }
+ return dest;
+} */
+
+
+inline const KDecorationOptions* options() { return KDecoration::options(); }
+
+enum FramePixmap{FrameTop=0, FrameBottom, FrameLeft, FrameRight, FrameTopLeft,
+ FrameTopRight, FrameBottomLeft, FrameBottomRight};
+
+static TQPixmap *framePixmaps[8];
+static TQPixmap *menuPix, *iconifyPix, *closePix, *maxPix, *minmaxPix,
+ *pinupPix, *pindownPix;
+static KPixmap *aTitlePix = 0;
+static KPixmap *iTitlePix = 0;
+static KPixmapEffect::GradientType grType;
+static int maxExtent, titleAlign;
+static bool titleGradient = true;
+static bool pixmaps_created = false;
+static bool titleSunken = false;
+static bool titleTransparent;
+
+static void create_pixmaps()
+{
+ const char *keys[] = {"wm_top", "wm_bottom", "wm_left", "wm_right",
+ "wm_topleft", "wm_topright", "wm_bottomleft", "wm_bottomright"};
+
+ if(pixmaps_created)
+ return;
+ pixmaps_created = true;
+
+ TDEConfig *config = TDEGlobal::config();
+ config->setGroup("General");
+ TQString tmpStr;
+
+ for(int i=0; i < 8; ++i)
+ {
+ framePixmaps[i] = new TQPixmap(locate("data",
+ "twin/pics/"+config->readEntry(keys[i], " ")));
+ if(framePixmaps[i]->isNull())
+ kdWarning() << "Unable to load frame pixmap for " << keys[i] << endl;
+ }
+/*
+ *framePixmaps[FrameTop] = stretchPixmap(*framePixmaps[FrameTop], false);
+ *framePixmaps[FrameBottom] = stretchPixmap(*framePixmaps[FrameBottom], false);
+ *framePixmaps[FrameLeft] = stretchPixmap(*framePixmaps[FrameLeft], true);
+ *framePixmaps[FrameRight] = stretchPixmap(*framePixmaps[FrameRight], true);
+*/
+ maxExtent = framePixmaps[FrameTop]->height();
+ if(framePixmaps[FrameBottom]->height() > maxExtent)
+ maxExtent = framePixmaps[FrameBottom]->height();
+ if(framePixmaps[FrameLeft]->width() > maxExtent)
+ maxExtent = framePixmaps[FrameLeft]->width();
+ if(framePixmaps[FrameRight]->width() > maxExtent)
+ maxExtent = framePixmaps[FrameRight]->width();
+
+ maxExtent++;
+
+ menuPix = new TQPixmap(locate("data",
+ "twin/pics/"+config->readEntry("menu", " ")));
+ iconifyPix = new TQPixmap(locate("data",
+ "twin/pics/"+config->readEntry("iconify", " ")));
+ maxPix = new TQPixmap(locate("appdata",
+ "pics/"+config->readEntry("maximize", " ")));
+ minmaxPix = new TQPixmap(locate("data",
+ "twin/pics/"+config->readEntry("maximizedown", " ")));
+ closePix = new TQPixmap(locate("data",
+ "twin/pics/"+config->readEntry("close", " ")));
+ pinupPix = new TQPixmap(locate("data",
+ "twin/pics/"+config->readEntry("pinup", " ")));
+ pindownPix = new TQPixmap(locate("data",
+ "twin/pics/"+config->readEntry("pindown", " ")));
+ if(menuPix->isNull())
+ menuPix->load(locate("data", "twin/pics/menu.png"));
+ if(iconifyPix->isNull())
+ iconifyPix->load(locate("data", "twin/pics/iconify.png"));
+ if(maxPix->isNull())
+ maxPix->load(locate("data", "twin/pics/maximize.png"));
+ if(minmaxPix->isNull())
+ minmaxPix->load(locate("data", "twin/pics/maximizedown.png"));
+ if(closePix->isNull())
+ closePix->load(locate("data", "twin/pics/close.png"));
+ if(pinupPix->isNull())
+ pinupPix->load(locate("data", "twin/pics/pinup.png"));
+ if(pindownPix->isNull())
+ pindownPix->load(locate("data", "twin/pics/pindown.png"));
+
+ tmpStr = config->readEntry("TitleAlignment");
+ if(tmpStr == "right")
+ titleAlign = Qt::AlignRight | Qt::AlignVCenter;
+ else if(tmpStr == "middle")
+ titleAlign = Qt::AlignCenter;
+ else
+ titleAlign = Qt::AlignLeft | Qt::AlignVCenter;
+ titleSunken = config->readBoolEntry("TitleFrameShaded", true);
+ // titleSunken = true; // is this fixed?
+ titleTransparent = config->readBoolEntry("PixmapUnderTitleText", true);
+
+ tmpStr = config->readEntry("TitlebarLook");
+ if(tmpStr == "shadedVertical"){
+ aTitlePix = new KPixmap;
+ aTitlePix->resize(32, 20);
+ KPixmapEffect::gradient(*aTitlePix,
+ options()->color(KDecorationOptions::ColorTitleBar, true),
+ options()->color(KDecorationOptions::ColorTitleBlend, true),
+ KPixmapEffect::VerticalGradient);
+ iTitlePix = new KPixmap;
+ iTitlePix->resize(32, 20);
+ KPixmapEffect::gradient(*iTitlePix,
+ options()->color(KDecorationOptions::ColorTitleBar, false),
+ options()->color(KDecorationOptions::ColorTitleBlend, false),
+ KPixmapEffect::VerticalGradient);
+ titleGradient = false; // we can just tile this
+
+ }
+ else if(tmpStr == "shadedHorizontal")
+ grType = KPixmapEffect::HorizontalGradient;
+ else if(tmpStr == "shadedDiagonal")
+ grType = KPixmapEffect::DiagonalGradient;
+ else if(tmpStr == "shadedCrossDiagonal")
+ grType = KPixmapEffect::CrossDiagonalGradient;
+ else if(tmpStr == "shadedPyramid")
+ grType = KPixmapEffect::PyramidGradient;
+ else if(tmpStr == "shadedRectangle")
+ grType = KPixmapEffect::RectangleGradient;
+ else if(tmpStr == "shadedPipeCross")
+ grType = KPixmapEffect::PipeCrossGradient;
+ else if(tmpStr == "shadedElliptic")
+ grType = KPixmapEffect::EllipticGradient;
+ else{
+ titleGradient = false;
+ tmpStr = config->readEntry("TitlebarPixmapActive", "");
+ if(!tmpStr.isEmpty()){
+ aTitlePix = new KPixmap;
+ aTitlePix->load(locate("data", "twin/pics/" + tmpStr));
+ }
+ else
+ aTitlePix = NULL;
+ tmpStr = config->readEntry("TitlebarPixmapInactive", "");
+ if(!tmpStr.isEmpty()){
+ iTitlePix = new KPixmap;
+ iTitlePix->load(locate("data", "twin/pics/" + tmpStr));
+ }
+ else
+ iTitlePix = NULL;
+ }
+}
+
+static void delete_pixmaps()
+{
+ for(int i=0; i < 8; ++i)
+ delete framePixmaps[i];
+
+ delete menuPix;
+ delete iconifyPix;
+ delete closePix;
+ delete maxPix;
+ delete minmaxPix;
+ delete pinupPix;
+ delete pindownPix;
+ delete aTitlePix;
+ aTitlePix = 0;
+ delete iTitlePix;
+ iTitlePix = 0;
+
+ titleGradient = true;
+ pixmaps_created = false;
+ titleSunken = false;
+}
+
+void MyButton::drawButtonLabel(TQPainter *p)
+{
+ if(pixmap()){
+ // If we have a theme who's button covers the entire width or
+ // entire height, we shift down/right by 1 pixel so we have
+ // some visual notification of button presses. i.e. for MGBriezh
+ int offset = (isDown() && ((pixmap()->width() >= width()) ||
+ (pixmap()->height() >= height()))) ? 1 : 0;
+ style().drawItem(p, TQRect( offset, offset, width(), height() ),
+ AlignCenter, colorGroup(),
+ true, pixmap(), TQString::null);
+ }
+}
+
+KWMThemeClient::KWMThemeClient( KDecorationBridge* b, KDecorationFactory* f )
+ : KDecoration( b, f )
+{
+}
+
+void KWMThemeClient::init()
+{
+ createMainWidget( WResizeNoErase | WStaticContents );
+ widget()->installEventFilter( this );
+
+ stickyBtn = maxBtn = mnuBtn = 0;
+ layout = new TQGridLayout(widget());
+ layout->addColSpacing(0, maxExtent);
+ layout->addColSpacing(2, maxExtent);
+
+ layout->addRowSpacing(0, maxExtent);
+
+ layout->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed,
+ TQSizePolicy::Expanding));
+
+ if( isPreview())
+ layout->addWidget( new TQLabel( i18n( "<center><b>KWMTheme</b></center>" ), widget()), 2, 1);
+ else
+ layout->addItem( new TQSpacerItem( 0, 0 ), 2, 1);
+
+ // Without the next line, shading flickers
+ layout->addItem( new TQSpacerItem(0, 0, TQSizePolicy::Fixed, TQSizePolicy::Expanding) );
+ layout->addRowSpacing(3, maxExtent);
+ layout->setRowStretch(2, 10);
+ layout->setColStretch(1, 10);
+
+ TQBoxLayout* hb = new TQBoxLayout(0, TQBoxLayout::LeftToRight, 0, 0, 0);
+ layout->addLayout( hb, 1, 1 );
+
+ TDEConfig *config = TDEGlobal::config();
+ config->setGroup("Buttons");
+ TQString val;
+ MyButton *btn;
+ int i;
+ static const char *defaultButtons[]={"Menu","Sticky","Off","Iconify",
+ "Maximize","Close"};
+ static const char keyOffsets[]={"ABCDEF"};
+ for(i=0; i < 6; ++i){
+ if(i == 3){
+ titlebar = new TQSpacerItem(10, 20, TQSizePolicy::Expanding,
+ TQSizePolicy::Minimum );
+ hb->addItem( titlebar );
+ }
+ TQString key("Button");
+ key += TQChar(keyOffsets[i]);
+ val = config->readEntry(key, defaultButtons[i]);
+ if(val == "Menu"){
+ mnuBtn = new MyButton(widget(), "menu");
+ TQToolTip::add( mnuBtn, i18n("Menu"));
+ iconChange();
+ hb->addWidget(mnuBtn);
+ mnuBtn->setFixedSize(20, 20);
+ connect(mnuBtn, TQT_SIGNAL(pressed()), this,
+ TQT_SLOT(menuButtonPressed()));
+ }
+ else if(val == "Sticky"){
+ stickyBtn = new MyButton(widget(), "sticky");
+ TQToolTip::add( stickyBtn, i18n("Sticky"));
+ if (isOnAllDesktops())
+ stickyBtn->setPixmap(*pindownPix);
+ else
+ stickyBtn->setPixmap(*pinupPix);
+ connect(stickyBtn, TQT_SIGNAL( clicked() ), this, TQT_SLOT(toggleOnAllDesktops()));
+ hb->addWidget(stickyBtn);
+ stickyBtn->setFixedSize(20, 20);
+ }
+ else if((val == "Iconify") && isMinimizable()){
+ btn = new MyButton(widget(), "iconify");
+ TQToolTip::add( btn, i18n("Minimize"));
+ btn->setPixmap(*iconifyPix);
+ connect(btn, TQT_SIGNAL(clicked()), this, TQT_SLOT(minimize()));
+ hb->addWidget(btn);
+ btn->setFixedSize(20, 20);
+ }
+ else if((val == "Maximize") && isMaximizable()){
+ maxBtn = new MyButton(widget(), "max");
+ TQToolTip::add( maxBtn, i18n("Maximize"));
+ maxBtn->setPixmap(*maxPix);
+ connect(maxBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(maximize()));
+ hb->addWidget(maxBtn);
+ maxBtn->setFixedSize(20, 20);
+ }
+ else if((val == "Close") && isCloseable()){
+ btn = new MyButton(widget(), "close");
+ TQToolTip::add( btn, i18n("Close"));
+ btn->setPixmap(*closePix);
+ connect(btn, TQT_SIGNAL(clicked()), this, TQT_SLOT(closeWindow()));
+ hb->addWidget(btn);
+ btn->setFixedSize(20, 20);
+ }
+ else{
+ if((val != "Off") &&
+ ((val == "Iconify") && !isMinimizable()) &&
+ ((val == "Maximize") && !isMaximizable()))
+ kdWarning() << "KWin: Unrecognized button value: " << val << endl;
+
+ }
+ }
+ if(titleGradient){
+ aGradient = new KPixmap;
+ iGradient = new KPixmap;
+ }
+ else{
+ aGradient = 0;
+ iGradient = 0;
+ }
+ widget()->setBackgroundMode(NoBackground);
+}
+
+void KWMThemeClient::drawTitle(TQPainter &dest)
+{
+ TQRect titleRect = titlebar->geometry();
+ TQRect r(0, 0, titleRect.width(), titleRect.height());
+ TQPixmap buffer;
+
+ if(buffer.width() == r.width())
+ return;
+
+ buffer.resize(r.size());
+ TQPainter p;
+ p.begin(&buffer);
+
+ if(titleSunken){
+ qDrawShadeRect(&p, r, options()->colorGroup(KDecorationOptions::ColorFrame, isActive()),
+ true, 1, 0);
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ }
+
+ KPixmap *fill = isActive() ? aTitlePix : iTitlePix;
+ if(fill)
+ p.drawTiledPixmap(r, *fill);
+ else if(titleGradient){
+ fill = isActive() ? aGradient : iGradient;
+ if(fill->width() != r.width()){
+ fill->resize(r.width(), 20);
+ KPixmapEffect::gradient(*fill,
+ options()->color(KDecorationOptions::ColorTitleBar, isActive()),
+ options()->color(KDecorationOptions::ColorTitleBlend, isActive()),
+ grType);
+ }
+ p.drawTiledPixmap(r, *fill);
+ }
+ else{
+ p.fillRect(r, options()->colorGroup(KDecorationOptions::ColorTitleBar, isActive()).
+ brush(TQColorGroup::Button));
+ }
+ p.setFont(options()->font(isActive()));
+ p.setPen(options()->color(KDecorationOptions::ColorFont, isActive()));
+ // Add left & right margin
+ r.setLeft(r.left()+5);
+ r.setRight(r.right()-5);
+ p.drawText(r, titleAlign, caption());
+ p.end();
+
+ dest.drawPixmap(titleRect.x(), titleRect.y(), buffer);
+}
+
+
+void KWMThemeClient::resizeEvent( TQResizeEvent* )
+{
+ doShape();
+ widget()->repaint();
+}
+
+void KWMThemeClient::captionChange()
+{
+ widget()->repaint( titlebar->geometry(), false );
+}
+
+void KWMThemeClient::paintEvent( TQPaintEvent *)
+{
+ TQPainter p;
+ p.begin(widget());
+ int x,y;
+ // first the corners
+ int w1 = framePixmaps[FrameTopLeft]->width();
+ int h1 = framePixmaps[FrameTopLeft]->height();
+ if (w1 > width()/2) w1 = width()/2;
+ if (h1 > height()/2) h1 = height()/2;
+ p.drawPixmap(0,0,*framePixmaps[FrameTopLeft],
+ 0,0,w1, h1);
+ int w2 = framePixmaps[FrameTopRight]->width();
+ int h2 = framePixmaps[FrameTopRight]->height();
+ if (w2 > width()/2) w2 = width()/2;
+ if (h2 > height()/2) h2 = height()/2;
+ p.drawPixmap(width()-w2,0,*framePixmaps[FrameTopRight],
+ framePixmaps[FrameTopRight]->width()-w2,0,w2, h2);
+
+ int w3 = framePixmaps[FrameBottomLeft]->width();
+ int h3 = framePixmaps[FrameBottomLeft]->height();
+ if (w3 > width()/2) w3 = width()/2;
+ if (h3 > height()/2) h3 = height()/2;
+ p.drawPixmap(0,height()-h3,*framePixmaps[FrameBottomLeft],
+ 0,framePixmaps[FrameBottomLeft]->height()-h3,w3, h3);
+
+ int w4 = framePixmaps[FrameBottomRight]->width();
+ int h4 = framePixmaps[FrameBottomRight]->height();
+ if (w4 > width()/2) w4 = width()/2;
+ if (h4 > height()/2) h4 = height()/2;
+ p.drawPixmap(width()-w4,height()-h4,*(framePixmaps[FrameBottomRight]),
+ framePixmaps[FrameBottomRight]->width()-w4,
+ framePixmaps[FrameBottomRight]->height()-h4,
+ w4, h4);
+
+ TQPixmap pm;
+ TQWMatrix m;
+ int n,s,w;
+ //top
+ pm = *framePixmaps[FrameTop];
+
+ if (pm.width() > 0){
+ s = width()-w2-w1;
+ n = s/pm.width();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(w/(float)pm.width(), 1);
+ pm = pm.xForm(m);
+
+ x = w1;
+ while (1){
+ if (pm.width() < width()-w2-x){
+ p.drawPixmap(x,maxExtent-pm.height()-1,
+ pm);
+ x += pm.width();
+ }
+ else {
+ p.drawPixmap(x,maxExtent-pm.height()-1,
+ pm,
+ 0,0,width()-w2-x,pm.height());
+ break;
+ }
+ }
+ }
+
+ //bottom
+ pm = *framePixmaps[FrameBottom];
+
+ if (pm.width() > 0){
+ s = width()-w4-w3;
+ n = s/pm.width();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(w/(float)pm.width(), 1);
+ pm = pm.xForm(m);
+
+ x = w3;
+ while (1){
+ if (pm.width() < width()-w4-x){
+ p.drawPixmap(x,height()-maxExtent+1,pm);
+ x += pm.width();
+ }
+ else {
+ p.drawPixmap(x,height()-maxExtent+1,pm,
+ 0,0,width()-w4-x,pm.height());
+ break;
+ }
+ }
+ }
+
+ //left
+ pm = *framePixmaps[FrameLeft];
+
+ if (pm.height() > 0){
+ s = height()-h3-h1;
+ n = s/pm.height();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(1, w/(float)pm.height());
+ pm = pm.xForm(m);
+
+ y = h1;
+ while (1){
+ if (pm.height() < height()-h3-y){
+ p.drawPixmap(maxExtent-pm.width()-1, y,
+ pm);
+ y += pm.height();
+ }
+ else {
+ p.drawPixmap(maxExtent-pm.width()-1, y,
+ pm,
+ 0,0, pm.width(),
+ height()-h3-y);
+ break;
+ }
+ }
+ }
+
+ //right
+ pm = *framePixmaps[FrameRight];
+
+ if (pm.height() > 0){
+ s = height()-h4-h2;
+ n = s/pm.height();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(1, w/(float)pm.height());
+ pm = pm.xForm(m);
+
+ y = h2;
+ while (1){
+ if (pm.height() < height()-h4-y){
+ p.drawPixmap(width()-maxExtent+1, y,
+ pm);
+ y += pm.height();
+ }
+ else {
+ p.drawPixmap(width()-maxExtent+1, y,
+ pm,
+ 0,0, pm.width(),
+ height()-h4-y);
+ break;
+ }
+ }
+ }
+ drawTitle(p);
+
+ TQColor c = widget()->colorGroup().background();
+
+ // KWM evidently had a 1 pixel border around the client window. We
+ // emulate it here, but should be removed at some point in order to
+ // seamlessly mesh widget themes
+ p.setPen(c);
+ p.drawRect(maxExtent-1, maxExtent-1, width()-(maxExtent-1)*2,
+ height()-(maxExtent-1)*2);
+
+ // We fill the area behind the wrapped widget to ensure that
+ // shading animation is drawn as smoothly as possible
+ TQRect r(layout->cellGeometry(2, 1));
+ p.fillRect( r.x(), r.y(), r.width(), r.height(), c);
+ p.end();
+}
+
+void KWMThemeClient::doShape()
+{
+
+ TQBitmap shapemask(width(), height());
+ shapemask.fill(color0);
+ TQPainter p;
+ p.begin(&shapemask);
+ p.setBrush(color1);
+ p.setPen(color1);
+ int x,y;
+ // first the corners
+ int w1 = framePixmaps[FrameTopLeft]->width();
+ int h1 = framePixmaps[FrameTopLeft]->height();
+ if (w1 > width()/2) w1 = width()/2;
+ if (h1 > height()/2) h1 = height()/2;
+ if (framePixmaps[FrameTopLeft]->mask())
+ p.drawPixmap(0,0,*framePixmaps[FrameTopLeft]->mask(),
+ 0,0,w1, h1);
+ else
+ p.fillRect(0,0,w1,h1,color1);
+ int w2 = framePixmaps[FrameTopRight]->width();
+ int h2 = framePixmaps[FrameTopRight]->height();
+ if (w2 > width()/2) w2 = width()/2;
+ if (h2 > height()/2) h2 = height()/2;
+ if (framePixmaps[FrameTopRight]->mask())
+ p.drawPixmap(width()-w2,0,*framePixmaps[FrameTopRight]->mask(),
+ framePixmaps[FrameTopRight]->width()-w2,0,w2, h2);
+ else
+ p.fillRect(width()-w2,0,w2, h2,color1);
+
+ int w3 = framePixmaps[FrameBottomLeft]->width();
+ int h3 = framePixmaps[FrameBottomLeft]->height();
+ if (w3 > width()/2) w3 = width()/2;
+ if (h3 > height()/2) h3 = height()/2;
+ if (framePixmaps[FrameBottomLeft]->mask())
+ p.drawPixmap(0,height()-h3,*framePixmaps[FrameBottomLeft]->mask(),
+ 0,framePixmaps[FrameBottomLeft]->height()-h3,w3, h3);
+ else
+ p.fillRect(0,height()-h3,w3,h3,color1);
+
+ int w4 = framePixmaps[FrameBottomRight]->width();
+ int h4 = framePixmaps[FrameBottomRight]->height();
+ if (w4 > width()/2) w4 = width()/2;
+ if (h4 > height()/2) h4 = height()/2;
+ if (framePixmaps[FrameBottomRight]->mask())
+ p.drawPixmap(width()-w4,height()-h4,*framePixmaps[FrameBottomRight]->mask(),
+ framePixmaps[FrameBottomRight]->width()-w4,
+ framePixmaps[FrameBottomRight]->height()-h4,
+ w4, h4);
+ else
+ p.fillRect(width()-w4,height()-h4,w4,h4,color1);
+
+ TQPixmap pm;
+ TQWMatrix m;
+ int n,s,w;
+ //top
+ if (framePixmaps[FrameTop]->mask())
+ {
+ pm = *framePixmaps[FrameTop]->mask();
+
+ s = width()-w2-w1;
+ n = s/pm.width();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(w/(float)pm.width(), 1);
+ pm = pm.xForm(m);
+
+ x = w1;
+ while (1){
+ if (pm.width() < width()-w2-x){
+ p.drawPixmap(x,maxExtent-pm.height()-1,
+ pm);
+ x += pm.width();
+ }
+ else {
+ p.drawPixmap(x,maxExtent-pm.height()-1,
+ pm,
+ 0,0,width()-w2-x,pm.height());
+ break;
+ }
+ }
+ }
+
+ //bottom
+ if (framePixmaps[FrameBottom]->mask())
+ {
+ pm = *framePixmaps[FrameBottom]->mask();
+
+ s = width()-w4-w3;
+ n = s/pm.width();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(w/(float)pm.width(), 1);
+ pm = pm.xForm(m);
+
+ x = w3;
+ while (1){
+ if (pm.width() < width()-w4-x){
+ p.drawPixmap(x,height()-maxExtent+1,pm);
+ x += pm.width();
+ }
+ else {
+ p.drawPixmap(x,height()-maxExtent+1,pm,
+ 0,0,width()-w4-x,pm.height());
+ break;
+ }
+ }
+ }
+
+ //left
+ if (framePixmaps[FrameLeft]->mask())
+ {
+ pm = *framePixmaps[FrameLeft]->mask();
+
+ s = height()-h3-h1;
+ n = s/pm.height();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(1, w/(float)pm.height());
+ pm = pm.xForm(m);
+
+ y = h1;
+ while (1){
+ if (pm.height() < height()-h3-y){
+ p.drawPixmap(maxExtent-pm.width()-1, y,
+ pm);
+ y += pm.height();
+ }
+ else {
+ p.drawPixmap(maxExtent-pm.width()-1, y,
+ pm,
+ 0,0, pm.width(),
+ height()-h3-y);
+ break;
+ }
+ }
+ }
+
+ //right
+ if (framePixmaps[FrameRight]->mask())
+ {
+ pm = *framePixmaps[FrameRight]->mask();
+
+ s = height()-h4-h2;
+ n = s/pm.height();
+ w = n>0?s/n:s;
+ m.reset();
+ m.scale(1, w/(float)pm.height());
+ pm = pm.xForm(m);
+
+ y = h2;
+ while (1){
+ if (pm.height() < height()-h4-y){
+ p.drawPixmap(width()-maxExtent+1, y,
+ pm);
+ y += pm.height();
+ }
+ else {
+ p.drawPixmap(width()-maxExtent+1, y,
+ pm,
+ 0,0, pm.width(),
+ height()-h4-y);
+ break;
+ }
+ }
+ }
+ p.fillRect(maxExtent-1, maxExtent-1, width()-2*maxExtent+2, height()-2*maxExtent+2, color1);
+ setMask(shapemask);
+}
+
+
+void KWMThemeClient::showEvent(TQShowEvent *)
+{
+ doShape();
+ widget()->repaint(false);
+}
+
+void KWMThemeClient::mouseDoubleClickEvent( TQMouseEvent * e )
+{
+ if (e->button() == LeftButton && titlebar->geometry().contains( e->pos() ) )
+ titlebarDblClickOperation();
+}
+
+void KWMThemeClient::desktopChange()
+{
+ if (stickyBtn) {
+ bool on = isOnAllDesktops();
+ stickyBtn->setPixmap(on ? *pindownPix : *pinupPix);
+ TQToolTip::remove( stickyBtn );
+ TQToolTip::add( stickyBtn, on ? i18n("Unsticky") : i18n("Sticky") );
+ }
+}
+
+void KWMThemeClient::maximizeChange()
+{
+ if (maxBtn) {
+ bool m = maximizeMode() == MaximizeFull;
+ maxBtn->setPixmap(m ? *minmaxPix : *maxPix);
+ TQToolTip::remove( maxBtn );
+ TQToolTip::add( maxBtn, m ? i18n("Restore") : i18n("Maximize"));
+ }
+}
+
+void KWMThemeClient::slotMaximize()
+{
+ maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull );
+}
+
+void KWMThemeClient::activeChange()
+{
+ widget()->update();
+}
+
+KDecoration::Position KWMThemeClient::mousePosition(const TQPoint &p) const
+{
+ Position m = KDecoration::mousePosition(p);
+ // corners
+ if(p.y() < framePixmaps[FrameTop]->height() &&
+ p.x() < framePixmaps[FrameLeft]->width()){
+ m = PositionTopLeft;
+ }
+ else if(p.y() < framePixmaps[FrameTop]->height() &&
+ p.x() > width()-framePixmaps[FrameRight]->width()){
+ m = PositionTopRight;
+ }
+ else if(p.y() > height()-framePixmaps[FrameBottom]->height() &&
+ p.x() < framePixmaps[FrameLeft]->width()){
+ m = PositionBottomLeft;
+ }
+ else if(p.y() > height()-framePixmaps[FrameBottom]->height() &&
+ p.x() > width()-framePixmaps[FrameRight]->width()){
+ m = PositionBottomRight;
+ } // edges
+ else if(p.y() < framePixmaps[FrameTop]->height())
+ m = PositionTop;
+ else if(p.y() > height()-framePixmaps[FrameBottom]->height())
+ m = PositionBottom;
+ else if(p.x() < framePixmaps[FrameLeft]->width())
+ m = PositionLeft;
+ else if(p.x() > width()-framePixmaps[FrameRight]->width())
+ m = PositionRight;
+ return(m);
+}
+
+void KWMThemeClient::menuButtonPressed()
+{
+ mnuBtn->setDown(false); // will stay down if I don't do this
+ TQPoint pos = mnuBtn->mapToGlobal(mnuBtn->rect().bottomLeft());
+ showWindowMenu( pos );
+}
+
+void KWMThemeClient::iconChange()
+{
+ if(mnuBtn){
+ if( icon().pixmap( TQIconSet::Small, TQIconSet::Normal ).isNull()){
+ mnuBtn->setPixmap(*menuPix);
+ }
+ else{
+ mnuBtn->setPixmap(icon().pixmap( TQIconSet::Small, TQIconSet::Normal ));
+ }
+ }
+}
+
+bool KWMThemeClient::eventFilter( TQObject* o, TQEvent* e )
+{
+ if ( o != widget() )
+ return false;
+
+ switch ( e->type() )
+ {
+ case TQEvent::Resize:
+ resizeEvent( static_cast< TQResizeEvent* >( e ) );
+ return true;
+
+ case TQEvent::Paint:
+ paintEvent( static_cast< TQPaintEvent* >( e ) );
+ return true;
+
+ case TQEvent::MouseButtonDblClick:
+ mouseDoubleClickEvent( static_cast< TQMouseEvent* >( e ) );
+ return true;
+
+ case TQEvent::MouseButtonPress:
+ processMousePressEvent( static_cast< TQMouseEvent* >( e ) );
+ return true;
+
+ case TQEvent::Show:
+ showEvent( static_cast< TQShowEvent* >( e ) );
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+TQSize KWMThemeClient::minimumSize() const
+{
+ return widget()->minimumSize().expandedTo( TQSize( 100, 50 ));
+}
+
+void KWMThemeClient::resize( const TQSize& s )
+{
+ widget()->resize( s );
+}
+
+void KWMThemeClient::borders( int& left, int& right, int& top, int& bottom ) const
+{
+ left =
+ right =
+ top =
+ bottom =
+
+TODO
+}
+
+KWMThemeFactory::KWMThemeFactory()
+{
+ create_pixmaps();
+}
+
+KWMThemeFactory::~KWMThemeFactory()
+{
+ delete_pixmaps();
+}
+
+KDecoration* KWMThemeFactory::createDecoration( KDecorationBridge* b )
+{
+ return new KWMThemeClient( b, this );
+}
+
+bool KWMThemeFactory::reset( unsigned long mask )
+{
+ bool needHardReset = false;
+
+TODO
+
+ // doesn't obey the Border size setting
+ if( mask & ( SettingFont | SettingButtons ))
+ needHardReset = true;
+
+ if( mask & ( SettingFont | SettingColors )) {
+ KWMTheme::delete_pixmaps();
+ KWMTheme::create_pixmaps();
+ }
+
+ if( !needHardReset )
+ resetDecorations( mask );
+ return needHardReset;
+}
+
+}
+
+extern "C"
+{
+ KDE_EXPORT KDecorationFactory *create_factory()
+ {
+ return new KWMTheme::KWMThemeFactory();
+ }
+}
+
+#include "kwmthemeclient.moc"
diff --git a/twin/clients/kwmtheme/kwmthemeclient.h b/twin/clients/kwmtheme/kwmthemeclient.h
new file mode 100644
index 00000000..58db3d14
--- /dev/null
+++ b/twin/clients/kwmtheme/kwmthemeclient.h
@@ -0,0 +1,74 @@
+#ifndef __KWMTHEMECLIENT_H
+#define __KWMTHEMECLIENT_H
+
+#include <tqbutton.h>
+#include <tqtoolbutton.h>
+#include <kpixmap.h>
+#include <kdecoration.h>
+#include <kdecorationfactory.h>
+
+class TQLabel;
+class TQSpacerItem;
+class TQGridLayout;
+
+namespace KWMTheme {
+
+class MyButton : public TQToolButton
+{
+public:
+ MyButton(TQWidget *parent=0, const char *name=0)
+ : TQToolButton(parent, name){setAutoRaise(true);setCursor( arrowCursor ); }
+protected:
+ void drawButtonLabel(TQPainter *p);
+};
+
+class KWMThemeClient : public KDecoration
+{
+ Q_OBJECT
+public:
+ KWMThemeClient( KDecorationBridge* b, KDecorationFactory* f );
+ ~KWMThemeClient(){;}
+ void init();
+ void resize( const TQSize& s );
+ TQSize minimumSize() const;
+ void borders( int& left, int& right, int& top, int& bottom ) const;
+protected:
+ void doShape();
+ void drawTitle(TQPainter &p);
+ void resizeEvent( TQResizeEvent* );
+ void paintEvent( TQPaintEvent* );
+ void showEvent( TQShowEvent* );
+ void mouseDoubleClickEvent( TQMouseEvent * );
+ bool eventFilter( TQObject* o, TQEvent* e );
+ void captionChange();
+ void desktopChange();
+ void maximizeChange();
+ void iconChange();
+ void activeChange();
+ void shadeChange() {};
+ Position mousePosition(const TQPoint &) const;
+protected slots:
+ //void slotReset();
+ void menuButtonPressed();
+ void slotMaximize();
+private:
+ TQPixmap buffer;
+ KPixmap *aGradient, *iGradient;
+ MyButton *maxBtn, *stickyBtn, *mnuBtn;
+ TQSpacerItem *titlebar;
+ TQGridLayout* layout;
+};
+
+class KWMThemeFactory : public KDecorationFactory
+{
+public:
+ KWMThemeFactory();
+ ~KWMThemeFactory();
+ KDecoration* createDecoration( KDecorationBridge* b );
+ bool reset( unsigned long mask );
+};
+
+}
+
+#endif
+
diff --git a/twin/clients/laptop/CMakeLists.txt b/twin/clients/laptop/CMakeLists.txt
new file mode 100644
index 00000000..a06afdaf
--- /dev/null
+++ b/twin/clients/laptop/CMakeLists.txt
@@ -0,0 +1,35 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/twin/lib
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES laptop.desktop DESTINATION ${DATA_INSTALL_DIR}/twin )
+
+
+##### twin3_laptop (module) #####################
+
+tde_add_kpart( twin3_laptop AUTOMOC
+ SOURCES laptopclient.cpp
+ LINK tdecorations-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/twin/clients/laptop/Makefile.am b/twin/clients/laptop/Makefile.am
new file mode 100644
index 00000000..ccf1d359
--- /dev/null
+++ b/twin/clients/laptop/Makefile.am
@@ -0,0 +1,17 @@
+
+INCLUDES = -I$(srcdir)/../../lib $(all_includes)
+
+kde_module_LTLIBRARIES = twin3_laptop.la
+
+twin3_laptop_la_SOURCES = laptopclient.cpp
+twin3_laptop_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin3_laptop_la_LIBADD = ../../lib/libtdecorations.la
+
+METASOURCES = AUTO
+noinst_HEADERS = laptopclient.h
+
+lnkdir = $(kde_datadir)/twin
+lnk_DATA = laptop.desktop
+
+EXTRA_DIST = $(lnk_DATA)
+
diff --git a/twin/clients/laptop/laptop.desktop b/twin/clients/laptop/laptop.desktop
new file mode 100644
index 00000000..b1c78ca9
--- /dev/null
+++ b/twin/clients/laptop/laptop.desktop
@@ -0,0 +1,69 @@
+[Desktop Entry]
+Name=Laptop
+Name[af]=Draagbare rekenaar
+Name[ar]=الحاسوب النقّال
+Name[az]=Dizüstü Kompüter
+Name[be]=Ноўтбук
+Name[bg]=Лаптоп
+Name[bn]=ল্যাপটপ
+Name[br]=Hezoug
+Name[ca]=Portàtil
+Name[cs]=Notebook
+Name[cy]=Gluniadur
+Name[da]=Bærbar
+Name[el]=Φορητό
+Name[eo]=Tekokomputilo
+Name[es]=Portátil
+Name[eu]=Ordenagailu eramangarria
+Name[fa]=رایانۀ کیفی
+Name[fi]=Kannettava
+Name[fr]=Ordinateur portable
+Name[fy]=Skoatkompjûter
+Name[ga]=Ríomhaire Glúine
+Name[gl]=Portátil
+Name[he]=מחשב נייד
+Name[hi]=लैपटॉप
+Name[hsb]=laptop
+Name[hu]=Noteszgép
+Name[is]=Ferðavél
+Name[it]=Portatile
+Name[ja]=ラップトップ
+Name[ka]=ლეპტოპი
+Name[kk]=Ноутбук
+Name[km]=កុំព្យូទ័រ​យួរ​ដៃ
+Name[ko]=랩탑
+Name[lo]=ແລບທອບ
+Name[lt]=Nešiojamas kompiuteris
+Name[lv]=Laptops
+Name[mk]=Лаптоп
+Name[mn]=Лаптоп
+Name[ms]=Komputer riba
+Name[nb]=Bærbar
+Name[nds]=Klappreekner
+Name[ne]=ल्यापटप
+Name[nn]=Berbar
+Name[oc]=Portatil
+Name[pa]=ਲੈਪਟਾਪ
+Name[pt]=Portátil
+Name[ru]=Ноутбук
+Name[rw]=Mudasobwa Igendanwa
+Name[se]=Mátkedihtor
+Name[sl]=Prenosnik
+Name[sr]=Лаптоп
+Name[sv]=Bärbar dator
+Name[ta]=மடிக்கணினி
+Name[te]=లాప్ టాప్
+Name[tg]=Ноутбук
+Name[th]=แลปทอป
+Name[tr]=Dizüstü
+Name[tt]=Qulsanaq
+Name[uk]=Мобільний комп'ютер (лептоп)
+Name[uz@cyrillic]=Лаптоп
+Name[ven]=Khomupwutha pfarwa
+Name[vi]=Máy xách tay
+Name[wa]=Poirtåve
+Name[xh]=Umphezulu osongiweyo
+Name[zh_CN]=笔记本电脑
+Name[zh_TW]=筆記型電腦
+Name[zu]=Ikhomputha ephathwayo eyisicaba
+X-TDE-Library=twin3_laptop
diff --git a/twin/clients/laptop/laptopclient.cpp b/twin/clients/laptop/laptopclient.cpp
new file mode 100644
index 00000000..34c79b2d
--- /dev/null
+++ b/twin/clients/laptop/laptopclient.cpp
@@ -0,0 +1,761 @@
+/*
+ * Laptop KWin Decoration
+ *
+ * Copyright (c) 2005 Sandro Giessl <sandro@giessl.com>
+ * Port of this decoration to KDE 3.2, accessibility enhancement are
+ * Copyright (c) 2003 Luciano Montanaro <mikelima@cirulla.net>
+ */
+
+#include <tdeconfig.h> // up here to avoid X11 header conflict :P
+#include "laptopclient.h"
+#include <tqdrawutil.h>
+#include <kpixmapeffect.h>
+#include <kdrawutil.h>
+#include <tdeglobal.h>
+#include <tdelocale.h>
+#include <tqbitmap.h>
+
+namespace Laptop {
+
+static const unsigned char iconify_bits[] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18};
+
+static const unsigned char close_bits[] = {
+ 0x42, 0xe7, 0x7e, 0x3c, 0x3c, 0x7e, 0xe7, 0x42};
+
+static const unsigned char maximize_bits[] = {
+ 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0xff, 0xff };
+
+static const unsigned char r_minmax_bits[] = {
+ 0x0c, 0x18, 0x33, 0x67, 0xcf, 0x9f, 0x3f, 0x3f};
+
+static const unsigned char l_minmax_bits[] = {
+ 0x30, 0x18, 0xcc, 0xe6, 0xf3, 0xf9, 0xfc, 0xfc};
+
+static const unsigned char question_bits[] = {
+ 0x3c, 0x66, 0x60, 0x30, 0x18, 0x00, 0x18, 0x18};
+
+static const unsigned char unsticky_bits[] = {
+ 0x3c, 0x42, 0x99, 0xbd, 0xbd, 0x99, 0x42, 0x3c};
+
+static const unsigned char sticky_bits[] = {
+ 0x3c, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3c};
+
+static TQPixmap *titlePix;
+static KPixmap *aUpperGradient;
+static KPixmap *iUpperGradient;
+// buttons active, inactive, up, down, and 2 sizes :P
+static KPixmap *btnPix1;
+static KPixmap *iBtnPix1;
+static KPixmap *btnDownPix1;
+static KPixmap *iBtnDownPix1;
+static KPixmap *btnPix2;
+static KPixmap *btnDownPix2;
+static KPixmap *iBtnPix2;
+static KPixmap *iBtnDownPix2;
+static TQColor btnForeground;
+
+static int titleHeight = 14;
+static int btnWidth1 = 17;
+static int btnWidth2 = 27;
+
+static int handleSize = 8; // the resize handle size in pixels
+
+static bool pixmaps_created = false;
+
+// =====================================
+
+extern "C" KDE_EXPORT KDecorationFactory* create_factory()
+{
+ return new Laptop::LaptopClientFactory();
+}
+
+// =====================================
+
+static inline const KDecorationOptions* options()
+{
+ return KDecoration::options();
+}
+
+static void drawButtonFrame(KPixmap *pix, const TQColorGroup &g, bool sunken)
+{
+ TQPainter p;
+ int w = pix->width();
+ int h = pix->height();
+ int x2 = w-1;
+ int y2 = h-1;
+ p.begin(pix);
+
+ if(sunken){
+ qDrawShadePanel(&p, 0, 0, w, h, g, true, 2);
+ }
+ else{
+ p.setPen(g.dark());
+ p.drawRect(0, 0, w-1, h-1);
+ p.setPen(g.light());
+ p.drawLine(x2, 0, x2, y2);
+ p.drawLine(0, y2, x2, y2);
+ p.drawLine(1, 1, x2-2, 1);
+ p.drawLine(1, 1, 1, y2-2);
+ p.end();
+ }
+}
+
+static void create_pixmaps()
+{
+ if(pixmaps_created)
+ return;
+ pixmaps_created = true;
+
+ titleHeight = TQFontMetrics(options()->font(true)).height() + 2;
+ if (titleHeight < handleSize) titleHeight = handleSize;
+ titleHeight &= ~1; // Make title height even
+ if (titleHeight < 14) titleHeight = 14;
+
+ btnWidth1 = titleHeight + 3;
+ btnWidth2 = 3*titleHeight/2 + 6;
+
+ // titlebar
+ TQPainter p;
+ TQPainter maskPainter;
+ int i, x, y;
+ titlePix = new TQPixmap(33, 12);
+ TQBitmap mask(33, 12);
+ mask.fill(Qt::color0);
+
+ p.begin(titlePix);
+ maskPainter.begin(&mask);
+ maskPainter.setPen(Qt::color1);
+ for(i=0, y=2; i < 3; ++i, y+=4){
+ for(x=1; x <= 33; x+=3){
+ p.setPen(options()->color(KDecoration::ColorTitleBar, true).light(150));
+ p.drawPoint(x, y);
+ maskPainter.drawPoint(x, y);
+ p.setPen(options()->color(KDecoration::ColorTitleBar, true).dark(150));
+ p.drawPoint(x+1, y+1);
+ maskPainter.drawPoint(x+1, y+1);
+ }
+ }
+ p.end();
+ maskPainter.end();
+ titlePix->setMask(mask);
+
+ if(TQPixmap::defaultDepth() > 8){
+ aUpperGradient = new KPixmap;
+ aUpperGradient->resize(32, titleHeight+2);
+ iUpperGradient = new KPixmap;
+ iUpperGradient->resize(32, titleHeight+2);
+ TQColor bgColor = options()->color(KDecoration::ColorTitleBar, true);
+ KPixmapEffect::gradient(*aUpperGradient,
+ bgColor.light(120),
+ bgColor.dark(120),
+ KPixmapEffect::VerticalGradient);
+ bgColor = options()->color(KDecoration::ColorTitleBar, false);
+ KPixmapEffect::gradient(*iUpperGradient,
+ bgColor.light(120),
+ bgColor.dark(120),
+ KPixmapEffect::VerticalGradient);
+ }
+ // buttons (active/inactive, sunken/unsunken, 2 sizes each)
+ TQColorGroup g = options()->colorGroup(KDecoration::ColorButtonBg, true);
+ TQColor c = g.background();
+ btnPix1 = new KPixmap;
+ btnPix1->resize(btnWidth1, titleHeight);
+ btnDownPix1 = new KPixmap;
+ btnDownPix1->resize(btnWidth1, titleHeight);
+ btnPix2 = new KPixmap;
+ btnPix2->resize(btnWidth2, titleHeight);
+ btnDownPix2 = new KPixmap;
+ btnDownPix2->resize(btnWidth2, titleHeight);
+ iBtnPix1 = new KPixmap;
+ iBtnPix1->resize(btnWidth1, titleHeight);
+ iBtnDownPix1 = new KPixmap;
+ iBtnDownPix1->resize(btnWidth1, titleHeight);
+ iBtnPix2 = new KPixmap;
+ iBtnPix2->resize(btnWidth2, titleHeight);
+ iBtnDownPix2 = new KPixmap;
+ iBtnDownPix2->resize(btnWidth2, titleHeight);
+ if(TQPixmap::defaultDepth() > 8){
+ KPixmapEffect::gradient(*btnPix1, c.light(120), c.dark(130),
+ KPixmapEffect::DiagonalGradient);
+ KPixmapEffect::gradient(*btnDownPix1, c.dark(130), c.light(120),
+ KPixmapEffect::DiagonalGradient);
+ KPixmapEffect::gradient(*btnPix2, c.light(120), c.dark(130),
+ KPixmapEffect::DiagonalGradient);
+ KPixmapEffect::gradient(*btnDownPix2, c.dark(130), c.light(120),
+ KPixmapEffect::DiagonalGradient);
+ g = options()->colorGroup(KDecoration::ColorButtonBg, false);
+ c = g.background();
+ KPixmapEffect::gradient(*iBtnPix1, c.light(120), c.dark(130),
+ KPixmapEffect::DiagonalGradient);
+ KPixmapEffect::gradient(*iBtnDownPix1, c.dark(130), c.light(120),
+ KPixmapEffect::DiagonalGradient);
+ KPixmapEffect::gradient(*iBtnPix2, c.light(120), c.dark(130),
+ KPixmapEffect::DiagonalGradient);
+ KPixmapEffect::gradient(*iBtnDownPix2, c.dark(130), c.light(120),
+ KPixmapEffect::DiagonalGradient);
+ }
+ else{
+ btnPix1->fill(c.rgb());
+ btnDownPix1->fill(c.rgb());
+ btnPix2->fill(c.rgb());
+ btnDownPix2->fill(c.rgb());
+ g = options()->colorGroup(KDecoration::ColorButtonBg, false);
+ c = g.background();
+ iBtnPix1->fill(c.rgb());
+ iBtnDownPix1->fill(c.rgb());
+ iBtnPix2->fill(c.rgb());
+ iBtnDownPix2->fill(c.rgb());
+ }
+ g = options()->colorGroup(KDecoration::ColorButtonBg, true);
+ c = g.background();
+ drawButtonFrame(btnPix1, g, false);
+ drawButtonFrame(btnDownPix1, g, true);
+ drawButtonFrame(btnPix2, g, false);
+ drawButtonFrame(btnDownPix2, g, true);
+ g = options()->colorGroup(KDecoration::ColorButtonBg, false);
+ c = g.background();
+ drawButtonFrame(iBtnPix1, g, false);
+ drawButtonFrame(iBtnDownPix1, g, true);
+ drawButtonFrame(iBtnPix2, g, false);
+ drawButtonFrame(iBtnDownPix2, g, true);
+
+ if(tqGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 128)
+ btnForeground = Qt::black;
+ else
+ btnForeground = Qt::white;
+}
+
+static void delete_pixmaps()
+{
+ delete titlePix;
+ if(aUpperGradient){
+ delete aUpperGradient;
+ delete iUpperGradient;
+ delete btnPix1;
+ delete btnDownPix1;
+ delete iBtnPix1;
+ delete iBtnDownPix1;
+ delete btnPix2;
+ delete btnDownPix2;
+ delete iBtnPix2;
+ delete iBtnDownPix2;
+ }
+ pixmaps_created = false;
+}
+
+// =====================================
+
+LaptopButton::LaptopButton(ButtonType type, LaptopClient *parent, const char *name)
+ : KCommonDecorationButton(type, parent, name)
+{
+ setBackgroundMode(TQWidget::NoBackground);
+}
+
+void LaptopButton::reset(unsigned long changed)
+{
+ if (changed&DecorationReset || changed&ManualReset || changed&SizeChange || changed&StateChange) {
+ switch (type() ) {
+ case CloseButton:
+ setBitmap(close_bits);
+ break;
+ case HelpButton:
+ setBitmap(question_bits);
+ break;
+ case MinButton:
+ setBitmap(iconify_bits);
+ break;
+ case MaxButton:
+ if (isOn() ) {
+ setBitmap(isLeft() ? l_minmax_bits : r_minmax_bits);
+ } else {
+ setBitmap(maximize_bits);
+ }
+ break;
+ case OnAllDesktopsButton:
+ setBitmap( isOn() ? unsticky_bits : sticky_bits );
+ break;
+ default:
+ setBitmap(0);
+ break;
+ }
+
+ this->update();
+ }
+}
+
+void LaptopButton::setBitmap(const unsigned char *bitmap)
+{
+ if (bitmap)
+ deco = TQBitmap(8, 8, bitmap, true);
+ else {
+ deco = TQBitmap(8,8);
+ deco.fill(Qt::color0);
+ }
+ deco.setMask(deco);
+ repaint();
+}
+
+void LaptopButton::drawButton(TQPainter *p)
+{
+ bool smallBtn = width() == btnWidth1;
+ if(btnPix1){
+ if(decoration()->isActive()){
+ if(isDown())
+ p->drawPixmap(0, 0, smallBtn ? *btnDownPix1 : *btnDownPix2);
+ else
+ p->drawPixmap(0, 0, smallBtn ? *btnPix1 : *btnPix2);
+ }
+ else{
+ if(isDown())
+ p->drawPixmap(0, 0, smallBtn ? *iBtnDownPix1 : *iBtnDownPix2);
+ else
+ p->drawPixmap(0, 0, smallBtn ? *iBtnPix1 : *iBtnPix2);
+ }
+ }
+ else{
+ TQColorGroup g = options()->colorGroup(KDecoration::ColorButtonBg, decoration()->isActive());
+ int w = width();
+ int h = height();
+ p->fillRect(1, 1, w-2, h-2, isDown() ? g.mid() : g.button());
+ p->setPen(isDown() ? g.dark() : g.light());
+ p->drawLine(0, 0, w-1, 0);
+ p->drawLine(0, 0, 0, w-1);
+ p->setPen(isDown() ? g.light() : g.dark());
+ p->drawLine(w-1, 0, w-1, h-1);
+ p->drawLine(0, h-1, w-1, h-1);
+ }
+
+ p->setPen(btnForeground);
+ int xOff = (width()-8)/2;
+ int yOff = (height()-8)/2;
+ p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, deco);
+}
+
+// =====================================
+
+void LaptopClient::reset(unsigned long changed)
+{
+ KCommonDecoration::reset(changed);
+}
+
+LaptopClient::LaptopClient(KDecorationBridge *b, KDecorationFactory *f)
+ : KCommonDecoration(b, f)
+{
+}
+
+LaptopClient::~LaptopClient()
+{
+}
+
+TQString LaptopClient::visibleName() const
+{
+ return i18n("Laptop");
+}
+
+TQString LaptopClient::defaultButtonsLeft() const
+{
+ return "X";
+}
+
+TQString LaptopClient::defaultButtonsRight() const
+{
+ return "HSIA";
+}
+
+bool LaptopClient::decorationBehaviour(DecorationBehaviour behaviour) const
+{
+ switch (behaviour) {
+ case DB_MenuClose:
+ return false;
+
+ case DB_WindowMask:
+ return true;
+
+ case DB_ButtonHide:
+ return true;
+
+ default:
+ return KCommonDecoration::decorationBehaviour(behaviour);
+ }
+}
+
+int LaptopClient::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const
+{
+ switch (lm) {
+ case LM_TitleEdgeLeft:
+ case LM_TitleEdgeRight:
+ case LM_BorderLeft:
+ case LM_BorderRight:
+ return 4;
+
+ case LM_BorderBottom:
+ return mustDrawHandle() ? handleSize : 4;
+
+ case LM_TitleEdgeTop:
+ return 3;
+
+ case LM_TitleEdgeBottom:
+ return 1;
+
+ case LM_TitleBorderLeft:
+ case LM_TitleBorderRight:
+ return 0;
+
+ case LM_ButtonWidth:
+ {
+ if (btn && (btn->type()==HelpButton||btn->type()==OnAllDesktopsButton) ) {
+ return btnWidth1;
+ } else {
+ return btnWidth2;
+ }
+ }
+
+ case LM_ButtonHeight:
+ case LM_TitleHeight:
+ if (isToolWindow() )
+ return titleHeight-2;
+ else
+ return titleHeight;
+
+ case LM_ButtonSpacing:
+ return 0;
+
+ case LM_ExplicitButtonSpacer:
+ return 0;
+
+ default:
+ return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
+ }
+}
+
+KCommonDecorationButton *LaptopClient::createButton(ButtonType type)
+{
+ switch (type) {
+ case OnAllDesktopsButton:
+ return new LaptopButton(OnAllDesktopsButton, this, "on_all_desktops");
+
+ case HelpButton:
+ return new LaptopButton(HelpButton, this, "help");
+
+ case MinButton:
+ return new LaptopButton(MinButton, this, "minimize");
+
+ case MaxButton:
+ return new LaptopButton(MaxButton, this, "maximize");
+
+ case CloseButton:
+ return new LaptopButton(CloseButton, this, "close");
+
+ default:
+ return 0;
+ }
+}
+
+void LaptopClient::init()
+{
+ bufferDirty = true;
+
+ KCommonDecoration::init();
+}
+
+void LaptopClient::captionChange()
+{
+ bufferDirty = true;
+
+ KCommonDecoration::captionChange();
+}
+
+void LaptopClient::paintEvent( TQPaintEvent* )
+{
+ TQPainter p(widget());
+ TQColorGroup g = options()->colorGroup(KDecoration::ColorFrame, isActive());
+
+ TQRect r(widget()->rect());
+ p.setPen(Qt::black);
+ p.drawRect(r);
+
+ // fill mid frame...
+ p.setPen(g.background() );
+ p.drawLine(r.x()+2, r.y()+2, r.right()-2, r.y()+2);
+ p.drawLine(r.left()+2, r.y()+3, r.left()+2, r.bottom()-layoutMetric(LM_BorderBottom)+1 );
+ p.drawLine(r.right()-2, r.y()+3, r.right()-2, r.bottom()-layoutMetric(LM_BorderBottom)+1 );
+ p.drawLine(r.left()+3, r.y()+3, r.left()+3, r.y()+layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeTop) );
+ p.drawLine(r.right()-3, r.y()+3, r.right()-3, r.y()+layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeTop) );
+ if (!mustDrawHandle() )
+ p.drawLine(r.left()+1, r.bottom()-2, r.right()-1, r.bottom()-2);
+
+ // outer frame
+ p.setPen(g.light());
+ p.drawLine(r.x()+1, r.y()+1, r.right()-1, r.y()+1);
+ p.drawLine(r.x()+1, r.y()+1, r.x()+1, r.bottom()-1);
+ p.setPen(g.dark());
+ p.drawLine(r.right()-1, r.y()+1, r.right()-1, r.bottom()-1);
+ p.drawLine(r.x()+1, r.bottom()-1, r.right()-1, r.bottom()-1);
+
+ int th = titleHeight;
+ int bb = handleSize + 2; // Bottom border
+ int bs = handleSize - 2; // inner size of bottom border
+ if (!mustDrawHandle()) {
+ bb = 6;
+ bs = 0;
+ }
+ if ( isToolWindow() )
+ th -= 2;
+
+ // inner rect
+ p.drawRect(r.x() + 3, r.y() + th + 3, r.width() - 6, r.height() - th - bb);
+
+ // handles
+ if (mustDrawHandle()) {
+ if (r.width() > 3*handleSize + 20) {
+ int range = 8 + 3*handleSize/2;
+ qDrawShadePanel(&p, r.x() + 1, r.bottom() - bs, range,
+ handleSize - 2, g, false, 1, &g.brush(TQColorGroup::Mid));
+ qDrawShadePanel(&p, r.x() + range + 1, r.bottom() - bs,
+ r.width() - 2*range - 2, handleSize - 2, g, false, 1,
+ isActive() ? &g.brush(TQColorGroup::Background) :
+ &g.brush(TQColorGroup::Mid));
+ qDrawShadePanel(&p, r.right() - range, r.bottom() - bs,
+ range, bs, g, false, 1, &g.brush(TQColorGroup::Mid));
+ } else {
+ qDrawShadePanel(&p, r.x() + 1, r.bottom() - bs,
+ r.width() - 2, bs, g, false, 1,
+ isActive() ? &g.brush(TQColorGroup::Background) :
+ &g.brush(TQColorGroup::Mid));
+ }
+ }
+
+ r = titleRect();
+
+ if(isActive()){
+ updateActiveBuffer();
+ p.drawPixmap(r.x(), r.y(), activeBuffer);
+ p.setPen(g.background());
+ p.drawPoint(r.x(), r.y());
+ p.drawPoint(r.right(), r.y());
+ p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
+ }
+ else{
+ if(iUpperGradient)
+ p.drawTiledPixmap(r.x(), r.y(), r.width(), r.height()-1,
+ *iUpperGradient);
+ else
+ p.fillRect(r.x(), r.y(), r.width(), r.height()-1,
+ options()->color(KDecoration::ColorTitleBar, false));
+
+ p.setFont(options()->font(false, isToolWindow() ));
+ TQFontMetrics fm(options()->font(false));
+ g = options()->colorGroup(KDecoration::ColorTitleBar, false);
+ if(iUpperGradient)
+ p.drawTiledPixmap(r.x()+((r.width()-fm.width(caption()))/2)-4,
+ r.y(), fm.width(caption())+8, r.height()-1,
+ *iUpperGradient);
+ else
+ p.fillRect(r.x()+((r.width()-fm.width(caption()))/2)-4, r.y(),
+ fm.width(caption())+8, r.height()-1,
+ g.brush(TQColorGroup::Background));
+ p.setPen(g.mid());
+ p.drawLine(r.x(), r.y(), r.right(), r.y());
+ p.drawLine(r.x(), r.y(), r.x(), r.bottom());
+ p.setPen(g.button());
+ p.drawLine(r.right(), r.y(), r.right(), r.bottom());
+ p.drawLine(r.x(), r.bottom(), r.right(), r.bottom());
+ p.setPen(options()->color(KDecoration::ColorFont, false));
+ p.drawText(r.x(), r.y(), r.width(), r.height()-1,
+ AlignCenter, caption() );
+ g = options()->colorGroup(KDecoration::ColorFrame, true);
+ p.setPen(g.background());
+ p.drawPoint(r.x(), r.y());
+ p.drawPoint(r.right(), r.y());
+ p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
+ }
+}
+
+TQRegion LaptopClient::cornerShape(WindowCorner corner)
+{
+ switch (corner) {
+ case WC_TopLeft:
+ return TQRect(0, 0, 1, 1);
+
+ case WC_TopRight:
+ return TQRect(width()-1, 0, 1, 1);
+
+ case WC_BottomLeft:
+ return TQRect(0, height()-1, 1, 1);
+
+ case WC_BottomRight:
+ return TQRect(width()-1, height()-1, 1, 1);
+
+ default:
+ return TQRegion();
+ }
+
+}
+
+bool LaptopClient::mustDrawHandle() const
+{
+ bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
+ if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
+ return false;
+ } else {
+ return isResizable();
+ }
+}
+
+void LaptopClient::updateActiveBuffer( )
+{
+ TQRect rTitle = titleRect();
+ if( !bufferDirty && (lastBufferWidth == rTitle.width()))
+ return;
+ if ( rTitle.width() <= 0 || rTitle.height() <= 0 )
+ return;
+ lastBufferWidth = rTitle.width();
+ bufferDirty = false;
+
+ activeBuffer.resize(rTitle.width(),
+ rTitle.height());
+ TQPainter p;
+ TQRect r(0, 0, activeBuffer.width(), activeBuffer.height());
+ p.begin(&activeBuffer);
+ if(aUpperGradient){
+ p.drawTiledPixmap(r, *aUpperGradient);
+ }
+ else{
+ p.fillRect(r, options()->color(KDecoration::ColorTitleBar, true));
+ }
+ if(titlePix)
+ p.drawTiledPixmap(r, *titlePix);
+
+ p.setFont(options()->font(true, isToolWindow() ));
+ TQFontMetrics fm(options()->font(true));
+ TQColorGroup g = options()->colorGroup(KDecoration::ColorTitleBar, true);
+ if(aUpperGradient)
+ p.drawTiledPixmap(r.x()+((r.width()-fm.width(caption()))/2)-4,
+ r.y(), fm.width(caption())+8, r.height()-1,
+ *aUpperGradient);
+ else
+ p.fillRect(r.x()+((r.width()-fm.width(caption()))/2)-4, 0,
+ fm.width(caption())+8, r.height(),
+ g.brush(TQColorGroup::Background));
+ p.setPen(g.mid());
+ p.drawLine(r.x(), r.y(), r.right(), r.y());
+ p.drawLine(r.x(), r.y(), r.x(), r.bottom());
+ p.setPen(g.button());
+ p.drawLine(r.right(), r.y(), r.right(), r.bottom());
+ p.drawLine(r.x(), r.bottom(), r.right(), r.bottom());
+ p.setPen(options()->color(KDecoration::ColorFont, true));
+ p.drawText(r.x(), r.y(), r.width(), r.height()-1,
+ AlignCenter, caption() );
+ g = options()->colorGroup(KDecoration::ColorFrame, true);
+ p.setPen(g.background());
+ p.drawPoint(r.x(), r.y());
+ p.drawPoint(r.right(), r.y());
+ p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
+ p.end();
+}
+
+static const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask |
+ NET::DesktopMask | NET::DockMask | NET::ToolbarMask | NET::MenuMask |
+ NET::DialogMask | /*NET::OverrideMask |*/ NET::TopMenuMask |
+ NET::UtilityMask | NET::SplashMask;
+
+bool LaptopClient::isTransient() const
+{
+ NET::WindowType type = windowType(SUPPORTED_WINDOW_TYPES_MASK);
+ return type == NET::Dialog;
+}
+
+// =====================================
+
+LaptopClientFactory::LaptopClientFactory()
+{
+ create_pixmaps();
+}
+
+LaptopClientFactory::~LaptopClientFactory()
+{
+ delete_pixmaps();
+}
+
+KDecoration *LaptopClientFactory::createDecoration(KDecorationBridge *b)
+{
+ findPreferredHandleSize();
+ return new Laptop::LaptopClient(b, this);
+}
+
+bool LaptopClientFactory::reset(unsigned long changed)
+{
+ findPreferredHandleSize();
+
+ // TODO Do not recreate decorations if it is not needed. Look at
+ // ModernSystem for how to do that
+ Laptop::delete_pixmaps();
+ Laptop::create_pixmaps();
+
+ bool needHardReset = true;
+ if (changed & SettingButtons) {
+ // handled by KCommonDecoration
+ needHardReset = false;
+ }
+
+ if (needHardReset) {
+ return true;
+ } else {
+ resetDecorations(changed);
+ return false;
+ }
+}
+
+bool LaptopClientFactory::supports( Ability ability )
+{
+ switch( ability )
+ {
+ case AbilityAnnounceButtons:
+ case AbilityButtonOnAllDesktops:
+ case AbilityButtonHelp:
+ case AbilityButtonMinimize:
+ case AbilityButtonMaximize:
+ case AbilityButtonClose:
+ return true;
+ default:
+ return false;
+ };
+}
+
+TQValueList< LaptopClientFactory::BorderSize >
+LaptopClientFactory::borderSizes() const
+{
+ // the list must be sorted
+ return TQValueList< BorderSize >() << BorderNormal << BorderLarge <<
+ BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
+}
+
+void LaptopClientFactory::findPreferredHandleSize()
+{
+ switch (options()->preferredBorderSize(this)) {
+ case KDecoration::BorderLarge:
+ handleSize = 11;
+ break;
+ case KDecoration::BorderVeryLarge:
+ handleSize = 16;
+ break;
+ case KDecoration::BorderHuge:
+ handleSize = 24;
+ break;
+ case KDecoration::BorderVeryHuge:
+ handleSize = 32;
+ break;
+ case KDecoration::BorderOversized:
+ handleSize = 40;
+ break;
+ case KDecoration::BorderTiny:
+ case KDecoration::BorderNormal:
+ default:
+ handleSize = 8;
+ }
+}
+
+} // Laptop namespace
+
+// vim: sw=4
diff --git a/twin/clients/laptop/laptopclient.h b/twin/clients/laptop/laptopclient.h
new file mode 100644
index 00000000..de6e742f
--- /dev/null
+++ b/twin/clients/laptop/laptopclient.h
@@ -0,0 +1,76 @@
+/*
+ * Laptop KWin Client
+ *
+ * Copyright (c) 2005 Sandro Giessl <sandro@giessl.com>
+ * Ported to the trinity.2 API by Luciano Montanaro <mikelima@cirulla.net>
+ */
+#ifndef __KDECLIENT_H
+#define __KDECLIENT_H
+
+#include <tqbitmap.h>
+#include <kpixmap.h>
+#include <kcommondecoration.h>
+#include <kdecorationfactory.h>
+
+namespace Laptop {
+
+class LaptopClient;
+
+class LaptopButton : public KCommonDecorationButton
+{
+public:
+ LaptopButton(ButtonType type, LaptopClient *parent, const char *name);
+ void setBitmap(const unsigned char *bitmap);
+ virtual void reset(unsigned long changed);
+
+protected:
+ virtual void drawButton(TQPainter *p);
+ TQBitmap deco;
+};
+
+class LaptopClient : public KCommonDecoration
+{
+public:
+ LaptopClient( KDecorationBridge* b, KDecorationFactory* f );
+ ~LaptopClient();
+
+ virtual TQString visibleName() const;
+ virtual TQString defaultButtonsLeft() const;
+ virtual TQString defaultButtonsRight() const;
+ virtual bool decorationBehaviour(DecorationBehaviour behaviour) const;
+ virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
+ virtual KCommonDecorationButton *createButton(ButtonType type);
+
+ virtual TQRegion cornerShape(WindowCorner corner);
+
+ void init();
+protected:
+ void paintEvent( TQPaintEvent* );
+ void reset( unsigned long );
+ void updateActiveBuffer();
+ void captionChange();
+private:
+ bool mustDrawHandle() const;
+ bool isTransient() const;
+private:
+ KPixmap activeBuffer;
+ int lastBufferWidth;
+ bool bufferDirty;
+};
+
+class LaptopClientFactory : public TQObject, public KDecorationFactory
+{
+public:
+ LaptopClientFactory();
+ virtual ~LaptopClientFactory();
+ virtual KDecoration* createDecoration( KDecorationBridge* );
+ virtual bool reset( unsigned long changed );
+ virtual bool supports( Ability ability );
+ virtual TQValueList< BorderSize > borderSizes() const;
+private:
+ void findPreferredHandleSize();
+};
+
+}
+
+#endif
diff --git a/twin/clients/modernsystem/CMakeLists.txt b/twin/clients/modernsystem/CMakeLists.txt
new file mode 100644
index 00000000..62c2d766
--- /dev/null
+++ b/twin/clients/modernsystem/CMakeLists.txt
@@ -0,0 +1,36 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( config )
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/twin/lib
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES modernsystem.desktop DESTINATION ${DATA_INSTALL_DIR}/twin )
+
+
+##### twin3_modernsys (module) ##################
+
+tde_add_kpart( twin3_modernsys
+ SOURCES modernsys.cpp
+ LINK tdecorations-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/twin/clients/modernsystem/Makefile.am b/twin/clients/modernsystem/Makefile.am
new file mode 100644
index 00000000..e4c21d7a
--- /dev/null
+++ b/twin/clients/modernsystem/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../lib $(all_includes)
+
+SUBDIRS = config
+
+kde_module_LTLIBRARIES = twin3_modernsys.la
+
+twin3_modernsys_la_SOURCES = modernsys.cpp
+twin3_modernsys_la_LIBADD = ../../lib/libtdecorations.la
+twin3_modernsys_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+
+METASOURCES = AUTO
+noinst_HEADERS = modernsys.h
+
+lnkdir = $(kde_datadir)/twin/
+lnk_DATA = modernsystem.desktop
+
+EXTRA_DIST = $(lnk_DATA)
+
diff --git a/twin/clients/modernsystem/btnhighcolor.h b/twin/clients/modernsystem/btnhighcolor.h
new file mode 100644
index 00000000..fa323b9e
--- /dev/null
+++ b/twin/clients/modernsystem/btnhighcolor.h
@@ -0,0 +1,93 @@
+/* XPM */
+static const char * btnhighcolor_xpm[] = {
+"14 15 75 1",
+" c None",
+". c #6E6E6E",
+"+ c #757575",
+"@ c #878787",
+"# c #7D7D7D",
+"$ c #9E9E9E",
+"% c #B9B9B9",
+"& c #C6C6C6",
+"* c #BABABA",
+"= c #A5A5A5",
+"- c #7F7F7F",
+"; c #848484",
+"> c #A7A7A7",
+", c #BFBFBF",
+"' c #D1D1D1",
+") c #D7D7D7",
+"! c #DADADA",
+"~ c #CBCBCB",
+"{ c #ABABAB",
+"] c #B3B3B3",
+"^ c #C2C2C2",
+"/ c #CACACA",
+"( c #C9C9C9",
+"_ c #B6B6B6",
+": c #9A9A9A",
+"< c #999999",
+"[ c #B0B0B0",
+"} c #C4C4C4",
+"| c #C3C3C3",
+"1 c #C0C0C0",
+"2 c #AEAEAE",
+"3 c #969696",
+"4 c #C1C1C1",
+"5 c #CCCCCC",
+"6 c #C5C5C5",
+"7 c #BEBEBE",
+"8 c #AAAAAA",
+"9 c #CECECE",
+"0 c #D4D4D4",
+"a c #DBDBDB",
+"b c #DEDEDE",
+"c c #D5D5D5",
+"d c #D3D3D3",
+"e c #BCBCBC",
+"f c #CDCDCD",
+"g c #E0E0E0",
+"h c #E4E4E4",
+"i c #E8E8E8",
+"j c #EBEBEB",
+"k c #E9E9E9",
+"l c #E6E6E6",
+"m c #DDDDDD",
+"n c #E1E1E1",
+"o c #EDEDED",
+"p c #F1F1F1",
+"q c #F5F5F5",
+"r c #F8F8F8",
+"s c #F6F6F6",
+"t c #F3F3F3",
+"u c #EEEEEE",
+"v c #E5E5E5",
+"w c #DCDCDC",
+"x c #B7B7B7",
+"y c #E2E2E2",
+"z c #FDFDFD",
+"A c #FFFFFF",
+"B c #FCFCFC",
+"C c #F7F7F7",
+"D c #B5B5B5",
+"E c #F2F2F2",
+"F c #FAFAFA",
+"G c #9B9B9B",
+"H c #FBFBFB",
+"I c #A9A9A9",
+"J c #747474",
+" .... ",
+" ..+@@+.. ",
+" .#$%&&*=-. ",
+" .;>,')!)~{#. ",
+" .$]^///(&_:. ",
+".<[*^}||11*23.",
+".[4&5555~(678.",
+".,90!aba)cd~e.",
+".faghijklhm06.",
+".'nopqrstuvw/.",
+".xyprzAzBCunD.",
+" .'EzAAAAFpf. ",
+" .GcHAAAAF0<. ",
+" ..I5kk5I.. ",
+" J..... "};
diff --git a/twin/clients/modernsystem/buttondata.h b/twin/clients/modernsystem/buttondata.h
new file mode 100644
index 00000000..1af5fb8d
--- /dev/null
+++ b/twin/clients/modernsystem/buttondata.h
@@ -0,0 +1,42 @@
+/* Image bits processed by KPixmap2Bitmaps */
+
+#define lowcolor_mask_width 14
+#define lowcolor_mask_height 15
+static const unsigned char lowcolor_mask_bits[] = {
+ 0xf0,0x03,0xf8,0x07,0xfc,0xcf,0xfe,0x1f,0xfe,0x1f,0xff,0xff,0xff,0xff,0xff,
+ 0x3f,0xff,0x3f,0xff,0xbf,0xfe,0xdf,0xfe,0x9f,0xfc,0x0f,0xf8,0x07,0xf0,0x03,
+ 0x00,0x40,0x80,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x7c,0xfe,0x87,0x40,0x00,
+ 0x00,0x64,0x00,0x20,0x00,0x64,0x00,0x86,0xfe,0x87,0x40,0x00,0x00,0x65,0x00 };
+
+#define lowcolor_6a696a_width 14
+#define lowcolor_6a696a_height 15
+static const unsigned char lowcolor_6a696a_bits[] = {
+ 0xf0,0x03,0x18,0x06,0x04,0xcc,0x06,0x18,0x02,0x10,0x00,0xc0,0x00,0xc0,0x00,
+ 0x00,0x00,0x00,0x00,0xc0,0x00,0xc0,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x40,0x80,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x80,0x24,0x0e,0x08,0x61,0x00,0x00,0x00,0xf0,0xd9,0x0c,0x08 };
+
+#define lowcolor_949194_width 14
+#define lowcolor_949194_height 15
+static const unsigned char lowcolor_949194_bits[] = {
+ 0x00,0x40,0xe0,0x01,0x08,0x02,0x00,0x04,0x04,0x08,0x07,0x78,0x03,0xf0,0x01,
+ 0xe0,0x01,0x60,0x01,0x20,0x00,0xc0,0x02,0x90,0x04,0x08,0x08,0x04,0xf0,0x03,
+ 0x00,0x40,0x80,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0xc8,0x51,0x0c,0x08,0x0e,
+ 0x01,0x00,0x00,0x37,0x00,0x00,0x00,0x58,0x5f,0x49,0x6d,0x61,0x67,0x65,0x54 };
+
+#define lowcolor_b4b6b4_width 14
+#define lowcolor_b4b6b4_height 15
+static const unsigned char lowcolor_b4b6b4_bits[] = {
+ 0x00,0x40,0x00,0x00,0x10,0x00,0x08,0x02,0x18,0x06,0xb8,0x47,0x0c,0xce,0x0e,
+ 0xd8,0x06,0x58,0x02,0x10,0x02,0xd0,0x00,0x80,0x00,0x00,0x10,0x02,0x00,0x00,
+ 0x00,0x40,0x80,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,
+ 0x00,0x08,0x00,0x02,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x38,0x5b,0x0c,0x08 };
+
+#define lowcolor_e6e6e6_width 14
+#define lowcolor_e6e6e6_height 15
+static const unsigned char lowcolor_e6e6e6_bits[] = {
+ 0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x01,0x00,0x00,0x00,0x40,0x00,0xc0,0x00,
+ 0xc0,0x00,0x40,0xe0,0xc0,0xe0,0xc1,0xe0,0x81,0xf0,0x03,0xc0,0x00,0x00,0x00,
+ 0x00,0x40,0x80,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x08,0x19,0x0d,0x08,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00 };
+
diff --git a/twin/clients/modernsystem/config/CMakeLists.txt b/twin/clients/modernsystem/config/CMakeLists.txt
new file mode 100644
index 00000000..8a6d6db4
--- /dev/null
+++ b/twin/clients/modernsystem/config/CMakeLists.txt
@@ -0,0 +1,30 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### twin_modernsys_config (module) ############
+
+tde_add_kpart( twin_modernsys_config AUTOMOC
+ SOURCES config.cpp
+ LINK tdeui-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
diff --git a/twin/clients/modernsystem/config/Makefile.am b/twin/clients/modernsystem/config/Makefile.am
new file mode 100644
index 00000000..aaae38b2
--- /dev/null
+++ b/twin/clients/modernsystem/config/Makefile.am
@@ -0,0 +1,14 @@
+
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = twin_modernsys_config.la
+
+twin_modernsys_config_la_SOURCES = config.cpp
+twin_modernsys_config_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+twin_modernsys_config_la_LIBADD = $(LIB_TDEUI)
+
+METASOURCES = AUTO
+noinst_HEADERS = config.h
+
+lnkdir = $(kde_datadir)/twin/
+
diff --git a/twin/clients/modernsystem/config/config.cpp b/twin/clients/modernsystem/config/config.cpp
new file mode 100644
index 00000000..18d6870f
--- /dev/null
+++ b/twin/clients/modernsystem/config/config.cpp
@@ -0,0 +1,130 @@
+// Melchior FRANZ <mfranz@kde.org> -- 2001-04-22
+
+#include <tdeapplication.h>
+#include <tdeconfig.h>
+#include <kdialog.h>
+#include <tdelocale.h>
+#include <tdeglobal.h>
+#include <tqlayout.h>
+#include <tqwhatsthis.h>
+#include "config.h"
+
+
+extern "C"
+{
+ KDE_EXPORT TQObject* allocate_config(TDEConfig* conf, TQWidget* parent)
+ {
+ return(new ModernSysConfig(conf, parent));
+ }
+}
+
+
+// 'conf' is a pointer to the twindecoration modules open twin config,
+// and is by default set to the "Style" group.
+//
+// 'parent' is the parent of the TQObject, which is a VBox inside the
+// Configure tab in twindecoration
+
+ModernSysConfig::ModernSysConfig(TDEConfig* conf, TQWidget* parent) : TQObject(parent)
+{
+ clientrc = new TDEConfig("twinmodernsysrc");
+ TDEGlobal::locale()->insertCatalogue("twin_clients");
+ mainw = new TQWidget(parent);
+ vbox = new TQVBoxLayout(mainw);
+ vbox->setSpacing(6);
+ vbox->setMargin(0);
+
+ handleBox = new TQWidget(mainw);
+ TQGridLayout* layout = new TQGridLayout(handleBox, 0, KDialog::spacingHint());
+
+ cbShowHandle = new TQCheckBox(i18n("&Show window resize handle"), handleBox);
+ TQWhatsThis::add(cbShowHandle,
+ i18n("When selected, all windows are drawn with a resize "
+ "handle at the lower right corner. This makes window resizing "
+ "easier, especially for trackballs and other mouse replacements "
+ "on laptops."));
+ layout->addMultiCellWidget(cbShowHandle, 0, 0, 0, 1);
+ connect(cbShowHandle, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotSelectionChanged()));
+
+ sliderBox = new TQVBox(handleBox);
+ handleSizeSlider = new TQSlider(0, 4, 1, 0, Qt::Horizontal, sliderBox);
+ TQWhatsThis::add(handleSizeSlider,
+ i18n("Here you can change the size of the resize handle."));
+ handleSizeSlider->setTickInterval(1);
+ handleSizeSlider->setTickmarks(TQSlider::Below);
+ connect(handleSizeSlider, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSelectionChanged()));
+
+ hbox = new TQHBox(sliderBox);
+ hbox->setSpacing(6);
+
+ bool rtl = kapp->reverseLayout();
+ label1 = new TQLabel(i18n("Small"), hbox);
+ label1->setAlignment(rtl ? AlignRight : AlignLeft);
+ label2 = new TQLabel(i18n("Medium"), hbox);
+ label2->setAlignment(AlignHCenter);
+ label3 = new TQLabel(i18n("Large"), hbox);
+ label3->setAlignment(rtl ? AlignLeft : AlignRight);
+
+ vbox->addWidget(handleBox);
+ vbox->addStretch(1);
+
+// layout->setColSpacing(0, 30);
+ layout->addItem(new TQSpacerItem(30, 10, TQSizePolicy::Fixed, TQSizePolicy::Fixed), 1, 0);
+ layout->addWidget(sliderBox, 1, 1);
+
+ load(conf);
+ mainw->show();
+}
+
+
+ModernSysConfig::~ModernSysConfig()
+{
+ delete mainw;
+ delete clientrc;
+}
+
+
+void ModernSysConfig::slotSelectionChanged()
+{
+ bool i = cbShowHandle->isChecked();
+ if (i != hbox->isEnabled()) {
+ hbox->setEnabled(i);
+ handleSizeSlider->setEnabled(i);
+ }
+ emit changed();
+}
+
+
+void ModernSysConfig::load(TDEConfig* /*conf*/)
+{
+ clientrc->setGroup("General");
+ bool i = clientrc->readBoolEntry("ShowHandle", true );
+ cbShowHandle->setChecked(i);
+ hbox->setEnabled(i);
+ handleSizeSlider->setEnabled(i);
+ handleWidth = clientrc->readUnsignedNumEntry("HandleWidth", 6);
+ handleSize = clientrc->readUnsignedNumEntry("HandleSize", 30);
+ handleSizeSlider->setValue(TQMIN((handleWidth - 6) / 2, 4));
+
+}
+
+
+void ModernSysConfig::save(TDEConfig* /*conf*/)
+{
+ clientrc->setGroup("General");
+ clientrc->writeEntry("ShowHandle", cbShowHandle->isChecked());
+ clientrc->writeEntry("HandleWidth", 6 + 2 * handleSizeSlider->value());
+ clientrc->writeEntry("HandleSize", 30 + 4 * handleSizeSlider->value());
+ clientrc->sync();
+}
+
+
+void ModernSysConfig::defaults()
+{
+ cbShowHandle->setChecked(true);
+ hbox->setEnabled(true);
+ handleSizeSlider->setEnabled(true);
+ handleSizeSlider->setValue(0);
+}
+
+#include "config.moc"
diff --git a/twin/clients/modernsystem/config/config.h b/twin/clients/modernsystem/config/config.h
new file mode 100644
index 00000000..20ce5539
--- /dev/null
+++ b/twin/clients/modernsystem/config/config.h
@@ -0,0 +1,50 @@
+#ifndef __KDE_MODSYSTEMCONFIG_H
+#define __KDE_MODSYSTEMCONFIG_H
+
+#include <tqcheckbox.h>
+#include <tqgroupbox.h>
+#include <tqlayout.h>
+#include <tqvbox.h>
+#include <tqslider.h>
+#include <tqlabel.h>
+
+class ModernSysConfig : public TQObject
+{
+ Q_OBJECT
+
+ public:
+ ModernSysConfig(TDEConfig* conf, TQWidget* parent);
+ ~ModernSysConfig();
+
+ // These public signals/slots work similar to KCM modules
+ signals:
+ void changed();
+
+ public slots:
+ void load(TDEConfig* conf);
+ void save(TDEConfig* conf);
+ void defaults();
+
+ protected slots:
+ void slotSelectionChanged(); // Internal use
+
+ private:
+ TDEConfig *clientrc;
+ TQWidget *mainw;
+ TQVBoxLayout *vbox;
+ TQWidget *handleBox;
+ TQCheckBox *cbShowHandle;
+ TQVBox *sliderBox;
+ TQSlider *handleSizeSlider;
+ TQHBox *hbox;
+ TQLabel *label1;
+ TQLabel *label2;
+ TQLabel *label3;
+
+ unsigned handleWidth;
+ unsigned handleSize;
+
+};
+
+
+#endif
diff --git a/twin/clients/modernsystem/modernsys.cpp b/twin/clients/modernsystem/modernsys.cpp
new file mode 100644
index 00000000..68c8716c
--- /dev/null
+++ b/twin/clients/modernsystem/modernsys.cpp
@@ -0,0 +1,739 @@
+// Daniel M. DULEY <mosfet@kde.org> original work
+// Melchior FRANZ <a8603365@unet.univie.ac.at> configuration options
+
+#include <tdeconfig.h>
+#include <tdeglobal.h>
+#include <tdelocale.h>
+#include <tqlayout.h>
+#include <tqdrawutil.h>
+#include <kpixmapeffect.h>
+#include <kdrawutil.h>
+#include <tqbitmap.h>
+#include <tqtooltip.h>
+#include <tqapplication.h>
+#include <tqlabel.h>
+#include "modernsys.h"
+
+#include "buttondata.h"
+#include "btnhighcolor.h"
+#include <tqimage.h>
+
+namespace ModernSystem {
+
+static unsigned char iconify_bits[] = {
+ 0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00};
+
+static unsigned char close_bits[] = {
+ 0x00, 0x66, 0x7e, 0x3c, 0x3c, 0x7e, 0x66, 0x00};
+
+static unsigned char maximize_bits[] = {
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00};
+
+static unsigned char r_minmax_bits[] = {
+ 0x0c, 0x18, 0x33, 0x67, 0xcf, 0x9f, 0x3f, 0x3f};
+
+static unsigned char l_minmax_bits[] = {
+ 0x30, 0x18, 0xcc, 0xe6, 0xf3, 0xf9, 0xfc, 0xfc};
+
+static unsigned char unsticky_bits[] = {
+ 0x3c, 0x42, 0x99, 0xbd, 0xbd, 0x99, 0x42, 0x3c};
+
+static unsigned char sticky_bits[] = {
+ 0x3c, 0x42, 0x81, 0x81, 0x