summaryrefslogtreecommitdiffstats
path: root/kdecore
diff options
context:
space:
mode:
Diffstat (limited to 'kdecore')
-rw-r--r--kdecore/40.colors48
-rw-r--r--kdecore/AUTHORS56
-rw-r--r--kdecore/DESIGN.COLOR141
-rw-r--r--kdecore/DESIGN.iconloading187
-rw-r--r--kdecore/DESIGN.kconfig224
-rw-r--r--kdecore/KCONFIG_DESIGN51
-rw-r--r--kdecore/MAINTAINERS116
-rw-r--r--kdecore/Mainpage.dox44
-rw-r--r--kdecore/Makefile.am189
-rw-r--r--kdecore/README3
-rw-r--r--kdecore/README.exec41
-rw-r--r--kdecore/README.kiosk681
-rw-r--r--kdecore/README.kstartupinfo282
-rw-r--r--kdecore/README.user_profiles136
-rw-r--r--kdecore/Rainbow.colors118
-rw-r--r--kdecore/Royal.colors258
-rw-r--r--kdecore/Web.colors218
-rw-r--r--kdecore/all_languages.desktop11919
-rw-r--r--kdecore/configure.in.in234
-rw-r--r--kdecore/eventsrc2741
-rw-r--r--kdecore/fakes.c363
-rw-r--r--kdecore/fixx11h.h233
-rwxr-xr-xkdecore/generate_keys.sh63
-rw-r--r--kdecore/kaboutdata.cpp512
-rw-r--r--kdecore/kaboutdata.h629
-rw-r--r--kdecore/kaccel.cpp660
-rw-r--r--kdecore/kaccel.h390
-rw-r--r--kdecore/kaccelaction.cpp565
-rw-r--r--kdecore/kaccelaction.h576
-rw-r--r--kdecore/kaccelbase.cpp616
-rw-r--r--kdecore/kaccelbase.h282
-rw-r--r--kdecore/kaccelmanager.cpp871
-rw-r--r--kdecore/kaccelmanager.h88
-rw-r--r--kdecore/kaccelmanager_private.h196
-rw-r--r--kdecore/kaccelprivate.h53
-rw-r--r--kdecore/kallocator.cpp260
-rw-r--r--kdecore/kallocator.h140
-rw-r--r--kdecore/kapp.h6
-rw-r--r--kdecore/kappdcopiface.cpp66
-rw-r--r--kdecore/kappdcopiface.h74
-rw-r--r--kdecore/kapplication.cpp3272
-rw-r--r--kdecore/kapplication.h1476
-rw-r--r--kdecore/kapplication_win.cpp117
-rw-r--r--kdecore/kasyncio.cpp27
-rw-r--r--kdecore/kasyncio.h85
-rw-r--r--kdecore/kaudioplayer.cpp56
-rw-r--r--kdecore/kaudioplayer.h93
-rw-r--r--kdecore/kbufferedio.cpp299
-rw-r--r--kdecore/kbufferedio.h289
-rw-r--r--kdecore/kcalendarsystem.cpp146
-rw-r--r--kdecore/kcalendarsystem.h357
-rw-r--r--kdecore/kcalendarsystemfactory.cpp70
-rw-r--r--kdecore/kcalendarsystemfactory.h65
-rw-r--r--kdecore/kcalendarsystemgregorian.cpp329
-rw-r--r--kdecore/kcalendarsystemgregorian.h92
-rw-r--r--kdecore/kcalendarsystemhebrew.cpp746
-rw-r--r--kdecore/kcalendarsystemhebrew.h105
-rw-r--r--kdecore/kcalendarsystemhijri.cpp596
-rw-r--r--kdecore/kcalendarsystemhijri.h98
-rw-r--r--kdecore/kcalendarsystemjalali.cpp560
-rw-r--r--kdecore/kcalendarsystemjalali.h83
-rw-r--r--kdecore/kcatalogue.cpp157
-rw-r--r--kdecore/kcatalogue.h129
-rw-r--r--kdecore/kcharsets.cpp664
-rw-r--r--kdecore/kcharsets.h142
-rw-r--r--kdecore/kcheckaccelerators.cpp216
-rw-r--r--kdecore/kcheckaccelerators.h96
-rw-r--r--kdecore/kckey.cpp286
-rw-r--r--kdecore/kckey.h17
-rw-r--r--kdecore/kclipboard.cpp199
-rw-r--r--kdecore/kclipboard.h123
-rw-r--r--kdecore/kcmdlineargs.cpp1298
-rw-r--r--kdecore/kcmdlineargs.h690
-rw-r--r--kdecore/kcompletion.cpp892
-rw-r--r--kdecore/kcompletion.h1010
-rw-r--r--kdecore/kcompletion_private.h216
-rw-r--r--kdecore/kcompletionbase.cpp154
-rw-r--r--kdecore/kconfig.cpp367
-rw-r--r--kdecore/kconfig.h296
-rw-r--r--kdecore/kconfig_compiler/Makefile.am18
-rw-r--r--kdecore/kconfig_compiler/README.dox255
-rw-r--r--kdecore/kconfig_compiler/TODO0
-rwxr-xr-xkdecore/kconfig_compiler/checkkcfg.pl83
-rw-r--r--kdecore/kconfig_compiler/example/Makefile.am27
-rw-r--r--kdecore/kconfig_compiler/example/autoexample.cpp64
-rw-r--r--kdecore/kconfig_compiler/example/example.cpp52
-rw-r--r--kdecore/kconfig_compiler/example/example.kcfg63
-rw-r--r--kdecore/kconfig_compiler/example/exampleprefs_base.kcfgc18
-rw-r--r--kdecore/kconfig_compiler/example/general_base.ui46
-rw-r--r--kdecore/kconfig_compiler/example/myoptions_base.ui35
-rw-r--r--kdecore/kconfig_compiler/kcfg.xsd192
-rw-r--r--kdecore/kconfig_compiler/kconfig_compiler.cpp1700
-rw-r--r--kdecore/kconfig_compiler/tests/Makefile.am134
-rw-r--r--kdecore/kconfig_compiler/tests/kconfigcompiler_test.cpp96
-rw-r--r--kdecore/kconfig_compiler/tests/kconfigcompiler_test.h35
-rw-r--r--kdecore/kconfig_compiler/tests/myprefs.h7
-rw-r--r--kdecore/kconfig_compiler/tests/test1.cpp.ref72
-rw-r--r--kdecore/kconfig_compiler/tests/test1.h.ref196
-rw-r--r--kdecore/kconfig_compiler/tests/test1.kcfg55
-rw-r--r--kdecore/kconfig_compiler/tests/test1.kcfgc18
-rw-r--r--kdecore/kconfig_compiler/tests/test1main.cpp29
-rw-r--r--kdecore/kconfig_compiler/tests/test2.cpp.ref98
-rw-r--r--kdecore/kconfig_compiler/tests/test2.h.ref333
-rw-r--r--kdecore/kconfig_compiler/tests/test2.kcfg78
-rw-r--r--kdecore/kconfig_compiler/tests/test2.kcfgc11
-rw-r--r--kdecore/kconfig_compiler/tests/test2main.cpp29
-rw-r--r--kdecore/kconfig_compiler/tests/test3.cpp.ref29
-rw-r--r--kdecore/kconfig_compiler/tests/test3.h.ref138
-rw-r--r--kdecore/kconfig_compiler/tests/test3.kcfg26
-rw-r--r--kdecore/kconfig_compiler/tests/test3.kcfgc12
-rw-r--r--kdecore/kconfig_compiler/tests/test3main.cpp29
-rw-r--r--kdecore/kconfig_compiler/tests/test4.cpp.ref82
-rw-r--r--kdecore/kconfig_compiler/tests/test4.h.ref135
-rw-r--r--kdecore/kconfig_compiler/tests/test4.kcfg42
-rw-r--r--kdecore/kconfig_compiler/tests/test4.kcfgc11
-rw-r--r--kdecore/kconfig_compiler/tests/test4main.cpp30
-rw-r--r--kdecore/kconfig_compiler/tests/test5.cpp.ref82
-rw-r--r--kdecore/kconfig_compiler/tests/test5.h.ref127
-rw-r--r--kdecore/kconfig_compiler/tests/test5.kcfg42
-rw-r--r--kdecore/kconfig_compiler/tests/test5.kcfgc11
-rw-r--r--kdecore/kconfig_compiler/tests/test5main.cpp30
-rw-r--r--kdecore/kconfig_compiler/tests/test6.cpp.ref31
-rw-r--r--kdecore/kconfig_compiler/tests/test6.h.ref93
-rw-r--r--kdecore/kconfig_compiler/tests/test6.kcfg25
-rw-r--r--kdecore/kconfig_compiler/tests/test6.kcfgc11
-rw-r--r--kdecore/kconfig_compiler/tests/test6main.cpp30
-rw-r--r--kdecore/kconfig_compiler/tests/test7.cpp.ref31
-rw-r--r--kdecore/kconfig_compiler/tests/test7.h.ref93
-rw-r--r--kdecore/kconfig_compiler/tests/test7.kcfg25
-rw-r--r--kdecore/kconfig_compiler/tests/test7.kcfgc11
-rw-r--r--kdecore/kconfig_compiler/tests/test7main.cpp30
-rw-r--r--kdecore/kconfig_compiler/tests/test8a.cpp.ref22
-rw-r--r--kdecore/kconfig_compiler/tests/test8a.h.ref61
-rw-r--r--kdecore/kconfig_compiler/tests/test8a.kcfg17
-rw-r--r--kdecore/kconfig_compiler/tests/test8a.kcfgc3
-rw-r--r--kdecore/kconfig_compiler/tests/test8b.cpp.ref46
-rw-r--r--kdecore/kconfig_compiler/tests/test8b.h.ref96
-rw-r--r--kdecore/kconfig_compiler/tests/test8b.kcfg21
-rw-r--r--kdecore/kconfig_compiler/tests/test8b.kcfgc6
-rw-r--r--kdecore/kconfig_compiler/tests/test8main.cpp34
-rw-r--r--kdecore/kconfig_compiler/tests/test9.cpp.ref35
-rw-r--r--kdecore/kconfig_compiler/tests/test9.h.ref82
-rw-r--r--kdecore/kconfig_compiler/tests/test9.kcfg24
-rw-r--r--kdecore/kconfig_compiler/tests/test9.kcfgc18
-rw-r--r--kdecore/kconfig_compiler/tests/test9main.cpp43
-rw-r--r--kdecore/kconfig_compiler/tests/test_dpointer.cpp.ref344
-rw-r--r--kdecore/kconfig_compiler/tests/test_dpointer.h.ref224
-rw-r--r--kdecore/kconfig_compiler/tests/test_dpointer.kcfg78
-rw-r--r--kdecore/kconfig_compiler/tests/test_dpointer.kcfgc11
-rw-r--r--kdecore/kconfig_compiler/tests/test_dpointer_main.cpp30
-rw-r--r--kdecore/kconfigbackend.cpp1135
-rw-r--r--kdecore/kconfigbackend.h293
-rw-r--r--kdecore/kconfigbase.cpp1869
-rw-r--r--kdecore/kconfigbase.h2178
-rw-r--r--kdecore/kconfigdata.h146
-rw-r--r--kdecore/kconfigdialogmanager.cpp399
-rw-r--r--kdecore/kconfigdialogmanager.h236
-rw-r--r--kdecore/kconfigskeleton.cpp1207
-rw-r--r--kdecore/kconfigskeleton.h1230
-rw-r--r--kdecore/kcrash.cpp522
-rw-r--r--kdecore/kcrash.h127
-rw-r--r--kdecore/kdcoppropertyproxy.cpp335
-rw-r--r--kdecore/kdcoppropertyproxy.h106
-rw-r--r--kdecore/kde-config.cpp.in270
-rw-r--r--kdecore/kde_dmalloc.h28
-rw-r--r--kdecore/kde_file.h125
-rw-r--r--kdecore/kdebug.areas599
-rw-r--r--kdecore/kdebug.cpp595
-rw-r--r--kdecore/kdebug.h665
-rw-r--r--kdecore/kdebugclasses.h33
-rw-r--r--kdecore/kdebugdcopiface.cpp40
-rw-r--r--kdecore/kdebugdcopiface.h52
-rw-r--r--kdecore/kdebugrc142
-rw-r--r--kdecore/kdelibs_export.h85
-rw-r--r--kdecore/kdemacros.h.in220
-rw-r--r--kdecore/kdesktopfile.cpp346
-rw-r--r--kdecore/kdesktopfile.h251
-rw-r--r--kdecore/kdeversion.cpp46
-rw-r--r--kdecore/kdeversion.h79
-rw-r--r--kdecore/kentities.c837
-rw-r--r--kdecore/kentities.gperf317
-rw-r--r--kdecore/kextendedsocket.h4
-rw-r--r--kdecore/kextsock.cpp2241
-rw-r--r--kdecore/kextsock.h1110
-rw-r--r--kdecore/kgenericfactory.h397
-rw-r--r--kdecore/kgenericfactory.tcc272
-rw-r--r--kdecore/kglobal.cpp264
-rw-r--r--kdecore/kglobal.h237
-rw-r--r--kdecore/kglobalaccel.cpp139
-rw-r--r--kdecore/kglobalaccel.h239
-rw-r--r--kdecore/kglobalaccel_emb.h18
-rw-r--r--kdecore/kglobalaccel_mac.h31
-rw-r--r--kdecore/kglobalaccel_win.cpp345
-rw-r--r--kdecore/kglobalaccel_win.h77
-rw-r--r--kdecore/kglobalaccel_x11.cpp397
-rw-r--r--kdecore/kglobalaccel_x11.h109
-rw-r--r--kdecore/kglobalsettings.cpp730
-rw-r--r--kdecore/kglobalsettings.h566
-rw-r--r--kdecore/kgrantpty.c179
-rw-r--r--kdecore/kiconeffect.cpp770
-rw-r--r--kdecore/kiconeffect.h230
-rw-r--r--kdecore/kiconloader.cpp1408
-rw-r--r--kdecore/kiconloader.h553
-rw-r--r--kdecore/kiconloader_p.h60
-rw-r--r--kdecore/kicontheme.cpp605
-rw-r--r--kdecore/kicontheme.h368
-rw-r--r--kdecore/kidna.cpp63
-rw-r--r--kdecore/kidna.h51
-rw-r--r--kdecore/kinstance.cpp283
-rw-r--r--kdecore/kinstance.h159
-rw-r--r--kdecore/kipc.cpp112
-rw-r--r--kdecore/kipc.h79
-rw-r--r--kdecore/kkeynative.h258
-rw-r--r--kdecore/kkeynative_x11.cpp201
-rw-r--r--kdecore/kkeyserver.h29
-rw-r--r--kdecore/kkeyserver_x11.cpp1052
-rw-r--r--kdecore/kkeyserver_x11.h477
-rw-r--r--kdecore/klargefile.h27
-rw-r--r--kdecore/klibloader.cpp580
-rw-r--r--kdecore/klibloader.h405
-rw-r--r--kdecore/klocale.cpp2448
-rw-r--r--kdecore/klocale.h1340
-rw-r--r--kdecore/klockfile.cpp376
-rw-r--r--kdecore/klockfile.h123
-rw-r--r--kdecore/kmacroexpander.cpp529
-rw-r--r--kdecore/kmacroexpander.h380
-rw-r--r--kdecore/kmanagerselection.cpp490
-rw-r--r--kdecore/kmanagerselection.h229
-rw-r--r--kdecore/kmdcodec.cpp1510
-rw-r--r--kdecore/kmdcodec.h745
-rw-r--r--kdecore/kmdcodec_compat.h4
-rw-r--r--kdecore/kmimesourcefactory.cpp106
-rw-r--r--kdecore/kmimesourcefactory.h85
-rw-r--r--kdecore/kmountpoint.cpp385
-rw-r--r--kdecore/kmountpoint.h116
-rw-r--r--kdecore/kmultipledrag.cpp82
-rw-r--r--kdecore/kmultipledrag.h105
-rw-r--r--kdecore/knotifyclient.cpp363
-rw-r--r--kdecore/knotifyclient.h325
-rw-r--r--kdecore/kpalette.cpp237
-rw-r--r--kdecore/kpalette.h228
-rw-r--r--kdecore/kpixmapprovider.cpp27
-rw-r--r--kdecore/kpixmapprovider.h55
-rw-r--r--kdecore/kprocctrl.cpp277
-rw-r--r--kdecore/kprocctrl.h150
-rw-r--r--kdecore/kprocess.cpp1137
-rw-r--r--kdecore/kprocess.h934
-rw-r--r--kdecore/kprocio.cpp276
-rw-r--r--kdecore/kprocio.h217
-rw-r--r--kdecore/kprotocolinfo_kdecore.cpp562
-rw-r--r--kdecore/kprotocolinfofactory.cpp113
-rw-r--r--kdecore/kprotocolinfofactory.h91
-rw-r--r--kdecore/kpty.cpp541
-rw-r--r--kdecore/kpty.h149
-rw-r--r--kdecore/kqiodevicegzip_p.cpp159
-rw-r--r--kdecore/kqiodevicegzip_p.h64
-rw-r--r--kdecore/krandomsequence.cpp239
-rw-r--r--kdecore/krandomsequence.h145
-rw-r--r--kdecore/kregexp.cpp210
-rw-r--r--kdecore/kregexp.h129
-rw-r--r--kdecore/kregpriv.h57
-rw-r--r--kdecore/krfcdate.cpp505
-rw-r--r--kdecore/krfcdate.h100
-rw-r--r--kdecore/krootprop.cpp303
-rw-r--r--kdecore/krootprop.h206
-rw-r--r--kdecore/ksavefile.cpp230
-rw-r--r--kdecore/ksavefile.h152
-rw-r--r--kdecore/ksharedptr.h175
-rw-r--r--kdecore/kshell.cpp377
-rw-r--r--kdecore/kshell.h147
-rw-r--r--kdecore/kshortcut.cpp671
-rw-r--r--kdecore/kshortcut.h851
-rw-r--r--kdecore/kshortcutlist.cpp220
-rw-r--r--kdecore/kshortcutlist.h295
-rw-r--r--kdecore/kshortcutmenu.cpp161
-rw-r--r--kdecore/kshortcutmenu.h61
-rw-r--r--kdecore/ksimpleconfig.cpp81
-rw-r--r--kdecore/ksimpleconfig.h81
-rw-r--r--kdecore/ksock.cpp435
-rw-r--r--kdecore/ksock.h346
-rw-r--r--kdecore/ksockaddr.cpp894
-rw-r--r--kdecore/ksockaddr.h683
-rw-r--r--kdecore/ksocks.cpp600
-rw-r--r--kdecore/ksocks.h210
-rw-r--r--kdecore/ksortablevaluelist.h171
-rw-r--r--kdecore/kstandarddirs.cpp1682
-rw-r--r--kdecore/kstandarddirs.h729
-rw-r--r--kdecore/kstartupinfo.cpp1498
-rw-r--r--kdecore/kstartupinfo.h668
-rw-r--r--kdecore/kstaticdeleter.cpp10
-rw-r--r--kdecore/kstaticdeleter.h139
-rw-r--r--kdecore/kstdaccel.cpp396
-rw-r--r--kdecore/kstdaccel.h492
-rw-r--r--kdecore/kstddirs.h6
-rw-r--r--kdecore/kstringhandler.cpp663
-rw-r--r--kdecore/kstringhandler.h441
-rw-r--r--kdecore/ksycoca.cpp524
-rw-r--r--kdecore/ksycoca.h186
-rw-r--r--kdecore/ksycocadict.cpp454
-rw-r--r--kdecore/ksycocadict.h123
-rw-r--r--kdecore/ksycocaentry.h123
-rw-r--r--kdecore/ksycocafactory.cpp202
-rw-r--r--kdecore/ksycocafactory.h143
-rw-r--r--kdecore/ksycocatype.h64
-rw-r--r--kdecore/ktempdir.cpp218
-rw-r--r--kdecore/ktempdir.h172
-rw-r--r--kdecore/ktempfile.cpp289
-rw-r--r--kdecore/ktempfile.h213
-rw-r--r--kdecore/ktimezones.cpp790
-rw-r--r--kdecore/ktimezones.h351
-rw-r--r--kdecore/ktypelist.h473
-rw-r--r--kdecore/kuniqueapp.h6
-rw-r--r--kdecore/kuniqueapplication.cpp495
-rw-r--r--kdecore/kuniqueapplication.h221
-rw-r--r--kdecore/kunload.h22
-rw-r--r--kdecore/kurl.cpp2356
-rw-r--r--kdecore/kurl.h1828
-rw-r--r--kdecore/kurldrag.cpp294
-rw-r--r--kdecore/kurldrag.h165
-rw-r--r--kdecore/kuser.cpp425
-rw-r--r--kdecore/kuser.h384
-rw-r--r--kdecore/kvmallocator.cpp274
-rw-r--r--kdecore/kvmallocator.h119
-rw-r--r--kdecore/kwin.cpp1269
-rw-r--r--kdecore/kwin.h721
-rw-r--r--kdecore/kwinmodule.cpp480
-rw-r--r--kdecore/kwinmodule.h358
-rw-r--r--kdecore/kxerrorhandler.cpp121
-rw-r--r--kdecore/kxerrorhandler.h104
-rw-r--r--kdecore/kxmessages.cpp214
-rw-r--r--kdecore/kxmessages.h167
-rw-r--r--kdecore/language.codes3
-rw-r--r--kdecore/libintl.cpp420
-rw-r--r--kdecore/libkdecore.nmcheck79
-rw-r--r--kdecore/libkdecore_weak.nmcheck28
-rw-r--r--kdecore/libqt-mt.nmcheck43
-rw-r--r--kdecore/libqt-mt_weak.nmcheck34
-rw-r--r--kdecore/malloc/Makefile.am31
-rw-r--r--kdecore/malloc/README56
-rw-r--r--kdecore/malloc/configure.in.in134
-rw-r--r--kdecore/malloc/glibc.h31
-rw-r--r--kdecore/malloc/malloc.c5758
-rw-r--r--kdecore/malloc/x86.h41
-rw-r--r--kdecore/netsupp.cpp1237
-rw-r--r--kdecore/netsupp.h301
-rw-r--r--kdecore/netsupp_win32.cpp65
-rw-r--r--kdecore/netwm.cpp4634
-rw-r--r--kdecore/netwm.h1471
-rw-r--r--kdecore/netwm_def.h670
-rw-r--r--kdecore/netwm_p.h155
-rw-r--r--kdecore/network/Makefile.am59
-rw-r--r--kdecore/network/ipv6blacklist3
-rw-r--r--kdecore/network/kbufferedsocket.cpp414
-rw-r--r--kdecore/network/kbufferedsocket.h253
-rw-r--r--kdecore/network/kclientsocketbase.cpp477
-rw-r--r--kdecore/network/kclientsocketbase.h517
-rw-r--r--kdecore/network/kdatagramsocket.cpp283
-rw-r--r--kdecore/network/kdatagramsocket.h278
-rw-r--r--kdecore/network/khttpproxysocketdevice.cpp281
-rw-r--r--kdecore/network/khttpproxysocketdevice.h122
-rw-r--r--kdecore/network/kiobuffer.h144
-rw-r--r--kdecore/network/kmulticastsocket.h113
-rw-r--r--kdecore/network/kmulticastsocketdevice.h151
-rw-r--r--kdecore/network/knetworkinterface.h46
-rw-r--r--kdecore/network/kresolver.cpp1164
-rw-r--r--kdecore/network/kresolver.h945
-rw-r--r--kdecore/network/kresolver_p.h353
-rw-r--r--kdecore/network/kresolvermanager.cpp822
-rw-r--r--kdecore/network/kresolverstandardworkers.cpp1028
-rw-r--r--kdecore/network/kresolverstandardworkers_p.h111
-rw-r--r--kdecore/network/kresolverworkerbase.cpp150
-rw-r--r--kdecore/network/kresolverworkerbase.h317
-rw-r--r--kdecore/network/kreverseresolver.cpp263
-rw-r--r--kdecore/network/kreverseresolver.h195
-rw-r--r--kdecore/network/kserversocket.cpp413
-rw-r--r--kdecore/network/kserversocket.h435
-rw-r--r--kdecore/network/ksocketaddress.cpp957
-rw-r--r--kdecore/network/ksocketaddress.h912
-rw-r--r--kdecore/network/ksocketbase.cpp327
-rw-r--r--kdecore/network/ksocketbase.h762
-rw-r--r--kdecore/network/ksocketbuffer.cpp329
-rw-r--r--kdecore/network/ksocketbuffer_p.h164
-rw-r--r--kdecore/network/ksocketdevice.cpp886
-rw-r--r--kdecore/network/ksocketdevice.h428
-rw-r--r--kdecore/network/ksockssocketdevice.cpp487
-rw-r--r--kdecore/network/ksockssocketdevice.h129
-rw-r--r--kdecore/network/ksrvresolverworker.cpp257
-rw-r--r--kdecore/network/ksrvresolverworker_p.h85
-rw-r--r--kdecore/network/kstreamsocket.cpp368
-rw-r--r--kdecore/network/kstreamsocket.h249
-rw-r--r--kdecore/network/syssocket.h93
-rw-r--r--kdecore/standard_weak.nmcheck6
-rw-r--r--kdecore/svgicons/Makefile.am6
-rw-r--r--kdecore/svgicons/TODO5
-rw-r--r--kdecore/svgicons/ksvgiconengine.cpp686
-rw-r--r--kdecore/svgicons/ksvgiconengine.h49
-rw-r--r--kdecore/svgicons/ksvgiconpainter.cpp2837
-rw-r--r--kdecore/svgicons/ksvgiconpainter.h101
-rw-r--r--kdecore/tests/KIDLTest.cpp33
-rw-r--r--kdecore/tests/KIDLTest.h16
-rw-r--r--kdecore/tests/KIDLTestClient.cpp17
-rw-r--r--kdecore/tests/Makefile.am86
-rw-r--r--kdecore/tests/cplusplustest.cpp44
-rw-r--r--kdecore/tests/dcopkonqtest.cpp36
-rw-r--r--kdecore/tests/kapptest.cpp40
-rw-r--r--kdecore/tests/kcalendartest.cpp152
-rw-r--r--kdecore/tests/kcharsetstest.cpp12
-rw-r--r--kdecore/tests/kcmdlineargstest.cpp91
-rw-r--r--kdecore/tests/kconfigtest.cpp162
-rw-r--r--kdecore/tests/kconfigtestgui.cpp200
-rw-r--r--kdecore/tests/kconfigtestgui.h72
-rw-r--r--kdecore/tests/kdebugtest.cpp98
-rw-r--r--kdecore/tests/kglobaltest.cpp64
-rw-r--r--kdecore/tests/kiconloadertest.cpp34
-rw-r--r--kdecore/tests/kipctest.cpp33
-rw-r--r--kdecore/tests/kipctest.h21
-rw-r--r--kdecore/tests/klocaletest.cpp199
-rw-r--r--kdecore/tests/klocaletest.h32
-rw-r--r--kdecore/tests/kmacroexpandertest.cpp137
-rw-r--r--kdecore/tests/kmdcodectest.cpp395
-rw-r--r--kdecore/tests/kmemtest.cpp248
-rw-r--r--kdecore/tests/knotifytest.cpp10
-rw-r--r--kdecore/tests/kprocesstest.cpp116
-rw-r--r--kdecore/tests/kprocesstest.h50
-rw-r--r--kdecore/tests/kprociotest.cpp65
-rw-r--r--kdecore/tests/kprociotest.h42
-rw-r--r--kdecore/tests/krandomsequencetest.cpp91
-rw-r--r--kdecore/tests/kresolvertest.cpp420
-rw-r--r--kdecore/tests/krfcdatetest.cpp81
-rw-r--r--kdecore/tests/kshelltest.cpp55
-rw-r--r--kdecore/tests/ksimpleconfigtest.cpp48
-rw-r--r--kdecore/tests/ksocktest.cpp109
-rw-r--r--kdecore/tests/ksortablevaluelisttest.cpp32
-rw-r--r--kdecore/tests/kstdacceltest.cpp39
-rw-r--r--kdecore/tests/kstddirstest.cpp52
-rw-r--r--kdecore/tests/kstringhandlertest.cpp97
-rw-r--r--kdecore/tests/ktempfiletest.cpp48
-rw-r--r--kdecore/tests/ktimezonestest.cpp62
-rw-r--r--kdecore/tests/kuniqueapptest.cpp59
-rw-r--r--kdecore/tests/kurltest.cpp1124
-rw-r--r--kdecore/tests/kxerrorhandlertest.cpp54
-rw-r--r--kdecore/tests/startserviceby.cpp41
-rw-r--r--kdecore/tests/testqtargs.cpp104
-rw-r--r--kdecore/vsnprintf.c170
444 files changed, 160633 insertions, 0 deletions
diff --git a/kdecore/40.colors b/kdecore/40.colors
new file mode 100644
index 000000000..4f08d39c5
--- /dev/null
+++ b/kdecore/40.colors
@@ -0,0 +1,48 @@
+KDE RGB Palette
+0 0 0 Black
+48 48 48 Almost black
+88 88 88 Very dark gray
+128 128 128 Dark gray
+160 160 160 Mid gray
+195 195 195 Light gray
+220 220 220 Very light gray
+255 255 255 White
+
+64 0 0 Very dark red
+128 0 0 Dark red
+192 0 0 Mid red
+255 0 0 Red
+255 192 192 Light red
+
+0 64 0 Very dark green
+0 128 0 Dark green
+0 192 0 Mid green
+0 255 0 Green
+192 255 192 Light green
+
+0 0 128 Dark blue
+0 0 192 Mid blue
+0 0 255 Blue
+192 192 255 Light blue
+
+64 64 0 Very dark yellow
+128 128 0 Dark yellow
+192 192 0 Mid yellow
+255 255 0 Yellow
+255 255 192 Light yellow
+
+0 64 64 Very dark cyan
+0 128 128 Dark cyan
+0 192 192 Mid cyan
+0 255 255 Cyan
+192 255 255 Light cyan
+
+128 0 128 Dark magenta
+192 0 192 Mid magenta
+255 0 255 Magenta
+255 192 255 Light magenta
+
+192 88 0 Dark orange
+255 128 0 Orange
+255 168 88 Light orange
+255 220 168 Very light orange
diff --git a/kdecore/AUTHORS b/kdecore/AUTHORS
new file mode 100644
index 000000000..a76f6be1e
--- /dev/null
+++ b/kdecore/AUTHORS
@@ -0,0 +1,56 @@
+Matthias Kalle Dalheimer <kalle@kde.org>:
+classes KConfig, KTextStream, KColorSet, KApplication
+automake, autoconf, maintenance
+
+Richard Moore <moorer@cs.man.ac.uk>:
+KLedLamp class
+
+Martynas Kunigelis <algikun@santaka.ktu.lt>:
+KProgress class
+
+Steffen Hansen <stefh@dit.ou.dk>:
+KURL class
+
+Torben Weis <weis@stud.uni-frankfurt.de>
+DnD stuff, KSocket and KServerSocket classes, KPixmap
+
+Alexander Sanda <alex@darkstar.ping.at>
+Read and write numerical config entries, KPanner, KTabControl,
+KPopupMenu, KMessageBox, KEdit widgets.
+
+Martin Jones <mjones@powerup.com.au>
+Bugfixes in KPixmap and KURL, KColorDialog, KSelector
+
+Keith Brown <kbrown@pdq.net>
+KTreeList class
+
+Bernd Johannes Wuebben <wuebben@math.cornell.edu>
+KFontDialog classes
+
+Tim D. Gilman <tdgilman@best.com>
+KDatePicker, KDateTable class
+
+Nicolas Hadacek <hadacek@kde.org>
+Key configuration classes, bug fixes
+
+Michael Will <Michael.Will@student.uni-tuebingen.de>
+loading routine in KPixmap
+
+Christian Czezatke <e9025461@student.tuwien.ac.at>
+KProcess class
+
+Matthias Ettrich <ettrich@kde.org>
+KWM, Changes to KApplication and KIconLoader
+
+Stephan Kulow <coolo@kde.org>
+heavy modifications to KURL, autoconf and automake stuff
+
+Jacek Konieczny <jajcus@zeus.polsl.gliwice.pl>
+KCharset* classes
+
+These files are part of GNU Libtool, originally by
+Thomas Tanner <tanner@gmx.de>
+ltdl.c + ltdl.h
+
+Carsten Pfeiffer <pfeiffer@kde.org>
+KCompletion classes
diff --git a/kdecore/DESIGN.COLOR b/kdecore/DESIGN.COLOR
new file mode 100644
index 000000000..e06c7c7d3
--- /dev/null
+++ b/kdecore/DESIGN.COLOR
@@ -0,0 +1,141 @@
+Color Management in KDE
+
+Colors are in important part of KDE and are an important tool to make
+a good looking desktop. Colors can also be a burden, especially for
+people with visual impairments.
+
+The goal of color management is to take full advantage of colors while
+reducing the disadvantages of color use to a minimum.
+
+Color Schemes
+=============
+
+Color Management is based around the concept of color schemes.
+A color scheme defines colors for different elements in the
+UI. The most important factor for the readability of a UI is the
+contrast between foreground and background colors. Colors in a color
+scheme are therefor grouped in pairs which define the foreground and
+background color for a UI element. When composing a color scheme care
+should be taken to use sufficiently contrasting colors for fore- and
+background in the same group. When using colors in applications, care
+should be taken never to mix foreground colors from one group with
+background colors from another group: they do not necasserily have any
+contrast at all which can lead to a completely unreadable UI.
+
+Color schemes are supported by Qt (see QColorGroup) and can be
+configured on a KDE wide basis from the Control Panel. The settings
+are stored in the global KDE configuration file under the "General"
+setting. The KApplication class takes care that the configured
+settings are passed on to Qt. Application developers can just use the
+values provided by QColorGroup.
+
+There are three major color categories:
+
+General
+=======
+The colors in this group are used when no particular other group is
+relevant.
+
+QColorGroup...: ColorRole::Background, background()
+KDE config key: background
+Control Center: i18n("Window Background")
+Description...: General background color
+Example use...: Background of dialogs
+
+QColorGroup...: ColorRole::Foreground, foreground()
+KDE config key: foreground
+Control Center: i18n("Window Text")
+Description...: General foreground color
+Example use...: Text in dialogs
+
+Text Areas
+==========
+The colors in this group are used where the user can type text. it is
+also used for lists from which the user can choose.
+
+QColorGroup...: ColorRole::Base, base()
+KDE config key: windowBackground
+Control Center: i18n("Standard background")
+Description...: Background color for text areas.
+Example use...: Background in a word-processor.
+
+QColorGroup...: ColorRole::Text, text()
+KDE config key: windowForeground
+Control Center: i18n("Standard text")
+Description...: Text color for text areas.
+Example use...: Text in a word-processor.
+
+QColorGroup...: ColorRole::Highlight, highlight()
+KDE config key: selectBackground
+Control Center: i18n("Select background")
+Description...: Background color for selected text.
+Example use...: In a selection list.
+
+QColorGroup...: ColorRole::HighlightedText, highlightedText()
+KDE config key: selectForeground
+Control Center: i18n("Select text")
+Description...: Text color for selected text.
+Example use...: In a selection list.
+
+"Base" and "Text" should have high contrast as well as "Highlight" and
+"HighlightedText". In addition, "Highlight"/"HighlightedText" and
+"Base"/"Text" are supposed to be sufficiently different to get a clear
+indication of what is selected and what is not.
+
+Buttons
+=======
+The colors used in this category are used for buttons in the broad
+sense, including e.g.scrollbars, menubars and
+popup-menus.
+
+QColorGroup...: ColorRole::Button, button()
+KDE config key: buttonBackground
+Control Center: i18n("Button background")
+Description...: Background color for buttons.
+Example use...: Background color of the OK button in a messagebox.
+
+QColorGroup...: ColorRole::ButtonText, buttonText()
+KDE config key: buttonForeground
+Control Center: i18n("Button text")
+Description...: Color for text on buttons.
+Example use...: Color of the OK text on a button in a messagebox.
+
+
+In addition to the above colors a number of derived colors are
+defined.They are all darker of lighter version of "Background".
+
+QColorGroup...: ColorRole::Shadow, shadow()
+Description...: Used for shadow effects.(Very dark)
+
+QColorGroup...: ColorRold::BrightText, brightText()
+Description...: Used for text on pushed pushbuttons
+
+QColorGroup...: ColorRole::Light, light()
+Description...: Lighter than "Button"
+
+QColorGroup...: ColorRole::Midlight, midlight()
+Description...: Between "Button" and "Light"
+
+QColorGroup...: ColorRole::Dark, dark()
+Description...: Darker than "Button"
+
+QColorGroup...: ColorRole::Mid, mid()
+Description...: Between "Button" and "Dark"
+
+Well Behaved Aplications
+========================
+
+Applications should never hardcode colors but always default to the
+colors from the users color scheme. This ensures consistency among
+applications on the desktop. It also ensures that all applications
+are equally readable.
+
+An application may offer the user an option to change the color of
+certain aspects of the application. It should be noted that an
+application specific color setting can cause unexpected results when
+the user changes its color scheme. The application specific color may
+look ugly in combination with other color schemes or the resulting UI
+may even become unreadable. Therefor applications specific colors
+should be used with care.
+
+
diff --git a/kdecore/DESIGN.iconloading b/kdecore/DESIGN.iconloading
new file mode 100644
index 000000000..ceb2ffbce
--- /dev/null
+++ b/kdecore/DESIGN.iconloading
@@ -0,0 +1,187 @@
+Discussion of Icon Loading for KDE 3
+====================================================
+
+This document describes the design ideas for improving icon loading
+in KDE 3.
+
+
+On Wednesday 08 August 2001 04:15 pm, Waldo Bastian wrote:
+> On Wednesday 08 August 2001 03:52 pm, Dirk Mueller wrote:
+> > On Mit, 08 Aug 2001, Waldo Bastian wrote:
+> > > I'm not really sure how to do it... the idea is this:
+> > >
+> > > A list of shared icons is published somewhere.
+> > > Applications load this list
+> > > For all icons the application wants to use:
+> > > It checks whether a shared version is available,
+> > > if so it uses that one.
+> > > If not, it loads the icon.
+> > > When it has loaded most icons, it somehow (*) adds the icons that it loaded
+> > > to the list of published icons.
+> > >
+> > > I think that the somehow (*) part can be done most reliable by a
+> > > central service, e.g. a KDED module. That might also be able to keep
+> > > track of usage so that it can throw icons out that aren't used any
+> > > more. I think it will be difficult / slow if we need to do ref-counting
+> > > for each and every shared icon using some mechanism that involves X.
+> >
+> > True. but things become a bit complicated if an application reregisters
+> > with a different name. or do we handle that already ?
+> >
+> > what do you do if the DCOP-connection lifetime is crossing the
+> > pixmap-lifetime somehow, i.e. the pixmap is still referenced after
+> > closing the dcop connection on shutdown ?
+
+Ok, I have looked into this a bit more and it seems to be rather easy to
+create one or more pixmaps in a server process containing icons, a client can
+then create a pixmap of the right size itself and with a simple XCopyArea
+call, it can copy the icon from the server pixmap to its own pixmap.
+
+That way the application's pixmap always remain valid.
+
+Some example code to get the idea:
+
+Server can publish an icon (test.png) like this:
+ QImage i("test.png");
+ QPixmap p;
+ p.convertFromImage(i);
+ qWarning("Handle = %08x", p.handle());
+
+Now, if Handle is e.g. 0x06c0000b, the following code (in another process)
+can copy this pixmap:
+
+ QPixmap p(35,35);
+ Drawable src = 0x06c0000b;
+ XGCValues values;
+ GC gc = XCreateGC(qt_xdisplay(), src, 0, &values);
+ XCopyArea(qt_xdisplay(), src, p.handle(), gc, 0, 0, 30, 30, 0, 0);
+ // p contains now 30x30 pixels of test.png.
+
+The only hard part is then to publish the icons in a way that applications
+know what to copy. I'm thinking about a ksycoca-sort-of index that
+applications can map and can use to do fast lookups with. This has no major
+problems except for the race-condition that might exist when an icon is
+removed. In that case you will remove it from the index first and then later
+you will remove the actual image data from the pixmap, however, you must make
+sure that none of the client apps will be using the outdated index informatin
+any more before you can remove the actual image data.
+
+For practical purposes that might be solved by removing the entry from the
+index, informing the applications via DCOP to flush their outdated index
+information and then waiting for a sufficient long period, e.. 5 minutes,
+before actually removing the image data.
+
+I can also imagine a scenario where the index information is only used very
+temporarily, e.g. during the creation of a KMainWindow (mmap the file in the
+constructor, unmap it from the next event loop) that way icons can be removed
+from the index and after e.g. a timeout of 5 minutes one can be relatively
+sure that the index will no longer be used.
+
+I think the best way to distribute the index information is through the file
+system but the update mechanism for this file should probably more complex
+than the one used in ksycoca. Since ksycoca updates only happen once in a
+while, we can afford it to write out a whole new file. For icons this will
+probably be more difficult since updates will be part of normal operation, if
+the index file is rather large (no idea about that.. how much icons are in
+use on an average desktop? 50? 200? 500? 500*80bytes = 40Kb, not too bad) we
+might want to write out only the updates, that would probably mean that we
+need to have some sort of extensible on-disk hash-table.
+Would that be worth the hassle? If we need to access hash-buckets throughout
+this 40Kb the OS probably ends up writing all of this file to disk ayway.
+
+Better keep it simple to start with then...
+
+Cheers,
+Waldo
+--
+KDE 2.2: We deliver.
+
+<Zogje> do you have any idea how many Kb of pixmaps are stored in the X-server on average?
+<Zogje> e.g. with a standard desktop with 5 konsole's and konqueror or os
+<Zogje> cause I was wondering... if we copy pixmaps on the X-server with XCopyArea like I proposed in my mail
+<Zogje> then the next step could be to use shared pixmaps on the X-server... if the X-server could refcount pixmaps
+<Zogje> i don't think it supports that at the moment
+<antlarr> I'm not sure, but Konqueror seems to open around 500 icons (some of them repeated), and konsole... 40 ? (I made the experiments with my other computer and it's down at the moment)
+<Zogje> and those icons are 22x22? 32x32?
+<Zogje> 4 bytes per pixel?
+<antlarr> I can have a look to see the sizes (my original experiments counted them in separate counters)
+<antlarr> yes, 4 bytes per pixel
+<Zogje> that's about 1.5Kb to 4Kb per pixmap
+<Zogje> cause I think pixmap space on the X_server is a limited resource
+<Zogje> it prolly can cache them in video-memory
+<antlarr> Zogje: what worries me most is how to know when to delete a pixmap from X
+<Zogje> but if we have the same pixmap 20 times in the X-server
+<Zogje> then we are wasting such caching in a terrible way.. and that would cost us performance
+<Zogje> antlarr: yes, that's why I say, we would need refcounting in the X-server itself
+<Zogje> antlarr: should talk with Keith about that
+<antlarr> Zogje: but if you unload the icon after all apps stop using it, then there's no benefit after you start konqueror again, because they'll have to be loaded again
+<Zogje> antlarr: but it will be easier to make the point if we have some solid data behind it
+<Zogje> antlarr: well.. there are two issues
+<antlarr> you'll just stop loading repeated icons that way
+<Zogje> 1) you want to have the benefit of caching, and for that you want to have the icon in the cache, you can throw it away after some time if you think it will not be needed any longer
+<Zogje> 2) If you actually _share_ the pixmap, you must 100% guarante that the pixmap remains available as long as it is in use
+<Zogje> so for the 1)-case there is no hard requirement, it just affects your cache-efficiency
+<Zogje> the 2)-case is a hard requirement, in that if you don't meet it, you will have incorrect operation
+<antlarr> Zogje: yes
+<Zogje> we can meet 2) by coying the pixmap with e.g. XCopyArea
+<Zogje> but a better way would be to have refcounting in the server
+<Zogje> that's independent from 1)
+<antlarr> Yes, that would be much better
+<Zogje> antlarr: so if you can provide staticstic on the icons in use on a typical KDE desktop, including total size and number of icons shared, etc.
+<antlarr> Zogje: ok, I'll try it tomorrow morning (I think I'll have some time, but little as I'm trying to study for exams)
+<antlarr> Btw, do you plan to use a kind of "icon server" ?
+<Zogje> antlarr: then we can take that to the XFree guys and say, if you gives us refcounting we can save XXX Kb of pixmap data on the x-server and we think that will give us better performance
+<antlarr> Yes, you're right, that would be the best thing to do
+<Zogje> in the mean time we might want to implement such an icon-server then, so that when they actually make ref-counting we can hook it in and get the results directly
+<antlarr> So you think the apps should load the icon, apply the effects, convert it to a X pixmap and use it. But how do you plan to know if an icon is already in the XServer ? via atoms ?
+<antlarr> s/an icon/an icon with the respective effects applied/
+<antlarr> pmax: that's precisely where I want to get to.
+<Zogje> antlarr: I would like to publish an index of the icons and their handles through the filesystem
+<Zogje> the app loads the icon, applies the effects, when it has finished starting up it
+<Zogje> can make a DCOP call to the icon-server and tell it, here, I'm using these icons
+<Zogje> then the icon-server can copy (or refcount++) them and update the file with the
+<Zogje> published icons
+<antlarr> Ok, so there'll be an icon server
+<Zogje> yes
+<antlarr> Zogje: you can never know when the app has finished starting up, as it can load some icons later than that
+<Zogje> you could basically publish the icons via properties on the X server itself as well
+<Zogje> but I think that will be slow
+<antlarr> Zogje: yes, I think that too
+<antlarr> But I'm not sure about the file with published icons
+<Zogje> well, when it loads icons later on, it can tell the icon-server about them later on
+<Zogje> or just ignore it
+<Zogje> whatever works
+<antlarr> what happens with remote connections of apps running on different hosts ?
+<Zogje> they are on their own
+<pmax> over a slow link
+<pmax> icon server becomes n times slower, right?
+<Zogje> pmax: when?
+<pmax> remote X connections
+<antlarr> pmax: it doesn't matter if it's a slow or fast link, I'm talking about the problem with loaded icons that are available on one of the computers, but not on another and about the file with the published icons
+<Zogje> pmax: if you use X properties you have X-server round-trips, so that will be an issue on slow-links
+<pmax> antlarr: true
+<Zogje> pmax: you don't have that if you use the file-system
+<pmax> you can always send icons back and forth with dcop too though
+<Zogje> antlarr: we have a DCOP communication space that is limited to a certain host and X-Display
+<pmax> I send x.509's pem encoded through dcop
+<Zogje> antlarr: icon caching should happen within that space
+<Zogje> antlarr: you can combine multiple spaces in various ways... but they don't communicate with each other
+<Zogje> pmax: no, i don't plan too
+<Zogje> pmax: it is faster to load the icon from disk than to use dcop, probably
+<antlarr> Zogje: ok
+<pmax> Zogje: certainly, but if there is a case where the icon doesn't exist on a remote machine, it could easily be transferred like that
+<Zogje> pmax: if the icons doesn't exist you haven't instaled KDE correctly
+<pmax> (I was referring to antlarr's comment)
+<antlarr> pmax: why do that if you can just store it in the X server and tell the icon server what icon is yours?
+<pmax> what about an app that is only on one machine but not the other? then it's icons won't be there
+<Zogje> pmax??
+<pmax> antlarr: I'm not saying that's the best way.. I was just saying it's a possibility
+<Zogje> pmax: how does that work now?
+<antlarr> pmax: Zogje is right, there's no problem with remote apps, it will just not use the icon cache, nothing more
+<vod> just found it
+<pmax> oh I see
+<Zogje> to answer you rfirst question: "won't the ipc be a bottleneck?" no, because you don't use ipc in the critical part (the icon loading)
+<pmax> yup I understand how it works now I think
+<Zogje> instead you access an index from disk which is quite fast (as fast as ksycoca)
+<pmax> I think this will definitely speed things up on my machine since I have a relatively fast box with slow disks
+<Zogje> that's why I want to use the file-system instaed of X-properties
diff --git a/kdecore/DESIGN.kconfig b/kdecore/DESIGN.kconfig
new file mode 100644
index 000000000..e683566cb
--- /dev/null
+++ b/kdecore/DESIGN.kconfig
@@ -0,0 +1,224 @@
+kconfigdata.h contains definitions of the data formats used by kconfig.
+
+Configuration entries are stored as "KEntry". They are indexed with "KEntryKey".
+The primary store is a "KEntryMap" which is defined as a QMap from "KEntryKey"
+to "KEntry"
+
+KEntry's are stored in order in the KEntryMap. The most significant sort
+criteria is mGroup. This means that all entries who belong in the same group,
+are grouped in the QMap as well.
+
+The start of a group is indicated with a KEntryKey with an empty mKey and a
+dummy KEntry. This allows us to search for the start of the group and then to
+iterate until we end up in another group. That way we will find all entries
+of a certain group.
+
+Entries that are localised with the _current_ locale are stored with bLocal
+set to true. Entries that are localised with another locale are either not
+stored at all (default), or with the localization as part of the key (when
+reading a file in order to merge it).
+[WABA: Does it make sense to keep both localized and non-localised around?
+Can't we just let the localised version override the non-localised version?]
+
+Currently the localization bit is the least significant sort criteria, that
+means that the localised version always follows the non-localised version
+immediately.
+
+<Changed for KDE 3.0>
+Entries that are being read from a location other than the location to
+which is written back are marked as "default" and will be added both as
+normal entry as well as an entry with the key marked as default.
+
+When entries are written to disk, it is checked whether the entry to write
+is equal to the default, if so the entry will not be written. The default
+entry always follows directly after the normal entry, due to the sorting.
+(After that the localised version follows)
+
+When entries are written to disk, it is checked whether the entry to write
+is equal to the default, if so the entry will not be written.
+</Changed>
+
+Open question:
+Should unmodified entries that are written back be compared with the default
+too? This seems to be mostly a transition issue.
+
+<Changed during KDE 3.0 / 3.2>
+Extra functions:
+
+bool entryIsImmutable(key); // Can entry be modified?
+bool hasDefault(key); // Is there a system wide default set for the entry?
+void revertToDefault(key); // Restore to default
+void deleteEntry(key); // Remove entry
+
+Note that there is a subtle difference between revertToDefault() and deleteEntry().
+revertToDefault() will change the entry to the default value set by the system
+administrator (Via e.g. $KDEDIR/share/config) or, if no such default was set,
+non-existant.
+deleteEntry() will make the entry non-existant.
+
+Entries are marked "immutable" if the key is followed by [$i]. This means
+that a user can not override these entries.
+
+Entries can be marked as deleted if they are followed by [$d]. This
+is needed if the system administrator has specified a default value but the
+entry was deleted (made 'non-existant'). In that case we can't just leave
+the entry out since that would mean we get the default from the system
+administrator back the next time we read the file.
+</changed>
+
+When an entry is read with readEntry(key, defaultValue), non-existing
+entries will return "defaultValue" while hasKey(key) will return "false"
+for such entries.
+
+Currently all entries are stored in memory. When KConfig is "sync()'ed"
+it reads the file that it is about to overwrite (for the second time), it
+then merges in the entries it has in memory and writes the result back to
+the file. It does NOT update its map of entries in memory with the entries
+(re)read from disk. It only updates the entries in memory when
+"reparseConfiguration()" is called.
+
+
+Open Question: The standard writeEntry() function returns the original value,
+is this needed? Nobody seems to use it.
+
+Open Question: The bPersistent flag doesn't seem to be used... could it be removed?
+
+Open Question: Is the bNLS flag needed? Localised entries seem to be mostly
+useful for default files, are they ever created by the user itself?
+
+Open Question: Would it be worthwhile to lock a user option that is equal to the
+default so that it doesn't change when the default changes?
+
+
+KDE3.0 Changes
+==============
+
+*) writeEntry now returns void instead of QString.
+*) deleteEntry functions added
+
+
+------------------------------------------------------------------------------
+
+KConfig XT
+==========
+
+My buzzword picker offered KConfig XT ("eXtended Technology") and KConfig NG
+("Next Generation"). Since the planned changes are ment to be evolutionary
+rather than revolutionary, KConfig NG was dropped.
+
+Goals
+=====
+
+* Have the default value for config entries defined in 1 place. Currently it is
+not uncommon to have them defined in three places:
+ 1) In the application that reads the setting in order to use it
+ 2) In the settings dialog when reading the setting
+ 3) In the settings dialog when selecting "Use defaults".
+
+* Provide type-information about config entries to facilate "KConfEdit" like
+tools. Ideally type-information also includes range-information; this is even
+mandatory if enums become an explicit type.
+
+* Facilitate the documentation of config entries.
+
+
+Instead of relying on the defaults that are hard-coded in the application,
+rely on default configuration files being installed in $KDEDIR. The technical
+changes required for this are very minimal, it is mostly a change in policy.
+
+Type information can be provide by preceding every entry with a formalized
+comment.
+
+Work to be done:
+* KConfig needs to be extended to provide access to the default values provided
+by the default config files. KConfig already stores this information internally.
+(DONE)
+* A formal comment structure needs to be designed that can convey type-information.
+Preferably in such a way that it is easily parsable by both machine and user.
+* KConfig needs to be extended, or another class created, that is able to parse
+the formalized comments.
+* A tool needs to be developed that can assist developers with the generation
+and verification of default configuration files including type-information.
+
+Drawbacks:
+* We rely on default configuration files being properly installed.
+* The user can break applications by making improper modifications to these
+files.
+* It is not possible to store defaults settings in a config file that are
+of a dynamic nature. Examples are settings derived from other settings,
+e.g. a color setting could be derived from the current color theme, or
+e.g. the default high score user name which is determined by the user
+currently logged in.
+
+
+Some random ideas:
+* The format of the entries would be something like this:
+
+[Mail Settings]
+#!Type=string
+#!Description=SMTP server to use for sending mail
+#!Description[nl]=SMTP server voor het versturen van mail
+Host=wantelbos.zogje.fr
+
+- the type could be subclassed more, e.g. strings can be "email", "hostname",
+ "url", etc.
+
+- having translations in these files is very arguable. external po's would be
+ better.
+
+
+
+Class overview
+
+ KConfigBase
+ |
+ v
+ KConfigBackend <-----> KConfig <------> KConfigSkeleton /--< myapp.kcfg
+ | | | /
+ v v |*---------------<
+KConfigINIBackend KSimpleConfig |kconfig_compiler \
+ | \--< myconfig.kcfg-codegen
+ v
+ MyConfig <-----KConfigDialogManager----> MyConfigWidget *---< myconfigwidget.ui
+ uic
+
+KConfigBase: defines API for generic config class
+
+KConfig: functional generic config class that supports merging of cascaded
+ configuration files
+
+KSimpleConfig: functional generic config class without support for cascading
+ configuration files.
+
+KConfigBackend: defines API for config backend, t.i. the actual handling
+ of the storage method and storage format.
+
+KConfigINIBackend: the standard (and only one so far) class that implements
+ the config backend using the file-based .INI format
+ for configuration files
+
+KConfigSkeleton: base class for deriving classes that store application
+ specific options providing type-safety and single-point
+ defaults.
+
+MyConfig: An application specific class that offers configuration options
+ to the applications via variables or accessor functions and that
+ handles type-safety and defaults. MyConfig is just an example
+ name, the application developer choses the actual name.
+
+myapp.kcfg: File describing the configuration options used by a specific
+ application. myapp.kcfg is just an example name, the application
+ developer choses the actual name.
+
+myconfig.kcfg-codegen: Implementation specific code generation instructions
+ for the MyConfig class. myconfig.kcfg-codegen is
+ just an example name, the application developer
+ choses the actual name.
+
+KConfigDialogManager: Class that links widgets in a dialog up with their
+ corresponding confguration options in a configuration
+ object derived from KConfigSkeleton.
+
+MyConfigWidget: Dialog generated from a .ui description file. Widget names
+ in the dialog that start with "kcfg_" refer to configuration
+ options.
diff --git a/kdecore/KCONFIG_DESIGN b/kdecore/KCONFIG_DESIGN
new file mode 100644
index 000000000..dfd9aa151
--- /dev/null
+++ b/kdecore/KCONFIG_DESIGN
@@ -0,0 +1,51 @@
+
+ The basic design on KConfig for KDE 2.0 and KDE 3.0:
+ ----------------------------------------
+
+KConfig is a hierarchy of classes for loading and saving configuration
+data in KDE. KConfigBase is an abstract data type (ADT) with pure
+virtual functions which describes the API for accessing configuration
+data. It cannot be instantiated directly; only subclasses which
+actually implement the API may be created. The reason for this design
+is that different ways of storing configuration data in _memory_ may
+be desired. The default design uses a QMap (red-black tree) for
+storing values in memory once they are read from disk. However, a
+different design might use a shared database or something similar to
+achieve shared memory config values. The possibilities are endless,
+and with this design we insure that future designs will not break
+compatibility.
+
+This means that most classes that currently take pointers to KConfig
+objects should be changed to take pointers to KConfigBase objects.
+The virtual functions and c++ polymorphism will make sure that the
+correct function in the actual, instantiated object are called, but
+this lets the user/programmer change the type of KConfig that has been
+implemented at runtime without changing other code.
+
+Similarly, there is a abstract data type KConfigBackEnd. All
+reading/writing of the physical, on-disk configuration should be done
+through a subclass of KConfigBackEnd. The only class that is
+currently implemented right now is KConfigINIBackEnd, which
+reads/writes the standard windows INI-style configuration files that
+KDE has used since KDE 1.x days. However, it is conceivable that one
+might program an XML backend, or even a database/registry style
+backend. Again, this abstract data type approach provides flexibility
+for the future. Currently KConfig and KSimpleConfig hardcode that
+they are using a KConfigINIBackEnd in the constructor. If more back
+ends are implemented, this will have to be changed to use a factory
+method of some sort to create the backend; all they maintain is a
+pointer to a KConfigBackEnd, so the actual type of backend does not
+matter.
+
+If you are interested in using KConfig, you need simply to look at the
+public members of KConfigBase. They will provide you with everything
+you need to do to look up data, change and write data, etc. If you
+are interested in implementing a new KConfig format, look at KConfig
+for ideas. Likewise if you want to implement a backend, look at
+KConfigINIBackEnd for inspiration. The KDoc-style API documentation
+should be complete. If there is anything confusing, please either fix
+it in CVS yourself or mail me with your questions, and we will make
+sure things get clarified.
+
+
+- Preston Brown <pbrown@kde.org>
diff --git a/kdecore/MAINTAINERS b/kdecore/MAINTAINERS
new file mode 100644
index 000000000..50820b5f0
--- /dev/null
+++ b/kdecore/MAINTAINERS
@@ -0,0 +1,116 @@
+Here are the code maintainers for each part of this library. Any problems or
+suggested patches for a class should be directed to the responsible person for
+that class.
+
+When adding yourself as a maintainer, don't be afraid to reorder the files to a
+more logical grouping.
+
+dmalloc.cpp
+kaboutdata.cpp David Faure <faure@kde.org>
+kaccel.cpp Ellis Whitehead <ellis@kde.org>
+kaccelaction.cpp Ellis Whitehead <ellis@kde.org>
+kaccelbase.cpp Ellis Whitehead <ellis@kde.org>
+kallocator.cpp Waldo Bastian <bastian@kde.org>
+kappdcopiface.cpp
+kapplication.cpp Waldo Bastian <bastian@kde.org>
+kaudioplayer.cpp
+kcatalogue.cpp Hans Petter Bieker <bieker@kde.org>
+kcharsets.cpp Lars Knoll <knoll@kde.org>
+kckey.cpp
+kcmdlineargs.cpp Waldo Bastian <bastian@kde.org>
+kcompletion.cpp Carsten Pfeiffer <pfeiffer@kde.org>
+kcompletionbase.cpp
+kconfig.cpp Waldo Bastian <bastian@kde.org>
+kconfigbackend.cpp Waldo Bastian <bastian@kde.org>
+kconfigbase.cpp Waldo Bastian <bastian@kde.org>
+kcrash.cpp Waldo Bastian <bastian@kde.org>
+kdcoppropertyproxy.cpp
+kdebug.cpp Stephan Kulow <coolo@kde.org>
+kdesktopfile.cpp
+kglobal.cpp Stephan Kulow <coolo@kde.org>
+kglobalaccel.cpp Ellis Whitehead <ellis@kde.org>
+kglobalaccel_x11.cpp Ellis Whitehead <ellis@kde.org>
+kglobalsettings.cpp David Faure <faure@kde.org>
+kiconeffect.cpp
+kiconloader.cpp
+kicontheme.cpp
+kinstance.cpp Stephan Kulow <coolo@kde.org>
+kipc.cpp Lubos Lunak <l.lunak@kde.org>
+kkey_x11.cpp Ellis Whitehead <ellis@kde.org>
+kkeynative_x11.cpp Ellis Whitehead <ellis@kde.org>
+kkeysequence.cpp Ellis Whitehead <ellis@kde.org>
+kkeysequence_emb.cpp Ellis Whitehead <ellis@kde.org>
+klibloader.cpp
+klocale.cpp Hans Petter Bieker <bieker@kde.org>
+kmdcodec.cpp
+kmimesourcefactory.cpp
+kmultipledrag.cpp David Faure <faure@kde.org>
+knotifyclient.cpp
+kpalette.cpp Waldo Bastian <bastian@kde.org>
+kpixmapprovider.cpp Carsten Pfeiffer <pfeiffer@kde.org>
+kprocctrl.cpp Waldo Bastian <bastian@kde.org>
+kprocess.cpp Waldo Bastian <bastian@kde.org>
+kprocio.cpp Waldo Bastian <bastian@kde.org>
+krandomsequence.cpp Waldo Bastian <bastian@kde.org>
+kregexp.cpp
+krfcdate.cpp Waldo Bastian <bastian@kde.org>
+krootprop.cpp Lubos Lunak <l.lunak@kde.org>
+ksavefile.cpp Waldo Bastian <bastian@kde.org>
+kshortcut.cpp Ellis Whitehead <ellis@kde.org>
+ksimpleconfig.cpp Waldo Bastian <bastian@kde.org>
+ksocks.cpp
+kstandarddirs.cpp Waldo Bastian <bastian@kde.org>
+kstartupinfo.cpp Lubos Lunak <l.lunak@kde.org>
+kstaticdeleter.cpp Stephan Kulow <coolo@kde.org>
+kstdaccel.cpp Ellis Whitehead <ellis@kde.org>
+kstringhandler.cpp
+ksycoca.cpp Waldo Bastian <bastian@kde.org>
+ksycocadict.cpp Waldo Bastian <bastian@kde.org>
+ksycocafactory.cpp Waldo Bastian <bastian@kde.org>
+ktempfile.cpp Waldo Bastian <bastian@kde.org>
+kuniqueapplication.cpp Waldo Bastian <bastian@kde.org>
+kurl.cpp Waldo Bastian <bastian@kde.org>
+kurldrag.cpp David Faure <faure@kde.org>
+kwin.cpp Lubos Lunak <l.lunak@kde.org>
+kwinmodule.cpp Lubos Lunak <l.lunak@kde.org>
+kxmessages.cpp Lubos Lunak <l.lunak@kde.org>
+kxerrorhandler.cpp Lubos Lunak <l.lunak@kde.org>
+libintl.cpp Hans Petter Bieker <bieker@kde.org>
+akasyncio.cpp Thiago Macieira <thiago@kde.org>
+kbufferedio.cpp Thiago Macieira <thiago@kde.org>
+kextsock.cpp Thiago Macieira <thiago@kde.org>
+kidna.cpp Thiago Macieira <thiago@kde.org>
+ksock.cpp Thiago Macieira <thiago@kde.org>
+ksockaddr.cpp Thiago Macieira <thiago@kde.org>
+netsupp.cpp Thiago Macieira <thiago@kde.org>
+network/ Thiago Macieira <thiago@kde.org>
+netwm.cpp Lubos Lunak <l.lunak@kde.org>
+kapplication_win.cpp Jaroslaw Staniek <js@iidea.pl> (copyright)
+kcalendarsystem.cpp
+kcalendarsystemfactory.cpp
+kcalendarsystemgregorian.cpp
+kcalendarsystemhebrew.cpp Hans Petter Bieker <bieker@kde.org> (copyright)
+kcalendarsystemhijri.cpp
+kcalendarsystemjalali.cpp Arash Bijanzadeh and FarsiKDE Project <www.farsikde.org> (copyright)
+kcheckaccelerators.cpp Matthias Kalle Dalheimer (kalle@kde.org) (copyright)
+kclipboard.cpp Carsten Pfeiffer <pfeiffer@kde.org> (copyright)
+kconfigdialogmanager.cpp
+kconfigskeleton.cpp
+kdebugdcopiface.cpp Andreas Beckermann (b_mann@gmx.de) (copyright)
+kdeversion.cpp
+kglobalaccel_win.cpp Ellis Whitehead <ellis@kde.org> (copyright)
+kkeyserver_x11.cpp
+klockfile.cpp Waldo Bastian <bastian@kde.org> (copyright)
+kmacroexpander.cpp
+kmanagerselection.cpp Lubos Lunak <l.lunak@kde.org> (copyright)
+kmountpoint.cpp Waldo Bastian <bastian@kde.org> (copyright)
+kprotocolinfo_kdecore.cpp Torben Weis <weis@kde.org> (copyright)
+kprotocolinfofactory.cpp Torben Weis <weis@kde.org> (copyright)
+kprotocolinfofactory.cpp Waldo Bastian <bastian@kde.org> (copyright)
+kpty.cpp
+kshell.cpp Oswald Buddenhagen <ossi@kde.org> (copyright)
+kshortcutmenu.cpp Ellis Whitehead <ellis@kde.org> (copyright)
+ktempdir.cpp Joseph Wenninger <jowenn@kde.org> (copyright)
+kuser.cpp Tim Jansen <tim@tjansen.de> (copyright)
+kvmallocator.cpp Waldo Bastian (bastian@kde.org) (copyright)
+netsupp_win32.cpp
diff --git a/kdecore/Mainpage.dox b/kdecore/Mainpage.dox
new file mode 100644
index 000000000..338b27ae5
--- /dev/null
+++ b/kdecore/Mainpage.dox
@@ -0,0 +1,44 @@
+/** \mainpage The KDE Core Library
+
+All KDE programs use this library to provide basic functionality such
+as the configuration system, IPC, internationalization and locale
+support, site-independent access to the filesystem and a large number
+of other (but no less important) things.
+<p>
+All KDE applications should link to the kdecore library. Also, using a
+KApplication derived class instead of QApplication is almost
+mandatory if you expect your application to behave nicely within the
+KDE environment.
+
+If you are unsure where to start, have a look at the
+<a href="http://techbase.kde.org/Development/Tutorials">tutorials on
+TechBase</a> to get you going.
+
+If you know what you are looking for, you should be able to find it in
+the <a href="annotated.html">class list</a> or the
+<a href="modules.html">modules list</a>.
+
+@authors
+Various: see copyrights on individual files for more information
+
+@maintainers
+See the
+<a href="http://websvn.kde.org/trunk/KDE/kdelibs/kdecore/MAINTAINERS?view=markup">MAINTAINERS</a>
+file.
+
+@licenses
+Library: @lgpl<br>
+Some helper utilities: @gpl
+
+*/
+
+/**
+
+\defgroup KDEMacros KDE Macros
+
+*/
+
+// DOXYGEN_EXCLUDE = malloc kde_file.h
+// DOXYGEN_SET_INPUT += @topdir@/kdemacros.h.cmake
+// DOXYGEN_SET_PROJECT_NAME = KDECore
+// vim:ts=4:sw=4:expandtab:filetype=doxygen
diff --git a/kdecore/Makefile.am b/kdecore/Makefile.am
new file mode 100644
index 000000000..b312a0e24
--- /dev/null
+++ b/kdecore/Makefile.am
@@ -0,0 +1,189 @@
+# This file is part of the KDE libraries
+#
+# $Id$
+#
+# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997 Stephan Kulow (coolo@kde.org)
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+
+# This library 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+INCLUDES = -I$(top_srcdir)/kdefx -I$(top_srcdir)/kdecore/network $(all_includes) $(LIBART_CFLAGS)
+
+if include_SVGICONS
+SVGICONS=svgicons
+SVGICON_LIB=svgicons/libkdesvgicons.la
+endif
+
+SUBDIRS = malloc network $(SVGICONS) . kconfig_compiler tests
+
+# For the future: examine if condensing the tons of *_LDFLAGS variables
+# into $(all_libraries) isn't better
+AM_LDFLAGS = $(LDFLAGS_AS_NEEDED) $(LDFLAGS_NEW_DTAGS)
+
+lib_LTLIBRARIES = libkdefakes.la libkdecore.la
+lib_LIBRARIES = libkdefakes_nonpic.a
+
+include_HEADERS = kconfig.h kconfigskeleton.h \
+ kconfigdata.h ksimpleconfig.h kconfigdialogmanager.h \
+ kconfigbase.h kdesktopfile.h kurl.h ksock.h kaboutdata.h \
+ kcmdlineargs.h kconfigbackend.h kapp.h kapplication.h kuniqueapp.h \
+ kuniqueapplication.h kcharsets.h kdeversion.h kpty.h kprocess.h \
+ kprocctrl.h klocale.h kicontheme.h kiconloader.h kdebug.h \
+ kwinmodule.h kwin.h krootprop.h kshortcut.h kkeynative.h kaccel.h \
+ kglobalaccel.h kstdaccel.h kshortcutlist.h kcatalogue.h \
+ kregexp.h kcompletion.h kstringhandler.h \
+ kstddirs.h kstandarddirs.h kglobal.h kglobalsettings.h ksharedptr.h \
+ kallocator.h kvmallocator.h kcrash.h krfcdate.h \
+ kinstance.h kpalette.h kipc.h klibloader.h ktempfile.h ksavefile.h \
+ krandomsequence.h knotifyclient.h kiconeffect.h \
+ kaudioplayer.h kdcoppropertyproxy.h netwm.h kaccelmanager.h \
+ netwm_def.h kpixmapprovider.h kunload.h kstaticdeleter.h \
+ kextsock.h kextendedsocket.h ksockaddr.h kprocio.h kasyncio.h \
+ kbufferedio.h kurldrag.h kmimesourcefactory.h kmdcodec.h ksocks.h \
+ ksycoca.h ksycocaentry.h ksycocatype.h kxmessages.h kstartupinfo.h \
+ klargefile.h kmultipledrag.h kgenericfactory.h kgenericfactory.tcc \
+ ktypelist.h ksortablevaluelist.h kdebugclasses.h kclipboard.h \
+ kcalendarsystem.h kcalendarsystemfactory.h kmacroexpander.h \
+ kmanagerselection.h kmountpoint.h kuser.h klockfile.h \
+ kidna.h ktempdir.h kshell.h fixx11h.h kxerrorhandler.h kdelibs_export.h \
+ kdemacros.h kde_file.h ktimezones.h
+
+libkdefakes_la_SOURCES = fakes.c vsnprintf.c
+libkdefakes_la_LDFLAGS = -version-info 6:0:2
+libkdefakes_la_LIBADD = $(LIBSOCKET)
+
+libkdefakes_nonpic_a_SOURCES = fakes_nonpic.c vsnprintf_nonpic.c
+
+fakes_nonpic.c:$(srcdir)/fakes.c
+ -rm -f fakes_nonpic.c
+ $(LN_S) $(srcdir)/fakes.c fakes_nonpic.c
+
+vsnprintf_nonpic.c: $(srcdir)/vsnprintf.c
+ -rm -f vsnprintf_nonpic.c
+ $(LN_S) $(srcdir)/vsnprintf.c vsnprintf_nonpic.c
+
+noinst_HEADERS = kaccelaction.h kaccelbase.h kaccelprivate.h kckey.h \
+ kcompletion_private.h netwm_p.h \
+ kglobalaccel_x11.h kglobalaccel_win.h kkeyserver_x11.h kkeyserver.h \
+ kregpriv.h kshortcutmenu.h ksycocadict.h ksycocafactory.h netsupp.h \
+ kcheckaccelerators.h kcalendarsystemgregorian.h \
+ kcalendarsystemhijri.h kcalendarsystemhebrew.h kcalendarsystemjalali.h \
+ kprotocolinfofactory.h kqiodevicegzip_p.h kiconloader_p.h
+
+libkdecore_la_SOURCES = libintl.cpp kapplication.cpp \
+ kdebug.cpp netwm.cpp kconfigbase.cpp kconfig.cpp ksimpleconfig.cpp \
+ kconfigbackend.cpp kmanagerselection.cpp kdesktopfile.cpp \
+ kstandarddirs.cpp ksock.cpp kpty.cpp kprocess.cpp kprocctrl.cpp \
+ klocale.cpp krfcdate.cpp kiconeffect.cpp kicontheme.cpp \
+ kiconloader.cpp kwin.cpp kwinmodule.cpp krootprop.cpp kcharsets.cpp \
+ kckey.cpp kshortcut.cpp kkeynative_x11.cpp kkeyserver_x11.cpp \
+ kaccelaction.cpp kshortcutmenu.cpp kaccelbase.cpp kaccel.cpp \
+ kglobalaccel_x11.cpp kglobalaccel.cpp kstdaccel.cpp kshortcutlist.cpp \
+ kcrash.cpp kurl.cpp kregexp.cpp kglobal.cpp kglobalsettings.cpp \
+ kallocator.cpp kvmallocator.cpp kmimesourcefactory.cpp \
+ kinstance.cpp kpalette.cpp kipc.cpp klibloader.cpp ktempfile.cpp \
+ kuniqueapplication.cpp kaccelmanager.cpp \
+ ksavefile.cpp krandomsequence.cpp kstringhandler.cpp kcompletion.cpp \
+ kcmdlineargs.cpp kaboutdata.cpp kcompletionbase.cpp knotifyclient.cpp \
+ kaudioplayer.cpp kdcoppropertyproxy.cpp \
+ ksockaddr.cpp kextsock.cpp netsupp.cpp kprocio.cpp kbufferedio.cpp \
+ kpixmapprovider.cpp kurldrag.cpp \
+ kmdcodec.cpp ksocks.cpp fakes.c vsnprintf.c \
+ ksycoca.cpp ksycocadict.cpp ksycocafactory.cpp ksycoca.skel \
+ kxmessages.cpp kstartupinfo.cpp kcatalogue.cpp kasyncio.cpp \
+ kmultipledrag.cpp kstaticdeleter.cpp kappdcopiface.cpp \
+ kappdcopiface.skel kclipboard.cpp kcheckaccelerators.cpp \
+ kdeversion.cpp kdebugdcopiface.cpp kdebugdcopiface.skel \
+ kcalendarsystem.cpp kcalendarsystemgregorian.cpp \
+ kcalendarsystemhijri.cpp kcalendarsystemhebrew.cpp \
+ kcalendarsystemfactory.cpp kmacroexpander.cpp kidna.cpp \
+ ktempdir.cpp kshell.cpp kmountpoint.cpp kcalendarsystemjalali.cpp \
+ kprotocolinfo_kdecore.cpp kprotocolinfofactory.cpp kxerrorhandler.cpp \
+ kuser.cpp kconfigskeleton.cpp kconfigdialogmanager.cpp klockfile.cpp \
+ kqiodevicegzip_p.cpp ktimezones.cpp
+
+libkdecore_la_LDFLAGS = $(QT_LDFLAGS) $(KDE_RPATH) $(KDE_MT_LDFLAGS) $(X_LDFLAGS) $(USER_LDFLAGS) -version-info 6:0:2 -no-undefined
+libkdecore_la_LIBADD = malloc/libklmalloc.la network/libkdecorenetwork.la $(SVGICON_LIB) ../dcop/libDCOP.la ../libltdl/libltdlc.la $(LIB_XEXT) $(LIBRESOLV) $(LIBUTIL) $(LIBART_LIBS) $(LIB_IDN) ../kdefx/libkdefx.la
+libkdecore_la_NMCHECK = $(srcdir)/libkdecore.nmcheck
+libkdecore_la_NMCHECKWEAK = $(srcdir)/libkdecore_weak.nmcheck $(srcdir)/libqt-mt_weak.nmcheck \
+ $(top_srcdir)/dcop/libDCOP_weak.nmcheck $(top_srcdir)/kdecore/standard_weak.nmcheck
+
+libkdecore_la_METASOURCES = AUTO
+
+SRCDOC_DEST=$(kde_htmldir)/en/kdelibs/kdecore
+
+kdebugdir = $(kde_confdir)
+kdebug_DATA = kdebug.areas kdebugrc language.codes
+
+.PHONY: kckey_h parser
+kckey_h : $(srcdir)/generate_keys.sh $(QNAMESPACE_H)
+ (cd $(srcdir) && ./generate_keys.sh $(QNAMESPACE_H))
+
+# Also uninstall the old names of the KDE color palette files
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_locale)
+ $(INSTALL_DATA) $(srcdir)/all_languages.desktop $(DESTDIR)$(kde_locale)/all_languages
+ $(mkinstalldirs) $(DESTDIR)$(includedir)/kio
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/knotify
+ $(INSTALL_DATA) $(srcdir)/eventsrc $(DESTDIR)$(kde_datadir)/knotify/eventsrc
+ $(INSTALL_DATA) $(srcdir)/kmdcodec_compat.h $(DESTDIR)$(includedir)/kio/kmdcodec.h
+ rm -f "$(DESTDIR)$(kde_confdir)/colors/40 Colors"
+ rm -f $(DESTDIR)$(kde_confdir)/colors/Web
+ rm -f $(DESTDIR)$(kde_confdir)/colors/Royal
+
+uninstall-local:
+ -rm -f $(DESTDIR)$(includedir)/kio/kmdcodec.h
+
+# If you add a color palette file here, please change kdelibs/kdeui/kcolordialog.cpp too to allow to translate the name
+colors_DATA = 40.colors Web.colors Royal.colors Rainbow.colors
+colorsdir = $(kde_confdir)/colors
+
+EXTRA_DIST = generate_keys.sh $(kdebug_DATA) \
+ DESIGN.COLOR KCONFIG_DESIGN eventsrc \
+ kentities.c kentities.gperf makeentities kmdcodec_compat.h \
+ all_languages.desktop
+
+kcharsets.lo: kentities.c
+
+parser: kentities.gperf
+ cd $(srcdir) && gperf -a -L "ANSI-C" -E -C -c -o -t -k '*' -Nkde_findEntity -D -Hhash_Entity -Wwordlist_Entity -s 2 kentities.gperf > kentities.c
+
+bin_PROGRAMS = kde-config kgrantpty
+
+kde_config_SOURCES = kde-config.cpp
+kde_config_LDADD = ./libkdecore.la
+kde_config_LDFLAGS = $(KDE_RPATH) $(KDE_MT_LDFLAGS)
+
+kgrantpty_SOURCES = kgrantpty.c
+kgrantpty_CFLAGS= $(KDE_USE_FPIE)
+kgrantpty_LDFLAGS = $(KDE_USE_PIE) $(KDE_RPATH) $(all_libraries)
+kgrantpty_LDADD = ./libkdefakes.la
+
+# kgrantpty needs to be installed setuid root
+install-exec-hook:
+ @(chown 0 $(DESTDIR)$(bindir)/kgrantpty && chmod 4755 $(DESTDIR)$(bindir)/kgrantpty) || echo "Please make kgrantpty setuid root" >&2
+ @echo ""
+ @echo "kgrantpty is by default installed with a set SETUID root bit!"
+ @echo "This is needed for konsole, etc. to ensure that they can't be eavesdropped."
+ @echo ""
+
+DISTCLEANFILES = kde-config.cpp
+
+DOXYGEN_REFERENCES = dcop kdeui kparts kio
+DOXYGEN_EXCLUDE = malloc kde_file.h
+DOXYGEN_SET_WARN_IF_UNDOCUMENTED = YES
+
+include ../admin/Doxyfile.am
diff --git a/kdecore/README b/kdecore/README
new file mode 100644
index 000000000..0788341af
--- /dev/null
+++ b/kdecore/README
@@ -0,0 +1,3 @@
+This is the KDE "core" library. The kdecore library provides basic non user
+interface functionality.
+
diff --git a/kdecore/README.exec b/kdecore/README.exec
new file mode 100644
index 000000000..f2065b7ad
--- /dev/null
+++ b/kdecore/README.exec
@@ -0,0 +1,41 @@
+Starting other programs
+
+In KDE 2 and KDE 3 there are several ways to start other programs from within
+your application. Here is a short summary of your options with reasons why
+you should or should not use them.
+
+1. fork + exec
+
+You never want to use this unless you have a very good reason why it is
+impossible to use KProcess.
+
+2. KProcess
+
+You want to use this if you need to start a new process which needs to be a
+child of your process, e.g. because you want to catch stdout/stderr or need
+to send it data via stdin. You should never use this to start other KDE
+applications unless your application is called kgdb :-) If you need to
+send/receive text like data to/from the process, you are probably better
+off with KProcIO
+
+3. KProcIO
+
+Like KProcess. Unlike KProcess, this class actually makes it easy to
+send data to and receive data from the process.
+
+4. startServiceByDesktopPath
+
+Preferred way to launch desktop (KDE/Gnome/X) applications or KDE services.
+The application/service must have a .desktop file. It will make use of
+KDEinit for increased startup performance and lower memory usage. These
+benefits only apply to applications available as KDEinit loadable module (KLM)
+
+5. KRun
+
+Generic way to open documents/applications/shell commands. Uses
+startServiceBy.... where applicable. Offers the additional
+benefit of startup-notification.
+KRun can start any application, from the binary or the desktop file,
+it will determine the mimetype of a file before running the
+preferred handler for it, and it can also start shell commands.
+This makes KRun the recommended way to run another program in KDE 2.
diff --git a/kdecore/README.kiosk b/kdecore/README.kiosk
new file mode 100644
index 000000000..cd59f8db3
--- /dev/null
+++ b/kdecore/README.kiosk
@@ -0,0 +1,681 @@
+In KDE3 a kiosk-framework has been introduced.
+
+One of the driving forces behind KDE is to put the user in control and
+give him or her a large amount of possibilities to adjust KDE to his or her
+liking. However, in some situations it is required to reduce the possibilities
+of KDE, e.g. because the system is to be used for one or more specific
+dedicated tasks only.
+
+The kiosk-framework provides an easy way to disable certain features within
+KDE to create a more controlled environment.
+
+KDE's kiosk-framework builds on KDE's configuration framework and adds a
+simple application API that applications can query to get authorisation
+for certain operations.
+
+The KDE kiosk-framework should be used IN ADDITION to the standard UNIX
+security measures.
+
+The configuration framework in KDE3
+===================================
+
+Since the very beginning KDE makes use of file-hierarchy to store resources
+for its applications. Resources range from icons, wallpapers, fonts to
+sounds, menu-descriptions and configuration files.
+
+In KDE1 there were two locations were resources could be located: The
+resources provided by the system were located under $KDEDIR and user-
+specific resources were located under $HOME/.kde.
+
+In KDE2 resource management has been largely abstracted by the introduction
+of the KStandardDirs class and has become much more flexible. The user /
+administrator can now specify a variable number of locations where resources
+can be found. A list of locations can either be specified via $KDEDIRS
+(notice the extra 'S'), via /etc/kderc and even via the kdeglobals config
+file. The location where user-specific resources can be found can be
+set with $KDEHOME (The default is $HOME/.kde). Changes made by the user
+are always written back to $KDEHOME.
+
+Both KDE1 and KDE2 feature so called "cascading configuration files": There
+can be multiple configuration files with the same name in the various
+locations for (config) resources, when that is the case, the information of
+all these configuration files is combined on a key by key basis. If the same
+key (within a certain group) is defined in more than one place, the value
+of the key for the config file that was read last will override any previously
+read values. Configuration files under $KDEHOME are always read last. This
+ensures that after a configuration entry is written, the same value wil be
+read back.
+
+In KDE3 two important changes have been made:
+
+* Default values are no longer written.
+When a configuration file in a location other than $KDEHOME defines a value
+for a key and the application subsequently writes out a new configuration file
+to $KDEHOME, that configuration file will only contain an entry for the key
+if its value differs from the value read from the other file.
+
+This counters the problem that changing default configuration files under
+$KDEDIR would not take effect for users, since these users would most likely
+have their own copy of these settings under $KDEHOME. KDE3 will make sure
+not to copy these settings so changes made under $KDEDIR will affect all users
+that haven't explicitly changed the affected settings to something else.
+
+* Configuration entries can be marked "immutable".
+Starting with KDE3, configuration entries can be marked "immutable". When a
+configuration entry is immutable it means that configuration files that are
+read later will not be able to override its value. Immutable entries cannot
+be changed via KConfig and if the entry is present under $KDEHOME it will
+be ignored.
+
+Entries can be marked immutable on 4 different levels:
+
+- On an entry by entry basis by appending "[$i]" after the key.
+
+Example:
+[MyGroup]
+someKey[$i]=42
+
+- On a group by group basis by appending "[$i]" after the group. All entries
+specified in the group will be marked immutable and no new entries can be
+added to the group.
+
+Example:
+[MyGroup][$i]
+someKey=42
+
+- On a file by file basis by starting the file with [$i].
+
+Example:
+[$i]
+[MyGroup]
+someKey=42
+[MyOtherGroup]
+someOtherKey=11
+
+- On a directory basis. [Not yet implemented]
+
+- The filesystem can also be used to mark files immutable. If KDE does not
+have write-access to the user's version of a configuration file, the file
+will be automatically considered immutable.
+
+To make the configration file of kicker (the panel) immutable one could for
+example use the commands below.
+
+Example:
+chown root.root /home/user/.kde/share/config/kickerrc
+chmod 644 /home/user/.kde/share/config/kickerrc
+
+If you do this, the user will be warned that the configuration file is not
+writable. Since you will normally not want that, you can add the following
+two lines to the application's configuration file (or to kdeglobals to
+disable the warning for all applications):
+
+[KDE Action Restrictions]
+warn_unwritable_config=false
+
+Note that the avove example is not fool-proof, the user can potentially still
+rename either the root-owned kickerrc file or any of the directories in
+the path to another name and create a new kickerrc _with_ write-access.
+
+KDE3 Action Restrictions
+========================
+
+Most functionality within KDE is coupled to so called actions. For example when a user
+selects the File->Open option in the menubar of a KDE application, the "file_open"
+action is activated. Likewise, toolbar icons are usually also coupled to actions. KDE
+makes it possible to disable functionality by restricting specific actions. By restricting the
+"file_open" action for example, the corresponding entry in the menubar and the corresponding icon on
+the toolbar, if any, will disappear.
+
+To restrict access to function the kdeglobals file should contain the
+group "[KDE Action Restrictions]", each action can then be restricted by
+adding "<action>=false". E.g. to disable the action "shell_access" one
+would add:
+[KDE Action Restrictions][$i]
+shell_access=false
+
+Actions that refer to menu and toolbar actions are prefixed with 'action/'.
+The following standard actions are defined:
+
+action/file_new
+action/file_open
+action/file_open_recent
+action/file_save
+action/file_save_as
+action/file_revert
+action/file_close
+action/file_print
+action/file_print_preview
+action/file_mail
+action/file_quit
+action/edit_undo
+action/edit_redo
+action/edit_cut
+action/edit_copy
+action/edit_paste
+action/edit_select_all
+action/edit_deselect
+action/edit_find
+action/edit_find_next
+action/edit_find_last
+action/edit_replace
+action/view_actual_size
+action/view_fit_to_page
+action/view_fit_to_width
+action/view_fit_to_height
+action/view_zoom_in
+action/view_zoom_out
+action/view_zoom
+action/view_redisplay
+action/go_up
+action/go_back
+action/go_forward
+action/go_home
+action/go_previous
+action/go_next
+action/go_goto
+action/go_goto_page
+action/go_goto_line
+action/go_first
+action/go_last
+action/bookmarks // See note below
+action/bookmark_add
+action/bookmark_edit
+action/tools_spelling
+action/options_show_menubar
+action/options_show_toolbar // See note below
+action/options_show_statusbar
+action/options_save_options
+action/options_configure
+action/options_configure_keybinding
+action/options_configure_toolbars
+action/options_configure_notifications
+action/help // See note below
+action/help_contents
+action/help_whats_this
+action/help_report_bug
+action/help_about_app
+action/help_about_kde
+action/fullscreen
+
+Actions in the KDE File Dialog:
+action/home // Go to home directory
+action/up // Go to parent directory
+action/back // Go to previous directory
+action/forward // Go to next directory
+action/reload // Reload directory
+action/mkdir // Create new directory
+action/toggleSpeedbar // Show/hide sidebar
+action/sorting menu // Sorting options
+action/short view // Select short view
+action/detailed view // Select detailed view
+action/show hidden // Show/hide hidden files
+action/preview // Show/hide preview
+action/separate dirs // Show/hide separate directories
+
+
+Konqueror & KDesktop related:
+action/editfiletype
+action/properties
+action/openwith
+action/openintab
+action/kdesktop_rmb // RMB menu, see note below
+action/iconview_preview
+action/sharefile // File sharing, see note below
+action/sendURL // Send Link Address
+action/sendPage // Send File
+action/devnew // Create New -> Device
+action/incIconSize // Increase icon size
+action/decIconSize // Decrease icon size
+action/go // Entire go menu
+action/configdesktop // Configure desktop in RMB menu, see also Control Module Restrictions
+action/executeshellcommand // In Konqueror Tools menu, see also shell_access
+action/show_dot // Show Hidden Files, see note below
+
+
+Kicker related:
+action/kicker_rmb // RMB menu
+action/menuedit
+
+
+KWin related:
+action/kwin_rmb // RMB window context menu
+
+Konsole related:
+action/konsole_rmb // RMB context menu
+
+action/settings // Entire settings menu
+action/show_menubar
+action/show_toolbar
+action/scrollbar
+action/fullscreen
+action/bell
+action/font
+action/keyboard
+action/schema
+action/size
+action/history
+action/save_default
+action/save_sessions_profile
+action/options_configure_notifications
+action/options_configure_keybinding
+action/options_configure
+
+action/send_signal
+action/bookmarks
+action/add_bookmark
+action/edit_bookmarks
+action/clear_terminal
+action/reset_clear_terminal
+action/find_history
+action/find_next
+action/find_previous
+action/save_history
+action/clear_history
+action/clear_all_histories
+action/detach_session
+action/rename_session
+action/zmodem_upload
+action/monitor_activity
+action/monitor_silence
+action/send_input_to_all_sessions
+action/close_session
+action/new_session
+action/activate_menu
+action/list_sessions
+action/move_session_left
+action/move_session_right
+action/previous_session
+action/next_session
+action/switch_to_session_1
+action/switch_to_session_2
+action/switch_to_session_3
+action/switch_to_session_4
+action/switch_to_session_5
+action/switch_to_session_6
+action/switch_to_session_7
+action/switch_to_session_8
+action/switch_to_session_9
+action/switch_to_session_10
+action/switch_to_session_11
+action/switch_to_session_12
+action/bigger_font
+action/smaller_font
+action/toggle_bidi
+
+
+
+Notes:
+* action/options_show_toolbar will also disable the "Toolbars" submenu
+ if present.
+* action/bookmarks also disables action/bookmark_add and action/bookmark_edit
+* action/help is not yet fully implemented
+* action/kdesktop_rmb disables the RMB menu but some actions may still be accesible
+ via keyboard shortcuts: cut/copy/rename/trash/delete
+* action/iconview_preview disables the option to toggle previews on or off
+ in icon mode but the actual preview settings remains unaffected.
+ To disable previews you also need to add the following lines to
+ konqiconviewrc:
+ [Settings]
+ PreviewsEnabled[$i]=false
+* action/show_dot disables the option to toggle showing hidden files, the actual
+ setting remains unaffected.
+ To disable showing hidden files, add the following lines to konqiconviewrc:
+ [Settings]
+ ShowDotFiles[$i]=false
+* action/sharefile disables file sharing from the UI, but you may also want
+ to disable filesharing altogether.
+
+
+Applications may use additional actions that they defined themselves.
+You can get a list of the actions used by a certain applications by using the
+following dcop command:
+
+dcop <dcopid> qt objects | grep KActionCollection/ | cut -d '/' -f 3
+
+or with
+
+dcop <dcopid> <maindwindowid> actions
+
+
+Actions that refer to applications that need to be run as a different user
+are prefixed by user/ and identified by the username. For example:
+
+user/root=false
+
+will disable all application entries that require root access.
+
+
+Printing related action restrictions:
+
+print/system
+ - disables the option to select the printing system (backend). It is
+ recommended to disable this option once the correct printing
+ system has been configured.
+
+print/properties
+ - disables the button to change printer properties or to add a new printer.
+
+print/options
+ - disables the button to select additional print options.
+
+print/copies
+ - disables the panel that allows users to make more than one copy.
+
+print/selection
+ - disables the options that allows selecting a (pseudo) printer or
+ change any of the printer properties. Make sure that a proper
+ default printer has been selected before disabling this option.
+ Disabling this option also disables print/system, print/options
+ and print/properties.
+
+print/dialog
+ - disables the complete print dialog. Selecting the print option will
+ immediately print the selected document using default settings.
+ Make sure that a system wide default printer has been selected.
+ No application specific settings are honored.
+
+Other defined actions:
+
+shell_access
+ - defines whether a shell suitable for entering random commands
+ may be started. This also determines whether the "Run Command"
+ option (Alt-F2) can be used to run shell-commands and arbitrary
+ executables. Likewise, executables placed in the user's
+ Autostart folder will no longer be executed. Applications can
+ still be autostarted by placing .desktop files in the $KDEHOME/Autostart
+ or $KDEDIR/share/autostart directory.
+ See also run_desktop_files.
+
+custom_config
+ - defines whether the --config command line option should be honored.
+ The --config command line option can be used to circumvent
+ locked-down configuration files.
+
+logout
+ - defines whether the user will be able to logout from KDE.
+
+lock_screen
+ - defines whether the user will be able to lock the screen.
+
+run_command
+ - defines whether the "Run Command" (Alt-F2) option is available.
+
+movable_toolbars
+ - define whether toolbars may be moved around by the user.
+ See also action/options_show_toolbar.
+
+editable_desktop_icons
+ - define whether icons on the desktop can be moved, renamed,
+ deleted or added. You might want to set the path for
+ the Desktop to some read-only directory as well.
+ (Instead of $HOME/Desktop)
+
+run_desktop_files
+ - defines whether users may execute desktop files that are not
+ part of the default desktop, KDE menu, registered services and
+ autostarting services.
+ * The default desktop includes the files under
+ $KDEDIR/share/kdesktop/Desktop but _NOT_ the files under
+ $HOME/Desktop.
+ * The KDE menu includes all files under $KDEDIR/share/applnk and
+ $XDGDIR/applications
+ * Registered services includes all files under $KDEDIR/share/services.
+ * Autostarting services include all files under $KDEDIR/share/autostart
+ but _NOT_ the files under $KDEHOME/Autostart
+
+ You probably also want to activate the following resource
+ restictions:
+ "appdata_kdesktop" - To restrict the default desktop.
+ "apps" - To restrict the KDE menu.
+ "xdgdata-apps" - To restrict the KDE menu.
+ "services" - To restrict registered services.
+ "autostart" - To restrict autostarting services.
+ Otherwise users can still execute .desktop files by placing them
+ in e.g. $KDEHOME/share/kdesktop/Desktop
+
+lineedit_text_completion
+ - defines whether input lines should have the potential to remember
+ any previously entered data and make suggestions based on this
+ when typing. When a single account is shared by multiple people you
+ may wish to disable this out of privacy concerns.
+
+start_new_session
+ - defines whether the user may start a second X session.
+ See also the kdm configuration.
+
+switch_user
+ - defines whether user switching via kdm is allowed
+
+skip_drm
+ - defines if the user may omit DRM checking.
+ Currently only used by kpdf
+
+Screensaver related:
+opengl_screensavers
+ - defines whether OpenGL screensavers are allowed to be used.
+
+manipulatescreen_screensavers
+ - defines whether screensavers that manipulate an image of the screen
+ (e.g. moving chunks of the screen around) are allowed to be used.
+
+When configuration files are marked immutable in whole or in part the user will no
+longer be able to make permanent changes to the settings that have been marked
+immutable. Ideally the application will recognize this and will no longer offer the
+user the possibility to change these settings. Unfortunately not all applications
+support this at the moment. It's therefor possible that the user will still be
+presented with an option in the user interface to change a setting that is
+immutable, changes made this way will not be saved though. In some cases the
+user may be able to use the changed setting till the application terminates, in
+other cases the changed setting will simply be ignored and the application will
+continue to work with the immutable setting.
+
+The following applications currently detect when their configuration files have been
+marked immutable and adjust their user interface accordingly:
+
+* kicker - By marking the kickerrc config file as immutable, the panel will be
+"locked down" and it will not be possible to make any changes to it.
+
+* kdesktop - By marking the kdesktoprc config file as immutable, the desktop
+will be "locked down" and it will no longer be possible to select
+"Configure Desktop" from its menus.
+
+* kcalc - By marking the kcalcrc config file as immutable, the "Configure" button
+will not be shown
+
+Application .desktop files can have an additional field "X-KDE-AuthorizeAction".
+If this field is present the .desktop file is only considered if the action(s)
+mentioned in this field has been authorized. If multiple actions are listed
+they should be separated by commas (','). So if the .desktop file of an application
+lists one or more actions this way and the user has no authorization for one
+of these actions then the application will not appear in the KDE menu and will not
+be used by KDE for opening files.
+
+IMPORTANT NOTE:
+Changing restrictions may influence the data that is cached in the ksycoca
+database. Since changes to .../share/config/kdeglobals do not trigger an
+automatic ksycoca update you need to force an update manually.
+To force an update of the ksycoca database touch the file
+.../share/services/update_ksycoca. This will force a user's sycoca database
+to be rebuild the next time the user logs in.
+
+KDE3 URL Restrictions
+=====================
+
+It is also possible to restrict URL related actions. The restriction framework
+can disable URL actions based on the action, the URL in question and in some cases
+the referring URL. URLs can be matched based on protocol, host and path.
+
+The syntax for adding URL action restrictions to kdeglobals is as follows:
+
+[KDE URL Restrictions]
+rule_count=<N>
+rule_1=<action>,<referingURL_protocol>,<referingURL_host>,<referingURL_path>,<URL_protocol>,<URL_host>,<URL_path>,<enabled>
+...
+rule_N=<action>,<referingURL_protocol>,<referingURL_host>,<referingURL_path>,<URL_protocol>,<URL_host>,<URL_path>,<enabled>
+
+The following actions are supported:
+redirect - e.g. a html-page obtained via HTTP could redirect itself to file:/path/some-file. This
+ is disabled by default but could be explicitly enabled for a specific HTTP host.
+ This also applies to links contained in html documents.
+ Example: rule_1=redirect,http,myhost.acme.com,,file,,,true
+
+list - This controls which directories can be browsed with KDE's file-dialogs. If a user
+ should only be able to browse files under home directory one could use:
+ rule_1=list,,,,file,,,false
+ rule_2=list,,,,file,,$HOME,true
+ The first rule disables browing any directories on the local filesystem. The second rule
+ then enables browsing the users home directory.
+
+open - This controls which files can be opened by the user in applications. It also
+ affects where users can save files. To only allow a user to open the files
+ in his own home directory one could use:
+ rule_1=open,,,,file,,,false
+ rule_2=open,,,,file,,$HOME,true
+ rule_3=open,,,,file,,$TMP,true
+ Note that with the above, users would still be able to open files from
+ the internet. Note that the user is also given access to $TMP in order to
+ ensure correct operation of KDE applications. $TMP is replaced with the
+ temporary directory that KDE uses for this user.
+
+Some remarks:
+* empty entries match everything
+* host names may start with a wildcard, e.g. "*.acme.com"
+* a protocol also matches similar protocols that start with the same name,
+ e.g. "http" matches both http and https. You can use "http!" if you only want to
+ match http (and not https)
+* specifying a path matches all URLs that start with the same path. For better results
+ you should not include a trailing slash. If you want to specify one specific path, you can
+ add an exclamation mark. E.g. "/srv" matches both "/srv" and "/srv/www" but "/srv!" only
+ matches "/srv" and not "/srv/www".
+
+
+KDE3 Resource Restrictions
+==========================
+Most KDE applications make use of additional resource files that are typically
+located in directories under $KDEDIR/share. By default KDE allows users to
+override any of these resources by placing files in the same location
+under $KDEHOME/share. For example, Konsole stores profiles under
+$KDEDIR/share/apps/konsole and users can add additional profiles by
+installing files in $KDEHOME/share/apps/konsole.
+
+KDE3 Resource Restrictions make it possible to restrict the lookup of files
+to directories outside of $KDEHOME only.
+
+The following resources are defined:
+
+autostart - share/autostart
+data - share/apps
+html - share/doc/HTML
+icon - share/icon
+config - share/config
+pixmap - share/pixmaps
+apps - share/applnk
+xdgdata-apps - share/applications
+sound - share/sounds
+locale - share/locale
+services - share/services
+servicetypes - share/servicetypes
+mime - share/mimelnk
+wallpaper - share/wallpapers
+templates - share/templates
+exe - bin
+lib - lib
+
+For the purpose of resource restrictions there are two special resources:
+all - covers all resources
+data_<appname> - covers the sub section for <appname> in the data resource.
+
+To restrict resources the kdeglobals file should contain the
+group "[KDE Resource Restrictions]", each resource can then be restricted by
+adding "<resource>=false". E.g. to restrict the "wallpaper" resource to
+$KDEDIR/share/wallpapers one would add:
+[KDE Resource Restrictions][$i]
+wallpaper=false
+
+And to prevent a user from adding additional konsole profiles, one would add:
+[KDE Resource Restrictions][$i]
+data_konsole=false
+
+
+Control Module Restrictions
+===========================
+
+It is possible to restrict access to particular control modules.
+Although it is possible to remove control modules from the Control
+Center by editing the menu structure, such modules will then still
+be available to applications. A better way is to use the control
+module restrictions offered by KIOSK:
+
+[KDE Control Module Restrictions][$i]
+<menu-id>=false
+
+Some example menu-ids are:
+
+kde-display.desktop
+kde-proxy.desktop
+kde-screensaver.desktop
+
+See also kcmshell --list for a list of all the base names.
+
+Expansion of environment variables in KDE config files.
+=======================================================
+
+In KDE3.1 arbitrary entries in configuration files can contain environment
+variables. In order to use this the entry must be marked with [$e].
+
+Example:
+Name[$e]=$USER
+
+When the "Name" entry is read $USER will be replaced with the value of the
+$USER environment variable. Note that the application will replace $USER
+with the value of the environment variable after saving. To prevent this
+combine the $e option with $i (immmutable) option.
+
+Example:
+Name[$ei]=$USER
+
+The above will make that the "Name" entry will always return the value of
+the $USER environment variable. The user will not be able to change this entry.
+
+The following syntax is also supported:
+Name[$ei]=${USER}
+
+
+Shell Commands in KDE config files.
+===================================
+
+In KDE3.1 arbitrary entries in configuration files can contain shell
+commands. This way the value of a configuration entry can be determined
+dynamically at runtime. In order to use this the entry must be marked
+with [$e].
+
+Example:
+Host[$e]=$(hostname)
+
+
+KDE3 Kiosk Application API
+==========================
+
+Three new methods have been added to KApplication:
+
+- bool authorize(QString action); // Generic actions
+- bool authorizeKAction(QString action); // For KActions exclusively
+- bool authorizeURLAction(QString, referringURL, destinationURL) // URL Handling
+
+Automatic Logout
+================
+
+Since KDE 3.4 it is possible to automatically logout users that have been idle
+for a certain period of time.
+
+WARNING: Be careful with this option, logging out a user may result in dataloss!
+
+In kdesktoprc you can use the following entry to enable automatic logout:
+
+[ScreenSaver]
+AutoLogout=true
+AutoLogoutTimeout=600
+
+The AutoLogoutTimeout is the time in seconds that the user has to be idle before
+his session is logged out.
diff --git a/kdecore/README.kstartupinfo b/kdecore/README.kstartupinfo
new file mode 100644
index 000000000..233ccde1e
--- /dev/null
+++ b/kdecore/README.kstartupinfo
@@ -0,0 +1,282 @@
+$Id$
+
+
+Application startup notification
+Lubos Lunak <l.lunak@kde.org>
+--------------------------------
+--------------------------------
+
+
+ When a new application is started in KDE, together with it a startup
+notification is sent, which is used to show a startup entry in taskbar,
+the busy icon next to the cursor and put the window of the started app
+on correct desktop.
+ This application startup notification ( ASN for short in the following
+text ) usually works fine without problems, but some applications and
+some special cases may need special handling.
+ Right now, this is only an internal KDE standard, but since a toolkit
+support would improve the results a bit, I'll try to discuss this
+on http://www.freedesktop.org .
+
+
+Starting apps with ASN :
+-------------------------
+
+ When an application is started from the K-Menu or the minicli, and from other
+places, ASN is sent automatically for it, assuming a matching .desktop file
+is found for the starting application. Application without a .desktop file
+don't get ASN ( this may change, but it's unlikely as it creates too many
+ASNs which will stay too long until a timeout ). For improving the quality
+of ASN and reducing the number of ASNs that don't detect when the application
+has started, some .desktop file entries may be helpful ( see below ).
+ If you want to start an application in your code, prefer using KRun or
+KApplication::startServiceByXXX() calls. Classes like KProcess don't create
+ASN, so if you need to use it, you have to send it manually ( only in case
+ASN is useful in this case, it shouldn't be sent e.g. for system processes ).
+
+
+.desktop files :
+-----------------
+
+These following .desktop file entries affect ASN :
+
+X-KDE-StartupNotify=<bool>
+ - if true, this app/service will get app startup notify
+ - if false, this app/service will _not_ get app startup notify
+ - if not set
+ - if it's service, it will _not_ get app startup notify
+ - if it's app, it will get app startup notify, but
+ X-KDE-WMClass will be assumed to be "0" ( non-compliant )
+X-KDE-WMClass=<string>
+ - if set, and it's different from "0" ( without quotes ), this
+ is the WMClass value for startup notification
+ - if it's "0" ( without quotes ), such app is considered non-compliant,
+ and the startup notification will stop
+ - either if its windows is correctly detected using the default
+ WMClass value ( the name of the binary )
+ - or if a window is mapped that is not recognized ( doesn't have
+ neither _KDE_STARTUP_ID nor _NET_WM_PID property /*CHECKME*/),
+ it's assumed this window belongs to the started app;
+ the start-on-desktop feature won't work then too
+ - if not set, it defaults to the binary name of the app ( ok for most apps,
+ including KDE ones )
+ - to get the WMCLASS value for any app, run 'xprop' and click on the app's
+ window, WMCLASS value for this app should be any of the strings listed
+ in the WM_CLASS property ( it's usually the same as the name of the
+ app's binary file, in such case it doesn't need to be explicitly set )
+MapNotify=<bool>
+ - this key is obsolete
+ - true is equivalent to X-KDE-StartupNotify=true and no X-KDE-WMClass set
+ - false is equivalent to X-KDE-StartupNotify=true and X-KDE-WMClass=0
+ - many .desktop files in KDE ( especially in kdebase/kappfinder )
+ seem to have MapNotify=false even though it's not needed, this
+ needs to be checked and replaced by the needed X-KDE-* values,
+ often just X-KDE-StartupNotify=true should be enough
+
+ The best way to check if the entries are set correctly is to start
+the application and switch to other desktop. If the startup notification
+disappears and the application appears on the desktop on which it was
+started, it's correct ( with X-KDE-WMClass=0, the start-on-desktop
+feature may not work ).
+
+ Ideally, every .desktop file should have X-KDE-StartupNotify set to the correct
+value, and for apps which need it also X-KDE-WMClass should be set. This
+sometimes gives slightly better behavior than when these entries are not set.
+
+
+The KStartupInfo classes :
+--------------------------
+
+ In some cases, or if you are interested in getting the ASN information, you
+have to use the KStartupInfo classes in kdelibs/kdecore.
+
+Receiving the application startup notification information :
+------------------------------------------------------------
+
+ Create an instance of class KStartupInfo and connect to its slots, they
+will be emitted whenever a ASN info is received.
+ The clean_on_cantdetect argument to the constructor means whether all
+ASN info for non-compliant apps should be removed when a window is mapped
+which cannot be identified ( it's not possible to say if it belong to one
+of the starting applications or not ). If the argument is true, it is
+assumed that the window does belong to one of the starting applications,
+and all ASN info for non-compliant apps must be removed, otherwise the ASN
+info would timeout ( e.g. kdesktop sets it to true, otherwise the busy
+icon would sometimes stay for too long, which is oftern annoying ).
+On the other hand, KWin, which maps the first window of the starting apps
+to the given virtual desktop, sets it to false, because there's no visual
+representation and if a window for a starting non-compliant application is
+detected later, it still will be successfully places on the correct virtual
+desktop.
+ Note that the ASN info is often send in several messages, and the slots
+will be therefore emitted several times, with the updated info ( e.g. the
+binary name or PID is not know from the beginning ).
+
+Sending the application startup notification information :
+----------------------------------------------------------
+
+ Before an application is started, ASN info for it must be sent ( unless
+it's done by classes like KRun ). See e.g. KRun sources for details.
+ During the starting of the application, the info may need some updating
+( e.g. right after starting the app, the PID with hostname may be sent,
+or a PID change when KUniqueApplication forks into background ).
+ When it's detected that the started process exited, it an ASN info
+about the finished process should be sent. Since the application may
+have forked into background, the finish info should include the PID
+and hostname, and the notification will be stopped only if there's
+no other PID for it. On the other hand, if you simply really need
+to stop ASN, send only the identification ( KStartupInfo::sendFinish()
+with only KStartupInfoId argument ).
+
+
+
+Implementation details :
+------------------------
+
+ The ASN info data is sent using X ClientMessages as text ( see below ),
+this is mainly in hope also non-KDE people will start using it, and
+they wouldn't be very happy with DCOP.
+ Before starting an application, and environment variable called
+KDE_STARTUP_ENV is added to it's environment, and it's set to unique
+identifier of its startup notification, or "0" for disabled ASN.
+Ideally, the application should read it, and set a window property
+called _KDE_STARTUP_ID ( type XA_STRING ) at least on its first mapped
+toplevel window to this value. It should also unset it, so it doesn't get
+propagated to other applications started from it. It should also
+update the ASN info when necessary, e.g. when KUniqueApplication
+forks into background, it sends the PID change. That's how compliant
+applications should work, and this support for ASN should be provided
+by toolkits. All KDE application should be compliant by now, since
+kdelibs do all the necessary things. The KDE_STARTUP_ENV variable
+is read and unset in KApplication constructor, and _KDE_STARTUP_ID
+is set on every toplevel window in KApplication::setTopWidget().
+ However, majority of applications aren't compliant now, and even
+if I succeed making this thing a standard ( part of NETWM_SPEC
+or whatever ), there still will be old applications that won't behave
+this way. Not unsetting KDE_STARTUP_ENV is not a big problem, since
+the ASN for its value will usually timeout, and when the app starts
+a new application, this ASN identification value will get reused without
+problems. The other problem is detecting, which newly mapped windows
+belong to which starting application. If a newly mapped window doesn't
+have _KDE_STARTUP_ID property, the code tries to read its _NET_WM_PID
+property, and if it's set, it tries to match it ( together with
+WM_CLIENT_MACHINE ) with PIDs of all ASN infos. And if the window
+doesn't have even the _NET_WM_PID property, WM_CLASS property is used
+then. It's usually set to two strings, and at least one of them is
+usually the binary name of the application, so it's converted
+to lowercase and compared. For applications, where such comparison
+would fail, the X-KDE-WMClass .desktop file entry should be set
+to the correct WMClass value ( e.g. for XEmacs, the binary name
+is 'xemacs', but WM_CLASS is 'emacs', 'Emacs', so its X-KDE-WMClass
+in its .desktop file should be set to 'emacs' - the case doesn't
+matter ).
+ The ASN identification string must be a unique string for every ASN.
+In KStartupInfo class, it's created as 'hostname;tm.sec;tm.usec;pid',
+tm being the current time. If the identification string is set to "0",
+it means no ASN should be done ( e.g. for things like kio_uiserver,
+which shouldn't get ASN ). Empty identification string means the same
+like "0", except for the call to KStartupInfoId::initId(), where it means
+to create a new one.
+
+
+Format of the text messages :
+-----------------------------
+
+There are 3 types of messages :
+ - new: message
+ - this message announces that a new application is being started,
+ if there is not ASN info for this ASN identification, it should be
+ updated, otherwise it will be created
+ - the text of the message starts with 4 characters 'new:', followed
+ by the text entries ( see below )
+ - change: message
+ - this message is like new: message, but it's only for updating existing
+ ASN info, if there's no ASN info for the given identification, it won't
+ be created. This is used e.g. in KUniqueApplication when it forks
+ into background and sends info about the PID change - it should update
+ any existing ASN info, but mustn't create a new one, otherwise there
+ could appear ASN even for applications which shouldn't have ASN
+ - the text of the message starts with 4 characters 'change:', followed
+ by the text entries ( see below )
+ - remove: message
+ - this message is sent for stopping ASN with the given identification.
+ If the only item in the message is the identification string, the ASN
+ info should be removed. If there are also the PID and HOSTNAME entries
+ ( see below ), the matching ASN info should be only removed if this
+ given PID is the only PID for it ( in this case, the identification
+ string may be omitted ).
+ - the text of the message starts with 4 characters 'remove:', followed
+ by
+ - only ID entry
+ - only ID, PID and HOSTNAME entries
+ - only PID and HOSTNAME entries
+
+
+Text entries in the messages :
+------------------------------
+
+Every entry is of the form <name>=<value>. Value may be either a number
+or a string. If the string contains spaces, it must be quoted ("), all
+backslashes and quotes (") must be escaped by backslashes. If this ever
+becomes more than an internal KDE standard, non-standard entry names should
+start with an underscore.
+
+Entries :
+
+- ID - string
+ - the identification string of the startup notification
+ - it must be present in all messages except for the remove:
+ message with only PID and HOSTNAME
+- BIN - string
+ - the binary name of the starting application
+ - usually used as a fallback value if WMCLASS is not present
+ - e.g. 'kcontrol'
+- NAME - string
+ - the name of the starting application
+ - usually used only for displaying it when indicating that
+ the application is starting
+ - e.g. 'Control Center'
+- ICON - string
+ - the icon for this startup notification
+ - it should be handled like the Icon= entry in .desktop files
+ - e.g. 'kcontrol'
+- DESKTOP - number
+ - the virtual desktop on which the application should appear
+ - if the application's first window has _NET_WM_DESKTOP already
+ set when the window is mapped, it shouldn't be changed
+- WMCLASS - string
+ - the WMCLASS value used for matching newly mapped windows
+ of non-compliant applications
+ - useful only if it's different from the binary
+ name of the application
+- PID - number
+ - the PID of a process that belongs to this startup notification
+ - there may be several PIDs for one notification
+ - value 0 is also valid, meaning that there's a process
+ with unknown PID for this notification ( is used e.g.
+ by kfmclient when it sends a DCOP message to already running
+ konqueror instance to create a new window and exits immediately,
+ without adding the zero PID to the notification, process
+ that started kfmclient could detect it exited and would send
+ a remove: message for the notification with kfmclient's PID,
+ which would cause the notification to stop if there wasn't also
+ PID=0 for it
+- HOSTNAME - string
+ - the hostname of the machine on which the application is being
+ started
+ - this is used together with the PID entry
+
+--------------------
+
+ Well, I guess that's all. The KDE2.2 release will show if the users like it
+or not ( it's quite good IMHO, even though there are probably some minor
+details to fix or improve ). The only big thing remaining is to make also
+non-KDE people agree on using something like this. My first attempt
+https://listman.redhat.com/pipermail/xdg-list/2001-May/000083.html
+didn't get much attention, but now that there's a working implementation,
+I hope it will get better, when I try again sometime in the future.
+
+
+
+ Lubos Lunak <l.lunak@kde.org>
+
diff --git a/kdecore/README.user_profiles b/kdecore/README.user_profiles
new file mode 100644
index 000000000..4fb43b757
--- /dev/null
+++ b/kdecore/README.user_profiles
@@ -0,0 +1,136 @@
+Users can be associated with Profile(s)
+=======================================
+
+A user can be associated with one or more profiles. A profile indicates a
+configuration set that applies to a group of users. Each profile has a name
+to identify it. If a user is associated with more than one profile then the
+order of the two profiles is important. Settings associated with one profile
+could override the settings in the other profile, depending on the order.
+
+
+Mapping profiles to users
+=========================
+
+A mapping file determines which profile(s) should be used for which user.
+The mapping file can be configured in /etc/kderc in the [Directories] group:
+
+ [Directories]
+ userProfileMapFile=/etc/kde-user-profile
+
+Profiles can be mapped to individual users based on username, or profiles can
+be mapped to groups of users based on the UNIX group(s) the users are part of.
+(See man 1 groups)
+
+
+Mapping profiles to individual users
+====================================
+
+The mapping file can contain a [Users] section for mapping profiles to
+an individual user. The [Users] section contains the user's account name
+followed by one or more profiles as follow:
+
+ [Users]
+ bastian=developer
+ adrians=developer,packager
+
+The above example assigns to user "bastian" the profile "developer". To user
+"adrians" it assigns the two profiles "developer" and "packager". The order
+in which the profiles are listed makes a difference, settings in earlier
+profiles overrule settings in profiles that are listed after it. In the above
+case of user "adrians", wherever the "developer" and "packager" profiles contain
+conflicting settings, the settings of the "developer" profile will take precedent.
+
+If a user has an entry under the [Users] section, this entry will determine all
+profiles that are applicable to the user. The user will not be assigned any
+additional profiles based on the groups the user is part of.
+
+Mapping profiles to user groups
+===============================
+
+If a user has no entry under the [Users] section in the mapping file, the profiles
+that are applicable to the user will be based on the UNIX group(s) the user is
+part of.
+
+The groups and the order in which the groups are considered is determined by
+the following entry in the [General] section of the mapping file:
+
+ [General]
+ groups=pkgs,devel
+
+Each of these groups should have an entry under the [Groups] section that defines
+which profile(s) belongs to that group. This looks as follows:
+
+ [Groups]
+ pkgs=packager
+ devel=developer
+ bofh=admin,packager,developer
+
+For each group that a user is part of, the corresponding profile(s) are used. The
+order in which the groups are listed in the "groups" entry, determines the resulting
+order of all the applicable profiles. If multiple profiles are applicable to a
+particular user and a profile contains settings that conflict with settings in
+another profile then the settings in the earlier listed profile take precedent.
+
+So if, based on the example above, a user is part of the "pkgs" group then the
+"packager" profile will be used for that user. If the user is part of the "devel"
+group then the "developer" profile will be used. Users that are part of the "bofh"
+group will use the "admin", "packager" as well as the "developer" profile. In case
+of conflict, settings in the "admin" profile will take precedent over settings
+in the "packager" or "developer" profiles.
+
+If the user is part of both the "pkgs" and "devel" groups, then both the "packager"
+and "developer" profiles will be used. In case of conflicting settings between the
+two profiles, the "packager" profile will take precedent because the "pkgs" group
+associated with the profile was listed before the "devel" group.
+
+The "groups" command can be used to see to which groups a user belongs:
+
+ > groups coolo
+ coolo : users uucp dialout audio video cdrecording devel
+
+Note that in general only a few groups will have profiles associated with them.
+In the example above only the "devel" group has a profile associated with it,
+the other groups do not and will be ignored.
+
+If there is no profile defined for any of the groups that the user is in, the
+user will be assigned the "default" profile.
+
+
+The Profile determines the directory prefixes
+=============================================
+
+The global KDE configuration file (e.g. kdeglobals or /etc/kderc) can
+contain config-groups that are associated with a certain user profile.
+Such a config-group is treated similar as the [Directories] config-group.
+
+The name of a such config-group is [Directories-<ProfileName>]
+
+
+Integration with KIOSK Admin Tool
+=================================
+
+The KIOSK Admin Tool uses /etc/kderc as source for all its profile
+information. For this it uses the following keys in the
+[Directories-<ProfileName>] config-group:
+
+ # Short text describing this profile
+ ProfileDescription=
+
+ # Files will be installed with the uid of this user
+ ProfileInstallUser=
+
+The KIOSK Admin Tool uses the first directory from the prefixes= entry
+as default installation directory for this profile.
+
+
+Default setting as example
+==========================
+
+The following snipped could be added to /etc/kderc to define a "default" profile:
+
+ [Directories-default]
+ ProfileDescription=Default profile
+ ProfileDescription[de]=Defaultprofiel
+ ProfileInstallUser=root
+ prefixes=/var/run/kde-profile/default
+
diff --git a/kdecore/Rainbow.colors b/kdecore/Rainbow.colors
new file mode 100644
index 000000000..afe836eb8
--- /dev/null
+++ b/kdecore/Rainbow.colors
@@ -0,0 +1,118 @@
+GIMP Palette
+255 204 204
+255 230 204
+255 255 204
+230 255 204
+204 255 204
+204 255 230
+204 255 255
+204 230 255
+204 204 255
+230 204 255
+255 204 255
+255 204 230
+255 255 255
+255 153 153
+255 204 153
+255 255 153
+204 255 153
+153 255 153
+153 255 204
+153 255 255
+153 204 255
+153 153 255
+204 153 255
+255 153 255
+255 153 204
+224 224 224
+255 102 102
+255 179 102
+255 255 102
+179 255 102
+102 255 102
+102 255 179
+102 255 255
+102 179 255
+102 102 255
+179 102 255
+255 102 255
+255 102 179
+192 192 192
+255 51 51
+255 153 51
+255 255 51
+153 255 51
+ 51 255 51
+ 51 255 153
+ 51 255 255
+ 51 153 255
+ 51 51 255
+153 51 255
+255 51 255
+255 51 153
+160 160 160
+255 0 0
+255 128 0
+255 255 0
+128 255 0
+ 0 255 0
+ 0 255 128
+ 0 255 255
+ 0 128 255
+ 0 0 255
+128 0 255
+255 0 255
+255 0 128
+128 128 128
+204 0 0
+204 102 0
+204 204 0
+102 204 0
+ 0 204 0
+ 0 204 102
+ 0 204 204
+ 0 102 204
+ 0 0 204
+102 0 204
+204 0 204
+204 0 102
+ 96 96 96
+153 0 0
+153 77 0
+153 153 0
+ 77 153 0
+ 0 153 0
+ 0 153 77
+ 0 153 153
+ 0 77 153
+ 0 0 153
+ 77 0 153
+153 0 153
+153 0 77
+ 64 64 64
+102 0 0
+102 51 0
+102 102 0
+ 51 102 0
+ 0 102 0
+ 0 102 51
+ 0 102 102
+ 0 51 102
+ 0 0 102
+ 51 0 102
+102 0 102
+102 0 51
+ 32 32 32
+ 51 0 0
+ 51 26 0
+ 51 51 0
+ 26 51 0
+ 0 51 0
+ 0 51 26
+ 0 51 51
+ 0 26 51
+ 0 0 51
+ 26 0 51
+ 51 0 51
+ 51 0 26
+ 0 0 0
diff --git a/kdecore/Royal.colors b/kdecore/Royal.colors
new file mode 100644
index 000000000..5ea4fe638
--- /dev/null
+++ b/kdecore/Royal.colors
@@ -0,0 +1,258 @@
+GIMP Palette
+ 0 0 0
+ 60 0 80
+ 60 0 80
+ 60 0 84
+ 64 0 84
+ 64 0 84
+ 64 0 88
+ 64 0 88
+ 68 0 88
+ 68 0 92
+ 68 0 92
+ 68 0 92
+ 72 0 96
+ 72 0 96
+ 72 0 96
+ 72 0 100
+ 76 0 100
+ 76 0 100
+ 76 0 104
+ 76 0 104
+ 76 0 104
+ 80 0 104
+ 80 0 108
+ 80 0 108
+ 80 0 108
+ 84 0 112
+ 84 0 112
+ 84 0 112
+ 84 0 116
+ 88 0 116
+ 88 0 116
+ 88 0 120
+ 88 0 120
+ 92 0 120
+ 92 0 124
+ 92 0 124
+ 92 0 124
+ 96 0 128
+ 96 0 128
+ 96 0 128
+ 96 0 132
+ 96 0 132
+100 0 132
+100 0 132
+100 0 136
+100 0 136
+104 0 136
+104 0 140
+104 0 140
+104 0 140
+108 0 144
+108 0 144
+108 0 144
+108 0 148
+112 0 148
+112 0 148
+112 0 152
+112 0 152
+116 0 152
+116 0 156
+116 0 156
+116 0 156
+120 0 160
+120 0 160
+124 4 160
+124 8 164
+128 12 164
+128 16 164
+132 20 168
+132 24 168
+136 28 168
+136 32 172
+140 36 172
+140 40 172
+144 44 176
+144 48 176
+148 52 180
+148 56 180
+152 60 180
+152 64 184
+156 68 184
+156 72 184
+160 76 188
+160 80 188
+164 84 188
+164 88 192
+168 92 192
+168 96 192
+172 100 196
+172 104 196
+176 108 200
+176 112 200
+180 116 200
+180 120 204
+184 124 204
+188 128 204
+188 132 208
+192 136 208
+192 140 208
+196 144 212
+196 148 212
+200 152 216
+200 156 216
+204 160 216
+204 164 220
+208 168 220
+208 172 220
+212 176 224
+212 180 224
+216 184 224
+216 188 228
+220 192 228
+220 196 228
+224 200 232
+224 204 232
+228 208 236
+228 212 236
+232 216 236
+232 220 240
+236 224 240
+236 228 240
+240 232 244
+240 236 244
+244 240 244
+244 244 248
+248 248 248
+252 252 252
+252 252 252
+252 252 248
+252 252 244
+252 252 240
+252 252 236
+252 252 232
+252 252 228
+252 252 224
+252 252 220
+252 252 216
+252 252 212
+252 252 208
+252 252 204
+252 252 200
+252 252 196
+252 252 192
+252 252 188
+252 252 184
+252 252 180
+252 252 176
+252 252 172
+252 252 168
+252 252 164
+252 252 160
+252 252 156
+252 252 152
+252 252 148
+252 252 144
+252 252 140
+252 252 136
+252 252 132
+252 252 128
+252 252 124
+252 252 120
+252 252 116
+252 252 112
+252 252 108
+252 252 104
+252 252 100
+252 252 96
+252 252 92
+252 252 88
+252 252 84
+252 252 80
+252 252 76
+252 252 72
+252 252 68
+252 252 64
+252 252 60
+252 252 56
+252 252 52
+252 252 48
+252 252 44
+252 252 40
+252 252 36
+252 252 32
+252 252 28
+252 252 24
+252 252 20
+252 252 16
+252 252 12
+252 252 8
+252 252 4
+252 252 0
+252 248 0
+248 244 0
+244 240 0
+240 236 4
+240 232 4
+236 228 4
+232 224 8
+228 220 8
+228 216 8
+224 212 12
+220 208 12
+216 204 12
+212 200 16
+212 196 16
+208 192 16
+204 188 20
+200 184 20
+200 180 20
+196 176 24
+192 172 24
+188 168 24
+184 164 28
+184 160 28
+180 156 28
+176 152 32
+172 148 32
+172 144 32
+168 140 36
+164 136 36
+160 132 36
+160 128 36
+156 124 40
+152 120 40
+148 116 40
+144 112 44
+144 108 44
+140 104 44
+136 100 48
+132 96 48
+132 92 48
+128 88 52
+124 84 52
+120 80 52
+116 76 56
+116 72 56
+112 68 56
+108 64 60
+104 60 60
+104 56 60
+100 52 64
+ 96 48 64
+ 92 44 64
+ 88 40 68
+ 88 36 68
+ 84 32 68
+ 80 28 72
+ 76 24 72
+ 76 20 72
+ 72 16 76
+ 68 12 76
+ 64 8 76
+ 60 0 80
+ 60 0 80
+ 60 0 80
+ 60 0 80
+# The royal purple ... by D. Egnor
diff --git a/kdecore/Web.colors b/kdecore/Web.colors
new file mode 100644
index 000000000..efdd23dd8
--- /dev/null
+++ b/kdecore/Web.colors
@@ -0,0 +1,218 @@
+GIMP Palette
+# Netscape -- GIMP Palette file
+255 255 255
+255 255 204
+255 255 153
+255 255 102
+255 255 51
+255 255 0
+255 204 255
+255 204 204
+255 204 153
+255 204 102
+255 204 51
+255 204 0
+255 153 255
+255 153 204
+255 153 153
+255 153 102
+255 153 51
+255 153 0
+255 102 255
+255 102 204
+255 102 153
+255 102 102
+255 102 51
+255 102 0
+255 51 255
+255 51 204
+255 51 153
+255 51 102
+255 51 51
+255 51 0
+255 0 255
+255 0 204
+255 0 153
+255 0 102
+255 0 51
+255 0 0
+204 255 255
+204 255 204
+204 255 153
+204 255 102
+204 255 51
+204 255 0
+204 204 255
+204 204 204
+204 204 153
+204 204 102
+204 204 51
+204 204 0
+204 153 255
+204 153 204
+204 153 153
+204 153 102
+204 153 51
+204 153 0
+204 102 255
+204 102 204
+204 102 153
+204 102 102
+204 102 51
+204 102 0
+204 51 255
+204 51 204
+204 51 153
+204 51 102
+204 51 51
+204 51 0
+204 0 255
+204 0 204
+204 0 153
+204 0 102
+204 0 51
+204 0 0
+153 255 255
+153 255 204
+153 255 153
+153 255 102
+153 255 51
+153 255 0
+153 204 255
+153 204 204
+153 204 153
+153 204 102
+153 204 51
+153 204 0
+153 153 255
+153 153 204
+153 153 153
+153 153 102
+153 153 51
+153 153 0
+153 102 255
+153 102 204
+153 102 153
+153 102 102
+153 102 51
+153 102 0
+153 51 255
+153 51 204
+153 51 153
+153 51 102
+153 51 51
+153 51 0
+153 0 255
+153 0 204
+153 0 153
+153 0 102
+153 0 51
+153 0 0
+102 255 255
+102 255 204
+102 255 153
+102 255 102
+102 255 51
+102 255 0
+102 204 255
+102 204 204
+102 204 153
+102 204 102
+102 204 51
+102 204 0
+102 153 255
+102 153 204
+102 153 153
+102 153 102
+102 153 51
+102 153 0
+102 102 255
+102 102 204
+102 102 153
+102 102 102
+102 102 51
+102 102 0
+102 51 255
+102 51 204
+102 51 153
+102 51 102
+102 51 51
+102 51 0
+102 0 255
+102 0 204
+102 0 153
+102 0 102
+102 0 51
+102 0 0
+51 255 255
+51 255 204
+51 255 153
+51 255 102
+51 255 51
+51 255 0
+51 204 255
+51 204 204
+51 204 153
+51 204 102
+51 204 51
+51 204 0
+51 153 255
+51 153 204
+51 153 153
+51 153 102
+51 153 51
+51 153 0
+51 102 255
+51 102 204
+51 102 153
+51 102 102
+51 102 51
+51 102 0
+51 51 255
+51 51 204
+51 51 153
+51 51 102
+51 51 51
+51 51 0
+51 0 255
+51 0 204
+51 0 153
+51 0 102
+51 0 51
+51 0 0
+0 255 255
+0 255 204
+0 255 153
+0 255 102
+0 255 51
+0 255 0
+0 204 255
+0 204 204
+0 204 153
+0 204 102
+0 204 51
+0 204 0
+0 153 255
+0 153 204
+0 153 153
+0 153 102
+0 153 51
+0 153 0
+0 102 255
+0 102 204
+0 102 153
+0 102 102
+0 102 51
+0 102 0
+0 51 255
+0 51 204
+0 51 153
+0 51 102
+0 51 51
+0 51 0
+0 0 255
+0 0 204
+0 0 153
+0 0 102
+0 0 51
+0 0 0
diff --git a/kdecore/all_languages.desktop b/kdecore/all_languages.desktop
new file mode 100644
index 000000000..2f36efff6
--- /dev/null
+++ b/kdecore/all_languages.desktop
@@ -0,0 +1,11919 @@
+[aa]
+Name=Afar
+Name[az]=Afarca
+Name[be]=ÐфарÑкаÑ
+Name[bg]=Ðфар
+Name[bn]=আফার
+Name[csb]=Afarsczi
+Name[cy]=Afareg
+Name[eo]=Fora
+Name[fa]=اÙار
+Name[ga]=Afárais
+Name[he]=×פ×ר
+Name[hi]=अफà¥à¤°
+Name[hr]=Afarski
+Name[ja]=アファル語
+Name[ka]=áƒáƒ¤áƒáƒ áƒ£áƒšáƒ˜
+Name[kk]=Ðфарша
+Name[km]=អាហ្វារ
+Name[ko]=아파르어
+Name[lt]=Afarų
+Name[lv]=AfÄru
+Name[mk]=Ðфар
+Name[mn]=Ðфар
+Name[nds]=Afaarsch
+Name[ne]=अफार
+Name[nso]=Kgolekgole
+Name[pa]=ਅਫਾਰ
+Name[pl]=Afarski
+Name[ro]=Afară
+Name[ru]=ÐфарÑкий
+Name[rw]=Ikinyafari
+Name[se]=Afárgiella
+Name[sk]=afarÄina
+Name[sl]=afarsko
+Name[sq]=Afarisht
+Name[sr]=ÐфарÑки
+Name[sr@Latn]=Afarski
+Name[ss]=Si-Afar
+Name[ta]=அஃபாரà¯
+Name[te]=ఎఫారà±
+Name[tg]=Ðфарӣ
+Name[th]=ภาษาอะฟาร์
+Name[tt]=Afarça
+Name[uk]=Ðфар
+Name[uz@cyrillic]=Ðфар
+Name[vi]=Ä‚-pha
+Name[zh_CN]=阿法尔语
+Name[zh_HK]=阿發爾
+Name[zh_TW]=阿發爾
+Name[zu]=Okude kakhulu
+[ab]
+Name=Abkhazian
+Name[ar]=أبخازي
+Name[az]=Abxazca
+Name[be]=ÐбхазÑкаÑ
+Name[bg]=Ðбхазки
+Name[bn]=আবখাজিয়ান
+Name[br]=Abkhazieg
+Name[bs]=Abhaski
+Name[ca]=Àzeri
+Name[cs]=Abcházský
+Name[csb]=Abchasczi
+Name[cy]=Abkhazeg
+Name[da]=Abkhaziansk
+Name[de]=Abhasisch
+Name[eo]=Abĥaza
+Name[et]=Abhaasia
+Name[fa]=ابخازیان
+Name[fi]=Abhaasi
+Name[fr]=Abkhaze
+Name[fy]=Abkhasysk
+Name[ga]=Abcáisis
+Name[gl]=Abxásio
+Name[he]=×בחזית
+Name[hi]=अबकाजियन
+Name[hr]=Abhaški
+Name[hsb]=Abchazisce
+Name[hu]=Abház
+Name[it]=Abkhaziano
+Name[ja]=アブãƒã‚ºèªž
+Name[ka]=áƒáƒ¤áƒ®áƒáƒ–ური
+Name[kk]=Ðхбазша
+Name[km]=អាប់ážáž¶áž áŸ’ស៊ាន
+Name[ko]=아브하지아어
+Name[lb]=Abhasesch
+Name[lt]=Abhazų
+Name[lv]=AbhÄzu
+Name[mk]=ÐбхаÑки
+Name[mn]=Ðбкааз
+Name[ms]=Abkhazia
+Name[nb]=Abkhasisk
+Name[nds]=Abchaassch
+Name[ne]=अबà¥à¤–ाजियन
+Name[nn]=Abkhasisk
+Name[nso]=Se-Abkhazian
+Name[pa]=ਅਬਖਾਜ਼ੀਨ
+Name[pl]=Abchaski
+Name[pt_BR]=Turco
+Name[ro]=Abhaziană
+Name[ru]=ÐбхазÑкий
+Name[rw]=Abukaziyani
+Name[se]=Abhásiagiella
+Name[sk]=abcházÄina
+Name[sl]=abkazijansko
+Name[sq]=Abkhazanisht
+Name[sr]=ÐбхазијÑки
+Name[sr@Latn]=Abhazijski
+Name[ss]=Si-Abkhazian
+Name[sv]=Abkhasiska
+Name[ta]=அபà¯à®•à®¾à®šà®¿à®¯à®©à¯
+Name[te]=à°…à°¬à±à°–జియనà±
+Name[tg]=Ðбхозӣ
+Name[th]=ภาษาà¹à¸­à¸šà¸„าเซียน
+Name[tt]=Abxazça
+Name[uk]=Ðбхазька
+Name[uz]=Abxazcha
+Name[uz@cyrillic]=Ðбхазча
+Name[vi]=Ap-kha-xi-an
+Name[wa]=Abxhaze
+Name[zh_CN]=阿布哈西亚语
+Name[zh_HK]=阿布哈西亞語
+Name[zh_TW]=阿布哈西亞語
+Name[zu]=I-Abkhazian
+[ae]
+Name=Avestan
+Name[ar]=أيراني Ø£Ùستان
+Name[az]=Avestanca
+Name[be]=ÐвеÑтанÑкаÑ
+Name[bg]=ÐвеÑтийÑки
+Name[bn]=আভেসà§à¦¤à¦¾à¦¨
+Name[cs]=Avestánský
+Name[csb]=Awestańsczi (irańsczi)
+Name[cy]=Afestaneg
+Name[da]=Avestansk
+Name[de]=Avestisch
+Name[eo]=Avesta
+Name[et]=Vanapärsia
+Name[fa]=اوستایی
+Name[fi]=Avesta
+Name[fy]=Avestaansk
+Name[ga]=Aivéistis
+Name[gl]=Avestani
+Name[he]=×ווסטית
+Name[hi]=अवेसà¥à¤¤à¤¨
+Name[hr]=Avestanski
+Name[hsb]=Awestisce
+Name[hu]=Avesztáni
+Name[it]=Avestano
+Name[ja]=アベスタ語
+Name[ka]=áƒáƒ•áƒ”სტური
+Name[kk]=ÐвеÑтша
+Name[km]=អាវែស្ážáž„់
+Name[ko]=아베스탄어
+Name[mk]=ÐвеÑтан
+Name[mn]=ÐвеÑтан
+Name[nb]=Avestisk
+Name[nds]=Avesta
+Name[ne]=अभेसà¥à¤Ÿà¤¨
+Name[nn]=Avestisk
+Name[nso]=Se-Avestan
+Name[pa]=ਅਵਸਟਅਨ
+Name[pl]=Awestański (Irański)
+Name[ro]=Avestană
+Name[ru]=ÐвеÑтийÑкий
+Name[rw]=Ikinyavesitani
+Name[se]=Avestánagiella
+Name[sk]=avestÄina
+Name[sl]=avestansko
+Name[sq]=Avestanisht
+Name[sr]=ÐвеÑтанÑки
+Name[sr@Latn]=Avestanski
+Name[ss]=Si-Avestan
+Name[sv]=Avestiska
+Name[ta]=அவெஸà¯à®¤à®©à¯
+Name[te]=అవెసà±à°¥à°¨à±
+Name[tg]=ÐваÑтоӣ
+Name[th]=ภาษาอะเวสà¹à¸—น
+Name[tt]=Avestança
+Name[uk]=ÐвеÑтан
+Name[uz]=Avesta
+Name[uz@cyrillic]=ÐвеÑта
+Name[vi]=Ä‚-ve-x-tanh
+Name[zh_CN]=阿维斯陀语
+Name[zh_HK]=阿維斯陀語
+Name[zh_TW]=阿維斯陀語
+Name[zu]=Isi-Avestan
+[af]
+Name=Afrikaans
+Name[ar]=الأÙريكانس
+Name[az]=Afrika Dili
+Name[be]=ÐфрыканÑкаÑ
+Name[bg]=ÐфрикаанÑ
+Name[bn]=আফà§à¦°à¦¿à¦•à¦¾à¦¨à§â€Œà¦¸
+Name[cs]=Afrikánský
+Name[csb]=Afrikanersczi
+Name[cy]=Affricaneg
+Name[el]=ΑφÏικανικά
+Name[eo]=Afrikansa
+Name[et]=Afrikaani
+Name[eu]=Afrikaansa
+Name[fa]=Ø¢Ùریکانس
+Name[fy]=Afrikaansk
+Name[ga]=Afracáinis
+Name[gl]=Africáner
+Name[he]=×פריקנס
+Name[hi]=अफà¥à¤°à¥€à¤•à¤¨à¥à¤¸
+Name[id]=Afrika
+Name[ja]=アフリカーンス語
+Name[ka]=áƒáƒ¤áƒ áƒ˜áƒ™áƒáƒáƒœáƒ¡áƒ˜
+Name[kk]=ÐафрикаанÑ
+Name[km]=អាហ្វ្រីកាអាន
+Name[ko]=남아프리카 공용어
+Name[lt]=Afrikanso
+Name[lv]=Ä€frikÄņu
+Name[mi]=Reo Äwherika Tatimana
+Name[mk]=ÐфриканÑки
+Name[mn]=Ðфрик
+Name[ms]=Afrika
+Name[mt]=Afrikans
+Name[nds]=Afrikaansch
+Name[ne]=अफà¥à¤°à¤¿à¤•à¥€
+Name[nso]=Seburu
+Name[pa]=ਅਫਰੀਕਨ
+Name[pl]=Afrykanerski
+Name[pt_BR]=Africâners
+Name[ro]=Africană
+Name[ru]=ÐфрикаанÑ
+Name[rw]=Ikinyafurikansi
+Name[se]=Afrikánsgiella
+Name[sk]=afrikánÄina
+Name[sl]=afrikansko
+Name[sq]=Afrikanisht
+Name[sr]=ÐфриканерÑки
+Name[sr@Latn]=Afrikanerski
+Name[ss]=Sibhunu
+Name[sv]=Sydafrikansk holländska
+Name[ta]=ஆஃபரிகானà¯à®¸à¯
+Name[te]=ఆఫà±à°°à°¿à°•à°¾à°¨à±à°¸à±
+Name[tg]=Ðфрикоӣ
+Name[th]=ภาษาà¹à¸­à¸Ÿà¸£à¸´à¸à¸²
+Name[tr]=Afrika Dili
+Name[tt]=Afrikança
+Name[uk]=ПівденноафриканÑька
+Name[uz]=Afrikancha
+Name[uz@cyrillic]=Ðфриканча
+Name[ven]=Tshivhuru
+Name[vi]=Hoà Nam Phi
+Name[xh]=Isibhulu
+Name[zh_CN]=å—éžè·å…°è¯­
+Name[zh_HK]=å—éžè·è˜­èªž
+Name[zh_TW]=å—éžè·è˜­èªž
+Name[zu]=Isi-Bhunu
+[am]
+Name=Amharic
+Name[ar]=أمهري
+Name[az]=AmharikcÉ™
+Name[be]=ÐмхарÑкаÑ
+Name[bg]=ÐмхарÑки
+Name[bn]=আমহারিক
+Name[br]=Amhareg
+Name[bs]=Amharski
+Name[ca]=Amhàric
+Name[cs]=Amharský
+Name[csb]=Etiopsczi
+Name[cy]=Amhareg
+Name[da]=Amharisk
+Name[de]=Amharisch
+Name[eo]=Amhara
+Name[es]=Amárico
+Name[et]=Amhaara
+Name[fa]=امهری
+Name[fi]=Amhara
+Name[fr]=Amharique
+Name[fy]=Amhaarsk
+Name[ga]=Amáiris
+Name[he]=×מהרית
+Name[hi]=अमà¥à¤¹à¤¾à¤°à¤¿à¤•
+Name[hr]=Amarski
+Name[hsb]=Amharisce
+Name[hu]=Amhár
+Name[it]=Amarico
+Name[ja]=アムãƒãƒ©èªž
+Name[ka]=áƒáƒ›áƒ°áƒáƒ áƒ£áƒšáƒ˜
+Name[kk]=Ðхмарша
+Name[km]=អាមហារី
+Name[ko]=암하ë¼ì–´
+Name[lb]=Amharesch
+Name[lt]=Amhari
+Name[lv]=Amariešu
+Name[mk]=ÐмхарÑки
+Name[mn]=Ðмхар
+Name[nb]=Amharisk
+Name[nds]=Amhaarsch
+Name[ne]=अमà¥à¤¹à¤¾à¤°à¤¿à¤•
+Name[nl]=Amharisch
+Name[nn]=Amharisk
+Name[nso]=Se-Amharic
+Name[pa]=ਅਮਹਾਰਿਕ
+Name[pl]=Etiopski
+Name[pt]=Amárico
+Name[pt_BR]=Amârico
+Name[ro]=Amarică
+Name[ru]=ÐмхарÑкий
+Name[rw]=Ikinyamarike
+Name[se]=Ambháriagiella
+Name[sk]=amharÄina
+Name[sl]=amharik
+Name[sq]=Amharikisht
+Name[sr]=ÐмарÑки
+Name[sr@Latn]=Amarski
+Name[ss]=Si-Amharic
+Name[sv]=Amarinja
+Name[ta]=à®…à®®à¯à®¹à®¾à®°à®¿à®•à¯
+Name[te]=à°…à°®à±à°¹à°°à°¿à°•à±
+Name[tg]=Ðмхарикӣ
+Name[th]=ภาษาอัมฮาริค
+Name[tt]=Amharça
+Name[uk]=ÐмхарÑька
+Name[uz]=Amxarik
+Name[uz@cyrillic]=Ðмхарик
+Name[vi]=Am-ha-ri
+Name[zh_CN]=阿姆哈拉语
+Name[zh_HK]=衣索比亞官方語
+Name[zh_TW]=衣索比亞官方語
+Name[zu]=isi-Amharic
+[ar]
+Name=Arabic
+Name[af]=Arabies
+Name[ar]=العربية
+Name[az]=ÆrabcÉ™
+Name[be]=ÐрабÑкаÑ
+Name[bg]=ÐрабÑки
+Name[bn]=আরবী
+Name[br]=Arabeg
+Name[bs]=Arapski
+Name[ca]=Àrab
+Name[cs]=Arabský
+Name[csb]=Arabsczi
+Name[cy]=Arabeg
+Name[da]=Arabisk
+Name[de]=Arabisch
+Name[el]=ΑÏαβικά
+Name[eo]=Araba
+Name[es]=Arábe
+Name[et]=Araabia
+Name[eu]=Arabiera
+Name[fa]=عربی
+Name[fi]=Arabia
+Name[fr]=Arabe
+Name[fy]=Arabysk
+Name[ga]=Araibis
+Name[gl]=Ãrabe
+Name[he]=ערבית
+Name[hi]=अरेबिक
+Name[hr]=Arapski
+Name[hsb]=Arabsce
+Name[hu]=Arab
+Name[id]=Arab
+Name[is]=Arabíska
+Name[it]=Arabo
+Name[ja]=アラビア語
+Name[ka]=áƒáƒ áƒáƒ‘ული
+Name[kk]=Ðрабша
+Name[km]=អារ៉ាប់
+Name[ko]=ì•„ë¼ë¹„ì•„ì–´
+Name[lb]=Arabesch
+Name[lt]=Arabų
+Name[lv]=ArÄbu
+Name[mi]=Reo Arapia
+Name[mk]=ÐрапÑки
+Name[mn]=Ðраб
+Name[ms]=Arab
+Name[mt]=Għarbi
+Name[nb]=Arabisk
+Name[nds]=Araabsch
+Name[ne]=अरबी
+Name[nl]=Arabisch
+Name[nn]=Arabisk
+Name[nso]=Searapo
+Name[oc]=Arab
+Name[pa]=ਅਰਬੀ
+Name[pl]=Arabski
+Name[pt]=Ãrabe
+Name[pt_BR]=Ãrabe
+Name[ro]=Arabă
+Name[ru]=ÐрабÑкий
+Name[rw]=Icyarabu
+Name[se]=Arábiagiella
+Name[sk]=arabÄina
+Name[sl]=arabsko
+Name[sq]=Arabisht
+Name[sr]=ÐрапÑки
+Name[sr@Latn]=Arapski
+Name[ss]=Si-Arabhu
+Name[sv]=Arabiska
+Name[ta]=அராபிகà¯
+Name[te]=అరబికà±
+Name[tg]=Ðрабӣ
+Name[th]=ภาษาอารบิà¸
+Name[tr]=Arapça
+Name[tt]=Ğäräpçä
+Name[uk]=ÐрабÑька
+Name[uz]=Arabcha
+Name[uz@cyrillic]=Ðрабча
+Name[ven]=Tshiarabiki
+Name[vi]=A-rập
+Name[wa]=Arabe
+Name[zh_CN]=阿拉伯语
+Name[zh_HK]=阿拉伯語
+Name[zh_TW]=阿拉伯語
+Name[zu]=Isi-Arabhu
+[as]
+Name=Assamese
+Name[ar]=هندي أساميزي
+Name[az]=AssamescÉ™
+Name[be]=ÐÑамÑкаÑ
+Name[bg]=ÐÑами
+Name[bn]=আসামী
+Name[bs]=Asamski
+Name[ca]=Assamès
+Name[cs]=Asamský
+Name[csb]=Assamijsczi
+Name[cy]=Assameg
+Name[de]=Assamesisch
+Name[eo]=Asama
+Name[et]=Assami
+Name[fa]=آسامی
+Name[fi]=Assami
+Name[fr]=Assamais
+Name[fy]=Assameesk
+Name[ga]=Asaimis
+Name[gl]=Asamixa
+Name[he]=×סמית
+Name[hi]=असमी
+Name[hr]=Asamski
+Name[hsb]=Asamezisce
+Name[hu]=Asszámi
+Name[ja]=アッサム語
+Name[ka]=áƒáƒ¡áƒáƒ›áƒ”სე
+Name[kk]=ÐÑÑамша
+Name[km]=អាសាមីស
+Name[ko]=아삼어
+Name[lb]=Assamesesch
+Name[lt]=Asamesų
+Name[lv]=Asamiešu
+Name[mk]=ÐÑамеÑки
+Name[mn]=ÐÑÑаме
+Name[nb]=Assamesisk
+Name[nds]=Assameesch
+Name[ne]=आसामी
+Name[nl]=Assamees
+Name[nn]=Assami
+Name[nso]=Se-Assamese
+Name[pa]=ਆਸਾਮੀ
+Name[pl]=Assamijski
+Name[ro]=Asameză
+Name[ru]=ÐÑÑамÑкий
+Name[rw]=Ikinyasamese
+Name[se]=Assamesegiella
+Name[sk]=ásámÄina
+Name[sl]=asamese
+Name[sq]=Assamesisht
+Name[sr]=ÐÑамÑки
+Name[sr@Latn]=Asamski
+Name[ss]=Si-Assamese
+Name[sv]=Assamesiska
+Name[ta]=அஸà¯à®¸à®¾à®®à®¿à®¯
+Name[te]=à°…à°¸à±à°¸à°¾à°®à±€
+Name[tg]=ÐÑÑамӣ
+Name[th]=ภาษาอัสสัม
+Name[tt]=Assamesçä
+Name[uk]=ÐÑамійÑька
+Name[uz@cyrillic]=ÐÑÑамеÑе
+Name[vi]=A-xam
+Name[zh_CN]=阿è¨å§†è¯­
+Name[zh_HK]=阿薩姆語
+Name[zh_TW]=阿薩姆語
+Name[zu]=Isi-Assamese
+[ay]
+Name=Aymara
+Name[ar]=هندي من سكان بوليÙيا والبيرو
+Name[az]=Aymaraca
+Name[be]=ÐймарÑкаÑ
+Name[bg]=Ðймара
+Name[bn]=আইমারা
+Name[cy]=Aimareg
+Name[de]=Aimara
+Name[eo]=Ajmara
+Name[et]=Aimaraa
+Name[fa]=آیمارایی
+Name[fi]=Aimara
+Name[ga]=Adhmarais
+Name[gl]=Aimará
+Name[he]=×יימרה
+Name[hi]=अयमारा
+Name[hr]=Ajmarski
+Name[hu]=Ajmara
+Name[ja]=アイマラ語
+Name[ka]=áƒáƒ˜áƒ›áƒáƒ áƒ
+Name[kk]=Ðймарша
+Name[km]=អីម៉ារ៉ា
+Name[ko]=ì•„ì´ë§ˆë¼ì–´
+Name[lb]=Aimara
+Name[lv]=Ajmaru
+Name[mk]=Ðјмара
+Name[mn]=ÐÑмара
+Name[ne]=आइमारा
+Name[nso]=Se-Aymara
+Name[pa]=ਅਯਮਾਰਾ
+Name[ro]=Aymară
+Name[ru]=ÐймарÑкий
+Name[rw]=Ikinyayimara
+Name[se]=Aimáragiella
+Name[sk]=aymarÄina
+Name[sl]=ajmarsko
+Name[sq]=Ajmarisht
+Name[sr]=ÐјмарÑки
+Name[sr@Latn]=Ajmarski
+Name[ss]=Si-Aymara
+Name[ta]=அயà¯à®®à®¾à®°à®¾
+Name[te]=à°…à°¯à±à°®à°°à°¾
+Name[tg]=Ðймарагӣ
+Name[th]=ภาษาอัยมารา
+Name[tt]=Aymarça
+Name[uk]=ÐймарÑька
+Name[uz@cyrillic]=Ðймара
+Name[vi]=Ay-ma-ra
+Name[zh_CN]=艾马拉语
+Name[zh_HK]=愛瑪拉語
+Name[zh_TW]=愛瑪拉語
+Name[zu]=Isi-Aymara
+[az]
+Name=Azerbaijani
+Name[ar]=الأذربيجانية
+Name[az]=Azərbaycanca
+Name[be]=ÐзербайджанÑкаÑ
+Name[bg]=ÐзербайджанÑки
+Name[bn]=আজেরবাইজানি
+Name[br]=Azerbaidjanek
+Name[bs]=Azerbejdžanski
+Name[ca]=Àzeri
+Name[cs]=Ãzerbajdžánský
+Name[csb]=Azerbejdżańsczi
+Name[cy]=Azerbaijaneg
+Name[da]=Azerbaijansk
+Name[de]=Aserbaidschanisch
+Name[el]=ΑζεÏμπαϊτζανικά
+Name[eo]=AzerbajÄana
+Name[es]=Azerbayano
+Name[et]=Aserbaidžaani
+Name[eu]=Azerbaijanera
+Name[fa]=آذربایجانی
+Name[fi]=Azerbaidžani
+Name[fr]=Azerbaïdjanais
+Name[fy]=Azerbeidzjaansk
+Name[ga]=Asarbaiseáinis
+Name[gl]=Azeri
+Name[he]=×זרביג'נית
+Name[hi]=अजरबैजानी
+Name[hr]=Azerbejdžanski
+Name[hsb]=Azerbajdźansce
+Name[hu]=Azerbajdzsán
+Name[id]=Azerbaijan
+Name[is]=Azerbaijanska
+Name[it]=Azerbaigiano
+Name[ja]=アゼルãƒã‚¤ã‚¸ãƒ£ãƒ³èªž
+Name[ka]=áƒáƒ–ერბáƒáƒ˜áƒ¯áƒáƒœáƒ£áƒšáƒ˜
+Name[kk]=Ðзербайжанша
+Name[km]=អាហ្ស៊ែរបែហ្សង់
+Name[ko]=아제르바ì´ìž”ì–´
+Name[lb]=Asserbaidschanesch
+Name[lt]=AzerbaidžanieÄių
+Name[lv]=AzerbaidžÄņu
+Name[mk]=ÐзербејџанÑки
+Name[mn]=Ðзербажайн
+Name[ms]=Azerbaijan
+Name[mt]=Ażerbajġani
+Name[nb]=Aserbajdsjansk
+Name[nds]=Aserbaidschaansch
+Name[ne]=अजरबैजानी
+Name[nl]=Azerbeidjaans
+Name[nn]=Aserbajdsjansk
+Name[nso]=Se-Azerbaijani
+Name[pa]=ਅਜ਼ਰਬਾਈਜਾਨੀ
+Name[pl]=Azerbejdżański
+Name[pt]=Azerbaijano
+Name[pt_BR]=Azerbaijão
+Name[ro]=Azerbaijană
+Name[ru]=ÐзербайджанÑкий
+Name[rw]=Ikinyazeribayijani
+Name[se]=Azerbaižánagiella
+Name[sk]=azerbajdžanÄina
+Name[sl]=azerbajdžansko
+Name[sq]=Azerbejxhanisht
+Name[sr]=ÐзербејџанÑки
+Name[sr@Latn]=Azerbejdžanski
+Name[ss]=Si-Azerbaijani
+Name[sv]=Azerbajdzjanska
+Name[ta]=அசரà¯à®ªà¯ˆà®šà®¾à®©à®¿
+Name[te]=అజెరౠబైజాని
+Name[tg]=Озарбойҷонӣ
+Name[th]=ภาษาอาเซอร์ไบจัน
+Name[tr]=Azerbeycanca
+Name[tt]=Äzerçä
+Name[uk]=ÐзербайджанÑька
+Name[uz]=Ozarbayjoncha
+Name[uz@cyrillic]=Озарбайжонча
+Name[vi]=A-xợ-bai-gianh
+Name[wa]=Azeri
+Name[zh_CN]=阿塞拜疆语
+Name[zh_HK]=亞塞拜彊語
+Name[zh_TW]=亞塞拜然語
+Name[zu]=Isi-Azerbaijani
+[ba]
+Name=Bashkir
+Name[ar]=بشكير
+Name[az]=BaÅŸkircÉ™
+Name[be]=БашкірÑкаÑ
+Name[bg]=БашкирÑки
+Name[bn]=বাশকীর
+Name[bs]=Baškir
+Name[cs]=Baškirský
+Name[csb]=Baszkirsczi
+Name[cy]=Bashkireg
+Name[de]=Baschkirisch
+Name[eo]=BaÅkira
+Name[et]=Baškiiri
+Name[fa]=بشکیری
+Name[fi]=Baškiiri
+Name[fr]=Bachkir
+Name[ga]=Baiscíris
+Name[gl]=Bashquir
+Name[he]=בשקירית
+Name[hi]=बाशकिर
+Name[hr]=Baškirski
+Name[hu]=Baskír
+Name[ja]=ãƒã‚·ãƒ¥ã‚­ãƒ¼ãƒ«èªž
+Name[ka]=ბáƒáƒ¨áƒ™áƒ˜áƒ áƒ£áƒšáƒ˜
+Name[kk]=Башкұртша
+Name[km]=បាសគៀរ
+Name[ko]=바시킬어
+Name[lb]=Baschkiresch
+Name[lt]=Baškirų
+Name[lv]=Baškīru
+Name[mk]=Башкир
+Name[mn]=Башкир
+Name[nds]=Baschkiirsch
+Name[ne]=बासà¥à¤•à¤¿à¤°
+Name[nn]=Basjkirsk
+Name[nso]=Se-Bashkir
+Name[pa]=ਬਸਕੀਰ
+Name[pl]=Baszkirski
+Name[ro]=Başchiră
+Name[ru]=БашкирÑкий
+Name[rw]=Ikinyabashikiri
+Name[se]=Baškiriagiella
+Name[sk]=baÅ¡kirÄina
+Name[sl]=baškirsko
+Name[sq]=Bashkirisht
+Name[sr]=БашкирÑки
+Name[sr@Latn]=Baškirski
+Name[ss]=Si-Bashkir
+Name[ta]=பாகà¯à®·à¯€à®°à¯
+Name[te]=బాషà±à°•à°¿à°°à±
+Name[tg]=Бошқирдӣ
+Name[th]=ภาษาà¹à¸šà¸Šà¹€à¸„ียร์
+Name[tt]=Başqortça
+Name[uk]=БашкирÑька
+Name[uz]=Boshqircha
+Name[uz@cyrillic]=Бошқирча
+Name[vi]=Ba-x-kia
+Name[zh_CN]=巴什基尔语
+Name[zh_HK]=Bashkir語
+Name[zh_TW]=Bashkir語
+Name[zu]=Isi-Bashkir
+[be]
+Name=Belarusian
+Name[ar]=بلاروسي
+Name[az]=Belarusca
+Name[be]=БеларуÑкаÑ
+Name[bg]=БелоруÑки
+Name[bn]=বেলারà§à¦¶à¦¿à§Ÿ
+Name[br]=Belarusieg
+Name[bs]=Bjeloruski
+Name[ca]=Bielorús
+Name[cs]=Běloruský
+Name[csb]=Białorusczi
+Name[cy]=Belarwsieg
+Name[da]=Hviderussisk
+Name[de]=Weißrussisch
+Name[el]=ΛευκοÏωσικά
+Name[eo]=Bjelorusa
+Name[es]=Bieloruso
+Name[et]=Valgevene
+Name[eu]=Bielorrusiera
+Name[fa]=بلاروسی
+Name[fi]=Valkovenäjä
+Name[fr]=Bélarus
+Name[fy]=Wyt-Russysk
+Name[ga]=Bealarúisis
+Name[gl]=Bielorruso
+Name[he]=בלרוסית
+Name[hi]=बेलारूसियन
+Name[hr]=Bjeloruski
+Name[hsb]=Běłorusce
+Name[hu]=Belorusz
+Name[id]=Belarusia
+Name[is]=Hvíta-Rússneska
+Name[it]=Bielorusso
+Name[ja]=ベラルーシ語
+Name[ka]=ბელáƒáƒ áƒ£áƒ¡áƒ£áƒšáƒ˜
+Name[kk]=БелоруÑша
+Name[km]=áž”áŸáž¡áž¶ážšáž»ážŸáŸ’ស
+Name[ko]=백러시아어
+Name[lb]=Wéisrussesch
+Name[lt]=Baltarusių
+Name[lv]=Baltkrievu
+Name[mk]=БелоруÑки
+Name[mn]=БеларуÑÑ
+Name[ms]=Belarusia
+Name[mt]=Bjelorussu
+Name[nb]=Hviterussisk
+Name[nds]=Wittruss'sch
+Name[ne]=बेलारसियाली
+Name[nl]=Wit-Rusland
+Name[nn]=Kviterussisk
+Name[nso]=Se-Belarusian
+Name[pa]=ਬੇਲਾਰੂਸ
+Name[pl]=Białoruski
+Name[pt]=Bielorrusso
+Name[pt_BR]=Bielo-Russo
+Name[ro]=Belarusă
+Name[ru]=БелоруÑÑкий
+Name[rw]=Ikibelarusiya
+Name[se]=Vilgesruoššagiella
+Name[sk]=bieloruština
+Name[sl]=belorusko
+Name[sq]=Bellorusisht
+Name[sr]=БелоруÑки
+Name[sr@Latn]=Beloruski
+Name[ss]=Si-Belarusian
+Name[sv]=Vitryska
+Name[ta]=பெலாரூசியனà¯
+Name[te]=బెలరషియనà±
+Name[tg]=БелоруÑÓ£
+Name[th]=ภาษาเบลารุสเซีย
+Name[tr]=Belarus Dili
+Name[tt]=Belarusça
+Name[uk]=БілоруÑька
+Name[uz]=Beloruscha
+Name[uz@cyrillic]=БелоруÑча
+Name[vi]=Be-la-ru-xợ
+Name[wa]=Bielorûsse
+Name[zh_CN]=白俄罗斯语
+Name[zh_HK]=白俄羅斯語
+Name[zh_TW]=白俄羅斯語
+Name[zu]=Isi-Belarusian
+[bg]
+Name=Bulgarian
+Name[af]=Bulgaars
+Name[ar]=البلغارية
+Name[az]=Bolqarca
+Name[be]=БалгарÑкаÑ
+Name[bg]=БългарÑки
+Name[bn]=বà§à¦²à¦—েরিয়
+Name[br]=Bulgareg
+Name[bs]=Bugarski
+Name[ca]=Búlgar
+Name[cs]=Bulharský
+Name[csb]=Bùlgarsczi
+Name[cy]=Bwlgareg
+Name[da]=Bulgarsk
+Name[de]=Bulgarisch
+Name[el]=ΒουλγαÏικά
+Name[eo]=Bulgara
+Name[es]=Búlgaro
+Name[et]=Bulgaaria
+Name[eu]=Bulgariera
+Name[fa]=بلغاری
+Name[fi]=Bulgaria
+Name[fr]=Bulgare
+Name[fy]=Bulgaarsk
+Name[ga]=Bulgáiris
+Name[gl]=Búlgaro
+Name[he]=בולגרית
+Name[hi]=बलà¥à¤—ारियन
+Name[hr]=Bugarski
+Name[hsb]=Bołharsce
+Name[hu]=Bolgár
+Name[id]=Bulgaria
+Name[is]=Búlgarska
+Name[it]=Bulgaro
+Name[ja]=ブルガリア語
+Name[ka]=ბულგáƒáƒ áƒ£áƒšáƒ˜
+Name[kk]=Болғарша
+Name[km]=ប៊ុលហ្ការី
+Name[ko]=불가리아어
+Name[lb]=Bulgaresch
+Name[lt]=Bulgarų
+Name[lv]=BulgÄru
+Name[mi]=Reo Purukeria
+Name[mk]=БугарÑки
+Name[mn]=Болгар
+Name[ms]=Bulgaria
+Name[mt]=Bulgaru
+Name[nb]=Bulgarsk
+Name[nds]=Bulgaarsch
+Name[ne]=बà¥à¤²à¥à¤—ेरियाली
+Name[nl]=Bulgaars
+Name[nn]=Bulgarsk
+Name[nso]=Se-Bulgarian
+Name[oc]=Bulgar
+Name[pa]=ਬà©à¨²à¨—ਾਰੀਆ
+Name[pl]=Bułgarski
+Name[pt]=Búlgaro
+Name[pt_BR]=Búlgaro
+Name[ro]=Bulgară
+Name[ru]=БолгарÑкий
+Name[rw]=Ikinyabulugariya
+Name[se]=Bulgáriagiella
+Name[sk]=bulharÄina
+Name[sl]=bolgarsko
+Name[sq]=Bullgarisht
+Name[sr]=БугарÑки
+Name[sr@Latn]=Bugarski
+Name[ss]=Si-Bulgarian
+Name[sv]=Bulgariska
+Name[ta]=பலà¯à®•à¯‡à®°à®¿à®¯à®©à¯
+Name[te]=బలà±à°—ెరియనà±
+Name[tg]=Булғорӣ
+Name[th]=ภาษาบัลà¹à¸à¹€à¸£à¸µà¸¢
+Name[tr]=Bulgarca
+Name[tt]=Bulgarça
+Name[uk]=БолгарÑька
+Name[uz]=Bolgarcha
+Name[uz@cyrillic]=Болгарча
+Name[vi]=Bảo-gia-lơi
+Name[wa]=Bulgåre
+Name[zh_CN]=ä¿åŠ åˆ©äºšè¯­
+Name[zh_HK]=ä¿åŠ åˆ©äºžèªž
+Name[zh_TW]=ä¿åŠ åˆ©äºžèªž
+Name[zu]=Isi-Bulgarian
+[bh]
+Name=Bihari
+Name[ar]=بهاري
+Name[az]=BiharicÉ™
+Name[be]=БіхарÑкаÑ
+Name[bg]=Бихари
+Name[bn]=বিহারী
+Name[ca]=Biharí
+Name[cy]=Bihareg
+Name[de]=Biharisch
+Name[fa]=بیهاری
+Name[fy]=Bihary
+Name[ga]=Bihairis
+Name[he]=ביהרי
+Name[hi]=बिहारी
+Name[hr]=Biharski
+Name[ja]=ビãƒãƒ¼ãƒ«èªž
+Name[ka]=ბიჰáƒáƒ áƒ˜
+Name[kk]=Бихарша
+Name[km]=បិហារ
+Name[ko]=비하르어
+Name[lb]=Biharesch
+Name[mk]=Бихари
+Name[mn]=Бихари
+Name[ne]=बिहारी
+Name[nso]=Se-Bihari
+Name[pa]=ਬਿਹਾਰੀ
+Name[ru]=БихарÑкий
+Name[rw]=Ikibihari
+Name[se]=Biháragiella
+Name[sk]=bihárske jazyky
+Name[sl]=bihari
+Name[sq]=Biharisht
+Name[sr]=БихарÑки
+Name[sr@Latn]=Biharski
+Name[ss]=Si-Bihari
+Name[ta]=பீகாரி
+Name[te]=బిహారి
+Name[tg]=Бихарӣ
+Name[th]=ภาษาบิฮาริ
+Name[tt]=Biharça
+Name[uk]=Біхарі
+Name[uz]=Bixari
+Name[uz@cyrillic]=Бихари
+Name[vi]=Bi-ha-ri
+Name[zh_CN]=比哈里语
+Name[zh_HK]=比哈爾語
+Name[zh_TW]=比哈爾語
+Name[zu]=Isi-Bihari
+[bi]
+Name=Bislama
+Name[ar]=بيسلاما
+Name[az]=Bislamaca
+Name[be]=БіÑламÑкаÑ
+Name[bg]=БиÑлама
+Name[bn]=বিসলামা
+Name[cy]=Bislameg
+Name[fa]=بیسلاما
+Name[fr]=Bichlamar
+Name[ga]=Bioslamais
+Name[he]=ביסלמה
+Name[hi]=बिसà¥à¤²à¤¾à¤®à¤¾
+Name[hr]=Bislamski
+Name[hu]=Biszlama
+Name[ja]=ビスラマ語
+Name[ka]=ბისლáƒáƒ›áƒ
+Name[kk]=БиÑамша
+Name[km]=បីសឡាម៉ា
+Name[ko]=비슬ë¼ë§ˆì–´
+Name[mk]=БиÑлама
+Name[mn]=БиÑлам
+Name[ne]=बिसà¥à¤²à¤¾à¤®à¤¾
+Name[nso]=Se-Bislama
+Name[pa]=ਬਿਸਲਾਮਾ
+Name[ru]=БиÑлама
+Name[rw]=Ikibisilamu
+Name[se]=Bislamagiella
+Name[sk]=bislama
+Name[sl]=bislama
+Name[sq]=Bislamisht
+Name[sr]=БиÑламÑки
+Name[sr@Latn]=Bislamski
+Name[ss]=Si-Bislama
+Name[ta]=பிஸà¯à®²à®¾à®®à®¾
+Name[te]=బిసà±à°²à°®à°¾
+Name[tg]=БиÑлама
+Name[th]=ภาษาบิสลามา
+Name[tt]=Bislamaça
+Name[uk]=БіÑлама
+Name[uz@cyrillic]=БиÑлама
+Name[vi]=Bit-la-ma
+Name[zh_CN]=比斯拉马语
+Name[zh_HK]=Bislama語
+Name[zh_TW]=Bislama語
+Name[zu]=Isi-Bislama
+[bn]
+Name=Bengali
+Name[ar]=بنغالي
+Name[az]=Benqalca
+Name[be]=БенгальÑкаÑ
+Name[bg]=Бенгали
+Name[bn]=বাংলা
+Name[br]=Bangali
+Name[bs]=Bengalski
+Name[ca]=Bengalí
+Name[cs]=Bengálský
+Name[csb]=Bengalsczi
+Name[cy]=Bengaleg
+Name[eo]=Bengala
+Name[es]=Bengalí
+Name[eu]=Bengalera
+Name[fa]=بنگلادشی
+Name[fy]=Bengaalsk
+Name[ga]=Beangáilis
+Name[he]=בנגלית
+Name[hi]=बंगाली
+Name[hr]=Bengalski
+Name[hsb]=Bengalsce
+Name[hu]=Bengáli
+Name[is]=Bengalst
+Name[it]=Bengalese
+Name[ja]=ベンガル語
+Name[ka]=ბენგáƒáƒšáƒ˜
+Name[kk]=Бенгали
+Name[km]=áž”áŸáž“្កាលី
+Name[ko]=벵갈어
+Name[lb]=Bengalesch
+Name[lt]=Bengalų
+Name[lv]=BengÄļu
+Name[mk]=БенгалÑки
+Name[mn]=Бенгали
+Name[nds]=Bengaalsch
+Name[ne]=बङà¥à¤—ाली
+Name[nso]=Se-Bengali
+Name[pa]=ਬੰਗਾਲੀ
+Name[pl]=Bengalski
+Name[ru]=Бенгали
+Name[rw]=Ikibengali
+Name[se]=Bengalagiella
+Name[sk]=bengálÄina
+Name[sl]=bengalsko
+Name[sq]=Bengalisht
+Name[sr]=БенгалÑки
+Name[sr@Latn]=Bengalski
+Name[ss]=Si-Bengali
+Name[ta]=பெஙà¯à®•à®¾à®²à®¿
+Name[te]=బెంగాలి
+Name[tg]=Бенголӣ
+Name[th]=ภาษาเบงà¸à¸²à¸¥à¸µ
+Name[tr]=Bengal
+Name[tt]=Bengalça
+Name[uk]=БенгальÑька
+Name[uz]=Bengalcha
+Name[uz@cyrillic]=Бенгалча
+Name[vi]=Ben-ga-li
+Name[zh_CN]=孟加拉语
+Name[zh_HK]=孟加拉語
+Name[zh_TW]=孟加拉語
+Name[zu]=Isi-Bengali
+[bo]
+Name=Tibetan
+Name[ar]=تبتي
+Name[az]=TibetcÉ™
+Name[be]=ТыбецкаÑ
+Name[bg]=ТибетÑки
+Name[bn]=তিবà§à¦¬à¦¤à§€
+Name[br]=Yezh an Tibet
+Name[bs]=Tibetanski
+Name[ca]=Tibetà
+Name[cs]=Tibetský
+Name[csb]=Tibetańsczi
+Name[cy]=Tibeteg
+Name[da]=Tibetansk
+Name[de]=Tibetisch
+Name[el]=Θιβετιανά
+Name[eo]=Tibeta
+Name[es]=Tibetano
+Name[et]=Tiibeti
+Name[eu]=Tibetera
+Name[fa]=تیبوتیایی
+Name[fi]=Tiibet
+Name[fr]=Tibétain
+Name[fy]=Tibetaansk
+Name[ga]=Tibéidis
+Name[gl]=Tibetano
+Name[he]=טיבטית
+Name[hi]=तिबà¥à¤¤à¥€
+Name[hr]=Tibetanski
+Name[hsb]=Tibetisce
+Name[hu]=Tibeti
+Name[id]=Tibet
+Name[is]=Tíbeska
+Name[it]=Tibetano
+Name[ja]=ãƒãƒ™ãƒƒãƒˆèªž
+Name[ka]=ტიბეტური
+Name[kk]=Тибетше
+Name[km]=ទីបáŸ
+Name[ko]=티벳어
+Name[lb]=Tibetanesch
+Name[lt]=TibetieÄių
+Name[lv]=Tibetiešu
+Name[mk]=ТибетанÑки
+Name[mn]=Төвд
+Name[ms]=Tibet
+Name[nb]=Tibetansk
+Name[nds]=Tibeetsch
+Name[ne]=तिबà¥à¤¬à¤¤à¥€
+Name[nl]=Tibetaans
+Name[nn]=Tibetansk
+Name[nso]=Se-Tibetan
+Name[pa]=ਤਿੱਬਤੀ
+Name[pl]=Tybetański
+Name[pt]=Tibetano
+Name[pt_BR]=Tibetano
+Name[ro]=Tibetană
+Name[ru]=ТибетÑкий
+Name[rw]=Ikinyatibeti
+Name[se]=Tibehtagiella
+Name[sk]=tibetÄina
+Name[sl]=tibetansko
+Name[sq]=Tibetisht
+Name[sr]=ТибетанÑки
+Name[sr@Latn]=Tibetanski
+Name[ss]=Si-Tibetan
+Name[sv]=Tibetanska
+Name[ta]=திபெதà¯à®¤à®¿à®¯à®©à¯
+Name[te]=టిబెటియనà±
+Name[tg]=Тибетӣ
+Name[th]=ภาษาฑิเบต
+Name[tt]=Tibetçä
+Name[uk]=ТибетÑька
+Name[uz]=Tibetcha
+Name[uz@cyrillic]=Тибетча
+Name[vi]=Tây-tạng
+Name[wa]=Tibetyin
+Name[zh_CN]=è—语
+Name[zh_HK]=è—語
+Name[zh_TW]=è—語
+Name[zu]=Isi-Tibetan
+[br]
+Name=Breton
+Name[ar]=البريتون
+Name[az]=Bretonca
+Name[be]=БрÑтонÑкаÑ
+Name[bg]=БретонÑки
+Name[bn]=বà§à¦°à§‡à¦Ÿà¦¨
+Name[br]=Brezhoneg
+Name[bs]=Bretonski
+Name[ca]=Bretó
+Name[cs]=Bretonský
+Name[csb]=Bretońsczi
+Name[cy]=Llydaweg
+Name[da]=Bretonsk
+Name[de]=Bretonisch
+Name[el]=Î’Ïετονικά
+Name[eo]=Bretona
+Name[es]=Bretón
+Name[et]=Bretooni
+Name[eu]=Bretoiera
+Name[fa]=برتونیایی
+Name[fi]=Bretoni
+Name[fy]=Bretonsk
+Name[ga]=Briotáinis
+Name[gl]=Bretón
+Name[he]=ברטונית
+Name[hi]=बà¥à¤°à¥‡à¤Ÿà¥‹à¤¨
+Name[hr]=Bretonski
+Name[hsb]=Bretonisce
+Name[is]=Bretánska
+Name[it]=Bretone
+Name[ja]=ブルトン語
+Name[ka]=ბრეტáƒáƒœáƒ£áƒšáƒ˜
+Name[kk]=Бретонша
+Name[km]=ប្រឺážáž»áž„
+Name[ko]=브르타뉴어
+Name[lb]=Britesch
+Name[lt]=Bretonų
+Name[lv]=Bretoņu
+Name[mi]=Reo Parani Uropi-Ãnia
+Name[mk]=БретонÑки
+Name[mn]=Бретон
+Name[nb]=Bretonsk
+Name[nds]=Bretoonsch
+Name[ne]=बेलायती
+Name[nl]=Bretoens
+Name[nn]=Bretonsk
+Name[nso]=Se-Breton
+Name[oc]=Briton
+Name[pa]=ਬਰੀਟੋਨ
+Name[pl]=Bretoński
+Name[pt]=Bretão
+Name[pt_BR]=Bretão
+Name[ro]=Bretonă
+Name[ru]=БретонÑкий
+Name[rw]=Ikinyabureto
+Name[se]=Bretonagiella
+Name[sk]=bretónÄina
+Name[sl]=bretonsko
+Name[sq]=Bretonisht
+Name[sr]=БретонÑки
+Name[sr@Latn]=Bretonski
+Name[ss]=Si-Breton
+Name[sv]=Bretonska
+Name[ta]=பிரெடானà¯
+Name[te]=à°¬à±à°°à±†à°Ÿà°¨à±
+Name[tg]=Бретонӣ
+Name[th]=ภาษาเบรทตัน
+Name[tr]=Britanya Dili
+Name[tt]=Bretonça
+Name[uk]=БретонÑька
+Name[uz]=Bretoncha
+Name[uz@cyrillic]=Бретонча
+Name[vi]=Bợ-re-ton
+Name[wa]=Burton
+Name[zh_CN]=布里多尼语
+Name[zh_HK]=ä¸åˆ—塔尼語
+Name[zh_TW]=ä¸åˆ—塔尼語
+Name[zu]=Isi-Breton
+[bs]
+Name=Bosnian
+Name[af]=Bosnies
+Name[ar]=البوسنية
+Name[az]=Bosnakca
+Name[be]=БаÑнійÑкаÑ
+Name[bg]=БоÑненÑки
+Name[bn]=বসনীয়
+Name[br]=Bosnieg
+Name[bs]=Bosanski
+Name[ca]=Bosnià
+Name[cs]=Bosenský
+Name[csb]=Bósniany
+Name[cy]=Bosneg
+Name[da]=Bosnisk
+Name[de]=Bosnisch
+Name[el]=Βοσνιακά
+Name[eo]=Bosnia
+Name[es]=Bosnio
+Name[et]=Bosnia
+Name[eu]=Bosniera
+Name[fa]=بوسنیایی
+Name[fi]=Bosnia
+Name[fr]=Bosniaque
+Name[fy]=Bosnysk
+Name[ga]=Boisnis
+Name[gl]=Bósnio
+Name[he]=בוסנית
+Name[hi]=बोसà¥à¤¨à¤¿à¤¯à¤¨
+Name[hr]=BoÅ¡njaÄki
+Name[hsb]=Bosnisce
+Name[hu]=Bosnyák
+Name[id]=Bosnia
+Name[is]=Bosníska
+Name[it]=Bosniaco
+Name[ja]=ボスニア語
+Name[ka]=ბáƒáƒ¡áƒœáƒ˜áƒ£áƒ áƒ˜
+Name[kk]=БоÑнаша
+Name[km]=បូស្នី
+Name[ko]=보스니아어
+Name[lb]=Bosnesch
+Name[lt]=Bosnių
+Name[lv]=Bosniešu
+Name[mk]=БоÑанÑки
+Name[mn]=БоÑни
+Name[ms]=Bosnia
+Name[mt]=Bożniaku
+Name[nb]=Bosnisk
+Name[nds]=Bosnisch
+Name[ne]=बोसà¥à¤¨à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Bosnisch
+Name[nn]=Bosnisk
+Name[nso]=Se-Bosnian
+Name[pa]=ਬੋਸਨੀਆ
+Name[pl]=Bośniacki
+Name[pt]=Bósnio
+Name[pt_BR]=Bósnio
+Name[ro]=Bosniacă
+Name[ru]=БоÑнийÑкий
+Name[rw]=Ikinyabosiniya
+Name[se]=Bosniagiella
+Name[sk]=bosniaÄtina
+Name[sl]=bosansko
+Name[sq]=Boshnjakisht
+Name[sr]=Бошњачки
+Name[sr@Latn]=BoÅ¡njaÄki
+Name[ss]=Si-Bosnian
+Name[sv]=Bosniska
+Name[ta]=பொஸà¯à®©à®¿à®¯à®©à¯
+Name[te]=బొసà±à°¨à°¿à°¯à°¨à±
+Name[tg]=БоÑниÑвӣ
+Name[th]=ภาษาบอสเนีย
+Name[tr]=Boşnakça
+Name[tt]=Bosniçä
+Name[uk]=БоÑнійÑька
+Name[uz]=Bosniyacha
+Name[uz@cyrillic]=БоÑниÑча
+Name[ven]=Mubosinia
+Name[vi]=Bo-x-ni-a
+Name[wa]=Bosnyin
+Name[zh_CN]=波斯尼亚语
+Name[zh_HK]=波斯尼亞語
+Name[zh_TW]=波士尼亞語
+Name[zu]=Isi-Bosnian
+[ca]
+Name=Catalan
+Name[af]=Katelaans
+Name[ar]=الكاتالونية
+Name[az]=Katalanca
+Name[be]=КаталонÑкаÑ
+Name[bg]=КаталонÑки
+Name[bn]=কà§à¦¯à¦¾à¦Ÿà¦¾à¦²à¦¾à¦¨
+Name[br]=Katalaneg
+Name[bs]=Katalonski
+Name[ca]=Català
+Name[cs]=Katalánský
+Name[csb]=Katalońsczi
+Name[cy]=Catalaneg
+Name[da]=Catalansk
+Name[de]=Katalanisch
+Name[el]=Καταλανικά
+Name[eo]=Kataluna
+Name[es]=Catalán
+Name[et]=Katalaani
+Name[eu]=Katalaniera
+Name[fa]=کاتالانی
+Name[fi]=Katalaani
+Name[fy]=Katalaansk
+Name[ga]=Catalóinis
+Name[gl]=Catalán
+Name[he]=קטלונית
+Name[hi]=केटालन
+Name[hr]=Katalonski
+Name[hsb]=Katalansce
+Name[hu]=Katalán
+Name[is]=Katalánska
+Name[it]=Catalano
+Name[ja]=カタロニア語
+Name[ka]=კáƒáƒ¢áƒáƒšáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=Каталанша
+Name[km]=កាážáž¶áž¡áž¶áž“
+Name[ko]=카탈로니아어
+Name[lb]=Katalanesch
+Name[lt]=Katalonų
+Name[lv]=Kataloņu
+Name[mi]=Reo Peina Raki Räwhiti
+Name[mk]=КаталонÑки
+Name[mn]=Каталан
+Name[mt]=Katalan
+Name[nb]=Katalansk
+Name[nds]=Katalaansch
+Name[ne]=काटालान
+Name[nl]=Catalaans
+Name[nn]=Katalansk
+Name[nso]=Se-Catalan
+Name[pa]=ਕਾਟਾਲਾਨ
+Name[pl]=Kataloński
+Name[pt]=Catalão
+Name[pt_BR]=Catalão
+Name[ro]=Catalană
+Name[ru]=КаталонÑкий
+Name[rw]=Igikatalani
+Name[se]=Katalánagiella
+Name[sk]=katalánÄina
+Name[sl]=katalonsko
+Name[sq]=Katalanisht
+Name[sr]=КаталонÑки
+Name[sr@Latn]=Katalonski
+Name[ss]=Si-Catalan
+Name[sv]=Katalanska
+Name[ta]=கடலானà¯
+Name[te]=కెటలనà±
+Name[tg]=Каталанӣ
+Name[th]=ภาษาคาตาลาน
+Name[tr]=Katalan Dili
+Name[tt]=Katalança
+Name[uk]=КаталонÑька
+Name[uz]=Katalancha
+Name[uz@cyrillic]=Каталанча
+Name[vi]=Ca-ta-lan
+Name[zh_CN]=加泰罗尼亚语
+Name[zh_HK]=嘉泰羅尼亞語
+Name[zh_TW]=嘉泰羅尼亞語
+Name[zu]=Isi-Catalan
+[ce]
+Name=Chechen
+Name[ar]=شيشاني
+Name[az]=Çexencə
+Name[be]=ЧачÑнÑкаÑ
+Name[bg]=ЧеченÑки
+Name[bn]=চেচেন
+Name[br]=Tchetcheneg
+Name[bs]=ÄŒeÄenski
+Name[ca]=Txetxè
+Name[cs]=ÄŒeÄenský
+Name[csb]=Czeczeńsczi
+Name[cy]=Checheneg
+Name[de]=Tschetschenisch
+Name[eo]=Ĉeĉena
+Name[es]=Checheno
+Name[et]=Tšetšeeni
+Name[fa]=چچنی
+Name[fi]=Tšetšeeni
+Name[fr]=Tchétchène
+Name[fy]=Tsjechysk
+Name[ga]=Seisnis
+Name[gl]=Checheno
+Name[he]=צ'צ'נית
+Name[hi]=चेचेन
+Name[hr]=ÄŒeÄenski
+Name[hsb]=ÄŒeÄenisce
+Name[hu]=Csecsen
+Name[is]=Tékkneska
+Name[it]=Ceceno
+Name[ja]=ãƒã‚§ãƒã‚§ãƒ³èªž
+Name[ka]=ჩეჩნური
+Name[kk]=Шешенше
+Name[km]=ឆáŸáž€ážˆáž·áž“
+Name[ko]=체첸어
+Name[lb]=Tschetschenesch
+Name[lt]=ČėÄÄ—nų
+Name[lv]=ÄŒeÄenu
+Name[mk]=ЧеченÑки
+Name[mn]=Чечен
+Name[nb]=Tsjetsjensk
+Name[nds]=Tschetscheensch
+Name[ne]=चेचेन
+Name[nn]=Tsjetsjensk
+Name[nso]=Se-Chechen
+Name[pa]=ਚੇਚਨ
+Name[pl]=Czeczeński
+Name[pt]=Checheno
+Name[pt_BR]=Chechênio
+Name[ro]=Cecenă
+Name[ru]=ЧеченÑкий
+Name[rw]=Igiceceni
+Name[se]=ÄŒeÄeniagiella
+Name[sk]=ÄeÄenÄina
+Name[sl]=ÄeÄensko
+Name[sq]=Çeçenisht
+Name[sr]=ЧеченÑки
+Name[sr@Latn]=ÄŒeÄenski
+Name[ss]=Si-Chechen
+Name[sv]=Tjetjenska
+Name[ta]=செசà¯à®šà¯†à®©à¯
+Name[te]=చెచనà±
+Name[tg]=Чеченӣ
+Name[th]=ภาษาเชเชน
+Name[tr]=Çeçen
+Name[tt]=Çäçänçä
+Name[uk]=ЧеченÑька
+Name[uz]=Chechencha
+Name[uz@cyrillic]=Чеченча
+Name[vi]=Che-chen
+Name[wa]=Tchetchene
+Name[zh_CN]=车臣语
+Name[zh_HK]=Chechen語
+Name[zh_TW]=Chechen語
+Name[zu]=Isi-Chechen
+[ch]
+Name=Chamorro
+Name[ar]=شامورو
+Name[az]=Xamorroca
+Name[be]=ЧаморÑкаÑ
+Name[bg]=Чаморо
+Name[bn]=চামোরো
+Name[bs]=Kamoro
+Name[cy]=Chamorreg
+Name[eo]=Ĉamora
+Name[fa]=کاماروئی
+Name[ga]=Seamóróis
+Name[he]=צ'מורו
+Name[hi]=केमोरो
+Name[hr]=ÄŒamorski
+Name[is]=Chamorró
+Name[ja]=ãƒãƒ£ãƒ¢ãƒ­èªž
+Name[ka]=ჩáƒáƒ›áƒáƒ áƒ
+Name[kk]=Чаморро
+Name[km]=ចាមូរូ
+Name[mk]=Чаморо
+Name[mn]=Чаморро
+Name[ne]=कà¥à¤¯à¤¾à¤®à¥‹à¤°à¥‹à¤¨à¥€
+Name[nso]=Se-Chamorro
+Name[pa]=ਚਾਮੂਰੂ
+Name[ro]=Camoro
+Name[ru]=Чаморро
+Name[rw]=Igishamoro
+Name[se]=Chamorrogiella
+Name[sk]=ÄamorÄina
+Name[sl]=chamorro
+Name[sq]=Kamoroisht
+Name[sr]=ЧаморÑки
+Name[sr@Latn]=ÄŒamorski
+Name[ss]=Si-Chamorro
+Name[ta]=சமாரோ
+Name[te]=చమొరà±à°°à±Š
+Name[tg]=Чаморроӣ
+Name[th]=ภาษาชามอโร
+Name[tt]=Çamorroça
+Name[uk]=Чаморо
+Name[uz@cyrillic]=Чаморро
+Name[vi]=Cha-mo-rô
+Name[zh_CN]=查莫罗语
+Name[zh_HK]=查摩洛語
+Name[zh_TW]=查摩洛語
+Name[zu]=Isi-Chamorro
+[co]
+Name=Corsican
+Name[ar]=كورسيكي
+Name[az]=Korsikaca
+Name[be]=КарÑіканÑкаÑ
+Name[bg]=КорÑиканÑки
+Name[bn]=করà§à¦¸à¦¿à¦•à¦¾à¦¨
+Name[br]=Korseg
+Name[bs]=Korzikanski
+Name[ca]=Cors
+Name[cs]=Korsický
+Name[csb]=Kòrsykańsczi
+Name[cy]=Corsiceg
+Name[da]=Korsikansk
+Name[de]=Korsisch
+Name[el]=ΚοÏσικανικά
+Name[eo]=Korsika
+Name[es]=Corso
+Name[et]=Korsika
+Name[eu]=Korsiera
+Name[fa]=کورسیکانی
+Name[fi]=Korsika
+Name[fr]=Corse
+Name[fy]=Korsikaansk
+Name[ga]=Corsaicis
+Name[gl]=Corso
+Name[he]=קורסיקנית
+Name[hi]=कॉरà¥à¤¸à¤¿à¤¯à¤¨
+Name[hr]=Korzikanski
+Name[hsb]=Korsisce
+Name[hu]=Korzikai
+Name[is]=Korsíkanska
+Name[it]=Corso
+Name[ja]=コルシカ語
+Name[ka]=კáƒáƒ áƒ¡áƒ˜áƒ™áƒ£áƒšáƒ˜
+Name[kk]=КорÑиканша
+Name[km]=កូស៊ីកា
+Name[lb]=Korsesch
+Name[lt]=KorsikieÄių
+Name[lv]=Korsikiešu
+Name[mk]=КорзиканÑки
+Name[mn]=КорÑикан
+Name[nb]=Korsikansk
+Name[nds]=Korssch
+Name[ne]=कोरà¥à¤¸à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Corsicaans
+Name[nn]=Korsikansk
+Name[nso]=Se-Corsican
+Name[pa]=ਕà©à¨°à¨¸à©€à¨•à©‡à¨¨
+Name[pl]=Korsykański
+Name[pt]=Corso
+Name[ro]=Corsicană
+Name[ru]=КорÑиканÑкий
+Name[rw]=Igikoruse
+Name[se]=Korsikagiella
+Name[sk]=korziÄtina
+Name[sl]=korzijško
+Name[sq]=Korsikanisht
+Name[sr]=КорзиканÑки
+Name[sr@Latn]=Korzikanski
+Name[ss]=Si-Corsican
+Name[sv]=Korsikanska
+Name[ta]=கோரà¯à®šà®¿à®•à®©à¯
+Name[te]=కొరà±à°¸à°¿à°•à°¨à±
+Name[tg]=КорÑиканӣ
+Name[th]=ภาษาคอร์ซิà¸à¸±à¸™
+Name[tt]=Korsikça
+Name[uk]=КорÑиканÑька
+Name[uz]=Korsikancha
+Name[uz@cyrillic]=КорÑиканча
+Name[vi]=Coa-xi-ca
+Name[wa]=Corse
+Name[zh_CN]=科西嘉语
+Name[zh_HK]=科西嘉語
+Name[zh_TW]=科西嘉語
+Name[zu]=Isi-Corsican
+[cs]
+Name=Czech
+Name[af]=Tsjeggië
+Name[ar]=التشيكية
+Name[az]=Çexcə
+Name[be]=ЧÑшÑкаÑ
+Name[bg]=Чешки
+Name[bn]=চেক
+Name[br]=Tchekeg
+Name[bs]=Češki
+Name[ca]=Txec
+Name[cs]=Český
+Name[csb]=Czesczi
+Name[cy]=Tsiec
+Name[da]=Tjekkisk
+Name[de]=Tschechisch
+Name[el]=Τσέχικα
+Name[eo]=Ĉeĥa
+Name[es]=Checo
+Name[et]=TÅ¡ehhi
+Name[eu]=Txekiera
+Name[fa]=Ú†Ú©
+Name[fi]=TÅ¡ekki
+Name[fr]=Tchèque
+Name[fy]=Tsjechysk
+Name[ga]=Seicis
+Name[gl]=Checo
+Name[he]=צ'כית
+Name[hi]=चेक
+Name[hr]=Češki
+Name[hsb]=Čěsce
+Name[hu]=Cseh
+Name[id]=Ceko
+Name[is]=Tékkneska
+Name[it]=Ceco
+Name[ja]=ãƒã‚§ã‚³èªž
+Name[ka]=ჩეხური
+Name[kk]=Чехше
+Name[km]=ឆáŸáž€
+Name[ko]=체코어
+Name[lb]=Tschechesch
+Name[lt]=Čekų
+Name[lv]=ÄŒehu
+Name[mk]=Чешки
+Name[mn]=Чех
+Name[mt]=ÄŠek
+Name[nb]=Tsjekkisk
+Name[nds]=Tschechsch
+Name[ne]=चेक
+Name[nl]=Tsjechisch
+Name[nn]=Tsjekkisk
+Name[nso]=Se-Czech
+Name[oc]=Chec
+Name[pa]=ਚੈੱਕ
+Name[pl]=Czeski
+Name[pt]=Checo
+Name[pt_BR]=Tcheco
+Name[ro]=Cehă
+Name[ru]=ЧешÑкий
+Name[rw]=Ikinyaceke
+Name[se]=ÄŒehkagiella
+Name[sk]=korziÄtina
+Name[sl]=ÄeÅ¡ko
+Name[sq]=Çekisht
+Name[sr]=Чешки
+Name[sr@Latn]=Češki
+Name[ss]=Si-Czech
+Name[sv]=Tjeckiska
+Name[ta]=செகà¯
+Name[te]=చెకà±
+Name[tg]=Чехӣ
+Name[th]=เชค
+Name[tr]=Çekçe
+Name[tt]=Çexçä
+Name[uk]=ЧеÑька
+Name[uz]=Chexcha
+Name[uz@cyrillic]=Чехча
+Name[vi]=Séc
+Name[wa]=Tcheke
+Name[zh_CN]=æ·å…‹è¯­
+Name[zh_HK]=æ·å…‹èªž
+Name[zh_TW]=æ·å…‹èªž
+Name[zu]=Isi-Czech
+[csb]
+Name=Kashubian
+Name[bg]=КашубÑки
+Name[ca]=Caixubi
+Name[da]=Kashubiansk
+Name[de]=Kaschubisch
+Name[es]=Casubio
+Name[et]=Kašuubi
+Name[fr]=Kachoube
+Name[is]=Kashubíska
+Name[it]=Casciubico
+Name[ja]=カシューブ語
+Name[km]=ážáž¶áž áž·ážáž„់
+Name[nds]=Kaschuubsch
+Name[pl]=Kaszubski
+Name[sk]=kaÅ¡ubÄtina
+Name[sr]=КашубианÑки
+Name[sr@Latn]=КашубианÑки
+Name[sv]=Kasjubiska
+[cu]
+Name=Church Slavic
+Name[az]=Kilisə Slavcası
+Name[bg]=ЦърковноÑлавÑнÑки
+Name[bn]=চারà§à¦š সà§à¦²à¦¾à¦­à¦¿à¦•
+Name[br]=Slaveg an iliz
+Name[bs]=Crkveno-slavenski
+Name[ca]=Eslau eclesiàstic
+Name[cs]=Staroslověnský
+Name[csb]=Stôrôcerwiowò-słowiańsczi
+Name[cy]=Slaveg Eglwysol
+Name[da]=Kirkeslavisk
+Name[de]=Kirchenslawisch
+Name[eo]=Eklezia Slava
+Name[es]=Eslavo eclesiástico
+Name[et]=Kirikuslaavi
+Name[eu]=Church Eslaviera
+Name[fa]=یوگوسلاویایی
+Name[fi]=Kirkkoslaavi
+Name[fr]=Slavon d'égise
+Name[fy]=Tsjerk-slavysk
+Name[ga]=Slaivis Eaglaise
+Name[gl]=Eslávo Eclesiástico
+Name[he]=סלבית כנסייתית
+Name[hi]=चरà¥à¤š सà¥à¤²à¤¾à¤µà¤¿à¤•
+Name[hr]=Crkveni pravoslavni
+Name[hsb]=Cyrkwinosłowjansce
+Name[hu]=Szláv (egyházi)
+Name[is]=Kirkju-slavneska
+Name[it]=Slavo della Chiesa
+Name[ja]=教会スラブ語
+Name[ka]=სáƒáƒ”კლესირსლáƒáƒ•áƒ£áƒ áƒ˜
+Name[kk]=Шірке ÑлавÑнша
+Name[km]=ឆឺច ស្លាវិច
+Name[ko]=êµíšŒ 슬ë¼ë¸Œì–´
+Name[lb]=Kiircheslawesch
+Name[lt]=Bažnytinė slavų
+Name[lv]=SlÄvu baznÄ«cas
+Name[mk]=ЦрковноÑловенÑки
+Name[mn]=Чүрч Ñлавик
+Name[nb]=Kirkeslavisk
+Name[nds]=Ooltslaawsch
+Name[ne]=चरà¥à¤š सà¥à¤²à¤¾à¤­à¤¿à¤•
+Name[nl]=Kerk Slavisch
+Name[nn]=Kyrkjeslavisk
+Name[nso]=Se-Church Slavic
+Name[pa]=ਚੂਰਚ ਸਲਾਵਿਨ
+Name[pl]=Starocerkiewno-słowiański
+Name[pt]=Igreja Eslava
+Name[pt_BR]=Eslavo Clássico
+Name[ro]=Slavă bisericească
+Name[ru]=Церковно-ÑлавÑнÑкий
+Name[rw]=Igisilavika
+Name[se]=Slávagiella
+Name[sk]=cirkevná slovanÄina
+Name[sl]=cerkvena slovanÅ¡Äina
+Name[sq]=Slavishte Kisthore
+Name[sr]=Црквени правоÑлавни
+Name[sr@Latn]=Crkveni pravoslavni
+Name[ss]=Si-Church Slavic
+Name[sv]=Kyrkoslaviska
+Name[ta]=சரà¯à®šà¯ ஸà¯à®²à®¾à®µà®¿à®•à¯
+Name[te]=à°šà°°à±à°šà°¿ à°¸à±à°²à°¾à°µà°¿à°•à±
+Name[tg]=СлавÑнии мазҳабӣ
+Name[th]=ภาษาเชิร์ชสลาฟ
+Name[tt]=Slavça, Çerkäw
+Name[uk]=ЦерковноÑлов'ÑнÑька
+Name[uz]=Cherkov-slovyancha
+Name[uz@cyrillic]=Черков-ÑловÑнча
+Name[ven]=Slavic Zwakereke
+Name[vi]=Xla-vơ nhà thơ
+Name[wa]=Eslave d' eglijhe
+Name[zh_CN]=宗教斯拉夫语(å¤ä»£ä¿„语)
+Name[zh_HK]=教堂斯拉夫語
+Name[zh_TW]=教堂斯拉夫語
+Name[zu]=Isi-Church Slavic
+[cv]
+Name=Chuvash
+Name[ar]=شوÙاش
+Name[az]=Çuvaşca
+Name[be]=ЧувашÑкаÑ
+Name[bg]=Чувашки
+Name[bn]=চà§à¦­à¦¾à¦¶
+Name[br]=Tchuvasheg
+Name[bs]=Čuvaš
+Name[cs]=Čuvašský
+Name[csb]=Czuwasczi
+Name[cy]=Chuvasheg
+Name[de]=Tschuwaschisch
+Name[eo]=ĈuvaÅa
+Name[et]=Tšuvaši
+Name[fa]=چواش
+Name[fi]=TÅ¡uvassi
+Name[fr]=Tchouvache
+Name[ga]=Suvais
+Name[he]=צ'ובשית
+Name[hi]=चाउवेश
+Name[hr]=Čuvaški
+Name[hsb]=Čuwašisce
+Name[hu]=Csuvas
+Name[ja]=ãƒãƒ¥ãƒ¯ã‚·ãƒ¥èªž
+Name[ka]=ჩუვáƒáƒ¨áƒ£áƒ áƒ˜
+Name[kk]=Шуашша
+Name[km]=ចូវ៉ាស
+Name[ko]=추바시어
+Name[lb]=Chuvas
+Name[lt]=Čiuvašų
+Name[lv]=Čuvašu
+Name[mk]=Чуваш
+Name[mn]=Чуваш
+Name[nds]=Tschuwasch
+Name[ne]=कà¥à¤¯à¥à¤­à¤¾à¤¸à¥€
+Name[nso]=Se-Chuvash
+Name[pa]=ਚੂਵਸ਼
+Name[pl]=Czuwaski
+Name[ro]=Ciuvaşă
+Name[ru]=ЧувашÑкий
+Name[rw]=Igicuvashi
+Name[se]=Chuvashgiella
+Name[sk]=ÄuvaÅ¡tina
+Name[sl]=chuvash
+Name[sq]=Çuvashisisht
+Name[sr]=Чувашки
+Name[sr@Latn]=Čuvaški
+Name[ss]=Si-Chuvash
+Name[sv]=Tjuvasjiska
+Name[ta]=சà¯à®µà®¾à®·à¯
+Name[te]=à°šà±à°µà°¾à°·à±
+Name[tg]=Чувашӣ
+Name[th]=ภาษาชูวาช
+Name[tt]=Çuaşça
+Name[uk]=ЧуваÑька
+Name[uz]=Chuvashcha
+Name[uz@cyrillic]=Чувашча
+Name[vi]=Chu-va-xợ
+Name[wa]=Tchouvache
+Name[zh_CN]=楚瓦什语
+Name[zh_HK]=楚瓦士語
+Name[zh_TW]=楚瓦士語
+Name[zu]=Isi-Chuvash
+[cy]
+Name=Welsh
+Name[af]=Wallies
+Name[ar]=الويلزية
+Name[az]=UelscÉ™
+Name[be]=УÑльÑкаÑ
+Name[bg]=УелÑки
+Name[bn]=ওয়েলà§â€Œà¦¶
+Name[br]=Kembraeg
+Name[bs]=Velški
+Name[ca]=Gal·lès
+Name[cs]=Welšský
+Name[csb]=Walijsczi
+Name[cy]=Cymraeg
+Name[da]=Walisisk
+Name[de]=Walisisch
+Name[el]=Ουαλικά
+Name[eo]=Valisa
+Name[es]=Galés
+Name[et]=Uelsi
+Name[eu]=Galesa
+Name[fa]=ولزی
+Name[fi]=Wales
+Name[fr]=Gallois
+Name[fy]=Welsk
+Name[ga]=Breatnais
+Name[gl]=Galés
+Name[he]=וולשית
+Name[hi]=वेलà¥à¤¶
+Name[hr]=Velški
+Name[hsb]=Kymrisce
+Name[hu]=Velszi
+Name[id]=Wales
+Name[is]=Velska
+Name[it]=Gallese
+Name[ja]=ウェールズ語
+Name[ka]=უელსური
+Name[kk]=УÑлÑше
+Name[km]=វែល
+Name[ko]=웨ì¼ìŠ¤ì–´
+Name[lb]=Walisesch
+Name[lt]=VelsieÄių
+Name[lv]=Velšu
+Name[mk]=Велшки
+Name[mn]=Вел
+Name[ms]=Wales
+Name[mt]=Welx
+Name[nb]=Walisisk
+Name[nds]=Waliessch
+Name[ne]=वेलà¥à¤¸
+Name[nn]=Walisisk
+Name[nso]=Se-Welsh
+Name[pa]=ਵਾਲਿਸ਼
+Name[pl]=Walijski
+Name[pt]=Galês
+Name[pt_BR]=Gaulês
+Name[ro]=Velşă
+Name[ru]=УÑльÑкий
+Name[rw]=Ikiwelishi
+Name[se]=Walesagiella
+Name[sk]=waleština
+Name[sl]=valižansko
+Name[sq]=Uelsh
+Name[sr]=ВелшанÑки
+Name[sr@Latn]=Velšanski
+Name[ss]=Si-Welsh
+Name[sv]=Walesiska
+Name[ta]=வெலà¯à®·à¯
+Name[te]=వెలà±à°·à±
+Name[tg]=УÑлÑÓ£
+Name[th]=ภาษาเวลช์
+Name[tt]=Welşçä
+Name[uk]=УельÑька
+Name[uz]=Uelscha
+Name[uz@cyrillic]=УÑлÑча
+Name[vi]=Ouen-x
+Name[wa]=Walès
+Name[zh_CN]=å¨å°”士
+Name[zh_HK]=å¨çˆ¾æ–¯èªž
+Name[zh_TW]=å¨çˆ¾æ–¯èªž
+Name[zu]=Isi-Welsh
+[da]
+Name=Danish
+Name[af]=Deens
+Name[ar]=الدنماركية
+Name[az]=Danimarkaca
+Name[be]=ДацкаÑ
+Name[bg]=ДатÑки
+Name[bn]=ডà§à¦¯à¦¾à¦¨à¦¿à¦¶
+Name[br]=Daneg
+Name[bs]=Danski
+Name[ca]=Danès
+Name[cs]=Dánský
+Name[csb]=Dëńsczi
+Name[cy]=Daneg
+Name[da]=Dansk
+Name[de]=Dänisch
+Name[el]=Δανέζικα
+Name[eo]=Dana
+Name[es]=Danés
+Name[et]=Taani
+Name[eu]=Daniera
+Name[fa]=دانمارکی
+Name[fi]=Tanska
+Name[fr]=Danois
+Name[fy]=Deensk
+Name[ga]=Danmhairgis
+Name[gl]=Dinamarqués
+Name[he]=דנית
+Name[hi]=दानिश
+Name[hr]=Danski
+Name[hsb]=Dansce
+Name[hu]=Dán
+Name[id]=Denmark
+Name[is]=Danska
+Name[it]=Danese
+Name[ja]=デンマーク語
+Name[ka]=დáƒáƒœáƒ˜áƒ£áƒ áƒ˜
+Name[kk]=Датша
+Name[km]=ដាណឺម៉ាក
+Name[ko]=ë´ë§ˆí¬ì–´
+Name[lb]=Dänesch
+Name[lt]=Danų
+Name[lv]=DÄņu
+Name[mi]=Reo Tenemaka
+Name[mk]=ДанÑки
+Name[mn]=Дани
+Name[mt]=Daniż
+Name[nb]=Dansk
+Name[nds]=Däänsch
+Name[ne]=डेनिश
+Name[nl]=Deens
+Name[nn]=Dansk
+Name[nso]=Se-Danish
+Name[oc]=Danès
+Name[pa]=ਡੈਨਿਸ਼
+Name[pl]=Duński
+Name[pt]=Dinamarquês
+Name[pt_BR]=Dinamarquês
+Name[ro]=Daneză
+Name[ru]=ДатÑкий
+Name[rw]=Ikidanwa
+Name[se]=Dánskkagiella
+Name[sk]=dánÄina
+Name[sl]=dansko
+Name[sq]=Danisht
+Name[sr]=ДанÑки
+Name[sr@Latn]=Danski
+Name[ss]=Si-Danish
+Name[sv]=Danska
+Name[ta]=டேனிஷà¯
+Name[te]=డెనిషà±
+Name[tg]=ДаниÑвӣ
+Name[th]=ภาษาเดนมาร์ค
+Name[tr]=Danimarka Dili
+Name[tt]=Dança
+Name[uk]=ДанÑька
+Name[uz]=Daniyacha
+Name[uz@cyrillic]=ДаниÑча
+Name[vi]=Äan-mạch
+Name[wa]=Daenwès
+Name[zh_CN]=丹麦语
+Name[zh_HK]=丹麥語
+Name[zh_TW]=丹麥語
+Name[zu]=Isi-Danishi
+[de]
+Name=German
+Name[af]=Duits
+Name[ar]=الألمانية
+Name[az]=Almanca
+Name[be]=ÐÑмецкаÑ
+Name[bg]=ÐемÑки
+Name[bn]=জারà§à¦®à¦¾à¦¨
+Name[br]=Alamaneg
+Name[bs]=NjemaÄki
+Name[ca]=Alemany
+Name[cs]=Německý
+Name[csb]=Miemiecczi
+Name[cy]=Almaeneg
+Name[da]=Tysk
+Name[de]=Deutsch
+Name[el]=ΓεÏμανικά
+Name[eo]=Germana
+Name[es]=Alemán
+Name[et]=Saksa
+Name[eu]=Alemaniera
+Name[fa]=آلمانی
+Name[fi]=Saksa
+Name[fr]=Allemand
+Name[fy]=Dútsk
+Name[ga]=Gearmáinis
+Name[gl]=Alemán
+Name[he]=גרמנית
+Name[hi]=जरà¥à¤®à¤¨
+Name[hr]=NjemaÄki
+Name[hsb]=Němsce
+Name[hu]=Német
+Name[id]=Jerman
+Name[is]=Þýska
+Name[it]=Tedesco
+Name[ja]=ドイツ語
+Name[ka]=გერმáƒáƒœáƒ£áƒšáƒ˜
+Name[kk]=ÐеміÑше
+Name[km]=អាល្លឺម៉ង់
+Name[ko]=ë…ì¼ì–´
+Name[lb]=Däitsch
+Name[lt]=VokieÄių
+Name[lv]=VÄcu
+Name[mi]=Reo Tiamana
+Name[mk]=ГерманÑки
+Name[mn]=Герман
+Name[ms]=Jerman
+Name[mt]=Ġermaniż
+Name[nb]=Tysk
+Name[nds]=Hoochdüütsch
+Name[ne]=जरà¥à¤®à¤¨à¥€
+Name[nl]=Duits
+Name[nn]=Tysk
+Name[nso]=Se-German
+Name[oc]=Alemani
+Name[pa]=ਜਰਮਨ
+Name[pl]=Niemiecki
+Name[pt]=Alemão
+Name[pt_BR]=Alemão
+Name[ro]=Germană
+Name[ru]=Ðемецкий
+Name[rw]=Ikidage
+Name[se]=Duiskkagiella
+Name[sk]=nemÄina
+Name[sl]=nemško
+Name[sq]=Gjermanisht
+Name[sr]=Ðемачки
+Name[sr@Latn]=NemaÄki
+Name[ss]=SiJalimani
+Name[sv]=Tyska
+Name[ta]=ஜெரà¯à®®à®©à¯
+Name[te]=జెరà±à°®à°¨à±
+Name[tg]=Олмонӣ
+Name[th]=ภาษาเยอรมัน
+Name[tr]=Almanca
+Name[tt]=Almança
+Name[uk]=Ðімецька
+Name[uz]=Nemischa
+Name[uz@cyrillic]=ÐемиÑча
+Name[ven]=Mudzhemeni
+Name[vi]=Äức
+Name[wa]=Almand
+Name[xh]=Isijamani
+Name[zh_CN]=德语
+Name[zh_HK]=德語
+Name[zh_TW]=德語
+Name[zu]=Isi-Jalimani
+[dz]
+Name=Dzongkha
+Name[ar]=الجونغا
+Name[az]=Dzunqxaca
+Name[be]=Цонга
+Name[bg]=Джонкгха
+Name[bn]=জঙখা
+Name[cy]=Dzongkhaeg
+Name[fa]=زونگخا
+Name[gl]=Dzongca
+Name[he]=ג'ונקה
+Name[hi]=à¤à¥‹à¤‚खा
+Name[ja]=ゾンカ語
+Name[ka]=ჯáƒáƒœáƒ™áƒ (ბუტáƒáƒœáƒ˜)
+Name[kk]=(Дзонгха) Бутанша
+Name[km]=ដុងហ្កា
+Name[ko]=부탄어
+Name[mk]=Ðонгха
+Name[mn]=Жонгха
+Name[ne]=जोङà¥à¤–ा
+Name[nso]=Se-Dzongkha
+Name[pa]=ਡਜ਼ੋਨਗਖਾ
+Name[ru]=Дзонгка (Бутан)
+Name[rw]=Ikinyazongika
+Name[se]=Dzongkhagiella
+Name[sk]=dzongkä
+Name[sl]=dzonkha
+Name[sq]=Xonganisht
+Name[sr]=Ðонка
+Name[sr@Latn]=Džonka
+Name[ss]=Si-Dzongkha
+Name[ta]=டà¯à®šà¯Šà®™à¯à®•à¯à®¹à®¾
+Name[te]=జొంగà±à°–
+Name[tg]=Дзонгка (Бутан)
+Name[th]=ภาษาซองคา
+Name[tt]=Dzongxaça
+Name[uk]=Дзонгка
+Name[uz]=Dzongxa
+Name[uz@cyrillic]=Дзонгха
+Name[vi]=Ä-xong-kha
+Name[wa]=Boutanès
+Name[zh_CN]=ä¸ä¸¹å®—å¡è¯­
+Name[zh_HK]=Dzongkha語
+Name[zh_TW]=Dzongkha語
+Name[zu]=Isi-Dzongkha
+[el]
+Name=Greek
+Name[af]=Grieks
+Name[ar]=اليونانية
+Name[az]=Yunanca
+Name[be]=ГрÑцкаÑ
+Name[bg]=Гръцки
+Name[bn]=গà§à¦°à§€à¦•
+Name[br]=Gresianeg
+Name[bs]=GrÄki
+Name[ca]=Grec
+Name[cs]=Řecký
+Name[csb]=Grecczi
+Name[cy]=Groeg
+Name[da]=Græsk
+Name[de]=Griechisch
+Name[el]=Ελληνικά
+Name[eo]=Greka
+Name[es]=Griego
+Name[et]=Kreeka
+Name[eu]=Grekoa
+Name[fa]=یونانی
+Name[fi]=Kreikka
+Name[fr]=Grec
+Name[fy]=Gryks
+Name[ga]=Gréigis
+Name[gl]=Grego
+Name[he]=יוונית
+Name[hi]=यूनानी
+Name[hr]=GrÄki
+Name[hsb]=Grjeksce
+Name[hu]=Görög
+Name[id]=Yunani
+Name[is]=Gríska
+Name[it]=Greco
+Name[ja]=ギリシャ語
+Name[ka]=ბერძნული
+Name[kk]=Грекше
+Name[km]=ក្រិក
+Name[ko]=그리스어
+Name[lb]=Griichesch
+Name[lt]=Graikų
+Name[lv]=GrieÄ·u
+Name[mi]=Reo Kariki
+Name[mk]=Грчки
+Name[mn]=Грек
+Name[mt]=Grieg
+Name[nb]=Gresk
+Name[nds]=Greeksch
+Name[ne]=गà¥à¤°à¥€à¤•
+Name[nl]=Grieks
+Name[nn]=Gresk
+Name[nso]=Se-Greek
+Name[oc]=Grec
+Name[pa]=ਗਰੀਕ
+Name[pl]=Grecki
+Name[pt]=Grego
+Name[pt_BR]=Grego
+Name[ro]=Greacă
+Name[ru]=ГречеÑкий
+Name[rw]=Ikigereki
+Name[se]=Greikkagiella
+Name[sk]=gréÄtina
+Name[sl]=grško
+Name[sq]=Greqisht
+Name[sr]=Грчки
+Name[sr@Latn]=GrÄki
+Name[ss]=SiGriki
+Name[sv]=Grekiska
+Name[ta]=கிரேகà¯à®•à®®à¯
+Name[te]=à°—à±à°°à±€à°•à±
+Name[tg]=Юнонӣ
+Name[th]=ภาษาà¸à¸£à¸µà¸
+Name[tr]=Yunanca
+Name[tt]=Yunança
+Name[uk]=Грецька
+Name[uz]=Yunoncha
+Name[uz@cyrillic]=Юнонча
+Name[ven]=Mugerika
+Name[vi]=Hy-lạp
+Name[wa]=Grek
+Name[xh]=isigrike
+Name[zh_CN]=希腊语
+Name[zh_HK]=希臘語
+Name[zh_TW]=希臘語
+Name[zu]=Isi-Grike
+[en]
+Name=English
+Name[af]=Engels
+Name[ar]=الإنجليزية
+Name[az]=Ä°ngliscÉ™
+Name[be]=ÐнглійÑкаÑ
+Name[bg]=ÐнглийÑки
+Name[bn]=ইংরেজ
+Name[br]=Saozneg
+Name[bs]=Engleski
+Name[ca]=Anglès
+Name[cs]=Anglický
+Name[csb]=Anielsczi
+Name[cy]=Saesneg
+Name[da]=Engelsk
+Name[de]=Englisch
+Name[el]=Αγγλικά
+Name[eo]=Angla
+Name[es]=Inglés
+Name[et]=Inglise
+Name[eu]=Ingelesa
+Name[fa]=انگلیسی
+Name[fi]=Englanti
+Name[fr]=Anglais
+Name[fy]=Ingelsk
+Name[ga]=Béarla
+Name[gl]=Inglés
+Name[he]=×נגלית
+Name[hi]=अंगà¥à¤°à¥‡à¤œà¤¼à¥€
+Name[hr]=Engleski
+Name[hsb]=Jendźelsce
+Name[hu]=Angol
+Name[id]=Inggris
+Name[is]=Enska
+Name[it]=Inglese
+Name[ja]=英語
+Name[ka]=ინგლისური
+Name[kk]=Ðғылшынша
+Name[km]=អង់គ្លáŸážŸ
+Name[ko]=ì˜ì–´
+Name[lb]=Englesch
+Name[lt]=Anglų
+Name[lv]=Angļu
+Name[mi]=Reo Päkehä
+Name[mk]=ÐнглиÑки
+Name[mn]=Ðнгли
+Name[ms]=Inggeris
+Name[mt]=Ingliż
+Name[nb]=Engelsk
+Name[nds]=Engelsch
+Name[ne]=अङà¥à¤—à¥à¤°à¥‡à¤œà¥€
+Name[nl]=Engels
+Name[nn]=Engelsk
+Name[nso]=Sekgowa
+Name[oc]=Anglès
+Name[pa]=ਅੰਗਰੇਜ਼ੀ
+Name[pl]=Angielski
+Name[pt]=Inglês
+Name[pt_BR]=Inglês
+Name[ro]=Engleză
+Name[ru]=ÐнглийÑкий
+Name[rw]=Icyongereza
+Name[se]=EÅ‹gelasgiella
+Name[sk]=angliÄtina
+Name[sl]=angleško
+Name[sq]=Anglisht
+Name[sr]=ЕнглеÑки
+Name[sr@Latn]=Engleski
+Name[ss]=SiNgisi
+Name[sv]=Engelska
+Name[ta]=ஆஙà¯à®•à®¿à®²à®®à¯
+Name[te]=ఆంగà±à°²à°‚
+Name[tg]=ÐнглиÑÓ£
+Name[th]=ภาษาอังà¸à¸¤à¸©
+Name[tr]=Ä°ngilizce
+Name[tt]=İnglizçä
+Name[uk]=ÐнглійÑька
+Name[uz]=Inglizcha
+Name[uz@cyrillic]=Инглизча
+Name[ven]=Luisimane
+Name[vi]=Anh
+Name[wa]=Inglès
+Name[xh]=Isingesi
+Name[zh_CN]=英语
+Name[zh_HK]=英語
+Name[zh_TW]=英語
+Name[zu]=Isi-Ngisi
+[en_GB]
+Name=British English
+Name[af]=Britse Engels
+Name[be]=ÐнглійÑÐºÐ°Ñ Ð±Ñ€Ñ‹Ñ‚Ð°Ð½ÑкаÑ
+Name[bg]=БританÑки английÑки
+Name[bn]=বৃটিশ ইংরেজি
+Name[br]=Saozneg eus Bro Saoz
+Name[bs]=Britanski engleski
+Name[ca]=Anglès britànic
+Name[cs]=Britská angliÄtina
+Name[csb]=Britijsczi anielsczi
+Name[cy]=Saesneg Prydain
+Name[da]=Britisk engelsk
+Name[de]=Englisch (UK)
+Name[el]=Αγγλικά (Îœ. Î’Ïετανίας)
+Name[eo]=Brita Angla
+Name[es]=Inglés británico
+Name[et]=Briti inglise
+Name[eu]=Ingelesa (britainiarra)
+Name[fa]=انگلیسی بریتانیایی
+Name[fi]=Brittienglanti
+Name[fr]=Anglais britannique
+Name[fy]=Britsk Ingelsk
+Name[ga]=Béarla na Sasanach
+Name[gl]=Inglés de GB
+Name[he]=×נגלית בריטית
+Name[hr]=Britanski Engleski
+Name[hsb]=Jendźelsce (WB)
+Name[hu]=Angol (brit)
+Name[id]=Inggris Inggris
+Name[is]=Bresk enska
+Name[it]=Inglese britannico
+Name[ja]=イギリス英語
+Name[ka]=ინგლისური (დიდი ბრიტáƒáƒœáƒ”თი)
+Name[kk]=Британдық ағылшынша
+Name[km]=អង់គ្លáŸážŸ (អង់គ្លáŸážŸ)
+Name[lb]=Britescht Englesch
+Name[lt]=Anglų (D.Britanijos)
+Name[lv]=Britu angļu
+Name[mk]=ÐнглиÑки (британÑки)
+Name[nb]=Britisk engelsk
+Name[nds]=Britsch Engelsch
+Name[ne]=बेलायती अङà¥à¤—à¥à¤°à¥‡à¤œà¥€
+Name[nl]=Engels (Brits)
+Name[nn]=Engelsk (Storbritannia)
+Name[pa]=ਅੰਗਰੇਜ਼ੀ ਬਰਤਾਨੀਆ
+Name[pl]=Angielski brytyjski
+Name[pt]=Inglês da Grã-Bretanha
+Name[pt_BR]=Inglês Britânico
+Name[ro]=Engleză britanică
+Name[ru]=ÐнглийÑкий (ВеликобританиÑ)
+Name[rw]=Icyongereza, Nyongereza
+Name[se]=EÅ‹gelasgiella (Stuorra Brittania)
+Name[sk]=angliÄtina (Spojené kráľovstvo)
+Name[sl]=britansko angleško
+Name[sr]=БританÑки енглеÑки
+Name[sr@Latn]=Britanski engleski
+Name[sv]=Brittisk engelska
+Name[ta]=பிரிடà¯à®Ÿà®¿à®·à¯ ஆஙà¯à®•à®¿à®²à®®à¯
+Name[te]=à°¬à±à°°à°¿à°Ÿà°¿à°·à± ఆంగà±à°²à°‚
+Name[tg]=ÐнглиÑÓ£(Британӣ)
+Name[th]=ภาษาอังà¸à¸¤à¸© บริติช
+Name[tr]=Ä°ngiliz Ä°ngilizcesi
+Name[tt]=İnglizçä (Britania)
+Name[uk]=ÐнглійÑька (ВеликобританіÑ)
+Name[uz]=Inglizcha (Angliya)
+Name[uz@cyrillic]=Инглизча (ÐнглиÑ)
+Name[vi]=Anh (quốc Anh)
+Name[wa]=Inglès britanike
+Name[zh_CN]=英国英语
+Name[zh_HK]=英å¼è‹±èªž
+Name[zh_TW]=(英å¼ï¼‰è‹±èªž
+[en_US]
+Name=American English
+Name[af]=Amerikaanse Engels
+Name[be]=ÐнглійÑÐºÐ°Ñ Ð°Ð¼ÐµÑ€Ñ‹ÐºÐ°Ð½ÑкаÑ
+Name[bg]=ÐмериканÑки английÑки
+Name[bn]=মারà§à¦•à¦¿à¦¨ ইংরেজি
+Name[br]=Saozneg eus SUA
+Name[bs]=AmeriÄki engleski
+Name[ca]=Anglès americà
+Name[cs]=Americká angliÄtina
+Name[csb]=Amerikańsczi anielsczi
+Name[da]=Amerikansk engelsk
+Name[de]=Englisch (US)
+Name[el]=Αγγλικά (ΑμεÏικής)
+Name[eo]=Usona Angla
+Name[es]=Inglés americano
+Name[et]=Ameerika inglise
+Name[eu]=Ingelesa (amerikarra)
+Name[fa]=انگلیسی امریکایی
+Name[fi]=Amerikanenglanti
+Name[fr]=Anglais américain
+Name[fy]=Amerikaansk Ingelsk
+Name[ga]=Béarla Mheiriceá
+Name[gl]=Inglés Americano
+Name[he]=×נגלית ×מרק×ית
+Name[hr]=AmeriÄki Engleski
+Name[hsb]=Jendźelsce (USA)
+Name[hu]=Angol (amerikai)
+Name[id]=Inggris Amerika
+Name[is]=Bandarísk enska
+Name[it]=Inglese americano
+Name[ja]=アメリカ英語
+Name[ka]=ინგლისური (áƒáƒ¨áƒ¨)
+Name[kk]=Ðмерикандық ағылшынша
+Name[km]=អង់គ្លáŸážŸ អាមáŸážšáž·áž€
+Name[lb]=Amerikanescht Englesch
+Name[lt]=Anglų (JAV)
+Name[lv]=AmerikÄņu angļu
+Name[mk]=ÐнглиÑки (американÑки)
+Name[nb]=Amerikansk engelsk
+Name[nds]=Amerikaansch Engelsch
+Name[ne]=अमेरेकी अङà¥à¤—à¥à¤°à¥‡à¤œà¥€
+Name[nl]=Engels (Amerikaans)
+Name[nn]=Engelsk (USA)
+Name[pa]=ਅੰਗਰੇਜ਼ੀ ਅਮਰੀਕੀ
+Name[pl]=Angielski amerykański
+Name[pt]=Inglês Americano
+Name[pt_BR]=Inglês Americano
+Name[ro]=Engleză americană
+Name[ru]=ÐнглийÑкий (СШÐ)
+Name[rw]=Icyongereza cy'Amerika
+Name[se]=Eŋgelasgiella (Amerihkáhlaš)
+Name[sk]=angliÄtina (USA)
+Name[sl]=ameriško angleško
+Name[sr]=Ðмерички енглеÑки
+Name[sr@Latn]=AmeriÄki engleski
+Name[sv]=Amerikansk engelska
+Name[ta]=அமெரிகà¯à®•à®©à¯ ஆஙà¯à®•à®¿à®²à®®à¯
+Name[te]=అమెరికనౠఆంగà±à°²à°‚
+Name[tg]=ÐнглиÑÓ£(Ðмрикоӣ)
+Name[th]=ภาษาอังà¸à¸¤à¸© อเมริà¸à¸±à¸™
+Name[tr]=Amerikan Ä°ngilizcesi
+Name[tt]=İnglizçä (Amerika)
+Name[uk]=ÐнглійÑька (СШÐ)
+Name[uz]=Inglizcha (AQSH)
+Name[uz@cyrillic]=Инглизча (ÐҚШ)
+Name[vi]=Anh (Mỹ)
+Name[zh_CN]=美国英语
+Name[zh_HK]=美å¼è‹±èªž
+Name[zh_TW]=美語
+[eo]
+Name=Esperanto
+Name[ar]=الإسبرانتو
+Name[az]=Esperantoca
+Name[be]=ЭÑперанта
+Name[bg]=ЕÑперанто
+Name[bn]=à¦à¦¸à§à¦ªà¦¾à¦°à¦¾à¦¨à§à¦¤à§‹
+Name[br]=Esperanteg
+Name[eu]=Esperantoa
+Name[fa]=اسپرانتور
+Name[fr]=Espéranto
+Name[he]=×ספרנטו
+Name[hi]=à¤à¤¸à¥à¤ªà¤°à¥‡à¤‚तो
+Name[hu]=Eszperantó
+Name[ja]=エスペラント語
+Name[ka]=ესპერáƒáƒœáƒ¢áƒ
+Name[kk]=ЭÑперанто
+Name[km]=អáŸážŸáŸ’áž–áŸážšáŸ‰áž¶áž“់ážáž¼
+Name[ko]=ì—스페란토
+Name[mk]=ЕÑперанто
+Name[mn]=ÐÑпиранто
+Name[ne]=इसà¥à¤ªà¥‡à¤°à¤¾à¤¨à¥à¤¤à¥‹
+Name[nso]=Se-Esperanto
+Name[oc]=Esperantò
+Name[pa]=ਇਸਪੀਰਨਟੋ
+Name[ru]=ЭÑперанто
+Name[rw]=Icyesiperanto
+Name[sk]=esperanto
+Name[sl]=esperanto
+Name[sr]=ЕÑперанто
+Name[ss]=Si-Esperanto
+Name[ta]=எஸà¯à®ªà®°à®¾à®©à¯à®Ÿà¯‹
+Name[te]=à°Žà°¸à±à°ªà°°à°¾à°¨à±à°Ÿà±Š
+Name[tg]=ЭÑперантоӣ
+Name[th]=ภาษาเอสเปอร์รันโต
+Name[tt]=Esperantoça
+Name[uk]=ЕÑперанто
+Name[uz@cyrillic]=ЭÑперанто
+Name[vi]=Ét-pe-ran-tô
+Name[zh_CN]=世界语
+Name[zh_HK]=世界語
+Name[zh_TW]=世界語
+Name[zu]=Isi-Esperanto
+[es]
+Name=Spanish
+Name[af]=Spaans
+Name[ar]=الأسبانية
+Name[az]=Ä°spanca
+Name[be]=ІÑпанÑкаÑ
+Name[bg]=ИÑпанÑки
+Name[bn]=সà§à¦ªà§à¦¯à¦¾à¦¨à¦¿à¦¶
+Name[br]=Spagnoleg
+Name[bs]=Å panski
+Name[ca]=Espanyol
+Name[cs]=Španělský
+Name[csb]=Szpańsczi
+Name[cy]=Sbaeneg
+Name[da]=Spansk
+Name[de]=Spanisch
+Name[el]=Ισπανικά
+Name[eo]=Hispana
+Name[es]=Español
+Name[et]=Hispaania
+Name[eu]=Gaztelera
+Name[fa]=اسپانیایی
+Name[fi]=Espanja
+Name[fr]=Espagnol
+Name[fy]=Spaansk
+Name[ga]=Spáinnis
+Name[gl]=Castellano
+Name[he]=ספרדית
+Name[hi]=सà¥à¤ªà¥‡à¤¨à¥€
+Name[hr]=Å panjolski
+Name[hsb]=Å panisce
+Name[hu]=Spanyol
+Name[id]=Spanyol
+Name[is]=Spánska
+Name[it]=Spagnolo
+Name[ja]=スペイン語
+Name[ka]=ესპáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=ИÑпанша
+Name[km]=អáŸážŸáŸ’ប៉ាញ
+Name[ko]=스페ì¸ì–´
+Name[lb]=Spuenesch
+Name[lt]=Ispanų
+Name[lv]=SpÄņu
+Name[mi]=Reo Peina
+Name[mk]=ШпанÑки
+Name[mn]=ИÑпани
+Name[ms]=Sepanyol
+Name[mt]=Spanjol
+Name[nb]=Spansk
+Name[nds]=Spaansch
+Name[ne]=सà¥à¤ªà¥‡à¤¨à¤¿à¤¶
+Name[nl]=Spaans
+Name[nn]=Spansk
+Name[nso]=Se-Spanish
+Name[oc]=Espanhòl
+Name[pa]=ਸਪੇਨੀ
+Name[pl]=Hiszpański
+Name[pt]=Espanhol
+Name[pt_BR]=Espanhol
+Name[ro]=Spaniolă
+Name[ru]=ИÑпанÑкий
+Name[rw]=Igisipanyole
+Name[se]=Spánskkagiella
+Name[sk]=Å¡panielÄina
+Name[sl]=Å¡pansko
+Name[sq]=Spanjollisht
+Name[sr]=ШпанÑки
+Name[sr@Latn]=Å panski
+Name[ss]=SiSpanishi
+Name[sv]=Spanska
+Name[ta]=ஸà¯à®ªà®¾à®©à®¿à®¯
+Name[te]=à°¸à±à°ªà±†à°¨à°¿à°·à±
+Name[tg]=ИÑпанӣ
+Name[th]=ภาษาสเปน
+Name[tr]=Ä°spanyolca
+Name[tt]=İspança
+Name[uk]=ІÑпанÑька
+Name[uz]=Ispancha
+Name[uz@cyrillic]=ИÑпанча
+Name[vi]=Tây-ban-nha
+Name[wa]=Castiyan
+Name[xh]=Isipanishi
+Name[zh_CN]=西ç­ç‰™è¯­
+Name[zh_HK]=西ç­ç‰™èªž
+Name[zh_TW]=西ç­ç‰™èªž
+Name[zu]=Isi-Penishi
+[et]
+Name=Estonian
+Name[af]=Estonianse
+Name[ar]=الإستونية
+Name[az]=Estonca
+Name[be]=ЭÑтонÑкаÑ
+Name[bg]=ЕÑтонÑки
+Name[bn]=à¦à¦¸à§à¦Ÿà§‹à¦¨à§€à§Ÿ
+Name[br]=Estoneg
+Name[bs]=Estonski
+Name[ca]=Estonià
+Name[cs]=Estonský
+Name[csb]=Estońsczi
+Name[cy]=Estoneg
+Name[da]=Estisk
+Name[de]=Estnisch
+Name[el]=Εσθονικά
+Name[eo]=Estlanda
+Name[es]=Estonio
+Name[et]=Eesti
+Name[eu]=Estoniera
+Name[fa]=استونیایی
+Name[fi]=Eesti
+Name[fr]=Estonien
+Name[fy]=Estsk
+Name[ga]=Eastóinis
+Name[gl]=Estoniano
+Name[he]=×סטונית
+Name[hi]=à¤à¤¸à¥à¤¤à¥‹à¤¨à¤¿à¤¯à¤¨
+Name[hr]=Estonski
+Name[hsb]=Estnisce
+Name[hu]=Észt
+Name[id]=Estonia
+Name[is]=Eistneska
+Name[it]=Estone
+Name[ja]=エストニア語
+Name[ka]=ესტáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=ЭÑтонша
+Name[km]=អáŸážŸáŸ’ážáž¼áž“ី
+Name[ko]=ì—스토니아어
+Name[lb]=Estnesch
+Name[lt]=Estų
+Name[lv]=Igauņu
+Name[mi]=Reo Etonia
+Name[mk]=ЕÑтонÑки
+Name[mn]=ЭÑтони
+Name[ms]=Estonia
+Name[mt]=Estonjan
+Name[nb]=Estisk
+Name[nds]=Estnsch
+Name[ne]=इसà¥à¤Ÿà¥‹à¤¨à¤¿à¤¯à¤¨
+Name[nl]=Ests
+Name[nn]=Estisk
+Name[nso]=Se-Estonian
+Name[pa]=ਇਸਟੋਨੀਆ
+Name[pl]=Estoński
+Name[pt]=Estónio
+Name[pt_BR]=Estoniano
+Name[ro]=Estoniană
+Name[ru]=ЭÑтонÑкий
+Name[rw]=Icyesitoniya
+Name[se]=Esttegiella
+Name[sk]=estónÄina
+Name[sl]=estonsko
+Name[sq]=Estonisht
+Name[sr]=ЕÑтонÑки
+Name[sr@Latn]=Estonski
+Name[ss]=Si-Estonian
+Name[sv]=Estniska
+Name[ta]=எஸà¯à®Ÿà¯‹à®©à®¿à®¯à®©à¯
+Name[te]=à°Žà°¸à±à°Ÿà±Šà°¨à°¿à°¯à°¨à±
+Name[tg]=ЭÑтонӣ
+Name[th]=ภาษาเอสโทเนีย
+Name[tr]=Estonca
+Name[tt]=Estonça
+Name[uk]=ЕÑтонÑька
+Name[uz]=Estoncha
+Name[uz@cyrillic]=ЭÑтонча
+Name[vi]=E-x-tô-ni-a
+Name[wa]=Estonyin
+Name[zh_CN]=爱沙尼亚语
+Name[zh_HK]=愛沙尼亞語
+Name[zh_TW]=愛沙尼亞語
+Name[zu]=Isi-Estonian
+[eu]
+Name=Basque
+Name[ar]=الباسك
+Name[az]=Baskca
+Name[be]=БаÑцкаÑ
+Name[bg]=БаÑкийÑки
+Name[bn]=বাসà§à¦•
+Name[br]=Euskareg
+Name[bs]=Baskijski
+Name[ca]=Basc
+Name[cs]=Baskický
+Name[csb]=Baskijsczi
+Name[cy]=Basgeg
+Name[da]=Baskisk
+Name[de]=Baskisch
+Name[el]=Βασκικά
+Name[eo]=Vaska
+Name[es]=Vasco
+Name[et]=Baski
+Name[eu]=Euskara
+Name[fa]=باسکی
+Name[fi]=Baski
+Name[fy]=Baskysk
+Name[ga]=Bascais
+Name[gl]=Basco
+Name[he]=בסקית
+Name[hi]=बाशà¥à¤•
+Name[hr]=Baskijski
+Name[hsb]=Baskisce
+Name[hu]=Baszk
+Name[is]=Baskamál
+Name[it]=Basco
+Name[ja]=ãƒã‚¹ã‚¯èªž
+Name[ka]=ბáƒáƒ¡áƒ™áƒ£áƒ áƒ˜
+Name[kk]=БаÑкша
+Name[km]=បាស្កáŸ
+Name[ko]=바스í¬ì–´
+Name[lb]=Baskesch
+Name[lt]=Baskų
+Name[lv]=Basku
+Name[mk]=БаÑкиÑки
+Name[mn]=БаÑкү
+Name[mt]=Bask
+Name[nb]=Baskisk
+Name[nds]=Basksch
+Name[ne]=बासà¥à¤•
+Name[nl]=Baskisch
+Name[nn]=Baskisk
+Name[nso]=Se-Basque
+Name[oc]=Bascon
+Name[pa]=ਬਸਕਿਉ
+Name[pl]=Baskijski
+Name[pt]=Basco
+Name[pt_BR]=Basco
+Name[ro]=Bască
+Name[ru]=БаÑкÑкий
+Name[rw]=Ikibasike
+Name[se]=Baskalašgiella
+Name[sk]=baskiÄtina
+Name[sl]=baskovsko
+Name[sq]=Baskisht
+Name[sr]=БаÑкијÑки
+Name[sr@Latn]=Baskijski
+Name[ss]=Si-Basque
+Name[sv]=Baskiska
+Name[ta]=பாஸà¯à®•à¯
+Name[te]=బాసà±à°•à±
+Name[tg]=БаÑкӣ
+Name[th]=ภาษาบาสà¸à¹Œ
+Name[tr]=Bask Dili
+Name[tt]=Basqça
+Name[uk]=БаÑкÑька
+Name[uz]=Baskcha
+Name[uz@cyrillic]=БаÑкча
+Name[vi]=Ba-x-quợ
+Name[wa]=Basse
+Name[zh_CN]=巴斯克语
+Name[zh_HK]=巴斯克語
+Name[zh_TW]=巴斯克語
+Name[zu]=Isi-Basque
+[fa]
+Name=Farsi (Persian)
+Name[af]=Farsi (Persies)
+Name[ar]=Ùارسي
+Name[be]=ПерÑідÑкаÑ
+Name[bg]=ФарÑи
+Name[bn]=ফারà§à¦¸à¦¿ (পারà§à¦¸à¦¿à§Ÿà¦¾à¦¨)
+Name[br]=Farsieg (Persieg)
+Name[bs]=Farsi (Perzijski)
+Name[ca]=Farsi (Persa)
+Name[cs]=Farsi (Perský)
+Name[csb]=Farsi (persczi)
+Name[cy]=Farsi (Perseg)
+Name[da]=Farsi (Persisk)
+Name[de]=Farsi (Persisch)
+Name[el]=Farsi (ΠεÏσικά)
+Name[eo]=Frisa (Persa)
+Name[es]=Persa
+Name[et]=Farsi (pärsia)
+Name[eu]=Farsiera (Persiera)
+Name[fa]=Ùارسی
+Name[fi]=Farsi (Persia)
+Name[fr]=Persan
+Name[fy]=Farsysk (Persysk)
+Name[ga]=Fairsis (Peirsis)
+Name[gl]=Frisón (Pársi)
+Name[he]=פרסית
+Name[hi]=फ़ारसी (परà¥à¤¸à¤¿à¤¯à¤¨)
+Name[hr]=Farsi (Perzijski)
+Name[hsb]=Farsi (Persisce)
+Name[hu]=Fárszi (perzsa)
+Name[id]=Persia
+Name[is]=Farsi (Persneska)
+Name[it]=Farsi (Persiano)
+Name[ja]=ペルシア語
+Name[ka]=სპáƒáƒ áƒ¡áƒ£áƒšáƒ˜ (ფáƒáƒ áƒ¡áƒ˜)
+Name[kk]=ФарÑи
+Name[km]=ហ្វាស៊ី (ពឺស៊ាន)
+Name[ko]=팔시 (페르시아어)
+Name[lb]=Farsi (Persesch)
+Name[lt]=Farsi (persų)
+Name[lv]=Persiešu (Farsi)
+Name[mk]=ФарÑи (перÑиÑки)
+Name[mn]=ФарÑи (ПерÑ)
+Name[ms]=Parsi
+Name[nb]=Farsi (Persisk)
+Name[nds]=Farsi (Persisch)
+Name[ne]=फारसी (परà¥à¤¸à¤¿à¤¯à¤¨)
+Name[nl]=Farsi (Perzisch)
+Name[nn]=Persisk
+Name[pa]=ਫਾਰਸੀ (ਪਰਸ਼ੀਆਈ)
+Name[pl]=Farsi (Perski)
+Name[pt]=Farsi (Persa)
+Name[pt_BR]=Farsi (Persa)
+Name[ro]=Farsi (Persană)
+Name[ru]=ФарÑи
+Name[rw]=Igifarisi
+Name[se]=Farsigiella (Persialaš)
+Name[sk]=perzština
+Name[sl]=Farsi (perzijsko)
+Name[sr]=ФарÑи (ПерÑијÑки)
+Name[sr@Latn]=Farsi (Persijski)
+Name[sv]=Persiska
+Name[ta]=பாரà¯à®šà®¿ (பெரà¯à®šà®¿à®¯à®©à¯)
+Name[te]=ఫారà±à°¸à°¿ (పెరà±à°·à°¿à°¯à°¨à±)
+Name[tg]=ФриÑианӣ
+Name[th]=ภาษาฟาร์ซี (เปอร์เซียน)
+Name[tr]=Ä°ranca
+Name[tt]=Farsı
+Name[uk]=ФризійÑька (ПерÑька)
+Name[uz]=Forscha (Perscha)
+Name[uz@cyrillic]=ФорÑча (ПерÑча)
+Name[vi]=Pha-xi
+Name[wa]=Farsi
+Name[zh_CN]=波斯语
+Name[zh_HK]=波斯語
+Name[zh_TW]=波斯語
+[fi]
+Name=Finnish
+Name[af]=Feense
+Name[ar]=الÙنلندية
+Name[az]=FincÉ™
+Name[be]=ФінÑкаÑ
+Name[bg]=ФинÑки
+Name[bn]=ফিনিশ
+Name[br]=Finneg
+Name[bs]=Finski
+Name[ca]=Finès
+Name[cs]=Finský
+Name[csb]=Finsczi
+Name[cy]=Ffineg
+Name[da]=Finsk
+Name[de]=Finnisch
+Name[el]=Φιλανδικά
+Name[eo]=Fina
+Name[es]=Finés
+Name[et]=Soome
+Name[eu]=Finlandiera
+Name[fa]=Ùنلاندی
+Name[fi]=Suomi
+Name[fr]=Finnois
+Name[fy]=Finsk
+Name[ga]=Fionlainnis
+Name[gl]=Finlandés
+Name[he]=פינית
+Name[hi]=फिनिश
+Name[hr]=Finski
+Name[hsb]=Finsce
+Name[hu]=Finn
+Name[id]=Finlandia
+Name[is]=Finnska
+Name[it]=Finlandese
+Name[ja]=フィンランド語
+Name[ka]=ფინური
+Name[kk]=Финнша
+Name[km]=ហ្វាំងឡង់
+Name[ko]=핀란드어
+Name[lb]=Finnesch
+Name[lt]=Suomių
+Name[lv]=Somu
+Name[mi]=Reo Whinarana
+Name[mk]=ФинÑки
+Name[mn]=ФиннлÑнд
+Name[mt]=Finlandiż
+Name[nb]=Finsk
+Name[nds]=Finnsch
+Name[ne]=फिनिश
+Name[nl]=Fins
+Name[nn]=Finsk
+Name[nso]=Se-Finnish
+Name[oc]=Finlandès
+Name[pa]=ਫੈਨਿਸ਼
+Name[pl]=Fiński
+Name[pt]=Finlandês
+Name[pt_BR]=Finlandês
+Name[ro]=Finlandeză
+Name[ru]=ФинÑкий
+Name[rw]=Ikinyafinilande
+Name[se]=Suomagiella
+Name[sk]=fínÄina
+Name[sl]=finsko
+Name[sq]=Finlandisht
+Name[sr]=ФинÑки
+Name[sr@Latn]=Finski
+Name[ss]=Si-Finnish
+Name[sv]=Finska
+Name[ta]=ஃபினà¯à®©à®¿à®·à¯
+Name[te]=à°«à°¿à°¨à±à°¨à°¿à°·à±
+Name[tg]=Финӣ
+Name[th]=ภาษาฟินà¹à¸¥à¸™à¸”์
+Name[tr]=Fince
+Name[tt]=Finçä
+Name[uk]=ФінÑька
+Name[uz]=Fincha
+Name[uz@cyrillic]=Финча
+Name[vi]=Phần-lan
+Name[wa]=Finwès
+Name[zh_CN]=芬兰语
+Name[zh_HK]=芬蘭語
+Name[zh_TW]=芬蘭語
+Name[zu]=Isi-Finishi
+[fj]
+Name=Fijian
+Name[ar]=Ùيجي
+Name[az]=Fijiyaca
+Name[be]=ФіджыйÑкаÑ
+Name[bg]=Фиджи
+Name[bn]=ফিজিয়ান
+Name[br]=Fidjeg
+Name[bs]=Fidžijski
+Name[ca]=Fijí
+Name[cs]=Fidžijský
+Name[csb]=z Fiji
+Name[cy]=Fijieg
+Name[da]=Fijiansk
+Name[de]=Fidschi
+Name[eo]=FiÄia
+Name[es]=Fiyiano
+Name[et]=Fidži
+Name[eu]=Fijiera
+Name[fa]=Ùیجیایی
+Name[fi]=Fidži
+Name[fr]=Fidjien
+Name[fy]=Fijdzjysk
+Name[ga]=Fidsis
+Name[gl]=Fijiano
+Name[he]=פיגי'ת
+Name[hi]=फिज़ी
+Name[hr]=Fidžijski
+Name[hsb]=Fidźiasce
+Name[hu]=Fidzsi
+Name[it]=Figiano
+Name[ja]=フィジー語
+Name[ka]=ფიჯი
+Name[kk]=Фиджише
+Name[km]=ហ្វ៊ីហ្ស៊ី
+Name[ko]=피지어
+Name[lb]=Fidschi-Sprooch
+Name[lt]=Fidži
+Name[lv]=Fidži
+Name[mk]=ФиџиÑки
+Name[mn]=Фижи
+Name[nb]=Fijisk
+Name[nds]=Fidschi
+Name[ne]=फिजियन
+Name[nl]=Fijisch
+Name[nn]=Fijisk
+Name[nso]=Se-Fijian
+Name[pa]=ਫਿਜੀਨ
+Name[pl]=z Fiji
+Name[pt]=Fidjiano
+Name[ro]=Fijiană
+Name[ru]=Фиджи
+Name[rw]=Igifijiyani
+Name[se]=Fižigiella
+Name[sk]=fidžijÄina
+Name[sl]=fidžijsko
+Name[sq]=Figjinisht
+Name[sr]=ФиџијÑки
+Name[sr@Latn]=Fidžijski
+Name[ss]=Si-Fijian
+Name[sv]=Fijianska
+Name[ta]=ஃபிஜியனà¯
+Name[te]=ఫిజియనà±
+Name[tg]=Фиҷианӣ
+Name[th]=ภาษาฟิจิ
+Name[tt]=Fijiçä
+Name[uk]=ФіджійÑька
+Name[uz]=Fijicha
+Name[uz@cyrillic]=Фижича
+Name[vi]=Phi-gi
+Name[wa]=Fidjyin
+Name[zh_CN]=æ–济语
+Name[zh_HK]=æ–濟語
+Name[zh_TW]=æ–濟語
+Name[zu]=Isi-Fijiyani
+[fo]
+Name=Faroese
+Name[ar]=Ùروي
+Name[az]=FaroezcÉ™
+Name[be]=ФароÑкаÑ
+Name[bg]=ФарьорÑки
+Name[bn]=ফারোইস
+Name[br]=Faroeseg
+Name[bs]=Farski
+Name[ca]=Feroès
+Name[cs]=Faerský
+Name[csb]=z Òwczëch Òstrowów
+Name[cy]=Faroeg
+Name[da]=Færøsk
+Name[de]=Färöisch
+Name[eo]=Feroa
+Name[es]=Feroés
+Name[et]=Fääri
+Name[eu]=Faroera
+Name[fa]=Ùاروسی
+Name[fi]=Fääri
+Name[fr]=Féroïen
+Name[fy]=Faeroersk
+Name[ga]=Faróis
+Name[gl]=Feroés
+Name[he]=פ×רו×ית
+Name[hi]=फ़ारसी
+Name[hr]=Farski
+Name[hsb]=Farösce
+Name[hu]=Faröei
+Name[is]=Færeyska
+Name[ja]=フェーロー語
+Name[ka]=ფáƒáƒ áƒ”რული
+Name[kk]=ФароÑзше
+Name[km]=ហ្វាអáŸážšáž¼ážŸážº
+Name[lb]=Faröesch
+Name[lt]=Farerų
+Name[lv]=FÄ“ru
+Name[mk]=ФарÑки
+Name[mn]=Фаро
+Name[nb]=Færøyisk
+Name[nds]=Färöösch
+Name[ne]=फारोसी
+Name[nn]=Færøysk
+Name[nso]=Se-Faroese
+Name[pa]=ਫਾਰੋਇਸੀ
+Name[pl]=z Wysp Owczych
+Name[pt]=Faroês
+Name[ro]=Faroeză
+Name[ru]=ФарерÑкий
+Name[rw]=Igifero
+Name[se]=Fearagiella
+Name[sk]=faerÄina
+Name[sl]=fersko
+Name[sq]=Farosisht
+Name[sr]=ФарÑки
+Name[sr@Latn]=Farski
+Name[ss]=Si-Faroese
+Name[sv]=Färöiska
+Name[ta]=ஃபாரோவீஸà¯
+Name[te]=ఫారొఈసà±
+Name[tg]=ФароеÑÓ£
+Name[th]=ภาษาฟาโรอีส
+Name[tt]=Farosça
+Name[uk]=ФарерÑька
+Name[uz]=Farercha
+Name[uz@cyrillic]=Фарерча
+Name[vi]=Pha-rô
+Name[wa]=Faeroyès
+Name[zh_CN]=法罗群岛语
+Name[zh_HK]=法羅語
+Name[zh_TW]=法羅語
+Name[zu]=Isi-Faroese
+[fr]
+Name=French
+Name[af]=Franse
+Name[ar]=الÙرنسية
+Name[az]=Fransızca
+Name[be]=ФранцузÑкаÑ
+Name[bg]=ФренÑки
+Name[bn]=ফরাসী
+Name[br]=Galleg
+Name[bs]=Francuski
+Name[ca]=Francès
+Name[cs]=Francouzský
+Name[csb]=Francësczi
+Name[cy]=Frangeg
+Name[da]=Fransk
+Name[de]=Französisch
+Name[el]=Γαλλικά
+Name[eo]=Franca
+Name[es]=Francés
+Name[et]=Prantsuse
+Name[eu]=Frantsesa
+Name[fa]=Ùرانسوی
+Name[fi]=Ranska
+Name[fr]=Français
+Name[fy]=Frânsk
+Name[ga]=Fraincis
+Name[gl]=Francés
+Name[he]=צרפתית
+Name[hi]=फà¥à¤°à¥‡à¤‚च
+Name[hr]=Francuski
+Name[hsb]=Francosce
+Name[hu]=Francia
+Name[id]=Prancis
+Name[is]=Franska
+Name[it]=Francese
+Name[ja]=フランス語
+Name[ka]=ფრáƒáƒœáƒ’ული
+Name[kk]=Французша
+Name[km]=បារាំង
+Name[ko]=불어
+Name[lb]=Franzéisch
+Name[lt]=Prancūzų
+Name[lv]=FranÄu
+Name[mi]=Reo Parani
+Name[mk]=ФранцуÑки
+Name[mn]=Франц
+Name[ms]=Perancis
+Name[mt]=Franċiż
+Name[nb]=Fransk
+Name[nds]=Franzöösch
+Name[ne]=फà¥à¤°à¥‡à¤¨à¥à¤š
+Name[nl]=Frans
+Name[nn]=Fransk
+Name[nso]=Sefora
+Name[oc]=Franchimand
+Name[pa]=ਫਰੈਂਚ
+Name[pl]=Francuski
+Name[pt]=Francês
+Name[pt_BR]=Francês
+Name[ro]=Franceză
+Name[ru]=ФранцузÑкий
+Name[rw]=Igifaransa
+Name[se]=Fránskkagiella
+Name[sk]=francúzština
+Name[sl]=francosko
+Name[sq]=Frengjisht
+Name[sr]=ФранцуÑки
+Name[sr@Latn]=Francuski
+Name[ss]=SiFrentji
+Name[sv]=Franska
+Name[ta]=பிரெனà¯à®šà¯
+Name[te]=à°«à±à°°à±†à°‚à°šà±
+Name[tg]=ФранÑавӣ
+Name[th]=ภาษาà¸à¸£à¸±à¹ˆà¸‡à¹€à¸¨à¸ª
+Name[tr]=Fransızca
+Name[tt]=Fransça
+Name[uk]=Французька
+Name[uz]=Fransuzcha
+Name[uz@cyrillic]=Французча
+Name[ven]=Mufura
+Name[vi]=Pháp
+Name[wa]=Francès
+Name[xh]=Isifrentshi
+Name[zh_CN]=法语
+Name[zh_HK]=法語
+Name[zh_TW]=法語
+Name[zu]=Isi-Frentshi
+[fy]
+Name=Frisian
+Name[ar]=الÙريزية
+Name[az]=FriscÉ™
+Name[be]=ФрыÑійÑкаÑ
+Name[bg]=ФризийÑки
+Name[bn]=ফà§à¦°à¦¿à¦¸à¦¿à§Ÿà¦¾à¦¨
+Name[br]=Frisianeg
+Name[bs]=Frizijski
+Name[ca]=Frisó
+Name[cs]=Fríský
+Name[csb]=Frizëjsczi
+Name[cy]=Frisieg
+Name[da]=Frisisk
+Name[de]=Friesisch
+Name[eo]=Frisa
+Name[es]=Frisio
+Name[et]=Friisi
+Name[eu]=Frisiera
+Name[fa]=Ùریسی
+Name[fi]=Friisi
+Name[fr]=Frison
+Name[fy]=Frysk
+Name[ga]=Freaslainnis
+Name[gl]=Frísio
+Name[he]=פריזי×נית
+Name[hi]=फà¥à¤°à¤¿à¤¸à¤¿à¤¯à¤¨
+Name[hr]=Frizijski
+Name[hsb]=Frizisce
+Name[hu]=Fríz
+Name[is]=Frísneska
+Name[it]=Frisone
+Name[ja]=フリジア語
+Name[ka]=ფრიზიული
+Name[kk]=Фризше
+Name[km]=ហ្វ្រីស៊ាន
+Name[ko]=프리시안어
+Name[lb]=Friesesch
+Name[lt]=Fryzų
+Name[lv]=Frīziešu
+Name[mk]=ФризиÑки
+Name[mn]=ФриÑ
+Name[ms]=Frisia
+Name[nb]=Frisisk
+Name[nds]=Freesch
+Name[ne]=फà¥à¤°à¤¿à¤¸à¤¿à¤¯à¤¨
+Name[nl]=Frysk
+Name[nn]=Frisisk
+Name[nso]=Se-Frisian
+Name[pa]=ਫਰੀਸੀਨਿਸ
+Name[pl]=Fryzyjski
+Name[pt]=Frísio
+Name[ro]=Frisiană
+Name[ru]=ФризийÑкий
+Name[rw]=Igifuriziyani
+Name[se]=Frisagiella
+Name[sk]=frízština
+Name[sl]=frizijsko
+Name[sq]=Frisisht
+Name[sr]=ФризијÑки
+Name[sr@Latn]=Frizijski
+Name[ss]=Si-Frisian
+Name[sv]=Frisiska
+Name[ta]=ஃபரீசியனà¯
+Name[te]=à°«à±à°°à°¿à°¸à°¿à°¯à°¨à±
+Name[tg]=Фризианӣ
+Name[th]=ภาษาฟรีเชียน
+Name[uk]=ФризійÑька
+Name[uz]=Frizcha
+Name[uz@cyrillic]=Фризча
+Name[vi]=Ph-ri-xi
+Name[wa]=Frizon
+Name[zh_CN]=弗里斯兰语
+Name[zh_HK]=弗利然語
+Name[zh_TW]=弗利然語
+Name[zu]=Isi-Frisiyani
+[ga]
+Name=Irish Gaelic
+Name[af]=Ierse Gaelic
+Name[be]=ІрландÑÐºÐ°Ñ Ð³Ð°Ð»ÑŒÑкаÑ
+Name[bg]=ИрландÑки
+Name[bn]=আইরিশ গেলিক
+Name[br]=Iwerzhoneg eus Bro Iwerzhon
+Name[bs]=Irski Gaelic
+Name[ca]=Irlandès gaèlic
+Name[cs]=Galský (irština)
+Name[csb]=Irlandzczi Gaelic
+Name[da]=Irsk gælisk
+Name[de]=Irisches Gälisch
+Name[eo]=Irlanda Gaela
+Name[es]=Gaélico irlandés
+Name[et]=Iiri gaeli
+Name[eu]=Irlandar gaelikoa
+Name[fa]=اسکاتلندی ایرلندی
+Name[fi]=Irlannin gael
+Name[fr]=Gaélique irlandais
+Name[fy]=Iersk Gaelic
+Name[ga]=Gaeilge
+Name[gl]=Gaélico
+Name[he]=×’×לית ×ירית
+Name[hr]=Irski Galski
+Name[hsb]=Gaelisce (Irska)
+Name[hu]=Gall (ír)
+Name[is]=Ãrsk gelíska
+Name[it]=Gaelico irlandese
+Name[ja]=アイルランド系ゲール語
+Name[ka]=ირლáƒáƒœáƒ“იური (გáƒáƒšáƒ£áƒ áƒ˜)
+Name[kk]=Ирланд галлша
+Name[km]=អៀរឡង់ ហ្កែលិគ
+Name[lb]=Irescht Gällesch
+Name[mk]=ИрÑки галÑки
+Name[nb]=Irsk gaelisk
+Name[nds]=Irsch Gäälsch
+Name[ne]=आइरिश गà¥à¤¯à¤¾à¤²à¤¿à¤•
+Name[nl]=Gaelic (Iers)
+Name[nn]=Gælisk (Irland)
+Name[pa]=ਆਈਰਿਸ਼ ਗਾਈਲਿਕ
+Name[pl]=Irlandzki Gaelic
+Name[pt]=Galês da Irlanda
+Name[pt_BR]=Irlandês "Gaelic"
+Name[ro]=Galeză irlandeză
+Name[ru]=ГалльÑкий (ИрландиÑ)
+Name[rw]=Ikinyirilande Gayerike
+Name[se]=Irlánddalaš gaelagiella
+Name[sk]=írska gaelÄina
+Name[sl]=irsko galsko
+Name[sr]=ИрÑки галÑки
+Name[sr@Latn]=Irski galski
+Name[sv]=Irländsk galiciska
+Name[ta]=à®à®°à®¿à®·à¯ காலிகà¯
+Name[te]=à°à°°à°¿à°·à± గెలికà±
+Name[tg]=Ирландӣ (Галикӣ)
+Name[th]=ภาษาไอริชเà¸à¸¥à¸´à¸„
+Name[tr]=Ä°rlanda Galik
+Name[tt]=Galça (İrland)
+Name[uk]=ГаельÑька (ІрландіÑ)
+Name[vi]=Xen-tợ Ãi-nhÄ©-lan
+Name[zh_CN]=爱尔兰盖尔语
+Name[zh_TW]=(愛爾蘭)蓋爾語
+[gd]
+Name=Gaelic
+Name[ar]=غالي
+Name[az]=QaelikcÉ™
+Name[be]=ГальÑкаÑ
+Name[bg]=ГаелÑки
+Name[bn]=গেলিক
+Name[br]=Iwerzhoneg
+Name[ca]=Gaèlic
+Name[cs]=Galský
+Name[csb]=Celtycczi (gaelic)
+Name[cy]=Gaeleg
+Name[da]=Gælisk
+Name[de]=Gälisch
+Name[eo]=Gaela
+Name[es]=Gaélico
+Name[et]=Gaeli
+Name[eu]=Gaelikoa
+Name[fa]=اسکاتلندی
+Name[fi]=Gael
+Name[fr]=Gaélique
+Name[ga]=Gàidhlig
+Name[gl]=Gaélico
+Name[he]=×’×לית
+Name[hi]=गैलिक
+Name[hr]=Galski
+Name[hsb]=Gaelisce
+Name[hu]=Gall
+Name[is]=Gelíska
+Name[it]=Gaelico
+Name[ja]=ゲール語
+Name[ka]=გáƒáƒšáƒ£áƒ áƒ˜
+Name[kk]=Галлша
+Name[km]=ហ្កែលិគ
+Name[lb]=Gällesch
+Name[lt]=Galų
+Name[mk]=ГалÑки
+Name[mn]=Гаели
+Name[nb]=Gælisk
+Name[nds]=Gäälsch
+Name[ne]=गà¥à¤¯à¤¾à¤²à¤¿à¤•
+Name[nn]=Gælisk
+Name[nso]=Se-Gaelic
+Name[pa]=ਗਾਈਲਿਕ
+Name[pl]=celtycki (gaelic)
+Name[pt]=Galês
+Name[pt_BR]=Galês
+Name[ro]=Galică
+Name[ru]=ГалльÑкий
+Name[rw]=Ikinyagayeli
+Name[se]=Gaelagiella
+Name[sk]=gaelÄina
+Name[sl]=galsko
+Name[sq]=Galikisht
+Name[sr]=ГалÑки
+Name[sr@Latn]=Galski
+Name[ss]=Si-Gaelic
+Name[sv]=Galiciska
+Name[ta]=கேலிகà¯
+Name[te]=గెలికà±
+Name[tg]=Галӣ
+Name[th]=ภาษาเà¸à¸¥à¸´à¸„ีย
+Name[tr]=Galik
+Name[tt]=Galça
+Name[uk]=ГаельÑька
+Name[uz]=Galikcha
+Name[uz@cyrillic]=Галикча
+Name[vi]=Xen-tợ
+Name[wa]=Gayel
+Name[zh_CN]=盖尔语
+Name[zh_HK]=蓋爾語
+Name[zh_TW]=蓋爾語
+Name[zu]=Isi-Gayelikhi
+[gl]
+Name=Galician
+Name[be]=ГаліцыйÑкаÑ
+Name[bg]=ГалиÑийÑки
+Name[bn]=গেলিসিয়ান
+Name[br]=Galiseg
+Name[bs]=Galicijski
+Name[ca]=Gallec
+Name[cs]=HaliÄský
+Name[csb]=Galicëjsczi
+Name[cy]=Galiseg
+Name[da]=Galicisk
+Name[de]=Galicisch
+Name[eo]=Gaela
+Name[es]=Gallego
+Name[et]=Galeegi
+Name[eu]=Galiziera
+Name[fa]=اسکاتلندی
+Name[fi]=Gallicia
+Name[fr]=Gaélicien
+Name[fy]=Galiciaansk
+Name[ga]=Gailísis
+Name[gl]=Galego
+Name[he]=×’×לית
+Name[hr]=Galicijski
+Name[hsb]=Galicisce
+Name[hu]=Galíciai
+Name[is]=Gelíska
+Name[it]=Gallego
+Name[ja]=ガリシア語
+Name[ka]=გáƒáƒšáƒ˜áƒªáƒ˜áƒ£áƒ áƒ˜
+Name[kk]=ГалициÑша
+Name[km]=ហ្កាលីស៊ី
+Name[lb]=Galizesch
+Name[lt]=GalicieÄių
+Name[lv]=GaliciÄņu
+Name[mk]=ГалÑки
+Name[mt]=Galiċian
+Name[nb]=Gaelisk
+Name[nds]=Galizsch
+Name[ne]=गà¥à¤¯à¤¾à¤²à¤¿à¤¸à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Galicisch
+Name[nn]=Galisisk
+Name[pa]=ਗਾਈਲੀਅਨ
+Name[pl]=Galicyjski
+Name[pt]=Galego
+Name[pt_BR]=Galês
+Name[ro]=Galică
+Name[ru]=ГалицийÑкий
+Name[rw]=Ikinyagalisiya
+Name[se]=Galisiagiella
+Name[sk]=galícijÄina
+Name[sl]=galicijsko
+Name[sr]=ГалицијÑки
+Name[sr@Latn]=Galicijski
+Name[sv]=Galiciska
+Name[ta]=காலிசியனà¯
+Name[te]=గలిచియనà±
+Name[tg]=Галлӣ
+Name[th]=ภาษาà¹à¸à¸¥à¸´à¹€à¸‹à¸µà¸¢
+Name[tr]=Galce
+Name[tt]=Galisçä
+Name[uk]=ГаліÑійÑька
+Name[uz]=Galikcha
+Name[uz@cyrillic]=Галикча
+Name[ven]=Mugalata
+Name[vi]=Ga-li-ci
+Name[wa]=Galicyin
+Name[xh]=isiGalacian
+Name[zh_CN]=加利西亚语
+Name[zh_TW]=加利西亞語
+Name[zu]=Isi-Galashiyani
+[gn]
+Name=Guarani
+Name[ar]=غوراني
+Name[az]=Quaranca
+Name[be]=ГуÑрані
+Name[bg]=Гуарани
+Name[bn]=গà§à§Ÿà¦¾à¦°à¦¾à¦¨à¦¿
+Name[ca]=Guaraní
+Name[el]=ΓκουαÏάνι
+Name[eo]=Gvarania
+Name[es]=Guaraní
+Name[et]=Guaranii
+Name[eu]=Guaraniera
+Name[fa]=گوارانی
+Name[ga]=Guaráinis
+Name[he]=גו×רני
+Name[hi]=गौरानी
+Name[hr]=Gvaranski
+Name[ja]=グァラニ語
+Name[ka]=გვáƒáƒ áƒáƒœáƒ˜
+Name[kk]=Гуарани
+Name[km]=ហ្កួរ៉ានី
+Name[ko]=ê³¼ë¼ë‹ˆì–´
+Name[mk]=Гуарани
+Name[mn]=Гуарани
+Name[ne]=गà¥à¤µà¤¾à¤°à¤¾à¤¨à¥€
+Name[nso]=Se-Guarani
+Name[pa]=ਗà©à¨°à¨¾à¨¨à©€
+Name[ro]=Guarană
+Name[ru]=Гуарани
+Name[rw]=Ikigwarani
+Name[se]=Guaránagiella
+Name[sk]=guaraní
+Name[sl]=guarani
+Name[sq]=Guaranisht
+Name[sr]=ГваранÑки
+Name[sr@Latn]=Gvaranski
+Name[ss]=Si-Guarani
+Name[sv]=Gujarati
+Name[ta]=கà¯à®µà®°à®¾à®©à®¿
+Name[te]=à°—à±à°µà°¾à°°à°¾à°¨à°¿
+Name[tg]=Гуаранӣ
+Name[th]=ภาษาà¸à¸§à¸²à¸£à¸²à¸™à¸µ
+Name[tt]=Guarança
+Name[uk]=Гуарані
+Name[uz@cyrillic]=Гуарани
+Name[vi]=Gua-ra-ni
+Name[wa]=Gwarani
+Name[zh_CN]=瓜拉尼语
+Name[zh_HK]=瓜拉尼語
+Name[zh_TW]=瓜拉尼語
+Name[zu]=Isi-Guarani
+[gu]
+Name=Gujarati
+Name[ar]=جوجوراتي
+Name[az]=QujaraticÉ™
+Name[be]=ГуÑраці
+Name[bg]=Гуджарати
+Name[bn]=গà§à¦œà¦°à¦¾à¦¤à§€
+Name[br]=Gujaratieg
+Name[eo]= GuÄarata
+Name[et]=Gudžarati
+Name[eu]=Gujaratera
+Name[fa]=گجراتی
+Name[fi]=Gudžarati
+Name[ga]=Gúisearáitis
+Name[gl]=Guxarati
+Name[he]=גוג'רטית
+Name[hi]=गà¥à¤œà¤°à¤¾à¤¤à¥€
+Name[hr]=Gudžaratski
+Name[hu]=Gudzsarati
+Name[id]=Gujarat
+Name[ja]=グジャラート語
+Name[ka]=გუჯáƒáƒ áƒáƒ—ი
+Name[kk]=Гуджарати
+Name[km]=ហ្កុយ៉ារាទី
+Name[ko]=구ìžë¼íŠ¸ì–´
+Name[lt]=Gudžarati
+Name[mk]=Гујарати
+Name[mn]=ГуÑрати
+Name[nds]=Gudscharati
+Name[ne]=गà¥à¤œà¤°à¤¾à¤¤à¥€
+Name[nso]=Se-Gujarati
+Name[pa]=ਗà©à¨œà¨°à¨¾à¨¤à©€
+Name[ru]=Гуджарати
+Name[rw]=Ikigujarati
+Name[se]=Gujaratigiella
+Name[sk]=gudžarátÄina
+Name[sl]=gujarati
+Name[sq]=Guxharatish
+Name[sr]=ГујаратÑки
+Name[sr@Latn]=Gujaratski
+Name[ss]=Si-Gujarati
+Name[ta]=கà¯à®œà®°à®¾à®¤à¯à®¤à®¿
+Name[te]=à°—à±à°œà°°à°¾à°¤à±€
+Name[tg]=Гӯҷаратӣ
+Name[th]=ภาษาà¸à¸¹à¸ˆà¸²à¸£à¸²à¸•à¸µ
+Name[uk]=ГуÑраті
+Name[uz@cyrillic]=Гужарати
+Name[vi]=Gu-gia-ra-ti
+Name[wa]=Goudjarati
+Name[zh_CN]=å¤å‰æ‹‰ç‰¹è¯­
+Name[zh_HK]=å¤å‰æ‹‰ç‰¹èªž
+Name[zh_TW]=å¤å‰æ‹‰ç‰¹èªž
+Name[zu]=Isi-Gujarati
+[gv]
+Name=Manx
+Name[ar]=مانكس
+Name[az]=Manksca
+Name[be]=ÐœÑнкÑ
+Name[bg]=МанкÑки
+Name[bn]=মানকà§à¦¸
+Name[br]=Manav
+Name[cy]=Manneg
+Name[da]=Mansk
+Name[eo]=Manksa
+Name[et]=Mänksi
+Name[eu]=Manera
+Name[fa]=مانکسی
+Name[fr]=Mannois
+Name[ga]=Manainnis
+Name[he]=מנקס
+Name[hi]=मांकà¥à¤¸
+Name[hsb]=Manxowsce
+Name[it]=Man, lingua dell'isola di
+Name[ja]=マン島語
+Name[ka]=მáƒáƒœáƒ¥áƒ¡áƒ˜
+Name[kk]=МанкÑша
+Name[km]=ម៉ុង
+Name[ko]=ë§ìŠ¤ì–´
+Name[mk]=МанкÑ
+Name[mn]=МанкÑ
+Name[ne]=मà¥à¤¯à¤¾à¤™à¥à¤•à¥à¤¸
+Name[nso]=Se-Manx
+Name[pa]=ਮਾਲਸ
+Name[ro]=Manxă
+Name[ru]=МанкÑ
+Name[rw]=Ikimangisi
+Name[se]=Mánksagiella
+Name[sk]=manÄina
+Name[sl]=manx
+Name[sq]=Manksisht
+Name[sr]=МанкÑки
+Name[sr@Latn]=Mankski
+Name[ss]=Si-Manx
+Name[ta]=மானà¯à®•à¯à®¸à¯
+Name[te]=మేనà±à°•à±à°¸à±
+Name[tg]=МанкÑÓ£
+Name[th]=ภาษาà¹à¸¡à¸‡à¸‹à¹Œà¹€à¸à¸¥à¸´à¸„
+Name[tt]=Manksça
+Name[uk]=МанкÑ
+Name[uz]=Manks
+Name[uz@cyrillic]=МанкÑ
+Name[vi]=Man-xợ
+Name[wa]=Gayel del Iye di Man
+Name[zh_CN]=马æ©å²›è¯­
+Name[zh_HK]=曼島語
+Name[zh_TW]=曼島語
+Name[zu]=Isi-Manx
+[ha]
+Name=Hausa
+Name[ar]=الهاوسا
+Name[be]=ХаўÑа
+Name[bg]=ХауÑа
+Name[bn]=হাউসা
+Name[br]=Haousa
+Name[eo]=HaÅ­sa
+Name[fa]=هوسا
+Name[fr]=Haoussa
+Name[ga]=Hásais
+Name[he]=×”×וסה
+Name[hi]=हौसा
+Name[ja]=ãƒã‚¦ã‚µèªž
+Name[ka]=ჰáƒáƒ£áƒ¡áƒ
+Name[kk]=ХауÑа
+Name[km]=ហូសា
+Name[ko]=하우사어
+Name[lb]=Haussa-Sprooch
+Name[lv]=Hausu
+Name[mk]=ХауÑа
+Name[mn]=ХауÑа
+Name[nds]=Haussa
+Name[ne]=हउसा
+Name[nso]=Se-Hausa
+Name[pa]=ਹਾਉਸਾ
+Name[ro]=Hausă
+Name[ru]=ХауÑа
+Name[rw]=Igihawusa
+Name[se]=Hausagiella
+Name[sk]=hauština
+Name[sl]=hausa
+Name[sq]=Hausisht
+Name[sr]=ХауÑа
+Name[ss]=Si-Hausa
+Name[ta]=ஹவà¯à®šà®¾
+Name[te]=హౌసా
+Name[tg]=ХауÑагӣ
+Name[th]=ภาษาเฮาซา
+Name[tt]=Hausça
+Name[uk]=ГауÑа
+Name[uz]=Xausa
+Name[uz@cyrillic]=ХауÑа
+Name[vi]=Hau-sa
+Name[zh_CN]=豪撒语
+Name[zh_HK]=豪薩語
+Name[zh_TW]=豪薩語
+Name[zu]=Isi-Hausa
+[he]
+Name=Hebrew
+Name[af]=Hibreüs
+Name[ar]=العبرية
+Name[az]=Yəhudicə
+Name[be]=ГабрÑйÑкаÑ
+Name[bg]=Иврит
+Name[bn]=হীবà§à¦°à§
+Name[br]=Hebreeg
+Name[bs]=Hebrejski
+Name[ca]=Hebreu
+Name[cs]=Hebrejský
+Name[csb]=Hebrejsczi
+Name[cy]=Iddeweg
+Name[da]=Hebraisk
+Name[de]=Hebräisch
+Name[el]=ΕβÏαϊκά
+Name[eo]=Hebrea
+Name[es]=Hebreo
+Name[et]=Heebrea
+Name[eu]=Hebreera
+Name[fa]=عبری
+Name[fi]=Heprea
+Name[fr]=Hébreu
+Name[fy]=Hebrieuwsk
+Name[ga]=Eabhrais
+Name[gl]=Hebraico
+Name[he]=עברית
+Name[hi]=हिबà¥à¤°à¥‚
+Name[hr]=Hebrejski
+Name[hsb]=Hebrejsce
+Name[hu]=héber
+Name[id]=Israel
+Name[is]=Hebreska
+Name[it]=Ebraico
+Name[ja]=ヘブライ語
+Name[ka]=ივრითი
+Name[kk]=Ивритше
+Name[km]=áž áŸáž”្រូ
+Name[ko]=히브리어
+Name[lb]=Hebräesch
+Name[lt]=Hebrajų
+Name[lv]=Ebreju
+Name[mi]=Reo Hürai
+Name[mk]=ЕврејÑки
+Name[mn]=Хебрев
+Name[mt]=Lhudi
+Name[nb]=Hebraisk
+Name[nds]=Hebrääsch
+Name[ne]=हिबà¥à¤°à¥
+Name[nl]=Hebreeuws
+Name[nn]=Hebraisk
+Name[nso]=Se-Heberu
+Name[oc]=Hebreu
+Name[pa]=ਹੈਬਰਿਊ
+Name[pl]=Hebrajski
+Name[pt]=Hebreu
+Name[pt_BR]=Hebreu
+Name[ro]=Israeliană
+Name[ru]=Иврит
+Name[rw]=Igiheburayo
+Name[se]=Hebreagiella
+Name[sk]=hebrejÄina
+Name[sl]=hebrejsko
+Name[sq]=Hebraisht
+Name[sr]=ХебрејÑки
+Name[sr@Latn]=Hebrejski
+Name[ss]=SiHebheru
+Name[sv]=Hebreiska
+Name[ta]=எபிரேயமà¯
+Name[te]=హీబà±à°°à±‚
+Name[tg]=Яҳудӣ
+Name[th]=ภาษาฮิบรู
+Name[tr]=Ä°branice
+Name[tt]=Yähüdçä
+Name[uk]=ЄврейÑька
+Name[uz]=Yahudiycha
+Name[uz@cyrillic]=Яҳудийча
+Name[vi]=Do-thái
+Name[wa]=Ebreu
+Name[xh]=Isihebhere
+Name[zh_CN]=希伯æ¥è¯­
+Name[zh_HK]=希伯來語
+Name[zh_TW]=希伯來語
+Name[zu]=Isi-Hebheru
+[hi]
+Name=Hindi
+Name[ar]=هندي
+Name[be]=Хіндзі
+Name[bg]=Хинди
+Name[bn]=হিনà§à¦¦à§€
+Name[cs]=Hindský
+Name[cy]=Hindw^
+Name[eo]=Hinda
+Name[fa]=هندی
+Name[fy]=Hindy
+Name[ga]=Hiondúis
+Name[he]=הינדית
+Name[hi]=हिनà¥à¤¦à¥€
+Name[hr]=Hinduski
+Name[ja]=ヒンディー語
+Name[ka]=ჰინდი
+Name[kk]=Хинди
+Name[km]=ហិណ្ឌូ
+Name[ko]=힌디어
+Name[lv]=Hindu
+Name[mk]=Хинди
+Name[mn]=Хинди
+Name[ne]=हिनà¥à¤¦à¥€
+Name[nso]=Se-Hindi
+Name[pa]=ਹਿੰਦੀ
+Name[pt]=Hindu
+Name[ro]=Hindusă
+Name[ru]=Хинди
+Name[rw]=Igihindi
+Name[se]=Hindigiella
+Name[sk]=hindÄina
+Name[sl]=hindujsko
+Name[sq]=Hinduisht
+Name[sr]=Хинду
+Name[sr@Latn]=Hindu
+Name[ss]=Si-Hindi
+Name[ta]=ஹிநà¯à®¤à®¿
+Name[te]=హింది
+Name[tg]=Ҳиндӣ
+Name[th]=ภาษาฮินดี
+Name[tt]=Hindçä
+Name[uk]=Гінді
+Name[uz]=Hindcha
+Name[uz@cyrillic]=Ҳиндча
+Name[vi]=Hin-Ä‘i
+Name[zh_CN]=北å°åº¦è¯­
+Name[zh_HK]=北å°åº¦èªž
+Name[zh_TW]=北å°åº¦èªž
+Name[zu]=Isi-Hindi
+[ho]
+Name=Hiri Motu
+Name[ar]=الهيري-موتو
+Name[be]=Хірымоту
+Name[bg]=Хири Моту
+Name[bn]=হিরি মোটà§
+Name[eo]=Hiri-Motuo
+Name[fa]=هیری موتو
+Name[fi]=Hiri-motu
+Name[fr]=Hiri motu
+Name[ga]=Hírí-Mótúis
+Name[he]=הירי מוטו
+Name[hi]=हिरी मोतू
+Name[hu]=Hiri motu
+Name[it]=Hiri motu
+Name[ja]=ヒリモトゥ語
+Name[ka]=ჰირი მáƒáƒ¢áƒ£
+Name[kk]=Хири Моту
+Name[km]=ហ៊ីរី ម៉ូទូ
+Name[ko]=히리 모투어
+Name[lb]=Hiri-Motu
+Name[mk]=Хири Моту
+Name[mn]=Хири Моту
+Name[ne]=हिरी मोतà¥
+Name[nn]=Hiri motu
+Name[nso]=Se-Hiri Motu
+Name[pa]=ਹੀਰੀ ਮੋਟੂ
+Name[ru]=Хири Моту
+Name[rw]=Igihiri-motu
+Name[se]=Hiri Motu-giella
+Name[sk]=hiri motu
+Name[sl]=hiri motu
+Name[sr]=ХиримотÑки
+Name[sr@Latn]=Hirimotski
+Name[ss]=Si-Hiri Motu
+Name[sv]=Hirimotu
+Name[ta]=ஹிரி மொடà¯à®Ÿà¯
+Name[te]=హిరి మోటà±
+Name[tg]=Хири Моту
+Name[th]=ภาษาฮิริโมตู
+Name[uk]=Хірі Моту
+Name[uz]=Xiri Motu
+Name[uz@cyrillic]=Хири Моту
+Name[vi]=Hi-ri-mô-tu
+Name[zh_CN]=新里木托语
+Name[zh_HK]=Hiri Motu語
+Name[zh_TW]=Hiri Motu語
+Name[zu]=Isi-Hiri Motu
+[hr]
+Name=Croatian
+Name[af]=Kroatiese
+Name[ar]=الكرواتية
+Name[az]=Xorvatca
+Name[be]=ХарвацкаÑ
+Name[bg]=ХърватÑки
+Name[bn]=কà§à¦°à§‹à§Ÿà§‡à¦¶à§€à§Ÿ
+Name[br]=Kroateg
+Name[bs]=Hrvatski
+Name[ca]=Croat
+Name[cs]=Chorvatský
+Name[csb]=Chòrwacczi
+Name[cy]=Croatieg
+Name[da]=Kroatisk
+Name[de]=Kroatisch
+Name[el]=ΚÏοατικά
+Name[eo]=Kroata
+Name[es]=Croata
+Name[et]=Horvaadi
+Name[eu]=Kroaziera
+Name[fa]=کروواسیایی
+Name[fi]=Kroatia
+Name[fr]=Croate
+Name[fy]=Kroatysk
+Name[ga]=Cróitis
+Name[gl]=Croata
+Name[he]=קרו×טית
+Name[hi]=कà¥à¤°à¥‹à¤à¤¶à¤¿à¤¯à¤¨
+Name[hr]=Hrvatski
+Name[hsb]=Chorwatsce
+Name[hu]=Horvát
+Name[id]=Kroasia
+Name[is]=Króatíska
+Name[it]=Croato
+Name[ja]=クロアãƒã‚¢èªž
+Name[ka]=ხáƒáƒ áƒ•áƒáƒ¢áƒ£áƒšáƒ˜
+Name[kk]=Хорватша
+Name[km]=ក្រូអាស៊ី
+Name[ko]=í¬ë¡œì•„í‹°ì•„ì–´
+Name[lb]=Kroatesch
+Name[lt]=Kroatų
+Name[lv]=HorvÄtu
+Name[mi]=Reo Koroätia
+Name[mk]=ХрватÑки
+Name[mn]=Хорват
+Name[ms]=Croatia
+Name[mt]=Kroat
+Name[nb]=Kroatisk
+Name[nds]=Kroaatsch
+Name[ne]=कà¥à¤°à¥‹à¤¯à¤¸à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Kroatisch
+Name[nn]=Kroatisk
+Name[nso]=Se-Croatian
+Name[oc]=Cròatian
+Name[pa]=ਕਰੋਟੀਅਨ
+Name[pl]=Chorwacki
+Name[pt]=Croata
+Name[pt_BR]=Croata
+Name[ro]=Croată
+Name[ru]=ХорватÑкий
+Name[rw]=Ikinyakorowasi
+Name[se]=Kroatiagiella
+Name[sk]=chorvátÄina
+Name[sl]=hrvaško
+Name[sq]=Kroatisht
+Name[sr]=ХрватÑки
+Name[sr@Latn]=Hrvatski
+Name[ss]=Si-Croatian
+Name[sv]=Kroatiska
+Name[ta]=கà¯à®°à¯Šà®µà¯‡à®šà®¿à®¯à®©à¯
+Name[te]=à°•à±à°°à±Šà°¯à±†à°·à°¿à°¯à°¨à±
+Name[tg]=Хорватӣ
+Name[th]=ภาษาโครเอเชียน
+Name[tr]=Hırvatça
+Name[tt]=Kroatça
+Name[uk]=ХорватÑька
+Name[uz]=Xorvatcha
+Name[uz@cyrillic]=Хорватча
+Name[vi]=Cợ-rô-a-ti-a
+Name[wa]=Crowåte
+Name[zh_CN]=克罗地亚语
+Name[zh_HK]=克羅地亞語
+Name[zh_TW]=克羅埃西亞語
+Name[zu]=Isi-Croatian
+[hsb]
+Name=Upper Sorbian
+Name[af]=Hoog Serbiese
+Name[be]=ВерхнÑлужыцкаÑ
+Name[bg]=ГорноÑорбийÑки
+Name[bn]=উচà§à¦š সারà§à¦¬à§€à§Ÿ
+Name[br]=Sorab uhel
+Name[bs]=Gornji lužiÄkosrpski
+Name[ca]=Alt sòrab
+Name[cs]=Hornolužicko srbský
+Name[csb]=Górnosorbsczi
+Name[cy]=Sorbieg Uchaf
+Name[da]=Øvre Sorbisk
+Name[de]=Obersorbisch
+Name[eo]=Supra Soraba
+Name[es]=Serbio superior
+Name[et]=Ãœlemsorbi
+Name[eu]=Goi Serbiera
+Name[fa]=صربستان شمالی
+Name[fi]=Yläsorbi
+Name[fr]=Haut Sorabe
+Name[fy]=Heech Sorbysk
+Name[ga]=Sorbais Uachtarach
+Name[gl]=Alto Sórabo
+Name[he]=סרבית עליונה
+Name[hi]=अपर सरà¥à¤¬à¤¿à¤¯à¤¨
+Name[hr]=Gornjosrpski
+Name[hsb]=Hornjoserbsce
+Name[hu]=Felső szorb
+Name[it]=Alto sorabo
+Name[ja]=上ソルブ語
+Name[ka]=ზედáƒáƒ¡áƒáƒ áƒ‘ული
+Name[kk]=Жоғары Ñорбше
+Name[km]=សូបៀន លើ
+Name[lb]=Uewersorbesch
+Name[mk]=Јужно лужички
+Name[nb]=Øvresorbisk
+Name[nds]=Böversorbsch
+Name[ne]=माथिलà¥à¤²à¥‹ सोरà¥à¤¬à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Opper Sorbian
+Name[nn]=Øvresorbisk
+Name[pa]=ਉੱਪਰੀ ਸਰਬੀਅਨ
+Name[pl]=Górnołużycki
+Name[pt]=Sérvio de Cima
+Name[pt_BR]=Sérvio
+Name[ro]=Sîrbă de Sus
+Name[ru]=Верхнелужицкий
+Name[rw]=Ikinyasorubiya cyo hejuru
+Name[se]=Bajil Sorbiagiella
+Name[sk]=dolnolužická srbÄina
+Name[sl]=zgornjesorbijsko
+Name[sr]=Горње лужичко ÑрпÑки
+Name[sr@Latn]=Gornje lužiÄko srpski
+Name[sv]=Högsorbiska
+Name[ta]=அபà¯à®ªà®°à¯ செரà¯à®ªà®¿à®¯à®©à¯
+Name[te]=à°…à°ªà±à°ªà°°à± సొరà±à°¬à°¿à°¯à°¨à±
+Name[tg]=ЛужаÑагии болоӣ
+Name[th]=ภาษาซอร์เบียนตอนบน
+Name[tr]=Yukarı Sırpça
+Name[tt]=Sorbça, Öske
+Name[uk]=Верхньолужицька
+Name[uz]=Yuqori Sorbcha
+Name[uz@cyrillic]=Юқори Сорбча
+Name[vi]=Xoa-bi muá»™n
+Name[wa]=Hôt sorbyin
+Name[zh_CN]=索布语
+Name[zh_TW]=塞爾維亞語
+[hu]
+Name=Hungarian
+Name[af]=Hongaars
+Name[ar]=الهنغارية (المجرية)
+Name[az]=Macarca
+Name[be]=ВенгерÑкаÑ
+Name[bg]=УнгарÑки
+Name[bn]=হাঙà§à¦—ারীয়
+Name[br]=Hungareg
+Name[bs]=Mađarski
+Name[ca]=Hongarès
+Name[cs]=MaÄarský
+Name[csb]=Madżarsczi
+Name[cy]=Hwngareg
+Name[da]=Ungarsk
+Name[de]=Ungarisch
+Name[el]=ΟυγγÏικά
+Name[eo]=Hungara
+Name[es]=Húngaro
+Name[et]=Ungari
+Name[eu]=Hungariera
+Name[fa]=مجارستانی
+Name[fi]=Unkari
+Name[fr]=Hongrois
+Name[fy]=Hongaarsk
+Name[ga]=Ungáiris
+Name[gl]=Húngaro
+Name[he]=הונגרית
+Name[hi]=हंगेरियन
+Name[hr]=Mađarski
+Name[hsb]=Madźarsce
+Name[hu]=Magyar
+Name[id]=Hungaria
+Name[is]=Ungverska
+Name[it]=Ungherese
+Name[ja]=ãƒãƒ³ã‚¬ãƒªãƒ¼èªž
+Name[ka]=უნგრული
+Name[kk]=Мажарша
+Name[km]=ហុងគ្រី
+Name[ko]=í—가리어
+Name[lb]=Ungaresch
+Name[lt]=Vengrų
+Name[lv]=UngÄru
+Name[mi]=Reo Hanekari
+Name[mk]=УнгарÑки
+Name[mn]=Унгар
+Name[ms]=Hungaria
+Name[mt]=Ungeriż
+Name[nb]=Ungarsk
+Name[nds]=Ungaarsch
+Name[ne]=हङà¥à¤—ेरेली
+Name[nl]=Hongaars
+Name[nn]=Ungarsk
+Name[nso]=Se-Hungarian
+Name[oc]=Hongarian
+Name[pa]=ਹੰਗਰੀਅਨ
+Name[pl]=Węgierski
+Name[pt]=Húngaro
+Name[pt_BR]=Húngaro
+Name[ro]=Maghiară
+Name[ru]=ВенгерÑкий
+Name[rw]=Ikinyahangariya
+Name[se]=Ungárgiella
+Name[sk]=maÄarÄina
+Name[sl]=madžarsko
+Name[sq]=Hungarisht
+Name[sr]=МађарÑки
+Name[sr@Latn]=Mađarski
+Name[ss]=Si-Hungarian
+Name[sv]=Ungerska
+Name[ta]=ஹஙà¯à®•à¯‡à®°à®¿à®¯à®©à¯
+Name[te]=హంగెరియనà±
+Name[tg]=Венгерӣ
+Name[th]=ภาษาฮังà¸à¸²à¹€à¸£à¸µà¸¢à¸™
+Name[tr]=Macarca
+Name[tt]=Macarça
+Name[uk]=УгорÑька
+Name[uz]=Vengrcha
+Name[uz@cyrillic]=Венгрча
+Name[vi]=Hung-gia-lợi
+Name[wa]=Hongrwès
+Name[zh_CN]=匈牙利语
+Name[zh_HK]=匈牙利語
+Name[zh_TW]=匈牙利語
+Name[zu]=Isi-Hangariyani
+[hy]
+Name=Armenian
+Name[af]=Armeens
+Name[ar]=أرمني
+Name[az]=Ermənicə
+Name[be]=ÐрмÑнÑкаÑ
+Name[bg]=ÐрменÑки
+Name[bn]=আরà§à¦®à§‡à¦¨à§€à§Ÿ
+Name[br]=Armenieg
+Name[bs]=Armenski
+Name[ca]=Armeni
+Name[cs]=Arménský
+Name[csb]=Armeńsczi
+Name[cy]=Armeineg
+Name[da]=Armensk
+Name[de]=Armenisch
+Name[el]=ΑÏμενικά
+Name[eo]=Armena
+Name[es]=Armenio
+Name[et]=Armeenia
+Name[eu]=Armeniera
+Name[fa]=ارمنی
+Name[fi]=Armenia
+Name[fr]=Arménien
+Name[fy]=Armeensk
+Name[ga]=Airméinis
+Name[gl]=Arménio
+Name[he]=×רמנית
+Name[hi]=आरमेनियन
+Name[hr]=Armenski
+Name[hsb]=Armensce
+Name[hu]=Örmény
+Name[id]=Armenia
+Name[is]=Armeskt
+Name[it]=Armeno
+Name[ja]=アルメニア語
+Name[ka]=სáƒáƒ›áƒ®áƒ£áƒ áƒ˜
+Name[kk]=Ðрменше
+Name[km]=អារមáŸáž“ី
+Name[ko]=아르메니아어
+Name[lb]=Armenesch
+Name[lt]=Armėnų
+Name[lv]=Armēņu
+Name[mk]=ЕрменÑки
+Name[mn]=Ðрмен
+Name[ms]=Armenia
+Name[nb]=Armensk
+Name[nds]=Armeensch
+Name[ne]=आरà¥à¤®à¥‡à¤¨à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Armeens
+Name[nn]=Armensk
+Name[nso]=Se-Armenian
+Name[pa]=ਅਰਮੀਅਨ
+Name[pl]=Ormiański
+Name[pt]=Arménio
+Name[pt_BR]=Armênio
+Name[ro]=Armenă
+Name[ru]=ÐрмÑнÑкий
+Name[rw]=Icyarumeniya
+Name[se]=Armeniagiella
+Name[sk]=arménÄina
+Name[sl]=armensko
+Name[sq]=Armenisht
+Name[sr]=ЈерменÑки
+Name[sr@Latn]=Jermenski
+Name[ss]=Si-Armenian
+Name[sv]=Armenska
+Name[ta]=ஆரà¯à®®à¯€à®©à®¿à®¯à®©à¯
+Name[te]=à°…à°°à±à°®à±†à°¨à°¿à°¯à°¨à±
+Name[tg]=Ðрманӣ
+Name[th]=ภาษาอาร์เมเนีย
+Name[tr]=Ermenice
+Name[tt]=Ärmänçä
+Name[uk]=ВірменÑька
+Name[uz]=Armancha
+Name[uz@cyrillic]=Ðрманча
+Name[vi]=Ãc-mê-ni
+Name[wa]=Ã…rmenyin
+Name[zh_CN]=亚美尼亚语
+Name[zh_HK]=亞美尼亞語
+Name[zh_TW]=亞美尼亞語
+Name[zu]=Isi-Armenian
+[hz]
+Name=Herero
+Name[ar]=الهيريرو
+Name[be]=Ð¥ÑÑ€Ñра
+Name[bg]=Хереро
+Name[bn]=হেরেরো
+Name[cy]=Hausa
+Name[eo]=Herera
+Name[fa]=هررو
+Name[ga]=Heiréiróis
+Name[he]=הררו
+Name[hi]=हेरेरो
+Name[hu]=Hereró
+Name[ja]=ヘレロ語
+Name[ka]=ჰერერáƒ
+Name[kk]=Хереро
+Name[km]=áž áŸážšáŸáž¢áž¼
+Name[ko]=헤레로어
+Name[mk]=Хереро
+Name[mn]=Хереро
+Name[ne]=हेरेरो
+Name[nso]=Se-Herero
+Name[pa]=ਹੀਰੀਰੋ
+Name[ro]=Hereră
+Name[ru]=Эреро
+Name[rw]=Igiherero
+Name[se]=Hererogiella
+Name[sk]=hererÄina
+Name[sl]=herero
+Name[sq]=Herisht
+Name[sr]=ХерерÑки
+Name[sr@Latn]=Hererski
+Name[ss]=Si-Herero
+Name[ta]=ஹெரà¯à®°à¯‹
+Name[te]=హెరెరో
+Name[tg]=ХерÑро
+Name[th]=ภาษาเฮอเรโร
+Name[tt]=Hereroça
+Name[uk]=Гереро
+Name[uz]=Xerero
+Name[uz@cyrillic]=Хереро
+Name[vi]=He-re-rô
+Name[zh_CN]=赫雷罗语
+Name[zh_HK]=Herero語
+Name[zh_TW]=Herero語
+Name[zu]=Isi-Herero
+[ia]
+Name=Interlingua
+Name[ar]=الإنترلينغوا
+Name[az]=Ä°nterlinqua
+Name[be]=ІнтÑрлінгуа
+Name[bg]=Интерлингва
+Name[bn]=ইনà§à¦Ÿà¦¾à¦°à¦²à¦¿à¦™à§à¦—à§à§Ÿà¦¾
+Name[eo]=Interlingvao
+Name[fa]=میان زبانی
+Name[ga]=Idirtheanga
+Name[he]=×ינטרלינגו××”
+Name[hi]=इंटरलिंगà¥à¤†
+Name[ja]=インターリンガ
+Name[ka]=ინტერლინგვáƒ
+Name[kk]=Интерлингва
+Name[km]=អ៊ីងážážºáž›áž¸áž„áž‚áŸážš
+Name[ko]=국제어 (Interlingua)
+Name[lv]=Interlingva
+Name[mk]=Интерлингва
+Name[mn]=Интерлингуа
+Name[ne]=इनà¥à¤Ÿà¤°à¤²à¤¿à¤™à¥à¤—à¥à¤µà¤¾
+Name[nso]=Se-Interlingua
+Name[pa]=ਇੰਟਰਲੀਗੂਆ
+Name[pt_BR]=Interlíngua
+Name[ru]=Интерлингва
+Name[rw]=Ikinyenterilinga
+Name[sk]=interlingua
+Name[sl]=interlingua
+Name[sr]=ИнтерлингванÑки
+Name[sr@Latn]=Interlingvanski
+Name[ss]=Si-Interlingua
+Name[ta]=இனà¯à®Ÿà¯†à®°à¯à®²à®¿à®™à¯à®•à¯à®µà®¾
+Name[te]=ఇంటరౠలింగà±à°µà°¾
+Name[tg]=Забони миёнрав
+Name[th]=ภาษานานาชาติ
+Name[tt]=Ä°nterlingua
+Name[uk]=Інтерлінгва
+Name[uz@cyrillic]=Интерлингуа
+Name[ven]=Luambo lwa hothe
+Name[vi]=In-tợ-lin-gua
+Name[wa]=Interlingua (noû latén)
+Name[zh_CN]=拉ä¸å›½é™…语(国际辅助语)
+Name[zh_HK]=科技共通語
+Name[zh_TW]=科技共通語
+Name[zu]=Ulimi olufanayo
+[id]
+Name=Indonesian
+Name[af]=Indonesië
+Name[ar]=الإندونيسية
+Name[az]=Ä°ndoneziyaca
+Name[be]=ІнданÑзійÑкаÑ
+Name[bg]=ИндонезийÑки
+Name[bn]=ইনà§à¦¦à§‹à¦¨à§‡à¦¶à§€à§Ÿ
+Name[br]=Indoneseg
+Name[bs]=Indonezijski
+Name[ca]=Indonesi
+Name[cs]=Indonéský
+Name[csb]=Indonezëjsczi
+Name[cy]=Indonesieg
+Name[da]=Indonesisk
+Name[de]=Indonesisch
+Name[el]=Ινδονησιακά
+Name[eo]=Indonezia
+Name[es]=Indonesio
+Name[et]=Indoneesia
+Name[eu]=Indonesiera
+Name[fa]=اندونزیایی
+Name[fi]=Indonesia
+Name[fr]=Indonésien
+Name[fy]=Yndonesysk
+Name[ga]=Indinéisis
+Name[gl]=Bahasa Indonésia
+Name[he]=×ינדונזית
+Name[hi]=इंडोनेशियन
+Name[hr]=Indonezijski
+Name[hsb]=Indonezisce
+Name[hu]=Indonéz
+Name[id]=Indonesia
+Name[is]=Indónesíska
+Name[it]=Indonesiano
+Name[ja]=インドãƒã‚·ã‚¢èªž
+Name[ka]=ინდáƒáƒœáƒ”ზიური
+Name[kk]=ИндонезиÑша
+Name[km]=ឥណ្ឌូនáŸážŸáŸŠáž¸
+Name[ko]=ì¸ë„네시아어
+Name[lb]=Indonesesch
+Name[lt]=IndonezieÄių
+Name[lv]=Indonēziešu
+Name[mk]=ИндонезиÑки
+Name[mn]=Индонези
+Name[ms]=Indonesia
+Name[mt]=Indoneżjan
+Name[nb]=Indonesisk
+Name[nds]=Indoneesch
+Name[ne]=इनà¥à¤¡à¥‹à¤¨à¥‡à¤¸à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Indonesisch
+Name[nn]=Indonesisk
+Name[nso]=Se-Indonesian
+Name[pa]=ਇੰਡੋਨੇਸ਼ੀਆ
+Name[pl]=Indonezyjski
+Name[pt]=Indonésio
+Name[pt_BR]=Indonésio
+Name[ro]=Indoneziană
+Name[ru]=ИндонезийÑкий
+Name[rw]=Ikinyendonisiya
+Name[se]=Indonesiagiella
+Name[sk]=indonézština
+Name[sl]=indonezijsko
+Name[sq]=Indonezisht
+Name[sr]=ИндонезијÑки
+Name[sr@Latn]=Indonezijski
+Name[ss]=Si-Indonesian
+Name[sv]=Indonesiska
+Name[ta]=இநà¯à®¤à¯‹à®©à¯€à®šà®¿à®¯à®©à¯
+Name[te]=ఇనà±à°¡à±Šà°¨à±†à°·à°¿à°¯à°¨à±
+Name[tg]=Индонезӣ
+Name[th]=ภาษาอินโดนีเซีย
+Name[tr]=Ä°ndonezya dili
+Name[tt]=İndonesçä
+Name[uk]=ІндонезійÑька
+Name[uz]=Indonezcha
+Name[uz@cyrillic]=Индонезча
+Name[vi]=Nam-dÆ°Æ¡ng
+Name[wa]=Indonezyin
+Name[zh_CN]=å°åº¦å°¼è¥¿äºšè¯­
+Name[zh_HK]=å°å°¼èªž
+Name[zh_TW]=å°å°¼èªž
+Name[zu]=Indoneshiya
+[ie]
+Name=Interlingue
+Name[ar]=الإنترلينغوي
+Name[be]=ІнтÑрлінг
+Name[bg]=ОкÑидентал
+Name[bn]=ইনà§à¦Ÿà¦¾à¦°à¦²à¦¿à¦‚
+Name[br]=Interlingeg
+Name[eo]=Interlingveo
+Name[es]=Interlinga
+Name[fa]=میان زبانی
+Name[fy]=Interlingua
+Name[ga]=Idirtheanga iartharach
+Name[gl]=Interlingua
+Name[he]=×ינטרלינגווה
+Name[hi]=इंटरलिंग
+Name[ja]=インターリング
+Name[ka]=ინტერლინგვე
+Name[kk]=Интерлигве
+Name[km]=អ៊ីងážážºáž›áž¸áž„áž‚áž¹
+Name[ko]=국제어 (Interlingue)
+Name[lb]=Interlingua
+Name[lv]=Interlingva
+Name[mk]=Интерлингва
+Name[mn]=Интерлингуе
+Name[ne]=इनà¥à¤Ÿà¤°à¤²à¤¿à¤™à¥à¤—à¥à¤µà¤¾
+Name[nso]=Se-Interlingue
+Name[pa]=ਇੰਟਰਈਨੂਗੂਈ
+Name[rw]=Ikinyenterilinge
+Name[sk]=interlingue
+Name[sl]=interlingue
+Name[sr]=ИнтерлингвијÑки
+Name[sr@Latn]=Interlingvijski
+Name[ss]=Si-Interlingue
+Name[sv]=Interlingua
+Name[ta]=இனà¯à®Ÿà¯†à®°à¯à®²à®¿à®™à¯à®•à¯
+Name[te]=ఇంటరౠలింగె
+Name[tg]=Забони миёнрав
+Name[th]=ภาษาอินเทอร์ลิงà¸à¹Œ
+Name[tt]=Ä°nterlingue
+Name[uk]=Інтерлінгва
+Name[uz@cyrillic]=Интерлингуе
+Name[ven]=Luambo lwa hothe
+Name[vi]=In-tợ-lin-guợ
+Name[zh_CN]=语际语
+Name[zh_HK]=Interlingue語
+Name[zh_TW]=Interlingue語
+Name[zu]=Izilimi ezifanayo
+[ik]
+Name=Inupiaq
+Name[ar]=الإنوبياك
+Name[az]=Ä°nupiaqca
+Name[be]=ІнупіцкаÑ
+Name[bg]=Инупиак
+Name[bn]=ইনà§à¦ªà¦¿à§Ÿà¦¾à¦•
+Name[br]=Inupiak
+Name[bs]=Inupiak
+Name[eo]=Inuita
+Name[fa]=اینوپیاک
+Name[fi]=Inupiatun
+Name[he]=×ינופי×ק
+Name[hi]=इनà¥à¤ªà¤¿à¤†à¤•
+Name[hsb]=Inupiak
+Name[hu]=Inupiak
+Name[it]=Inupiak
+Name[ja]=イヌピアック語
+Name[ka]=ინუპიáƒáƒ™áƒ˜
+Name[kk]=Инупиакша
+Name[km]=អ៊ីនូភាគ
+Name[mk]=Инупиак
+Name[mn]=Инупиак
+Name[nds]=Inupiak
+Name[ne]=इनà¥à¤ªà¤¿à¤•
+Name[nn]=Inupiak
+Name[nso]=Se-Inupiaq
+Name[pa]=ਇਨਪੀਕਾਉ
+Name[ro]=Inupiacă
+Name[ru]=Инупиак
+Name[rw]=Ikinupiyake
+Name[se]=Inupiaqgiella
+Name[sk]=inupiaq
+Name[sl]=inupiaq
+Name[sq]=Inupikisht
+Name[sr]=ИнупиакÑки
+Name[sr@Latn]=Inupiakski
+Name[ss]=Si-Inupiaq
+Name[ta]=இனà¯à®ªà®¿à®¯à®¾à®•à¯
+Name[te]=ఇనà±à°ªà°¿à°¯à°¾à°•à±
+Name[tg]=Инупиакӣ
+Name[th]=ภาษาอินุพิอัค
+Name[tt]=İnupiaqça
+Name[uk]=Інупіак
+Name[uz]=Inupiak
+Name[uz@cyrillic]=Инупиак
+Name[vi]=I-nu-piac
+Name[wa]=Inyupiak
+Name[zh_CN]=因纽佩特语
+Name[zh_HK]=Inupiaq語
+Name[zh_TW]=Inupiaq語
+Name[zu]=Isi-Inupiaq
+[io]
+Name=Ido
+Name[ar]=الإيدو
+Name[be]=Ідо
+Name[bg]=Идо
+Name[bn]=ইডো
+Name[fa]=ایدو
+Name[he]=×דו
+Name[hi]=इडो
+Name[ja]=イド語
+Name[ka]=იდáƒ
+Name[kk]=Идо
+Name[km]=អ៊ីឌូ
+Name[ko]=ì´ë„ì–´
+Name[mk]=Идо
+Name[mn]=Идо
+Name[ne]=इडो
+Name[nso]=Se-Ido
+Name[pa]=ਆਈਡੋ
+Name[ru]=Идо
+Name[rw]=Ikido
+Name[se]=Idogiella
+Name[sk]=ido
+Name[sl]=ido
+Name[sq]=Idoisht
+Name[sr]=ИдоÑки
+Name[sr@Latn]=Idoski
+Name[ss]=Si-Ido
+Name[ta]=ஈடோ
+Name[te]=ఇడొ
+Name[tg]=Идо
+Name[th]=ภาษาอิดอ
+Name[tt]=İdoça
+Name[uk]=Ідо
+Name[uz@cyrillic]=Идо
+Name[vi]=I-đô
+Name[zh_CN]=伊多语
+Name[zh_HK]=伊多語
+Name[zh_TW]=伊多語
+Name[zu]=Isi-Ido
+[is]
+Name=Icelandic
+Name[af]=Yslandies
+Name[ar]=الآيسلندية
+Name[az]=Ä°slandiyaca
+Name[be]=ІÑландÑкаÑ
+Name[bg]=ИÑландÑки
+Name[bn]=আইসলà§à¦¯à¦¾à¦¨à§à¦¡à¦¿à¦•
+Name[br]=Islandeg
+Name[bs]=Islandski
+Name[ca]=Islandès
+Name[cs]=Islandský
+Name[csb]=Islandzczi
+Name[cy]=Islandeg
+Name[da]=Islandsk
+Name[de]=Isländisch
+Name[el]=Ισλανδικά
+Name[eo]=Islanda
+Name[es]=Islandés
+Name[et]=Islandi
+Name[eu]=Islandiera
+Name[fa]=ایسلندی
+Name[fi]=Islanti
+Name[fr]=Islandais
+Name[fy]=Iislânsk
+Name[ga]=Ãoslainnis
+Name[gl]=Islandés
+Name[he]=×יסלנדית
+Name[hi]=आइसलैंडिक
+Name[hr]=Islandski
+Name[hsb]=Islandsce
+Name[hu]=Izlandi
+Name[id]=Islandia
+Name[is]=Ãslenska
+Name[it]=Islandese
+Name[ja]=アイスランド語
+Name[ka]=ისლáƒáƒœáƒ“იური
+Name[kk]=ИÑландша
+Name[km]=អ៊ីស្លង់
+Name[ko]=ì•„ì´ìŠ¬ëž€ë“œì–´
+Name[lb]=Islännesch
+Name[lt]=Islandų
+Name[lv]=Islandiešu
+Name[mi]=Reo Tiorangi
+Name[mk]=ИÑландÑки
+Name[mn]=ИÑланд
+Name[mt]=Islandiż
+Name[nb]=Islandsk
+Name[nds]=Islannsch
+Name[ne]=आइसलà¥à¤¯à¤¾à¤¨à¥à¤¡à¤¿à¤•
+Name[nl]=IJslands
+Name[nn]=Islandsk
+Name[nso]=Se-Icelandic
+Name[oc]=Islandès
+Name[pa]=ਆਇਸਲੈਂਡ
+Name[pl]=Islandzki
+Name[pt]=Islandês
+Name[pt_BR]=Islândico
+Name[ro]=Islandeză
+Name[ru]=ИÑландÑкий
+Name[rw]=Ikinyisilande
+Name[se]=Islánddagiella
+Name[sk]=islandÄina
+Name[sl]=islandsko
+Name[sq]=Islandisht
+Name[sr]=ИÑландÑки
+Name[sr@Latn]=Islandski
+Name[ss]=Si-Icelandic
+Name[sv]=Isländska
+Name[ta]=à®à®¸à¯à®²à®¾à®¨à¯à®¤à®¿à®•à¯
+Name[te]=à°à°¸à± లేండికà±
+Name[tg]=ИÑландӣ
+Name[th]=ภาษาไอซ์à¹à¸¥à¸™à¸”์
+Name[tr]=Ä°zlanda Dili
+Name[tt]=İslandça
+Name[uk]=ІÑландÑька
+Name[uz]=Islandcha
+Name[uz@cyrillic]=ИÑландча
+Name[vi]=Băng-đảo
+Name[wa]=Izlandès
+Name[zh_CN]=冰岛语
+Name[zh_HK]=冰島語
+Name[zh_TW]=冰島語
+Name[zu]=isi-Icelandic
+[it]
+Name=Italian
+Name[af]=Italiaans
+Name[ar]=الإيطالية
+Name[az]=Ä°talyanca
+Name[be]=ІтальÑнÑкаÑ
+Name[bg]=ИталианÑки
+Name[bn]=ইতালীয়
+Name[br]=Italianeg
+Name[bs]=Talijanski
+Name[ca]=Italià
+Name[cs]=Italský
+Name[csb]=Italsczi
+Name[cy]=Eidaleg
+Name[da]=Italiensk
+Name[de]=Italienisch
+Name[el]=Ιταλικά
+Name[eo]=Itala
+Name[es]=Italiano
+Name[et]=Itaalia
+Name[eu]=Italiera
+Name[fa]=ایتالیایی
+Name[fi]=Italia
+Name[fr]=Italien
+Name[fy]=Italiaansk
+Name[ga]=Iodáilis
+Name[gl]=Italiano
+Name[he]=×יטלקית
+Name[hi]=इतालवी
+Name[hr]=Talijanski
+Name[hsb]=Italsce
+Name[hu]=Olasz
+Name[id]=Italia
+Name[is]=Ãtalska
+Name[it]=Italiano
+Name[ja]=イタリア語
+Name[ka]=იტáƒáƒšáƒ˜áƒ£áƒ áƒ˜
+Name[kk]=ИтальÑнша
+Name[km]=អ៊ីážáž¶áž›áž¸
+Name[ko]=ì´íƒˆë¦¬ì•„ì–´
+Name[lb]=Italienesch
+Name[lt]=Italų
+Name[lv]=ItÄļu
+Name[mi]=Reo Itari
+Name[mk]=ИталијанÑки
+Name[mn]=Итали
+Name[ms]=Italia
+Name[mt]=Taljan
+Name[nb]=Italiensk
+Name[nds]=Italieensch
+Name[ne]=इटालियन
+Name[nl]=Italiaans
+Name[nn]=Italiensk
+Name[nso]=Se-Italian
+Name[pa]=ਇਤਾਲਵੀ
+Name[pl]=WÅ‚oski
+Name[pt]=Italiano
+Name[pt_BR]=Italiano
+Name[ro]=Italiană
+Name[ru]=ИтальÑнÑкий
+Name[rw]=Igitaliyani
+Name[se]=Itáliagiella
+Name[sk]=talianÄina
+Name[sl]=italijansko
+Name[sq]=Italisht
+Name[sr]=ИталијанÑки
+Name[sr@Latn]=Italijanski
+Name[ss]=Sitaliyani
+Name[sv]=Italienska
+Name[ta]=இதà¯à®¤à®¾à®²à®¿à®¯à®©à¯
+Name[te]=ఇటాలియనà±
+Name[tg]=Итолиёӣ
+Name[th]=ภาษาอิตาเลียน
+Name[tr]=Ä°talyanca
+Name[tt]=İtalça
+Name[uk]=ІталійÑька
+Name[uz]=Italyancha
+Name[uz@cyrillic]=ИталÑнча
+Name[vi]=Ã
+Name[wa]=Itålyin
+Name[xh]=isitaliyane
+Name[zh_CN]=æ„大利语
+Name[zh_HK]=æ„大利語
+Name[zh_TW]=義大利語
+Name[zu]=Isi-Ntaliyane
+[iu]
+Name=Inuktitut
+Name[ar]=الإنكتيتوت
+Name[be]=Інуктытут
+Name[bg]=Инуктитут
+Name[bn]=ইনাকà§à¦Ÿà¦¿à¦Ÿà§à¦Ÿ
+Name[fa]=اینوکتیتوت
+Name[ga]=Ionúitis
+Name[he]=×ינוקטיטוט
+Name[hi]=इनà¥à¤•à¥à¤¤à¤¿à¤¤à¥
+Name[ja]=イヌイット語
+Name[ka]=ინუქტიუტუტი
+Name[kk]=Инуктиут
+Name[km]=អ៊ីនូកទីទូáž
+Name[mk]=Инуктитут
+Name[mn]=Инуктитут
+Name[ne]=इनकà¥à¤Ÿà¤¿à¤Ÿà¥à¤Ÿ
+Name[nn]=Inuittisk
+Name[nso]=Se-Inuktitut
+Name[pa]=ਇਨੂਕਟੀਟੂਟ
+Name[ru]=Инуктитут
+Name[rw]=Ikinukititutu
+Name[se]=Inuhkagiella
+Name[sk]=inuktitut
+Name[sl]=inuktitut
+Name[sq]=Inukituisht
+Name[sr]=ИнуктитутÑки
+Name[sr@Latn]=Inuktitutski
+Name[ss]=Si-Inuktitut
+Name[ta]=இனà¯à®•à¯à®Ÿà®¿à®Ÿà¯à®Ÿà¯
+Name[te]=ఇనà±à°•à±à°¤à°¿à°Ÿà±à°Ÿà±
+Name[tg]=Инуктитут
+Name[th]=ภาษาอินุคทิทุท
+Name[tt]=İnuktitutça
+Name[uk]=Інуктитут
+Name[uz@cyrillic]=Инуктитут
+Name[vi]=I-nuc-ti-túc
+Name[zh_CN]=因纽特语
+Name[zh_HK]=Inuktitut語
+Name[zh_TW]=Inuktitut語
+Name[zu]=Isi-Inuktitut
+[ja]
+Name=Japanese
+Name[af]=Japanees
+Name[ar]=اليابانية
+Name[az]=Yaponca
+Name[be]=ЯпонÑкаÑ
+Name[bg]=ЯпонÑки
+Name[bn]=জাপানী
+Name[br]=Japaneg
+Name[bs]=Japanski
+Name[ca]=Japonès
+Name[cs]=Japonský
+Name[csb]=Japòńsczi
+Name[cy]=Japaneg
+Name[da]=Japansk
+Name[de]=Japanisch
+Name[el]=Ιαπωνικά
+Name[eo]=Japana
+Name[es]=Japonés
+Name[et]=Jaapani
+Name[eu]=Japoniera
+Name[fa]=ژاپنی
+Name[fi]=Japani
+Name[fr]=Japonais
+Name[fy]=Japansk
+Name[ga]=Seapáinis
+Name[gl]=Xaponés
+Name[he]=יפנית
+Name[hi]=जापानी
+Name[hr]=Japanski
+Name[hsb]=Japansce
+Name[hu]=Japán
+Name[id]=Jepang
+Name[is]=Japanska
+Name[it]=Giapponese
+Name[ja]=日本語
+Name[ka]=იáƒáƒžáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=Жапонша
+Name[km]=ជប៉ុន
+Name[ko]=ì¼ë³¸ì–´
+Name[lb]=Japanesch
+Name[lt]=Japonų
+Name[lv]=JapÄņu
+Name[mi]=Reo Hapana
+Name[mk]=ЈапонÑки
+Name[mn]=Япон
+Name[ms]=Jepun
+Name[mt]=Ġappuniż
+Name[nb]=Japansk
+Name[nds]=Japaansch
+Name[ne]=जापानी
+Name[nl]=Japans
+Name[nn]=Japansk
+Name[nso]=Se-Japanese
+Name[oc]=Japònès
+Name[pa]=ਜਾਪਾਨੀ
+Name[pl]=Japoński
+Name[pt]=Japonês
+Name[pt_BR]=Japonês
+Name[ro]=Japoneză
+Name[ru]=ЯпонÑкий
+Name[rw]=Ikiyapani
+Name[se]=Jáhpangiella
+Name[sk]=japonÄina
+Name[sl]=japonsko
+Name[sq]=Japonisht
+Name[sr]=ЈапанÑки
+Name[sr@Latn]=Japanski
+Name[ss]=Si-Japanese
+Name[sv]=Japanska
+Name[ta]=ஜபà¯à®ªà®¾à®©à®¿à®¯à®®à¯
+Name[te]=జపనీసà±
+Name[tg]=Японӣ
+Name[th]=ภาษาà¸à¸µà¹ˆà¸›à¸¸à¹ˆà¸™
+Name[tr]=Japonca
+Name[tt]=Japança
+Name[uk]=ЯпонÑька
+Name[uz]=Yaponcha
+Name[uz@cyrillic]=Японча
+Name[ven]=Mudzhapani
+Name[vi]=Nhật
+Name[wa]=Djaponès
+Name[xh]=Isijapani
+Name[zh_CN]=日语
+Name[zh_HK]=日語
+Name[zh_TW]=日語
+Name[zu]=Isi-Jaliphani
+[jv]
+Name=Javanese
+Name[af]=Javanees
+Name[ar]=جاويه
+Name[az]=Yavonca
+Name[be]=ЯванÑкаÑ
+Name[bg]=ЯвайÑки
+Name[bn]=জাভানিস
+Name[br]=Javaneg
+Name[bs]=Javanski
+Name[ca]=Javanès
+Name[cs]=Jávský
+Name[csb]=Jawańsczi
+Name[cy]=Javaneg
+Name[da]=Javansk
+Name[de]=Javanisch
+Name[eo]=Java
+Name[es]=Javanés
+Name[et]=Jaava
+Name[eu]=Javera
+Name[fa]=جاوانیز
+Name[fi]=Jaava
+Name[fr]=Javanais
+Name[fy]=Javaansk
+Name[ga]=Iávais
+Name[gl]=Xavanés
+Name[he]=×™×ווה
+Name[hi]=जावानी (Javanese)
+Name[hr]=Javanski
+Name[hsb]=Jawanisce
+Name[hu]=Jávai
+Name[id]=Jawa
+Name[it]=Giavanese
+Name[ja]=ジャワ語
+Name[ka]=იáƒáƒ•áƒ
+Name[kk]=Ява
+Name[km]=យ៉ាវា
+Name[ko]=ìžë°”ì–´
+Name[lb]=Javanesesch
+Name[lt]=JavieÄių
+Name[lv]=Javiešu
+Name[mk]=ЈаванÑки
+Name[mn]=Явон
+Name[ms]=Jawa
+Name[nb]=Javanesisk
+Name[nds]=Javaneesch
+Name[ne]=जाभानिज
+Name[nl]=Javanees
+Name[nn]=Javanesisk
+Name[nso]=Se-Javanese
+Name[pa]=ਜਾਵਾਨੀਅਨ
+Name[pl]=Jawański
+Name[pt]=Javanês
+Name[pt_BR]=Javanês
+Name[ro]=Iavaneză
+Name[ru]=ЯванÑкий
+Name[rw]=Ikijavani
+Name[se]=Jávagiella
+Name[sk]=jávÄina
+Name[sl]=javansko
+Name[sq]=Javonisht
+Name[sr]=ЈаванÑки
+Name[sr@Latn]=Javanski
+Name[ss]=Si-Javanese
+Name[sv]=Javanska
+Name[ta]=ஜாவானீஸà¯
+Name[te]=జావానీసà±
+Name[tg]=Ðвонӣ
+Name[th]=ภาษาชวา
+Name[tt]=Javaça
+Name[uk]=ЯванÑька
+Name[uz]=Yaavanez
+Name[uz@cyrillic]=Яаванез
+Name[vi]=Gia-va
+Name[wa]=Djavanès
+Name[zh_CN]=爪哇语
+Name[zh_HK]=爪哇語
+Name[zh_TW]=爪哇語
+Name[zu]=Isi-Javanisi
+[ka]
+Name=Georgian
+Name[af]=Georgiën
+Name[ar]=جورجي
+Name[az]=Gürcücə
+Name[be]=ГрузінÑкаÑ
+Name[bg]=ГрузинÑки
+Name[bn]=জরà§à¦œà¦¿à§Ÿà¦¾à¦¨
+Name[br]=Jeorjieg
+Name[bs]=Gruzijski
+Name[ca]=Georgià
+Name[cs]=Gruzínský
+Name[csb]=Grëzóńsczi
+Name[cy]=Georgeg
+Name[da]=Georgisk
+Name[de]=Georgisch
+Name[el]=ΓεωÏγιανά
+Name[eo]=Kartvela
+Name[es]=Georgiano
+Name[et]=Gruusia
+Name[eu]=Georgiera
+Name[fa]=گرجی
+Name[fi]=Georgia
+Name[fr]=Géorgien
+Name[fy]=Georgysk
+Name[ga]=Seoirsis
+Name[gl]=Xeorxiano
+Name[he]=גרוזינית
+Name[hi]=जà¥à¤¯à¥‰à¤°à¥à¤œà¤¿à¤¯à¤¨
+Name[hr]=Gruzijski
+Name[hsb]=Gruzinsce
+Name[hu]=Grúz
+Name[is]=Georgíska
+Name[it]=Georgiano
+Name[ja]=グルジア語
+Name[ka]=ქáƒáƒ áƒ—ული
+Name[kk]=Грузинше
+Name[km]=ហ្សកហ្ស៉ី
+Name[ko]=그루지안어
+Name[lb]=Georgesch
+Name[lt]=Gruzinų
+Name[lv]=Gruzīņu
+Name[mk]=ГрузиÑки
+Name[mn]=Георги
+Name[ms]=Georgia
+Name[nb]=Georgisk
+Name[nds]=Georgsch
+Name[ne]=जरà¥à¤œà¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Georgisch
+Name[nn]=Georgisk
+Name[nso]=Se-Georgian
+Name[pa]=ਜਾਰਜੀਆ
+Name[pl]=Gruziński
+Name[pt]=Geórgio
+Name[pt_BR]=Geórgio
+Name[ro]=Georgiană
+Name[ru]=ГрузинÑкий
+Name[rw]=Ikinyageworugiya
+Name[se]=Grusiagiella
+Name[sk]=gruzínÄina
+Name[sl]=gruzijsko
+Name[sq]=Xhorxhanisht
+Name[sr]=ГрузијÑки
+Name[sr@Latn]=Gruzijski
+Name[ss]=Si-Georgian
+Name[sv]=Georgiska
+Name[ta]=ஜாரà¯à®œà®¿à®¯à®©à¯
+Name[te]=జారà±à°œà°¿à°¯à°¨à±
+Name[tg]=Гурҷӣ
+Name[th]=ภาษาจอร์เจียน
+Name[tr]=Gürcüce
+Name[tt]=Görceçä
+Name[uk]=ГрузинÑька
+Name[uz]=Gruzincha
+Name[uz@cyrillic]=Грузинча
+Name[vi]=Gi-oa-gi-ạ
+Name[wa]=Djeyordjyin
+Name[zh_CN]=乔治亚语
+Name[zh_HK]=喬治亞語
+Name[zh_TW]=喬治亞語
+Name[zu]=Isi-Jojiyani
+[ki]
+Name=Kikuyu
+Name[ar]=الكيكويو
+Name[az]=Kikuyuca
+Name[be]=Кікую
+Name[bg]=Кикю
+Name[bn]=কিকà§à§Ÿà§
+Name[et]=Kikuju
+Name[fa]=کیکویا
+Name[fi]=Kikuju
+Name[ga]=Ciocúis
+Name[he]=קיקויו
+Name[hi]=किकूयू
+Name[hu]=Kikuju
+Name[ja]=キクユ語
+Name[ka]=კიკუიუ
+Name[kk]=Кикую
+Name[km]=គីគូយូ
+Name[ko]=키쿠유어
+Name[lb]=Kikuyu-Sprooch
+Name[mk]=Кикују
+Name[mn]=Кикуюу
+Name[ne]=किकà¥à¤¯à¥
+Name[nso]=Se-Kikuyu
+Name[pa]=ਕਿਕੂਯੂ
+Name[ru]=Кикую
+Name[rw]=Ikikuyu
+Name[se]=Kikujugiella
+Name[sk]=kikuju
+Name[sl]=kikuyu
+Name[sq]=Kikuisht
+Name[sr]=КикујÑки
+Name[sr@Latn]=Kikujski
+Name[ss]=Si-Kikuyu
+Name[ta]=கியà¯à®•à¯
+Name[te]=à°•à°¿à°•à±à°¯à±
+Name[tg]=КикуÑгӣ
+Name[th]=ภาษาคิคุยุ
+Name[tt]=Kikuyuça
+Name[uk]=Кікуйю
+Name[uz@cyrillic]=Кикуйу
+Name[vi]=Ki-ku-yu
+Name[zh_CN]=基库尤语
+Name[zh_HK]=å‰åº«çŒ¶èªž
+Name[zh_TW]=å‰åº«çŒ¶èªž
+Name[zu]=Isi-Kikuyu
+[kk]
+Name=Kazakh
+Name[ar]=كزخي
+Name[az]=Qazaxca
+Name[be]=КазахÑкаÑ
+Name[bg]=КазахÑки
+Name[bn]=কাজাখ
+Name[br]=Kazakstaneg
+Name[bs]=Kazaški
+Name[cs]=Kazašský
+Name[csb]=Kazachsczi
+Name[de]=Kasachisch
+Name[el]=Καζαχικά
+Name[eo]=Kazaĥa
+Name[es]=Kazajo
+Name[et]=Kasahhi
+Name[eu]=Kazakhera
+Name[fa]=قزاق
+Name[fi]=Kazakki
+Name[ga]=Casaicis
+Name[gl]=Cazaxo
+Name[he]=קזחית
+Name[hi]=कज़ाख
+Name[hr]=KazaÄki
+Name[hsb]=Kazachisce
+Name[hu]=Kazah
+Name[it]=Kazako
+Name[ja]=カザフ語
+Name[ka]=ყáƒáƒ–áƒáƒ®áƒ£áƒ áƒ˜
+Name[kk]=Қазақша
+Name[km]=កាហ្សាក់ស្ážáž„់
+Name[ko]=ì¹´ìží¬ì–´
+Name[lb]=Kasachesch
+Name[lt]=Kazachų
+Name[lv]=Kazahu
+Name[mk]=КазахÑтанÑки
+Name[mn]=Казак
+Name[nds]=Kasachsch
+Name[ne]=कजाक
+Name[nn]=Kasakhisk
+Name[nso]=Se-Kazakh
+Name[pa]=ਕਾਜ਼ਾਖ
+Name[pl]=Kazachski
+Name[pt]=Cazaquistanês
+Name[ro]=Cazacă
+Name[ru]=КазахÑкий
+Name[rw]=Igikazaki
+Name[se]=Kazakhagiella
+Name[sk]=kazaština
+Name[sl]=kazaško
+Name[sq]=Kazakistanisht
+Name[sr]=Казачки
+Name[sr@Latn]=KazaÄki
+Name[ss]=Si-Kazakh
+Name[sv]=Kazakiska
+Name[ta]=கசாகà¯
+Name[te]=కజాఖà±
+Name[tg]=Қазоқӣ
+Name[th]=ภาษาคาซัคสถาน
+Name[tt]=Qazaqça
+Name[uk]=КазахÑька
+Name[uz]=Qozoqcha
+Name[uz@cyrillic]=Қозоқча
+Name[vi]=Kha-xakh
+Name[wa]=Kazaxh
+Name[zh_CN]=哈è¨å…‹è¯­
+Name[zh_HK]=哈薩克語
+Name[zh_TW]=哈薩克語
+Name[zu]=Isi-Kazakhi
+[kl]
+Name=Kalaallisut
+Name[ar]=الكالاليسوت
+Name[az]=Kalaallisutca
+Name[be]=КалааліÑут
+Name[bg]=КалиÑути
+Name[bn]=কালালিসà§à¦Ÿ
+Name[fa]=کالالیسوت
+Name[fi]=Grönlanti
+Name[ga]=Graonlainnis
+Name[gl]=Groenlandés
+Name[he]=קל×ליסוט
+Name[hi]=कलालिसà¥à¤¤
+Name[hu]=Kalaalliszut
+Name[ja]=グリーンランド語
+Name[ka]=კáƒáƒšáƒáƒáƒšáƒ˜áƒ¡áƒ£áƒ¢áƒ˜
+Name[kk]=КалаалиÑутша
+Name[km]=កាឡាលីសាážáŸ‹
+Name[ko]=그린란드어
+Name[mk]=КалалиÑут
+Name[mn]=КалааллиÑут
+Name[ne]=कलालà¥à¤²à¤¿à¤¸à¥à¤Ÿ
+Name[nn]=Grønlandsk
+Name[nso]=Se-Kalaallisut
+Name[pa]=ਕਾਲਾਆਲਿਸੂਟ
+Name[ro]=Calalisută
+Name[ru]=КалаалиÑут
+Name[rw]=Igikalalisuti
+Name[se]=Kalállisutgiella
+Name[sk]=grónÄina
+Name[sl]=kalaallisut
+Name[sq]=Katalisht
+Name[sr]=КалалиÑутÑки
+Name[sr@Latn]=Kalalisutski
+Name[ss]=Si-Kalaallisut
+Name[sv]=Grönländska
+Name[ta]=கலாலிசà¯à®Ÿà¯
+Name[te]=కలాలà±à°²à°¿à°¸à±à°¤à±
+Name[tg]=КалаалиÑутӣ
+Name[th]=ภาษาคาลัทลิซุท
+Name[tt]=Kalaallisutça
+Name[uk]=КалааліÑут
+Name[uz@cyrillic]=КалааллиÑут
+Name[vi]=Ka-lă-li-sút
+Name[zh_CN]=格陵兰语
+Name[zh_HK]=Kalaallisut語
+Name[zh_TW]=Kalaallisut語
+Name[zu]=Isi-Kalaallisut
+[km]
+Name=Khmer
+Name[ar]=خميري
+Name[az]=XmercÉ™
+Name[be]=ХмерÑкаÑ
+Name[bg]=КхмерÑки
+Name[bn]=খমের
+Name[br]=Kmereg
+Name[bs]=Kmerski
+Name[cs]=Kmérský
+Name[csb]=Khmersczi
+Name[eo]=Kmera
+Name[et]=Khmeeri
+Name[fa]=خمری
+Name[ga]=Ciméiris
+Name[he]=חמר
+Name[hi]=खà¥à¤®à¥‡à¤°
+Name[hr]=Kmerski
+Name[ja]=クメール語
+Name[ka]=ქჰმერული
+Name[kk]=Кхмерше
+Name[km]=ážáŸ’មែរ
+Name[ko]=캄보디아어
+Name[lt]=Khmerų
+Name[lv]=Khmeru
+Name[mk]=КмерÑки
+Name[mn]=Хмер
+Name[ne]=खमेर
+Name[nso]=Se-Khmer
+Name[pa]=ਖਮੀਰ
+Name[pl]=Khmerski
+Name[ro]=Kmeră
+Name[ru]=КхмерÑкий
+Name[rw]=Ikinyakime
+Name[se]=Khmeragiella
+Name[sk]=khmérÄina
+Name[sl]=kmersko
+Name[sq]=Kmerisht
+Name[sr]=КмерÑки
+Name[sr@Latn]=Kmerski
+Name[ss]=Si-Khmer
+Name[sv]=Kambodjanska
+Name[ta]=கெமரà¯
+Name[te]=à°–à±à°®à±†à°°à±
+Name[tg]=Хмерӣ
+Name[th]=ภาษาเขมร
+Name[tt]=Xmerçä
+Name[uk]=КхмерÑька
+Name[uz]=Kxmercha
+Name[uz@cyrillic]=Кхмерча
+Name[vi]=Khơ-me
+Name[wa]=Xhmer
+Name[zh_CN]=高棉语
+Name[zh_HK]=高棉語
+Name[zh_TW]=高棉語
+Name[zu]=Isi-Khmer
+[kn]
+Name=Kannada
+Name[af]=Kanadees
+Name[ar]=الكانادا
+Name[az]=Kannadaca
+Name[be]=КанадÑкаÑ
+Name[bg]=Каннада
+Name[bn]=কনà§à¦¨à¦¾à¦¡à¦¾
+Name[br]=Kanada
+Name[fa]=کانادایی
+Name[ga]=Cannadais
+Name[he]=קנ×דה
+Name[hi]=कनà¥à¤¨à¤¡à¤¼
+Name[ja]=カンナダ語
+Name[ka]=კáƒáƒœáƒœáƒáƒ“áƒ
+Name[kk]=Каннада
+Name[km]=កិណាដា
+Name[mk]=Канада
+Name[mn]=Канад
+Name[ne]=कानाडा
+Name[nso]=Se-Kannada
+Name[pa]=ਕਾਨਡਾ
+Name[pt_BR]=Canadá
+Name[ro]=Kanada
+Name[ru]=Каннада
+Name[rw]=Iginyakanada
+Name[se]=Kannadagiella
+Name[sk]=kannadÄina
+Name[sl]=kannada
+Name[sq]=Kanadisht
+Name[sr]=КанадÑки
+Name[sr@Latn]=Kanadski
+Name[ss]=Si-Kannada
+Name[sv]=Kanaresiska
+Name[ta]=கனà¯à®©à®Ÿà®®à¯
+Name[te]=à°•à°¨à±à°¨à°¡
+Name[tg]=Каннадӣ
+Name[th]=ภาษาà¸à¸±à¸“ณาท
+Name[tt]=Kannadça
+Name[uk]=Каннада
+Name[uz@cyrillic]=Каннада
+Name[vi]=Ka-na-Ä‘a
+Name[zh_CN]=åŽçº³å¾·è¯­
+Name[zh_HK]=åŽé‚£é”語
+Name[zh_TW]=åŽé‚£é”語
+Name[zu]=Isi-Khanada
+[ko]
+Name=Korean
+Name[af]=Koriaanse
+Name[ar]=الكورية
+Name[az]=Koreyaca
+Name[be]=КарÑйÑкаÑ
+Name[bg]=КорейÑки
+Name[bn]=কোরীয়
+Name[br]=Koreeg
+Name[bs]=Korejski
+Name[ca]=Coreà
+Name[cs]=Korejský
+Name[csb]=Kòrejańsczi
+Name[cy]=Koreëg
+Name[da]=Koreansk
+Name[de]=Koreanisch
+Name[el]=ΚοÏεάτικα
+Name[eo]=Korea
+Name[es]=Coreano
+Name[et]=Korea
+Name[eu]=Koreera
+Name[fa]=کره‌ای
+Name[fi]=Korea
+Name[fr]=Coréen
+Name[fy]=Koareaansk
+Name[ga]=Cóiréis
+Name[gl]=Coreano
+Name[he]=קורי×נית
+Name[hi]=कोरियाई
+Name[hr]=Korejski
+Name[hsb]=Koreansce
+Name[hu]=Koreai
+Name[id]=Korea
+Name[is]=Kóreska
+Name[it]=Coreano
+Name[ja]=韓国語・æœé®®èªž
+Name[ka]=კáƒáƒ áƒ”ული
+Name[kk]=Корейше
+Name[km]=កូរ៉áŸ
+Name[ko]=한국어
+Name[lb]=Koreanesch
+Name[lt]=KorÄ—jieÄių
+Name[lv]=Korejiešu
+Name[mk]=КорејÑки
+Name[mn]=СолонгоÑ
+Name[ms]=Korea
+Name[nb]=Koreansk
+Name[nds]=Koreaansch
+Name[ne]=कोरियाली
+Name[nl]=Koreaans
+Name[nn]=Koreansk
+Name[nso]=Se-Korean
+Name[oc]=Còrean
+Name[pa]=ਕੋਰੀਆਈ
+Name[pl]=Koreański
+Name[pt]=Coreano
+Name[pt_BR]=Coreano
+Name[ro]=Coreană
+Name[ru]=КорейÑкий
+Name[rw]=Igikoreya
+Name[se]=Koreagiella
+Name[sk]=kórejÄina
+Name[sl]=korejsko
+Name[sq]=Koreanisht
+Name[sr]=КорејÑки
+Name[sr@Latn]=Korejski
+Name[ss]=SiKoriya
+Name[sv]=Koreanska
+Name[ta]=கொரியனà¯
+Name[te]=కొరియనà±
+Name[tg]=КореÑгӣ
+Name[th]=ภาษาเà¸à¸²à¸«à¸¥à¸µ
+Name[tr]=Korece
+Name[tt]=Koreyçä
+Name[uk]=КорейÑька
+Name[uz]=Koreyscha
+Name[uz@cyrillic]=КорейÑча
+Name[vi]=Triều-tiên
+Name[wa]=Coreyin
+Name[xh]=Isikorea
+Name[zh_CN]=æœé²œè¯­
+Name[zh_HK]=韓國語
+Name[zh_TW]=韓國語
+Name[zu]=Isi-Korean
+[ks]
+Name=Kashmiri
+Name[ar]=كشميري
+Name[az]=KaÅŸmircÉ™
+Name[be]=КашмірÑкаÑ
+Name[bg]=Кашмири
+Name[bn]=কাশà§à¦®à§€à¦°à¦¿
+Name[bs]=Kašmirski
+Name[cs]=Kašmírský
+Name[csb]=Kaszmirsczi
+Name[da]=Kashmirsk
+Name[eo]=KaÅmira
+Name[et]=Kašmiiri
+Name[eu]=Kaxmirera
+Name[fa]=کشمیری
+Name[fi]=Kašmiri
+Name[ga]=Caismíris
+Name[gl]=Caxemir
+Name[he]=קשמירית
+Name[hi]=कशà¥à¤®à¥€à¤°à¥€
+Name[hr]=Kašmirski
+Name[hsb]=Kašmirsce
+Name[hu]=Kasmír
+Name[id]=Kashmir
+Name[it]=Cachemire, lingua del
+Name[ja]=カシュミール語
+Name[ka]=ქáƒáƒ¨áƒ›áƒ˜áƒ áƒ£áƒšáƒ˜
+Name[kk]=Кашмирше
+Name[km]=កាស្មៀរ
+Name[ko]=카슈미르어
+Name[lt]=Kašmiro
+Name[lv]=Kašmiriešu
+Name[mk]=КашмирÑки
+Name[mn]=Кашмири
+Name[nds]=Kaschmiirsch
+Name[ne]=काशà¥à¤®à¤¿à¤°à¥€
+Name[nn]=Kasjmiri
+Name[nso]=Se-Kashmiri
+Name[pa]=ਕਸ਼ਮੀਰੀ
+Name[pl]=Kaszmirski
+Name[pt_BR]=Cashimira
+Name[ro]=Caşmiră
+Name[ru]=КашмирÑкий
+Name[rw]=Igikashimiri
+Name[se]=Kašmirgiella
+Name[sk]=kaÅ¡mírÄina
+Name[sl]=kašmirsko
+Name[sq]=Kashmirisht
+Name[sr]=КашмирÑки
+Name[sr@Latn]=Kašmirski
+Name[ss]=Si-Kashmiri
+Name[ta]=காஷà¯à®®à¯€à®°à®¿
+Name[te]=à°•à°·à±à°®à±€à°°à±€
+Name[tg]=Кашмирӣ
+Name[th]=ภาษาà¸à¸±à¸¨à¸¡à¸´à¸£à¸µ
+Name[tt]=Kaşmirçä
+Name[uk]=КашмірÑька
+Name[uz]=Kashmircha
+Name[uz@cyrillic]=Кашмирча
+Name[vi]=Ka-x-mi-ri
+Name[wa]=Cachmiri
+Name[zh_CN]=克什米尔语
+Name[zh_HK]=喀什米爾語
+Name[zh_TW]=喀什米爾語
+Name[zu]=Isi-Kashimiri
+[ku]
+Name=Kurdish
+Name[ar]=الكردية
+Name[az]=Kürdcə
+Name[be]=КурдÑкаÑ
+Name[bg]=КюрдÑки
+Name[bn]=কà§à¦°à§à¦¦à¦¿à¦¶
+Name[br]=Kurdeg
+Name[bs]=Kurdski
+Name[ca]=Kurd
+Name[cs]=Kurdský
+Name[csb]=Kùrdijsczi
+Name[cy]=Kwrdeg
+Name[da]=Kurdisk
+Name[de]=Kurdisch
+Name[el]=ΚουÏδικά
+Name[eo]=Kurda
+Name[es]=Kurdo
+Name[et]=Kurdi
+Name[eu]=Turkiera
+Name[fa]=کردی
+Name[fi]=Kurdi
+Name[fr]=Kurde
+Name[fy]=Koerdysk
+Name[ga]=Coirdis
+Name[gl]=Kurdo
+Name[he]=כורדית
+Name[hi]=कà¥à¤°à¥à¤¦à¤¿à¤¶
+Name[hr]=Kurdski
+Name[hsb]=Kurdisce
+Name[hu]=Kurd
+Name[id]=Kurdi
+Name[is]=Kúrdíska
+Name[it]=Curdo
+Name[ja]=クルド語
+Name[ka]=ქურთული
+Name[kk]=Курдше
+Name[km]=ឃឺដ
+Name[ko]=쿠르드어
+Name[ku]=Kurdî
+Name[lb]=Kurdesch
+Name[lt]=Kurdų
+Name[lv]=Kurdu
+Name[mk]=КурдÑки
+Name[mn]=Күрд
+Name[mt]=Kurd
+Name[nb]=Kurdisk
+Name[nds]=Kurdsch
+Name[ne]=कà¥à¤°à¥à¤¦à¤¿à¤¶
+Name[nl]=Koerdisch
+Name[nn]=Kurdisk
+Name[nso]=Se-Kurdish
+Name[pa]=ਕà©à¨°à¨¦
+Name[pl]=Kurdyjski
+Name[pt]=Curdo
+Name[pt_BR]=Turco
+Name[ro]=Curdă
+Name[ru]=КурдÑкий
+Name[rw]=Igikurudishi
+Name[se]=Kurdigiella
+Name[sk]=kurdÄina
+Name[sl]=kurdsko
+Name[sq]=Kurdisht
+Name[sr]=КурдÑки
+Name[sr@Latn]=Kurdski
+Name[ss]=Si-Kurdish
+Name[sv]=Kurdiska
+Name[ta]=கà¯à®°à¯à®¤à®¿à®·à¯
+Name[te]=à°•à±à°°à±à°¦à°¿à°·à±
+Name[tg]=Курдиш
+Name[th]=ภาษาเคอร์ดิช
+Name[tr]=Kürtçe
+Name[tt]=Kördçä
+Name[uk]=КурдÑька
+Name[uz]=Kurdcha
+Name[uz@cyrillic]=Курдча
+Name[vi]=Kuổ-đị
+Name[wa]=Kurdi
+Name[zh_CN]=库尔德语
+Name[zh_HK]=庫德語
+Name[zh_TW]=庫德語
+Name[zu]=isi-Kurdish
+[kv]
+Name=Komi
+Name[ar]=الكومي
+Name[az]=KomicÉ™
+Name[be]=Комі
+Name[bg]=КомизирÑнÑки
+Name[bn]=কোমি
+Name[csb]=z Komi
+Name[eo]=Komia
+Name[eu]=Komoreera
+Name[fa]=کمی
+Name[ga]=Coimí
+Name[he]=קומי
+Name[hi]=कोमी
+Name[ja]=コミ語
+Name[ka]=კáƒáƒ›áƒ˜
+Name[kk]=Коми
+Name[km]=កូមី
+Name[ko]=코미어
+Name[lb]=Komi-Sprooch
+Name[mk]=Коми
+Name[mn]=Коми
+Name[ne]=कोमी
+Name[nso]=Se-Komi
+Name[pa]=ਕੋਮੀ
+Name[pl]=z Komi
+Name[ru]=Коми
+Name[rw]=Igikomi
+Name[se]=Komigiella
+Name[sk]=komijÄina
+Name[sl]=komi
+Name[sq]=Komisht
+Name[sr]=КомÑки
+Name[sr@Latn]=Komski
+Name[ss]=Si-Komi
+Name[ta]=கோமி
+Name[te]=కోమి
+Name[tg]=Коми
+Name[th]=ภาษาคอมี
+Name[tt]=Komiçä
+Name[uk]=Комі
+Name[uz@cyrillic]=Коми
+Name[vi]=Khô-mi
+Name[zh_CN]=科米语
+Name[zh_HK]=Komi語
+Name[zh_TW]=Komi語
+Name[zu]=Isi-Komi
+[kw]
+Name=Cornish
+Name[ar]=كورنش
+Name[az]=KorniÅŸcÉ™
+Name[be]=КорнÑкаÑ
+Name[bg]=КорнуълÑки
+Name[bn]=করà§à¦¨à¦¿à¦¶
+Name[br]=Korneveg
+Name[bs]=Kornski
+Name[cs]=Kornišský
+Name[csb]=Kòrnwalijsczi
+Name[cy]=Cernyweg
+Name[da]=Kornisk
+Name[de]=Kornisch
+Name[el]=ΚοÏνουαλικά
+Name[eo]=Kornvala
+Name[et]=Korni
+Name[fa]=کرنیشی
+Name[fi]=Korni
+Name[fr]=Cornique
+Name[fy]=Cornysk
+Name[ga]=Coirnis
+Name[gl]=Córnico
+Name[he]=קורנית
+Name[hi]=कॉरà¥à¤¨à¤¿à¤¶
+Name[hr]=Kornski
+Name[hsb]=Kornisce
+Name[hu]=Korn
+Name[it]=Cornovaglia, lingua della
+Name[ja]=コーンウォール語
+Name[ka]=კáƒáƒ áƒœáƒ£áƒ”ლური
+Name[kk]=Корнуолше
+Name[km]=កូនីស
+Name[ko]=콘월어
+Name[lb]=Kornesch
+Name[lt]=Kornų
+Name[mk]=Корниш
+Name[mn]=Корни
+Name[nb]=Cornisk
+Name[nds]=Kornisch
+Name[ne]=करà¥à¤¨à¤¿à¤¸
+Name[nn]=Kornisk
+Name[nso]=Se-Cornish
+Name[pa]=ਕੋਰਨਿਸ਼
+Name[pl]=Kornwalijski
+Name[pt]=Cornualho
+Name[ro]=Corneză
+Name[ru]=КорнуольÑкий
+Name[rw]=Igikorunishe
+Name[se]=Kornagiella
+Name[sk]=kornÄina
+Name[sl]=cornish
+Name[sq]=Kornisht
+Name[sr]=КорнÑки
+Name[sr@Latn]=Kornski
+Name[ss]=Si-Cornish
+Name[sv]=Korniska
+Name[ta]=கோரà¯à®©à®¿à®·à¯
+Name[te]=కొరà±à°¨à°¿à°·à±
+Name[tg]=КорниÑгӣ
+Name[th]=ภาษาคอร์นิช
+Name[tt]=Kornişçä
+Name[uk]=КорнійÑька
+Name[uz]=Korn
+Name[uz@cyrillic]=Корн
+Name[vi]=Xen-tợ Coanh-ouặn
+Name[wa]=Cornike
+Name[zh_CN]=康瓦尔郡语
+Name[zh_HK]=康瓦耳語
+Name[zh_TW]=康瓦耳語
+Name[zu]=Isi-Khonishi
+[ky]
+Name=Kirghiz
+Name[ar]=قرغيز
+Name[az]=Qırğızca
+Name[be]=КіргізÑкаÑ
+Name[bg]=Киргизки
+Name[bn]=কারà§à¦˜à¦¿à¦¸
+Name[br]=Kirgistaneg
+Name[bs]=Kirgiški
+Name[cs]=Kyrgizský
+Name[csb]=Kirgijsczi
+Name[de]=Kirgisisch
+Name[eo]=Kirgiza
+Name[es]=Kirguiz
+Name[et]=Kirgiisi
+Name[eu]=Kirgiera
+Name[fa]=قرقیزی
+Name[fi]=Kirgiisi
+Name[fr]=Kirghize
+Name[fy]=Kirgizysk
+Name[ga]=Cirgeastáinis
+Name[gl]=Quirguize
+Name[he]=קירגיזית
+Name[hi]=किरà¥à¤—िज
+Name[hr]=Kirgiški
+Name[hsb]=Kirgisce
+Name[hu]=Kirgiz
+Name[is]=Kirgíska
+Name[it]=Chirghiso
+Name[ja]=キルギス語
+Name[ka]=ყირგიზული
+Name[kk]=Қырғызша
+Name[km]=គៀរហ្គីស្ážáž„់
+Name[ko]=키르키즈어
+Name[lb]=Kirghisesch
+Name[lt]=Kirgizų
+Name[lv]=Kirgīzu
+Name[mk]=КиргизтанÑки
+Name[mn]=Киргиз
+Name[nb]=Kirgisisk
+Name[nds]=Kirgiisch
+Name[ne]=कà¥à¤°à¤¿à¤—िज
+Name[nl]=Kirghizisch
+Name[nn]=Kirgisisk
+Name[nso]=Se-Kirghiz
+Name[pa]=ਕਿਰਘੀਜ਼
+Name[pl]=Kirgiski
+Name[pt]=Quirguistanês
+Name[ro]=Chirghiză
+Name[ru]=КиргизÑкий
+Name[rw]=Ikirigizi
+Name[se]=Kirgisiagiella
+Name[sk]=kirgizština
+Name[sl]=kirgizijsko
+Name[sq]=Kirgjizisht
+Name[sr]=КиргиÑки
+Name[sr@Latn]=Kirgiski
+Name[ss]=Si-Kirghiz
+Name[sv]=Kirghiziska
+Name[ta]=கிரà¯à®•à®¿à®¸à¯
+Name[te]=à°•à°¿à°°à±à°˜à°¿à°œà±
+Name[tg]=Кирғизӣ
+Name[th]=ภาษาเคอร์à¸à¸´à¸‹
+Name[tr]=Kırgız
+Name[tt]=Qırğızça
+Name[uk]=Киргизька
+Name[uz]=Qirgʻizcha
+Name[uz@cyrillic]=Қирғизча
+Name[vi]=Kia-gi-x
+Name[wa]=Kirguize
+Name[zh_CN]=å‰å°”å‰æ–¯è¯­
+Name[zh_HK]=å‰çˆ¾å‰æ–¯èªž
+Name[zh_TW]=å‰çˆ¾å‰æ–¯èªž
+Name[zu]=Isi-Kirghizi
+[la]
+Name=Latin
+Name[af]=Latyn
+Name[ar]=لاتيني
+Name[az]=Latınca
+Name[be]=ЛацінÑкаÑ
+Name[bg]=ЛатинÑки
+Name[bn]=লাতিন
+Name[bs]=Latinski
+Name[ca]=Llatí
+Name[cs]=Latina
+Name[csb]=Åacëzna
+Name[cy]=Lladin
+Name[de]=Latein
+Name[el]=Λατινικά
+Name[eo]=Latino
+Name[es]=Latín
+Name[et]=Ladina
+Name[eu]=Latina
+Name[fa]=لاتین
+Name[fi]=Latina
+Name[fy]=Latyn
+Name[ga]=Laidin
+Name[he]=לטינית
+Name[hi]=लेटिन
+Name[hr]=Latinski
+Name[hsb]=Åaćonsce
+Name[is]=Latína
+Name[it]=Latino
+Name[ja]=ラテン語
+Name[ka]=ლáƒáƒ—ინური
+Name[kk]=Латынша
+Name[km]=ឡាážáž¶áŸ†áž„
+Name[ko]=ë¼í‹´ì–´
+Name[lb]=Latäin
+Name[lt]=Lotynų
+Name[mk]=ЛатинÑки
+Name[mn]=Латин
+Name[nds]=Latiensch
+Name[ne]=लà¥à¤¯à¤¾à¤Ÿà¤¿à¤¨
+Name[nl]=Latijn
+Name[nso]=Se-Latin
+Name[pa]=ਲੈਟਿਨ
+Name[pl]=ÅaciÅ„ski
+Name[pt]=Latim
+Name[pt_BR]=Latim
+Name[ro]=Latină
+Name[ru]=ЛатинÑкий
+Name[rw]=Ikilatini
+Name[se]=Láhtengiella
+Name[sk]=latinÄina
+Name[sl]=latinsko
+Name[sq]=Latinisht
+Name[sr]=ЛатинÑки
+Name[sr@Latn]=Latinski
+Name[ss]=Si-Latin
+Name[ta]=இலதà¯à®¤à¯€à®©à¯
+Name[te]=లాటినà±
+Name[tg]=Лотинӣ
+Name[th]=ภาษาละติน
+Name[tt]=Latínça
+Name[uk]=ЛатинÑька
+Name[uz]=Lotincha
+Name[uz@cyrillic]=Лотинча
+Name[vi]=La-tinh
+Name[wa]=Latén
+Name[zh_CN]=拉ä¸è¯­
+Name[zh_HK]=拉ä¸èªž
+Name[zh_TW]=拉ä¸èªž
+Name[zu]=Isi-Lathini
+[lb]
+Name=Luxembourgish
+Name[ar]=لوكسمبورغي
+Name[az]=Lyuksemburqca
+Name[be]=ЛюкÑембургÑкаÑ
+Name[bg]=ЛюкÑембургÑки
+Name[bn]=লাকà§à¦¸à§‡à¦®à¦¬à¦¾à¦°à§à¦—িশ
+Name[br]=Luksembourgeg
+Name[bs]=Luksemburški
+Name[ca]=Luxemburguès
+Name[cs]=Lucemburský
+Name[csb]=Luksembùrsczi
+Name[cy]=Luxembwrgeg
+Name[de]=Luxemburgisch
+Name[el]=ΛουξεμβουÏγικά
+Name[eo]=Luksemburga
+Name[es]=Luxemburgués
+Name[et]=Luksemburgi
+Name[eu]=Luxenburgera
+Name[fa]=لوکزامبورگ
+Name[fi]=Luxemburg
+Name[fr]=Luxembourgeois
+Name[fy]=Luksemboarchsk
+Name[ga]=Lucsambuirgis
+Name[gl]=Luxemburgués
+Name[he]=לוקסמבורגית
+Name[hi]=लकà¥à¤¸à¤®à¤¬à¤°à¥à¤—िश
+Name[hr]=Luksemburški
+Name[hsb]=Luksemburgsce
+Name[hu]=Luxemburgi
+Name[id]=Luxemburg
+Name[is]=Lúxemborgiska
+Name[it]=Lussemburghese
+Name[ja]=ルクセンブルグ語
+Name[ka]=ლუქსემბურგული
+Name[kk]=ЛюкÑимбургша
+Name[km]=លុចហ្សំបួរ
+Name[lb]=Lëtzebuergesch
+Name[lt]=LiuksemburgieÄių
+Name[lv]=Luksemburgiešu
+Name[mk]=ЛукÑембургÑки
+Name[mn]=ЛюькÑембүрг
+Name[nb]=Luxemburgisk
+Name[nds]=Luxemborgsch
+Name[ne]=लगà¥à¤œà¥‡à¤®à¤¬à¤°à¥à¤—िस
+Name[nl]=Letzenburgs
+Name[nn]=Luxembourgsk
+Name[nso]=Se-Luxembourgish
+Name[pa]=ਲਕਸ਼ਬਰਗਸ਼
+Name[pl]=Luksemburski
+Name[pt]=Luxemburguês
+Name[pt_BR]=Luxemburgo
+Name[ro]=Luxemburgheză
+Name[ru]=ЛюкÑембургÑкий
+Name[rw]=Ikinyalugizamburu
+Name[se]=Luksenburggagiella
+Name[sk]=luxemburÄina
+Name[sl]=luksemburško
+Name[sq]=Luksemburgisht
+Name[sr]=ЛукÑембуршки
+Name[sr@Latn]=Luksemburški
+Name[ss]=Si-Luxembourgish
+Name[sv]=Luxemburgiska
+Name[ta]=லகà¯à®šà®®à¯à®ªà¯‹à®°à¯à®•à®¿à®·à¯
+Name[te]=లకà±à°¸à±†à°‚బరà±à°—à°¿à°·à±
+Name[tg]=ЛюкÑембургӣ
+Name[th]=ภาษาลัà¸à¹€à¸‹à¸¡à¹€à¸šà¸­à¸£à¹Œà¸
+Name[tt]=Lüksemburgça
+Name[uk]=ЛюкÑембурзька
+Name[uz]=Lyuksemburgcha
+Name[uz@cyrillic]=ЛюкÑембургча
+Name[vi]=Lúc-xăm-buac
+Name[wa]=Lussimbordjwès
+Name[zh_CN]=å¢æ£®å ¡è¯­
+Name[zh_HK]=盧森堡語
+Name[zh_TW]=盧森堡語
+Name[zu]=Isi-Luxembourgish
+[li]
+Name=Limburgan
+Name[ar]=الليمبورغية
+Name[az]=Limburqca
+Name[be]=ЛімбургÑкаÑ
+Name[bg]=ЛимбурганÑки
+Name[bn]=লিমবারà§à¦—ান
+Name[br]=Limburgeg
+Name[bs]=Limburški
+Name[ca]=Limburgà
+Name[csb]=Limbùrgańsczi
+Name[cy]=Limbwrgeg
+Name[da]=Limburgansk
+Name[de]=Limburgisch
+Name[eo]=Limburga
+Name[es]=Limburgano
+Name[et]=Limburgi
+Name[fa]=لیمبرگان
+Name[fi]=Limburgi
+Name[fr]=Limbourgeois
+Name[fy]=Limburgsk
+Name[ga]=Limbuirgis
+Name[gl]=Limburgano
+Name[he]=לימבורגית
+Name[hi]=लिंबरगन
+Name[hr]=Limburški
+Name[hsb]=Limburgsce
+Name[hu]=Limburgi
+Name[is]=Limburgian
+Name[it]=Limburghese
+Name[ja]=リグリア語
+Name[ka]=ლიმბურგული
+Name[kk]=Лимбургша
+Name[km]=លីបួគ
+Name[lb]=Limburgesch
+Name[mk]=ЛимбурганÑки
+Name[mn]=Лимбүрг
+Name[nb]=Limburgisk
+Name[nds]=Limborgsch
+Name[ne]=लिमà¥à¤¬à¥à¤°à¤—न
+Name[nl]=Limburgs
+Name[nn]=Limburgsk
+Name[nso]=Se-Limburgan
+Name[pa]=ਲੀਮਬà©à¨°à¨—ਾਨ
+Name[pl]=Limburgiański
+Name[pt]=Limburguês
+Name[ro]=Limburgană
+Name[ru]=ЛимбуржÑкий
+Name[rw]=Ikilimburigani
+Name[se]=Limburggagiella
+Name[sk]=limburÄina
+Name[sl]=limburgan
+Name[sq]=Limburganisht
+Name[sr]=Лимбуршки
+Name[sr@Latn]=Limburški
+Name[ss]=Si-Limburgan
+Name[sv]=Limburgiska
+Name[ta]=லகà¯à®šà®®à¯à®ªà¯‡à®°à¯à®•à¯
+Name[te]=లింబరà±à°—à°¨à±
+Name[tg]=Лимбурганӣ
+Name[th]=ภาษาลิมเบอร์à¸à¸±à¸™
+Name[tt]=Limburgça
+Name[uk]=ЛімбурганÑька
+Name[uz@cyrillic]=Лимбурган
+Name[vi]=Lim-bua-ga
+Name[wa]=Limbordjwès
+Name[zh_CN]=林堡语
+Name[zh_HK]=Limburgan語
+Name[zh_TW]=Limburgan語
+Name[zu]=Isi-Lumburgan
+[ln]
+Name=Lingala
+Name[ar]=اللينغالا
+Name[az]=Linqalaca
+Name[be]=ЛінгальÑкаÑ
+Name[bg]=Лингала
+Name[bn]=লিঙà§à¦—ালা
+Name[br]=Lingaleg
+Name[fa]=لینگالا
+Name[he]=לינגלה
+Name[hi]=लिंगला
+Name[hr]=Lingalski
+Name[ja]=リンガラ語
+Name[ka]=ლინგáƒáƒšáƒ
+Name[kk]=Лингата
+Name[km]=លីនហ្កាឡា
+Name[mk]=Лингала
+Name[mn]=Лингала
+Name[ne]=लिङà¥à¤—ाला
+Name[nso]=Se-Lingala
+Name[pa]=ਲੀਨਗਾਲਾ
+Name[ro]=Lingală
+Name[ru]=Лингала
+Name[rw]=Ilingala
+Name[se]=Lingalagiella
+Name[sk]=lingalÄina
+Name[sl]=lingala
+Name[sq]=Lingalisht
+Name[sr]=ЛингалÑки
+Name[sr@Latn]=Lingalski
+Name[ss]=Si-Lingala
+Name[ta]=லிஙà¯à®•à®¾à®²à®¾
+Name[te]=లింగాలా
+Name[tg]=Лингалӣ
+Name[th]=ภาษาลิงà¸à¸²à¸¥à¸²
+Name[tt]=Lingalaça
+Name[uk]=Лінгала
+Name[uz@cyrillic]=Лингала
+Name[vi]=Lin-ga-la
+Name[zh_CN]=林加拉语
+Name[zh_HK]=Lingala語
+Name[zh_TW]=Lingala語
+Name[zu]=Isi-Lingala
+[lo]
+Name=Lao
+Name[ar]=لاويه
+Name[az]=Laoca
+Name[be]=ЛаоÑкаÑ
+Name[bg]=ЛаоÑки
+Name[bn]=লাও
+Name[ca]=Laosià
+Name[cs]=Laoský
+Name[csb]=Laòtańsczi
+Name[de]=Laotisch
+Name[eo]=LaÅ­a
+Name[es]=Laosiano
+Name[eu]=Laosera
+Name[fa]=لائویی
+Name[ga]=Láóis
+Name[he]=ל×ו
+Name[hi]=लाओ
+Name[hsb]=Laotisce
+Name[ja]=ラオ語
+Name[ka]=ლáƒáƒ
+Name[kk]=ЛаоÑша
+Name[km]=ឡាវ
+Name[ko]=ë¼ì˜¤ì–´
+Name[lt]=LaosieÄių
+Name[lv]=Laosiešu
+Name[mk]=Лао
+Name[mn]=Лао
+Name[nds]=Laootsch
+Name[ne]=लाओ
+Name[nso]=Se-Lao
+Name[pa]=ਲਿਓ
+Name[pl]=Laotański
+Name[ru]=Лао
+Name[rw]=Ikilawo
+Name[se]=Laogiella
+Name[sk]=laoština
+Name[sl]=laoško
+Name[sq]=Laisht
+Name[sr]=Лао
+Name[ss]=Si-Lao
+Name[sv]=Laotiska
+Name[ta]=லாவோ
+Name[te]=లావో
+Name[tg]=ЛаоÑÓ£
+Name[th]=ภาษาลาว
+Name[tt]=Laoça
+Name[uk]=ЛаоÑька
+Name[uz]=Laoscha
+Name[uz@cyrillic]=ЛаоÑча
+Name[vi]=Lào
+Name[wa]=Lawocyin
+Name[zh_CN]=è€æŒè¯­
+Name[zh_HK]=寮國語
+Name[zh_TW]=寮國語
+Name[zu]=Isi-Lao
+[lt]
+Name=Lithuanian
+Name[af]=Lithuaniese
+Name[ar]=الليتوانية
+Name[az]=Litovca
+Name[be]=ЛітоўÑкаÑ
+Name[bg]=ЛитовÑки
+Name[bn]=লিথà§à§Ÿà§‡à¦¨à§€à§Ÿ
+Name[br]=Lituaneg
+Name[bs]=Litvanski
+Name[ca]=Lituà
+Name[cs]=Litevský
+Name[csb]=Litewsczi
+Name[cy]=Lithuaneg
+Name[da]=Litauisk
+Name[de]=Litauisch
+Name[el]=Λιθουανικά
+Name[eo]=Litova
+Name[es]=Lituano
+Name[et]=Leedu
+Name[eu]=Lituaniera
+Name[fa]=لیتوانی
+Name[fi]=Liettua
+Name[fr]=Lituanien
+Name[fy]=Litouwsk
+Name[ga]=Liotuáinis
+Name[gl]=Lituano
+Name[he]=ליט×ית
+Name[hi]=लिथà¥à¤†à¤¨à¤¿à¤¯à¤¨
+Name[hr]=Litvanski
+Name[hsb]=Litawsce
+Name[hu]=Litván
+Name[id]=Lithuania
+Name[is]=Litháíska
+Name[it]=Lituano
+Name[ja]=リトアニア語
+Name[ka]=ლიტვური
+Name[kk]=Литваша
+Name[km]=លីទុយអានី
+Name[ko]=리투아니아어
+Name[lb]=Litauesch
+Name[lt]=Lietuvių
+Name[lv]=Lietuviešu
+Name[mk]=ЛитванÑки
+Name[mn]=Литви
+Name[ms]=Lithuania
+Name[mt]=Litwanjan
+Name[nb]=Litauisk
+Name[nds]=Litausch
+Name[ne]=लिथà¥à¤¨à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Litouws
+Name[nn]=Litauisk
+Name[nso]=Se-Lithuanian
+Name[oc]=Litua
+Name[pa]=ਲੀਥੂਨੀਆਨ
+Name[pl]=Litewski
+Name[pt]=Lituano
+Name[pt_BR]=Lituano
+Name[ro]=Lituaniană
+Name[ru]=ЛитовÑкий
+Name[rw]=Ikinyalitwani
+Name[se]=Lietuvagiella
+Name[sk]=litovÄina
+Name[sl]=litvansko
+Name[sq]=Lituanisht
+Name[sr]=ЛитванÑки
+Name[sr@Latn]=Litvanski
+Name[ss]=Si-Lithuanian
+Name[sv]=Litauiska
+Name[ta]=லிதà¯à®µà¯‡à®©à®¿à®¯à®©à¯
+Name[te]=లితà±à°µà±†à°¨à°¿à°¯à°¨à±
+Name[tg]=Литвонӣ
+Name[th]=ภาษาลิธัวเนีย
+Name[tr]=Litvanya Dili
+Name[tt]=Litçä
+Name[uk]=ЛитовÑька
+Name[uz]=Litvacha
+Name[uz@cyrillic]=Литвача
+Name[vi]=Li-tu-a-ni
+Name[wa]=Litwanyin
+Name[zh_CN]=立陶宛语
+Name[zh_HK]=立陶宛語
+Name[zh_TW]=立陶宛語
+Name[zu]=Isi-Lithuanian
+[lv]
+Name=Latvian
+Name[ar]=اللاتÙية
+Name[az]=Latışca
+Name[be]=ЛатвійÑкаÑ
+Name[bg]=ЛатвийÑки
+Name[bn]=লাটভিয়ান
+Name[br]=Latvieg
+Name[bs]=Latvijski
+Name[ca]=Letó
+Name[cs]=Lotyšský
+Name[csb]=Åotewsczi
+Name[cy]=Latfieg
+Name[da]=Lettisk
+Name[de]=Lettisch
+Name[el]=Λεττονικά
+Name[eo]=Latvia
+Name[es]=Latvio
+Name[et]=Läti
+Name[eu]=Letoniera
+Name[fa]=لاتوینی
+Name[fi]=Latvia
+Name[fr]=Letton
+Name[fy]=Letsk
+Name[ga]=Laitvis
+Name[gl]=Letón
+Name[he]=לטבית
+Name[hi]=लाटवियन
+Name[hr]=Latvijski
+Name[hsb]=Letisce
+Name[hu]=Lett
+Name[id]=Latvia
+Name[is]=Lettneska
+Name[it]=Lettone
+Name[ja]=ラトビア語
+Name[ka]=ლáƒáƒ¢áƒ•áƒ˜áƒ£áƒ áƒ˜
+Name[kk]=ЛатвиÑша
+Name[km]=ឡាážážœáž¸áž™áŸ‰áž¶
+Name[ko]=ë¼íŠ¸ë¹„ì•„ì–´
+Name[lb]=Lettesch
+Name[lt]=Latvių
+Name[lv]=Latviešu
+Name[mk]=ЛатвиÑки
+Name[mn]=Латви
+Name[ms]=Latvia
+Name[mt]=Latvjan
+Name[nb]=Latvisk
+Name[nds]=Lettsch
+Name[ne]=लाटà¥à¤­à¤¿à¤¯à¤¨
+Name[nl]=Lets
+Name[nn]=Latvisk
+Name[nso]=Se-Latvian
+Name[pa]=ਲਾਟਵੀਨ
+Name[pl]=Åotewski
+Name[pt]=Letão
+Name[pt_BR]=Latvia
+Name[ro]=Latviană
+Name[ru]=ЛатышÑкий
+Name[rw]=Ikilativiya
+Name[se]=Látviagiella
+Name[sk]=lotyština
+Name[sl]=latvijsko
+Name[sq]=Latvisht
+Name[sr]=ЛатвијÑки
+Name[sr@Latn]=Latvijski
+Name[ss]=Si-Latvian
+Name[sv]=Lettiska
+Name[ta]=இலடà¯à®µà®¿à®¯à®©à¯
+Name[te]=లాటివà±à°¯à°¨à±
+Name[tg]=ЛатвиÑгӣ
+Name[th]=ภาษาลัทเวีย
+Name[tr]=Litvanya Dili
+Name[tt]=Latça
+Name[uk]=ЛатвійÑька
+Name[uz]=Latishcha
+Name[uz@cyrillic]=Латишча
+Name[vi]=Lát-vi-a
+Name[wa]=Letonyin
+Name[xh]=Isilatvian
+Name[zh_CN]=拉脱维亚语
+Name[zh_HK]=拉脫維亞語
+Name[zh_TW]=拉脫維亞語
+Name[zu]=Isi-Latvian
+[mg]
+Name=Malagasy
+Name[az]=MalaqasicÉ™
+Name[be]=МалагаÑійÑкаÑ
+Name[bg]=Малагашки
+Name[bn]=মালাগাসি
+Name[br]=Malagacheg
+Name[ca]=Malgaix
+Name[csb]=Madagarsczi
+Name[de]=Madagassisch
+Name[el]=Μαλγασικά
+Name[eo]=Malagasa
+Name[es]=Malagasio
+Name[et]=Malagassi
+Name[eu]=Madagaskarera
+Name[fa]=مالاگازی
+Name[fi]=Malagasi
+Name[fr]=Malgache
+Name[fy]=Malagasysk
+Name[ga]=Malagásais
+Name[gl]=Kanu
+Name[he]=מלגשית
+Name[hi]=मलागासी
+Name[hr]=Malagaski
+Name[hu]=Malagazi
+Name[id]=Malagasi
+Name[it]=Malgascio
+Name[ja]=マラガシ語
+Name[ka]=მáƒáƒšáƒáƒ’áƒáƒ¡áƒ£áƒ áƒ˜
+Name[kk]=Мальгашша
+Name[km]=ម៉ាដាហ្កាសការ
+Name[ko]=ë§ë¼ê°€ì‹œì–´
+Name[lb]=Madagassesch
+Name[lt]=Malagasių
+Name[lv]=Malagasu
+Name[mk]=МалагаÑи
+Name[mn]=МалагаÑу
+Name[nds]=Madagass'sch
+Name[ne]=मालागासे
+Name[nn]=Gassisk
+Name[nso]=Se-Malagasy
+Name[pa]=ਮਾਲਾਗਾਸਆ
+Name[pl]=Madagaskarski
+Name[pt]=Malgaxe
+Name[ro]=Malgaşă
+Name[ru]=МальгашÑкий
+Name[rw]=Ikimaragasi
+Name[se]=Malagasigiella
+Name[sk]=malgaština
+Name[sl]=malagaško
+Name[sq]=Malagasisht
+Name[sr]=МалагаÑки
+Name[sr@Latn]=Malagaski
+Name[ss]=Si-Malagasy
+Name[sv]=Malagassiska
+Name[ta]=மலகாசி
+Name[te]=మలగాసి
+Name[tg]=МалагаÑÓ£
+Name[th]=ภาษามาลาà¸à¸²à¸‹à¸µ
+Name[tt]=Malagasça
+Name[uk]=МалайÑька
+Name[uz]=Malagasi
+Name[uz@cyrillic]=МалагаÑи
+Name[vi]=Ma-la-ga-xị
+Name[wa]=Malgache
+Name[zh_CN]=马尔加什语
+Name[zh_HK]=馬拉加西語
+Name[zh_TW]=馬拉加西語
+Name[zu]=Isi-Malagasy
+[mh]
+Name=Marshallese
+Name[ar]=المارشالية
+Name[az]=MarÅŸallca
+Name[be]=МаршальÑкаÑ
+Name[bg]=Ебон
+Name[bn]=মারà§à¦¶à¦¾à¦²à¦¿à¦¸
+Name[br]=Yezh an enez Marshall
+Name[bs]=Maršalski
+Name[ca]=Marshallès
+Name[cs]=Marshallský
+Name[csb]=z Òstrowów Marshalla
+Name[cy]=Marshalleg
+Name[da]=Marshallesisk
+Name[de]=Marshallisch
+Name[eo]=MarÅala
+Name[es]=Marshalés
+Name[et]=Maršalli
+Name[eu]=Marshallera
+Name[fa]=مارشالی
+Name[fi]=Marshall
+Name[fr]=Marshall
+Name[fy]=Marshalleesk
+Name[ga]=Marascailis
+Name[gl]=Marshalés
+Name[he]=מרשלית
+Name[hi]=मारà¥à¤¶à¤²à¥€à¤¸
+Name[hr]=Maršaleski
+Name[hsb]=Maršalezisce
+Name[hu]=Marsalli
+Name[is]=Maltneska
+Name[it]=Marshall, lingua delle isole
+Name[ja]=マーシャル語
+Name[ka]=მáƒáƒ áƒ¨áƒáƒšáƒ£áƒ áƒ˜
+Name[kk]=Маршаллша
+Name[km]=ម៉ាស្យលីស
+Name[lb]=Marschallesesch
+Name[lt]=MarÅ¡alieÄių
+Name[lv]=Maršaliešu
+Name[mk]=МаршалÑки
+Name[mn]=Маршалл
+Name[nb]=Marshallesisk
+Name[nds]=Marschalleesch
+Name[ne]=मारà¥à¤¶à¤¾à¤²à¤¿à¤¶
+Name[nl]=Marshallees
+Name[nn]=Marshallesisk
+Name[nso]=Se-Marshallese
+Name[pa]=ਮਾਰਸ਼ਲੀਈਸੀ
+Name[pl]=z Wysp Marshalla
+Name[pt]=Marselhês
+Name[ro]=Marşaleză
+Name[ru]=МаршалльÑкий
+Name[rw]=Ikimarishali
+Name[se]=Marshallagiella
+Name[sk]=marÅ¡alÄina
+Name[sl]=maršalsko
+Name[sq]=Marshalisht
+Name[sr]=МаршалеÑки
+Name[sr@Latn]=Maršaleski
+Name[ss]=Si-Marshallese
+Name[sv]=Marshall
+Name[ta]=மாரà¯à®·à®²à¯€à®¸à¯
+Name[te]=మారà±à°·à°²à±€à°¸à±
+Name[tg]=Маршалезӣ
+Name[th]=ภาษามาร์à¹à¸Šà¸¥à¸¥à¸µà¸ª
+Name[tt]=Marşallça
+Name[uk]=МаршальÑька
+Name[uz]=Marshallez
+Name[uz@cyrillic]=Маршаллез
+Name[vi]=Mă-xăn
+Name[wa]=Marshalès
+Name[zh_CN]=马ç»å°”语
+Name[zh_HK]=馬紹爾語
+Name[zh_TW]=馬紹爾語
+Name[zu]=Isi-Marshallese
+[mi]
+Name=Maori
+Name[ar]=الموري
+Name[az]=MaoricÉ™
+Name[be]=МаорÑкаÑ
+Name[bg]=Маори
+Name[bn]=মাওরি
+Name[br]=Maorieg
+Name[bs]=Maorski
+Name[cs]=Maorský
+Name[csb]=Maòrëjsczi
+Name[el]=ΜαοÏί
+Name[eo]=Maoria
+Name[es]=Maorí
+Name[et]=Maoori
+Name[eu]=Maoria
+Name[fa]=مائوری
+Name[ga]=Maorais
+Name[he]=מ×ורית
+Name[hi]=माओरी
+Name[hsb]=Maorisce
+Name[ja]=マオリ語
+Name[ka]=მáƒáƒáƒ áƒ˜
+Name[kk]=Маори
+Name[km]=ម៉ោរី
+Name[ko]=마오리어
+Name[lb]=Maoresch
+Name[lt]=Maorių
+Name[lv]=Maoru
+Name[mi]=Reo Mäori
+Name[mk]=МаорÑки
+Name[mn]=Маори
+Name[ne]=माओरी
+Name[nso]=Se-Maori
+Name[oc]=Maòri
+Name[pa]=ਮਾਓਰੀ
+Name[pl]=Maoryjski
+Name[ro]=Maură
+Name[ru]=Маори
+Name[rw]=Ikimawori
+Name[se]=Maoragiella
+Name[sk]=maorÄina
+Name[sl]=maorsko
+Name[sq]=Maorisht
+Name[sr]=МаорÑки
+Name[sr@Latn]=Maorski
+Name[ss]=Si-Maori
+Name[sv]=Maoriska
+Name[ta]=மாவோரி
+Name[te]=మావొరి
+Name[tg]=Маори
+Name[th]=ภาษาเมารี
+Name[tr]=Maori Dili
+Name[tt]=Maoriça
+Name[uk]=Маорі
+Name[uz@cyrillic]=Маори
+Name[vi]=Mao-ri
+Name[wa]=Mawori
+Name[zh_CN]=毛利语
+Name[zh_HK]=毛利語
+Name[zh_TW]=毛利語
+Name[zu]=Isi-Maori
+[mk]
+Name=Macedonian
+Name[ar]=المقدونية
+Name[az]=Makedonca
+Name[be]=МакедонÑкаÑ
+Name[bg]=МакедонÑки
+Name[bn]=মাসিডোনীয়
+Name[br]=Makedoneg
+Name[bs]=Makedonski
+Name[ca]=Macedoni
+Name[cs]=Makedonský
+Name[csb]=Macedońsczi
+Name[cy]=Macedoneg
+Name[da]=Makedonisk
+Name[de]=Mazedonisch
+Name[el]=Σλαβομακεδονικά
+Name[eo]=Macedonia
+Name[es]=Macedonio
+Name[et]=Makedoonia
+Name[eu]=Mazedoniera
+Name[fa]=مقدونی
+Name[fi]=Makedonia
+Name[fr]=Macédonien
+Name[fy]=Masedoanysk
+Name[ga]=Macadóinis
+Name[gl]=Macedónio
+Name[he]=מקדונית
+Name[hi]=मकदूनियन
+Name[hr]=Makedonski
+Name[hsb]=Makedonsce
+Name[hu]=Macedón
+Name[id]=Masedonian
+Name[is]=Makedóníska
+Name[it]=Macedone
+Name[ja]=マケドニア語
+Name[ka]=მáƒáƒ™áƒ”დáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=Македонша
+Name[km]=ម៉ាសáŸážŠáž¼áž“ី
+Name[ko]=마케ë„니아어
+Name[lb]=Mazedonesch
+Name[lt]=MakedonieÄių
+Name[lv]=Maķedoniešu
+Name[mi]=Reo Makerönia
+Name[mk]=МакедонÑки
+Name[mn]=Макидон
+Name[ms]=Macedonia
+Name[mt]=Maċedonjan
+Name[nb]=Makedonsk
+Name[nds]=Makedoonsch
+Name[ne]=मà¥à¤¯à¤¾à¤¸à¥‡à¤¡à¥‹à¤¨à¤¿à¤¯à¤¨
+Name[nl]=Macedonisch
+Name[nn]=Makedonsk
+Name[nso]=Se-Macedonian
+Name[pa]=ਮੈਕਡੋਨੀਆ
+Name[pl]=Macedoński
+Name[pt]=Macedónio
+Name[pt_BR]=Macedoniano
+Name[ro]=Macedoneană
+Name[ru]=МакедонÑкий
+Name[rw]=Ikinyamacedoniya
+Name[se]=Makedoniagiella
+Name[sk]=macedónÄina
+Name[sl]=makedonsko
+Name[sq]=SllavoMaqedonisht
+Name[sr]=МакедонÑки
+Name[sr@Latn]=Makedonski
+Name[ss]=Si-Macedonian
+Name[sv]=Makedonska
+Name[ta]=மாசிடோனியனà¯
+Name[te]=మసిడొనియనà±
+Name[tg]=Мақдунӣ
+Name[th]=ภาษามาเซโดเนีย
+Name[tr]=Makedonca
+Name[tt]=Makedonça
+Name[uk]=МакедонÑька
+Name[uz]=Makedoniyacha
+Name[uz@cyrillic]=МакедониÑча
+Name[vi]=Ma-xê-đô-ni
+Name[wa]=Macedonyin
+Name[zh_CN]=马其顿语
+Name[zh_HK]=馬其頓語
+Name[zh_TW]=馬其頓語
+Name[zu]=Isi-Makhedoniya
+[ml]
+Name=Malayalam
+Name[ar]=المالايالام
+Name[az]=Malayamca
+Name[be]=МалаÑламÑкаÑ
+Name[bg]=МалаÑлам
+Name[bn]=মালয়লম
+Name[csb]=Drawidańsczi (hindusczi)
+Name[eo]=Malajalama
+Name[es]=Malayo
+Name[et]=Malajalami
+Name[fa]=مالی
+Name[fi]=Malajalam
+Name[ga]=Mailéalaimis
+Name[gl]=Malaialam
+Name[he]=מלי×ל××
+Name[hi]=मलयालम
+Name[hr]=Malajamski
+Name[hu]=Malajalam
+Name[it]=Kerala, lingua del
+Name[ja]=マラヤーラム語
+Name[ka]=მáƒáƒšáƒáƒ˜áƒšáƒáƒ›áƒ˜
+Name[kk]=Малайамша
+Name[km]=ម៉ាឡាយ៉ាឡាម
+Name[lb]=Malajalam
+Name[lt]=MalajieÄių
+Name[mk]=Малајалам
+Name[mn]=МалаÑлам
+Name[ne]=मलायालम
+Name[nso]=Se-Malayalam
+Name[pa]=ਮਲਿਆਲਮ
+Name[pl]=Drawidiański (Hinduski)
+Name[ro]=Malailamă
+Name[ru]=МалайÑлам
+Name[rw]=Ikimalayalamu
+Name[se]=Malajalamagiella
+Name[sk]=malajálamÄina
+Name[sl]=malayalam
+Name[sq]=Malajamisht
+Name[sr]=МалајамÑки
+Name[sr@Latn]=Malajamski
+Name[ss]=Si-Malayalam
+Name[ta]=மலையாளமà¯
+Name[te]=మలయాళం
+Name[tg]=МалаÑмӣ
+Name[th]=ภาษามะละยาลัง
+Name[uk]=МалайÑька
+Name[uz@cyrillic]=Малайалам
+Name[vi]=Ma-lay-am
+Name[zh_CN]=德拉维æ—语
+Name[zh_HK]=馬來亞拉姆語
+Name[zh_TW]=馬來亞拉姆語
+Name[zu]=Isi-Malayalam
+[mn]
+Name=Mongolian
+Name[af]=Mongolees
+Name[ar]=منغولية
+Name[az]=Monqolca
+Name[be]=МангольÑкаÑ
+Name[bg]=МонголÑки
+Name[bn]=মোঙà§à¦—ল
+Name[br]=Mongolieg
+Name[bs]=Mongolski
+Name[ca]=Mongol
+Name[cs]=Mongolský
+Name[csb]=Mòngolsczi
+Name[cy]=Mongoleg
+Name[da]=Mongolsk
+Name[de]=Mongolisch
+Name[el]=Μογγολικά
+Name[eo]=Mongola
+Name[es]=Mongol
+Name[et]=Mongoolia
+Name[eu]=Mongoliera
+Name[fa]=مغول
+Name[fi]=Mongoli
+Name[fr]=Mongol
+Name[fy]=Moangoalsk
+Name[ga]=Mongóilis
+Name[gl]=Mongol
+Name[he]=מונגולית
+Name[hi]=मंगोलियन
+Name[hr]=Mongolski
+Name[hsb]=Mongolsce
+Name[hu]=Mongol
+Name[id]=Mongolia
+Name[is]=Bosníska
+Name[it]=Mongolo
+Name[ja]=モンゴル語
+Name[ka]=მáƒáƒœáƒ¦áƒáƒšáƒ£áƒ áƒ˜
+Name[kk]=Моңғолша
+Name[km]=ម៉ុងហ្គោលី
+Name[ko]=몽골어
+Name[ku]=Mongolî
+Name[lb]=Mongolesch
+Name[lt]=Mongolų
+Name[lv]=Mongoļu
+Name[mk]=МонголÑки
+Name[mn]=Монгол
+Name[ms]=Mongolia
+Name[nb]=Mongolsk
+Name[nds]=Mongoolsch
+Name[ne]=मङà¥à¤—ोलियाली
+Name[nl]=Mongolisch
+Name[nn]=Mongolsk
+Name[nso]=Se-Mongolian
+Name[pa]=ਮੰਗੋਲੀਅਨ
+Name[pl]=Mongolski
+Name[pt]=Mongol
+Name[pt_BR]=Mongolês
+Name[ro]=Mongolă
+Name[ru]=МонгольÑкий
+Name[rw]=Ikinyamongoliya
+Name[se]=Mongoliagiella
+Name[sk]=mongolÄina
+Name[sl]=mongolsko
+Name[sq]=Mongolisht
+Name[sr]=МонголÑки
+Name[sr@Latn]=Mongolski
+Name[ss]=Si-Mongolian
+Name[sv]=Mongoliska
+Name[ta]=மொஙà¯à®•à¯‹à®²à®¿à®¯à®©à¯
+Name[te]=మంగోలియనà±
+Name[tg]=Муғулӣ
+Name[th]=ภาษามองโà¸à¸¥
+Name[tr]=Mongolca
+Name[tt]=Moğolça
+Name[uk]=МонгольÑька
+Name[uz]=Mugʻulcha
+Name[uz@cyrillic]=Муғулча
+Name[vi]=Mông-cổ
+Name[wa]=Mongol
+Name[zh_CN]=è’™å¤è¯­
+Name[zh_HK]=è’™å¤èªž
+Name[zh_TW]=è’™å¤èªž
+Name[zu]=Isi-Mongolian
+[mo]
+Name=Moldavian
+Name[ar]=مولدوÙية
+Name[az]=Moldavca
+Name[be]=МалдаўÑкаÑ
+Name[bg]=МолдовÑки
+Name[bn]=মলডেভীয়
+Name[br]=Moldaveg
+Name[bs]=Moldavski
+Name[ca]=Moldau
+Name[cs]=Moldavský
+Name[csb]=Mòłdawsczi
+Name[cy]=Moldafeg
+Name[da]=Moldovisk
+Name[de]=Moldawisch
+Name[el]=Μολδαβικά
+Name[eo]=Moldava
+Name[es]=Moldavo
+Name[et]=Moldaavia
+Name[eu]=Moldabiera
+Name[fa]=مولداوی
+Name[fi]=Moldavia
+Name[fr]=Moldave
+Name[fy]=Moldavysk
+Name[ga]=Moldávais
+Name[gl]=Moldavo
+Name[he]=מולדבית
+Name[hi]=मोलà¥à¤¦à¤¾à¤µà¤¿à¤¯à¤¨
+Name[hr]=Moldavski
+Name[hsb]=Moldawisce
+Name[hu]=Moldáv
+Name[id]=Moldavia
+Name[is]=Moldóvíska
+Name[it]=Moldavo
+Name[ja]=モルダビア語
+Name[ka]=მáƒáƒšáƒ“áƒáƒ•áƒ£áƒ áƒ˜
+Name[kk]=Молдовша
+Name[km]=ម៉ុលដាវី
+Name[ko]=몰다비어
+Name[lb]=Moldawesch
+Name[lt]=Moldavų
+Name[lv]=MoldÄvu
+Name[mk]=МолдавÑки
+Name[mn]=Молдав
+Name[ms]=Moldavia
+Name[nb]=Moldavisk
+Name[nds]=Moldaawsch
+Name[ne]=मोलà¥à¤¡à¤¾à¤­à¤¿à¤¯à¤¨
+Name[nl]=Moldavisch
+Name[nn]=Moldovsk
+Name[nso]=Se-Moldavian
+Name[pa]=ਮੋਲਡਾਵੀਅਨ
+Name[pl]=Mołdawski
+Name[pt]=Moldavo
+Name[pt_BR]=Moldaviano
+Name[ro]=Moldovenească
+Name[ru]=МолдавÑкий
+Name[rw]=Ikinyamoludavi
+Name[se]=Moldáviagiella
+Name[sk]=moldavÄina
+Name[sl]=moldavsko
+Name[sq]=Moldavisht
+Name[sr]=МолдавÑки
+Name[sr@Latn]=Moldavski
+Name[ss]=Si-Moldavian
+Name[sv]=Moldaviska
+Name[ta]=மோலà¯à®Ÿà¯‹à®µà®¿à®¯à®©à¯
+Name[te]=మొలà±à°¦à°¾à°µà°¿à°¯à°¨à±
+Name[tg]=Молдаванӣ
+Name[th]=ภาษามอลดาเวียน
+Name[tr]=Moldavaca
+Name[tt]=Moldavça
+Name[uk]=МолдовÑька
+Name[uz]=Moldavcha
+Name[uz@cyrillic]=Молдавча
+Name[vi]=Mon-Ä‘a-vi
+Name[wa]=Moldåve
+Name[zh_CN]=摩尔多瓦
+Name[zh_HK]=摩爾é”維亞語
+Name[zh_TW]=摩爾é”維亞語
+Name[zu]=Isi-Moldavian
+[mr]
+Name=Marathi
+Name[ar]=الماراثي
+Name[az]=MaraticÉ™
+Name[be]=МараўÑкаÑ
+Name[bg]=Маратхи
+Name[bn]=মরাঠী
+Name[br]=Marateg
+Name[csb]=Marathi (hindusczi)
+Name[eo]=Marata
+Name[es]=Maratí
+Name[eu]=Marathera
+Name[fa]=ماراتی
+Name[fr]=Marathe
+Name[ga]=Maraitis
+Name[gl]=Marata
+Name[he]=מ×ר×תי
+Name[hi]=मराठी
+Name[hsb]=Marati
+Name[hu]=Marati
+Name[ja]=マラーティー語
+Name[ka]=მáƒáƒ áƒáƒ—ი
+Name[kk]=Марати
+Name[km]=ម៉ារាធី
+Name[ko]=마ë¼í‹°ì–´
+Name[lv]=Maratu
+Name[mk]=Марати
+Name[mn]=Марати
+Name[ne]=मराठी
+Name[nso]=Se-Marathi
+Name[pa]=ਮਰਾਠੀ
+Name[pl]=Marathi (Hinduski)
+Name[ru]=Марати
+Name[rw]=Ikimarati
+Name[se]=Marathagiella
+Name[sk]=maráthÄina
+Name[sl]=marathi
+Name[sq]=Maratisht
+Name[sr]=МаратÑки
+Name[sr@Latn]=Maratski
+Name[ss]=Si-Marathi
+Name[ta]=மராதà¯à®¤à®¿
+Name[te]=మరాఠి
+Name[tg]=Маравӣ
+Name[th]=ภาษามราà¸à¸µ
+Name[tt]=Maratça
+Name[uk]=Мараті
+Name[uz]=Marati
+Name[uz@cyrillic]=Марати
+Name[vi]=Ma-ra-ti
+Name[wa]=Marati
+Name[zh_CN]=马拉地语
+Name[zh_HK]=馬拉地語
+Name[zh_TW]=馬拉地語
+Name[zu]=Isi-Marathi
+[ms]
+Name=Malay
+Name[ar]=مالاوية
+Name[az]=Malayca
+Name[be]=МалайÑкаÑ
+Name[bg]=МалайÑки
+Name[bn]=মালয়
+Name[br]=Maya
+Name[bs]=Malajski
+Name[ca]=Malai
+Name[cs]=Malajský
+Name[csb]=Malajsczi
+Name[de]=Malaiisch
+Name[eo]=Malaja
+Name[es]=Malayo
+Name[et]=Malaisia
+Name[eu]=Malaysiera
+Name[fa]=مالی
+Name[fi]=Malaiji
+Name[fr]=Malais
+Name[fy]=Maleisk
+Name[ga]=Malaeis
+Name[gl]=Malaio
+Name[he]=מל×ית
+Name[hi]=मलय
+Name[hr]=Malajski
+Name[hsb]=Malajsce
+Name[hu]=Maláj
+Name[id]=Melayu
+Name[it]=Malese
+Name[ja]=マレー語
+Name[ka]=მáƒáƒšáƒáƒ£áƒ áƒ˜
+Name[kk]=Малайша
+Name[km]=ម៉ាឡáŸážŸáŸŠáž¸
+Name[ko]=ë§ë ˆì´ì–´
+Name[ku]=Malayî
+Name[lb]=Malaiesch
+Name[lt]=Malajų
+Name[lv]=Malajiešu
+Name[mk]=МалајÑки
+Name[mn]=МалÑ
+Name[nb]=Malaiisk
+Name[nds]=Malaiisch
+Name[ne]=मले
+Name[nn]=Malayisk
+Name[nso]=Se-Malay
+Name[pa]=ਮਾਲਿਆ
+Name[pl]=Malajski
+Name[pt]=Malaio
+Name[pt_BR]=Malaiano
+Name[ro]=Malaeză
+Name[ru]=МалайÑкий
+Name[rw]=Ikimalayi
+Name[se]=Malaigiella
+Name[sk]=malajálamÄina
+Name[sl]=malajsko
+Name[sq]=Malanisht
+Name[sr]=МалајÑки
+Name[sr@Latn]=Malajski
+Name[ss]=Si-Malay
+Name[sv]=Malajiska
+Name[ta]=மலாயà¯
+Name[te]=మలయ
+Name[tg]=Малайӣ
+Name[th]=ภาษามาเลย์
+Name[tt]=Malayça
+Name[uk]=МалайÑька
+Name[uz]=Malaycha
+Name[uz@cyrillic]=Малайча
+Name[vi]=Mã-lai
+Name[zh_CN]=马æ¥è¥¿äºšè¯­
+Name[zh_HK]=馬來語
+Name[zh_TW]=馬來語
+Name[zu]=Isi-Malay
+[mt]
+Name=Maltese
+Name[af]=Maltees
+Name[ar]=المالطية
+Name[az]=Maltaca
+Name[be]=МальтыйÑкаÑ
+Name[bg]=МалтийÑки
+Name[bn]=মলà§à¦Ÿà¦¿à¦¸
+Name[br]=Malteg
+Name[bs]=Malteški
+Name[ca]=Maltès
+Name[cs]=Maltézský
+Name[csb]=Maltajsczi
+Name[cy]=Malteg
+Name[da]=Maltesisk
+Name[de]=Maltesisch
+Name[el]=Μαλτέζικα
+Name[eo]=Malta
+Name[es]=Maltés
+Name[et]=Malta
+Name[eu]=Maltera
+Name[fa]=مالتز
+Name[fi]=Malta
+Name[fr]=Maltais
+Name[fy]=Malteesk
+Name[ga]=Máltais
+Name[gl]=Maltés
+Name[he]=מלטזית
+Name[hi]=मालà¥à¤Ÿà¥€à¤¸
+Name[hr]=Malteški
+Name[hsb]=Maltisce
+Name[hu]=Máltai
+Name[id]=Malta
+Name[is]=Maltneska
+Name[ja]=マルタ語
+Name[ka]=მáƒáƒšáƒ¢áƒ£áƒ áƒ˜
+Name[kk]=Мальташа
+Name[km]=ម៉ាល់ážáž¶
+Name[ko]=몰타어
+Name[ku]=Maltayî
+Name[lb]=Maltesesch
+Name[lt]=MaltieÄių
+Name[lv]=Maltiešu
+Name[mk]=Малтешки
+Name[mn]=Малт
+Name[mt]=Malti
+Name[nb]=Maltesisk
+Name[nds]=Malteesch
+Name[ne]=मालà¥à¤¤à¥‡à¤¸à¥€
+Name[nl]=Maltees
+Name[nn]=Maltesisk
+Name[nso]=Se-Maltese
+Name[pa]=ਮਾਲਟੀਸੀ
+Name[pl]=Maltański
+Name[pt]=Maltês
+Name[pt_BR]=Maltês
+Name[ro]=Malteză
+Name[ru]=МальтийÑкий
+Name[rw]=Ikinyamalite
+Name[se]=Maltagiella
+Name[sk]=maltÄina
+Name[sl]=maltežansko
+Name[sq]=Maltezisht
+Name[sr]=Малтешки
+Name[sr@Latn]=Malteški
+Name[ss]=Si-Maltese
+Name[sv]=Maltesiska
+Name[ta]=மாலà¯à®Ÿà¯€à®šà®¿à®¯
+Name[te]=మాలà±à°Ÿà±€à°¸à±
+Name[tg]=МалтеÑÓ£
+Name[th]=ภาษามอลตีส
+Name[tr]=Malta Dili
+Name[tt]=Maltesçä
+Name[uk]=МальтійÑька
+Name[uz]=Maltacha
+Name[uz@cyrillic]=Малтача
+Name[vi]=Man-tợ
+Name[wa]=Maltès
+Name[zh_CN]=马耳他语
+Name[zh_HK]=馬爾他語
+Name[zh_TW]=馬爾他語
+Name[zu]=Isi-Maltase
+[my]
+Name=Burmese
+Name[af]=Burmees
+Name[ar]=بورمي
+Name[az]=Burmaca
+Name[be]=БурмеÑкаÑ
+Name[bg]=БирманÑки
+Name[bn]=বরà§à¦®à§€
+Name[br]=Birmaneg
+Name[bs]=Burmanski
+Name[ca]=Burmès
+Name[cs]=Burmský
+Name[csb]=Birmańsczi
+Name[cy]=Burmeg
+Name[de]=Burmesisch
+Name[el]=ΒιÏμανικά
+Name[eo]=Birma
+Name[es]=Burmés
+Name[et]=Birma
+Name[eu]=Birmaniera
+Name[fa]=برمس
+Name[fi]=Burma
+Name[fr]=Birman
+Name[fy]=Burmeesk
+Name[ga]=Burmais
+Name[gl]=Burmés
+Name[he]=בורמזית
+Name[hi]=बरà¥à¤®à¥€à¤¸
+Name[hr]=Burmanski
+Name[hsb]=Burmezisce
+Name[hu]=Burmai
+Name[id]=Burma
+Name[is]=Búrmenska
+Name[it]=Birmano
+Name[ja]=ビルマ語
+Name[ka]=ბირმული
+Name[kk]=Бирманша
+Name[km]=ភូមា
+Name[ko]=버마어
+Name[lb]=Burmesesch
+Name[lt]=BirmieÄių
+Name[lv]=Birmiešu
+Name[mk]=БурманÑки
+Name[mn]=Бүрм
+Name[ms]=Burma
+Name[nb]=Burmesisk
+Name[nds]=Burmeesch
+Name[ne]=बरà¥à¤®à¥‡à¤²à¥€
+Name[nl]=Burmees
+Name[nn]=Burmesisk
+Name[nso]=Se-Burmese
+Name[pa]=ਬà©à¨°à¨®à©€à¨¸à©€
+Name[pl]=Birmański
+Name[pt]=Birmanês
+Name[ro]=Burmeză
+Name[ru]=БирманÑкий
+Name[rw]=Ikibarumi
+Name[se]=Burmagiella
+Name[sk]=barmÄina
+Name[sl]=burmansko
+Name[sq]=Burmesisht
+Name[sr]=БурманÑки
+Name[sr@Latn]=Burmanski
+Name[ss]=Si-Burmese
+Name[sv]=Burmesiska
+Name[ta]=பரà¯à®®à®¿à®¯
+Name[te]=బరà±à°®à±€à°¸à±
+Name[tg]=Бурмезӣ
+Name[th]=ภาษาพม่า
+Name[tt]=Burmesçä
+Name[uk]=БірманÑька
+Name[uz]=Burmezcha
+Name[uz@cyrillic]=Бурмезча
+Name[vi]=Miến-điện
+Name[zh_CN]=缅甸语
+Name[zh_HK]=緬甸語
+Name[zh_TW]=緬甸語
+Name[zu]=Isi-Burmese
+[na]
+Name=Nauru
+Name[ar]=الناورو
+Name[az]=Nauruca
+Name[be]=ÐаурÑкі
+Name[bg]=Ðауру
+Name[bn]=নাউরà§
+Name[br]=Naurueg
+Name[de]=Nauruisch
+Name[el]=ÎαουÏοÏ
+Name[eo]=Naura
+Name[eu]=Nauruera
+Name[fa]=نائورو
+Name[fr]=Nauruan
+Name[fy]=Naurûaansk
+Name[ga]=Nárúis
+Name[he]=× ×ורו
+Name[hi]=नौरू
+Name[ja]=ナウル語
+Name[ka]=ნáƒáƒ£áƒ áƒ£
+Name[kk]=Ðауру
+Name[km]=ណូរុ
+Name[ko]=나우루
+Name[lb]=Nauruesch
+Name[mk]=Ðауру
+Name[mn]=Ðауру
+Name[ne]=नाउरू
+Name[nso]=Se-Nauru
+Name[pa]=ਨਾਉਰੂ
+Name[ro]=Naură
+Name[ru]=Ðауру
+Name[rw]=Ikinawuru
+Name[se]=Naurugiella
+Name[sk]=nauruština
+Name[sl]=nauru
+Name[sq]=Naurisht
+Name[sr]=ÐаурÑки
+Name[sr@Latn]=Naurski
+Name[ss]=Si-Nauru
+Name[ta]=நவà¯à®°à¯
+Name[te]=నౌరà±
+Name[tg]=Ðауру
+Name[th]=ภาษานาอุรุ
+Name[uk]=Ðауру
+Name[uz@cyrillic]=Ðауру
+Name[vi]=Nau-ru
+Name[wa]=Nawouro
+Name[zh_CN]=ç‘™é²è¯­
+Name[zh_HK]=諾魯語
+Name[zh_TW]=諾魯語
+Name[zu]=Isi-Nauru
+[nb]
+Name=Norwegian Bokmål
+Name[ar]=بوكماال النرويجية
+Name[az]=Norveçcə (Bokmål)
+Name[be]=ÐарвежÑÐºÐ°Ñ (бокмаль)
+Name[bg]=Ðорвежки (букмол)
+Name[bn]=নরওয়েজীয় বোকমাল
+Name[br]=Norvegeg Bokmål
+Name[bs]=Norveški Bokmål
+Name[ca]=Noruec Bokmål
+Name[cs]=Norský (Bokmål)
+Name[csb]=Norwesczi Bokmål
+Name[cy]=Bokmal Norwyeg
+Name[da]=Norsk bokmål
+Name[de]=Norwegisch (Bokmål)
+Name[el]=ÎοÏβηγικά BokmÃ¥l
+Name[eo]=Norvega (Bokmal)
+Name[es]=Noruego Bokmål
+Name[et]=Norra bokmål
+Name[eu]=Norvegiera (Bokmål)
+Name[fa]=نروژی بوکمال
+Name[fi]=Norja (bokmål)
+Name[fr]=Norvégien Bokmaal
+Name[fy]=Noarsk, Bokmål
+Name[ga]=Ioruais (Bokmål)
+Name[gl]=Noruegués (Bokmaal)
+Name[he]=נורבגית Bokmål
+Name[hi]=नारà¥à¤µà¥‡à¤œà¤¿à¤¯à¤¨ बोकमॉल
+Name[hr]=Norveški Bokmål
+Name[hsb]=Norwegsce (Bokmål)
+Name[hu]=Norvég (bokmal)
+Name[is]=Norska (bókmál)
+Name[it]=Norvegese Bokmål
+Name[ja]=ノルウェー語 (ブークモール)
+Name[ka]=ნáƒáƒ áƒ•áƒ”გიული (ბიáƒáƒ™áƒ›áƒáƒšáƒ˜)
+Name[kk]=Ðорвег букмалша
+Name[km]=áž“áŸážšážœáŸ‚ស បុកម៉ាល់
+Name[ko]=노르웨ì´ì–´ (Bokmaal)
+Name[lb]=Norwegesch (Bokmål)
+Name[lt]=Norvegų Bokmål
+Name[lv]=NorvÄ“Ä£u (BokmÄlas)
+Name[mk]=Ðорвешки BokmÃ¥l
+Name[mn]=Ðорвеги, Бокмал
+Name[nb]=Norsk, bokmål
+Name[nds]=Norweegsch (Bokmål)
+Name[ne]=नरà¥à¤µà¥‡à¤²à¥€ बोकमल
+Name[nl]=Noors Bokmål
+Name[nn]=Norsk bokmål
+Name[nso]=Se-Norwegian Bokmål
+Name[pa]=ਨੋਰਵਿਗੀਆਨ ਬੋਕਮਾਲ
+Name[pl]=Norweski Bokmaal
+Name[pt]=Norueguês Bokmål
+Name[pt_BR]=Norueguês (Bokmaal)
+Name[ro]=Norvegiană Bokmål
+Name[ru]=ÐорвежÑкий (литературный)
+Name[rw]=Ikibokumali nyanoruveje
+Name[se]=Girjedárogiella
+Name[sk]=nórsky bokmål
+Name[sl]=norveško (bokmaal)
+Name[sr]=Ðорвешки (БокмалÑки)
+Name[sr@Latn]=Norveški (Bokmalski)
+Name[ss]=Si-Norwegian Bokmål
+Name[sv]=Norskt bokmål
+Name[ta]=நாரà¯à®µà¯€à®œà®¿à®¯à®©à¯ பொகà¯à®®à®¾à®²à¯
+Name[te]=నారà±à°µà±€à°œà°¿à°¯à°¨à± బోకà±à°®à°¾à°²à±
+Name[tg]=ÐорвегиÑгӣ Боқмал
+Name[th]=ภาษานอร์เวย์ (บ็อคมัล)
+Name[tr]=Norveççe Bokmål
+Name[tt]=Norvegçä (ädäbi)
+Name[uk]=Ðорвезька (BokmÃ¥l)
+Name[uz]=Norvegcha (Bokmaal)
+Name[uz@cyrillic]=Ðорвегча (Бокмаал)
+Name[vi]=Na-uy (Bóc-mặn)
+Name[wa]=Norvedjyin (Bokmål)
+Name[zh_CN]=挪å¨è¯­ (åšå…‹é©¬å°”语)
+Name[zh_TW]=æŒªå¨ BokmÃ¥l
+Name[zu]=Isi-Norwegian Bokmaal
+[nd]
+Name=Ndebele, North
+Name[af]=Ndebele, Noord
+Name[ar]=النديبيلي الشمالية
+Name[az]=Ndebele, Åžimal
+Name[be]=ÐдÑбель (поўнач)
+Name[bg]=Северен Ðдебеле
+Name[bn]=নà§â€Œà¦¦à§‡à¦¬à§‡à¦²à§‡, উতà§à¦¤à¦°
+Name[br]=Ndebele, Norzh
+Name[bs]=Ndebele, Sjeverni
+Name[ca]=Ndebele, Nord
+Name[cs]=Ndebele, Severní
+Name[csb]=Ndebele, Norda
+Name[cy]=Ndebele, Gogledd
+Name[da]=Ndebele, nord
+Name[de]=Ndebele (nördliches)
+Name[eo]=Norda Ndebele
+Name[es]=Ndebele del norte
+Name[et]=Põhja-ndebele
+Name[eu]=Ndebelera (iparraldekoa)
+Name[fa]=اندبل شمالی
+Name[fi]=Ndebele, Pohjoinen
+Name[fr]=Ndébélé du Nord
+Name[fy]=Ndebele, Noard
+Name[ga]=Ndebele Thuaidh
+Name[gl]=Ndebele do norte
+Name[he]=נדבלה צפונית
+Name[hi]=नेदेबेले, उतà¥à¤¤à¤°
+Name[hr]=Ndebele, Sjeverni
+Name[hsb]=Ndebele, Sewjerne
+Name[hu]=Ndebele (északi)
+Name[id]=Ndebele, Utara
+Name[is]=Ndebele, norður
+Name[it]=Ndebele settentrionale
+Name[ja]=北ンデベレ語
+Name[ka]=ჩრდილრნდებელე
+Name[kk]=СолтүÑік Ðдебеле
+Name[km]=នដិបិលិ​ážáž¶áž„​ជើង
+Name[ko]=ë¶ë¶€ ì€ë°ë²¨ë ˆ
+Name[lb]=Ndebele (nördlech)
+Name[lt]=Ndebele, Å iaurÄ—s
+Name[mk]=Ðдебеле, Ñеверен
+Name[mn]=ÐдÑбÑлÑ, умард
+Name[nb]=Ndebele, Nord
+Name[nds]=Ndebele, Noord
+Name[ne]=डेबेले, उतà¥à¤¤à¤°
+Name[nl]=Ndebele, Noord
+Name[nn]=Ndebele, nord
+Name[nso]=Se-Ndebele, sa Lebowa
+Name[pa]=ਨਡੀਬੀਲੀ, ਉੱਤਰੀ
+Name[pl]=Ndebele, Północ
+Name[pt]=Ndebele do Norte
+Name[pt_BR]=Ndebele, Norte
+Name[ro]=Ndebelă nordică
+Name[ru]=Сев. Ðдебеле
+Name[rw]=Ikindebele, amajyaruguru
+Name[se]=Ndebelegiella, davvi
+Name[sk]=severná ndebelÄina
+Name[sl]=ndebele, severno
+Name[sq]=Nbedelisht të Veriut
+Name[sr]=Ðдебеле, Северни
+Name[sr@Latn]=Ndebele, Severni
+Name[ss]=SiNdebele, sasenyakatfo
+Name[sv]=Nordndebele
+Name[ta]=டெபெலே, வட
+Name[te]=నెబేలె, ఉతà±à°¤à°°
+Name[tg]=Ðдебелӣ, Шимол
+Name[th]=ภาษาอึนเดเบเล ตอนเหนือ
+Name[tt]=Ndebeleçä, Tönyaq
+Name[uk]=Ðдебелє, Північна
+Name[uz]=Ndebele, Shimol
+Name[uz@cyrillic]=Ðдебеле, Шимол
+Name[ven]=Ndebele, Devhula
+Name[vi]=N-đe-be-lê (Bắc)
+Name[wa]=Ndebele (bijhe)
+Name[xh]=Isindebele, Emntla
+Name[zh_CN]=Ndebele,北部
+Name[zh_HK]=Ndebele語,北部
+Name[zh_TW]=Ndebele語,北部
+Name[zu]=Isi-Ndebele, Sase-Ntshonalanga
+[nds]
+Name=Low Saxon
+Name[af]=Lae Saxon
+Name[be]=ÐіжнеÑакÑонÑкаÑ
+Name[bg]=ДолноÑакÑонÑки
+Name[bn]=নিমà§à¦¨ সà§à¦¯à¦¾à¦•à§à¦¸à¦¨
+Name[br]=Saozeg izel
+Name[bs]=Niži saksonski
+Name[ca]=Baix saxó
+Name[cs]=Dolnosaský
+Name[csb]=Dolnosaksońsczi
+Name[cy]=Sacsoneg Isel
+Name[da]=Nedersaksisk
+Name[de]=Niederdeutsch
+Name[eo]=Malsupra Saksa
+Name[es]=Sajón bajo
+Name[et]=Alamsaksi
+Name[eu]=Beheko Sajoniera
+Name[fa]=ساکسونی سÙÙ„ÛŒ
+Name[fi]=Alasaksa
+Name[fr]=Bas saxon (ou francique, ou plattdeutsch)
+Name[fy]=Neder Saksysk
+Name[ga]=Sacsainis Ãochtarach
+Name[gl]=Baixo Saxón
+Name[hi]=लो सेकà¥à¤¸à¤¨
+Name[hr]=Donjosaksonski
+Name[hsb]=Delnjosaksce
+Name[hu]=Alsószász
+Name[it]=Basso sassone
+Name[ja]=低ザクセン語
+Name[ka]=ქვედრსáƒáƒ¥áƒ¡áƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=Төмен ÑакÑонша
+Name[km]=ឡូសាក់សុង
+Name[ku]=Saksonî ya Jêrîn
+Name[lb]=Niddersächsesch
+Name[lt]=Žemutinių saksonų
+Name[lv]=Lejas sakšu
+Name[mk]=ДолноÑакÑонÑки
+Name[nb]=Lavgermansk
+Name[nds]=Plattdüütsch
+Name[ne]=लो साकà¥à¤¸à¥‹à¤¨
+Name[nl]=Nedersaksisch
+Name[nn]=LÃ¥ggermansk
+Name[pa]=ਲੋਅ ਸਾਕੋਨ
+Name[pl]=Dolnosaksoński
+Name[pt]=Baixo-Saxão
+Name[pt_BR]=Baixa Saxonia
+Name[ro]=Saxona de Jos
+Name[ru]=ÐижнеÑакÑонÑкий
+Name[rw]=Igisagisoni cyo hasi
+Name[se]=Vuolil Sáksonagiella
+Name[sk]=dolná saština
+Name[sl]=spodnjesaško
+Name[sr]=Доњи ÑакÑонÑки
+Name[sr@Latn]=Donji saksonski
+Name[sv]=LÃ¥gsaxiska
+Name[ta]=லோ சாகà¯à®¸à®¾à®©à¯
+Name[te]=లో సాకà±à°¸à°¨à±
+Name[tg]=СакÑон
+Name[th]=ภาษาเยอรมัน ระดับล่าง
+Name[tr]=Aşağı Sakson
+Name[tt]=Saksonça, Asqı
+Name[uk]=ÐижньоÑакÑонÑька
+Name[uz]=Past Saksoncha
+Name[uz@cyrillic]=ПаÑÑ‚ СакÑонча
+Name[vi]=Xác-xá»nh thấp
+Name[wa]=Bas sacson
+Name[zh_CN]=撒克逊语
+Name[zh_TW]=è–©å…‹éœèªž
+[ne]
+Name=Nepali
+Name[ar]=نيبالي
+Name[az]=Nepalca
+Name[be]=ÐепальÑкаÑ
+Name[bg]=Ðепали
+Name[bn]=নেপালী
+Name[br]=Nepaleg
+Name[bs]=Nepalski
+Name[ca]=Nepalí
+Name[cs]=Nepálský
+Name[csb]=Nepalsczi
+Name[de]=Nepalesisch
+Name[eo]=Nepala
+Name[es]=Nepalí
+Name[et]=Nepaali
+Name[eu]=Nepalera
+Name[fa]=نپالی
+Name[fr]=Népalais
+Name[fy]=Nepaleesk
+Name[ga]=Neipealais
+Name[he]=נפ×לית
+Name[hi]=नेपाली
+Name[hr]=Nepalski
+Name[hsb]=Nepalezisce
+Name[hu]=Nepáli
+Name[id]=Nepal
+Name[it]=Nepalese
+Name[ja]=ãƒãƒ‘ール語
+Name[ka]=ნეპáƒáƒšáƒ£áƒ áƒ˜
+Name[kk]=Ðепалша
+Name[km]=áž“áŸáž”៉ាល់
+Name[ko]=네팔어
+Name[ku]=Nepalî
+Name[lb]=Nepalesesch
+Name[lt]=NepalieÄių
+Name[lv]=NepÄlieÅ¡u
+Name[mk]=ÐепалÑки
+Name[mn]=Ðепал
+Name[nds]=Nepaleesch
+Name[ne]=नेपाली
+Name[nl]=Nepalees
+Name[nn]=Nepalsk
+Name[nso]=Se-Nepali
+Name[pa]=ਨੇਪਾਲੀ
+Name[pl]=Nepalski
+Name[pt]=Nepalês
+Name[ro]=Nepaleză
+Name[ru]=ÐепальÑкий
+Name[rw]=Ikinyanepale
+Name[se]=Nepálagiella
+Name[sk]=nepálÄina
+Name[sl]=nepalsko
+Name[sq]=Nepalisht
+Name[sr]=ÐепалÑки
+Name[sr@Latn]=Nepalski
+Name[ss]=SiNepali
+Name[ta]=நேபாளி
+Name[te]=నేపాలి
+Name[tg]=Ðепалӣ
+Name[th]=ภาษาเนปาล
+Name[tr]=Nepalce
+Name[tt]=Nepalça
+Name[uk]=ÐепальÑька
+Name[uz]=Nepalcha
+Name[uz@cyrillic]=Ðепалча
+Name[vi]=Ne-pa-li
+Name[wa]=Nepalès
+Name[zh_CN]=尼泊尔语
+Name[zh_HK]=尼泊爾語
+Name[zh_TW]=尼泊爾語
+Name[zu]=Isi-Nepali
+[ng]
+Name=Ndonga
+Name[ar]=الندونغا
+Name[be]=Ðдонга
+Name[bg]=Ðдонга
+Name[bn]=নডোঙà§à¦—া
+Name[de]=Oshivambo
+Name[fa]=اندونگا
+Name[ga]=Ndongais
+Name[he]=נדונגה
+Name[hi]=नदोनà¥à¤—ा
+Name[ja]=ンドゥンガ語
+Name[ka]=ნდáƒáƒœáƒ’áƒ
+Name[kk]=Ðдонга
+Name[km]=នដុងហ្កា
+Name[mk]=Ðдонга
+Name[mn]=Ðдонга
+Name[ne]=डोङà¥à¤—ा
+Name[nso]=Se-Ndonga
+Name[pa]=ਨਡੋਨਗਾ
+Name[ro]=Ndongă
+Name[ru]=Ðдонга
+Name[rw]=Ikindonga
+Name[se]=Ndongagiella
+Name[sk]=ndonga
+Name[sl]=ndonga
+Name[sq]=Ndongisht
+Name[sr]=Ðдонга
+Name[ss]=SiNdonga
+Name[ta]=டொஙà¯à®•à®¾
+Name[te]=డొంగా
+Name[tg]=Ðдонга
+Name[th]=ภาษาอึนดองà¸à¸²
+Name[tt]=Ndongaça
+Name[uk]=Ðдонга
+Name[uz@cyrillic]=Ðдонга
+Name[vi]=N-Ä‘on-ga
+Name[zh_HK]=Ndonga語
+Name[zh_TW]=Ndonga語
+Name[zu]=Isi-Ndonga
+[nl]
+Name=Dutch
+Name[af]=Hollands
+Name[ar]=الهولندية
+Name[az]=FlamenkcÉ™
+Name[be]=ГаландÑкаÑ
+Name[bg]=ХоландÑки
+Name[bn]=ওলনà§à¦¦à¦¾à¦œ
+Name[br]=Nederlandeg
+Name[bs]=Nizozemski
+Name[ca]=Holandès
+Name[cs]=Holandský
+Name[csb]=Hòlandzczi
+Name[cy]=Iseldireg
+Name[da]=Hollandsk
+Name[de]=Niederländisch
+Name[el]=Ολλανδικά
+Name[eo]=Nederlanda
+Name[es]=Holandés
+Name[et]=Hollandi
+Name[eu]=Nederlandera
+Name[fa]=هلندی
+Name[fi]=Hollanti
+Name[fr]=Hollandais
+Name[fy]=Nederlânsk
+Name[ga]=Ollainnis
+Name[gl]=Holandés
+Name[he]=הולנדית
+Name[hi]=डच
+Name[hr]=Nizozemski
+Name[hsb]=Nižozemsce
+Name[hu]=Holland
+Name[id]=Belanda
+Name[is]=Hollenska
+Name[it]=Olandese
+Name[ja]=オランダ語
+Name[ka]=ჰáƒáƒšáƒáƒœáƒ“იური
+Name[kk]=Ðидреландша
+Name[km]=ហុល្លង់
+Name[ko]=네ëœëž€ë“œì–´
+Name[ku]=Holendî
+Name[lb]=Hollännesch
+Name[lt]=Danų
+Name[lv]=Holandiešu
+Name[mi]=Reo Tenemaka
+Name[mk]=ХоландÑки
+Name[mn]=Дуч
+Name[ms]=Belanda
+Name[mt]=Olandiż
+Name[nb]=Nederlandsk
+Name[nds]=Nedderlannsch
+Name[ne]=डच
+Name[nl]=Nederlands
+Name[nn]=Nederlandsk
+Name[nso]=Se-Dutch
+Name[oc]=Olandès
+Name[pa]=ਡੱਚ
+Name[pl]=Holenderski
+Name[pt]=Holandês
+Name[pt_BR]=Holandês
+Name[ro]=Olandeză
+Name[ru]=ГолландÑкий
+Name[rw]=Ikinyaholande
+Name[se]=Hollánddagiella
+Name[sk]=holandÄina
+Name[sl]=nizozemsko
+Name[sq]=Hungarisht
+Name[sr]=ХоландÑки
+Name[sr@Latn]=Holandski
+Name[ss]=SiDatji
+Name[sv]=Holländska
+Name[ta]=டசà¯à®šà¯
+Name[te]=à°¡à°šà±
+Name[tg]=Олмонӣ
+Name[th]=ภาษาดัทช์
+Name[tr]=Flamanca
+Name[tt]=Dutça
+Name[uk]=ÐідерландÑька
+Name[uz]=Gollandcha
+Name[uz@cyrillic]=Голландча
+Name[vi]=Hoà-lan
+Name[wa]=Neyerlandès
+Name[xh]=Isidatshi
+Name[zh_CN]=è·å…°è¯­
+Name[zh_HK]=è·è˜­èªž
+Name[zh_TW]=è·è˜­èªž
+Name[zu]=Isi-Danishi
+[nn]
+Name=Norwegian Nynorsk
+Name[af]=Noörweese Nynorsk
+Name[ar]=نينورسك النرويجية
+Name[az]=Norveçcə (Nynorsk)
+Name[be]=ÐарвежÑÐºÐ°Ñ (нюнорÑк)
+Name[bg]=Ðорвежки (нюнорÑк)
+Name[bn]=নরওয়েজীয় নাইনরà§à¦¸à§à¦•
+Name[br]=Norvegeg Nynorsk
+Name[bs]=Norveški Nynorsk
+Name[ca]=Noruec Nynorsk
+Name[cs]=Norský (Nynorsk)
+Name[csb]=Norwesczi Nynorsk
+Name[cy]=Nynorsk Norwyeg
+Name[da]=Nynorsk
+Name[de]=Norwegisch (Nynorsk)
+Name[el]=ÎοÏβηγικά Nynorsk
+Name[eo]=Norvega (Nynorsk)
+Name[es]=Noruego Nynorsk
+Name[et]=Norra nynorsk
+Name[eu]=Norvegiera (Nynorsk)
+Name[fa]=نرس جدید نروژی
+Name[fi]=Norja (nynorsk)
+Name[fr]=Norvégien Nynorsk
+Name[fy]=Noarsk, Nynorsk
+Name[ga]=Ioruais (Nynorsk)
+Name[gl]=Noruegués (Nynorsk)
+Name[he]=נורבגית Nynorsk
+Name[hi]=नारà¥à¤µà¥‡à¤œà¤¿à¤¯à¤¨ नायनोरसà¥à¤•
+Name[hr]=Norveški Nynorsk
+Name[hsb]=Norwegsce (Nynorsk)
+Name[hu]=Norvég (nynorsk)
+Name[id]=Norwegia (Nynorsk)
+Name[is]=Norska (nýnorska)
+Name[it]=Norvegese Nynorsk
+Name[ja]=ノルウェー語 (ニーノシュク)
+Name[ka]=ნáƒáƒ áƒ•áƒ”გიული (ნინáƒáƒ áƒ¡áƒ™áƒ˜)
+Name[kk]=Ðовег нунорÑкша
+Name[km]=áž“áŸážšážœáŸ‚ស នីនូស
+Name[ko]=노르웨ì´ì–´ (Nynorsk)
+Name[ku]=Norwêcî Nynorsk
+Name[lb]=Norwegesch (Nynorsk)
+Name[lt]=Norvegų Nynorsk
+Name[lv]=Norvēģu (Ņūnorskas)
+Name[mk]=Ðорвешки Nynorsk
+Name[mn]=Ðорвеги ÐинорÑк
+Name[nb]=Nynorsk
+Name[nds]=Norweegsch Nynorsk
+Name[ne]=नरà¥à¤µà¥‡à¤²à¥€ नाइनोरà¥à¤¸à¤•
+Name[nl]=Noors, Nynorsk
+Name[nn]=Norsk nynorsk
+Name[nso]=Se-Norwegian Nynorsk
+Name[pa]=ਨੋਰਵਿਗੀਆਨ ਨਯਾਨੋਰਸਕ
+Name[pl]=Norweski Nynorsk
+Name[pt]=Norueguês Nynorsk
+Name[pt_BR]=Norueguês do Norte
+Name[ro]=Norvegiană Nynorsk
+Name[ru]=ÐорвежÑкий (нинорÑкий)
+Name[rw]=Ikinyanoruveji nayinorusiki
+Name[se]=Ođđadárogiella
+Name[sk]=nórsky nynorsk
+Name[sl]=norveško (nyorsk)
+Name[sq]=Norvegjisht (Nynorsk)
+Name[sr]=Ðорвешки (Ðиноршки)
+Name[sr@Latn]=Norveški (Ninorški)
+Name[ss]=Si-Norwegian Nynorsk
+Name[sv]=Nynorska
+Name[ta]=நாரà¯à®µà¯€à®œà®¿à®¯à®©à¯ (நையோரà¯à®¸à¯à®•à¯)
+Name[te]=నారà±à°µà±€à°œà°¿à°¯à°¨à± à°¨à±à°¯à±‹à°°à±à°¸à±à°•à±
+Name[tg]=ÐорвегиÑгӣ ÐунорÑк
+Name[th]=ภาษานอร์เวย์ (นูนอร์สคฺ)
+Name[tr]=Norveççe Nynorsk
+Name[tt]=Norwejçä (Ninorsk)
+Name[uk]=Ðорвезька (Nynorsk)
+Name[uz]=Norvegiyacha (Nynorsk)
+Name[uz@cyrillic]=ÐорвегиÑча (ÐйнорÑк)
+Name[vi]=Na-uy (Ny-noạ-x-kh)
+Name[wa]=Noû-Norvedjyin (Nynorsk)
+Name[zh_CN]=挪å¨è¯­ (尼诺斯克语)
+Name[zh_HK]=æŒªå¨ Nynorsk 語
+Name[zh_TW]=æŒªå¨ Nynorsk 語
+Name[zu]=Isi-Norwegian Nynorsk
+[nr]
+Name=Ndebele, South
+Name[af]=Ndebele, Suid
+Name[ar]=النديبيلي الجنوبية
+Name[az]=Ndebele, Cənub
+Name[be]=ÐдÑбель (поўдзень)
+Name[bg]=Южен Ðдебеле
+Name[bn]=নà§â€Œà¦¦à§‡à¦¬à§‡à¦²à§‡, দকà§à¦·à¦¿à¦£
+Name[br]=Ndebele, Su
+Name[bs]=Ndebele, Južni
+Name[ca]=Ndebele, Sud
+Name[cs]=Ndebele, Jižní
+Name[csb]=Ndebele, Pôłnie
+Name[cy]=Ndebele, De
+Name[da]=Ndebele, syd
+Name[de]=Ndebele (südliches)
+Name[eo]=Suda Ndebele
+Name[es]=Ndebele del sur
+Name[et]=Lõuna-ndebele
+Name[eu]=Ndebelera (hegoaldekoa)
+Name[fa]=اندبل جنوبی
+Name[fi]=Ndebele, Etelä
+Name[fr]=Ndébélé du Sud
+Name[fy]=Ndebele, Súd
+Name[ga]=Ndebele Theas
+Name[gl]=Ndebele do Sur
+Name[he]=נדבלה דרומית
+Name[hi]=नेदेबेले,दकà¥à¤·à¤¿à¤£
+Name[hr]=Ndebele, Južni
+Name[hsb]=Ndebele, Južne
+Name[hu]=Ndebele (déli)
+Name[id]=Ndebele, Selatan
+Name[is]=Ndebele, suður
+Name[it]=Ndebele meridionale
+Name[ja]=å—ンデベレ語
+Name[ka]=სáƒáƒ›áƒ®áƒ áƒ”თ ნდებელე
+Name[kk]=ОңтүÑтік ндебеле
+Name[km]=នដិបិលិ​ážáž¶áž„​ážáŸ’បូង
+Name[ko]=남부 ì€ë°ë²¨ë ˆ
+Name[lb]=Ndebele (südlecht)
+Name[lt]=Ndebele, Pietų
+Name[mk]=Ðдебеле, јужен
+Name[mn]=ÐдÑбÑлÑ, өмнөд
+Name[nb]=Ndebele, Sør
+Name[nds]=Ndebele, Sööd
+Name[ne]=डेबेले, दकà¥à¤·à¤¿à¤£
+Name[nl]=Ndebele, Zuid
+Name[nn]=Ndebele, sør
+Name[nso]=Se-Ndebele, sa Borwa
+Name[pa]=ਨਡੀਬੀਲੀ, ਦੱਖਣੀ
+Name[pl]=Ndebele, Południe
+Name[pt]=Ndebele do Sul
+Name[pt_BR]=Ndebele, Sul
+Name[ro]=Ndebelă sudică
+Name[ru]=Юж. Ðдебеле
+Name[rw]=Ikindebele, Amajyepfo
+Name[se]=Ndebelegiella, lulli
+Name[sk]=južná ndebelÄina
+Name[sl]=ndebele, južno
+Name[sq]=NBedelisht të Jugut
+Name[sr]=Ðдебеле, Јужни
+Name[sr@Latn]=Ndebele, Južni
+Name[ss]=SiNdebele, saseningizimu
+Name[sv]=Sydndebele
+Name[ta]=டெபெலே, தெனà¯
+Name[te]=నెబేలె, దకà±à°·à°¿à°£
+Name[tg]=Ðдебелӣ, Ҷануб
+Name[th]=ภาษาอึนเดเบเล ตอนใต้
+Name[tt]=Ndebeleçä, Könyaq
+Name[uk]=Ðдебелє, Південна
+Name[uz]=Ndebele, Janub
+Name[uz@cyrillic]=Ðдебеле, Жануб
+Name[ven]=Ndebele, Tshipembe
+Name[vi]=N-đe-be-lê (Nam)
+Name[wa]=Ndebele (nonne)
+Name[xh]=Isindebele, Emazantsi
+Name[zh_CN]=Ndebele,å—部
+Name[zh_HK]=Ndebele語,å—部
+Name[zh_TW]=Ndebele語,å—部
+Name[zu]=Isi-Ndebele, Sase-Mzansi
+[nso]
+Name=Northern Sotho
+Name[af]=Noord Sotho
+Name[ar]=السوتو الشمالية
+Name[az]=Åžimali Sotho
+Name[be]=Паўночнае Сота
+Name[bg]=Северен Сото
+Name[bn]=উতà§à¦¤à¦° সোথো
+Name[br]=Soto, Norzh
+Name[bs]=Sjeverni Soto
+Name[ca]=Sotho del nord
+Name[cs]=Severní Sotho
+Name[csb]=Nordowé Sotho
+Name[cy]=Sotho'r Gogledd
+Name[da]=Nord Sotho
+Name[de]=Nord-Sotho
+Name[eo]=Norda Sotoa
+Name[es]=Sotho del norte
+Name[et]=Põhja-sotho
+Name[eu]=Sothoera (iparraldekoa)
+Name[fa]=سوتوی شمالی
+Name[fi]=Pohjoissotho
+Name[fr]=Sotho du Nord
+Name[fy]=Noard Sotho
+Name[ga]=Seipidis
+Name[gl]=Sotho do Norte
+Name[hi]=नारà¥à¤¦à¤°à¥à¤¨ सोथो
+Name[hr]=Sjeverni Sotho
+Name[hsb]=Sewjerne Sotho
+Name[hu]=Északi sotho
+Name[is]=Norður Sotho
+Name[it]=Sotho settentrionale
+Name[ja]=北ソト語
+Name[ka]=ჩრდილრსáƒáƒ¢áƒ
+Name[kk]=СолтүÑтік Ñото
+Name[km]=សូធូ​ជើង
+Name[ko]=ë¶ë¶€ 소토어
+Name[lb]=Nördlecht Sotho
+Name[lt]=Å iaurÄ—s Sotho
+Name[lv]=Ziemeļu Sotho
+Name[mk]=Северен Сото
+Name[mn]=Умард Сото
+Name[ms]=Sotho Utara
+Name[nb]=Nord-Sotho
+Name[nds]=Noord-Sotho
+Name[ne]=उतà¥à¤¤à¤°à¥€ सोथो
+Name[nl]=Noord-Sotho
+Name[nn]=Nord-Sotho
+Name[pa]=ਉੱਤਰੀ ਸੋਥੋ
+Name[pl]=Północne Sotho
+Name[pt]=Sotho do Norte
+Name[pt_BR]=Sotho do Norte
+Name[ro]=Soto nordică
+Name[ru]=Северное Сото
+Name[rw]=Igisoto cy'Amajyaruguru
+Name[se]=Davvi-sothogiella
+Name[sk]=severná sothÄina
+Name[sl]=severni sotho
+Name[sq]=Sothisht Të Veriut
+Name[sr]=Северни Ñото
+Name[sr@Latn]=Severni soto
+Name[sv]=Nordsotho
+Name[ta]=நாரà¯à®¤à®©à¯ சோதà¯à®¤à¯‹
+Name[te]=ఉతà±à°¤à°° సొతొ
+Name[tg]=Сотои Шимолӣ
+Name[th]=ภาษาโซโธ ตอนเหนือ
+Name[tt]=Tönyaq Sotho
+Name[uk]=Північне Сото
+Name[uz]=Shimoliy Sotocha
+Name[uz@cyrillic]=Шимолий Соточа
+Name[vi]=Xô-tô (Bắc)
+Name[wa]=Soto (bijhe)
+Name[zh_CN]=北部梭托语
+[nv]
+Name=Navajo
+Name[ar]=الناÙاجو
+Name[az]=Navayoca
+Name[be]=Ðаваё
+Name[bg]=Ðавахо
+Name[bn]=নাভায়ো
+Name[el]=Îάβαχο
+Name[eo]=Navaha
+Name[et]=Navaho
+Name[fa]=ناواجو
+Name[fi]=Navaho
+Name[fr]=Navaho
+Name[ga]=Navachóis
+Name[gl]=Navaxo
+Name[he]=נב×חו
+Name[hi]=नवाजो
+Name[hr]=Navaho
+Name[ja]=ナãƒãƒ›èªž
+Name[ka]=ნáƒáƒ•áƒáƒ®áƒ
+Name[kk]=Ðавахо
+Name[km]=ណាវាហ្សូ
+Name[ko]=나바조어
+Name[mk]=Ðавахо
+Name[mn]=ÐаваÑа
+Name[ne]=नेभाजो
+Name[nso]=Se-Navajo
+Name[pa]=ਨਾਵਾਜੋ
+Name[ru]=Ðавахо
+Name[rw]=Ikinavajo
+Name[se]=Naváhogiella
+Name[sk]=navajo
+Name[sl]=navajo
+Name[sq]=Navahisht
+Name[sr]=Ðавахо
+Name[sr@Latn]=Navaho
+Name[ss]=Si-Navajo
+Name[sv]=Navaho
+Name[ta]=நவாஜோ
+Name[te]=నవాజొ
+Name[tg]=Ðаваҷо
+Name[th]=ภาษานาวาโฮ
+Name[tt]=Navaxoça
+Name[uk]=Ðавахо
+Name[uz@cyrillic]=Ðаважо
+Name[vi]=Na-va-cá»™
+Name[wa]=Navaxho
+Name[zh_CN]=纳瓦éœè¯­
+Name[zh_HK]=ç´ç“¦ä¼™èªž
+Name[zh_TW]=ç´ç“¦ä¼™èªž
+Name[zu]=Isi-Navajo
+[ny]
+Name=Chichewa
+Name[ar]=التشيشيوا
+Name[az]=Çiçeva
+Name[be]=ЧычÑва
+Name[bg]=Чеуа
+Name[bn]=চিচেওয়া
+Name[de]=Nyanja
+Name[eo]=Ĉiĉeva
+Name[fa]=چیچوا
+Name[fi]=Njandža
+Name[ga]=Siseivis
+Name[he]=צ'יצ'ווה
+Name[hi]=चिचेवा
+Name[hu]=Csicseva
+Name[ja]=ãƒã‚§ãƒ¯èªž
+Name[ka]=ჩიჩევáƒ
+Name[kk]=Чичева
+Name[km]=ចីចិវ៉ា
+Name[lb]=Nyanja
+Name[lv]=ÄŒiÄevieÅ¡u
+Name[mk]=Чичева
+Name[mn]=Чичева
+Name[ne]=चिचेवा
+Name[nso]=Se-Chichewa
+Name[pa]=ਚਿਚੀਵਾ
+Name[ro]=Ciceuă
+Name[ru]=Чичева
+Name[rw]=Igicicewa
+Name[se]=Chichevagiella
+Name[sk]=ÄiÄewa
+Name[sl]=chichewa
+Name[sq]=Çiçevisht
+Name[sr]=ЧичевÑки
+Name[sr@Latn]=ÄŒiÄevski
+Name[ss]=Si-Chichewa
+Name[sv]=Chewa
+Name[ta]=சிசà¯à®šà¯†à®µà®¾
+Name[te]=చిచెవా
+Name[tg]=Чичевагӣ
+Name[th]=ภาษาชิเชวา
+Name[tt]=Çiçewaça
+Name[uk]=ЧічеванÑька
+Name[uz]=Chicheva
+Name[uz@cyrillic]=Чичева
+Name[vi]=Chi-che-ouă
+Name[wa]=Tchitchewa
+Name[zh_CN]=é½åˆ‡ç“¦è¯­
+Name[zh_HK]=Chichewa語
+Name[zh_TW]=Chichewa語
+Name[zu]=Isi-Chichewa
+[oc]
+Name=Occitan
+Name[af]=Okkitaan
+Name[ar]=الأوكسيتانية
+Name[az]=Oksitan
+Name[be]=ÐкітанÑкаÑ
+Name[bg]=ОкÑитанÑки
+Name[bn]=ওকà§à¦¸à¦¿à¦Ÿà¦¾à¦¨
+Name[br]=Oksitaneg
+Name[ca]=Occità
+Name[cs]=Okcitánský
+Name[csb]=Òkcitańsczi
+Name[cy]=Occitaneg
+Name[de]=Okzitanisch
+Name[eo]=Okcitana
+Name[es]=Occitano
+Name[et]=Oktsitaani
+Name[eu]=Okzitaniera
+Name[fa]=اÙکیتان
+Name[fi]=Oksitaani
+Name[fy]=Oksitaansk
+Name[ga]=Ocatáinis
+Name[gl]=Occitano
+Name[he]=פרובנסלית
+Name[hi]=ओसिटान
+Name[hsb]=Okcitansce
+Name[hu]=Okcitán
+Name[it]=Occitano
+Name[ja]=オック語
+Name[ka]=áƒáƒ¥áƒ˜áƒ¢áƒáƒœáƒ£áƒ áƒ˜ (ფრáƒáƒœáƒ’ული დიáƒáƒšáƒ”ქტი)
+Name[kk]=ОÑÑитанша
+Name[km]=អុកស៊ីážáž„់
+Name[ko]=오í¬ì–´
+Name[ku]=Oksîtanî
+Name[lb]=Okzitanesch
+Name[lv]=OkitÄņu
+Name[mk]=Очитан
+Name[mn]=ОкÑитан
+Name[mt]=OÄ‹Ä‹itan
+Name[nb]=Oksitansk
+Name[nds]=Okzitaansch
+Name[ne]=ओकà¥à¤¸à¤¿à¤Ÿà¤¾à¤¨
+Name[nn]=Oksitansk
+Name[nso]=Se-Occitan
+Name[oc]=Occitàn
+Name[pa]=ਓਸੀਟਾਨ
+Name[pl]=Okcytański
+Name[pt]=Occitano
+Name[ro]=Occitană
+Name[ru]=ФранцузÑкий (диалект Occitan)
+Name[rw]=Icyogisitani
+Name[se]=Oksitánagiella
+Name[sk]=okcitánÄina
+Name[sl]=oÄitansko
+Name[sq]=Oksitanisht
+Name[sr]=ОцитанÑки
+Name[sr@Latn]=Ocitanski
+Name[ss]=Si-Occitan
+Name[sv]=Occitanska
+Name[ta]=ஒகà¯à®šà®¿à®Ÿà¯à®Ÿà®¾à®©à¯
+Name[te]=à°’à°¸à±à°¸à°¿à°Ÿà°¾à°¨à±
+Name[tg]=Окитанӣ
+Name[th]=ภาษาออคซิทัน
+Name[tr]=Oksitan dili
+Name[tt]=Okkitança
+Name[uk]=ОкÑітанÑька
+Name[uz]=Fransuzcha (Ossitan shevasi)
+Name[uz@cyrillic]=Французча (ОÑÑитан шеваÑи)
+Name[vi]=Óc-ci-tan
+Name[zh_CN]=奥西å¦è¯­
+Name[zh_HK]=Occitan語
+Name[zh_TW]=Occitan語
+Name[zu]=Isi-Osithani
+[om]
+Name=Oromo
+Name[ar]=الأورومو
+Name[az]=Oromoca
+Name[be]=Ðрома
+Name[bg]=Ðфан Оромо
+Name[bn]=ওরোমো
+Name[eo]=Oroma
+Name[fa]=اورومو
+Name[ga]=Oraimis
+Name[he]=×ורומו
+Name[hi]=ओरोमो
+Name[hr]=Oromski
+Name[ja]=オロモ語
+Name[ka]=áƒáƒ áƒáƒ›áƒ
+Name[kk]=Оромо
+Name[km]=អុរុមុ
+Name[ko]=오로모어
+Name[mk]=Оромо
+Name[mn]=Оромо
+Name[ne]=ओरोमो
+Name[nso]=Se-Oromo
+Name[pa]=ਓਰੋਮੋ
+Name[ro]=Oromă
+Name[ru]=Оромо
+Name[rw]=Icyoromo
+Name[se]=Oromogiella
+Name[sk]=oromÄina
+Name[sl]=oromo
+Name[sq]=Oromisht
+Name[sr]=ОромÑки
+Name[sr@Latn]=Oromski
+Name[ss]=Si-Oromo
+Name[ta]=ஒரோமோ
+Name[te]=ఒరొమొ
+Name[tg]=Оромо
+Name[th]=ภาษาโอโรโม
+Name[tt]=Oromoça
+Name[uk]=Оромо
+Name[uz@cyrillic]=Оромо
+Name[vi]=O-ro-mô
+Name[zh_CN]=阿曼语
+Name[zh_HK]=Oromo語
+Name[zh_TW]=Oromo語
+Name[zu]=Isi-Oromo
+[or]
+Name=Oriya
+Name[ar]=لغة أهل أوريسا )الهند(
+Name[az]=Oriyaca
+Name[be]=ОрыÑ
+Name[bg]=ОриÑ
+Name[bn]=ওড়িয়া
+Name[eo]=Orijo
+Name[et]=Orija
+Name[fa]=اوریا
+Name[fi]=Orija
+Name[ga]=Oirísis
+Name[gl]=Orisa
+Name[he]=×וריה
+Name[hi]=ओरिया
+Name[hu]=Orija
+Name[ja]=オリヤー語
+Name[ka]=áƒáƒ áƒ˜áƒ
+Name[kk]=ОриÑ
+Name[km]=អូរីយ៉ា
+Name[ko]=오리야어
+Name[lb]=Orija
+Name[mk]=Орија
+Name[mn]=ОриÑ
+Name[ne]=ओरिया
+Name[nso]=Se-Oriya
+Name[pa]=ਉੜੀਆ
+Name[ro]=Oriană
+Name[ru]=ОриÑ
+Name[rw]=Icyoriya
+Name[se]=Orijagiella
+Name[sk]=uríjÄina
+Name[sl]=oriya
+Name[sq]=Orijisht
+Name[sr]=ОријÑки
+Name[sr@Latn]=Orijski
+Name[ss]=Si-Oriya
+Name[ta]=ஒரியா
+Name[te]=ఒరియా
+Name[tg]=Ориёӣ
+Name[th]=ภาษาโอริยา
+Name[uk]=ОріÑ
+Name[uz@cyrillic]=ОриÑ
+Name[vi]=Ô-ri-yạ
+Name[zh_CN]=欧里亚语
+Name[zh_HK]=Oriya語
+Name[zh_TW]=Oriya語
+Name[zu]=Isi-Oriya
+[os]
+Name=Ossetian
+Name[ar]=الأوسيتية
+Name[az]=Osetiyaca
+Name[be]=ÐÑетынÑкаÑ
+Name[bg]=ОÑетинÑки
+Name[bn]=ওসেটিয়ান
+Name[br]=Ossetieg
+Name[bs]=Osetski
+Name[ca]=Oseti
+Name[cs]=Osetský
+Name[csb]=Òsetańsczi
+Name[cy]=Oseteg
+Name[de]=Ossetisch
+Name[eo]=Oseta
+Name[es]=Osetio
+Name[et]=Osseedi
+Name[eu]=Osetiera
+Name[fa]=اوستی Ù‚Ùقاز
+Name[fi]=Osseetti
+Name[fr]=Ossète
+Name[fy]=Ossetysk
+Name[ga]=Óiséitis
+Name[gl]=Oseto
+Name[he]=×וסטית
+Name[hi]=ओसेटियन
+Name[hr]=Osetski
+Name[hsb]=Osetisce
+Name[hu]=Oszét
+Name[it]=Ossetiano
+Name[ja]=オセット語
+Name[ka]=áƒáƒ¡áƒ£áƒ áƒ˜
+Name[kk]=ОÑетинше
+Name[km]=អូសសិážáŸ’យុង
+Name[ko]=오세티안어
+Name[lb]=Ossetesch
+Name[lt]=Osetinų
+Name[lv]=Osetīņu
+Name[mk]=ОÑетиÑки
+Name[mn]=ОÑÑетан
+Name[nb]=Ossetisk
+Name[nds]=Osseetsch
+Name[ne]=ओसेसियन
+Name[nl]=Ossetisch
+Name[nn]=Ossetisk
+Name[nso]=Se-Ossetian
+Name[pa]=ਓਸੀਟੀਅਨ
+Name[pl]=Osetański
+Name[pt]=Osseta
+Name[ro]=Osetiană
+Name[ru]=ОÑетинÑкий
+Name[rw]=Icyosetiyani
+Name[se]=Ossetiagiella
+Name[sk]=osetÄina
+Name[sl]=osetijsko
+Name[sq]=Osetianisht
+Name[sr]=ОÑетÑки
+Name[sr@Latn]=Osetski
+Name[ss]=Si-Ossetian
+Name[sv]=Ossetsiska
+Name[ta]=ஒசெடà¯à®Ÿà®¿à®¯à®©à¯
+Name[te]=à°’à°¸à±à°¸à±†à°·à°¿à°¯à°¨à±
+Name[tg]=ОÑетинӣ
+Name[th]=ภาษาโอซิเชียน
+Name[tt]=Ossetinçä
+Name[uk]=ОÑетинÑька
+Name[uz]=Ossetincha
+Name[uz@cyrillic]=ОÑÑетинча
+Name[vi]=Óc-xe-ti-an
+Name[wa]=Ossete
+Name[zh_CN]=奥塞梯语
+Name[zh_HK]=Ossetian語
+Name[zh_TW]=Ossetian語
+Name[zu]=Isi-Ossethiyani
+[pa]
+Name=Panjabi
+Name[ar]=بنجابي
+Name[az]=PanjabicÉ™
+Name[be]=Панджабі
+Name[bg]=Панджаби
+Name[bn]=পাঞà§à¦œà¦¾à¦¬à§€
+Name[br]=Pendjabieg
+Name[cs]=Pandžábský
+Name[csb]=Pendżabsczi
+Name[de]=Pandschabi
+Name[eo]=PanÄaba
+Name[es]=Punjabí
+Name[et]=Pandžabi
+Name[eu]=Punjabera
+Name[fa]=پنجابی
+Name[fi]=Pandžabi
+Name[fr]=Pendjabi
+Name[ga]=Painseáibis
+Name[gl]=Panxabi
+Name[he]=פנג'בית
+Name[hi]=पंजाबी
+Name[hr]=Pandžabski
+Name[hsb]=Pandźabisce
+Name[hu]=Pandzsabi
+Name[it]=Punjabi
+Name[ja]=ãƒãƒ³ã‚¸ãƒ£ãƒ¼ãƒ–語
+Name[ka]=პენჯáƒáƒ‘ი
+Name[kk]=Панждаби
+Name[km]=ពូនយ៉ាប៊ី
+Name[ko]=펀잡어
+Name[ku]=Pêncabî
+Name[lb]=Panjabi-Sprooch
+Name[lt]=Pendžabo
+Name[lv]=Pandžabu
+Name[mk]=Пунџаби
+Name[mn]=Панжаби
+Name[nds]=Pandschaabsch
+Name[ne]=पनà¥à¤œà¤¾à¤¬à¥€
+Name[nso]=Se-Panjabi
+Name[pa]=ਪੰਜਾਬੀ
+Name[pl]=Pendżabski
+Name[ro]=Panjabă
+Name[ru]=Панджаби
+Name[rw]=Igipanjabi
+Name[se]=Panjabigiella
+Name[sk]=pandžábÄina
+Name[sl]=pandžabsko
+Name[sq]=Panjabisht
+Name[sr]=ПенџабÑки
+Name[sr@Latn]=Pendžabski
+Name[ss]=Si-Panjabi
+Name[ta]=பஞà¯à®šà®¾à®ªà®¿
+Name[te]=పంజాబి
+Name[tg]=Панҷабӣ
+Name[th]=ภาษาปัà¸à¸ˆà¸²à¸šà¸µ
+Name[tt]=Panjabça
+Name[uk]=ПанджабÑька
+Name[uz]=Panjabcha
+Name[uz@cyrillic]=Панжабча
+Name[vi]=Pan-gia-bi
+Name[wa]=Pundjabi
+Name[zh_CN]=æ—é®æ™®è¯­
+Name[zh_HK]=Panjabi語
+Name[zh_TW]=Panjabi語
+Name[zu]=Isi-Phanjabi
+[pi]
+Name=Pali
+Name[ar]=البالي
+Name[az]=PalicÉ™
+Name[be]=Палі
+Name[bg]=Пали
+Name[bn]=পালি
+Name[br]=Palieg
+Name[eo]=Palio
+Name[es]=Palí
+Name[et]=Paali
+Name[fa]=پالی
+Name[ga]=Páilis
+Name[he]=פ×לי
+Name[hi]=पाली
+Name[ja]=パーリ語
+Name[ka]=ფáƒáƒšáƒáƒ£áƒ áƒ˜
+Name[kk]=Пали
+Name[km]=បាលី
+Name[mk]=Пали
+Name[mn]=Пали
+Name[ne]=पाली
+Name[nso]=Se-Pali
+Name[pa]=ਪਾਲੀ
+Name[ru]=Пали
+Name[rw]=Igipali
+Name[se]=Páligiella
+Name[sk]=pálí
+Name[sl]=pali
+Name[sq]=Palisht
+Name[sr]=ПалијÑки
+Name[sr@Latn]=Palijski
+Name[ss]=Si-Pali
+Name[ta]=பாலி
+Name[te]=పాళి
+Name[tg]=Пали
+Name[th]=ภาษาบาลี
+Name[tt]=Paliçä
+Name[uk]=Палі
+Name[uz@cyrillic]=Пали
+Name[vi]=Pa-li
+Name[wa]=Pâli
+Name[zh_CN]=巴利语
+Name[zh_HK]=巴利語
+Name[zh_TW]=巴利語
+Name[zu]=Isi-Phali
+[pl]
+Name=Polish
+Name[af]=Poolse
+Name[ar]=البولندية
+Name[az]=Polyakca
+Name[be]=ПольÑкаÑ
+Name[bg]=ПолÑки
+Name[bn]=পোলিশ
+Name[br]=Poloneg
+Name[bs]=Poljski
+Name[ca]=Polonès
+Name[cs]=Polský
+Name[csb]=Pòlsczi
+Name[cy]=Pwyleg
+Name[da]=Polsk
+Name[de]=Polnisch
+Name[el]=Πολωνικά
+Name[eo]=Pola
+Name[es]=Polaco
+Name[et]=Poola
+Name[eu]=Poloniera
+Name[fa]=لهستانی
+Name[fi]=Puola
+Name[fr]=Polonais
+Name[fy]=Poalsk
+Name[ga]=Polainnis
+Name[gl]=Polaco
+Name[he]=פולנית
+Name[hi]=पोलिश
+Name[hr]=Poljski
+Name[hsb]=Pólsce
+Name[hu]=Lengyel
+Name[id]=Polandia
+Name[is]=Pólska
+Name[it]=Polacco
+Name[ja]=ãƒãƒ¼ãƒ©ãƒ³ãƒ‰èªž
+Name[ka]=პáƒáƒšáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=ПолÑкша
+Name[km]=ប៉ូឡូញ
+Name[ko]=í´ëž€ë“œì–´
+Name[ku]=Polî
+Name[lb]=Polnesch
+Name[lt]=Lenkų
+Name[lv]=Poļu
+Name[mi]=Reo Pörana
+Name[mk]=ПолÑки
+Name[mn]=Польш
+Name[mt]=Pollakk
+Name[nb]=Polsk
+Name[nds]=Poolsch
+Name[ne]=पोलीश
+Name[nl]=Pools
+Name[nn]=Polsk
+Name[nso]=Se-Polish
+Name[oc]=Pòlònès
+Name[pa]=ਪੋਲੈਂਡੀ
+Name[pl]=Polski
+Name[pt]=Polaco
+Name[pt_BR]=Polonês
+Name[ro]=Poloneză
+Name[ru]=ПольÑкий
+Name[rw]=Ikinyapolonye
+Name[se]=Polskkagiella
+Name[sk]=poľština
+Name[sl]=poljsko
+Name[sq]=Polonisht
+Name[sr]=ПољÑки
+Name[sr@Latn]=Poljski
+Name[ss]=Si-Polish
+Name[sv]=Polska
+Name[ta]=போலிஷà¯
+Name[te]=పోలిషà±
+Name[tg]=ПолÑкӣ
+Name[th]=ภาษาโปลิช
+Name[tr]=Lehçe
+Name[tt]=Polça
+Name[uk]=ПольÑька
+Name[uz]=Polyakcha
+Name[uz@cyrillic]=ПолÑкча
+Name[vi]=Ba-lan
+Name[wa]=Polonès
+Name[zh_CN]=波兰语
+Name[zh_HK]=波蘭語
+Name[zh_TW]=波蘭語
+Name[zu]=Isi-Pholishi
+[ps]
+Name=Pushto
+Name[ar]=باشتو
+Name[az]=PuÅŸtoca
+Name[be]=Пушту
+Name[bg]=Пущу
+Name[bn]=পà§à¦¸à§à¦¤
+Name[ca]=Pashto
+Name[de]=Paschtu
+Name[eo]=PaÅtua
+Name[es]=Pastún
+Name[et]=Puštu
+Name[eu]=Paxtuera
+Name[fa]=پشتو
+Name[fi]=Paštu
+Name[ga]=Paistis
+Name[he]=פשטו
+Name[hi]=पशà¥à¤¤à¥‹
+Name[hsb]=Pušto
+Name[hu]=Pusto
+Name[it]=Pashto
+Name[ja]=パシュトー語
+Name[ka]=პუშტუ
+Name[kk]=Пушту
+Name[km]=ប៉ាសážáž¼
+Name[ko]=푸시토어
+Name[lb]=Paschtu
+Name[lt]=Puštūnų
+Name[lv]=Puštu
+Name[mk]=Пушто
+Name[mn]=Пушто
+Name[nds]=Paschtuunsch
+Name[ne]=पà¥à¤¸à¥à¤¤à¥‹
+Name[nso]=Se-Pushto
+Name[pa]=ਪà©à¨¶à¨¤à©‹
+Name[ro]=Puştă
+Name[ru]=ПуштунÑкий
+Name[rw]=Igipushito
+Name[se]=Puštugiella
+Name[sk]=paÅ¡tÄina
+Name[sl]=pushto
+Name[sq]=Pushtisht
+Name[sr]=Пушто
+Name[sr@Latn]=Pušto
+Name[ss]=Si-Pushto
+Name[sv]=Pashto
+Name[ta]=பாஷà¯à®Ÿà¯à®©à¯
+Name[te]=à°ªà±à°·à±à°¤à±Š
+Name[tg]=Пушто
+Name[th]=ภาษาพาชโต
+Name[tt]=Puştu Farsíçası
+Name[uk]=ПуштунÑька
+Name[uz]=Pushtuncha
+Name[uz@cyrillic]=Пуштунча
+Name[vi]=Pu-x-tô
+Name[wa]=Pashto
+Name[zh_CN]=普什图语
+Name[zh_HK]=普什圖語
+Name[zh_TW]=普什圖語
+Name[zu]=Dudula ku
+[pt]
+Name=Portuguese
+Name[af]=Portugese
+Name[ar]=البرتغالية
+Name[az]=Portuqalca
+Name[be]=ПартугальÑкаÑ
+Name[bg]=ПортугалÑки
+Name[bn]=পরà§à¦¤à§à¦—ীজ
+Name[br]=Portugaleg
+Name[bs]=Portugalski
+Name[ca]=Portuguès
+Name[cs]=Portugalský
+Name[csb]=Pòrtugalsczi
+Name[cy]=Portiwgaleg
+Name[da]=Portugisisk
+Name[de]=Portugiesisch
+Name[el]=ΠοÏτογαλικά
+Name[eo]=Portugala
+Name[es]=Portugués
+Name[et]=Portugali
+Name[eu]=Portugesa
+Name[fa]=پرتغالی
+Name[fi]=Portugali
+Name[fr]=Portugais
+Name[fy]=Portugeesk
+Name[ga]=Portaingéilis
+Name[gl]=Portugués
+Name[he]=פורטוגזית
+Name[hi]=पोरà¥à¤¤à¥à¤—ीस
+Name[hr]=Portugalski
+Name[hsb]=Portugalsce
+Name[hu]=Portugál
+Name[id]=Portugis
+Name[is]=Portúgalska
+Name[it]=Portoghese
+Name[ja]=ãƒãƒ«ãƒˆã‚¬ãƒ«èªž
+Name[ka]=პáƒáƒ áƒ¢áƒ£áƒ’áƒáƒšáƒ£áƒ áƒ˜
+Name[kk]=Португалша
+Name[km]=áž–áŸážšáž‘ុយហ្គាល់
+Name[ko]=í¬ë¥´íˆ¬ê°ˆì–´
+Name[ku]=Portûgalî
+Name[lb]=Portugisesch
+Name[lt]=Portugalų
+Name[lv]=PortugÄļu
+Name[mi]=Reo Pötikï
+Name[mk]=ПортугалÑки
+Name[mn]=Португал
+Name[ms]=Portugis
+Name[mt]=Portugiż
+Name[nb]=Portugisisk
+Name[nds]=Portugeesch
+Name[ne]=पोरà¥à¤šà¥à¤—ाली
+Name[nl]=Portugees
+Name[nn]=Portugisisk
+Name[nso]=Sepotokisi
+Name[oc]=Pòrtuguès
+Name[pa]=ਪà©à¨°à¨¤à¨—ਾਲੀ
+Name[pl]=Portugalski
+Name[pt]=Português
+Name[pt_BR]=Português
+Name[ro]=Portugheză
+Name[ru]=ПортугальÑкий
+Name[rw]=Igiporutigali
+Name[se]=Portugálagiella
+Name[sk]=portugalÄina
+Name[sl]=portugalsko
+Name[sq]=Portugalisht
+Name[sr]=ПортугалÑки
+Name[sr@Latn]=Portugalski
+Name[ss]=SiPutukezi
+Name[sv]=Portugisiska
+Name[ta]=போரà¯à®¤à¯à®¤à¯à®•à¯à®•à¯€à®šà®¿à®¯
+Name[te]=పోరà±à°Ÿà±à°¯à±à°—ీసà±
+Name[tg]=Португалӣ
+Name[th]=ภาษาโปรตุเà¸à¸ª
+Name[tr]=Portekizce
+Name[tt]=Portugalça
+Name[uk]=ПортугальÑька
+Name[uz]=Portugalcha
+Name[uz@cyrillic]=Португалча
+Name[vi]=Bồ-đào-nha
+Name[wa]=Portuguès
+Name[zh_CN]=è‘¡è„牙语
+Name[zh_HK]=è‘¡è„牙語
+Name[zh_TW]=è‘¡è„牙語
+Name[zu]=Isi-Phuthukesi
+[pt_BR]
+Name=Brazilian Portuguese
+Name[ar]=البرتغالية البرازيلية
+Name[az]=Braziliya Portuqalcası
+Name[be]=ПартугальÑÐºÐ°Ñ Ð±Ñ€Ð°Ð·Ñ–Ð»ÑŒÑкаÑ
+Name[bg]=БразилÑки португалÑки
+Name[bn]=বà§à¦°à¦¾à¦œà¦¿à¦²à§€à§Ÿ পরà§à¦¤à§à¦—ীজ
+Name[br]=Portugaleg Brazil
+Name[bs]=Brazilski portugalski
+Name[ca]=Brasiler Portuguès
+Name[cs]=Portugalský (Brazílie)
+Name[csb]=Brazylsczi pòrtugalsczi
+Name[cy]=Portiwgaleg Brasil
+Name[da]=Brasiliansk portugisisk
+Name[de]=Brasilianisches Portugiesisch
+Name[el]=ΠοÏτογαλικά Î’Ïαζιλίας
+Name[eo]=Portugala (Brazilo)
+Name[es]=Portugués brasileño
+Name[et]=Brasiilia portugali
+Name[eu]=Portugesa (Brasilgoa)
+Name[fa]=پرتغالی برزیلی
+Name[fi]=Brasilian Portugali
+Name[fr]=Portugais Brésilien
+Name[fy]=Braziliaansk Portugeesk
+Name[ga]=Portaingéilis na Brasaíle
+Name[gl]=Portugués Do Brasil
+Name[he]=פורטוגזית ברזיל×ית
+Name[hi]=बà¥à¤°à¤¾à¤œà¤¿à¤²à¤¿à¤¯à¤¨ पà¥à¤°à¥à¤¤à¤—ाली
+Name[hr]=Brazilski portugalski
+Name[hsb]=Portugalsce (Brazilska)
+Name[hu]=Portugál (brazil)
+Name[id]=Portugis Brazil
+Name[is]=Brasílísk Portúgalska
+Name[it]=Portoghese brasiliano
+Name[ja]=ブラジル ãƒãƒ«ãƒˆã‚¬ãƒ«èªž
+Name[ka]=ბრáƒáƒ–ილიური (პáƒáƒ áƒ¢áƒ£áƒ’áƒáƒšáƒ£áƒ áƒ˜)
+Name[kk]=БразилиÑлық португалша
+Name[km]=ប្រáŸážŸáŸŠáž¸áž› áž–áŸážšáž‘ុយហ្គាល់
+Name[ko]=브ë¼ì§ˆì‹ í¬ë¥´íˆ¬ê°ˆì–´
+Name[ku]=Portûgalî ya Brazîl
+Name[lb]=Brazilianescht Portugisesch
+Name[lt]=Brazilijos portugalų
+Name[lv]=BrazÄ«lijas portugÄļu
+Name[mk]=БразилÑки португалÑки
+Name[mn]=Бразилын португал
+Name[ms]=Portugis Brazil
+Name[nb]=Brasil-portugisisk
+Name[nds]=Brasiliaansch Portugeesch
+Name[ne]=बà¥à¤°à¤¾à¤œà¤¿à¤²à¥€ पोरà¥à¤šà¥à¤—ाली
+Name[nl]=Braziliaans Portugees
+Name[nn]=Brasil-portugisisk
+Name[pa]=ਬਰਾਜ਼ੀਲ ਪà©à¨°à¨¤à¨—ਾਲੀ
+Name[pl]=Portugalski (brazylijski)
+Name[pt]=Português do Brasil
+Name[pt_BR]=Português do Brasil
+Name[ro]=Portugheză braziliană
+Name[ru]=ПортугальÑкий (БразилиÑ)
+Name[rw]=Igiporutigali cya Burezile
+Name[se]=Brasilialaš portugálagiella
+Name[sk]=portugalÄina (Brazília)
+Name[sl]=brazilska portugalÅ¡Äina
+Name[sq]=Portugalishte Braziliane
+Name[sr]=БразилÑко португалÑки
+Name[sr@Latn]=Brazilsko portugalski
+Name[sv]=Brasiliansk portugisiska
+Name[ta]=பிரேஸிலிய போரà¯à®¤à¯à®¤à¯à®•à¯à®•à¯€à®šà®¿à®¯
+Name[te]=à°¬à±à°°à°¾à°œà°¿à°²à°¿à°¯à°¨à± పోరà±à°Ÿà±à°¯à±à°—ీసà±
+Name[tg]=БразилиÑÓ£ Португалӣ
+Name[th]=ภาษาโปรตุเà¸à¸ªà¸šà¸£à¸²à¸‹à¸´à¸¥
+Name[tr]=Brezilya Portekizcesi
+Name[tt]=Portugalça, Brasil
+Name[uk]=БразильÑька португальÑька
+Name[uz]=Portugalcha (Braziliya)
+Name[uz@cyrillic]=Португалча (БразилиÑ)
+Name[vi]=Bồ-đào-nha (Bra-xin)
+Name[wa]=Portuguès do Braezi
+Name[zh_CN]=巴西葡è„牙语
+Name[zh_HK]=巴西葡è„牙語
+Name[zh_TW]=巴西葡è„牙語
+[qu]
+Name=Quechua
+Name[ar]=الكويتشيوا
+Name[az]=Kveçcə
+Name[be]=КÑчуа
+Name[bg]=Кечуа
+Name[bn]=কেচà§à§Ÿà¦¾
+Name[br]=Kechuaeg
+Name[eo]=Keĉua
+Name[et]=Ketšua
+Name[eu]=Kitxua
+Name[fa]=کوچوا
+Name[fi]=Ketšua
+Name[ga]=Ceatsuais
+Name[he]=קצ'ו××”
+Name[hi]=कà¥à¤µà¥‡à¤šà¥à¤†
+Name[hu]=Kecsua
+Name[ja]=ケãƒãƒ¥ã‚¢èªž
+Name[ka]=კეჩუáƒ
+Name[kk]=Кечуа
+Name[km]=កáŸáž‘្ជូអា
+Name[ko]=케추아어
+Name[lb]=Quechua-Sprooch
+Name[mk]=Кечуа
+Name[mn]=Куечуа
+Name[nds]=Ketschua
+Name[ne]=कà¥à¤µà¥‡à¤šà¤‰
+Name[nso]=Se-Quechua
+Name[pa]=ਕਿਉਚà©à¨†
+Name[ru]=Кечуа
+Name[rw]=Igikwecuwa
+Name[se]=KeÄÄuagiella
+Name[sk]=keÄuánÄina
+Name[sl]=quechua
+Name[sq]=Keçisht
+Name[sr]=Квечва
+Name[sr@Latn]=KveÄva
+Name[ss]=Si-Quechua
+Name[ta]=கà¯à®µà¯†à®šà¯à®šà®¾
+Name[te]=à°•à±à°µà±†à°šà±à°µà°¾
+Name[tg]=Квечуа
+Name[th]=ภาษาเคชัว
+Name[tt]=Queçuaça
+Name[uk]=Кечуа
+Name[uz]=Kvechua
+Name[uz@cyrillic]=Квечуа
+Name[vi]=Quê-chua
+Name[wa]=Kitchwa
+Name[zh_CN]=盖丘亚语
+Name[zh_HK]=蓋楚瓦語
+Name[zh_TW]=蓋楚瓦語
+Name[zu]=Isi-Quechua
+[rn]
+Name=Rundi
+Name[ar]=رواندي
+Name[az]=RundicÉ™
+Name[be]=Рундзі
+Name[bg]=Руанда
+Name[bn]=রà§à¦£à§à¦¡à¦¿
+Name[cy]=Rwndi
+Name[eo]=Ruanda
+Name[fa]=روندی
+Name[fy]=Rûandeesk
+Name[he]=רונדי
+Name[hi]=रूनà¥à¤¡à¥€
+Name[ja]=ルンディ語
+Name[ka]=რუნდი
+Name[kk]=Рунди
+Name[km]=រូន្ឌី
+Name[ko]=룬디어
+Name[lb]=Rundi-Sprooch
+Name[mk]=Рунди
+Name[mn]=Рунди
+Name[ne]=रूनà¥à¤¡à¥€
+Name[nso]=Se-Rundi
+Name[pa]=ਰੂਡੀ
+Name[ru]=Рунди
+Name[rw]=Ikirundi
+Name[se]=Rundigiella
+Name[sk]=rundÄina
+Name[sl]=rundi
+Name[sq]=Rundisht
+Name[sr]=Рунди
+Name[ss]=Si-Rundi
+Name[ta]=à®°à¯à®£à¯à®Ÿà®¿
+Name[te]=à°°à±à°‚à°¡à°¿
+Name[tg]=Рунди
+Name[th]=ภาษารุนดิ
+Name[tt]=Rundiçä
+Name[uk]=Рунді
+Name[uz@cyrillic]=Рунди
+Name[vi]=Run-Ä‘i
+Name[wa]=Kirundi
+Name[zh_CN]=基隆迪语
+Name[zh_HK]=Rundi語
+Name[zh_TW]=Rundi語
+Name[zu]=Isi-Rundi
+[ro]
+Name=Romanian
+Name[af]=Romeens
+Name[ar]=الرومانية
+Name[az]=Rumınca
+Name[be]=РумынÑкаÑ
+Name[bg]=РумънÑки
+Name[bn]=রোমানীয়
+Name[br]=Roumaneg
+Name[bs]=Rumunski
+Name[ca]=Romanès
+Name[cs]=Rumunský
+Name[csb]=Rumùńsczi
+Name[cy]=Romaneg
+Name[da]=Rumænsk
+Name[de]=Rumänisch
+Name[el]=Ρουμανικά
+Name[eo]=Rumana
+Name[es]=Rumano
+Name[et]=Rumeenia
+Name[eu]=Errumaniera
+Name[fa]=رومانیایی
+Name[fi]=Romania
+Name[fr]=Roumain
+Name[fy]=Roemeensk
+Name[ga]=Rómáinis
+Name[gl]=Romanés
+Name[he]=רומנית
+Name[hi]=रोमानियन
+Name[hr]=Rumunjski
+Name[hsb]=Rumunsce
+Name[hu]=Román
+Name[id]=Rumania
+Name[is]=Rúmenska
+Name[it]=Rumeno
+Name[ja]=ルーマニア語
+Name[ka]=რუმინული
+Name[kk]=Румынша
+Name[km]=រូម៉ានី
+Name[ko]=루마니아어
+Name[ku]=Romanî
+Name[lb]=Rumänesch
+Name[lt]=Rumunų
+Name[lv]=RumÄņu
+Name[mi]=Reo Romeinia
+Name[mk]=РоманÑки
+Name[mn]=Роман
+Name[ms]=Romania
+Name[mt]=Rumen
+Name[nb]=Rumensk
+Name[nds]=Rumäänsch
+Name[ne]=रोमनियाली
+Name[nl]=Roemeens
+Name[nn]=Rumensk
+Name[nso]=Se-Romanian
+Name[pa]=ਰੋਮਾਨੀਆਈ
+Name[pl]=Rumuński
+Name[pt]=Romeno
+Name[pt_BR]=Romeno
+Name[ro]=Română
+Name[ru]=РумынÑкий
+Name[rw]=Ikinyarumaniya
+Name[se]=Romániagiella
+Name[sk]=rumunÄina
+Name[sl]=romunsko
+Name[sq]=Rumanisht
+Name[sr]=РумунÑки
+Name[sr@Latn]=Rumunski
+Name[ss]=SiRoma
+Name[sv]=Rumänska
+Name[ta]=உரà¯à®®à¯‡à®©à®¿à®¯à®©à¯
+Name[te]=రొమేనియనà±
+Name[tg]=Романӣ
+Name[th]=ภาษาโรมาเนีย
+Name[tr]=Romence
+Name[tt]=Romança
+Name[uk]=РумунÑька
+Name[uz]=Rumincha
+Name[uz@cyrillic]=Руминча
+Name[vi]=Rô-ma-ni-a
+Name[wa]=Roumin
+Name[zh_CN]=罗马尼亚语
+Name[zh_HK]=羅馬尼亞語
+Name[zh_TW]=羅馬尼亞語
+Name[zu]=Isi-Romania
+[rom]
+Name=Romany
+Name[be]=РаманÑкаÑ
+Name[bg]=РомÑки
+Name[br]=Jipsianek
+Name[bs]=Romanski
+Name[ca]=Caló
+Name[cs]=Romský
+Name[csb]=Rumùńsczi
+Name[de]=Romani
+Name[el]=Ρουμανία
+Name[eo]=Romaa
+Name[es]=Rumaní
+Name[et]=Mustlaskeel
+Name[eu]=Errumaniera
+Name[fa]=رومانی
+Name[fi]=Romani
+Name[fr]=Rromani
+Name[ga]=Romainis
+Name[gl]=Romanés
+Name[he]=רומניה
+Name[hr]=Romanski
+Name[hu]=Lovári cigány
+Name[is]=Rúmenía
+Name[it]=Rom
+Name[ja]=ロマニー語
+Name[ka]=რáƒáƒ›áƒáƒœáƒ£áƒšáƒ˜
+Name[kk]=Цыганша
+Name[km]=រូម៉ានី
+Name[lb]=Romani
+Name[mk]=РомÑки
+Name[ms]=Romania
+Name[nb]=Romani
+Name[nds]=Romaneesch
+Name[ne]=रोमानी
+Name[nl]=Roma
+Name[nn]=Romani
+Name[pa]=ਰੋਮੇ
+Name[pl]=Romski
+Name[pt]=Romani
+Name[pt_BR]=Romani
+Name[ro]=Ţigănească
+Name[ru]=ЦыганÑкий
+Name[se]=Románigiella
+Name[sk]=rómÄina
+Name[sl]=romsko
+Name[sr]=РомÑки
+Name[sr@Latn]=Romski
+Name[sv]=Romanés
+Name[te]=రొమని
+Name[tg]=Романӣ
+Name[th]=ภาษาโรมานี
+Name[tr]=Çingene Dili
+Name[uk]=ЦиганÑька
+Name[vi]=Rô-ma-ny
+Name[zh_CN]=å‰æ™®èµ›è¯­
+Name[zh_TW]=å‰æ™®è³½èªž
+[ru]
+Name=Russian
+Name[af]=Russies
+Name[ar]=الروسية
+Name[az]=Rusca
+Name[be]=РаÑійÑкаÑ
+Name[bg]=РуÑки
+Name[bn]=রà§à¦¶
+Name[br]=Rusianeg
+Name[bs]=Ruski
+Name[ca]=Rus
+Name[cs]=Ruský
+Name[csb]=Rusczi
+Name[cy]=Rwsieg
+Name[da]=Russisk
+Name[de]=Russisch
+Name[el]=Ρωσικά
+Name[eo]=Rusa
+Name[es]=Ruso
+Name[et]=Vene
+Name[eu]=Errusiera
+Name[fa]=روسی
+Name[fi]=Venäjä
+Name[fr]=Russe
+Name[fy]=Russysk
+Name[ga]=Rúisis
+Name[gl]=Ruso
+Name[he]=רוסית
+Name[hi]=रशियन
+Name[hr]=Ruski
+Name[hsb]=Rusce
+Name[hu]=Orosz
+Name[id]=Rusia
+Name[is]=Rússneska
+Name[it]=Russo
+Name[ja]=ロシア語
+Name[ka]=რუსული
+Name[kk]=ОрыÑша
+Name[km]=រុស្សី
+Name[ko]=러시아어
+Name[ku]=Rûsî
+Name[lb]=Russesch
+Name[lt]=Rusų
+Name[lv]=Krievu
+Name[mi]=Reo Ruhia
+Name[mk]=РуÑки
+Name[mn]=ОроÑ
+Name[ms]=Russia
+Name[mt]=Russu
+Name[nb]=Russisk
+Name[nds]=Russ'sch
+Name[ne]=रसियाली
+Name[nl]=Russisch
+Name[nn]=Russisk
+Name[nso]=Se-Russian
+Name[oc]=Rus
+Name[pa]=ਰੂਸੀ
+Name[pl]=Rosyjski
+Name[pt]=Russo
+Name[pt_BR]=Russo
+Name[ro]=Rusă
+Name[ru]=РуÑÑкий
+Name[rw]=Ikirusiya
+Name[se]=Ruoššagiella
+Name[sk]=ruština
+Name[sl]=rusko
+Name[sq]=Rusisht
+Name[sr]=РуÑки
+Name[sr@Latn]=Ruski
+Name[ss]=SiRashiya
+Name[sv]=Ryska
+Name[ta]=இரஷியனà¯
+Name[te]=రషియనà±
+Name[tg]=РӯÑÓ£
+Name[th]=ภาษารัสเซีย
+Name[tr]=Rusça
+Name[tt]=Urısça
+Name[uk]=РоÑійÑька
+Name[uz]=Ruscha
+Name[uz@cyrillic]=РуÑча
+Name[vi]=Nga
+Name[wa]=Rûsse
+Name[xh]=Isirashiya
+Name[zh_CN]=俄语
+Name[zh_HK]=俄語
+Name[zh_TW]=俄語
+Name[zu]=Isi-Rashiya
+[rw]
+Name=Kinyarwanda
+Name[ar]=الكينارواندا
+Name[az]=Kinyarvandaca
+Name[be]=КіньÑрванда
+Name[bg]=КиниÑруанда
+Name[bn]=কিনà§à¦¯à¦¾à¦°à¦“য়াণà§à¦¡à¦¾
+Name[et]=Ruanda
+Name[eu]=Kinyaruanda
+Name[fa]=کینیارواندایی
+Name[fi]=Ruanda
+Name[ga]=Cinearuáindis
+Name[gl]=Quiñaruanda
+Name[he]=קיניירו×נדה
+Name[hi]=किनà¥à¤¯à¤¾à¤°à¤µà¤¾à¤¨à¥à¤¡à¤¾
+Name[hr]=Kinidžaruandski
+Name[hu]=Kinjarvanda
+Name[ja]=ルワンダ語
+Name[ka]=კინიáƒáƒ áƒ•áƒáƒœáƒ“áƒ
+Name[kk]=КиньÑруанда
+Name[km]=គីនយ៉ាវ៉ាន់ដា
+Name[ko]=키ëƒë¥´ì™„다어
+Name[lb]=Ruanda-Sprooch
+Name[mk]=Кинјарванда
+Name[mn]=КинÑрванда
+Name[ne]=किनà¥à¤¯à¤°à¤µà¤¾à¤¨à¥à¤¡à¤¾
+Name[nso]=Se-Kinyarwanda
+Name[pa]=ਕਿਨਯਾਰਵਾਡਾਂ
+Name[ro]=Chiniaruandeză
+Name[ru]=КиньÑруанда
+Name[rw]=Ikinyarwanda
+Name[se]=Kinyarwandagiella
+Name[sk]=rwandÄina
+Name[sl]=kinyarwanda
+Name[sq]=Kinjaruandaisht
+Name[sr]=КинијарвандаÑки
+Name[sr@Latn]=Kinijarvandaski
+Name[ss]=Si-Kinyarwanda
+Name[sv]=Rwanda
+Name[ta]=கினà¯à®¯à®¾à®°à¯à®µà®¾à®£à¯à®Ÿà®¾
+Name[te]=à°•à°¿à°¨à±à°¨à±à°¯à°¾à°°à±à°µà°¾à°‚à°¡à°¾
+Name[tg]=Кинуарвандӣ
+Name[th]=ภาษาคินยาร์วันดา
+Name[tt]=Kinyarwandaça
+Name[uk]=КіньÑрванда
+Name[uz]=Kinyarvanda
+Name[uz@cyrillic]=КинÑрванда
+Name[vi]=Ki-nyă-ouanh-đa
+Name[wa]=Kiniarwanda
+Name[zh_CN]=å¢æ—ºè¾¾è¯­
+Name[zh_HK]=Kinyarwanda語
+Name[zh_TW]=Kinyarwanda語
+Name[zu]=Isi-Kinyarwanda
+[sa]
+Name=Sanskrit
+Name[ar]=سنسيكريتي
+Name[az]=SanskritcÉ™
+Name[be]=СанÑкрыт
+Name[bg]=СанÑкрит
+Name[bn]=সংসà§à¦•à§ƒà¦¤
+Name[cy]=Sansgrit
+Name[el]=ΣανσκÏιτικά
+Name[eo]=Sanskrito
+Name[es]=Sanscrito
+Name[et]=Sanskriti
+Name[eu]=Sanskritoa
+Name[fa]=سانسکریت
+Name[fy]=Sanskryt
+Name[ga]=Sanscrait
+Name[gl]=Sánscrito
+Name[he]=סנסקריט
+Name[hi]=संसà¥à¤•à¥ƒà¤¤
+Name[hu]=Szanszkrit
+Name[id]=Sansekerta
+Name[is]=Sanskrít
+Name[it]=Sanscrito
+Name[ja]=サンスクリット語
+Name[ka]=სáƒáƒœáƒ¡áƒ™áƒ áƒ˜áƒ¢áƒ˜
+Name[kk]=СанÑкрит
+Name[km]=សំស្ក្រឹáž
+Name[ko]=범어
+Name[lt]=Sanskritas
+Name[lv]=Sanskrits
+Name[mk]=СанÑкрит
+Name[mn]=СанÑкрит
+Name[ne]=संसà¥à¤•à¥ƒà¤¤
+Name[nso]=Se-Sanskrit
+Name[pa]=ਸੰਸਕà©à¨°à¨¿à¨¤
+Name[pl]=Sanskryt
+Name[pt]=Sanscrito
+Name[ro]=Sanscrită
+Name[ru]=СанÑкрит
+Name[rw]=Igisansikiriti
+Name[se]=Sanskrihtagiella
+Name[sk]=sanskrit
+Name[sl]=sanskrt
+Name[sq]=Sanskritisht
+Name[sr]=СанÑкрит
+Name[ss]=Si-Sanskrit
+Name[ta]=சமஸà¯à®•à®¿à®°à¯à®¤à®®à¯
+Name[te]=సంసà±à°•à±à°°à±à°¤à°‚
+Name[tg]=СанÑкрит
+Name[th]=ภาษาสันสà¸à¸¤à¸•
+Name[tt]=Sanskritçä
+Name[uk]=СанÑкрит
+Name[uz@cyrillic]=СанÑкрит
+Name[vi]=Xan-s-cợ-ríth
+Name[zh_CN]=梵语
+Name[zh_HK]=梵語
+Name[zh_TW]=梵語
+Name[zu]=Isi-Sanskrit
+[sc]
+Name=Sardinian
+Name[ar]=الساردينية
+Name[be]=СардынÑкаÑ
+Name[bg]=СардинÑки
+Name[bn]=সারà§à¦¡à¦¿à¦¨à¦¿à§Ÿà¦¾à¦¨
+Name[br]=Sardinieg
+Name[bs]=Sardinijski
+Name[ca]=Sard
+Name[cs]=Sardinský
+Name[csb]=Sardińsczi
+Name[cy]=Sardinieg
+Name[da]=Sardinsk
+Name[de]=Sardisch
+Name[el]=ΣαÏδηνιακά
+Name[eo]=Sarda
+Name[es]=Sardo
+Name[et]=Sardiinia
+Name[eu]=Sardiera
+Name[fa]=ساردینی
+Name[fi]=Sardi
+Name[fr]=Sarde
+Name[fy]=Sardinysk
+Name[ga]=Sairdínis
+Name[gl]=Sardo
+Name[he]=סרדינית
+Name[hi]=सारदिनी
+Name[hr]=Sardinijski
+Name[hsb]=Sardinsce
+Name[hu]=Szardíniai
+Name[is]=Sardíníska
+Name[it]=Sardo
+Name[ja]=サルデーニャ語
+Name[ka]=სáƒáƒ áƒ“ინიული
+Name[kk]=Сардинше
+Name[km]=សារឌីណង់
+Name[ko]=사르디니아어
+Name[lb]=Sardinesch
+Name[lt]=Sardinijos
+Name[lv]=Sardīniešu
+Name[mk]=СардиниÑки
+Name[mn]=Сардин
+Name[nb]=Sardisk
+Name[nds]=Sardiensch
+Name[ne]=सरà¥à¤¦à¤¿à¤¨à¤¿à¤¯à¤¨
+Name[nl]=Sardinisch
+Name[nn]=Sardiniansk
+Name[nso]=Se-Sardinian
+Name[pa]=ਸਾਰਡੀਨੀਆਨ
+Name[pl]=Sardyński
+Name[pt]=Sardenho
+Name[ro]=Sardiniană
+Name[ru]=СардинийÑкий
+Name[rw]=Ikinyasaridini
+Name[se]=Sardiniagiella
+Name[sk]=sardínÄina
+Name[sl]=sardinsko
+Name[sq]=Sardinisht
+Name[sr]=СардинијÑки
+Name[sr@Latn]=Sardinijski
+Name[ss]=Si-Sardinian
+Name[sv]=Sardiska
+Name[ta]=சாரà¯à®Ÿà¯€à®©à®¿à®¯à®©à¯
+Name[te]=సారà±à°¡à°¿à°¨à°¿à°¯à°¨à±
+Name[tg]=СардиниÑгӣ
+Name[th]=ภาษาซาร์ดิเนียน
+Name[tt]=Sardinça
+Name[uk]=СардинÑька
+Name[uz]=Sardincha
+Name[uz@cyrillic]=Сардинча
+Name[vi]=Xa-Ä‘i-ni-a
+Name[wa]=Sardinyin
+Name[zh_CN]=æ’’ä¸è¯­
+Name[zh_HK]=è–©ä¸å°¼äºžèªž
+Name[zh_TW]=è–©ä¸å°¼äºžèªž
+Name[zu]=Isi-Sardinian
+[sd]
+Name=Sindhi
+Name[ar]=سندي
+Name[be]=Сіндхі
+Name[bg]=Синдхи
+Name[bn]=সিনà§à¦§à¦¿
+Name[br]=Sindhieg
+Name[eo]=Sinda
+Name[fa]=سیندهی
+Name[ga]=Sindis
+Name[he]=סינדהי
+Name[hi]=सिंधी
+Name[hu]=Szindi
+Name[is]=Shindi
+Name[ja]=シンド語
+Name[ka]=სინდჰი
+Name[kk]=Синдхи
+Name[km]=ស៊ីន្ដី
+Name[ko]=신디어
+Name[lb]=Sindhi-Sprooch
+Name[mk]=Синди
+Name[mn]=Синди
+Name[ne]=सिनà¥à¤§à¥€
+Name[nso]=Se-Sindhi
+Name[pa]=ਸਿੰਧੀ
+Name[ro]=Sindi
+Name[ru]=Синдхи
+Name[rw]=Igisindi
+Name[se]=Sindhigiella
+Name[sk]=sindhÄina
+Name[sl]=sindijsko
+Name[sq]=Sindisht
+Name[sr]=СиндиÑки
+Name[sr@Latn]=Sindiski
+Name[ss]=Si-Sindhi
+Name[ta]=சிநà¯à®¤à®¿
+Name[te]=సింధి
+Name[tg]=Синдхӣ
+Name[th]=ภาษาสินธุ
+Name[tt]=Sindihçä
+Name[uk]=Синдхі
+Name[uz]=Sindxi
+Name[uz@cyrillic]=Синдхи
+Name[vi]=Xin-Ä‘i
+Name[wa]=Sindi
+Name[zh_HK]=Sindhi語
+Name[zh_TW]=Sindhi語
+Name[zu]=Isi-Sindi
+[se]
+Name=Northern Sami
+Name[af]=Noordelike Sami
+Name[ar]=السامي الشمالية
+Name[az]=Åžimali Sami
+Name[be]=Самі (поўнач)
+Name[bg]=Северен Сами
+Name[bn]=উতà§à¦¤à¦° সামি
+Name[br]=Sami, Norzh
+Name[bs]=Sjeverni Sami
+Name[ca]=Sami del nord
+Name[cs]=Severní Sami
+Name[csb]=Nordowi Sami
+Name[cy]=Sami'r Gogledd
+Name[da]=Nordsamisk
+Name[de]=Nördliches Sami
+Name[eo]=Norda Samea
+Name[es]=Samí del norte
+Name[et]=Põhja-saami
+Name[eu]=Samia (iparrekoa)
+Name[fa]=سامی شمالی
+Name[fi]=Pohjoissaame
+Name[fr]=Sami du Nord
+Name[fy]=Noard-Koreaansk
+Name[ga]=Sáimis Thuaidh
+Name[gl]=Sami do Norte
+Name[he]=ס×מית צפונית
+Name[hi]=नारà¥à¤¦à¤°à¥à¤¨ सामी
+Name[hr]=Sjeverni Sami
+Name[hsb]=Sewjernosamisce
+Name[hu]=Északi szami
+Name[is]=Norður Sami
+Name[it]=Sami settentrionale
+Name[ja]=北サーミ語
+Name[ka]=ჩრდილრსáƒáƒáƒ›áƒ˜
+Name[kk]=СолтүÑтік Ñаами
+Name[km]=សាមីជើង
+Name[ko]=ë¶ë¶€ 사미어
+Name[lb]=Nördlecht Sami
+Name[lt]=Å iaurÄ—s Sami
+Name[mk]=Северен Сами
+Name[mn]=Умард Сами
+Name[ms]=Sami Utara
+Name[nb]=Nordsamisk
+Name[nds]=Noord-Saamsch
+Name[ne]=उतà¥à¤¤à¤°à¥€ सामी
+Name[nl]=Noord Sami
+Name[nn]=Nordsamisk
+Name[nso]=Se-Sami sa Lebowa
+Name[pa]=ਉੱਤਰੀ ਸਾਮੀ
+Name[pl]=Północny Sami
+Name[pt]=Sami do Norte
+Name[pt_BR]=Sami do Norte
+Name[ro]=Sami nordică
+Name[ru]=Северное Саами
+Name[rw]=Igisami amajyaruguru
+Name[se]=Davvisámegiella
+Name[sk]=severná saamÄina
+Name[sl]=severno sami
+Name[sq]=Sami Verior
+Name[sr]=СеверноÑамÑки
+Name[sr@Latn]=Severnosamski
+Name[ss]=SiSami sasenyakatfo
+Name[sv]=Samiska
+Name[ta]=நாரà¯à®¤à®©à¯ சாமி
+Name[te]=ఉతà±à°¤à°° సమి
+Name[tg]=Саамаи шимолӣ
+Name[th]=ภาษาซามี ตอนเหนือ
+Name[tt]=Tönyaq Sami
+Name[uk]=Північна Саамі
+Name[uz]=Shimoliy Sami
+Name[uz@cyrillic]=Шимолий Сами
+Name[ven]=Sami ya Devhula
+Name[vi]=Xa-mi (Bắc)
+Name[wa]=Bijhe såmi
+Name[xh]=Sami Yasemntla
+Name[zh_CN]=北部沙米语
+Name[zh_HK]=北薩米語
+Name[zh_TW]=北薩米語
+Name[zu]=Isi-Sami Sase-Ntshonalanga
+[sg]
+Name=Sango
+Name[ar]=السانغو
+Name[az]=Sagno
+Name[be]=Санга
+Name[bg]=Сангро
+Name[bn]=সাংগো
+Name[eo]=Sangoa
+Name[fa]=سانگو
+Name[ga]=Sangóis
+Name[he]=ס×נגו
+Name[hi]=सैनà¥à¤—ो
+Name[hu]=Szangó
+Name[ja]=サンゴ語
+Name[ka]=სáƒáƒœáƒ’áƒ
+Name[kk]=Санго
+Name[km]=សង់ហ្គោ
+Name[lb]=Sango-Sprooch
+Name[mk]=Санго
+Name[mn]=Санго
+Name[ne]=साङà¥à¤—ो
+Name[nso]=Se-Sango
+Name[pa]=ਸਾਂਗੋ
+Name[ro]=Sangă
+Name[ru]=Санго
+Name[rw]=Igisango
+Name[se]=Sangogiella
+Name[sk]=sango
+Name[sl]=sango
+Name[sq]=Sangisht
+Name[sr]=Санго
+Name[ss]=Si-Sango
+Name[ta]=சாஙà¯à®•à¯‹
+Name[te]=సాంగొ
+Name[tg]=Санго
+Name[th]=ภาษาà¹à¸‹à¸‡à¹‚à¸
+Name[tt]=Sangoça
+Name[uk]=Санго
+Name[uz@cyrillic]=Санго
+Name[vi]=Xan-gô
+Name[zh_CN]=桑戈语
+Name[zh_HK]=Sango語
+Name[zh_TW]=Sango語
+Name[zu]=Isi-Sango
+[si]
+Name=Sinhalese
+Name[ar]=السينهالية
+Name[az]=Sinhalca
+Name[be]=СінгальÑкаÑ
+Name[bg]=СингалÑки
+Name[bn]=সিংহলী
+Name[br]=Singaleg
+Name[bs]=Sinhaleški
+Name[ca]=Sinhalès
+Name[cs]=Sinhalský
+Name[csb]=Synagelsczi
+Name[cy]=Sinhaleg
+Name[da]=Sinhalesisk
+Name[de]=Singhalesisch
+Name[eo]=Sinhala
+Name[es]=Sinhalés
+Name[et]=Singaleesi
+Name[eu]=Sinhala
+Name[fa]=سینهالس
+Name[fi]=Sinhali
+Name[fr]=Singhalais
+Name[fy]=Singaleesk
+Name[ga]=Siolóinis
+Name[gl]=Sinhalés
+Name[he]=סינהלזית
+Name[hi]=सिंहली
+Name[hr]=Sinhalski
+Name[hsb]=Singalsce
+Name[hu]=Szingaléz
+Name[is]=Shinhalese
+Name[it]=Cingalese
+Name[ja]=シンãƒãƒ©èªž
+Name[ka]=სენეგáƒáƒšáƒ£áƒ áƒ˜
+Name[kk]=Сингалша
+Name[km]=ស៊ីងហាលីស
+Name[ko]=ì‹ í• ë¼ì–´
+Name[lb]=Singhalesesch
+Name[lt]=Sinhalų
+Name[mk]=СинхалÑки
+Name[mn]=Синхал
+Name[nb]=Singalesisk
+Name[nds]=Singaleesch
+Name[ne]=सिङà¥à¤¹à¤¾à¤²à¥€
+Name[nl]=Sinhalees
+Name[nn]=Singalesisk
+Name[nso]=Se-Sinhalese
+Name[pa]=ਸਿੰਹਾਲਸ਼
+Name[pl]=Syngaleski
+Name[ro]=Sinaleză
+Name[ru]=СингальÑкий
+Name[rw]=Ikinyasinali
+Name[se]=Singalesagiella
+Name[sk]=sinhalÄina
+Name[sl]=sinhalese
+Name[sq]=Sinalezisht
+Name[sr]=СинхалÑки
+Name[sr@Latn]=Sinhalski
+Name[ss]=Si-Sinhalese
+Name[sv]=Singalesiska
+Name[ta]=சிஙà¯à®•à®³à®®à¯
+Name[te]=సింహలీసà±
+Name[tg]=Сингалӣ
+Name[th]=ภาษาสิงหล
+Name[tt]=Sinhalçä
+Name[uk]=СингальÑька
+Name[uz]=Sinxalese
+Name[uz@cyrillic]=СинхалеÑе
+Name[vi]=Xin-ha-li
+Name[wa]=Sinhalès
+Name[zh_CN]=僧伽罗语
+Name[zh_HK]=錫蘭語
+Name[zh_TW]=錫蘭語
+Name[zu]=Isi-Sinhalese
+[sk]
+Name=Slovak
+Name[af]=Slovakies
+Name[ar]=السلوÙاكية
+Name[az]=Slovakca
+Name[be]=СлавацкаÑ
+Name[bg]=Словашки
+Name[bn]=সà§à¦²à§‹à¦­à¦¾à¦•
+Name[br]=Sloveg
+Name[bs]=SlovaÄki
+Name[ca]=Eslovè
+Name[cs]=Slovenský
+Name[csb]=SÅ‚owacczi
+Name[cy]=Sloveg
+Name[da]=Slovakisk
+Name[de]=Slowakisch
+Name[el]=Σλοβακικά
+Name[eo]=Slovaka
+Name[es]=Eslovaco
+Name[et]=Slovaki
+Name[eu]=Eslovakiera
+Name[fa]=اسلواکی
+Name[fi]=Slovakki
+Name[fr]=Slovaque
+Name[fy]=Slovaaks
+Name[ga]=Slóvaicis
+Name[gl]=Eslovaco
+Name[he]=סלובנית
+Name[hi]=सà¥à¤²à¥‹à¤µà¤¾à¤•à¤¨
+Name[hr]=SlovaÄki
+Name[hsb]=SÅ‚owaksce
+Name[hu]=Szlovák
+Name[id]=Slovakia
+Name[is]=Slóvenska
+Name[it]=Slovacco
+Name[ja]=スロãƒã‚­ã‚¢èªž
+Name[ka]=სლáƒáƒ•áƒáƒ™áƒ£áƒ áƒ˜
+Name[kk]=Словакша
+Name[km]=ស្លូវ៉ាគី
+Name[ko]=슬로바키아어
+Name[ku]=Slovakî
+Name[lb]=Slowakesch
+Name[lt]=Slovakų
+Name[lv]=SlovÄku
+Name[mk]=Словачки
+Name[mn]=Словак
+Name[mt]=Slovakk
+Name[nb]=Slovakisk
+Name[nds]=Slowaaksch
+Name[ne]=सà¥à¤²à¥‹à¤­à¤¾à¤•
+Name[nl]=Slowaaks
+Name[nn]=Slovakisk
+Name[oc]=Eslòvac
+Name[pa]=ਸਲੋਵਾਕ
+Name[pl]=SÅ‚owacki
+Name[pt]=Eslovaco
+Name[pt_BR]=Eslovaco
+Name[ro]=Slovacă
+Name[ru]=Словацкий
+Name[rw]=Igisilovake
+Name[se]=Slovákagiella
+Name[sk]=slovenÄina
+Name[sl]=slovaško
+Name[sq]=Sllovakisht
+Name[sr]=Словачки
+Name[sr@Latn]=SlovaÄki
+Name[sv]=Slovakiska
+Name[ta]=சà¯à®²à¯‹à®µà®¾à®•à¯
+Name[te]=à°¸à±à°²à±Šà°µà°¾à°•à±
+Name[tg]=Словакӣ
+Name[th]=ภาษาสโลวัค
+Name[tr]=Slovakça
+Name[tt]=Slovakça
+Name[uk]=Словацька
+Name[uz]=Slovakcha
+Name[uz@cyrillic]=Словакча
+Name[ven]=Musilovaka
+Name[vi]=Xlô-vák
+Name[wa]=Eslovake
+Name[xh]=isiSlovak
+Name[zh_CN]=斯洛ä¼å…‹è¯­
+Name[zh_HK]=斯洛ä¼å…‹èªž
+Name[zh_TW]=斯洛ä¼å…‹èªž
+Name[zu]=Isi-Silovaki
+[sl]
+Name=Slovenian
+Name[af]=Sloveniese
+Name[ar]=السلوÙينية
+Name[az]=SlovencÉ™
+Name[be]=СлавенÑкаÑ
+Name[bg]=СловенÑки
+Name[bn]=সà§à¦²à§‹à¦­à§‡à¦¨à§€à§Ÿ
+Name[br]=Slovenieg
+Name[bs]=SlovenaÄki
+Name[ca]=Eslovè
+Name[cs]=Slovinský
+Name[csb]=Slowensczi
+Name[cy]=Sloveneg
+Name[da]=Slovensk
+Name[de]=Slowenisch
+Name[el]=Σλοβενικά
+Name[eo]=Slovena
+Name[es]=Esloveno
+Name[et]=Sloveeni
+Name[eu]=Esloveniera
+Name[fa]=اسلونیایی
+Name[fi]=Sloveeni
+Name[fr]=Slovène
+Name[fy]=Sloveensk
+Name[ga]=Slóivéinis
+Name[gl]=Esloveno
+Name[he]=סלובנית
+Name[hi]=सà¥à¤²à¥‹à¤µà¥‡à¤¨à¤¿à¤¯à¤¨
+Name[hr]=Slovenski
+Name[hsb]=SÅ‚owjensce
+Name[hu]=Szlovén
+Name[id]=Slovenia
+Name[is]=Slóvenska
+Name[it]=Sloveno
+Name[ja]=スロベニア語
+Name[ka]=სლáƒáƒ•áƒ”ნური
+Name[kk]=Словенше
+Name[km]=ស្លូវ៉ានី
+Name[ko]=슬로베니아어
+Name[ku]=Slovenî
+Name[lb]=Slowenesch
+Name[lt]=Slovėnų
+Name[lv]=Slovēņu
+Name[mk]=Словенечки
+Name[mn]=Словиан
+Name[ms]=Slovenia
+Name[mt]=Sloven
+Name[nb]=Slovensk
+Name[nds]=Sloweensch
+Name[ne]=सà¥à¤²à¥‹à¤­à¥‡à¤¨à¤¿à¤¯à¤¨
+Name[nl]=Sloweens
+Name[nn]=Slovensk
+Name[nso]=Se-Slovenian
+Name[oc]=Eslòvian
+Name[pa]=ਸਲੋਵੀਨੀਆਨ
+Name[pl]=Słoweński
+Name[pt]=Esloveno
+Name[pt_BR]=Esloveno
+Name[ro]=Slovenă
+Name[ru]=СловенÑкий
+Name[rw]=Ikinyasiloveniya
+Name[se]=Slovenagiella
+Name[sk]=slovinÄina
+Name[sl]=slovensko
+Name[sq]=Sllovenisht
+Name[sr]=Словеначки
+Name[sr@Latn]=SlovenaÄki
+Name[ss]=Si-Slovenian
+Name[sv]=Slovenska
+Name[ta]=சà¯à®²à¯‹à®µà¯€à®©à®¿à®¯à®©à¯
+Name[te]=à°¸à±à°²à±Šà°µà±‡à°¨à°¿à°¯à°¨à±
+Name[tg]=Словенӣ
+Name[th]=ภาษาสโลเวเนีย
+Name[tr]=Slovence
+Name[tt]=Slovençä
+Name[uk]=СловенÑька
+Name[uz]=Sloveniancha
+Name[uz@cyrillic]=Словенианча
+Name[vi]=Xlô-ven
+Name[wa]=Eslovenyin
+Name[zh_CN]=斯洛文尼亚语
+Name[zh_HK]=斯洛維尼亞語
+Name[zh_TW]=斯洛維尼亞語
+Name[zu]=Isi-Slovenian
+[sm]
+Name=Samoan
+Name[ar]=الساموية
+Name[be]=Самоа
+Name[bg]=СамоанÑки
+Name[bn]=সামোয়ান
+Name[bs]=Samoanski
+Name[ca]=Samoanès
+Name[cs]=Samojský
+Name[csb]=Samoańsczi
+Name[cy]=Samoeg
+Name[da]=Samoansk
+Name[de]=Samoanisch
+Name[el]=Σαμοανικά
+Name[eo]=Samoa
+Name[es]=Samoano
+Name[et]=Samoa
+Name[eu]=Samoera
+Name[fa]=ساموان
+Name[fi]=Samoa
+Name[fy]=Samoaansk
+Name[ga]=Samóis
+Name[gl]=Samoano
+Name[he]=סמו×ית
+Name[hi]=सामोन
+Name[hr]=Samoanski
+Name[hsb]=Samoasce
+Name[hu]=Szamoai
+Name[id]=Samoa
+Name[it]=Samoano
+Name[ja]=サモア語
+Name[ka]=სáƒáƒ›áƒáƒ
+Name[kk]=Самоа
+Name[km]=សាមូអា
+Name[ko]=사모아어
+Name[lb]=Samoanesch
+Name[lt]=Samoa
+Name[lv]=Samoiešu
+Name[mk]=СамоанÑки
+Name[mn]=Самоан
+Name[nb]=Samoansk
+Name[nds]=Samoaansch
+Name[ne]=सामोआन
+Name[nl]=Samoaans
+Name[nn]=Samoansk
+Name[nso]=Se-Samoan
+Name[pa]=ਸਾਮੋਆਨ
+Name[pl]=Samoański
+Name[pt]=Samoano
+Name[pt_BR]=Samoa
+Name[ro]=Samoană
+Name[ru]=Самоа
+Name[rw]=Igisamowani
+Name[se]=Samoagiella
+Name[sk]=samojÄina
+Name[sl]=samojsko
+Name[sq]=Samonisht
+Name[sr]=СамоанÑки
+Name[sr@Latn]=Samoanski
+Name[ss]=Si-Samoan
+Name[sv]=Samoanska
+Name[ta]=சமோவனà¯
+Name[te]=సమొవనà±
+Name[tg]=Самоанӣ
+Name[th]=ภาษาซาโมน
+Name[tt]=Samoaça
+Name[uk]=СамоанÑька
+Name[uz]=Samoacha
+Name[uz@cyrillic]=Самоача
+Name[vi]=Xa-mô-a
+Name[wa]=Samowan
+Name[zh_CN]=è¨æ‘©äºšè¯­
+Name[zh_HK]=薩摩牙語
+Name[zh_TW]=薩摩牙語
+Name[zu]=Isi-Samoan
+[sn]
+Name=Shona
+Name[ar]=الشونا
+Name[be]=Шона
+Name[bg]=Шона
+Name[bn]=শোনা
+Name[eo]=Åœona
+Name[fa]=شوها
+Name[fi]=Å¡ona
+Name[ga]=Seoinis
+Name[he]=שונה
+Name[hi]=शोना
+Name[hu]=Sona
+Name[ja]=ショナ語
+Name[ka]=შáƒáƒœáƒ
+Name[kk]=Схона
+Name[km]=សូណា
+Name[ko]=쇼나어
+Name[mk]=Шона
+Name[mn]=Шона
+Name[nds]=Schona
+Name[ne]=शोना
+Name[nso]=Se-Shona
+Name[pa]=ਸ਼ੋਨਾ
+Name[ro]=Şonă
+Name[ru]=Схона
+Name[rw]=Igishona
+Name[se]=Å onagiella
+Name[sk]=Å¡ona
+Name[sl]=shona
+Name[sq]=Shonisht
+Name[sr]=ШонÑки
+Name[sr@Latn]=Å onski
+Name[ss]=SiShona
+Name[ta]=ஷோனா
+Name[te]=షొనా
+Name[tg]=Шонӣ
+Name[th]=ภาษาโชนา
+Name[tt]=Şonaça
+Name[uk]=Шона
+Name[uz@cyrillic]=Шона
+Name[vi]=Sô-na
+Name[xh]=Isishona
+Name[zh_CN]=修纳语
+Name[zh_HK]=Shona語
+Name[zh_TW]=Shona語
+Name[zu]=Isi-Shona
+[so]
+Name=Somali
+Name[ar]=صومالي
+Name[be]=СамалійÑкаÑ
+Name[bg]=Сомали
+Name[bn]=সোমালীয়
+Name[br]=Somalieg
+Name[bs]=Somalijski
+Name[ca]=Somalí
+Name[cs]=Somálský
+Name[csb]=Somalijsczi
+Name[da]=Somalisk
+Name[el]=Σομαλικά
+Name[eo]=Somala
+Name[es]=Somalí
+Name[et]=Somaali
+Name[eu]=Somaliera
+Name[fa]=سومالی
+Name[fy]=Somalysk
+Name[ga]=Somáilis
+Name[he]=סומלית
+Name[hi]=सोमाली
+Name[hr]=Somalijski
+Name[hsb]=Somalisce
+Name[hu]=Szomáli
+Name[id]=Somalia
+Name[is]=Sómalska
+Name[it]=Somalo
+Name[ja]=ソマリ語
+Name[ka]=სáƒáƒ›áƒáƒšáƒ£áƒ áƒ˜
+Name[kk]=Сомали
+Name[km]=សូម៉ាលី
+Name[ko]=소ë§ë¦¬ì•„ì–´
+Name[lb]=Somalesch
+Name[lt]=SomalieÄių
+Name[lv]=SomÄlieÅ¡u
+Name[mk]=СомалиÑки
+Name[mn]=Сомали
+Name[ne]=सोमाली
+Name[nl]=Somalisch
+Name[nso]=Se-Somali
+Name[pa]=ਸੋਮਾਲੀ
+Name[pl]=Somalijski
+Name[ro]=Somaleză
+Name[ru]=СомалийÑкий
+Name[rw]=Igisomali
+Name[se]=Somálagiella
+Name[sk]=somálÄina
+Name[sl]=somalsko
+Name[sq]=Somalisht
+Name[sr]=СомалијÑки
+Name[sr@Latn]=Somalijski
+Name[ss]=Si-Somali
+Name[ta]=சோமாலி
+Name[te]=సొమాలి
+Name[tg]=Сомалӣ
+Name[th]=ภาษาโซมาลี
+Name[tt]=Somaliçä
+Name[uk]=СомалійÑька
+Name[uz]=Somalicha
+Name[uz@cyrillic]=Сомалича
+Name[vi]=Xô-ma-li
+Name[wa]=Somalyin
+Name[zh_CN]=索马里语
+Name[zh_HK]=索馬利語
+Name[zh_TW]=索馬利語
+Name[zu]=Isi-Somali
+[sq]
+Name=Albanian
+Name[af]=Albanees
+Name[ar]=ألباني
+Name[az]=Albanca
+Name[be]=ÐлбанÑкаÑ
+Name[bg]=ÐлбанÑки
+Name[bn]=আলবেনীয়
+Name[br]=Albanieg
+Name[bs]=Albanski
+Name[ca]=Albanès
+Name[cs]=Albánský
+Name[csb]=Albańsczi
+Name[cy]=Albaneg
+Name[da]=Albansk
+Name[de]=Albanisch
+Name[el]=Αλβανικά
+Name[eo]=Albana
+Name[es]=Albanés
+Name[et]=Albaania
+Name[eu]=Albaniera
+Name[fa]=آلبانی
+Name[fi]=Albania
+Name[fr]=Albanais
+Name[fy]=Albaansk
+Name[ga]=Albáinis
+Name[gl]=Albanés
+Name[he]=×לבנית
+Name[hi]=अलà¥à¤¬à¤¾à¤¨à¤¿à¤¯à¤¨
+Name[hr]=Albanski
+Name[hsb]=Albansce
+Name[hu]=Albán
+Name[id]=Albania
+Name[is]=Albanskur
+Name[it]=Albanese
+Name[ja]=アルãƒãƒ‹ã‚¢èªž
+Name[ka]=áƒáƒšáƒ‘áƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=Ðлбанша
+Name[km]=អាល់បានី
+Name[ko]=알바니아어
+Name[ku]=Albanî
+Name[lb]=Albanesch
+Name[lt]=Albanų
+Name[lv]=AlbÄņu
+Name[mk]=ÐлбанÑки
+Name[mn]=Ðлбани
+Name[ms]=Albania
+Name[nb]=Albansk
+Name[nds]=Albaansch
+Name[ne]=अलà¥à¤¬à¤¾à¤¨à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Albanisch
+Name[nn]=Albansk
+Name[nso]=Se-Albanian
+Name[pa]=ਅਲਬਾਨੀਅਨ
+Name[pl]=Albański
+Name[pt]=Albanês
+Name[pt_BR]=Albanês
+Name[ro]=Albaneză
+Name[ru]=ÐлбанÑкий
+Name[rw]=Ikinyalubaniya
+Name[se]=Albániagiella
+Name[sk]=albánÄina
+Name[sl]=albansko
+Name[sq]=Shqip
+Name[sr]=ÐлбанÑки
+Name[sr@Latn]=Albanski
+Name[ss]=Si-Albanian
+Name[sv]=Albanska
+Name[ta]=அலà¯à®ªà¯‡à®©à®¿à®¯à®©à¯
+Name[te]=à°…à°²à±à°¬à±‡à°¨à°¿à°¯à°¨à±
+Name[tg]=Ðлбанӣ
+Name[th]=ภาษาอัลเบเนีย
+Name[tt]=Albança
+Name[uk]=ÐлбанÑька
+Name[uz]=Albancha
+Name[uz@cyrillic]=Ðлбанча
+Name[vi]=An-ba-ni
+Name[wa]=Albanyin
+Name[zh_CN]=阿尔巴尼亚语
+Name[zh_HK]=阿爾巴尼亞語
+Name[zh_TW]=阿爾巴尼亞語
+Name[zu]=Isi-Albanian
+[sr]
+Name=Serbian
+Name[af]=Serbiese
+Name[ar]=الصربية
+Name[az]=SerbcÉ™
+Name[be]=СербÑкаÑ
+Name[bg]=СръбÑки
+Name[bn]=সারà§à¦¬à§€à§Ÿ
+Name[br]=Serbeg
+Name[bs]=Srpski
+Name[ca]=Serbi
+Name[cs]=Srbský
+Name[csb]=Serbsczi
+Name[cy]=Serbieg
+Name[da]=Serbisk
+Name[de]=Serbisch
+Name[el]=ΣεÏβικά
+Name[eo]=Serba
+Name[es]=Serbio
+Name[et]=Serbia
+Name[eu]=Serbiera
+Name[fa]=صربستانی
+Name[fi]=Serbia
+Name[fr]=Serbe
+Name[fy]=Servysk
+Name[ga]=Seirbis
+Name[gl]=Sérvio
+Name[he]=סרבית
+Name[hi]=सरà¥à¤¬à¤¿à¤¯à¤¨
+Name[hr]=Srpski
+Name[hsb]=Serbisce
+Name[hu]=Szerb
+Name[id]=Serbia
+Name[is]=Serbneska
+Name[it]=Serbo
+Name[ja]=セルビア語
+Name[ka]=სერბული
+Name[kk]=Сербше
+Name[km]=សែប៊ី
+Name[ko]=세르비아어
+Name[ku]=Sirbî
+Name[lb]=Serbesch
+Name[lt]=Serbų
+Name[lv]=Serbu
+Name[mk]=СрпÑки
+Name[mn]=Серб
+Name[ms]=Serbia
+Name[mt]=Serb
+Name[nb]=Serbisk
+Name[nds]=Serbsch
+Name[ne]=सरà¥à¤¬à¤¿à¤¯à¤¾à¤²à¥€
+Name[nl]=Servisch
+Name[nn]=Serbisk
+Name[nso]=Se-Serbian
+Name[pa]=ਸਰਬੀਅਨ
+Name[pl]=Serbski
+Name[pt]=Sérvio
+Name[pt_BR]=Sérvio
+Name[ro]=Sîrbă
+Name[ru]=СербÑкий
+Name[rw]=Ikinyaseribiya
+Name[se]=Serbiagiella
+Name[sk]=srbÄina
+Name[sl]=srbsko
+Name[sq]=Serbisht
+Name[sr]=СрпÑки
+Name[sr@Latn]=Srpski
+Name[ss]=Si-Serbian
+Name[sv]=Serbiska
+Name[ta]=செரà¯à®ªà®¿à®¯à®©à¯
+Name[te]=సెరà±à°¬à°¿à°¯à°¨à±
+Name[tg]=Сербӣ
+Name[th]=ภาษาเซอร์เบีย
+Name[tr]=Sırpça
+Name[tt]=Serbçä
+Name[uk]=СербÑька
+Name[uz]=Serbcha
+Name[uz@cyrillic]=Сербча
+Name[vi]=Xéc-bi
+Name[wa]=Serbe
+Name[zh_CN]=塞尔维亚语
+Name[zh_HK]=塞爾維亞語
+Name[zh_TW]=塞爾維亞語
+Name[zu]=Isi-Serbian
+[sr@Latn]
+Name=Serbian Latin
+Name[be]=СербÑÐºÐ°Ñ (лацініца)
+Name[bg]=СръбÑки латинÑки
+Name[br]=Serbeg latin
+Name[bs]=Srpski latinica
+Name[ca]=Serbi llatí
+Name[cs]=Srbský (latinka)
+Name[csb]=Serbsczi (łacëńsczi)
+Name[cy]=Serbieg Lladin
+Name[da]=Serbisk latin
+Name[de]=Serbisch (lat. Alphabet)
+Name[el]=ΣεÏβικά (Λατινικά)
+Name[eo]=Serba Latina alfabeto
+Name[es]=Latín Serbio
+Name[et]=Serbia (ladina)
+Name[eu]=Serbiera (Latina)
+Name[fa]=صربستانی
+Name[fi]=Serbian latina
+Name[fr]=Serbe Latin
+Name[fy]=Servysk Latijnsk
+Name[ga]=Seirbis (aibítir Laidineach)
+Name[gl]=Sérbio Latino
+Name[he]=לטינית סרבית
+Name[hr]=Srpski latinica
+Name[hu]=Szerb (latin betűs)
+Name[is]=Serbnesk latína
+Name[it]=Serbo latino
+Name[ja]=セルビア語 (ラテン文字)
+Name[ka]=სერბული ლáƒáƒ—ინური
+Name[kk]=Сербше (Латын)
+Name[km]=សែប៊ី (ឡាážáž¶áŸ†áž„)
+Name[ku]=Sirbiya Latînî
+Name[lb]=Latäinescht Serbesch
+Name[lt]=Serbų lotynų
+Name[lv]=Serbu latīņu
+Name[mk]=СрпÑки (латиница)
+Name[ms]=Latin Serbia
+Name[nb]=Serbisk (latinsk)
+Name[nds]=Serbsch (latiensch Schrift)
+Name[ne]=सरà¥à¤¬à¤¿à¤¯à¤¾à¤²à¥€ लà¥à¤¯à¤¾à¤Ÿà¤¿à¤¨
+Name[nl]=Servisch Latijn
+Name[nn]=Serbisk, latinsk
+Name[pa]=ਸਰਬੀਅਨ ਲੈਟਿਨ
+Name[pl]=Serbski łaciński
+Name[pt]=Sérvio Latino
+Name[pt_BR]=Sérvio Latino
+Name[ro]=Sîrbă latină
+Name[ru]=СербÑкий латинницей
+Name[se]=Serbialaš latiidnagiella
+Name[sk]=srbÄina (latinka)
+Name[sl]=srbsko latinsko
+Name[sr]=СрпÑки латинични
+Name[sr@Latn]=Srpski latiniÄni
+Name[sv]=Latinsk serbiska
+Name[te]=సెరà±à°¬à°¿à°¯à°¨à± లాటినà±
+Name[tg]=Лотини СербиÑвӣ
+Name[th]=ภาษาละตินเซอร์เบีย
+Name[tr]=Sırpça Latin
+Name[uk]=СербÑька (латинь)
+Name[uz]=Serbcha (Lotin)
+Name[uz@cyrillic]=Сербча (Лотин)
+Name[vi]=Xéc-bi (La-tinh)
+Name[wa]=Siebe (alfabet latén)
+Name[zh_CN]=塞尔维亚语(拉ä¸)
+Name[zh_TW]=賽爾維亞拉ä¸èªž
+[ss]
+Name=Swati
+Name[ar]=السواتي
+Name[az]=Svati
+Name[be]=Сваці
+Name[bg]=Суази
+Name[bn]=সোয়াতি
+Name[et]=Svaasi
+Name[fa]=سواتی
+Name[fi]=Swazi
+Name[ga]=Sasuatais
+Name[he]=סוו×טי
+Name[hi]=सà¥à¤µà¤¾à¤¤à¥€
+Name[hu]=Szvati
+Name[ja]=スワティ語
+Name[ka]=სვáƒáƒ¢áƒ˜
+Name[kk]=Свати
+Name[km]=ស្វាទី
+Name[ko]=스와티어
+Name[lb]=Swazi
+Name[mk]=Свати
+Name[mn]=Свати
+Name[ne]=सà¥à¤µà¤¾à¤¤à¥€
+Name[nso]=Se-Swati
+Name[pa]=ਸਵਾਟੀ
+Name[ro]=Suată
+Name[ru]=Свати
+Name[rw]=Igiswati
+Name[se]=Svatigiella
+Name[sk]=swati
+Name[sl]=swati
+Name[sq]=Suatisht
+Name[sr]=Свати
+Name[sr@Latn]=Svati
+Name[ss]=SiSwati
+Name[sv]=Swazi
+Name[ta]=சà¯à®µà®¾à®¤à®¿
+Name[te]=à°¸à±à°µà°¾à°¤à°¿
+Name[tg]=Сватӣ
+Name[th]=ภาษาสวาตี
+Name[tt]=Swatça
+Name[uk]=Суаті
+Name[uz]=Svati
+Name[uz@cyrillic]=Свати
+Name[vi]=Xouă-ti
+Name[wa]=Suwati
+Name[xh]=Isiswati
+Name[zh_CN]=斯瓦特语
+Name[zh_HK]=Swati語
+Name[zh_TW]=Swati語
+Name[zu]=Isi-Swati
+[st]
+Name=Sotho, Southern
+Name[af]=Sotho, Suid
+Name[ar]=السوتو الشمالية
+Name[az]=Sotho, Cənubi
+Name[be]=Сота (поўдзень)
+Name[bg]=Южен Сото
+Name[bn]=সোথো, দকà§à¦·à¦¿à¦£
+Name[br]=Soto, Su
+Name[bs]=Soto, Južni
+Name[ca]=Sotho del sud
+Name[cs]=Sotho, Jižní
+Name[csb]=Sotho, Pôłniowi
+Name[cy]=Sotho, De
+Name[da]=Sotho, syd
+Name[de]=Südliches Sotho
+Name[eo]=Suda Sota
+Name[es]=Sotho del sur
+Name[et]=Lõuna-sotho
+Name[eu]=Sothoera (egoaldekoa)
+Name[fa]=سوتوی جنوبی
+Name[fi]=Sotho
+Name[fr]=Sotho du Sud
+Name[fy]=Sotho, Súd
+Name[ga]=Sótó Theas
+Name[gl]=Sotho do sur
+Name[he]=סותו דרומית
+Name[hi]=सोथो, दकà¥à¤·à¤¿à¤£à¥€
+Name[hr]=Sotho, Južni
+Name[hsb]=Sotho (juh)
+Name[hu]=Sotho (déli)
+Name[is]=Sotho, suður
+Name[it]=Sotho meridionale
+Name[ja]=å—ソト語
+Name[ka]=სáƒáƒ›áƒ®áƒ áƒ”თ სáƒáƒ¢áƒ
+Name[kk]=ОңтүÑтік Ñото
+Name[km]=សូធូ​ážáž¶áž„​ážáŸ’បូង
+Name[ko]=남부 소토어
+Name[lb]=Südlecht Sotho
+Name[lt]=Sotho, Pietų
+Name[mk]=Сото, јужен
+Name[mn]=Сото, Өмнөд
+Name[ms]=Sotho, Selatan
+Name[nb]=Sotho, Sørlig
+Name[nds]=Sotho, Sööd
+Name[ne]=सोथो, दकà¥à¤·à¤¿à¤£à¥€
+Name[nl]=Sotho, Zuid
+Name[nn]=Sotho, sør
+Name[nso]=Sesotho, sa Borwa
+Name[pa]=ਸੋਥੋ, ਦੱਖਣੀ
+Name[pl]=Sotho, Południowy
+Name[pt]=Sotho do Sul
+Name[pt_BR]=Sotho, Sul
+Name[ro]=Soto sudică
+Name[ru]=Юж. Сото
+Name[rw]=Igisotho, Amajyepfo
+Name[se]=Sothogiella, lulli
+Name[sk]=južná sothÄina
+Name[sl]=sotho, južni
+Name[sq]=Sothe Jugore
+Name[sr]=Сото, јужни
+Name[sr@Latn]=Soto, južni
+Name[ss]=SiSotho, saseningizimo
+Name[sv]=Sydsotho
+Name[ta]=சோதà¯à®¤à¯‹, தெனà¯
+Name[te]=సోతొ, దకà±à°·à°¿à°£
+Name[th]=ภาษาโซโธ ตอนใต้
+Name[tt]=Sothoça, Könyaq
+Name[uk]=Сото, Південна
+Name[uz]=Sotxo, Janubiy
+Name[uz@cyrillic]=Сотхо, Жанубий
+Name[ven]=Sotho, Tshipembe
+Name[vi]=Xô-tô (nam)
+Name[wa]=Soto (nonne)
+Name[xh]=Isisuthu, Sasemzantsi
+Name[zh_CN]=索托,å—部
+Name[zh_HK]=梭托語,å—部
+Name[zh_TW]=梭托語,å—部
+Name[zu]=Isi-Suthu, Sase-Mzantsi
+[su]
+Name=Sundanese
+Name[ar]=سوداني
+Name[az]=Sundanca
+Name[be]=СунданÑкаÑ
+Name[bg]=СунданÑки
+Name[bn]=সà§à¦¨à§à¦¦à¦¾à¦¨à¦¿à¦œ
+Name[br]=Soudaneg
+Name[bs]=Sundaneški
+Name[ca]=Sundanès
+Name[cs]=Sundanský
+Name[csb]=Sudańsczi
+Name[cy]=Sundaneg
+Name[da]=Sundansk
+Name[de]=Sundanesisch
+Name[eo]=Sunda
+Name[es]=Sudanés
+Name[et]=Sunda
+Name[eu]=Sundanera
+Name[fa]=ساندانیز
+Name[fi]=Sunda
+Name[fr]=Soudanais
+Name[fy]=Soendaneesk
+Name[ga]=Sundais
+Name[gl]=Sundanés
+Name[he]=סודנית
+Name[hi]=सूडानी
+Name[hsb]=Sundanesce
+Name[hu]=Szundanéz
+Name[id]=Sunda
+Name[it]=Sudanese
+Name[ja]=スンダ語
+Name[ka]=სუდáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=Суданша
+Name[km]=ស៊ូដង់
+Name[ko]=수단어
+Name[lb]=Sudanesesch
+Name[lt]=SudanieÄių
+Name[lv]=SudÄnieÅ¡u
+Name[mk]=СунданÑки
+Name[mn]=Сундан
+Name[nb]=Sundanesisk
+Name[nds]=Sundaneesch
+Name[ne]=सà¥à¤¡à¤¾à¤¨à¥€
+Name[nl]=Sundanees
+Name[nn]=Sundanesisk
+Name[nso]=Se-Sundan
+Name[pa]=ਸੂਡਾਨੀਅਸ
+Name[pl]=Sudański
+Name[pt]=Sudanês
+Name[pt_BR]=Sudanês
+Name[ro]=Sudaneză
+Name[ru]=СуданÑкий
+Name[rw]=Ikinyasundani
+Name[se]=Sundanesagiella
+Name[sk]=sundÄina
+Name[sl]=sudansko
+Name[sq]=Sundanezisht
+Name[sr]=СунданÑки
+Name[sr@Latn]=Sundanski
+Name[ss]=Si-Sundanese
+Name[sv]=Sundanesiska
+Name[ta]=சூடானீஸà¯
+Name[te]=సనà±à°¦à°¨à±€à°¸à±
+Name[tg]=Санданизӣ
+Name[th]=ภาษาซูดาน
+Name[tt]=Sundanesçä
+Name[uk]=СунданÑька
+Name[uz]=Sundancha
+Name[uz@cyrillic]=Сунданча
+Name[vi]=Xun-Ä‘a-ni
+Name[wa]=Soudanès
+Name[zh_CN]=巽他语
+Name[zh_HK]=Sundanese語
+Name[zh_TW]=Sundanese語
+Name[zu]=Isi-Sundanese
+[sv]
+Name=Swedish
+Name[af]=Sweeds
+Name[ar]=السويدية
+Name[az]=İsveçcə
+Name[be]=ШведÑкаÑ
+Name[bg]=ШведÑки
+Name[bn]=সà§à¦‡à¦¡à¦¿à¦¶
+Name[br]=Svedeg
+Name[bs]=Å vedski
+Name[ca]=Suec
+Name[cs]=Švédský
+Name[csb]=Szwedzczi
+Name[cy]=Swedeg
+Name[da]=Svensk
+Name[de]=Schwedisch
+Name[el]=Σουηδικά
+Name[eo]=Sveda
+Name[es]=Sueco
+Name[et]=Rootsi
+Name[eu]=Suediera
+Name[fa]=سوئدی
+Name[fi]=Ruotsi
+Name[fr]=Suédois
+Name[fy]=Sweedsk
+Name[ga]=Sualainnis
+Name[gl]=Sueco
+Name[he]=שבדית
+Name[hi]=सà¥à¤µà¥€à¤¡à¤¿à¤¶
+Name[hr]=Å vedski
+Name[hsb]=Å wedsce
+Name[hu]=Svéd
+Name[id]=Swedia
+Name[is]=Sænska
+Name[it]=Svedese
+Name[ja]=スウェーデン語
+Name[ka]=შვედური
+Name[kk]=Шведше
+Name[km]=ស៊ុយអែដ
+Name[ko]=스웨ë´ì–´
+Name[ku]=Swêdî
+Name[lb]=Schwedesch
+Name[lt]=Švedų
+Name[lv]=Zviedru
+Name[mi]=Reo Wïtana
+Name[mk]=ШведÑки
+Name[mn]=Швед
+Name[mt]=Svediż
+Name[nb]=Svensk
+Name[nds]=Sweedsch
+Name[ne]=सà¥à¤µà¤¿à¤¡à¥‡à¤¨à¥€
+Name[nl]=Zweeds
+Name[nn]=Svensk
+Name[nso]=Se-Swedish
+Name[oc]=Suedès
+Name[pa]=ਸਵੀਡਿਸ਼
+Name[pl]=Szwedzki
+Name[pt]=Sueco
+Name[pt_BR]=Sueco
+Name[ro]=Suedeză
+Name[ru]=ШведÑкий
+Name[rw]=Ikinyasuwede
+Name[se]=Ruoŧagiella
+Name[sk]=Å¡védÄina
+Name[sl]=Å¡vedsko
+Name[sq]=Suedisht
+Name[sr]=ШведÑки
+Name[sr@Latn]=Å vedski
+Name[ss]=SiSwidi
+Name[sv]=Svenska
+Name[ta]=சà¯à®µà¯€à®Ÿà®¿à®·à¯
+Name[te]=à°¸à±à°µà±€à°¡à°¿à°·à±
+Name[tg]=Шведӣ
+Name[th]=ภาษาสวีดิช
+Name[tr]=İsveççe
+Name[tt]=İswäcçä
+Name[uk]=ШведÑька
+Name[uz]=Shvedcha
+Name[uz@cyrillic]=Шведча
+Name[vi]=Thuỵ-điển
+Name[wa]=Suwedwès
+Name[zh_CN]=瑞典语
+Name[zh_HK]=瑞典語
+Name[zh_TW]=瑞典語
+Name[zu]=Isi-Swidishi
+[sw]
+Name=Swahili
+Name[ar]=سواحلي
+Name[az]=SvahilcÉ™
+Name[be]=Суахілі
+Name[bg]=Суахили
+Name[bn]=সোয়াহিলি
+Name[ca]=Suahili
+Name[cs]=Svahilský
+Name[de]=Suaheli
+Name[el]=Σουαχίλι
+Name[eo]=Svahila
+Name[es]=Suahili
+Name[et]=Suahiili
+Name[eu]=Swahiliera
+Name[fa]=سواهیلی
+Name[ga]=Svahaílis
+Name[he]=סוו×הילי
+Name[hi]=सà¥à¤µà¤¾à¤¹à¤¿à¤²à¥€
+Name[hr]=Svahili
+Name[hu]=Szvahili
+Name[ja]=スワヒリ語
+Name[ka]=სუáƒáƒ°áƒ˜áƒšáƒ˜
+Name[kk]=Суахили
+Name[km]=ស្វាហ៊ីលី
+Name[ko]=스와ížë¦¬ì–´
+Name[lt]=Suahili
+Name[lv]=Svahili
+Name[mk]=Свахили
+Name[mn]=Свахил
+Name[ne]=सà¥à¤µà¤¾à¤¹à¤¿à¤²à¥€
+Name[nso]=Se-Swahili
+Name[pa]=ਸਵਾਹਿਲੀ
+Name[ro]=Suahileză
+Name[ru]=Суахили
+Name[rw]=Igiswayili
+Name[se]=Svahilagiella
+Name[sk]=svahilÄina
+Name[sl]=svahili
+Name[sq]=Suailisht
+Name[sr]=Свахили
+Name[sr@Latn]=Svahili
+Name[ss]=SiSwahili
+Name[ta]=ஸà¯à®µà®¾à®¹à®¿à®²à®¿
+Name[te]=à°¸à±à°µà°¾à°¹à°¿à°²à°¿
+Name[tg]=Свахили
+Name[th]=ภาษาสวาฮิลี
+Name[tt]=Swahiliçä
+Name[uk]=Суахілі
+Name[uz]=Svaxili
+Name[uz@cyrillic]=Свахили
+Name[vi]=Xouă-hi-li
+Name[wa]=Suwahili
+Name[zh_CN]=斯瓦希里语
+Name[zh_HK]=æ–¯è¯è¥¿é‡Œèªž
+Name[zh_TW]=æ–¯è¯è¥¿é‡Œèªž
+Name[zu]=Isi-Swahili
+[ta]
+Name=Tamil
+Name[af]=Tamilies
+Name[ar]=التاميلية
+Name[az]=Tamil Dili
+Name[be]=ТамільÑкаÑ
+Name[bg]=ТамилÑки
+Name[bn]=তামিল
+Name[br]=Tamouleg
+Name[bs]=Tamilski
+Name[ca]=Tàmil
+Name[cs]=Tamilský
+Name[csb]=Tamilsczi
+Name[da]=Tamilsk
+Name[eo]=Tamila
+Name[et]=Tamili
+Name[eu]=Tamilera
+Name[fa]=تامیل
+Name[fi]=Tamili
+Name[fr]=Tamoul
+Name[ga]=Tamailis
+Name[he]=טמילית
+Name[hi]=तमिल
+Name[hr]=Tamilski
+Name[hsb]=Tamilsce
+Name[is]=Tamílska
+Name[ja]=タミル語
+Name[ka]=თáƒáƒ›áƒ˜áƒšáƒ£áƒ áƒ˜
+Name[kk]=Тамилша
+Name[km]=ážáž¶áž˜áž¸áž›
+Name[ko]=타밀어
+Name[lt]=Tamilų
+Name[lv]=Tamilu
+Name[mi]=Reo Ãnia tonga
+Name[mk]=ТамилÑки
+Name[mn]=Тамил
+Name[nds]=Tamielsch
+Name[ne]=तामिल
+Name[nn]=Tamilsk
+Name[nso]=Se-Tamil
+Name[pa]=ਤਾਮਿਲ
+Name[pl]=Tamiljski
+Name[ro]=Tamilă
+Name[ru]=ТамильÑкий
+Name[rw]=Igitamili
+Name[se]=Tamilgiella
+Name[sk]=tamilÄina
+Name[sl]=tamilsko
+Name[sq]=Tamilisht
+Name[sr]=ТамилÑки
+Name[sr@Latn]=Tamilski
+Name[ss]=Si-Tamil
+Name[ta]=தமிழà¯
+Name[te]=తమిళం
+Name[tg]=Тамилӣ
+Name[th]=ภาษาทมิฬ
+Name[tr]=Tamil Dili
+Name[tt]=Tamilça
+Name[uk]=ТамільÑька
+Name[uz]=Tamilcha
+Name[uz@cyrillic]=Тамилча
+Name[vi]=Ta-min
+Name[wa]=Tamoul
+Name[zh_CN]=泰米尔语
+Name[zh_HK]=å¦ç±³çˆ¾èªž
+Name[zh_TW]=å¦ç±³çˆ¾èªž
+Name[zu]=Isi-Tamili
+[te]
+Name=Telugu
+Name[ar]=التيلوغو
+Name[az]=Teluguca
+Name[be]=ТÑлугу
+Name[bg]=Телугу
+Name[bn]=তেলেগà§
+Name[br]=Telegu
+Name[eo]=Telugua
+Name[fa]=تلوگو
+Name[fr]=Télougou
+Name[fy]=Telûgû
+Name[ga]=Teileagúis
+Name[he]=טלוגו
+Name[hi]=तेलà¥à¤—à¥
+Name[ja]=テルグ語
+Name[ka]=ტელუგუ
+Name[kk]=Телугу
+Name[km]=ážáŸáž›áž¼áž áŸ’áž‚áž¼
+Name[ko]=테루그어
+Name[mk]=Телугу
+Name[mn]=ТÑлүгү
+Name[ne]=तेलà¥à¤—à¥
+Name[nso]=Se-Telugu
+Name[pa]=ਤੇਲਗੂ
+Name[ro]=Telugă
+Name[ru]=Телугу
+Name[rw]=Igitelugu
+Name[se]=Telugugiella
+Name[sk]=telugÄina
+Name[sl]=telugu
+Name[sq]=Talugisht
+Name[sr]=ТелугÑки
+Name[sr@Latn]=Telugski
+Name[ss]=Si-Telugu
+Name[ta]=தெலà¯à®™à¯à®•à¯
+Name[te]=తెలà±à°—à±
+Name[tg]=ТелугуÑгӣ
+Name[th]=ภาษาเตลูà¸à¸¹
+Name[tt]=Teluguça
+Name[uk]=Телугу
+Name[uz@cyrillic]=Телугу
+Name[vi]=Te-lu-gu
+Name[wa]=Telougou
+Name[zh_CN]=æ³°å¢å›ºè¯­
+Name[zh_HK]=特拉å¤èªž
+Name[zh_TW]=特拉å¤èªž
+Name[zu]=Isi-Telugu
+[tg]
+Name=Tajik
+Name[af]=Tajikees
+Name[ar]=طاجيكي
+Name[az]=TacikcÉ™
+Name[be]=ТаджыцкаÑ
+Name[bg]=ТаджикÑки
+Name[bn]=তাজিক
+Name[br]=Tajiek
+Name[bs]=TadžiÄki
+Name[cs]=Tádžikský
+Name[csb]=Tadżëcczi
+Name[de]=Tadschikisch
+Name[el]=Τατζικικά
+Name[eo]=TaÄika
+Name[es]=Tayiko
+Name[et]=Tadžiki
+Name[eu]=Tadjikera
+Name[fa]=تاجیک
+Name[fi]=Tadžikki
+Name[fr]=Tadjik
+Name[fy]=Tadzjyksk
+Name[ga]=Táidsícis
+Name[gl]=Taxico
+Name[he]=טג'יקית
+Name[hi]=ताजिक
+Name[hr]=Tadžik
+Name[hsb]=Tadźikisce
+Name[hu]=Tadzsik
+Name[it]=Tagicco
+Name[ja]=タジク語
+Name[ka]=ტáƒáƒ¯áƒ˜áƒ™áƒ£áƒ áƒ˜
+Name[kk]=Тәжікше
+Name[km]=ážáž¶ážŠáž áŸ’ស៊ីគីស្ážáž„់
+Name[ko]=타ì§ì–´
+Name[lb]=Tadschikesch
+Name[lt]=Tadžikų
+Name[lv]=Tadžiku
+Name[mk]=ТаџикиÑтанÑки
+Name[mn]=Тажик
+Name[nb]=Tadsjikisk
+Name[nds]=Tadschiiksch
+Name[ne]=ताजिक
+Name[nl]=Tajiks
+Name[nn]=Tadsjikisk
+Name[nso]=Se-Tajik
+Name[pa]=ਤਾਜਿਕ
+Name[pl]=Tadżycki
+Name[ro]=Tajică
+Name[ru]=ТаджикÑкий
+Name[rw]=Igitajika
+Name[se]=Tažihkagiella
+Name[sk]=tadžiÄtina
+Name[sl]=tadžiško
+Name[sq]=Taxhikisht
+Name[sr]=ТаџикиÑтанÑки
+Name[sr@Latn]=Tadžikistanski
+Name[ss]=Si-Tajik
+Name[sv]=Tadzjikiska
+Name[ta]=தஜிகà¯
+Name[te]=తాజికà±
+Name[tg]=Тоҷикӣ
+Name[th]=ภาษาทาจิà¸à¸´à¸ªà¸–าน
+Name[tt]=Tajıqça
+Name[uk]=Таджицька
+Name[uz]=Tojikcha
+Name[uz@cyrillic]=Тожикча
+Name[vi]=Ta-gíc
+Name[wa]=Tadjik
+Name[zh_CN]=å¡”å‰å…‹è¯­
+Name[zh_HK]=å¡”å‰å…‹èªž
+Name[zh_TW]=å¡”å‰å…‹èªž
+Name[zu]=Isi-Tajik
+[th]
+Name=Thai
+Name[af]=Thaïs
+Name[ar]=التايلاندية
+Name[az]=Tayca
+Name[be]=ТайÑкаÑ
+Name[bg]=ТайÑки
+Name[bn]=থাই
+Name[br]=Tailh
+Name[bs]=Tajlandski
+Name[cs]=Thajský
+Name[csb]=Tajsczi
+Name[da]=Thailandsk
+Name[el]=Ταϊλανδικά
+Name[eo]=Taja
+Name[es]=Tailandés
+Name[et]=Tai
+Name[eu]=Thailandiera
+Name[fa]=تایلندی
+Name[fr]=Thaïlandais
+Name[fy]=Taaisk
+Name[ga]=Téalainnis
+Name[gl]=Tailandés
+Name[he]=ת×ילנדית
+Name[hi]=थाई
+Name[hr]=Tajlandski
+Name[hsb]=Taisce
+Name[id]=Thailand
+Name[is]=Tælenska
+Name[it]=Thailandese
+Name[ja]=タイ語
+Name[ka]=ტáƒáƒ˜
+Name[kk]=Тайша
+Name[km]=ážáŸƒ
+Name[ko]=타ì´ì–´
+Name[ku]=Tay
+Name[lt]=TailandieÄių
+Name[lv]=Taizemiešu
+Name[mk]=ТајландÑки
+Name[mn]=Тай
+Name[mt]=Tai
+Name[ne]=थाई
+Name[nl]=Thais
+Name[nn]=Thailandsk
+Name[nso]=Se-Thai
+Name[oc]=Tai
+Name[pa]=ਥਾਈ
+Name[pl]=Tajski
+Name[pt]=Tailandês
+Name[ro]=Tailandeză
+Name[ru]=ТайÑкий
+Name[rw]=Igitayi
+Name[se]=Thaigiella
+Name[sk]=thajÄina
+Name[sl]=tajsko
+Name[sq]=Tajlandisht
+Name[sr]=ТајландÑки
+Name[sr@Latn]=Tajlandski
+Name[ss]=Si-Thai
+Name[sv]=Thailändska
+Name[ta]=தாயà¯
+Name[te]=థాయి
+Name[tg]=Тайландӣ
+Name[th]=ภาษาไทย
+Name[tt]=Tayça
+Name[uk]=ТайÑька
+Name[uz]=Taycha
+Name[uz@cyrillic]=Тайча
+Name[vi]=Thái
+Name[wa]=Taylandès
+Name[zh_CN]=泰语
+Name[zh_HK]=泰國語
+Name[zh_TW]=泰國語
+Name[zu]=Isi-Thayi
+[ti]
+Name=Tigrinya
+Name[ar]=التيغرينيا
+Name[az]=Tigrinyaca
+Name[be]=ТыгрыньÑ
+Name[bg]=ТигринÑ
+Name[bn]=টিগà§à¦°à¦¿à¦¨à§à¦¯à¦¾
+Name[de]=Tigrinja
+Name[eo]=Tigraja
+Name[et]=Tigrinja
+Name[fa]=تیگرینیا
+Name[fi]=Tigrinja
+Name[fr]=Tigrigna
+Name[fy]=Tigrysk
+Name[ga]=Tigrinis
+Name[gl]=Tigrignan
+Name[he]=טיגריניה
+Name[hi]=टिगà¥à¤°à¤¿à¤¨à¥à¤¯à¤¾
+Name[hsb]=Tigrinja
+Name[hu]=Tigrinja
+Name[ja]=ティグリニア語
+Name[ka]=ტიგრინიáƒ
+Name[kk]=ТигриньÑ
+Name[km]=ទីក្រីនយ៉ា
+Name[ko]=티그리ëƒì–´
+Name[lb]=Tigrinja-Sprooch
+Name[mk]=Тигринја
+Name[mn]=Тигрин
+Name[ne]=तिगà¥à¤°à¤¿à¤¨à¥à¤¯
+Name[nn]=Tigrinja
+Name[nso]=Se-Tigrinya
+Name[pa]=ਤਿਗਰੀਅਨ
+Name[ro]=Tigrină
+Name[ru]=ТигриньÑ
+Name[rw]=Igitigirinya
+Name[se]=Tigrinjágiella
+Name[sk]=tigriňa
+Name[sl]=tigrinya
+Name[sq]=Tigrinjisht
+Name[sr]=ТигринÑки
+Name[sr@Latn]=Tigrinski
+Name[ss]=Si-Tigrinya
+Name[sv]=Tigrinja
+Name[ta]=திகிரினà¯à®¯à®¾
+Name[te]=à°Ÿà°¿à°—à±à°°à°¿à°¨à±à°¯à°¾
+Name[tg]=ТигринÑгӣ
+Name[th]=ภาษาทิà¸à¸£à¸´à¸™à¸¢à¸²
+Name[tt]=Tigrinyaça
+Name[uk]=ТигринійÑька
+Name[uz@cyrillic]=ТигринÑ
+Name[vi]=Ti-gợ-ri-nia
+Name[wa]=Tigrinia
+Name[zh_CN]=æ格里尼亚语
+Name[zh_HK]=æ格利尼亞語
+Name[zh_TW]=æ格利尼亞語
+Name[zu]=Isi-Tigrinya
+[tk]
+Name=Turkmen
+Name[ar]=تركماني
+Name[az]=Türkməncə
+Name[be]=ТуркменÑкаÑ
+Name[bg]=ТуркменÑки
+Name[bn]=তà§à¦°à§à¦•à¦®à§‡à¦¨
+Name[bs]=Turkmenski
+Name[ca]=Turcmeni
+Name[cs]=Turkmenský
+Name[csb]=Turkmeńsczi
+Name[cy]=Twrcmeneg
+Name[de]=Turkmenisch
+Name[el]=ΤουÏκμενικά
+Name[eo]=Turkmena
+Name[es]=Turkmenio
+Name[et]=Turkmeeni
+Name[eu]=Turkmeniera
+Name[fa]=ترکمنی
+Name[fi]=Turkmeeni
+Name[fr]=Turkmène
+Name[fy]=Turkmeensk
+Name[ga]=Turcamáinis
+Name[gl]=Turquemeno
+Name[he]=טורקמנית
+Name[hi]=तà¥à¤°à¥à¤•à¤®à¥‡à¤¨
+Name[hr]=Turkmenski
+Name[hsb]=Turkmensce
+Name[hu]=Türkmén
+Name[it]=Turkmeno
+Name[ja]=トルクメン語
+Name[ka]=თურქმენული
+Name[kk]=Түркменше
+Name[km]=ទួគមáŸáž“ីស្ážáž„់
+Name[lb]=Turkmenesch
+Name[lt]=Turkmėnų
+Name[lv]=Turkmēņu
+Name[mk]=ТуркмениÑтанÑки
+Name[mn]=Туркмен
+Name[nb]=Turkmensk
+Name[nds]=Turkmeensch
+Name[ne]=टरà¥à¤•à¤®à¥à¤¯à¤¾à¤¨
+Name[nl]=Turkmeens
+Name[nn]=Turkmensk
+Name[nso]=Se-Turkmen
+Name[pa]=ਤà©à¨°à¨•à¨®à©€à¨¨
+Name[pl]=Turkmeński
+Name[pt]=Turquemenistanês
+Name[pt_BR]=Turco
+Name[ro]=Turcmenă
+Name[ru]=ТуркменÑкий
+Name[rw]=Igiturukimeni
+Name[se]=Turkmenagiella
+Name[sk]=turkménÄina
+Name[sl]=turkmensko
+Name[sq]=Turkmenisht
+Name[sr]=ТуркмениÑтанÑки
+Name[sr@Latn]=Turkmenistanski
+Name[ss]=Si-Turkmen
+Name[sv]=Turkmenska
+Name[ta]=தà¯à®°à¯à®•à¯à®®à¯†à®©à¯
+Name[te]=à°¤à±à°°à±à°•à±à°®à±†à°¨à±
+Name[tg]=Туркманӣ
+Name[th]=ภาษาเติร์à¸à¹€à¸¡à¸™
+Name[tr]=Türkmence
+Name[tt]=Törkmänçä
+Name[uk]=ТуркменÑька
+Name[uz]=Turkmancha
+Name[uz@cyrillic]=Туркманча
+Name[ven]=Munna wa Turkey
+Name[vi]=Tuổc-men
+Name[wa]=Turkmene
+Name[zh_CN]=土库曼语
+Name[zh_HK]=土庫曼語
+Name[zh_TW]=土庫曼語
+Name[zu]=Amadoda Ase-Thekishi
+[tn]
+Name=Tswana
+Name[ar]=التسوانا
+Name[az]=Tsvanaca
+Name[be]=Цвана
+Name[bg]=ТÑуана
+Name[bn]=তসওয়ানা
+Name[eo]=Cvana
+Name[et]=Tsvana
+Name[eu]=Tswanera
+Name[fa]=تی سوانا
+Name[fi]=TÅ¡wana
+Name[fy]=Tswanaansk
+Name[ga]=Suáinis
+Name[he]=צוו×× ×”
+Name[hi]=तसà¥à¤µà¤¾à¤¨à¤¾
+Name[hu]=Tszvana
+Name[ja]=ツワナ語
+Name[ka]=ტსვáƒáƒœáƒ
+Name[kk]=ТÑвана
+Name[km]=វ៉ាន់ណា
+Name[lb]=Tswana-Sprooch
+Name[mk]=Цвана
+Name[mn]=Цвана
+Name[ne]=तसà¥à¤µà¤¾à¤¨à¤¾
+Name[nn]=Setswana
+Name[nso]=Setswana
+Name[pa]=ਤਸਵਾਨਾ
+Name[ro]=Ţuană
+Name[ru]=ТÑвана
+Name[rw]=Igitswana
+Name[se]=Tswanagiella
+Name[sk]=ÄwanÄina
+Name[sl]=tswana
+Name[sq]=Cuanisht
+Name[sr]=Цвана
+Name[sr@Latn]=Cvana
+Name[ss]=SiTswana
+Name[ta]=ஸà¯à®µà®¾à®©à®¾
+Name[te]=à°¸à±à°µà°¾à°¨à°¾
+Name[tg]=Сванавӣ
+Name[th]=ภาษาสวานา
+Name[tt]=Tswanaça
+Name[uk]=ТÑвана
+Name[uz]=Tsvana
+Name[uz@cyrillic]=ТÑвана
+Name[vi]=T-xouă-nă
+Name[xh]=Isitswana
+Name[zh_CN]=茨瓦纳语
+Name[zh_HK]=ç­åœ–語
+Name[zh_TW]=ç­åœ–語
+Name[zu]=Isi-Tswana
+[to]
+Name=Tonga
+Name[ar]=تونجي
+Name[az]=Tongaca
+Name[be]=Тонга
+Name[bg]=Тонга
+Name[bn]=টংগা
+Name[br]=Inizi Tonga
+Name[el]=Τόνγκα
+Name[eu]=Tongera
+Name[fa]=تونگا
+Name[fy]=Tongaansk
+Name[ga]=Tongais
+Name[he]=טונגה
+Name[hi]=टोनà¥à¤—ा
+Name[ja]=トンガ語
+Name[ka]=ცáƒáƒœáƒ’áƒ
+Name[kk]=Тонга
+Name[km]=ážáž»áž„ហ្គោ
+Name[ko]=통가어
+Name[lv]=Tongiešu
+Name[mk]=Тонга
+Name[mn]=Тонга
+Name[ne]=टोङà¥à¤—ा
+Name[nn]=Tongansk
+Name[nso]=Se-Tonga
+Name[pa]=ਤੋਂਗਾ
+Name[ro]=Tongă
+Name[ru]=Тонга
+Name[se]=Tongagiella
+Name[sk]=tonga
+Name[sl]=tongaško
+Name[sq]=Tongisht
+Name[sr]=Тонга
+Name[ss]=Si-Tonga
+Name[ta]=டோஙà¯à®•à®¾
+Name[te]=టొనà±à°—à°¾
+Name[tg]=Тонгаӣ
+Name[th]=ภาษาทองà¸à¸²
+Name[uk]=Тонга
+Name[uz@cyrillic]=Тонга
+Name[vi]=Tông-ga
+Name[zh_CN]=汤加语
+Name[zh_HK]=æ±åŠ èªž
+Name[zh_TW]=æ±åŠ èªž
+Name[zu]=Isi-Tonga
+[tr]
+Name=Turkish
+Name[af]=Turks
+Name[ar]=التركية
+Name[az]=Türkcə
+Name[be]=ТурÑцкаÑ
+Name[bg]=ТурÑки
+Name[bn]=তà§à¦°à§à¦•à§€
+Name[br]=Turkeg
+Name[bs]=Turski
+Name[ca]=Turc
+Name[cs]=Turecký
+Name[csb]=Tërecczi
+Name[cy]=Twrceg
+Name[da]=Tyrkisk
+Name[de]=Türkisch
+Name[el]=ΤουÏκικά
+Name[eo]=Turka
+Name[es]=Turco
+Name[et]=Türgi
+Name[eu]=Turkiera
+Name[fa]=ترکی
+Name[fi]=Turkki
+Name[fr]=Turc
+Name[fy]=Turks
+Name[ga]=Tuircis
+Name[gl]=Turco
+Name[he]=טורקית
+Name[hi]=तà¥à¤°à¥à¤•à¥€
+Name[hr]=Turski
+Name[hsb]=Turkowsce
+Name[hu]=Török
+Name[id]=Turki
+Name[is]=Tyrkneska
+Name[it]=Turco
+Name[ja]=トルコ語
+Name[ka]=თურქული
+Name[kk]=Түрікше
+Name[km]=ទួរគី
+Name[ko]=터키어
+Name[ku]=Tirkî
+Name[lb]=Türkesch
+Name[lt]=Turkų
+Name[lv]=Turku
+Name[mk]=ТурÑки
+Name[mn]=Турк
+Name[ms]=Turki
+Name[mt]=Tork
+Name[nb]=Tyrkisk
+Name[nds]=Törksch
+Name[ne]=टरà¥à¤•à¤¿à¤¶
+Name[nl]=Turks
+Name[nn]=Tyrkisk
+Name[nso]=Se-Turkish
+Name[oc]=Turc
+Name[pa]=ਤà©à¨°à¨•à¨¿à¨¶
+Name[pl]=Turecki
+Name[pt]=Turco
+Name[pt_BR]=Turco
+Name[ro]=Turcă
+Name[ru]=Турецкий
+Name[rw]=Ikinyaturukiya
+Name[se]=Turkiijagiella
+Name[sk]=tureÄtina
+Name[sl]=turško
+Name[sq]=Turqisht
+Name[sr]=ТурÑки
+Name[sr@Latn]=Turski
+Name[ss]=Si-Turkish
+Name[sv]=Turkiska
+Name[ta]=தà¯à®°à¯à®•à¯à®•à®¿à®¯
+Name[te]=à°Ÿà°°à±à°•à°¿à°·à±
+Name[tg]=Туркӣ
+Name[th]=ภาษาตุรà¸à¸µ
+Name[tr]=Türkçe
+Name[tt]=Törekçä
+Name[uk]=Турецька
+Name[uz]=Turkcha
+Name[uz@cyrillic]=Туркча
+Name[vi]=Thổ-nhĩ-kỳ
+Name[wa]=Turk
+Name[zh_CN]=土耳其语
+Name[zh_HK]=土耳其語
+Name[zh_TW]=土耳其語
+Name[zu]=Isi-Thekishi
+[ts]
+Name=Tsonga
+Name[ar]=التسونغا
+Name[az]=Tsongaca
+Name[be]=Цонга
+Name[bg]=ТÑонга
+Name[bn]=তসংগা
+Name[eo]=Conga
+Name[eu]=Tsongera
+Name[fa]=تی سوانگا
+Name[fy]=Tsongaansk
+Name[ga]=Songais
+Name[he]=צונגה
+Name[hi]=तà¥à¤¸à¥‹à¤¨à¥à¤—ा
+Name[ja]=ツォンガ語
+Name[ka]=ცáƒáƒœáƒ’áƒ
+Name[kk]=ТÑонга
+Name[km]=សុងហ្កា
+Name[lb]=Tsonga-Sprooch
+Name[mk]=Цонга
+Name[mn]=Цонга
+Name[ne]=सोङà¥à¤—ा
+Name[nso]=Se-Tsonga
+Name[pa]=ਤਸੋਂਗਾ
+Name[ro]=Tsongă
+Name[ru]=ТÑонга
+Name[rw]=Igitsonga
+Name[se]=Tsongagiella
+Name[sk]=tsonga
+Name[sl]=tsonga
+Name[sq]=Congisht
+Name[sr]=Цонга
+Name[sr@Latn]=Conga
+Name[ss]=SiTsonga
+Name[ta]=டிசோஙà¯à®•à®¾
+Name[te]=సొంగా
+Name[tg]=Сонгавӣ
+Name[th]=ภาษาซองà¸à¸²
+Name[tt]=Tsongaça
+Name[uk]=Цонґа
+Name[uz]=Songa
+Name[uz@cyrillic]=Цонга
+Name[vi]=T-xông-ga
+Name[zh_CN]=特æ¾åŠ è¯­
+Name[zh_HK]=Tsonga語
+Name[zh_TW]=Tsonga語
+Name[zu]=Isi-Tsonga
+[tt]
+Name=Tatar
+Name[ar]=تتري
+Name[az]=Tatarca
+Name[be]=ТатарÑкаÑ
+Name[bg]=ТатарÑки
+Name[bn]=তাতার
+Name[br]=Tatareg
+Name[bs]=Tatarski
+Name[cs]=Tatarský
+Name[csb]=Tatarsczi
+Name[de]=Tatarisch
+Name[eo]=Tatara
+Name[et]=Tatari
+Name[eu]=Tatariera
+Name[fa]=تاتاری
+Name[fi]=Tataari
+Name[fy]=Tataarsk
+Name[ga]=Tatairis
+Name[he]=טטרית
+Name[hi]=तातार
+Name[hr]=Tatarski
+Name[hsb]=Tatarisce
+Name[hu]=Tatár
+Name[it]=Tartaro
+Name[ja]=タタール語
+Name[ka]=თáƒáƒ—რული
+Name[kk]=Татарша
+Name[km]=ážáž¶ážáž¶ážš
+Name[ko]=타타르어
+Name[lb]=Tataresch
+Name[lt]=Totorių
+Name[lv]=TatÄru
+Name[mk]=ТатарÑки
+Name[mn]=Татаар
+Name[nds]=Tartaarsch
+Name[ne]=टाटर
+Name[nn]=Tatarisk
+Name[nso]=Se-Tatar
+Name[pa]=ਤਾਟਾਰ
+Name[pl]=Tatarski
+Name[ro]=Tătară
+Name[ru]=ТатарÑкий
+Name[rw]=Igitatari
+Name[se]=Tatáragiella
+Name[sk]=tatárÄina
+Name[sl]=tatarsko
+Name[sq]=Tatarisht
+Name[sr]=ТатарÑки
+Name[sr@Latn]=Tatarski
+Name[ss]=Si-Tatar
+Name[sv]=Tatariska
+Name[ta]=டாடாரà¯
+Name[te]=తతరà±
+Name[tg]=Тоторӣ
+Name[th]=ภาษาทาทาร์
+Name[tt]=Tatarça
+Name[uk]=ТатарÑька
+Name[uz]=Totarcha
+Name[uz@cyrillic]=Тотарча
+Name[vi]=Ta-tă
+Name[wa]=Tatår
+Name[zh_CN]=éž‘é¼è¯­
+Name[zh_HK]=韃é¼èªž
+Name[zh_TW]=韃é¼èªž
+Name[zu]=Isi-Tatar
+[tw]
+Name=Twi
+Name[ar]=التوي
+Name[az]=TvicÉ™
+Name[be]=Тві
+Name[bg]=Туи
+Name[bn]=টà§à§Ÿà¦¿
+Name[et]=Tvii
+Name[fa]=توی
+Name[he]=צ'ווי
+Name[hi]=तà¥à¤µà¥€
+Name[hu]=Tvi
+Name[ja]=ãƒãƒ¥ã‚¤èªž
+Name[ka]=ტვი
+Name[kk]=Тви
+Name[km]=ទ្វី
+Name[lb]=Akan-Sprooch
+Name[mk]=Тви
+Name[mn]=Тви
+Name[ne]=तà¥à¤‡
+Name[nso]=Se-Twi
+Name[pa]=ਤਵੀ
+Name[ru]=Тви
+Name[rw]=Igitwi
+Name[se]=Twigiella
+Name[sk]=twi
+Name[sl]=twi
+Name[sq]=Tuisht
+Name[sr]=ТвиÑки
+Name[sr@Latn]=Tviski
+Name[ss]=Si-Twi
+Name[ta]=தà¯à®µà¯€
+Name[te]=à°Ÿà±à°µà°¿
+Name[tg]=ТвиÑгӣ
+Name[th]=ภาษาชวี
+Name[tt]=Twiçä
+Name[uk]=Тві
+Name[uz]=Tvi
+Name[uz@cyrillic]=Тви
+Name[vi]=Tui
+Name[zh_CN]=契维语
+Name[zh_HK]=契維語
+Name[zh_TW]=契維語
+Name[zu]=Isi-Twi
+[ty]
+Name=Tahitian
+Name[ar]=التاهيتية
+Name[az]=TaiticÉ™
+Name[be]=ТаіцкаÑ
+Name[bg]=ТаитÑки
+Name[bn]=তাহিশিয়ান
+Name[br]=Tahitieg
+Name[bs]=Tahićanski
+Name[ca]=Tahitià
+Name[cs]=Tahitský
+Name[csb]=Tahitańsczi
+Name[cy]=Tahitieg
+Name[da]=Tahitisk
+Name[de]=Tahitianisch
+Name[eo]=Tahitia
+Name[es]=Tahitiano
+Name[et]=Tahiti
+Name[eu]=Tahitiera
+Name[fa]=تاهیتی
+Name[fi]=Tahiti
+Name[fr]=Tahitien
+Name[fy]=Tahitiaansk
+Name[ga]=Taihítis
+Name[gl]=Taitiano
+Name[he]=טהיטית
+Name[hi]=ताहितियन
+Name[hr]=Tahićanski
+Name[hsb]=Tahitisce
+Name[hu]=Tahiti
+Name[id]=Tahiti
+Name[it]=Tahitiano
+Name[ja]=タヒãƒèªž
+Name[ka]=ტáƒáƒ˜áƒ¢áƒ˜
+Name[kk]=Таитише
+Name[km]=ážáž¶áž áž·ážáž„់
+Name[ko]=타히티어
+Name[lb]=Tahitesch
+Name[lt]=Tahiti
+Name[lv]=Taitiešu
+Name[mk]=ТахитÑки
+Name[mn]=Тахит
+Name[ms]=Tahiti
+Name[nb]=Tahitisk
+Name[nds]=Tahiitsch
+Name[ne]=ताहिसिन
+Name[nl]=Tahitiaans
+Name[nn]=Tahitisk
+Name[nso]=Se-Tahitian
+Name[pa]=ਤਾਹੀਟੀਅਨ
+Name[pl]=Tahitański
+Name[pt]=Tahitiano
+Name[pt_BR]=Tahitiano
+Name[ro]=Tahitiană
+Name[ru]=Таити
+Name[rw]=Ikinyatahiti
+Name[se]=Tahitigiella
+Name[sk]=tahitÄina
+Name[sl]=tahitijsko
+Name[sq]=Tahisht
+Name[sr]=ТахићанÑки
+Name[sr@Latn]=Tahićanski
+Name[ss]=Si-Tahitian
+Name[sv]=Tahitiska
+Name[ta]=தஹிடியனà¯
+Name[te]=టహితియనà±
+Name[tg]=ТаитиÑгӣ
+Name[th]=ภาษาตาฮิเตียน
+Name[tt]=Tahitçä
+Name[uk]=ТаїтÑнÑька
+Name[uz]=Taxitian
+Name[uz@cyrillic]=Тахитиан
+Name[vi]=Ta-hi-ti
+Name[wa]=Tahityin
+Name[zh_CN]=塔希æ语
+Name[zh_HK]=大溪地語
+Name[zh_TW]=大溪地語
+Name[zu]=Isi-Tahitian
+[ug]
+Name=Uighur
+Name[ar]=الأويغورية
+Name[az]=UyÄŸurca
+Name[be]=Уігур
+Name[bg]=Югхур
+Name[bn]=উইঘà§à¦°
+Name[bs]=Ujgurski
+Name[csb]=Ujgùrsczi
+Name[de]=Uigurisch
+Name[eo]=Ujgura
+Name[et]=Uiguuri
+Name[fa]=یوگر
+Name[fi]=Uiguuri
+Name[ga]=Úígiúiris
+Name[he]=×ויגור
+Name[hi]=उइघà¥à¤°
+Name[hr]=Ujgurski
+Name[hsb]=Ujgursce
+Name[hu]=Ujgur
+Name[ja]=ウイグル語
+Name[ka]=უიგურული
+Name[kk]=Ұйғырша
+Name[km]=វីហ្គៀរ
+Name[lb]=Uiguresch
+Name[lv]=Uiguru
+Name[mk]=Ујгур
+Name[mn]=Уйгур
+Name[nb]=Uigursk
+Name[nds]=Uighuursch
+Name[ne]=विगोर
+Name[nn]=Uigurisk
+Name[nso]=Se-Uighur
+Name[pa]=ਉਘੂਰ
+Name[pl]=Ujgurski
+Name[ro]=Uigură
+Name[ru]=УйгурÑкий
+Name[rw]=Icyuyiguru
+Name[se]=Uiguragiella
+Name[sk]=ujgurÄina
+Name[sl]=ujgursko
+Name[sq]=Uigurisht
+Name[sr]=УјгурÑки
+Name[sr@Latn]=Ujgurski
+Name[ss]=Si-Uighur
+Name[sv]=Uiguriska
+Name[ta]=உயிகூரà¯
+Name[te]=ఉఇఘరà±
+Name[tg]=Уйгурӣ
+Name[th]=ภาษาอุยà¸à¸¹à¸£à¹Œ
+Name[tr]=Uygurca
+Name[tt]=Uyğurça
+Name[uk]=Уйгур
+Name[uz]=Uygʻurcha
+Name[uz@cyrillic]=Уйғурча
+Name[vi]=Ui-gua
+Name[wa]=Ouygour
+Name[zh_CN]=ç»´å¾å°”语
+Name[zh_HK]=維å¾çˆ¾èªž
+Name[zh_TW]=維å¾çˆ¾èªž
+Name[zu]=Isi-Uighur
+[uk]
+Name=Ukrainian
+Name[af]=Ukraïnies
+Name[ar]=الأوكرانية
+Name[az]=Ukrayna Dili
+Name[be]=УкраінÑкаÑ
+Name[bg]=УкраинÑки
+Name[bn]=ইউকà§à¦°à§‡à¦¨à§€à§Ÿ
+Name[br]=Ukrainiek
+Name[bs]=Ukrajinski
+Name[ca]=Ucraïnès
+Name[cs]=Ukrajinský
+Name[csb]=Ùkrajińsczi
+Name[cy]=Ukraineg
+Name[da]=Ukrainsk
+Name[de]=Ukrainisch
+Name[el]=ΟυκÏανικά
+Name[eo]=Ukraina
+Name[es]=Ucranio
+Name[et]=Ukraina
+Name[eu]=Ukrainiera
+Name[fa]=اکراینی
+Name[fi]=Ukraina
+Name[fr]=Ukrainien
+Name[fy]=Oekraïnsk
+Name[ga]=Úcráinis
+Name[gl]=Ucraíno
+Name[he]=×וקר×ינית
+Name[hi]=उकà¥à¤°à¥‡à¤¨à¤¿à¤¯à¤¨
+Name[hr]=Ukrajinski
+Name[hsb]=Ukrainsce
+Name[hu]=Ukrán
+Name[id]=Ukraina
+Name[is]=Úkraínska
+Name[it]=Ucraino
+Name[ja]=ウクライナ語
+Name[ka]=უკრáƒáƒ˜áƒœáƒ£áƒšáƒ˜
+Name[kk]=Украинша
+Name[km]=អ៊ុយក្រែន
+Name[ko]=ìš°í¬ë¼ì´ë‚˜ì–´
+Name[lb]=Ukrainesch
+Name[lt]=UkrainieÄių
+Name[lv]=Ukraiņu
+Name[mk]=УкраинÑки
+Name[mn]=Украйн
+Name[ms]=Ukrainia
+Name[mt]=Ukranjan
+Name[nb]=Ukrainsk
+Name[nds]=Ukrainsch
+Name[ne]=यà¥à¤•à¥à¤°à¥‡à¤¨à¥€
+Name[nl]=Oekraïns
+Name[nn]=Ukrainsk
+Name[nso]=Se-Ukrainian
+Name[oc]=Ucranian
+Name[pa]=ਯੂਕਰੇਨ
+Name[pl]=Ukraiński
+Name[pt]=Ucraniano
+Name[pt_BR]=Ucraniano
+Name[ro]=Ucrainiană
+Name[ru]=УкраинÑкий
+Name[rw]=Ikinya-ikarayini
+Name[se]=Ukrainagiella
+Name[sk]=ukrajinÄina
+Name[sl]=ukrajinsko
+Name[sq]=Ukrainisht
+Name[sr]=УкрајинÑки
+Name[sr@Latn]=Ukrajinski
+Name[ss]=Si-Ukrainian
+Name[sv]=Ukrainska
+Name[ta]=உகà¯à®°à¯‡à®©à®¿à®¯à®©à¯
+Name[te]=ఉకà±à°°à±‡à°¨à°¿à°¯à°¨à±
+Name[tg]=Украинӣ
+Name[th]=ภาษายูเครน
+Name[tr]=Ukrayna Dili
+Name[tt]=Ukrainça
+Name[uk]=УкраїнÑька
+Name[uz]=Ukraincha
+Name[uz@cyrillic]=Украинча
+Name[vi]=U-cợ-rainh
+Name[wa]=Oucrinnyin
+Name[xh]=Ukranian
+Name[zh_CN]=乌克兰语
+Name[zh_HK]=çƒå…‹è˜­èªž
+Name[zh_TW]=çƒå…‹è˜­èªž
+Name[zu]=Isi-Ukraniyani
+[ur]
+Name=Urdu
+Name[ar]=أوردي
+Name[az]=Urduca
+Name[be]=Урду
+Name[bg]=Урду
+Name[bn]=উরà§à¦¦à§
+Name[ca]=Urdú
+Name[cy]=Wrdw
+Name[eo]=Urduo
+Name[fa]=اردو
+Name[fy]=Urdû
+Name[ga]=Urdais
+Name[he]=×ורדו
+Name[hi]=उरà¥à¤¦à¥‚
+Name[ja]=ウルドゥー語
+Name[ka]=ურდუ
+Name[kk]=Урду
+Name[km]=អ៊ូរ្ឌូ
+Name[ko]=울ë‘ì–´
+Name[mk]=Урду
+Name[mn]=Урду
+Name[ne]=उरà¥à¤¦à¥
+Name[nso]=Se-Urdu
+Name[pa]=ਉਰਦੂ
+Name[ru]=Урду
+Name[rw]=Icyuridu
+Name[se]=Urdugiella
+Name[sk]=urdÄina
+Name[sl]=urdu
+Name[sq]=Urdisht
+Name[sr]=Урду
+Name[ss]=Si-Urdu
+Name[ta]=உரà¯à®¤à¯
+Name[te]=ఉరà±à°¦à±
+Name[tg]=Урду
+Name[th]=ภาษาอูร์ดู
+Name[tt]=Urduça
+Name[uk]=Урду
+Name[uz@cyrillic]=Урду
+Name[vi]=Uổ-đu
+Name[wa]=Ourdou
+Name[zh_CN]=乌尔都语
+Name[zh_HK]=çƒéƒ½èªž
+Name[zh_TW]=çƒéƒ½èªž
+Name[zu]=Isi-Urdu
+[uz]
+Name=Uzbek
+Name[ar]=أوزباكي
+Name[az]=Özbəkcə
+Name[be]=УзбецкаÑ
+Name[bg]=УзбекÑки
+Name[bn]=উজবেক
+Name[br]=Ouzbeg
+Name[bs]=UzbeÄki
+Name[cs]=Uzbecký
+Name[csb]=Ùzbecczi
+Name[cy]=Wzbec
+Name[de]=Usbekisch
+Name[el]=Ουζμπεκικά
+Name[eo]=Uzbeka
+Name[es]=Uzbeko
+Name[et]=Usbeki
+Name[eu]=Uzbekera
+Name[fa]=ازبکی
+Name[fi]=Uzbekki
+Name[fy]=Oezbeeksk
+Name[ga]=Úisbéicis
+Name[gl]=Uzbeque
+Name[he]=×וזבקית
+Name[hi]=उजà¥à¤¬à¤¼à¥‡à¤•
+Name[hr]=UzbeÄki
+Name[hsb]=Uzbekisce
+Name[hu]=Üzbég
+Name[it]=Uzbeco
+Name[ja]=ウズベク語
+Name[ka]=უზბეკური
+Name[kk]=Өзбекше
+Name[km]=អ៊ូហ្សបáŸáž‚ីស្ážáž„់
+Name[ko]=우즈베í¬ì–´
+Name[lb]=Usbekesch
+Name[lt]=Uzbekų
+Name[lv]=Uzbeku
+Name[mk]=УзбекиÑтанÑки
+Name[mn]=Узбек
+Name[nb]=Usbekisk
+Name[nds]=Usbeeksch
+Name[ne]=उजà¥à¤¬à¥‡à¤•
+Name[nl]=Uzbeeks
+Name[nn]=Usbekisk
+Name[nso]=Se-Uzbek
+Name[pa]=ਊਜੇਬਕ
+Name[pl]=Uzbecki
+Name[pt]=Usbequistanês
+Name[ro]=Uzbecă
+Name[ru]=УзбекÑкий
+Name[rw]=Icyuzubeka
+Name[se]=Uzbehkagiella
+Name[sk]=uzbeÄtina
+Name[sl]=uzbeško
+Name[sq]=Uzbekisht
+Name[sr]=Узбечки
+Name[sr@Latn]=UzbeÄki
+Name[ss]=Si-Uzbek
+Name[sv]=Uzbekiska
+Name[ta]=உஸà¯à®ªà¯†à®•à¯
+Name[te]=ఉజà±à°¬à±†à°•à±
+Name[tg]=Ӯзбекӣ
+Name[th]=ภาษาอุซเบà¸à¸´à¸ªà¸–าน
+Name[tr]=Özbek
+Name[tt]=Üzbäkçä
+Name[uk]=Узбецька
+Name[uz]=Oʻzbekcha
+Name[uz@cyrillic]=Ўзбекча
+Name[vi]=U-x-béc
+Name[wa]=Ouzbeke
+Name[zh_CN]=乌兹别克语
+Name[zh_HK]=çƒèŒ²åˆ¥å…‹èªž
+Name[zh_TW]=çƒèŒ²åˆ¥å…‹èªž
+Name[zu]=Isi-Uzbek
+[uz@cyrillic]
+Name=Uzbek (Cyrillic)
+Name[bg]=УзбекÑки (кирилица)
+Name[ca]=Uzbek (Ciríl·lic)
+Name[da]=Uzbekisk (kyrillisk)
+Name[de]=Usbekisch (Kyrillisch)
+Name[el]=Ουζμπεκικά (ΚυÏιλικά)
+Name[es]=Uzbeko (Cirílico)
+Name[et]=Usbeki (kirillitsa)
+Name[fr]=Uzbek (Cyrillique)
+Name[is]=Uzbek (Kyrilísk)
+Name[it]=Usbeco (Cirillico)
+Name[ja]=ウズベク語 (キリル文字)
+Name[km]=អ៊ូហ្សបáŸáž‚ីស្ážáž„់ (ស៊ីរីលីក)
+Name[nds]=Usbeeksch (kyrillsch)
+Name[pl]=Uzbecki (cyrlica)
+Name[sk]=uzbeÄtina (cyrilika)
+Name[sr]=Узбечки ћирилични
+Name[sr@Latn]=Узбечки ћирилични
+Name[sv]=Kyrillisk Uzbekiska
+Name[zh_TW]=çƒèŒ²åˆ¥å…‹èªžï¼ˆæ–¯æ‹‰å¤«èªžç³»ï¼‰
+[ven]
+Name=Venda
+Name[ar]=Ùيندا
+Name[be]=Венда
+Name[bg]=Венда
+Name[bn]=ভেণà§à¦¡à¦¾
+Name[de]=Tshivenda
+Name[fa]=وندا
+Name[ga]=Veindis
+Name[hi]=वेंडा
+Name[ja]=ベンダ語
+Name[ka]=ვენდáƒ
+Name[kk]=Венда
+Name[km]=វង់ដា
+Name[ko]=벤다어
+Name[mk]=Венда
+Name[mn]=Венда
+Name[ne]=भेनà¥à¤¡à¤¾
+Name[pa]=ਵਾਂਡਾ
+Name[ru]=Венда
+Name[rw]=Ikivenda
+Name[se]=Vendagiella
+Name[sk]=venda
+Name[sl]=venda
+Name[sq]=Vendisht
+Name[sr]=Венда
+Name[ta]=வெணà¯à®Ÿà®¾
+Name[te]=వెండా
+Name[tg]=Вендаӣ
+Name[th]=ภาษาเวนดา
+Name[tt]=Vendaça
+Name[uk]=Венда
+Name[uz@cyrillic]=Венда
+Name[vi]=Ven-Ä‘a
+Name[zh_CN]=闻达语
+[vi]
+Name=Vietnamese
+Name[af]=Viëtnamees
+Name[ar]=الÙييتنامية
+Name[az]=Vyetnamca
+Name[be]=Ð’'етнамÑкаÑ
+Name[bg]=ВиетнамÑки
+Name[bn]=ভিয়েতনামী
+Name[br]=Viet-Nameg
+Name[bs]=Vijetnamski
+Name[ca]=Vietnamita
+Name[cs]=Vietnamský
+Name[csb]=Wietnamsczi
+Name[cy]=Vietnameg
+Name[da]=Vietnamesisk
+Name[de]=Vietnamesisch
+Name[el]=Βιετναμέζικα
+Name[eo]=Vjetnama
+Name[es]=Vietnamita
+Name[et]=Vietnami
+Name[eu]=Vietnamera
+Name[fa]=ویتنامی
+Name[fi]=Vietnam
+Name[fr]=Vietnamien
+Name[fy]=Vietnameesk
+Name[ga]=Vítneamais
+Name[gl]=Vietnamita
+Name[he]=וייטנ×מית
+Name[hi]=वियतनामी
+Name[hr]=Vijetnamski
+Name[hsb]=Vietnamsce
+Name[hu]=Vietnami
+Name[id]=Vietnam
+Name[is]=Víetnamska
+Name[it]=Vietnamita
+Name[ja]=ベトナム語
+Name[ka]=ვიეტნáƒáƒ›áƒ£áƒ áƒ˜
+Name[kk]=Вьетнамша
+Name[km]=វៀážážŽáž¶áž˜
+Name[ko]=베트남어
+Name[ku]=Viyetnamî
+Name[lb]=Vietnamesesch
+Name[lt]=VietnamieÄių
+Name[lv]=Vjetnamiešu
+Name[mk]=ВиетнамÑки
+Name[mn]=Витьнам
+Name[ms]=Vietnam
+Name[mt]=Vjetnamiż
+Name[nb]=Vietnamesisk
+Name[nds]=Vietnameesch
+Name[ne]=भियतनामी
+Name[nl]=Vietnamees
+Name[nn]=Vietnamesisk
+Name[nso]=Se-Vietnamese
+Name[pa]=ਵੀਅਤਨਾਮੀ
+Name[pl]=Wietnamski
+Name[pt]=Vietnamita
+Name[pt_BR]=Vietnamita
+Name[ro]=Vietnameză
+Name[ru]=ВьетнамÑкий
+Name[rw]=Ikinyaviyetinamu
+Name[se]=Vietnamagiella
+Name[sk]=vietnamÄina
+Name[sl]=vietnamsko
+Name[sq]=Vietnamisht
+Name[sr]=ВијетнамÑки
+Name[sr@Latn]=Vijetnamski
+Name[ss]=Si-Vietnamese
+Name[sv]=Vietnamesiska
+Name[ta]=வியடà¯à®©à®¾à®®à®¿à®¯
+Name[te]=వియతà±à°¨à°¾à°®à±€à°¸à±
+Name[tg]=Ветнамӣ
+Name[th]=ภาษาเวียตนาม
+Name[tr]=Vietnamca
+Name[tt]=Vietnamça
+Name[uk]=Ð’'єтнамÑька
+Name[uz]=Vetnamcha
+Name[uz@cyrillic]=Ветнамча
+Name[vi]=Việt
+Name[wa]=Vietnamyin
+Name[zh_CN]=越å—语
+Name[zh_HK]=越å—語
+Name[zh_TW]=越å—語
+Name[zu]=Isi-Vietnamese
+[vo]
+Name=Volapük
+Name[ar]=الÙولابوك
+Name[az]=Volapükcə
+Name[be]=Валапук
+Name[bg]=Волапюк
+Name[bn]=ভোলাপà§à¦•
+Name[br]=Volapuk
+Name[cy]=Volapuk
+Name[da]=Volapyk
+Name[eo]=Volapuko
+Name[fa]=ولاپوک
+Name[he]=וולפיק
+Name[hi]=वोलापक
+Name[ja]=ボラピューク語
+Name[ka]=ვáƒáƒšáƒáƒžáƒ˜áƒ£áƒ™áƒ˜
+Name[kk]=Волапюк
+Name[km]=វូឡាភូក
+Name[mk]=Волапук
+Name[mn]=Волапүк
+Name[ne]=भोलापà¥à¤•
+Name[nl]=Volapúk
+Name[nn]=Volapyk
+Name[nso]=Se-Volapük
+Name[pa]=ਵੂਲਾਉਕ
+Name[ro]=Volapucă
+Name[ru]=Волапюк
+Name[rw]=Ikivolapuke
+Name[se]=Volapükgiella
+Name[sk]=volapük
+Name[sl]=volapük
+Name[sq]=Volapisht
+Name[sr]=ВолапикÑки
+Name[sr@Latn]=Volapikski
+Name[ss]=Si-Volapük
+Name[ta]=வொலà¯à®ªà®¾à®•à¯
+Name[te]=వొలపà±à°•à±
+Name[tg]=Волапёкӣ
+Name[th]=ภาษาวอลาพุค
+Name[tt]=Volapükçä
+Name[uk]=Волапюк
+Name[uz]=Volapuk
+Name[uz@cyrillic]=Волапук
+Name[vi]=Vo-la-puc
+Name[zh_CN]=沃拉普克语
+Name[zu]=Isi-Volapük
+[wa]
+Name=Walloon
+Name[ar]=الوالون
+Name[az]=Valonca
+Name[be]=ВалонÑкаÑ
+Name[bg]=ВалонÑки
+Name[bn]=ওয়ালà§à¦¨
+Name[br]=Walloneg
+Name[bs]=Valonski
+Name[cs]=Wallonský
+Name[csb]=Walońsczi
+Name[da]=Vallonsk
+Name[de]=Wallonisch
+Name[eo]=Valona
+Name[et]=Vallooni
+Name[eu]=Waloiera
+Name[fa]=والونی
+Name[fi]=Valloni
+Name[fr]=Wallon
+Name[fy]=Waalsk
+Name[ga]=Vallúnais
+Name[gl]=Valón
+Name[he]=וולונית
+Name[hi]=वालून
+Name[hr]=Valonski
+Name[hsb]=Walloonisce
+Name[hu]=Vallon
+Name[id]=Wallon
+Name[is]=Vallónska
+Name[it]=Vallone
+Name[ja]=ワロン語
+Name[ka]=ვáƒáƒšáƒáƒœáƒ£áƒ áƒ˜
+Name[kk]=Валонша
+Name[km]=វ៉ាឡុង
+Name[ko]=왈론어
+Name[ku]=Walûn
+Name[lb]=Wallounesch
+Name[lt]=Valonų
+Name[lv]=Valoņu
+Name[mk]=ВалонÑки
+Name[mn]=Валлоон
+Name[nb]=Vallonsk
+Name[nds]=Walloonsch
+Name[ne]=वालोन
+Name[nl]=Waals
+Name[nn]=Vallonsk
+Name[nso]=Se-Walloon
+Name[oc]=Valon
+Name[pa]=ਵਾਲੂਨ
+Name[pl]=Waloński
+Name[pt]=Valão
+Name[ro]=Valonă
+Name[ru]=ВаллонÑкий
+Name[rw]=Ikiwaluni
+Name[se]=Vallonagiella
+Name[sk]=valónÄina
+Name[sl]=walloonsko
+Name[sq]=Uallunisht
+Name[sr]=ВалонÑки
+Name[sr@Latn]=Valonski
+Name[ss]=Si-Walloon
+Name[sv]=Vallonska
+Name[ta]=வாலூனà¯
+Name[te]=వాలూనà±
+Name[tg]=Валунӣ
+Name[th]=ภาษาวัลลูน
+Name[tr]=Valonca
+Name[tt]=Walonça
+Name[uk]=ВаллонÑька
+Name[uz]=Valloncha
+Name[uz@cyrillic]=Валлонча
+Name[vi]=Oua-lunh
+Name[wa]=Walon
+Name[zh_CN]=瓦龙语
+Name[zh_HK]=è¯éš†èªž
+Name[zh_TW]=è¯éš†èªž
+Name[zu]=Isi-Walloon
+[wo]
+Name=Wolof
+Name[ar]=الوولوÙ
+Name[az]=Volofca
+Name[be]=Волаф
+Name[bg]=Уолоф
+Name[bn]=ওয়োলফ
+Name[cy]=Woloff
+Name[eo]=Volofa
+Name[et]=Volofi
+Name[eu]=Wolofera
+Name[fa]=ولوÙ
+Name[ga]=Volaifis
+Name[he]=וולוף
+Name[hi]=वालाफ़
+Name[hr]=Volofski
+Name[hu]=Volof
+Name[ja]=ウォロフ語
+Name[ka]=უáƒáƒšáƒáƒ¤áƒ˜
+Name[kk]=Волофша
+Name[km]=វូឡុហ្វ
+Name[lb]=Wolof-Sprooch
+Name[mk]=Волоф
+Name[mn]=Волоф
+Name[ne]=वलोफ
+Name[nso]=Se-Wolof
+Name[pa]=ਵੂਲੂਫ
+Name[ro]=Volofă
+Name[ru]=Уолоф
+Name[rw]=Ikiwolofu
+Name[se]=Volofagiella
+Name[sk]=wolof
+Name[sl]=wolof
+Name[sq]=Ollofisht
+Name[sr]=ВолофÑки
+Name[sr@Latn]=Volofski
+Name[ss]=Si-Wolof
+Name[ta]=வொலொஃபà¯
+Name[te]=వొలొఫà±
+Name[tg]=Волофӣ
+Name[th]=ภาษาวอลอฟ
+Name[tt]=Wolofça
+Name[uk]=Волоф
+Name[uz]=Volof
+Name[uz@cyrillic]=Волоф
+Name[vi]=Ouo-lo-ph
+Name[zh_CN]=沃洛夫语
+Name[zh_HK]=Wolof語
+Name[zh_TW]=Wolof語
+Name[zu]=Isi-Wolof
+[xh]
+Name=Xhosa
+Name[ar]=الهاوسا
+Name[be]=КшоÑа
+Name[bg]=КÑоÑа
+Name[bn]=জোসা
+Name[de]=isiXhosa
+Name[eo]=Ĥosa
+Name[eu]=Xhosera
+Name[fa]=زسایی
+Name[ga]=Cóisis
+Name[he]=קוזה
+Name[hi]=à¤à¥‹à¤¸à¤¾
+Name[hu]=Xhosza
+Name[ja]=コサ語
+Name[ka]=ქშáƒáƒ¡áƒ
+Name[kk]=КхоÑа
+Name[km]=ឃសាLesotho
+Name[ko]=엑스호사어
+Name[mk]=КÑоÑа
+Name[mn]=ЧоÑа
+Name[ne]=होजा
+Name[nso]=Sethosa
+Name[pa]=à¨à©‹à¨¸à¨¾
+Name[ru]=КшоÑа
+Name[rw]=Ikigisosa
+Name[se]=Xhosagiella
+Name[sk]=xhosa
+Name[sl]=xhosa
+Name[sq]=Gjosisht
+Name[sr]=ЗоÑа
+Name[sr@Latn]=Zosa
+Name[ss]=SiXhosa
+Name[ta]=சோசா
+Name[te]=à°•à±à°œà±Šà°¸à°¾
+Name[tg]=ХоÑа
+Name[th]=ภาษาโคซา
+Name[uk]=КÑоза
+Name[uz@cyrillic]=ХҳоÑа
+Name[ven]=Xhoza
+Name[vi]=Xô-xa
+Name[wa]=Xhossa
+Name[xh]=isixhosa
+Name[zh_CN]=科è¨è¯­
+Name[zh_HK]=科薩語
+Name[zh_TW]=科薩語
+Name[zu]=Isi-Xhosa
+[yi]
+Name=Yiddish
+Name[ar]=اليديش
+Name[az]=YiddiÅŸcÉ™
+Name[be]=Ідыш
+Name[bg]=Идиш
+Name[bn]=য়িডà§à¦¡à¦¿à¦¶
+Name[bs]=Jidiš
+Name[cs]=Jidiš
+Name[csb]=Jidisz
+Name[cy]=Yideg
+Name[de]=Jiddish
+Name[eo]=Jida
+Name[et]=Jidiš
+Name[eu]=Jiddish
+Name[fa]=عبری
+Name[fi]=Jiddiš
+Name[fy]=Jiddysk
+Name[ga]=Giúdais
+Name[gl]=Iídiche
+Name[he]=יידיש
+Name[hi]=यिदिश
+Name[hr]=Jidiš
+Name[hsb]=Jidisce
+Name[hu]=Jiddis
+Name[is]=Jiddíska
+Name[ja]=イディッシュ語
+Name[ka]=იდიში
+Name[kk]=Идиш
+Name[km]=យីឌីហ្ស
+Name[ko]=ì´ë””시어
+Name[lb]=Jiddesch
+Name[lt]=Jidiš
+Name[lv]=Jidišš
+Name[mk]=ЕврејÑки
+Name[mn]=Юүд
+Name[nb]=Jiddisk
+Name[nds]=Jiddsch
+Name[ne]=इडिस
+Name[nn]=Jiddisk
+Name[nso]=Se-Yiddish
+Name[pa]=ਯੀਡਿਸ਼
+Name[pl]=Jidysz
+Name[ro]=IdiÅŸ
+Name[ru]=Идиш
+Name[rw]=Ikiyidishi
+Name[se]=Jiddišgiella
+Name[sk]=jidiš
+Name[sl]=yiddish
+Name[sq]=Jidisht
+Name[sr]=ЈидијÑки
+Name[sr@Latn]=Jidijski
+Name[ss]=Si-Yiddish
+Name[ta]=யிடà¯à®Ÿà®¿à®·à¯
+Name[te]=యిడà±à°¡à°¿à°·à±
+Name[tg]=Йидишӣ
+Name[th]=ภาษายิดดิช
+Name[tt]=YidiÅŸ
+Name[uk]=Ідиш
+Name[uz@cyrillic]=Йиддиш
+Name[vi]=Y-đít
+Name[wa]=Yidish
+Name[zh_CN]=ä¾åœ°è¯­
+Name[zh_HK]=æ„第緒語
+Name[zh_TW]=æ„第緒語
+Name[zu]=Isi-Yidishi
+[yo]
+Name=Yoruba
+Name[ar]=اليوروبا
+Name[az]=Yorubaca
+Name[be]=Яруба
+Name[bg]=Йоруба
+Name[bn]=য়োরà§à¦¬à¦¾
+Name[eo]=Joruba
+Name[et]=Joruba
+Name[eu]=Jorubera
+Name[fa]=یوروبا
+Name[fi]=Joruba
+Name[ga]=Iarúibis
+Name[gl]=Yorùbá
+Name[he]=יורובה
+Name[hi]=योरà¥à¤¬à¤¾
+Name[hu]=Joruba
+Name[ja]=ヨルãƒèªž
+Name[ka]=იáƒáƒ áƒ£áƒ‘áƒ
+Name[kk]=Йоруба
+Name[km]=យរូបា
+Name[ko]=요루바어
+Name[lb]=Yoruba-Sprooch
+Name[lv]=Jarubu
+Name[mk]=Јоруба
+Name[mn]=Ðруба
+Name[ne]=योरूबा
+Name[nn]=Joruba
+Name[nso]=Se-Yoruba
+Name[pa]=ਯੂਰੋਬਾ
+Name[ro]=Iorubă
+Name[ru]=Йоруба
+Name[rw]=Ikiyoruba
+Name[se]=Jorubagiella
+Name[sk]=jorubÄina
+Name[sl]=yoruba
+Name[sq]=Jorubisht
+Name[sr]=ЈорубÑки
+Name[sr@Latn]=Jorubski
+Name[ss]=Si-Yoruba
+Name[ta]=யொரூபா
+Name[te]=యొరà±à°¬à°¾
+Name[tg]=Ðруба
+Name[th]=ภาษาโยรูบา
+Name[tt]=Yorubaça
+Name[uk]=Йоруба
+Name[uz@cyrillic]=Ðруба
+Name[vi]=Yô-ru-ba
+Name[wa]=Yorouba
+Name[zh_CN]=约é²å·´è¯­
+Name[zh_HK]=優魯巴語
+Name[zh_TW]=優魯巴語
+Name[zu]=Isi-Yoruba
+[za]
+Name=Zhuang
+Name[ar]=الزهوانغ
+Name[az]=Zhuangca
+Name[be]=Цванг
+Name[bg]=Жуанг
+Name[bn]=à¦à§à§Ÿà¦¾à¦‚
+Name[et]=Zhuangi
+Name[fa]=هونگ
+Name[ga]=Siuáingis
+Name[gl]=Chuan
+Name[he]=×’'ו×× ×’
+Name[hi]=à¤à¥à¤†à¤‚ग
+Name[ja]=ãƒãƒ¥ãƒ¯ãƒ³èªž
+Name[ka]=ჩჟუáƒáƒœáƒ˜
+Name[kk]=Зуангша
+Name[km]=ចួង
+Name[mk]=Жуанг
+Name[mn]=Жунгаа
+Name[ne]=à¤à¤¿à¤†à¤™
+Name[nso]=Se-Zhuang
+Name[pa]=ਜ਼ੂੰਗ
+Name[ru]=Чжуанг
+Name[rw]=Ikizwange
+Name[se]=Zhuangagiella
+Name[sk]=ÄuangÄina
+Name[sl]=zhuang
+Name[sq]=Zhuanginsht
+Name[sr]=Цуанг
+Name[sr@Latn]=Cuang
+Name[ss]=Si-Zhuang
+Name[ta]=சà¯à®µà®¾à®™à¯
+Name[te]=à°œà±à°µà°¾à°‚à°—à±
+Name[tg]=Жуанг
+Name[th]=ภาษาจ้วง
+Name[tt]=Cuañça
+Name[uk]=Жуан
+Name[uz]=Zxuang
+Name[uz@cyrillic]=Зхуанг
+Name[vi]=Xuang
+Name[zh_CN]=壮语
+Name[zh_HK]=Zhuang語
+Name[zh_TW]=Zhuang語
+Name[zu]=Isi-Zhuang
+[zh]
+Name=Chinese
+Name[af]=Sjinese
+Name[ar]=الصينية
+Name[az]=Çincə
+Name[be]=КітайÑкаÑ
+Name[bg]=КитайÑки
+Name[bn]=চৈনিক
+Name[br]=Sinaeg
+Name[bs]=Kineski
+Name[ca]=Xinès
+Name[cs]=Čínský
+Name[csb]=Chińsczi
+Name[cy]=Tseineeg
+Name[da]=Kinesisk
+Name[de]=Chinesisch
+Name[el]=Κινέζικα
+Name[eo]=Ĉina
+Name[es]=Chino
+Name[et]=Hiina
+Name[eu]=Txinera
+Name[fa]=چینی
+Name[fi]=Kiina
+Name[fr]=Chinois
+Name[fy]=Sjineesk
+Name[ga]=Sínis
+Name[gl]=Chinés
+Name[he]=סינית
+Name[hi]=चाइनीस
+Name[hr]=Kineski
+Name[hsb]=Chinsce
+Name[hu]=Kínai
+Name[id]=Cina
+Name[is]=Kínverska
+Name[it]=Cinese
+Name[ja]=中国語
+Name[ka]=ჩინური
+Name[kk]=Қытайша
+Name[km]=áž…áž·áž“
+Name[ko]=중국어
+Name[ku]=Çînî
+Name[lb]=Chinesesch
+Name[lt]=KinieÄių
+Name[lv]=Ķīniešu
+Name[mi]=Reo Häina
+Name[mk]=КинеÑки
+Name[mn]=Ð¥Ñтад
+Name[ms]=China
+Name[mt]=Ċiniż
+Name[nb]=Kinesisk
+Name[nds]=Chineesch
+Name[ne]=चिनियाà¤
+Name[nl]=Chinees
+Name[nn]=Kinesisk
+Name[nso]=Se-China
+Name[oc]=Chinès
+Name[pa]=ਚੀਨੀ
+Name[pl]=Chiński
+Name[pt]=Chinês
+Name[pt_BR]=Chinês
+Name[ro]=Chineză
+Name[ru]=КитайÑкий
+Name[rw]=Igishinwa
+Name[se]=Kiinnágiella
+Name[sk]=ÄínÅ¡tina
+Name[sl]=kitajsko
+Name[sq]=Kinezisht
+Name[sr]=КинеÑки
+Name[sr@Latn]=Kineski
+Name[ss]=SiShayina
+Name[sv]=Kinesiska
+Name[ta]=சீனமà¯
+Name[te]=చైనీసà±
+Name[tg]=Хитоӣ
+Name[th]=ภาษาจีน
+Name[tr]=Çince
+Name[tt]=Çinçä
+Name[uk]=КитайÑька
+Name[uz]=Xitoycha
+Name[uz@cyrillic]=Хитойча
+Name[ven]=Mutshaina
+Name[vi]=Trung quốc
+Name[wa]=Chinwès
+Name[xh]=Isitshayina
+Name[zh_CN]=中文
+Name[zh_HK]=中文
+Name[zh_TW]=中文
+Name[zu]=Isi-Shayina
+[zh_CN]
+Name=Chinese Simplified
+Name[af]=Sjinese vereenvoudig
+Name[be]=КітайÑÐºÐ°Ñ ÑпрошчанаÑ
+Name[bg]=КитайÑки опроÑтен
+Name[bn]=সরলীকৃত চৈনিক
+Name[br]=Sineg eeun
+Name[bs]=Kineski pojednostavljeni
+Name[ca]=Xinès simplificat
+Name[cs]=Čínský (zjednodušená)
+Name[csb]=Chińsczi Prosti
+Name[cy]=Tseineeg Syml
+Name[da]=Kinesisk simplificeret
+Name[de]=Chinesisch (vereinfachtes)
+Name[el]=Κινέζικα απλά
+Name[eo]=Simpla Ĉina
+Name[es]=Chino simplificado
+Name[et]=Hiina (lihtsustatud)
+Name[eu]=Txinatar soildua
+Name[fa]=زبان چینی ساده‌شده
+Name[fi]=Yksinkertaistettu kiina
+Name[fr]=Chinois simplifié
+Name[fy]=Sjineesk (ynfaldich)
+Name[ga]=Sínis Simplithe
+Name[gl]=Chinés simplificado
+Name[he]=סינית מופשטת
+Name[hr]=Kineski pojednostavljen
+Name[hsb]=Chinsce (zjednorjene)
+Name[hu]=Kínai (egyszerűsített)
+Name[id]=Cina Sederhana
+Name[is]=Einfölduð kínverska
+Name[it]=Cinese semplificato
+Name[ja]=中国語 簡体字
+Name[ka]=ჩინური გáƒáƒ›áƒáƒ áƒ¢áƒ˜áƒ•áƒ”ბული
+Name[kk]=Жеңілдеткен қытайша
+Name[km]=ចិនសាមញ្ញ
+Name[ku]=Çîniya Hesankirî
+Name[lb]=Einfacht Chinesesch
+Name[lt]=Kinų supaprastinta
+Name[lv]=ĶīnieÅ¡u vienkÄrÅ¡otÄ
+Name[mk]=КинеÑки поедноÑтавен
+Name[nb]=Forenklet kinesisk
+Name[nds]=Vereenfacht Chineesch
+Name[ne]=सरलीकृत चिनियाà¤
+Name[nl]=Chinees (Vereenvoudigd)
+Name[nn]=Kinesisk (forenkla)
+Name[pa]=ਚੀਨੀ ਸਧਾਰਨ
+Name[pl]=Chiński uproszczony
+Name[pt]=Chinês Simplificado
+Name[pt_BR]=Chinês Simplificado
+Name[ro]=Chineză simplificată
+Name[ru]=КитайÑкий (КÐР)
+Name[rw]=Igishinwa Cyoroheje
+Name[se]=Ãlkiduvvon kiinnágiella
+Name[sk]=ÄínÅ¡tina (zjednoduÅ¡ená)
+Name[sl]=poenostavljeno kitajsko
+Name[sr]=ПоједноÑтављени кинеÑки
+Name[sr@Latn]=Pojednostavljeni kineski
+Name[sv]=Förenklad kinesiska
+Name[ta]=சீனம௠சà¯à®²à®ªà®®à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯
+Name[te]=సరళికరించిన చైనీసà±
+Name[tg]=Хитоӣ (Оддӣ)
+Name[th]=ภาษาจีนประยุà¸à¸•à¹Œ
+Name[tr]=Basitleştirilmiş Çince
+Name[tt]=Çinçä (Ciñel)
+Name[uk]=КитайÑька (Ñпрощена)
+Name[uz]=Soddalashtirilgan Xitoycha
+Name[uz@cyrillic]=Соддалаштирилган Хитойча
+Name[vi]=Trung quốc (phổ thông)
+Name[zh_CN]=简体中文
+Name[zh_HK]=簡體中文
+Name[zh_TW]=簡體中文
+[zh_HK]
+Name=Chinese (Hong Kong)
+Name[be]=КітайÑÐºÐ°Ñ (Гонг-Конг)
+Name[bg]=КитайÑки (Хонг Конг)
+Name[br]=Sinaeg (Hong Kong)
+Name[bs]=Kineski (Hong Kong)
+Name[ca]=Xinès (Hong Kong)
+Name[cs]=Čínský (Hong Kong)
+Name[csb]=Chińsczi (Hong Kong)
+Name[da]=Kinesisk (Hong Kong)
+Name[de]=Chinesisch (Hongkong)
+Name[el]=Κινέζικα (Χονγκ Κονγκ)
+Name[eo]=Ĉina (Hong Kong)
+Name[es]=Chino (Hong Kong)
+Name[et]=Hiina (Hong Kong)
+Name[eu]=Txinera (Hong Kong)
+Name[fa]=چینی)هنگ کنگ(
+Name[fi]=Kiina (Hong Kong)
+Name[fr]=Chinois (Hong Kong)
+Name[fy]=Sjineesk (Hong Kong)
+Name[ga]=Sínis (Hong Cong)
+Name[gl]=Chinés (Hong Kong)
+Name[he]=סינית (הונג קונג)
+Name[hr]=Kineski (Hong Kong)
+Name[hu]=Kínai (hongkongi)
+Name[id]=Cina (Hong Kong)
+Name[is]=Kínverska (Hong Kong)
+Name[it]=Cinese (Hong Kong)
+Name[ja]=中国語 (香港)
+Name[ka]=ჩინური (ჰáƒáƒœáƒ’ კáƒáƒœáƒ’ი)
+Name[kk]=Қытайша (СÑнган)
+Name[km]=ចិន (ហុងកុង)
+Name[ku]=Çînî (Hong Kong)
+Name[lb]=Chinesesch (Hong Kong)
+Name[lt]=KinieÄių (Honkongo)
+Name[lv]=Ķīniešu (Honkongas)
+Name[mk]=КинеÑки (Хонг Конг)
+Name[ms]=China (Hong Kong)
+Name[nb]=Kinesisk (Hong kong)
+Name[nds]=Chineesch (Hong Kong)
+Name[ne]=चिनियाठ(हङकङ)
+Name[nl]=Chinees (Hong Kong)
+Name[nn]=Kinesisk (Hong Kong)
+Name[pa]=ਚੀਨੀ (ਹਾਂਗਕਾਂਗ)
+Name[pl]=Chiński (Hong Kong)
+Name[pt]=Chinês (Hong Kong)
+Name[pt_BR]=Chinês (Hong Kong)
+Name[ro]=Chineză (Hong Kong)
+Name[ru]=КитайÑкий (Гонконг)
+Name[se]=Kiinnágiella (Hong Kong)
+Name[sk]=ÄínÅ¡tina (Hongkong)
+Name[sl]=kitajsko (Hong Kong)
+Name[sr]=КинеÑки (Хонгконг)
+Name[sr@Latn]=Kineski (Hongkong)
+Name[sv]=Kinesiska (Hong Kong)
+Name[te]=చైనీసౠ(హాంగౠకాంగà±)
+Name[tg]=Хитоӣ (Гон-Конг)
+Name[th]=ภาษาจีี (ฮ่องà¸à¸‡)น
+Name[tr]=Çince (Hong Kong)
+Name[uk]=КитайÑька (Гонконг)
+Name[uz]=Xitoycha (Gongkong)
+Name[uz@cyrillic]=Хитойча (Гонгконг)
+Name[vi]=Trung quốc (Hồng Kông)
+Name[zh_CN]=ç¹ä½“中文(香港)
+Name[zh_TW]=正體中文(香港)
+[zh_TW]
+Name=Chinese Traditional
+Name[af]=Sjinese tradisioneel
+Name[be]=КітайÑÐºÐ°Ñ Ñ‚Ñ€Ð°Ð´Ñ‹Ñ†Ñ‹Ð¹Ð½Ð°Ñ
+Name[bg]=КитайÑки традиционен
+Name[bn]=পারমà§à¦ªà¦°à¦¿à¦• চৈনিক
+Name[br]=Sinaeg da gustum
+Name[bs]=Kineski tradicionalni
+Name[ca]=Xinès tradicional
+Name[cs]=Čínský (tradiÄní)
+Name[csb]=Chińsczi Tradicëjny
+Name[cy]=Tsieineeg Traddodiadol
+Name[da]=Kinesisk traditionel
+Name[de]=Chinesisch (traditionelles)
+Name[el]=Κινέζικα παÏαδοσιακά
+Name[eo]=Tradicia Ĉina
+Name[es]=Chino tradicional
+Name[et]=Hiina (traditsiooniline)
+Name[eu]=Txinatar tradizionala
+Name[fa]=چینی سنتی
+Name[fi]=Perinteinen kiina
+Name[fr]=Chinois traditionnel
+Name[fy]=Sjineesk (tradisjoniel)
+Name[ga]=Sínis Thraidisiúnta
+Name[gl]=Chinés Tradicional
+Name[he]=סינית מסורתית
+Name[hr]=Kineski tradicionalan
+Name[hsb]=Chinsce (tradicionalnje)
+Name[hu]=Kínai (hagyományos)
+Name[id]=Cina Tradisional
+Name[is]=Hefðbundin kínverska
+Name[it]=Cinese tradizionale
+Name[ja]=中国語 ç¹ä½“å­—
+Name[ka]=ჩინური ტრáƒáƒ“იციული
+Name[kk]=ДәÑтүрлі қытайша
+Name[km]=ចិន​បុរាណ
+Name[ku]=Çîniya Kevneşop
+Name[lb]=Traditionellt Chinesesch
+Name[lt]=Kinų tradicinė
+Name[lv]=ĶīnieÅ¡u tradicionÄlÄ
+Name[mk]=КинеÑки традиционален
+Name[nb]=Tradisjonell kinesisk
+Name[nds]=Traditschonell Chineesch
+Name[ne]=चिनियाठपरमà¥à¤ªà¤°à¤¾à¤—त
+Name[nl]=Chinees (Traditioneel)
+Name[nn]=Kinesisk (tradisjonell)
+Name[pa]=ਚੀਨੀ ਮੂਲ
+Name[pl]=Chiński tradycyjny
+Name[pt]=Chinês Tradicional
+Name[pt_BR]=Chinês Tradicional
+Name[ro]=Chineză tradiţională
+Name[ru]=КитайÑкий (Тайвань)
+Name[rw]=Igishinwa Karande
+Name[se]=ÃrbevirolaÅ¡ kiinnágiella
+Name[sk]=ÄínÅ¡tina (tradiÄná)
+Name[sl]=tradicionalno kitajsko
+Name[sr]=Традиционални кинеÑки
+Name[sr@Latn]=Tradicionalni kineski
+Name[sv]=Traditionell kinesiska
+Name[ta]=சீனம௠பழமையானதà¯
+Name[te]=సాంపà±à°°à°¦à°¾à°¯à°• చైనీసà±
+Name[tg]=Хитоӣ (Ðнъанавӣ)
+Name[th]=ภาษาจีนดั้งเดิม
+Name[tr]=Geleneksel Çince
+Name[tt]=Çinçä (Ğädäti)
+Name[uk]=КитайÑька (традиційна)
+Name[uz]=Anʼanaviy Xitoycha
+Name[uz@cyrillic]=Ðнъанавий Хитойча
+Name[vi]=Trung quốc (truyá»n thống)
+Name[zh_CN]=ç¹ä½“中文
+Name[zh_HK]=ç¹é«”中文
+Name[zh_TW]=正體中文
+[zu]
+Name=Zulu
+Name[af]=Zoeloe
+Name[ar]=الزولو
+Name[be]=ЗулуÑкаÑ
+Name[bg]=Зулу
+Name[bn]=জà§à¦²à§
+Name[br]=Zouloued
+Name[csb]=Zulusczi
+Name[eo]=Zulua
+Name[es]=Zulú
+Name[et]=Suulu
+Name[eu]=Zuluera
+Name[fa]=ناتالی
+Name[fr]=Zoulou
+Name[ga]=Súlúis
+Name[he]=זולו
+Name[hi]=ज़à¥à¤²à¥
+Name[is]=Zúlú
+Name[ja]=ズールー語
+Name[ka]=ზულუსური
+Name[kk]=Зулу
+Name[km]=ហ្ស៊ូលូ
+Name[ko]=줄루어
+Name[lv]=Zulusu
+Name[mk]=Зулу
+Name[mn]=Зулу
+Name[mt]=Żulu
+Name[ne]=जà¥à¤²à¥
+Name[nso]=Se-Zulu
+Name[pa]=ਜ਼ੂਲੂ
+Name[pl]=Zuluski
+Name[ru]=ЗулуÑÑкий
+Name[rw]=Ikizulu
+Name[se]=Zulugiella
+Name[sk]=zuluština
+Name[sl]=zulu
+Name[sr]=Зулу
+Name[ss]=SiZulu
+Name[ta]=ஜà¯à®²à¯
+Name[te]=జూలà±
+Name[tg]=Зулу
+Name[th]=ภาษาซูลู
+Name[tt]=Zuluça
+Name[uk]=ЗулуÑька
+Name[uz]=Zulucha
+Name[uz@cyrillic]=Зулуча
+Name[ven]=Muzulu
+Name[vi]=Xu-lu
+Name[wa]=Zoulou
+Name[xh]=Isizulu
+Name[zh_CN]=祖é²è¯­
+Name[zh_HK]=袓魯語
+Name[zh_TW]=袓魯語
+Name[zu]=Isi-Zulu
diff --git a/kdecore/configure.in.in b/kdecore/configure.in.in
new file mode 100644
index 000000000..b2fe9bd6e
--- /dev/null
+++ b/kdecore/configure.in.in
@@ -0,0 +1,234 @@
+dnl Compile in the exec prefix to help kstddirs in finding dynamic libs
+AC_DEFINE_UNQUOTED(__KDE_EXECPREFIX, "$exec_prefix", [execprefix or NONE if not set, for libloading])
+
+dnl Compile in kde_bindir to safely find kdesu_stub.
+if test "$exec_prefix" = "NONE"; then
+ bindir_str="\"$prefix/bin\""
+else
+ bindir_str="\"$exec_prefix/bin\""
+fi
+AC_DEFINE_UNQUOTED(__KDE_BINDIR, $bindir_str, [KDE bindir])
+
+dnl tests for openpty support
+AC_MSG_CHECKING(whether we can use openpty)
+AC_ARG_ENABLE(openpty,
+ [ --disable-openpty disable openpty (UNIX98 terminals) support [default=enabled]],
+ [ac_use_openpty=$enableval], [ac_use_openpty=yes])
+if test "$ac_use_openpty" = "yes"; then
+ kde_safe_LIBS=$LIBS
+ LIBS="$LIBS $LIBUTIL"
+ AC_TRY_RUN([
+#include <pty.h>
+
+int main(int argc, char* argv) {
+ int master_fd, slave_fd;
+ int result;
+
+ result = openpty(&master_fd, &slave_fd, 0, 0, 0);
+
+ return 0;
+}
+], [ac_use_openpty="yes"], [ac_use_openpty="no"])
+ LIBS=$kde_safe_LIBS
+fi
+if test "$ac_use_openpty" = "yes"; then
+ AC_DEFINE(HAVE_OPENPTY, 1, [Defines whether we can use the openpty() function])
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+dnl -------
+dnl Test for libidn (IDNA support)
+dnl -------
+
+AC_ARG_WITH(libidn,
+ [AC_HELP_STRING(--with-libidn,
+ [enable support for libidn @<:@default=check@:>@])],
+ [], with_libidn=check)
+LIB_IDN=
+if test "x$with_libidn" != xno; then
+ AC_CHECK_HEADERS([idna.h punycode.h stringprep.h])
+ KDE_CHECK_LIB(idn, idna_to_ascii_4i, [
+ AC_DEFINE_UNQUOTED(HAVE_LIBIDN, 1, [Defined if you have libidn in your system])
+ LIB_IDN=-lidn
+ ])
+ if test "x$with_libidn" != xcheck && test -z "$LIB_IDN"; then
+ AC_MSG_ERROR([--with-libidn was given, but test for libidn failed])
+ fi
+fi
+AC_SUBST(LIB_IDN)
+
+dnl --------
+dnl KNetwork extra configuration
+dnl --------
+
+netincludes="#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>"
+
+kde_safe_LIBS="$LIBS"
+LIBS="$LIBS $all_libraries $X_EXTRA_LIBS"
+AC_CHECK_FUNCS([inet_ntop inet_pton getpeername getsockname getsockopt gethostbyname2_r gethostbyname_r gethostbyname2 if_nametoindex getprotobyname_r getservbyname_r getservbyport_r])
+LIBS="$kde_safe_LIBS"
+
+dnl
+dnl Some systems, like OpenBSD 3.6, have getservbyname_r but don't declare it
+dnl
+if test "x$ac_cv_func_getservbyname_r" = "xyes"; then
+
+ AC_CHECK_DECLS([getservbyname_r],,,[$netincludes])
+
+fi
+
+KDE_CHECK_HEADERS([netinet/in.h net/if.h],,,[$netincludes])
+KDE_CHECK_HEADERS([sys/filio.h])
+AC_CHECK_FUNCS([usleep poll madvise])
+
+dnl Check for struct addrinfo
+AC_CHECK_TYPES([struct addrinfo],,,[$netincludes])
+
+kde_safe_LIBS="$LIBS"
+LIBS="$LIBS $LIBSOCKET"
+AC_CHECK_FUNCS([getaddrinfo],
+ [
+ dnl Even though we now know that getaddrinfo is there, make sure getnameinfo is there too
+ kde_gai_ok=true
+ AC_CHECK_FUNCS([freeaddrinfo getnameinfo gai_strerror], : ,
+ [
+ kde_gai_ok=false
+ AC_DEFINE(HAVE_BROKEN_GETADDRINFO, 1, [Define if getaddrinfo is broken and should be replaced])
+ AC_DEFINE(GETADDRINFO_RETURNS_UNIX, 1, [Define if getaddrinfo returns AF_UNIX sockets])
+ break
+ ])
+
+ AC_MSG_CHECKING([if getaddrinfo works using numeric service with null host])
+ dnl On AIX (4.3), getaddrinfo returns NULL if the hint
+ dnl is AF_INET/SOCK_STREAM/AI_PASSIVE.
+ dnl The error code reports "Host not found".
+ dnl It only seems to return non-NULL if the port is known (eg. in
+ dnl /etc/services).
+ AC_TRY_RUN(dnl
+ [
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h>
+ #include <string.h>
+ int main()
+ {
+ struct addrinfo hint, *res;
+ int err;
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = AF_INET;
+ hint.ai_protocol = 0;
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_flags = AI_PASSIVE;
+ err = getaddrinfo(0, "18300", &hint, &res); /* kxmlrpc tries this */
+ if (err != 0 || res == 0 || res->ai_family != AF_INET)
+ return 1;
+ return 0;
+ }
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_DEFINE(HAVE_BROKEN_GETADDRINFO, 1, [Define if getaddrinfo is broken and should be replaced])
+ ],
+ [
+ AC_MSG_RESULT(cross compiling. We hope so)
+ ])
+ ]
+)
+LIBS="$kde_safe_LIBS"
+
+AC_CHECK_MEMBERS([struct sockaddr.sa_len],,,[#include <sys/socket.h>])
+AC_CHECK_TYPES([struct sockaddr_in6],
+ [AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id],,,[#include <netinet/in.h>])],,
+ [#include <sys/types.h>
+#include <netinet/in.h>])
+
+AC_MSG_CHECKING([for GLIBC function backtrace])
+AC_TRY_LINK(dnl
+ [
+ #include <execinfo.h>
+ ],
+ [
+ void* trace[256];
+ backtrace(trace, 256);
+ ],
+ [
+ AC_DEFINE(HAVE_BACKTRACE, 1, [Define if execinfo.h exists and defines backtrace (GLIBC >= 2.1)])
+ AC_MSG_RESULT(yes)
+ ],
+ AC_MSG_RESULT(no)
+)
+
+AC_CHECK_HEADERS(sys/mount.h)
+
+dnl AC_OUTPUT(kdecore/kde-config.cpp)
+
+AM_CONFIG_HEADER(kdecore/kdemacros.h)
+
+SVGICONS=
+
+AC_ARG_WITH(libart,
+ [AC_HELP_STRING(--with-libart,
+ [enable support for libart @<:@default=check@:>@])],
+ [], with_libart=check)
+
+if test "x$with_libart" != xno; then
+ KDE_FIND_PATH(libart2-config, LIBART_CONFIG, [${prefix}/bin ${exec_prefix}/bin], [
+ AC_MSG_WARN([Could not find libart anywhere, check http://www.levien.com/libart/])
+ ])
+
+ if test -n "$LIBART_CONFIG"; then
+ vers=`$LIBART_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 2003008
+ then
+ LIBART_LIBS="`$LIBART_CONFIG --libs`"
+ LIBART_RPATH=
+ for args in $LIBART_LIBS; do
+ case $args in
+ -L/usr/lib) ;;
+ -L*)
+ LIBART_RPATH="$LIBART_RPATH $args"
+ ;;
+ esac
+ done
+ LIBART_RPATH=`echo $LIBART_RPATH | sed -e "s/-L/-R/g"`
+ LIBART_CFLAGS="`$LIBART_CONFIG --cflags`"
+ SVGICONS=svgicons
+
+ AC_DEFINE_UNQUOTED(HAVE_LIBART, 1, [Defines if your system has the libart library])
+ else
+ AC_MSG_WARN([You need at least libart 2.3.8])
+ fi
+ fi
+ if test "x$with_libart" != xcheck && test -z "$LIBART_LIBS"; then
+ AC_MSG_ERROR([--with-libart was given, but test for libart failed])
+ fi
+fi
+
+
+AC_SUBST(LIBART_LIBS)
+AC_SUBST(LIBART_CFLAGS)
+AC_SUBST(LIBART_RPATH)
+AM_CONDITIONAL(include_SVGICONS, test -n "$SVGICONS")
+
+AC_CHECK_HEADERS([sys/stropts.h sys/select.h libutil.h util.h termios.h pty.h termio.h])
+AC_MSG_CHECKING([for revoke(tty) in unistd.h])
+AC_TRY_LINK(dnl
+ [
+ #include <unistd.h>
+ ],
+ [
+ revoke("/dev/tty");
+ ],
+ [
+ AC_DEFINE(HAVE_REVOKE, 1, [Define if revoke(tty) is present in unistd.h])
+ AC_MSG_RESULT(yes)
+ ],
+ AC_MSG_RESULT(no)
+)
diff --git a/kdecore/eventsrc b/kdecore/eventsrc
new file mode 100644
index 000000000..15b1016dc
--- /dev/null
+++ b/kdecore/eventsrc
@@ -0,0 +1,2741 @@
+[!Global!]
+IconName=kmenu
+Comment=KDE System Notifications
+Comment[af]=KDE Stelsel Inkennistelling
+Comment[ar]=تنبيهات كيدي
+Comment[az]=KDE Sistem Bildirişləri
+Comment[be]=СіÑÑ‚ÑÐ¼Ð½Ñ‹Ñ Ð½Ð°Ð³Ð°Ð´Ð²Ð°Ð½Ð½Ñ– KDE
+Comment[bg]=СиÑтемни ÑъобщениÑ
+Comment[bn]=কে.ডি.ই সিসà§à¦Ÿà§‡à¦® বারà§à¦¤à¦¾à¦¬à¦²à§€
+Comment[br]=Kemennoù ar reizhiad KDE
+Comment[bs]=KDE Sistemska obavještenja
+Comment[ca]=Notificacions del sistema KDE
+Comment[cs]=Systémová hlášení prostředí KDE
+Comment[csb]=Systemòwé òdkôzanié w KDE
+Comment[cy]=Hysbysiadau Cysawd KDE
+Comment[da]=KDE-systembekendtgørelser
+Comment[de]=KDE-Systemnachrichten
+Comment[el]=Ειδοποιήσεις συστήματος του KDE
+Comment[eo]=KDE-Sistematentigoj
+Comment[es]=Notificaciones del sistema de KDE
+Comment[et]=KDE süsteemi märguanded
+Comment[eu]=KDEren sistemako jakinarazpenak
+Comment[fa]=اخطارهای سیستم KDE
+Comment[fi]=KDE:n järjestelmähuomautukset
+Comment[fr]=Notifications du système KDE
+Comment[fy]=KDE Systeemberjochten
+Comment[ga]=Fógairt Chórais KDE
+Comment[gl]=Notificacións do Sistema de KDE
+Comment[he]=הודעות מערכת של KDE
+Comment[hi]=केडीई तंतà¥à¤° सूचना
+Comment[hr]=KDE sistemske obavijesti
+Comment[hsb]=KDE systemowe powěsće
+Comment[hu]=KDE rendszerüzenetek
+Comment[id]=Sistem Pemberitahuan KDE
+Comment[is]=Tilkynningar KDE kerfisins
+Comment[it]=Avvisi di sistema di KDE
+Comment[ja]=KDE システム通知
+Comment[ka]=KDE სისტემური შეტყáƒáƒ‘ინებები
+Comment[kk]=KDE жүйе құлақтандырулар
+Comment[km]=ការ​ជូន​ដំណឹង​អំពី​ប្រពáŸáž“្ធ​របស់ KDE
+Comment[ko]=KDE 시스템 알림
+Comment[lb]=KDE-System-Norichten
+Comment[lt]=KDE Sistemos Pranešimai
+Comment[lv]=KDE Sistēmas Paziņojumi
+Comment[mk]=KDE ÑиÑтемÑки извеÑтувања
+Comment[mn]=KDE-СиÑтемийн Ñонордуулга
+Comment[ms]= Sistem Pemberitahuan KDE
+Comment[mt]=Notifiki tas-sistema KDE
+Comment[nb]=KDE Systemvarsler
+Comment[nds]=KDE-Systeemnarichten
+Comment[ne]=KDE पà¥à¤°à¤£à¤¾à¤²à¥€ सूचना
+Comment[nl]=KDE Systeemnotificaties
+Comment[nn]=KDE Systempåminningar
+Comment[nso]=Ditsebiso tsa System ya KDE
+Comment[oc]=Notificacions dèu sistemo KDE
+Comment[pa]=KDE ਸਿਸਟਮ ਟਿੱਪਣੀਆਂ
+Comment[pl]=Powiadamianie systemowe w KDE
+Comment[pt]=Mensagens do sistema
+Comment[pt_BR]=Notificações de sistema do KDE
+Comment[ro]=Sistem de notificare KDE
+Comment[ru]=СиÑтемные ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ KDE
+Comment[rw]=Amamenyekanisha ya Sisitemu KDE
+Comment[se]=KDE vuogádatdieđáhusat
+Comment[sk]=KDE Systémové správy
+Comment[sl]=Sistemska obvestila KDE
+Comment[sq]=Njoftim nga Sistemi KDE
+Comment[sr]=KDE-ова ÑиÑтемÑка обавештења
+Comment[sr@Latn]=KDE-ova sistemska obaveštenja
+Comment[ss]=Tatiso temshini we KDE
+Comment[sv]=KDE:s systemunderrättelser
+Comment[ta]=கேடிஇ கணினி அறிவிபà¯à®ªà¯à®•à®³à¯
+Comment[te]=కెడిఈ à°µà±à°¯à°µà°¸à±à°¥ à°ªà±à°°à°•à°Ÿà°¨à°²à±
+Comment[tg]=Хабарҳои ÑиÑтемавии KDE
+Comment[th]=à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¸‚องระบบ KDE
+Comment[tr]=KDE Sistem Bildirimleri
+Comment[tt]=KDE'nıñ Sistem Beldermäläre
+Comment[uk]=СиÑтемні Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ KDE
+Comment[uz]=KDE tizimning xabarnomalari
+Comment[uz@cyrillic]=KDE тизимнинг хабарномалари
+Comment[ven]=U divhadza maitele a KDE
+Comment[vi]=Thông báo hệ thống KDE
+Comment[wa]=Notifiaedjes sistinme di KDE
+Comment[xh]=Izaziso Zendlela ye KDE
+Comment[zh_CN]=KDE 系统通知
+Comment[zh_HK]=KDE 系統通知
+Comment[zh_TW]=KDE 系統通知
+Comment[zu]=Izaziso Zesistimu ye-KDE
+
+[Trash: emptied]
+Name=Trash: emptied
+Name[af]=Gemors: leeggemaak
+Name[be]=Сметніца: парожнÑÑ
+Name[bg]=Кошчето е изтрито
+Name[bn]=আবরà§à¦œà¦¨à¦¾: ফাà¦à¦•à¦¾
+Name[br]=Pod-lastez : goullonderet
+Name[bs]=Smeće: ispražnjeno
+Name[ca]=Paperera: buida
+Name[cs]=Koš vyprázdněn
+Name[csb]=Kòsz: wëczëszczony
+Name[da]=Affald: tømt
+Name[de]=Mülleimer: geleert
+Name[el]=Ο Κάδος ΑποÏÏιμμάτων άδειασε
+Name[en_GB]=Wastebin: emptied
+Name[eo]=Rubujo: Malplena
+Name[es]=Papelera: vaciada
+Name[et]=Prügikast: tühjendatud
+Name[eu]=Zakarrontzia: hustuta
+Name[fa]=زباله: خالی‌شده
+Name[fi]=Roskakori: tyhjennetty
+Name[fr]=Corbeille : vidée
+Name[fy]=Jiskefet: leech makke
+Name[ga]=Bruscar: folmhaithe
+Name[gl]=Lixo: valeirado
+Name[he]=×שפה: רוקן
+Name[hr]=Otpad: ispražnjeno
+Name[hsb]=Papjernik: wuprózdnjeny
+Name[hu]=Szemétkosár: kiürítve
+Name[id]=Tempat Sampah: emptied
+Name[is]=Rusl: tæmt
+Name[it]=Cestino: svuotato
+Name[ja]=ã”ã¿ç®±: 空
+Name[ka]=ურნáƒ: ცáƒáƒ áƒ˜áƒ”ლიáƒ
+Name[kk]=Өшірігендер жойылды
+Name[km]=ធុង​សំរាម ៖ បាន​សម្អាáž
+Name[lb]=Dreckskëscht: eidel
+Name[lt]=Šiukšliadėžė: ištuštinta
+Name[lv]=Miskaste: iztukšota
+Name[mk]=Корпа: празна
+Name[ms]=Tong Sampah; dikosongkan
+Name[nb]=Papirkurven: tømt
+Name[nds]=Affalltünn: leddigmaakt
+Name[ne]=रदà¥à¤¦à¥€à¤Ÿà¥‹à¤•à¤°à¥€: रितà¥à¤¤à¤¿à¤¯à¥‹
+Name[nl]=Prullenbak: geleegd
+Name[nn]=Papirkorg: tømt
+Name[pa]=ਰੱਦੀ: ਖਾਲੀ ਕੀਤੀ ਗਈ
+Name[pl]=Kosz: opróżniony
+Name[pt]=Lixo: esvaziado
+Name[pt_BR]=Lixeira: vazia
+Name[ro]=Gunoi: golit
+Name[ru]=Корзина очищена
+Name[rw]=Agatebo: gafite ubusa
+Name[se]=Ruskalihtti: gurrejuvvon
+Name[sk]=Koš: vyprázdnený
+Name[sl]=Smeti: izpraznjeno
+Name[sr]=Смеће: иÑпражњено
+Name[sr@Latn]=Smeće: ispražnjeno
+Name[sv]=Papperskorg: tömd
+Name[ta]=தொடà¯à®Ÿà®¿: காலியாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯
+Name[te]=చెతà±à°¤ : ఖాళి
+Name[tg]=Ðхлотдон: тозашуда
+Name[th]=ถังขยะ: เททิ้ง
+Name[tr]=Çöp: boşaltıldı
+Name[tt]=Çüplek: buşatıldı
+Name[uk]=Смітник: Ñпорожнено
+Name[uz]=Chiqindilar qutisi boʻshatildi
+Name[uz@cyrillic]=Чиқиндилар қутиÑи бўшатилди
+Name[vi]=Rác: đã đổ
+Name[zh_CN]=回收站:已清空
+Name[zh_TW]=資æºå›žæ”¶æ¡¶å·²æ¸…空
+Comment=The trash has been emptied
+Comment[af]=Die gemors is leeggemaak
+Comment[be]=Сметніца парожнÑÑ
+Comment[bg]=Съдържанието а кошчето е изтрито
+Comment[bn]=আবরà§à¦œà¦¨à¦¾à¦° বাকà§à¦¸ ফাà¦à¦•à¦¾ করা হয়েছে
+Comment[br]=Goullonderet e oa ar pod-lastez
+Comment[bs]=Smeće je ispražnjeno
+Comment[ca]=S'ha buidat la paperera
+Comment[cs]=Koš byl vyprázdněn
+Comment[csb]=Kòsz òstôł wëczëszczony
+Comment[da]=Affaldet er blevet tømt ud
+Comment[de]=Der Mülleimer wurde geleert
+Comment[el]=Ο Κάδος ΑποÏÏιμμάτων άδειασε
+Comment[en_GB]=The wastebin has been emptied
+Comment[eo]=la rubujo malpleniÄis
+Comment[es]=La papelera se ha vaciado
+Comment[et]=Prügikast on tühjendatud
+Comment[eu]=Zakarrontzia hustu da
+Comment[fa]=زباله خالی شده است
+Comment[fi]=Roskakori on tyhjennetty
+Comment[fr]=La corbeille a été vidée
+Comment[fy]=It jiskefet is leech makke
+Comment[ga]=Folmhaíodh an bruscar
+Comment[gl]=O lixo foi valeirado
+Comment[he]=פה ×”×שפה רוקן
+Comment[hr]=Otpad je ispražnjen
+Comment[hsb]=sym papjernik wuprózdnił
+Comment[hu]=A szemétkosár kiürült
+Comment[id]=Tempat sampah sudah dikosongkan
+Comment[is]=Ruslafatan hefur verið tæmd
+Comment[it]=Il cestino è stato svuotato
+Comment[ja]=ã”ã¿ç®±ã‚’空ã«ã—ã¾ã—ãŸ
+Comment[ka]=ურნრდáƒáƒªáƒáƒ áƒ˜áƒ”ლდáƒ
+Comment[kk]=Өшірілгендер қапшық тазарды
+Comment[km]=ធុង​សំរាម​ážáŸ’រូវ​បាន​សម្អាáž
+Comment[lb]=D'Dreckskëscht ass eidelgemat ginn
+Comment[lt]=Šiukšliadėžė buvo ištuštinta
+Comment[lv]=Miskaste ir iztukšota
+Comment[mk]=Корпата беше иÑпразнета
+Comment[ms]=Tong sampah telah dikosongkan
+Comment[nb]=Papirkurven er tømt
+Comment[nds]=De Affalltünn wöör leddig maakt
+Comment[ne]=रदà¥à¤¦à¥€à¤Ÿà¥‹à¤•à¤°à¥€ रितà¥à¤¤à¤¿à¤à¤•à¥‹ छ
+Comment[nl]=De prullenbak is geleegd
+Comment[nn]=Papirkorga er tømt
+Comment[pa]=ਰੱਦੀ ਨੂੰ ਖਾਲੀ ਕੀਤਾ ਜਾ ਚà©à©±à¨•à¨¾ ਹੈ
+Comment[pl]=Kosz został opróżniony
+Comment[pt]=O lixo foi esvaziado
+Comment[pt_BR]=A lixeira foi esvaziada
+Comment[ro]=CoÅŸul de gunoi a fost golit
+Comment[ru]=Корзина была очищена
+Comment[rw]=Agatebo kavanywemo byose
+Comment[se]=Ruskelihtti gurrejuvvui
+Comment[sk]=Kôš bol vyprázdnený
+Comment[sl]=Smeti so spraznjene
+Comment[sr]=Смеће је иÑпражњено
+Comment[sr@Latn]=Smeće je ispražnjeno
+Comment[sv]=Papperskorgen har tömts
+Comment[ta]=தொடà¯à®Ÿà®¿ காலியாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯
+Comment[te]=చెతà±à°¤ నౠపారబొయటమైనది
+Comment[tg]=Ðхлотдон тоза карда шуд
+Comment[th]=เทถังขยะทิ้งà¹à¸¥à¹‰à¸§
+Comment[tr]=Çöp boşaltıldı
+Comment[tt]=Çüplek buşatılğan buldı
+Comment[uk]=Смітник було Ñпорожнено
+Comment[uz]=Chiqindilar qutisi boʻshatildi
+Comment[uz@cyrillic]=Чиқиндилар қутиÑи бўшатилди
+Comment[vi]=Rác đã được đổ.
+Comment[zh_CN]=回收站已被清空
+Comment[zh_TW]=資æºå›žæ”¶æ¡¶å·²æ¸…空。
+default_presentation=1
+
+[Textcompletion: rotation]
+Name=Textcompletion: rotation
+Name[af]=Teksvoltooiïng: rotering
+Name[ar]=اكمال نص: تدوير
+Name[az]=Textcompletion: döndərmə
+Name[be]=ЗаканчÑнне Ñ‚ÑкÑту: па колу
+Name[bg]=Ðвтоматично завършване: завъртане
+Name[bn]=Textcompletion: আবরà§à¦¤à¦¨
+Name[br]=KlokadurSrid : troerezh
+Name[bs]=Textcompletion: rotacija
+Name[ca]=Compleció de text: rotació
+Name[cs]=Doplňování textu: rotace
+Name[csb]=Dofùlowanié tekstu: rotacëjô
+Name[cy]=CwblhauTestun: cylchdroi
+Name[da]=Tekstkomplettering: rotation
+Name[de]=Textvervollständigung: rotierend
+Name[el]=ΣυμπλήÏωση κειμένου: πεÏιστÏοφή
+Name[eo]=Kkompletigo: rotacio
+Name[es]=Completado de texto: rotación
+Name[et]=Teksti lõpetamine: pööramine
+Name[eu]=Testu-osaketa: biraketa
+Name[fa]=تکمیل متن: چرخش
+Name[fi]=Tekstintäydennys: pyöritys
+Name[fr]=Autocomplètement de texte : rotation
+Name[fy]=Tekstkompletearing: rotaasje
+Name[ga]=Comhlánú téacs: imchasadh
+Name[gl]=Textcompletion: rotación
+Name[he]=השלמת טקסט: רוטציה
+Name[hi]=टेकà¥à¤¸à¥à¤Ÿ कमà¥à¤ªà¤²à¥€à¤¶à¤¨à¤ƒ रोटेशन
+Name[hr]=Textcompletion: rotacija
+Name[hsb]=Wudospołnjenje teksta: rotacija
+Name[hu]=Szövegkiegészítés: forgatás
+Name[id]=Pemenuhanteks: rotasi
+Name[is]=Textaklárun: snúningur
+Name[it]=Completamento testo: rotazione
+Name[ja]=テキスト補完: ç¹°ã‚Šè¿”ã—
+Name[ka]=თვითშევსებáƒ: მáƒáƒ¢áƒ áƒ˜áƒáƒšáƒ”ბáƒ
+Name[kk]=Ðвтотолтыру: бұрау
+Name[km]=ការ​បំពáŸáž‰â€‹áž¢ážáŸ’ážáž”ទ ៖ ការ​បង្វិល
+Name[ko]=글월 완성: 맴ëŒì´
+Name[lb]=Textergänzung: rotéierent
+Name[lt]=Textcompletion: sukimas
+Name[lv]=Tekstakomplekts: rotÄcija
+Name[mk]=Довршување текÑÑ‚: ротација
+Name[mn]=ТекÑÑ‚ гүйцÑÑлт: ÑргүүлÑлт
+Name[ms]= Penyudah teks: putaran
+Name[mt]=Kompletazzjoni tal-kliem: tidwir
+Name[nb]=Tekstfullføring: rotering
+Name[nds]=Textkompletteren: dreihen
+Name[ne]=पाठ समापà¥à¤¤à¤¿: परिकà¥à¤°à¤®à¤£
+Name[nl]=Tekstaanvulling: rotatie
+Name[nn]=Tekstfullføring: rotering
+Name[nso]=Phetso ya sengwalwana: tharelo
+Name[oc]=Textcompletion: rotacion
+Name[pa]=Textcompletion: ਘà©à©°à¨®à¨¾à¨“
+Name[pl]=Uzupełnianie tekstu: rotacja
+Name[pt]=Completação de texto: dei a volta
+Name[pt_BR]=Completar Texto: rotação
+Name[ro]=Completare text: rotire
+Name[ru]=Ðвтозавершение: поворот
+Name[rw]=Iyuzuzamwandiko: Ukuzenguruka
+Name[se]=Teakstaollašuhttin: joraheapmi
+Name[sk]=Doplnenie textu:rotácia
+Name[sl]=Dopolnjevanje: vrtenje
+Name[sq]=Mbarimtekski: rrotullim
+Name[sr]=Допуњавање текÑта: ротација
+Name[sr@Latn]=Dopunjavanje teksta: rotacija
+Name[ss]=Kucedzelwa kwembhalo:kujikeleta
+Name[sv]=Textkomplettering: rotation
+Name[ta]=உரைநிறைவà¯: சà¯à®´à®±à¯à®šà®¿
+Name[te]=వాచకపూరణ:à°­à±à°°à°®à°£à°‚
+Name[tg]=Худхотимадиҳӣ: гардиш
+Name[th]=à¸à¸²à¸£à¹€à¸•à¸´à¸¡à¸‚้อความให้สมบูรณ์: à¸à¸²à¸£à¸«à¸¡à¸¸à¸™
+Name[tr]=Textcompletion: çevirme
+Name[tt]=Süzazağı: äyländerü
+Name[uk]=Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ‚ÐµÐºÑту: обертаннÑ
+Name[uz]=Matnni tugatish: qaytarish
+Name[uz@cyrillic]=Матнни тугатиш: қайтариш
+Name[ven]=U fhela ha manwalwa: U mona
+Name[vi]=Nhập xong từ: xoay
+Name[xh]=Textcompletion: ujikeleziso
+Name[zh_CN]=文字补é½ï¼šè½®è½¬
+Name[zh_HK]=文字補齊:旋轉
+Name[zh_TW]=文字補齊:旋轉
+Name[zu]=Ukuqedwa kombhalo:ukujikelezisa
+Comment=The end of the list of matches has been reached
+Comment[af]=Die einde van die lys van ooreenkomste is bereik
+Comment[be]=ДаÑÑгнуты канец ÑпіÑа ÑупаданнÑÑž
+Comment[bg]=ДоÑтигнат е ÐºÑ€Ð°Ñ Ð½Ð° ÑпиÑъка от ÑъвпадениÑ
+Comment[bn]=মিলের তালিকার শেষে উপসà§à¦¥à¦¿à¦¤
+Comment[br]=Tizhet eo diwezh roll ar gendoareoù
+Comment[bs]=Došao sam do kraja liste pogodaka
+Comment[ca]=S'ha arribat al final de la llista de coincidències
+Comment[cs]=Dosaženo konce seznamu odpovídajících položek
+Comment[csb]=Je doszłé do kùńca lëstë dopasowaniów
+Comment[da]=Slutningen på listen over det fundne er nået
+Comment[de]=Das Ende der Liste mit Ãœbereinstimmungen wurde erreicht
+Comment[el]=Φτάσαμε στο τέλος της λίστας με τα ταιÏιάσματα
+Comment[eo]=Fino de la listo de kongruaĵoj
+Comment[es]=Se ha alcanzado el final de la lista de concordancias
+Comment[et]=Jõuti kokkulangevuste nimekirja lõppu
+Comment[eu]=Bat datozenen zerrendaren amaierara iritsi da
+Comment[fa]=به پایان Ùهرست تطبیقها رسیده است
+Comment[fi]=Osumalistan loppu saavutettu
+Comment[fr]=La fin de la liste des correspondances a été atteinte
+Comment[fy]=It ein fan de oerienkomstenlist is berikt
+Comment[gl]=Chegou-se á fin da lista de coincidéncias.
+Comment[he]=הגיעו לסוף רשימת ההת×מות
+Comment[hi]= मिलान सूची का अंतिम आ पंहà¥à¤šà¤¾.
+Comment[hr]=Stiglo se do završetka popisa podudarnosti
+Comment[hsb]=Sym na kóncu lisćiny namakankow
+Comment[hu]=A találatok listájának végére értem
+Comment[id]=Akhir daftar pencocokan telah dicapai
+Comment[is]=Enda listans yfir atriði sem passa náð
+Comment[it]=È stata raggiunta la fine della lista delle corrispondenze
+Comment[ja]=マッãƒãƒªã‚¹ãƒˆã®çµ‚端ã«é”ã—ã¾ã—ãŸ
+Comment[ka]=თáƒáƒœáƒ®áƒ•áƒ”დრáƒáƒ—რსიის ბáƒáƒšáƒ.
+Comment[kk]=СайкеÑтіктер тізімі Ñоңына жетті
+Comment[km]=បាន​ទៅ​ដល់​ចុង​បញ្ចប់​នៃ​បញ្ជី​ដំណូច
+Comment[lb]=D'Enn vun der Lëscht mat den Iwwerteneestëmmungen ass erreecht ginn
+Comment[lt]=Pasiektas atitikmenų sąrašo galas
+Comment[lv]=Sasniegtas atbilstību saraksta beigas
+Comment[mk]=ДоÑтигнат е крајот на лиÑтата на Ñовпаѓања
+Comment[ms]=Sampai ke akhiran senarai padanan
+Comment[nb]=Har kommet til slutten av lista over treff
+Comment[nds]=Dat is dat Enn vun de List mit Övereenstimmen
+Comment[ne]=मिलà¥à¤¦à¥‹ सूचीको अनà¥à¤¤à¥à¤¯à¤®à¤¾ पà¥à¤—िà¤à¤•à¥‹ छ
+Comment[nl]=Het einde van de lijst met overeenkomsten is bereikt
+Comment[nn]=Slutten av trefflista er nådd
+Comment[pa]=ਮੇਲ ਸੂਚੀ ਦਾ ਅੰਤ ਆ ਗਿਆ ਹੈ
+Comment[pl]=Osiągnięto koniec listy dopasowań
+Comment[pt]=O fim da lista de escolhas foi atingido
+Comment[pt_BR]=O fim da lista de coincidências foi atingido
+Comment[ro]=Am ajuns la sfîrşitul listei de potriviri
+Comment[ru]=ДоÑтигнут конец ÑпиÑка Ñовпадений.
+Comment[rw]=Impera y'urutonde rw'ibihura yagezweho
+Comment[se]=Ollii gávdnosiid listtu lohppii
+Comment[sk]=Bol dosiahnutý koniec zoznamu nájdených položiek
+Comment[sl]=To je konec seznama zadetkov
+Comment[sr]=ДоÑтигнут је крај лиÑте подударања
+Comment[sr@Latn]=Dostignut je kraj liste podudaranja
+Comment[sv]=Slutet på listan med träffar har nåtts
+Comment[ta]=பொரà¯à®¤à¯à®¤à®ªà¯ படà¯à®Ÿà®¿à®¯à®²à®¿à®©à¯ à®®à¯à®Ÿà®¿à®µà¯ˆ அடைநà¯à®¤à®¾à®¯à®¿à®±à¯à®±à¯.
+Comment[te]=జతల జాబితా చివరకౠచేరà±à°•à±à°¨à±à°¨à°®à±
+Comment[tg]=Охири рӯйхати мувофиқат раÑид
+Comment[th]=ถึงส่วนท้ายของรายà¸à¸²à¸£à¸—ี่เข้าคู่ได้à¹à¸¥à¹‰à¸§
+Comment[tr]=EÅŸleÅŸme listesinin sonuna gelindi
+Comment[tt]=Kileşülär tezmäseneñ azağına cittek
+Comment[uk]=ДоÑÑгнуто кінець ÑпиÑку збігань
+Comment[uz]=Mos keladigan elementlar roʻyxatining oxiri
+Comment[uz@cyrillic]=ÐœÐ¾Ñ ÐºÐµÐ»Ð°Ð´Ð¸Ð³Ð°Ð½ Ñлементлар рўйхатининг охири
+Comment[vi]=Mới tới kết thúc của danh sách từ khớp.
+Comment[zh_CN]=已到达匹é…项列表的最åŽ
+Comment[zh_TW]=符åˆæ¢ä»¶çš„列表已經到çµå°¾äº†ã€‚
+default_presentation=1
+
+[Textcompletion: no match]
+Name=Textcompletion: no match
+Name[af]=Teksvoltooiïng: nee ooreenstem
+Name[ar]=اكمال نص: لا يوجد تماثل
+Name[az]=Textcompletion: oxşarı Yoxdur
+Name[be]=ЗаканчÑнне Ñ‚ÑкÑту: нÑма ÑупаданнÑÑž
+Name[bg]=Ðвтоматично завършване: нÑма Ñъвпадение
+Name[bn]=Textcompletion: কোনো মিল পাওয়া যায়নি
+Name[br]=KlokadurSrid : kendoare ebet
+Name[bs]=Textcompletion: bez poklapanja
+Name[ca]=Compleció de text: cap coincidència
+Name[cs]=Doplňování textu: žádná shoda
+Name[csb]=Dofùlowanié tekstu: felënk dopasowaniô
+Name[cy]=CwblhauTestun: cydweddiad
+Name[da]=Tekstkomplettering: intet fundet
+Name[de]=Textvervollständigung: keine Übereinstimmung
+Name[el]=ΣυμπλήÏωση κειμένου: κανένα ταίÏιασμα
+Name[eo]=Kkompletigo: neniu trovaĵo
+Name[es]=Completado de texto: no hay concordancias
+Name[et]=Teksti lõpetamine: kokkulangevus puudub
+Name[eu]=Testu-osaketa: ez dago bat datorrenik
+Name[fa]=تکمیل متن: بدون تطبیق
+Name[fi]=Tekstintäydennys: ei osumia
+Name[fr]=Autocomplètement de texte : aucune correspondance
+Name[fy]=Tekstkompletearing - gjin oerienkomst
+Name[ga]=Comhlánú téacs: níl aon rud inchurtha
+Name[gl]=Textcompletion: sen coincidéncia
+Name[he]=השלמת טקסט: ×ין הת×מה
+Name[hi]=टेकà¥à¤¸à¥à¤Ÿ कमà¥à¤ªà¤²à¥€à¤¶à¤¨à¤ƒ मिलान नहीं
+Name[hr]=Textcompletion: bez poklapanja
+Name[hsb]=WudospoÅ‚njenje teksta: njejsym niÄo namakaÅ‚
+Name[hu]=Szövegkiegészítés: nincs találat
+Name[id]=Pemenuhanteks: tidak ada yang cocok
+Name[is]=Textaklárun: ekkert passar
+Name[it]=Completamento testo: nessuna corrispondenza
+Name[ja]=テキスト補完: マッãƒãªã—
+Name[ka]=თვითშევსებáƒ: თáƒáƒœáƒ®áƒ•áƒ”დრები áƒáƒ  áƒáƒ áƒ˜áƒ¡
+Name[kk]=Ðвтотолтыру: ÑәйкеÑтік жоқ
+Name[km]=ការ​បំពáŸáž‰â€‹áž¢ážáŸ’ážáž”ទ ៖ គ្មាន​ដំណូច
+Name[ko]=글월 완성: 맞는 ì§ì´ ì—†ìŒ
+Name[lb]=Textergänzung: keng Iwwerteneestëmmung
+Name[lt]=Textcompletion: netinka
+Name[lv]=Tekstakomplekts: nav atbilstību
+Name[mk]=Довршување текÑÑ‚: нема Ñовпаѓања
+Name[mn]=ТекÑÑ‚ гүйцÑÑлт: Харьцуулалтгүй
+Name[ms]= Penyudah teks: tiada padanan
+Name[mt]=Kompletazzjoni tal-kliem: ebda qbil
+Name[nb]=Tekstfullføring: ingen treff
+Name[nds]=Textkompletteren: nix passt
+Name[ne]=पाठ समापà¥à¤¤à¤¿: बेमेल
+Name[nl]=Tekstaanvulling - geen overeenkomsten
+Name[nn]=Tekstfullføring: ingen treff
+Name[nso]=Phetso ya sengwalwana: gagona tshwanelano
+Name[oc]=Textcompletion: a pas res de coincidencia
+Name[pa]=Textcompletion: ਕੋਈ ਮੇਲ ਨਹੀ
+Name[pl]=Uzupełnianie tekstu: brak dopasowania
+Name[pt]=Completação de texto: nenhuma encontrada
+Name[pt_BR]=Completar Texto: nenhuma coincidência
+Name[ro]=Completare text: nici o potrivire
+Name[ru]=Ðвтозавершение: нет Ñовпадений
+Name[rw]=Iyuzuzamwandiko: nta bihura
+Name[se]=Teakstaollašuhttin: ii gávdnon
+Name[sk]=Doplnenie textu: žiadna zhoda
+Name[sl]=Dopolnjevanje: ni ujemanja
+Name[sq]=Mabrimteksti: nuk ka përputhje
+Name[sr]=Допуњавање текÑта: нема поклапања
+Name[sr@Latn]=Dopunjavanje teksta: nema poklapanja
+Name[ss]=Kucedzelwa kwembhalo:akukho kuhambelana
+Name[sv]=Textkomplettering: ingen träff
+Name[ta]=உரைநிறைவà¯: பொரà¯à®¤à¯à®¤à®®à®¿à®²à¯à®²à¯ˆ
+Name[te]=వాచకపూరణ:జత లేదà±
+Name[tg]=Худхотимадиҳӣ: номуноÑиб
+Name[th]=à¸à¸²à¸£à¹€à¸•à¸´à¸¡à¸‚้อความให้สมบูรณ์: ไม่เข้าคู่
+Name[tr]=Textcompletion: eÅŸleÅŸme Yok
+Name[tt]=Süzazağı: kileşkäne yuq
+Name[uk]=Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ‚ÐµÐºÑту: немає відповідних значень
+Name[uz]=Matnni tugatish: mos keladigan yoʻq
+Name[uz@cyrillic]=Матнни тугатиш: Ð¼Ð¾Ñ ÐºÐµÐ»Ð°Ð´Ð¸Ð³Ð°Ð½ йўқ
+Name[ven]=U fhela ha manwalwa: A huna u fanyisa
+Name[vi]=Nhập xong từ: không khớp
+Name[xh]=Textcompletion: akukho ntelekiso
+Name[zh_CN]=文字补é½ï¼šæ²¡æœ‰åŒ¹é…
+Name[zh_HK]=文字補齊:沒有匹é…
+Name[zh_TW]=文字補齊:沒有匹é…
+Name[zu]=Ukuqedwa kokumbhalo: akukho okufanayo
+Comment=No matching completion was found
+Comment[af]=Geen ooreenstemming was gevind
+Comment[be]=ÐÑма варыÑнтаў заканчÑннÑ
+Comment[bg]=Ðе е намерено Ñъвпадение
+Comment[bn]=কোনো যà§à¦¤à¦¸à¦‡ পরিপূরক পাওয়া যায় নি
+Comment[br]=Kendoare ebet na voe kavet
+Comment[bs]=Nijedno dovršavanje nije pronađeno
+Comment[ca]=No s'ha trobat cap coincidència completable
+Comment[cs]=Nenalezeno žádné vhodné doplnění
+Comment[csb]=Dopasowanié nie òstałó nalazłé
+Comment[da]=Ingen passende komplettering blev fundet
+Comment[de]=Keine passende Ergänzung gefunden
+Comment[el]=Δε βÏέθηκε συμπλήÏωση που να ταιÏιάζει
+Comment[eo]=Ne troviÄis konvena kompletigo.
+Comment[es]=No se encontró ningún completado concordante
+Comment[et]=Kokkulangevat lõppu ei leitud
+Comment[eu]=Ez da bat datorren osaketarik aurkitu
+Comment[fa]=تکمیل مطابق پیدا نشد
+Comment[fi]=Ei osumia täydennettäväksi
+Comment[fr]=Aucune possibilité d'auto-complètement trouvée
+Comment[fy]=gjin oerienkomstige kompletearings binne fun
+Comment[gl]=Non se atopou nengunha completado coincidente.
+Comment[he]=×œ× × ×ž×¦××” ××£ השלמה תו×מת
+Comment[hi]=कोई मैचिंग कमà¥à¤ªà¥à¤²à¥€à¤¶à¤¨ नहीं मिला
+Comment[hr]=Nije pronađena nijedna podudarnost
+Comment[hsb]=Žane wudospołnjenje so njehodźi
+Comment[hu]=Nem található megfelelő kiegészítés
+Comment[id]=Tidak ada pelengkapan yang cocok
+Comment[is]=Ekkert passar
+Comment[it]=Nessun completamento corrispondente trovato
+Comment[ja]=マッãƒã™ã‚‹è£œå®Œã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ
+Comment[ka]=თáƒáƒœáƒ®áƒ•áƒ”დერები ვერ მáƒáƒ˜áƒ«áƒ”ბნáƒ.
+Comment[kk]=СәйкеÑтік жоқ
+Comment[km]=រក​មិន​ឃើញ​ការ​បំពáŸáž‰â€‹ážŠáŸ‚ល​ដូច
+Comment[lb]=Et gouf keng passend Ergänzung fonnt
+Comment[lt]=Nerasta atitinkanti pabaiga
+Comment[lv]=Atbilstoša pabeigšana netika atrasta
+Comment[mk]=Ðе е најдено Ñовпаѓање
+Comment[ms]=Tiada padanan lengkapan ditemui
+Comment[nb]=Ingen passende fullføring funnet
+Comment[nds]=Dor passt nix
+Comment[ne]=बेमेल समापà¥à¤¤à¤¿ फेला पारेको थियो
+Comment[nl]=Er werd geen overeenkomstige aanvulling gevonden
+Comment[nn]=Ingen passande fullføring funne
+Comment[pa]=ਸਮਾਪਤੀ ਤੱਕ ਕੋਈ ਮੇਲ ਨਹੀਂ ਲੱਭਾ
+Comment[pl]=Nie znaleziono dopasowania
+Comment[pt]=Não foi encontrada qualquer completação
+Comment[pt_BR]=Nenhuma coincidência foi encontrada
+Comment[ro]=Nu am găsit nimic potrivit
+Comment[ru]=Ðе найдено Ñовпадений.
+Comment[rw]=Nta yuzuza rihura ryabonetse
+Comment[se]=Heivvolaš ollašuhttin ii gávdnon
+Comment[sk]=Žiadna zhoda nebola nájdená
+Comment[sl]=Ni najti ujemajoÄih se zadetkov
+Comment[sr]=Подударна допуна није пронађена
+Comment[sr@Latn]=Podudarna dopuna nije pronađena
+Comment[sv]=Ingen matchande komplettering hittades
+Comment[ta]=பொரà¯à®¤à¯à®¤à®®à®¾à®© நிறைவ௠à®à®¤à¯à®®à®¿à®²à¯à®²à¯ˆ.
+Comment[te]=సరిపోయె జత దొరకలేదà±
+Comment[tg]=Ягон мувофиқат ёфт нашуд
+Comment[th]=ไม่พบส่วนเติมข้อความที่เข้าคู่
+Comment[tr]=Eşleşme bulunamadı
+Comment[tt]=Kileşkän azaqlar tabılmadı
+Comment[uk]=Відповідного Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð½Ðµ знайдено
+Comment[uz]=Mos keladigan tugatish topilmadi
+Comment[uz@cyrillic]=ÐœÐ¾Ñ ÐºÐµÐ»Ð°Ð´Ð¸Ð³Ð°Ð½ тугатиш топилмади
+Comment[vi]=Không tìm thấy.
+Comment[zh_CN]=没有找到匹é…的补全项
+Comment[zh_HK]=找ä¸åˆ°å®Œå…¨åŒ¹é…çš„é …ç›®
+Comment[zh_TW]=找ä¸åˆ°å®Œå…¨åŒ¹é…的項目。
+default_presentation=1
+
+[Textcompletion: partial match]
+Name=Textcompletion: partial match
+Name[af]=Teksvoltooiïng: gedeeltelike ooreenstem
+Name[ar]=اكمال نص: تماثل جزئي
+Name[az]=Textcompletion: qismi oxÅŸar
+Name[be]=ЗаканчÑнне Ñ‚ÑкÑту: чаÑтковае Ñупаданне
+Name[bg]=Ðвтоматично завършване: чаÑтично Ñъвпадение
+Name[bn]=Textcompletion: আংশিক মিল
+Name[br]=KlokadurSrid : kendoare darnek
+Name[bs]=Textcompletion: djelomiÄno poklapanje
+Name[ca]=Compleció de text: coincidència parcial
+Name[cs]=Doplňování textu: ÄásteÄná shoda
+Name[csb]=Dofùlowanié tekstu: dzélowé dopasowanié
+Name[cy]=CwblhauTestun: cydweddiad rhannol
+Name[da]=Tekstkomplettering: delvist fundet
+Name[de]=Textvervollständigung: teilweise Übereinstimmung
+Name[el]=ΣυμπλήÏωση κειμένου: μεÏικό ταίÏιασμα
+Name[eo]=Kkompletigo: parta trovaĵo
+Name[es]=Completado de texto: concordancia parcial
+Name[et]=Teksti lõpetamine: osaline kokkulangevus
+Name[eu]=Testu-osaketa: bat datorren partziala
+Name[fa]=تکمیل متن: تطبیق جزیی
+Name[fi]=Tekstintäydennys: osittainen osuma
+Name[fr]=Autocomplètement de texte : correspondance partielle
+Name[fy]=Tekstkompletearing - foar in diel oerienkommend
+Name[ga]=Comhlánú téacs: inchurtha i bpáirt
+Name[gl]=Textcompletion: coincidéncia parcial
+Name[he]=השלמת טקסט: הת×מה חלקית
+Name[hi]=टेकà¥à¤¸à¥à¤Ÿ कमà¥à¤ªà¤²à¥€à¤¶à¤¨à¤ƒ अधूरा मिलान
+Name[hr]=Textcompletion: djelomiÄno poklapanje
+Name[hsb]=Wudospołnjenje teksta: dźělne kryće
+Name[hu]=Szövegkiegészítés: részleges találat
+Name[id]=Pemenuhanteks: cocok sebagian
+Name[is]=Textaklárun: passar næstum því
+Name[it]=Completamento testo: corrispondenza parziale
+Name[ja]=テキスト補完: 部分的ã«ãƒžãƒƒãƒ
+Name[ka]=თვითშევსებáƒ: ნáƒáƒ¬áƒ˜áƒšáƒáƒ‘რივი თáƒáƒœáƒ®áƒ•áƒ”დრáƒ
+Name[kk]=Ðвтотолтыру: жарты-жарым ÑәйкеÑтік
+Name[km]=ការ​បំពáŸáž‰â€‹áž¢ážáŸ’ážáž”ទ ៖ ដូច​ážáŸ’លះៗ
+Name[ko]=글월 완성: ë¶€ë¶„ì€ ì§ì´ 맞ìŒ
+Name[lb]=Textergänzung: deelweis Iwwerteneestëmmung
+Name[lt]=Textcompletion: tinka dalinai
+Name[lv]=Tekstakomplekts: daļēja atbilstība
+Name[mk]=Довршување текÑÑ‚: делумни Ñовпаѓања
+Name[mn]=ТекÑÑ‚ гүйцÑÑлт: Ð¥Ð°Ð³Ð°Ñ Ñ…Ð°Ñ€ÑŒÑ†ÑƒÑƒÐ»Ð°Ð»Ñ‚Ñ‚Ð°Ð¹
+Name[ms]= Penyudah teks: separa padanan
+Name[mt]=Kompletazzjoni tal-kliem: qbil parzjali
+Name[nb]=Tekstfullføring: delvis treff
+Name[nds]=Textkompletteren: passt deelwies
+Name[ne]=पाठ समापà¥à¤¤à¤¿: आंशिक मिलà¥à¤¯à¥‹
+Name[nl]=Tekstaanvulling - gedeeltelijke overeenkomsten
+Name[nn]=Tekstfullføring: delvis treff
+Name[nso]=Phetso ya sengwalwana: tshwanelanyo dikarolong tse rilego
+Name[oc]=Textcompletion: coincidencia parciala
+Name[pa]=Textcompletion: ਅਧੂਰਾ ਮਿਲਾਨ
+Name[pl]=Uzupełnianie tekstu: częściowe dopasowanie
+Name[pt]=Completação de texto: parcial
+Name[pt_BR]=Completar Texto: coincidência parcial
+Name[ro]=Completare text: potrivire parţială
+Name[ru]=Ðвтозавершение: чаÑтичное Ñовпадение
+Name[rw]=Iyuzuzamwandiko: uguhura kutuzuye
+Name[se]=Taekstaollašuhttin: oasil gávdnui
+Name[sk]=Doplnenie textu: ÄiastoÄná zhoda
+Name[sl]=Dopolnjevanje: delno ujemanje
+Name[sq]=Mbarimteksti: përputhje e pjesërishme
+Name[sr]=Допуњавање текÑта: делимично поклапање
+Name[sr@Latn]=Dopunjavanje teksta: delimiÄno poklapanje
+Name[ss]=Kucedzelwa kwembhalo:kuhambelana lokungakapheleli
+Name[sv]=Textkomplettering: delvis träff
+Name[ta]=உரைநிறைவà¯: கà¯à®±à¯ˆà®ªà¯ பொரà¯à®¤à¯à®¤à®®à¯
+Name[te]=వాచకపూరణ: పాకà±à°·à°¿à°• జత
+Name[tg]=Худхотимадиҳӣ: мувофиқати қиÑмӣ
+Name[th]=à¸à¸²à¸£à¹€à¸•à¸´à¸¡à¸‚้อความให้สมบูรณ์: เข้าคู่บางส่วน
+Name[tr]=Textcompletion: kısmi eşleşme
+Name[tt]=Süzazağı: öleşçä kileşkän
+Name[uk]=Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ‚ÐµÐºÑту: чаÑткове збіганнÑ
+Name[uz]=Matnni tugatish: qisman mos kelish
+Name[uz@cyrillic]=Матнни тугатиш: қиÑман Ð¼Ð¾Ñ ÐºÐµÐ»Ð¸Ñˆ
+Name[ven]=U fhela ha manwalwa: U elana hu tukunyana
+Name[vi]=Nhập xong từ: khớp bộ phạn
+Name[xh]=Ugqibeko lokubhaliweyo: intelekiso engaphelelanga
+Name[zh_CN]=文字补é½ï¼šéƒ¨åˆ†åŒ¹é…
+Name[zh_HK]=文字補齊︰部分匹é…
+Name[zh_TW]=文字補齊︰部分匹é…
+Name[zu]=Ukuqedwa kokubhaliweyo: ukufaniswa kwesikhashana
+Comment=There is more than one possible match
+Comment[af]=Daar is meer as een moontlik ooreenkoms
+Comment[be]=Знойдзена некалькі варыÑнтаў заканчÑннÑ
+Comment[bg]=Ðамерени Ñа повече от едно Ñъвпадение
+Comment[bn]=à¦à¦•à¦¾à¦§à¦¿à¦• সমà§à¦­à¦¾à¦¬à§à¦¯ পরিপূরক বরà§à¦¤à¦®à¦¾à¦¨
+Comment[br]=Tremen ur c'hendoare a zo
+Comment[bs]=Postoji više od jednog mogućeg pogotka
+Comment[ca]=Hi ha més d'una possible coincidència
+Comment[cs]=Existuje více vhodných odpovídajících položek
+Comment[csb]=Je wicy jak jedno dopasowanié
+Comment[da]=Der er mere end en mulighed
+Comment[de]=Mehr als eine mögliche Ergänzung vorhanden
+Comment[el]=ΥπάÏχουν πεÏισσότεÏες από μία δυνατές συμπληÏώσεις
+Comment[eo]=Ekzistas pli ol unu konvena trovaĵo.
+Comment[es]=Hay más de una posible concordancia
+Comment[et]=Võimalike variante on rohkem kui üks
+Comment[eu]=Bat datorrenak bat baino gehiago dira
+Comment[fa]=بیش از یک تطبیق ممکن وجود دارد
+Comment[fi]=Useampia mahdollisia osumia
+Comment[fr]=Au moins deux correspondances ont été trouvées
+Comment[fy]=Der is wierskynlik mear as ien oerienkomst
+Comment[gl]=Hai máis dunha coincidéncia posíbel
+Comment[he]=יש יותר מהת×מה ×פשרית ×חת
+Comment[hi]=वहाठपर à¤à¤• से अघिक संभव जोड़ मिले हैं
+Comment[hr]=Postoji više od jedne moguće podudarnosti
+Comment[hsb]=Wjace haÄ jedne móžne wudospoÅ‚njenje
+Comment[hu]=Egynél több lehetséges kiegészítés van
+Comment[id]=Lebih dari satu kemungkinan cocok
+Comment[is]=Það eru fleiri en eitt atriði sem passar
+Comment[it]=C'è più di una corrispondenza possibile
+Comment[ja]=マッãƒã™ã‚‹ã‚‚ã®ãŒè¤‡æ•°ã‚ã‚Šã¾ã™
+Comment[ka]=მáƒáƒ˜áƒ«áƒ”ბნრერთზე მეტი თáƒáƒœáƒ®áƒ•áƒ”დრáƒ.
+Comment[kk]=Бірден артық ÑәйкеÑтік бар
+Comment[km]=អាច​មាន​ដំណូច​ច្រើន​ជាង​មួយ
+Comment[lb]=Et gëtt méi wéi eng méiglech Iwwerteneestëmmung
+Comment[lt]=Yra daugiau negu vienas galimas atitikmuo
+Comment[lv]=Å eit ir vairÄk kÄ viena iespÄ“jamÄ atbilstÄ«ba
+Comment[mk]=ПоÑтојат повеќе од едно Ñовпаѓање
+Comment[ms]=Ada lebih dari satu kebarangkalian padanan.
+Comment[nb]=Det er mer enn ett mulig treff
+Comment[nds]=Dor passt mehr as een
+Comment[ne]=तà¥à¤¯à¤¹à¤¾à¤ à¤à¤• भनà¥à¤¦à¤¾ बढी समà¥à¤­à¤µ जोडा छनà¥
+Comment[nl]=Er is meer dan één mogelijke overeenkomst
+Comment[nn]=Det er meir enn eitt mogleg treff
+Comment[pa]=ਇੱਕ ਤੋਂ ਵਧੇਰੇ ਮੇਲ ਉਪਲੱਬਧ ਹਨ
+Comment[pl]=Jest więcej niż jedno dopasowanie
+Comment[pt]=Há mais do que uma completação possível
+Comment[pt_BR]=Há mais de uma opção possível
+Comment[ro]=Există mai mult de o potrivire posibilă
+Comment[ru]=Ðайдено более чем одно Ñовпадение.
+Comment[rw]=Hari uguhura kurenga kumwe gushoboka
+Comment[se]=Leat eanet go ovtta vejolaš gávdnus
+Comment[sk]=Existuje viac ako jedna zhoda
+Comment[sl]=MogoÄ je veÄ kakor en zadetek
+Comment[sr]=ПоÑтоји више од једног могућег подударања
+Comment[sr@Latn]=Postoji više od jednog mogućeg podudaranja
+Comment[sv]=Det finns mer än en möjlig träff
+Comment[ta]=ஒனà¯à®±à¯à®•à¯à®•à¯ மேறà¯à®ªà®Ÿà¯à®Ÿ பொரà¯à®¤à¯à®¤à®™à¯à®•à®³à¯ உளà¯à®³à®©.
+Comment[te]=à°’à°•à°Ÿà°¿ కంటె à°Žà°•à±à°•à±à°µ సరిపోయె జతలౠకలవà±
+Comment[tg]=Зиёд аз Ñк мувофиқат Ñ‘Ñ„Ñ‚ шуд
+Comment[th]=มีส่วนที่เข้าคู่ได้อยู่มาà¸à¸à¸§à¹ˆà¸²à¸«à¸™à¸¶à¹ˆà¸‡
+Comment[tr]=Birden fazla muhtemel eÅŸleÅŸme var
+Comment[tt]=Kileşkäne berdän dä kübkär
+Comment[uk]=Більше одного відповідного значеннÑ
+Comment[uz]=Bittadan koʻp moslik topildi
+Comment[uz@cyrillic]=Биттадан кўп моÑлик топилди
+Comment[vi]=Khá»›p nhiá»u từ.
+Comment[zh_CN]=有多于一个的å¯èƒ½åŒ¹é…项
+Comment[zh_HK]=匹é…çš„å¯èƒ½æ€§å¤šæ–¼ä¸€å€‹
+Comment[zh_TW]=有多於一個的å¯èƒ½åŒ¹é…項。
+default_presentation=1
+
+[cannotopenfile]
+Name=Cannot Open File
+Name[af]=Kan nie Open Lêer
+Name[ar]=لا أستطيع Ùتح الملÙ
+Name[az]=Fayl Açıla bilmir
+Name[be]=Ðемагчыма адкрыць файл
+Name[bg]=Ðе може да Ñе отвори файла
+Name[bn]=ফাইল খোলা যাচà§à¦›à§‡ না
+Name[br]=N'hall ket digeriñ restr
+Name[bs]=Ne mogu otvoriti datoteku
+Name[ca]=No es pot obrir el fitxer
+Name[cs]=Není možné otevřít soubor
+Name[csb]=Nie je mòżno òtemknąc lopkù
+Name[cy]=Methu Agor y Ffeil
+Name[da]=Kan ikke åbne fil
+Name[de]=Datei lässt sich nicht öffnen
+Name[el]=Δεν είναι δυνατό το άνοιγμα του αÏχείου
+Name[eo]=Ne eblas malfermi dosieron
+Name[es]=No se puede abrir archivo
+Name[et]=Faili avamine ebaõnnestus
+Name[eu]=Ezin da fitxategia ireki
+Name[fa]=نمی‌توان پرونده را باز کرد
+Name[fi]=Ei voitu avata tiedostoa
+Name[fo]=Kann ikki opna fíla
+Name[fr]=Impossible d'ouvrir un fichier
+Name[fy]=Kin de triem net iepenje
+Name[ga]=Ní Féidir an Comhad a Oscailt
+Name[gl]=Non se pode abrir a ficheiro
+Name[he]=×ין ×פשרות לפתוח קובץ
+Name[hi]=फ़ाइल खोल नहीं सका
+Name[hr]=Datoteku nije moguće otvoriti
+Name[hsb]=Njemóžu dataju woÄinić
+Name[hu]=Nem sikerült megnyitni a fájlt
+Name[id]=Tidak Dapat Membuka Berkas
+Name[is]=Get ekki opnað skrá
+Name[it]=Impossibile aprire il file
+Name[ja]=ファイルを開ã‘ã¾ã›ã‚“
+Name[ka]=ფáƒáƒ˜áƒšáƒ˜áƒ¡ გáƒáƒ®áƒ¡áƒœáƒ ვერ ხერხდებáƒ
+Name[kk]=Файл ашылмайды
+Name[km]=មិន​អាច​បើក​ឯកសារ
+Name[ko]=파ì¼ì„ 열지 못함
+Name[lb]=Kann d'Datei net opmaachen
+Name[lt]=Nepavyksta atverti bylos
+Name[lv]=Nevar Atvērt Failu
+Name[mi]=Kaua i te Puare Könae
+Name[mk]=Ðе може да Ñе отвори датотеката
+Name[mn]=Файл нÑÑгдÑхгүй байна
+Name[ms]=Tidak boleh Buka Fail
+Name[mt]=Ma jistax jinfetaħ fajl
+Name[nb]=Kan ikke åpne fil
+Name[nds]=Datei lett sik nich opmaken
+Name[ne]=फाइल खोलà¥à¤¨ सकà¥à¤¦à¥ˆà¤¨
+Name[nl]=Kan het bestand niet openen
+Name[nn]=Kan ikkje opna fil
+Name[nso]=Ekase Bule Faele
+Name[oc]=Pot pas obrir lo fiquier
+Name[pa]=ਫਾਇਲ਼ ਖੋਲà©à¨¹à©€ ਨਹੀਂ ਜਾ ਸਕਦੀ
+Name[pl]=Nie można otworzyć pliku
+Name[pt]=Não Consigo Abrir o Ficheiro
+Name[pt_BR]=Não Foi Possível Abrir o Arquivo
+Name[ro]=Nu pot deschide fiÅŸierul
+Name[ru]=Ðе удаётÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл
+Name[rw]=Ntibishobotse Gufungura Idosiye
+Name[se]=Ii sáhte rahpat filla
+Name[sk]=Nemôžem otvoriť súbor
+Name[sl]=Ni moÄ odpreti datoteke
+Name[sq]=Nuk mund ta hap skedën
+Name[sr]=Ðије могуће отворити фајл
+Name[sr@Latn]=Nije moguće otvoriti fajl
+Name[ss]=Akukhonakali kuvula lifayela
+Name[sv]=Kan inte öppna fil
+Name[ta]=கோபà¯à®ªà¯ˆà®¤à¯ திறகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ
+Name[te]=దసà±à°¤à±à°°à°¾à°¨à±à°¨à°¿ తెరà±à°µà°²à±‡à°¨à±
+Name[tg]=Ðаметавон файлро кушод
+Name[th]=ไม่สามารถเปิดà¹à¸Ÿà¹‰à¸¡à¹„ด้
+Name[tr]=Dosya Açılamıyor
+Name[tt]=Biremne Aça Almím
+Name[uk]=Ðеможливо відкрити файл
+Name[uz]=Faylni ochib boʻlmadi
+Name[uz@cyrillic]=Файлни очиб бўлмади
+Name[ven]=I ngasi vule faela
+Name[vi]=Không thể mở tập tin
+Name[wa]=Dji n' sai drovi l' fitchî
+Name[xh]=Ayinakuyivula Ifayile
+Name[zh_CN]=无法打开文件
+Name[zh_HK]=無法打開檔案
+Name[zh_TW]=無法打開檔案
+Name[zu]=Ifayela Alivulekile
+Comment=The selected file cannot be opened for reading or writing
+Comment[af]=Die gekose lêer kan nie oop wees vir lees of om te skryf
+Comment[ar]=المل٠المختار لا يمكن Ùتحه للقراءة أو الكتابة
+Comment[az]=Seçili fayl oxunmaq ya da yazılmaq üçün açıla bilmir
+Comment[be]=Ðемагчыма прачытаць/запіÑаць выбраны файл
+Comment[bg]=ИзбраниÑÑ‚ файл не може да бъде отворен за четене или запиÑ
+Comment[bn]=নিরà§à¦¬à¦¾à¦šà¦¿à¦¤ ফাইলটি পড়া বা লেখার জনà§à¦¯ খোলা যাচà§à¦›à§‡ না
+Comment[br]=N'heller ket digeriñ ar restr diuzet evit lenn pe skrivañ
+Comment[bs]=Ne mogu otvoriti izabranu datoteku za Äitanje ili pisanje
+Comment[ca]=El fitxer seleccionat no es pot obrir per a lectura o escriptura
+Comment[cs]=Vybraný soubor není možné otevřít pro Ätení nebo zápis.
+Comment[csb]=Wëbróny lopk nie mòże òstac òtemkłi do czëtaniô czë zapisaniô
+Comment[cy]=Methu agor y ffeil penodol i'w ddarllen neu i'w ysgrifennu.
+Comment[da]=Den valgte fil kan ikke åbnes til læsning eller skrivning
+Comment[de]=Die gewählte Datei kann nicht zum Lesen oder Schreiben geöffnet werden.
+Comment[el]=Το επιλεγμένο αÏχείο δεν μποÏεί να ανοιχθεί για εγγÏαφή ή ανάγνωση
+Comment[eo]=La elektita dosiero ne estas malfermebla por legado aÅ­ skribado
+Comment[es]=El archivo seleccionado no se puede abrir para leer o escribir.
+Comment[et]=Valitud faili pole võimalik avada lugemiseks või kirjutamiseks.
+Comment[eu]=Hautatutako fitxategia ezin da irakurtzeko edo idazteko ireki
+Comment[fa]=پروندۀ برگزیده نمی‌تواند برای خواندن یا نوشتن باز شود
+Comment[fi]=Valittua tiedostoa ei voida avata luettavaksi tai kirjoitettavaksi
+Comment[fr]=Le fichier sélectionné ne peut être ouvert ni en lecture ni en écriture
+Comment[fy]=It selektearre triem kin net iepene wurde om te lêzen of skriuwen
+Comment[ga]=Ní féidir an comhad roghnaithe a oscailt chun é a léamh nó chun scríobh air
+Comment[gl]=O ficheiro escollido non se pode abrir para ler ou escreber
+Comment[he]=×ין ×פשרות לפתוח ×ת הקובץ הנבחר לקרי××” ×ו כתיבה
+Comment[hi]=चà¥à¤¨à¤¾ हà¥à¤† फ़ाइल पढ़ने अथवा लिखने के लिठखोला नहीं जा सकता।
+Comment[hr]=Odabranu datoteku nije moguće otvoriti za Äitanje ili zapisivanje
+Comment[hsb]=Wubrana dataja njehodźi so woÄinić
+Comment[hu]=A kiválasztott fájlt nem lehet megnyitni írásra vagy olvasásra
+Comment[id]=Berkas yang dipilih tidak dapat dibuka untuk dibaca atau ditulis
+Comment[is]=Ekki er hægt að opna völdu skrána til lestrar eða skriftar
+Comment[it]=Il file selezionato non può essere aperto per la lettura o la scrittura
+Comment[ja]=é¸æŠžã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’読ã¿è¾¼ã¿ã¾ãŸã¯æ›¸ãè¾¼ã¿ã®ãŸã‚ã«é–‹ã‘ã¾ã›ã‚“
+Comment[ka]=მáƒáƒœáƒ˜áƒ¨áƒœáƒ£áƒšáƒ˜ ფáƒáƒ˜áƒšáƒ˜áƒ¡ გáƒáƒ®áƒ¡áƒœáƒ წáƒáƒ¡áƒáƒ™áƒ˜áƒ—ხáƒáƒ“ áƒáƒœ ჩáƒáƒ¡áƒáƒ¬áƒ”რáƒáƒ“ ვერ ხერხდებáƒ
+Comment[kk]=Таңдалған файл жазуға не оқуға ашылмады
+Comment[km]=មិន​អាច​បើក​អាន​ពី ឬ សរសáŸážšâ€‹áž‘ៅ​ឯកសារ​ដែល​បាន​ជ្រើស
+Comment[ko]=고른 파ì¼ì„ ì½ê±°ë‚˜ 쓰기위해 ì—´ 수가 없습니다
+Comment[lb]=Déi ausgewielten Datei kann net opgemat gi fir ze liesen oder ze schreiwen
+Comment[lt]=Nurodytos bylos negalima atverti skaitymui arba rašymui
+Comment[lv]=Izvēlētais fails nevar tikt atvērts lasīšanai vai rakstīšanai
+Comment[mk]=Избраните датотеки не можат да Ñе отворат за читање или пишување
+Comment[mn]=СонгоÑон файл уншигдах ÑÑвÑл бичигдÑÑ…ÑÑÑ€ нÑÑгдÑхгүй байна.
+Comment[ms]=Fail dipilih tidak boleh dibaca atau ditulis
+Comment[mt]=Il-fajl magħżul ma setax jinfetaħ għall-qari jew kitba.
+Comment[nb]=Den valgte fila kan ikke åpnes for lesing eller skriving
+Comment[nds]=De utsöchte Datei lett sik nich lesen oder schrieven
+Comment[ne]=पढà¥à¤¨ वा लेखà¥à¤¨à¤•à¤¾ लागि चयन गरिà¤à¤•à¤¾ फाइल खोलà¥à¤¨ सकेन
+Comment[nl]=Het geselecteerde bestand kan niet worden geopend om te lezen of naar te schrijven.
+Comment[nn]=Den valte fila kan ikkje opnast for lesing eller skriving
+Comment[nso]=Faele yeo e kgethilwego ekase bulelwe go bala goba go ngwala
+Comment[oc]=Lo fiquièr seleccionat pod pas esser obrit per legir on escriure
+Comment[pa]=ਚà©à¨£à©€ ਫਾਇਲ ਨੂੰ ਪੜਨ ਜਾਂ ਲਿਖਣ ਲਈ ਖੋਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ ਹੈ
+Comment[pl]=Wybrany plik nie może być otwarty do odczytu lub zapisu
+Comment[pt]=O ficheiro seleccionado não pode ser aberto para leitura ou escrita.
+Comment[pt_BR]=O arquivo selecionado não pode ser aberto para leitura ou gravação
+Comment[ro]=FiÅŸierul selectat nu poate fi deschis pentru scriere sau citire
+Comment[ru]=Ðе удаётÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ выбранный файл Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи или чтениÑ
+Comment[rw]=Idosiye yatoranyijwe ntishoboye gufungurwa mu gusoma cyangwa kwandika
+Comment[se]=Válljejuvvon fiilla ii sáhte rahpat lohkama dahje Äállima várás
+Comment[sk]=Vybraný súbor nemôžem otvoriÅ¥ na Äítanie alebo zápis
+Comment[sl]=Izbrane datoteke ni bilo moÄ odpreti za branje ali pisanje.
+Comment[sq]=Skedari i zgjedhur nuk mund të hapet për lexim apo editim
+Comment[sr]=Изабрани фајл је немогуће отворити ради читања или пиÑања
+Comment[sr@Latn]=Izabrani fajl je nemoguće otvoriti radi Äitanja ili pisanja
+Comment[ss]=lifayela lelikhetsiwe akukhonakali kutsi livulwe kutsi lifundvwe kumbe libhalwe
+Comment[sv]=Den valda filen kan inte öppnas för läsning eller skrivning
+Comment[ta]=தேரà¯à®µà¯ செயà¯à®¤ கோபà¯à®ªà¯ˆ வாசிகà¯à®•à®µà¯‹ எழà¯à®¤à®µà¯‹ திறகà¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯
+Comment[te]=ఎఓపిక చేసిన దసà±à°¤à±à°°à°¾à°¨à±à°¨à°¿ à°šà°¦à±à°µà±à°Ÿà°•à± లేక à°µà±à°°à°¾à°¯à±à°Ÿà°•à± తెరà±à°µà°²à±‡à°¨à±
+Comment[tg]=Ðаметавон файли интихобшударо барои Ñабт Ñ‘ хондан кушод
+Comment[th]=ไม่สามารถเปิดà¹à¸Ÿà¹‰à¸¡à¸—ี่เลือà¸à¹„ว้ เพื่อทำà¸à¸²à¸£à¸­à¹ˆà¸²à¸™à¸«à¸£à¸·à¸­à¹€à¸‚ียนได้
+Comment[tr]=Seçili dosya okumnmak ya da yazılmak için açılamıyor
+Comment[tt]=Saylanğan biremne, uqu yä ki yazu eşe öçen açıp bulmí
+Comment[uk]=Вибраний файл не може бути відкритий Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ запиÑу
+Comment[uz]=Tanlangan faylni na oʻqish na yozish uchun ochib boʻladi.
+Comment[uz@cyrillic]=Танланган файлни на ўқиш на ёзиш учун очиб бўлади.
+Comment[ven]=Faela yo nangwaho ingasi vulwe u vhala kana u nwala
+Comment[vi]=Tập tin được chá»n không có khả năng mở để Ä‘á»c hay ghi.
+Comment[xh]=Ifayile ekhethiweyo ayinakuvulelwa ukufunda okanye ukubhala
+Comment[zh_CN]=选中的文件ä¸èƒ½æ‰“å¼€æ¥è¯»æˆ–写
+Comment[zh_HK]=所é¸å–的檔案無法開啟進行讀å–或者是寫入
+Comment[zh_TW]=所é¸å–的檔案無法開啟進行讀å–或者是寫入
+Comment[zu]=Ifayela elikhethiwe alingeke livulwe ukuze lifundwe ukufundwa noma ukubhalwa
+default_presentation=0
+
+[fatalerror]
+Name=Fatal Error
+Name[af]=Fatale Fout
+Name[ar]=خطأ قاتل
+Name[az]=Ölümcül Xəta
+Name[bg]=Фатална грешка
+Name[bn]=মারাতà§à¦®à¦• সমসà§à¦¯à¦¾
+Name[br]=Fazi sac'hus
+Name[bs]=Fatalna greška
+Name[ca]=Error fatal
+Name[cs]=Závažná chyba
+Name[csb]=Kriticznô fela
+Name[cy]=Gwall Angheuol
+Name[da]=Fatal fejl
+Name[de]=Schwerer Fehler
+Name[el]=ΜοιÏαίο σφάλμα
+Name[eo]=Grava Eraro
+Name[es]=Error fatal
+Name[et]=Fataalne viga
+Name[eu]=Errore larria
+Name[fa]=خطای مهلک
+Name[fi]=Peruuttamaton virhe
+Name[fr]=Problème critique
+Name[fy]=Fatale flater
+Name[ga]=Earráid Mharfach
+Name[gl]=Erro moi grave
+Name[he]=שגי××” חמורה
+Name[hi]=गंभीर तà¥à¤°à¥à¤Ÿà¤¿
+Name[hr]=Ozbiljna pogreška
+Name[hsb]=Fatalny zmylk
+Name[hu]=Végzetes hiba
+Name[id]=Kesalahan Fatal
+Name[is]=Banvæn villa
+Name[it]=Errore fatale
+Name[ja]=致命的ãªã‚¨ãƒ©ãƒ¼
+Name[ka]=ფáƒáƒ¢áƒáƒšáƒ£áƒ áƒ˜ შეცდáƒáƒ›áƒ
+Name[kk]=Түзелмейтін қате
+Name[km]=កំហុស​ធ្ងន់ធ្ងរ
+Name[ko]=치명ì ì¸ 오류
+Name[lb]=Fatale Feeler
+Name[lt]=Lemtinga klaida
+Name[lv]=FatÄla Kļūda
+Name[mk]=Фатална грешка
+Name[mn]=Үхлүүт(Fatal) алдаа
+Name[ms]=Ralat Maut
+Name[mt]=Problema Fatali
+Name[nb]=Fatal feil
+Name[nds]=Groot Malöör
+Name[ne]=घातक तà¥à¤°à¥à¤Ÿà¤¿
+Name[nl]=Fatale fout
+Name[nn]=Fatal feil
+Name[nso]=Bothatathata
+Name[oc]=Error fatala
+Name[pa]=ਘਾਤਕ ਗਲਤੀ
+Name[pl]=BÅ‚Ä…d krytyczny
+Name[pt]=Erro Fatal
+Name[pt_BR]=Erro fatal
+Name[ro]=Eroare fatală
+Name[ru]=Ð¤Ð°Ñ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°
+Name[rw]=Ikosa rikomeye
+Name[se]=Váralaš meattáhus
+Name[sk]=Fatálna chyba
+Name[sl]=Usodna napaka
+Name[sq]=Gabim fatal
+Name[sr]=Кобна грешка
+Name[sr@Latn]=Kobna greška
+Name[ss]=Liphutsa lelibi
+Name[sv]=Allvarligt fel
+Name[ta]=மீளமà¯à®Ÿà®¿à®¯à®¾à®¤à¯ தவறà¯
+Name[te]=హానికరమైన దోషం
+Name[tg]=Хатои ногузир
+Name[th]=เà¸à¸´à¸”ข้อผิดพลาดร้ายà¹à¸£à¸‡
+Name[tr]=Ölümcül Hata
+Name[tt]=Ütmäslek Xata
+Name[uk]=Фатальна помилка
+Name[uz]=Juda jiddiy xato
+Name[uz@cyrillic]=Жуда жиддий хато
+Name[ven]=Vhukhakhi vhuhulwane
+Name[vi]=Lá»—i nghiêm trá»ng
+Name[wa]=Aroke moirt
+Name[xh]=Imposiso Enengozi
+Name[zh_CN]=致命错误
+Name[zh_HK]=åš´é‡éŒ¯èª¤
+Name[zh_TW]=åš´é‡éŒ¯èª¤
+Name[zu]=Iphutha Lengozi
+Comment=There was a serious error causing the program to exit
+Comment[af]=Daar was 'n ernstige fout wat veroorsaak het dat die program beïendig is.
+Comment[be]=ÐдбылаÑÑ Ñур'Ñ‘Ð·Ð½Ð°Ñ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ°, ÑÐºÐ°Ñ Ð¿Ñ€Ñ‹Ð²Ñла да выхаду з праграмы
+Comment[bg]=ПоÑви Ñе Ñериозна грешка, коÑто предизвика Ñпиране на програмата
+Comment[bn]=à¦à¦•à¦Ÿà¦¿ গà§à¦°à§à¦¤à¦° তà§à¦°à§à¦Ÿà¦¿à¦° দরà§à¦£ পà§à¦°à§‹à¦—à§à¦°à¦¾à¦®à¦Ÿà¦¿ থেমে গেছে
+Comment[br]=Ur fazi grevus a voe pennabeg mont er-maez ar goulev.
+Comment[bs]=Program je morao završiti zbog ozbiljne greške
+Comment[ca]=Hi ha hagut un error seriós que ha fet que el programa acabi
+Comment[cs]=Nastala závažná chyba, která způsobila ukonÄení programu
+Comment[csb]=Pòkôza sã pòwôżnô fela, jakô doprowadzëła do zamkniãcô programë
+Comment[da]=Der var et alvorligt problem som fik programmet til at afslutte
+Comment[de]=Es ist ein schwerer Fehler aufgetreten und das Programm wurde beendet.
+Comment[el]=Συνέβη ένα σοβαÏÏŒ σφάλμα που έκανε το Ï€ÏόγÏαμμα να τεÏματίσει
+Comment[eo]=Okazis grava eraro, kiu ĉesigis la programon.
+Comment[es]=Hubo un error serio que ha causado el cierre del programa
+Comment[et]=Ilmnes tõsine viga, mis sundis programmi tööd lõpetama
+Comment[eu]=Errore larria gertatu da eta programa itxiarazi du.
+Comment[fa]=یک خطای جدی باعث خروج برنامه شد
+Comment[fi]=Tapahtui vakava virhe, jonka takia ohjelma lopetettiin
+Comment[fr]=Un problème grave a provoqué l'arrêt du programme
+Comment[fy]=Der wie in serieuse flater wertroch it programma sluten is
+Comment[ga]=Tharla droch-earráid, agus tá an clár tar éis stopadh
+Comment[gl]=Houbo un erro sério que provocou o remate da execución do programa
+Comment[he]=×ירעה שגי××” חמורה שגרמה לתוכנית לצ×ת
+Comment[hi]=à¤à¤• अति गंभीर तà¥à¤°à¥à¤Ÿà¤¿ हà¥à¤ˆ जिसके कारण पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बाहर हो गया
+Comment[hr]=Program je morao završiti s radom zbog ozbiljne pogreške
+Comment[hsb]=Je so chutny zmylk staÅ‚, kiž je program skónÄiÅ‚
+Comment[hu]=Súlyos hiba történt, ezért a program futása félbeszakadt.
+Comment[id]=Ada kesalahan serius yang menyebabkan progam diakhiri
+Comment[is]=Alvarleg villa stöðvaði keyrslu forritsins.
+Comment[it]=Si è verificato un errore grave che ha causato la fine del programma
+Comment[ja]=プログラムãŒçµ‚了ã™ã‚‹æ·±åˆ»ãªã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã—ãŸ
+Comment[ka]=სერიáƒáƒ–ული შეცდáƒáƒ›áƒ, რáƒáƒ›áƒ”ლმáƒáƒª პრáƒáƒ’რáƒáƒ›áƒ˜áƒ“áƒáƒœ გáƒáƒ¡áƒ•áƒšáƒ გáƒáƒ›áƒáƒ˜áƒ¬áƒ•áƒ˜áƒ.
+Comment[kk]=Бір маңызды қате бағдарламадан шығуға мәжбүрледі
+Comment[km]=មាន​កំហុស​ធ្ងន់ធ្ងរ​មួយ​ដែល​បាន​បណ្ážáž¶áž›â€‹áž²áŸ’យ​កម្មវិធី​បិទ
+Comment[lb]=Et gouf e schwéiere Feeler, an de Programm gouf zougemat
+Comment[lt]=Įvyko rimta klaida, privertusi programą užbaigti darbą
+Comment[lv]=Gadījusies nopietna kļuda, kas izraisa iziešanu no programmas
+Comment[mk]=Се Ñлучи Ñериозна грешка поради која програмот заврши
+Comment[ms]=Ada ralat serius menyebabkan program tutup.
+Comment[nb]=Det var en alvorlig feil som førte til at programmet avsluttet
+Comment[nds]=Dor is en Malöör passeert, dat Programm warrt afbraken
+Comment[ne]=कारà¥à¤¯à¤•à¥à¤°à¤®à¤¬à¤¾à¤Ÿ निसà¥à¤•à¤¨à¤¾à¤²à¥‡ तà¥à¤¯à¤¹à¤¾à¤ गमà¥à¤­à¤¿à¤° तà¥à¤°à¥à¤Ÿà¤¿ भयो
+Comment[nl]=Er was een ernstige fout die ervoor zorgde dat dit programma beëindigd werd
+Comment[nn]=Ein alvorleg feil førte til at programmet avslutta
+Comment[pa]= ਇੱਕ ਘਾਤਕ ਗਲਤੀ ਨੇ ਕਾਰਜ ਨੂੰ ਬੰਦ ਹੋਣ ਲਈ ਮਜਬੂਰ ਕਰ ਦਿੱਤਾ ਹੈ
+Comment[pl]=Wystąpił poważny błąd, który spowodował zamknięcie programu
+Comment[pt]=Ocorreu um erro grave que provocou o fim da execução do programa
+Comment[pt_BR]=Houve um erro sério, que fez o programa finalizar
+Comment[ro]=A apărut o eroare severă care a determinat terminarea programului
+Comment[ru]=Серьёзный Ñбой, приведший к выходу из программы.
+Comment[rw]=Habaye ikosa rikomeye ritera porogaramu guhagarara
+Comment[se]=Vearrás meattáhusa geažil prográmma heittii
+Comment[sk]=Vyskytla sa vážna chyba, ktorá spôsobila ukonÄenie programu
+Comment[sl]=Program se je konÄal zaradi resne napake
+Comment[sr]=ДеÑила Ñе озбиљна грешка, која је изазвала да Ñе програм затвори
+Comment[sr@Latn]=Desila se ozbiljna greška, koja je izazvala da se program zatvori
+Comment[sv]=Ett allvarligt fel uppstod vilket fick programmet att avslutas
+Comment[ta]=நிரலை வெளியேறச௠செயà¯à®•à®¿à®± அளவில௠ஒர௠பெரிய தவறà¯à®£à¯à®Ÿà¯.
+Comment[te]=à°®à±à°–à±à°¯à°®à±ˆà°¨ దోషం à°’à°•à°Ÿà°¿ కారà±à°¯à°•à±à°°à°®à°‚ నిషà±à°•à±à°°à°®à°£à°•à± కారణమైనది
+Comment[tg]=ÐуқÑони ҷиддие, ки ба баромадан аз барнома раÑонид
+Comment[th]=เà¸à¸´à¸”ข้อผิดพลาดร้ายà¹à¸£à¸‡ ทำให้ต้องออà¸à¸ˆà¸²à¸à¹‚ปรà¹à¸à¸£à¸¡
+Comment[tr]=Programın kapanmasına neden olan ciddi bir hata oluştu
+Comment[tt]=Yazılımnan çığuına kitergän citdi xata kilep çıqqan
+Comment[uk]=Серйозна помилка Ñтала причиною виходу програми
+Comment[uz]=Dasturning ishini yakunlanishiga sababchi boʻlgan jiddiy xato roʻy berdi
+Comment[uz@cyrillic]=ДаÑтурнинг ишини Ñкунланишига Ñабабчи бўлган жиддий хато рўй берди
+Comment[vi]=Gặp lỗi nghiêm trong mà gây ra chương trình thoát.
+Comment[zh_CN]=有一个严é‡çš„错误导致程åºé€€å‡º
+Comment[zh_HK]=發生了嚴é‡çš„錯誤,導致程å¼çµæŸ
+Comment[zh_TW]=發生了一個嚴é‡çš„錯誤導致çµæŸè©²ç¨‹å¼ã€‚
+default_presentation=2
+level=4
+
+[notification]
+Name=Notification
+Name[af]=Inkennisstelling
+Name[ar]=تنبيه
+Name[az]=Xəbərdarlıq
+Name[be]=Ðагадванне
+Name[bg]=Съобщение
+Name[bn]=সংবাদ
+Name[br]=Kemennadenn
+Name[bs]=Obavještenje
+Name[ca]=Notificació
+Name[cs]=Oznámení
+Name[csb]=Òdkôzanié
+Name[cy]=Hybys
+Name[da]=Bekendtgørelse
+Name[de]=Benachrichtigung
+Name[el]=Ειδοποίηση
+Name[eo]=Atentigo
+Name[es]=Notificación
+Name[et]=Märguanne
+Name[eu]=Jakinarazpena
+Name[fa]=اخطار
+Name[fi]=Huomautus
+Name[fo]=Ãminning
+Name[fy]=Notifikaasje
+Name[ga]=Fógairt
+Name[gl]=Notificación
+Name[he]=הודעה
+Name[hi]=सूचना
+Name[hr]=Obavijest
+Name[hsb]=Zdźělenka
+Name[hu]=Rendszerfigyelmeztetések
+Name[id]=Pemberitahuan
+Name[is]=Tilkynning
+Name[it]=Avviso
+Name[ja]=通知
+Name[ka]=შეტყáƒáƒ‘ინებáƒ
+Name[kk]=Құлақтандыру
+Name[km]=ការ​ជូន​ដំណឹង
+Name[ko]=알림
+Name[lb]=Noricht
+Name[lt]=Pranešimai
+Name[lv]=Apziņošana
+Name[mk]=ИзвеÑтување
+Name[mn]=Сонордуулга
+Name[ms]=Pemberitahuan
+Name[mt]=Notifika
+Name[nb]=Varsling
+Name[nds]=Bescheed
+Name[ne]=सूचना
+Name[nl]=Notificatie
+Name[nn]=PÃ¥minning
+Name[nso]=Tsebiso
+Name[oc]=Notificacion
+Name[pa]=ਟਿੱਪਣੀ
+Name[pl]=Powiadomienie
+Name[pt]=Mensagem
+Name[pt_BR]=Notificação
+Name[ro]=Notificare
+Name[ru]=Сообщение
+Name[rw]=Imenyesha
+Name[se]=Dieđáhus
+Name[sk]=Upozornenie
+Name[sl]=Obvestilo
+Name[sq]=Lajmërim
+Name[sr]=Обавештење
+Name[sr@Latn]=Obaveštenje
+Name[ss]=Satiso
+Name[sv]=Underrättelse
+Name[ta]=அறிவிபà¯à®ªà¯
+Name[te]=à°ªà±à°°à°•à°Ÿà°¨
+Name[tg]=Иттилоот
+Name[th]=à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™
+Name[tr]=Uyarı
+Name[tt]=Beldermä
+Name[uk]=ПовідомленнÑ
+Name[uz]=Xabarnoma
+Name[uz@cyrillic]=Хабарнома
+Name[ven]=Ndivhadzo
+Name[vi]=Thông báo
+Name[wa]=Notifiaedje
+Name[xh]=Isaziso
+Name[zh_CN]=通知
+Name[zh_HK]=通知
+Name[zh_TW]=通知
+Name[zu]=Isaziso
+Comment=Something special happened in the program
+Comment[af]=Iets spesiaal het met die program gebeur
+Comment[bg]=Ð’ програмата Ñе Ñлучи нещо неочаквано
+Comment[bn]=পà§à¦°à§‹à¦—à§à¦°à¦¾à¦®à§‡ বিশেষ কিছৠà¦à¦•à¦Ÿà¦¾ ঘটেছে
+Comment[br]=Un dra bennak dibar a c'hoarvezas gant ar goulev
+Comment[bs]=Nešto posebno se desilo u programu
+Comment[ca]=Ha passat quelcom d'especial al programa
+Comment[cs]=Něco zvláštního se stalo s programem
+Comment[csb]=W programie stało sã cos òsoblëwégò
+Comment[da]=Der skete noget specielt i programmet
+Comment[de]=Es ist eine besondere Programmsituation aufgetreten.
+Comment[el]=Κάτι εξαιÏετικό συνέβη στο Ï€ÏόγÏαμμα
+Comment[eo]=Io nekutima okazis en la programo
+Comment[es]=Ocurrió algo especial en el programa
+Comment[et]=Programmis juhtus midagi erilist
+Comment[eu]=Gertaera berezia gertatu da programan
+Comment[fa]=اتÙاق خاصی در برنامه رخ داد
+Comment[fi]=Ohjelmassa tapahtui jotain erikoista
+Comment[fr]=Quelque chose de spécial s'est passé dans le programme
+Comment[fy]=Der barde wat spesjaals yn't programma
+Comment[ga]=Tharla rud éigean ar leith sa chlár
+Comment[gl]=Ocorreu algo especial no programa
+Comment[he]=משהו מיוחד קרה ×¢× ×”×ª×•×›× ×™×ª
+Comment[hi]=पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® मे कà¥à¤› महतà¥à¤µà¤ªà¥‚रà¥à¤£ घटित हà¥à¤†
+Comment[hr]=Nešto se posebno dogodilo u programu
+Comment[hsb]=Něšto njewoÄakowane je so staÅ‚o
+Comment[hu]=Valami különleges történt a programban
+Comment[id]=Sesuatu yang khusus terjadi dalam program
+Comment[is]=Eitthvað sérstakt gerðist í forritinu
+Comment[it]=È successo qualcosa di speciale nel programma
+Comment[ja]=何ã‹ç‰¹åˆ¥ãªã“ã¨ãŒãƒ—ログラムã«èµ·ã“ã‚Šã¾ã—ãŸ
+Comment[ka]=პრáƒáƒ’რáƒáƒ›áƒáƒ¨áƒ˜ რáƒáƒ¦áƒáƒª გáƒáƒœáƒ¡áƒáƒ™áƒ£áƒ—რებული მáƒáƒ®áƒ“áƒ
+Comment[kk]=Бағдарламада ерекше бірдеме болды
+Comment[km]=មាន​អ្វី​ពិសáŸážŸâ€‹áž˜áž½áž™â€‹áž”ាន​កើážâ€‹áž¡áž¾áž„​ក្នុង​កម្មវិធី
+Comment[lb]=Et ass eng speziell Programmsituatioun opgetrueden
+Comment[lt]=Kažkoks specialus įvykis programoje
+Comment[lv]=ProgrammÄ noticis kas speciÄls
+Comment[mk]=Ðешто Ñпецијално Ñе Ñлучило во програмот
+Comment[ms]=Sesuatu yang pelik berlaku di dalam program
+Comment[nb]=Noe spesielt skjedde med programmet
+Comment[nds]=In dat Programm is wat besünners passeert
+Comment[ne]=कारà¥à¤¯à¤•à¥à¤°à¤®à¤®à¤¾ केही विशेष आइपरà¥à¤¯à¥‹
+Comment[nl]=Er gebeurde iets bijzonders in het programma
+Comment[nn]=Noko spesielt skjedde i programmet
+Comment[pa]=ਇਸ ਕਾਰਜ ਵਿੱਚ ਕà©à¨ ਖਾਸ ਹੋ ਗਿਆ ਹੈ
+Comment[pl]=Coś specjalnego stało sie w programie
+Comment[pt]=Ocorreu algo de especial no programa
+Comment[pt_BR]=Algo especial ocorreu no programa
+Comment[ro]=S-a întîmplat ceva neaşteptat în program
+Comment[ru]=Ð’ программе возникла Ð½ÐµÐ¿Ñ€ÐµÐ´Ð²Ð¸Ð´ÐµÐ½Ð½Ð°Ñ ÑитуациÑ
+Comment[rw]=Ikintu kidasanzwe cyabaye muri porogaramu
+Comment[se]=Juoga erenoamáš dáhpáhuvai prográmmas
+Comment[sk]=V programe sa udialo nieÄo neoÄakávané
+Comment[sl]=V programu se je zgodilo nekaj izrednega
+Comment[sr]=Ðешто поÑебно Ñе деÑило у програму
+Comment[sr@Latn]=Nešto posebno se desilo u programu
+Comment[sv]=Någonting speciellt inträffade i programmet
+Comment[ta]=நிரலில௠à®à®¤à¯‹ விசேடம௠நிகழà¯à®¨à¯à®¤à¯à®³à¯à®³à®¤à¯
+Comment[te]=కారà±à°¯à°•à±à°°à°®à°‚ లొ à°’à°• విశేషం చొటà±à°šà±†à°¸à±à°•à±à°‚ది
+Comment[tg]=Дар барнома ҳолати ногаҳонӣ рӯй дод
+Comment[th]=เà¸à¸´à¸”บางอย่างที่พิเศษขึ้นในโปรà¹à¸à¸£à¸¡
+Comment[tr]=Programda özel bir durum meydana geldi
+Comment[tt]=Yazılımda kötelmägän närsä kilep çıqqan
+Comment[uk]=ЩоÑÑŒ оÑобливе ÑталоÑÑŒ у програмі
+Comment[uz]=Dasturda qandaydir odatdan tashqari hodisa roʻy berdi
+Comment[uz@cyrillic]=ДаÑтурда қандайдир одатдан ташқари ҳодиÑа рўй берди
+Comment[vi]=Có gì đặc biệt đã xảy ra trong chương trình.
+Comment[zh_CN]=程åºä¸­å‘生了特殊情况
+Comment[zh_HK]=程å¼ç™¼ç”Ÿäº†ç‰¹æ®Šæƒ…æ³
+Comment[zh_TW]=程å¼ä¸­ç™¼ç”Ÿäº†ç‰¹æ®Šçš„情æ³
+default_presentation=1
+default_sound=KDE_Beep.ogg
+level=1
+
+[warning]
+Name=Warning
+Name[af]=Waarskuwing
+Name[ar]=تحذير
+Name[az]=Diqqət
+Name[be]=ПапÑÑ€Ñджанне
+Name[bg]=Предупреждение
+Name[bn]=সতরà§à¦•à§€à¦•à¦°à¦£
+Name[br]=Kemenn
+Name[bs]=Upozorenje
+Name[ca]=Avís
+Name[cs]=Varování
+Name[csb]=Ã’strzega
+Name[cy]=Rhybudd
+Name[da]=Advarsel
+Name[de]=Warnung
+Name[el]=ΠÏοειδοποίηση
+Name[eo]=Averto
+Name[es]=Aviso
+Name[et]=Hoiatus
+Name[eu]=Abisua
+Name[fa]=اخطار
+Name[fi]=Varoitus
+Name[fo]=Ãvaring
+Name[fr]=Avertissement
+Name[fy]=Warskôging
+Name[ga]=Rabhadh
+Name[gl]=Aviso
+Name[he]=×זהרה
+Name[hi]=चेतावनी
+Name[hr]=Upozorenje
+Name[hsb]=Warnowanje
+Name[hu]=Figyelmeztetés
+Name[id]=Perhatian
+Name[is]=Aðvörun
+Name[it]=Avvertimento
+Name[ja]=警告
+Name[ka]=გáƒáƒ¤áƒ áƒ—ხილებáƒ
+Name[kk]=ЕÑкерту
+Name[km]=ព្រមាន
+Name[ko]=경고
+Name[lb]=Warnung
+Name[lt]=DÄ—mesio
+Name[lv]=BrÄ«dinÄjums
+Name[mk]=Предупредување
+Name[mn]=Сануулга
+Name[ms]=Amaran
+Name[mt]=Twissija
+Name[nb]=Advarsel
+Name[nds]=Wohrschoen
+Name[ne]=चेतावनी
+Name[nl]=Waarschuwing
+Name[nn]=Ã…tvaring
+Name[nso]=Temoso
+Name[oc]=Avis
+Name[pa]=ਚੇਤਾਵਨੀ
+Name[pl]=Ostrzeżenie
+Name[pt]=Aviso
+Name[pt_BR]=Aviso
+Name[ro]=Avertizare
+Name[ru]=Предупреждение
+Name[rw]=Iburira
+Name[se]=Váruhus
+Name[sk]=Varovanie
+Name[sl]=Opozorilo
+Name[sq]=Vërejtje
+Name[sr]=Упозорење
+Name[sr@Latn]=Upozorenje
+Name[ss]=Secwayiso
+Name[sv]=Varning
+Name[ta]=எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆ
+Name[te]=హెచà±à°šà°°à°¿à°•
+Name[tg]=Огоҳӣ
+Name[th]=คำเตือน
+Name[tr]=Dikkat
+Name[tt]=Kisätmä
+Name[uk]=ПопередженнÑ
+Name[uz]=Diqqat
+Name[uz@cyrillic]=Диққат
+Name[ven]=Khaidzo
+Name[vi]=Cảnh báo
+Name[wa]=Adviertixhmint
+Name[xh]=Isilumkiso
+Name[zh_CN]=警告
+Name[zh_HK]=警告
+Name[zh_TW]=警告
+Name[zu]=Isexwayiso
+Comment=There was an error in the program which may cause problems
+Comment[af]=Daar was 'n fout in die program wat dalk probleme kan veroorsaak
+Comment[be]=У праграме адбылаÑÑ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ°, ÑÐºÐ°Ñ Ð¼Ð¾Ð¶Ð° Ñтварыць перашкоды нармальнай працы
+Comment[bg]=ПоÑви Ñе грешка, коÑто може да предизвика проблеми
+Comment[bn]=পà§à¦°à§‹à¦—à§à¦°à¦¾à¦®à§‡ à¦à¦•à¦Ÿà¦¿ তà§à¦°à§à¦Ÿà¦¿ ছিল যার ফলে সমসà§à¦¯à¦¾ হতে পারে
+Comment[br]=Ur fazi a voe er goulev a c'hellfe bezañ pennabeg kudennoù.
+Comment[bs]=Postoji greška u programu koja možda uzrokuje probleme.
+Comment[ca]=Hi ha hagut un error en el programa que podria causar problemes
+Comment[cs]=Nastala chyba v programu, která může způsobit problémy
+Comment[csb]=Pòkôza sã fela, jakô mòże doprowadzëc do zmiłków w dalszi robòce
+Comment[da]=Der opstod en alvorlig fejl som kan forårsage problemer
+Comment[de]=Es ist ein Programmfehler aufgetreten, der Probleme verursachen könnte.
+Comment[el]=ΥπήÏξε ένα σφάλμα στο Ï€ÏόγÏαμμα που ίσως να Ï€Ïοκαλέσει Ï€Ïοβλήματα
+Comment[eo]=Okazis eraro en la programo, kiu povus kaÅ­zi problemojn.
+Comment[es]=Hubo un error en el programa que puede causar problemas
+Comment[et]=Programmis ilmnes viga, mis võib tekitada probleeme
+Comment[eu]=Arazoak sor ditzakeen errorea gertatu da programan
+Comment[fa]=خطایی در برنامه وجود دارد که ممکن است باعث بروز مسائلی شود
+Comment[fi]=Ohjelmassa tapahtui virhe, joka voi aiheuttaa ongelmia
+Comment[fr]=Une erreur est survenu dans le programme, pouvant causer des dysfonctionnements.
+Comment[fy]=Der wie in flater yn it programma wat swierrichheid feroorsaakje kin
+Comment[ga]=Bhí earráid sa chlár agus b'fhéidir go mbeidh fadhbanna dá barr
+Comment[gl]=Houbo un erro no programa que pode causar problemas.
+Comment[he]=×ירעה שגי××” חמורה שעלולה ×œ×’×¨×•× ×œ×‘×¢×™×•×ª
+Comment[hi]=पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® में तà¥à¤°à¥à¤Ÿà¤¿ है जिससे समसà¥à¤¯à¤¾ उतà¥à¤ªà¤¨à¥à¤¨ हो सकती है
+Comment[hr]=UoÄena je pogreÅ¡ka u programu zbog koje bi moglo biti problema
+Comment[hsb]=Je so nÄ›kajki zmylk staÅ‚, kiž móhÅ‚ problemy sÄinić
+Comment[hu]=Olyan hiba történt a programban, mely további problémákat okozhat
+Comment[id]=Ada kesalahan dalam program yang dapat menyebabkan masalah
+Comment[is]=Það kom upp villa í forritinu sem gæti valdið vandræðum
+Comment[it]=Nel programma si è verificato un errore che può causare problemi
+Comment[ja]=å•é¡Œã‚’引ãèµ·ã“ã™å¯èƒ½æ€§ã®ã‚るエラーãŒãƒ—ログラムã«ã‚ã‚Šã¾ã—ãŸ
+Comment[ka]=პრáƒáƒ’რáƒáƒ›áƒ˜áƒ¡ შეცდáƒáƒ›áƒ, რáƒáƒ›áƒ”ლმáƒáƒª შესáƒáƒ«áƒšáƒáƒ პრáƒáƒ‘ლემრშექმნáƒáƒ¡
+Comment[kk]=Бір қате бағдарламада мәÑелелер тудырды
+Comment[km]=មាន​កំហុស​មួយ​ក្នុង​កម្មវិធី​ដែល​អាច​បណ្ážáž¶áž›â€‹áž²áŸ’យ​មាន​បញ្ហា
+Comment[lb]=Et ass e Feeler am Programm opgetrueden, dee Problemer verursaache kéint
+Comment[lt]=Įvyko programos klaida, galinti sukelti problemų
+Comment[lv]=ProgrammÄ bija kļūda, kas var radÄ«t problÄ“mas
+Comment[mk]=Се Ñлучи грешка во програмот што може да предизвика проблеми
+Comment[ms]=Ada ralat di dalam program yang menyebabkan masalah.
+Comment[nb]=Det var en feil i programmet som kan føre til problemer
+Comment[nds]=Dat geev en Fehler in dat Programm, villicht treckt he Problemen na sik
+Comment[ne]=समसà¥à¤¯à¤¾ आउनà¥à¤®à¤¾ कारà¥à¤¯à¤•à¥à¤°à¤®à¤®à¤¾ तà¥à¤°à¥à¤Ÿà¤¿ कारण थियो
+Comment[nl]=Er zat een fout in het programma die voor problemen kon zorgen
+Comment[nn]=Det oppstod ein feil i programmet og kan føra til problem
+Comment[pa]=ਕਾਰਜ ਵਿੱਚ ਗਲਤੀ ਆਈ ਹੈ, ਜੋ ਕਿ ਸਮੱਸਿਆ ਪੈਦਾ ਕਰ ਰਹੀ ਹੈ
+Comment[pl]=Wystąpił błąd, który może spowodować zakłócenia w pracy
+Comment[pt]=Ocorreu um erro grave no programa que pode causar problemas
+Comment[pt_BR]=Houve um erro no programa que pode ter causado problemas
+Comment[ro]=A apărut o eroare în program care ar putea cauza probleme
+Comment[ru]=Ошибка в программе, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¼Ð¾Ð¶ÐµÑ‚ вызвать проблемы
+Comment[rw]=Habaye ikosa muri porogaramu rishobora gutera ibibazo
+Comment[se]=Prográmmas lei meattáhus mii sáhttá dagahit váttisvuođaid
+Comment[sk]=V programe sa vyskytla chyba, ktorá môže spôsobiť problémy
+Comment[sl]=V programu je nastala napaka, ki lahko povzroÄi težave
+Comment[sr]=ДеÑила Ñе грешка у програму која може изазвати проблеме
+Comment[sr@Latn]=Desila se greška u programu koja može izazvati probleme
+Comment[sv]=Det uppstod ett fel i programmet vilket kan orsaka problem
+Comment[ta]=பிரசà¯à®©à¯ˆà®•à®³à¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ அளவிறà¯à®•à¯ நிரலில௠ஒர௠தவற௠இரà¯à®¨à¯à®¤à®¤à¯.
+Comment[te]=కారà±à°¯à°•à±à°°à°®à°‚ లొ దోషం కలదà±, ఇది సమసà±à°¯à°²à°¨à± à°•à°²à±à°—చేయవచà±à°šà±à°¨à±
+Comment[tg]=Хатои барнома, ки метавон ба маÑъалаҳое оварад
+Comment[th]=มีข้อผิดพลาดในโปรà¹à¸à¸£à¸¡ ซึ่งอาจจะส่งผลให้เà¸à¸´à¸”ปัà¸à¸«à¸²à¹„ด้
+Comment[tr]=Programda ciddi bir hata oluÅŸtu
+Comment[tt]=Qıyınlıqlarğa kiterä ala torğan xatalar kilep çıqqannar
+Comment[uk]=СталаÑÑ Ñерйозна помилка, Ñка може викликати проблеми
+Comment[uz]=Dasturda muammolarga olib kelishi mumkin boʻlgan xato roʻy berdi
+Comment[uz@cyrillic]=ДаÑтурда муаммоларга олиб келиши мумкин бўлган хато рўй берди
+Comment[vi]=Gặp lá»—i trong chÆ°Æ¡ng trình, mà có thể gây ra vấn Ä‘á».
+Comment[zh_CN]=程åºä¸­å‘生了å¯èƒ½å¯¼è‡´é—®é¢˜çš„错误
+Comment[zh_TW]=程å¼ä¸­ç™¼ç”Ÿäº†ä¸€å€‹å¯èƒ½æœƒå°Žè‡´ç™¼ç”Ÿå•é¡Œçš„錯誤。
+default_presentation=2
+level=2
+
+[catastrophe]
+Name=Catastrophe
+Name[af]=Katastrofe
+Name[ar]=كارثة
+Name[az]=FaciÉ™
+Name[be]=КатаÑтрофа
+Name[bg]=КатаÑтрофа
+Name[bn]=বিপরà§à¦¯à§Ÿ
+Name[br]=Gwalldaol
+Name[bs]=Katastrofa
+Name[ca]=Catàstrofe
+Name[cs]=Katastrofa
+Name[csb]=Katastrofa
+Name[cy]=Erchyll
+Name[da]=Katastrofe
+Name[de]=Schwerwiegender Fehler
+Name[el]=ΚαταστÏοφή
+Name[eo]=Katastrofo
+Name[es]=Catástrofe
+Name[et]=Katastroof
+Name[eu]=Ondamendia
+Name[fa]=Ùاجعه
+Name[fi]=Katastrofi
+Name[fy]=Katastrofe
+Name[ga]=Tubaiste
+Name[gl]=Catástrofe
+Name[he]=קטסטרופה
+Name[hi]=पà¥à¤°à¤²à¤¯
+Name[hr]=Katastrofa
+Name[hsb]=Katastrofa
+Name[hu]=Katasztrófa
+Name[id]=Katastrofi
+Name[is]=Stórslys
+Name[it]=Catastrofe
+Name[ja]=大惨事
+Name[ka]=სისტემის კრáƒáƒ®áƒ˜
+Name[kk]=ЖаңылыÑ
+Name[km]=មហន្ážážšáž¶áž™
+Name[ko]=í°ì¼ë‚¬ìŠµë‹ˆë‹¤
+Name[lb]=Katastroph
+Name[lt]=Katastrofa
+Name[lv]=Katastrofa
+Name[mk]=КатаÑтрофа
+Name[mn]=СүйрÑл
+Name[ms]=Malapetaka
+Name[mt]=Katastrofu
+Name[nb]=Katastrofe
+Name[nds]=Katastroof
+Name[ne]=विपतà¥à¤¤à¥€
+Name[nl]=Catastrofe
+Name[nn]=Katastrofe
+Name[oc]=Catastrofe
+Name[pa]=ਕਾਟਾਸਟਰੋਫੀ
+Name[pl]=Katastrofa
+Name[pt]=Catástrofe
+Name[pt_BR]=Catástrofe
+Name[ro]=Catastrofă
+Name[ru]=Сбой ÑиÑтемы
+Name[rw]=Amakuba
+Name[se]=Katastrofa
+Name[sk]=Katastrofa
+Name[sl]=Katastrofa
+Name[sq]=Katastrofë
+Name[sr]=КатаÑтрофа
+Name[sr@Latn]=Katastrofa
+Name[ss]=Inhlekelele
+Name[sv]=Katastrof
+Name[ta]=பிரளயமà¯
+Name[te]=విపతà±à°¤à±
+Name[tg]=ÐуқÑони ÑиÑтема
+Name[th]=เหตุหายนะ
+Name[tr]=Facia
+Name[tt]=Bälä-qaza
+Name[uk]=КатаÑтрофа
+Name[uz]=Fojia
+Name[uz@cyrillic]=Фожиа
+Name[ven]=Mutshinyalo
+Name[vi]=Lá»—i rất nghiêm trá»ng
+Name[xh]=Ingozi enkulu
+Name[zh_CN]=严é‡é—®é¢˜
+Name[zh_HK]=åš´é‡å•é¡Œ
+Name[zh_TW]=åš´é‡å•é¡Œ
+Name[zu]=Inhlekelele
+Comment=A very serious error occurred, at least causing the program to exit
+Comment[af]='n baie ernstige fout het voorgekom. Dit het veroorsaak dat ten minste die program beëindig is
+Comment[ar]=حدث خطأ كبير سيؤدي على الأقل الى ايقا٠البرنامج
+Comment[az]=Çox ciddi bir xəta yarandə və proqramı çıxmağa məcbur etdi
+Comment[be]=ÐдбылаÑÑ Ð²ÐµÐ»ÑŒÐ¼Ñ– Ñур'Ñ‘Ð·Ð½Ð°Ñ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ°, ÑÐºÐ°Ñ Ð¿Ñ€Ñ‹Ð²Ñла да выхаду з праграмы
+Comment[bg]=ПоÑви Ñе Ñериозна грешка, коÑто предизвика Ñпиране на програмата
+Comment[bn]=à¦à¦•à¦Ÿà¦¿ গমà§à¦­à§€à¦° তà§à¦°à§à¦Ÿà¦¿à¦° ফলে পà§à¦°à§‹à¦—à§à¦°à¦¾à¦®à¦Ÿà¦¿ থেমে গেছে
+Comment[br]=Ur fazi grevus-tre a c'hoarvezas, a lakas d'an nebeutañ ar goulev da vont er-maez
+Comment[bs]=Došlo je do vrlo ozbiljne greške koja je uzrokovala najmanje prekid programa
+Comment[ca]=Hi ha hagut un error molt seriós, com a mínim ha causat la finalització del programa
+Comment[cs]=Nastala velmi závažná chyba, která pÅ™inejmenším způsobila ukonÄení programu.
+Comment[csb]=Pòkôza sã pòwôżnô fela, jakô doprowadzëła co nômni do zakùńczeniô programë
+Comment[cy]=Digwyddodd gwall difrifol iawn, oedd o leiaf yn achosi i'r rhaglen derfynu
+Comment[da]=Der opstod et meget alvorligt problem som fik programmet til at afslutte.
+Comment[de]=Ein schwerer Fehler ist aufgetreten, der zumindest zum Beenden des Programms geführt hat.
+Comment[el]=Ένα Ï€Î¿Î»Ï ÏƒÎ¿Î²Î±ÏÏŒ σφάλμα συνέβη, που τουλάχιστον οδήγησε στο κλείσιμο του Ï€ÏογÏάμματος
+Comment[eo]=Okazis tre grava eraro, kiu ĉesigis la programon
+Comment[es]=Ocurrió un error muy serio, causando al menos el cierre del programa.
+Comment[et]=Ilmnes väga tõsine viga, mis sundis programmi tööd lõpetama.
+Comment[eu]=Errore oso larria gertatu da, programa itxiaraziz
+Comment[fa]=یک خطای بسیار جدی رخ داد، حداقل باعث خروج برنامه شد
+Comment[fi]=Tapahtui vakava virhe, jonka takia ohjelma ainakin lopetetaan.
+Comment[fr]=Une erreur très grave s'est produite, provoquant au moins l'arrêt du programme
+Comment[fy]=In serieuse flater had him foardyn wertroch it programma sluten is
+Comment[ga]=Tharla droch-earráid, agus ara laghad tá an clár tar éis stopadh
+Comment[gl]=Ocorreu un erro moi sério, causando polo menos o remate da execución do programa
+Comment[he]=×ירעה שגי××” חמורה מ×וד, שלפחות גרמה לתוכנית לצ×ת
+Comment[hi]=à¤à¤• अति गंभीर तà¥à¤°à¥à¤Ÿà¤¿ हà¥à¤ˆ, जिससे पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बाहर हो गया
+Comment[hr]=Došlo je do jako ozbiljne pogreške, koja će u najmanju ruku prouzrokovati zatvaranje programa.
+Comment[hsb]=Je so jara chutny zmylk staÅ‚, kiž je znajmjeÅ„Å¡a program skónÄiÅ‚
+Comment[hu]=Súlyos programhiba történt, a program futása félbeszakadt
+Comment[id]=Ada kesalahan serius muncul, menyebabkan program harus diakhiri
+Comment[is]=Mjög alvarleg villa kom upp, sem hefur stöðvað keyrslu forritsins
+Comment[it]=Si è verificato un errore molto grave, che come minimo ha causato la fine del programma
+Comment[ja]=éžå¸¸ã«é‡å¤§ãªã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã€ãã®ãŸã‚ã«å°‘ãªãã¨ã‚‚プログラムãŒçµ‚了ã—ã¾ã—ãŸ
+Comment[ka]=სერიáƒáƒ–ული შეცდáƒáƒ›áƒ, რáƒáƒ›áƒ”ლმáƒáƒª პრáƒáƒ’რáƒáƒ›áƒ˜áƒ“áƒáƒœ გáƒáƒ¡áƒ•áƒšáƒ გáƒáƒ›áƒáƒ˜áƒ¬áƒ•áƒ˜áƒ
+Comment[kk]=Өте маңызды бір қате кемінде бағдарламадан шығуға мәжбүрледі
+Comment[km]=កំហុស​ដáŸâ€‹áž’្ងន់ធ្ងរ​បំផុážâ€‹áž˜áž½áž™â€‹áž”ាន​កើážáž¡áž¾áž„ ដែល​យ៉ាង​ហោច​ណាស់ ​វា​បណ្ážáž¶áž›â€‹áž²áŸ’យកម្មវិធី​បិទ
+Comment[ko]=í”„ë¡œê·¸ëž¨ì´ ëë‚  ë•Œ 아주 심ê°í•œ 오류가 ìƒê²¼ìŠµë‹ˆë‹¤
+Comment[lb]=E ganz schlëmme Feeler ass opgetrueden, deen op Mannst zum Ophale vum Programm gefouert huet
+Comment[lt]=Įvyko labai rimta klaida, privertusi programą bent jau baigti darbą.
+Comment[lv]=GadÄ«jusies ļoti nopietna kļūda, kas kÄ minumums izraisa izieÅ¡anu no programmas
+Comment[mk]=Се Ñлучи Ñериозна грешка, што во најмала рака предизвика програмот да Ñе иÑклучи
+Comment[mn]=Дор хаÑж программыг таÑлан гарах ноцтой алдаа гарлаа.
+Comment[ms]=Ada ralat sangat serius di dalam program yang menyebabkan program keluar
+Comment[nb]=Det oppsto en alvorlig feil som til slutt førte til at programmet avsluttet
+Comment[nds]=Dor is en Malöör passeert, dat tominnst to't Enn vun't Programm föhrt hett
+Comment[ne]=कमà¥à¤¤à¤¿à¤®à¤¾ कारà¥à¤¯à¤•à¥à¤°à¤® अनà¥à¤¤à¥à¤¯ गरà¥à¤¦à¤¾, à¤à¤‰à¤Ÿà¤¾ धेरै गमà¥à¤­à¤¿à¤° तà¥à¤°à¥à¤Ÿà¤¿ देखा परà¥à¤¯à¥‹
+Comment[nl]=Er deed zich een zeer ernstige fout voor, waardoor tenminste de toepassing werd afgesloten
+Comment[nn]=Ein svært alvorleg feil oppstod, som førte til at programmet avslutta
+Comment[pa]=ਇੱਕ ਘਾਤਕ ਗਲਤੀ ਆਈ ਹੈ, ਘੱਟੋ-ਘੱਟ ਇਹ ਕਾਰਜ ਨੂੰ ਬੰਦ ਹੋਣ ਲਈ ਮਜ਼ਬੂਰ ਕਰ ਰਹੀ ਹੈ
+Comment[pl]=Wystąpił bardzo poważny błąd, który spowodował przynajmniej zakończenie programu
+Comment[pt]=Ocorreu um erro muito grave, que no mínimo provocou o fim da execução do programa
+Comment[pt_BR]=Ocorreu um erro grave, que causou no mínimo a saída do programa.
+Comment[ro]=A apărut o eroare foarte severă în program care a provocat cel puţin terminarea lui
+Comment[ru]=Возник Ñерьёзный Ñбой, приведший как минимум к выходу из программы
+Comment[rw]=Ikosa rikomeye cyane ryagaragaye, rituma porogaramu ihagarara
+Comment[se]=Hui vearrás meattáhus dáhpáhuvai, dagahii goit prográmma heaitit
+Comment[sk]=Vyskytla sa veľmi vážna chyba, ktorá minimálne ukonÄí program
+Comment[sl]=Nastala je tako resna napaka, da se bo konÄal program.
+Comment[sq]=Një gabim serioz ka ndodhur, së paku do të shkaktoj mbylljen e programit
+Comment[sr]=ДеÑила Ñе веома озбиљна грешка, која ће у најмању руку проузроковати затварање програма
+Comment[sr@Latn]=Desila se veoma ozbiljna greška, koja će u najmanju ruku prouzrokovati zatvaranje programa
+Comment[sv]=Ett väldigt allvarligt fel uppstod som åtminstone fick programmet att avslutas
+Comment[ta]=நிரலை வெளியேறச௠செயà¯à®¯à¯à®®à¯ அளவில௠ஒர௠பெரிய தவற௠à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯
+Comment[te]=చాలా à°®à±à°–à±à°¯à°®à±ˆà°¨ దోషం à°’à°•à°Ÿà°¿ కారà±à°¯à°•à±à°°à°®à°‚లో వచà±à°šà°¿à°‚ది,ఇది కనీసం కారà±à°¯à°•à±à°°à°®à°‚ నిషà±à°•à±à°°à°®à°£à°•à± కారణమౌతà±à°‚ది
+Comment[tg]=ÐуқÑони ҷиддӣ рӯй дод, ки чун минимум ба аз барнома баромадан раÑонид
+Comment[th]=เà¸à¸´à¸”ข้อผิดพลาดที่ร้ายà¹à¸£à¸‡à¸¡à¸²à¸ ซึ่งอย่างน้อยจะทำให้โปรà¹à¸à¸£à¸¡à¸ˆà¸šà¸à¸²à¸£à¸—ำงาน
+Comment[tr]=Programın kapanmasına neden olan ciddi bir hata oluştu ve programdan çıkıldı.
+Comment[tt]=İñ kimendä,yazılımnan çığuına kitergän bik citdi xata kilep çıqqan
+Comment[uk]=СталаÑÑ Ð´ÑƒÐ¶Ðµ Ñерйозна помилка, Ñка, щонайменше, Ñтала причиною виходу програми
+Comment[uz]=Dasturning ishini yakunlanishiga sababchi boʻlgan jiddiy xato roʻy berdi
+Comment[uz@cyrillic]=ДаÑтурнинг ишини Ñкунланишига Ñабабчи бўлган жиддий хато рўй берди
+Comment[vi]=Gặp lá»—i rất nghiêm trá»ng mà ít nhất đã gây ra chÆ°Æ¡ng trình thoát.
+Comment[zh_CN]=出现了一个éžå¸¸ä¸¥é‡çš„错误,至少使程åºé€€å‡º
+Comment[zh_HK]=發生了一個很嚴é‡çš„錯誤,令程å¼å¿…é ˆçµæŸ
+Comment[zh_TW]=因為發生了一個很嚴é‡çš„錯誤,所以該程å¼å¿…é ˆè¦çµæŸ
+default_presentation=2
+level=8
+[startkde]
+Name=Login
+Name[af]=Aanteken
+Name[ar]=دخول
+Name[az]=GiriÅŸ
+Name[be]=Уваход
+Name[bg]=Вход в ÑиÑтемата
+Name[bn]=লগ-ইন
+Name[br]=Anv ereañ
+Name[bs]=Prijava
+Name[ca]=Accés
+Name[cs]=Přihlášení
+Name[csb]=Logòwanié
+Name[cy]=Mewngofnodi
+Name[da]=Log på
+Name[de]=Anmelden
+Name[el]=ΣÏνδεση
+Name[eo]=Ensaluto
+Name[es]=Entrada
+Name[et]=Sisselogimine
+Name[eu]=Hasi saioa
+Name[fa]=ورود
+Name[fi]=Kirjaudu sisään
+Name[fo]=Innrita
+Name[fr]=Début de session
+Name[fy]=Oanmelde
+Name[ga]=Logáil Isteach
+Name[he]=כניסה למערכת
+Name[hi]=लॉगइन
+Name[hr]=Prijava
+Name[hsb]=Přizjewjenje
+Name[hu]=Bejelentkezés
+Name[is]=Innstimplun
+Name[it]=Accesso
+Name[ja]=ログイン
+Name[ka]=შესვლáƒ
+Name[kk]=Кіру
+Name[km]=ចូល
+Name[ko]=로그ì¸
+Name[ku]=Têketin
+Name[lb]=Umellen
+Name[lt]=Registracija
+Name[lv]=Pieteikties
+Name[mk]=Ðајавување
+Name[mn]=БүртгүүлÑÑ…
+Name[ms]=Log masuk
+Name[nb]=Logg inn
+Name[nds]=Anmellen
+Name[ne]=लगइन
+Name[nl]=Aanmelden
+Name[nn]=Logg inn
+Name[nso]=Tsena
+Name[oc]=Conneccion
+Name[pa]=ਲਾਗਇਨ
+Name[pl]=Zalogowanie
+Name[pt]=Inicio de sessão
+Name[ro]=Logare
+Name[ru]=Вход
+Name[rw]=Ifashayinjira
+Name[se]=SisaÄáliheapmi
+Name[sk]=Prihlásenie
+Name[sl]=Prijava
+Name[sq]=Hyni
+Name[sr]=Пријава
+Name[sr@Latn]=Prijava
+Name[ss]=Kungena
+Name[sv]=Logga in
+Name[ta]=நà¯à®´à¯ˆà®µà¯
+Name[te]=లాగినà±
+Name[tg]=Вурудот
+Name[th]=ล็อà¸à¸­à¸´à¸™
+Name[tr]=GiriÅŸ
+Name[tt]=KereÅŸ
+Name[uk]=РеєÑтраціÑ
+Name[uz]=Kirish
+Name[uz@cyrillic]=Кириш
+Name[ven]=U dzhena kha khomupwutha
+Name[vi]=Äăng nhập
+Name[wa]=Elodjaedje
+Name[xh]=Igama elithile
+Name[zh_CN]=登录
+Name[zh_HK]=登入
+Name[zh_TW]=登入
+Name[zu]=Ukungena ngaphakathi
+Comment=KDE is starting up
+Comment[af]=Begin KDE Laai
+Comment[ar]=جاري بدء تشغيل KDE
+Comment[be]=Стартаванне KDE
+Comment[bg]=Стартиране на ÑиÑтемата
+Comment[bn]=কে.ডি.ই. চালৠহচà§à¦›à§‡
+Comment[br]=Emañ o loc'hañ KDE
+Comment[bs]=KDE se pokreće
+Comment[ca]=S'està engegant el KDE
+Comment[cs]=Spouští se prostředí KDE
+Comment[csb]=Zrëszënié KDE
+Comment[da]=KDE er ved at starte
+Comment[de]=KDE startet
+Comment[el]=Το KDE ξεκινά
+Comment[eo]=KDE estas lanĉata
+Comment[es]=KDE está arrancando
+Comment[et]=KDE käivitub
+Comment[eu]=KDE abiarazten ari da
+Comment[fa]=KDE در حال راه‌اندازی است
+Comment[fi]=KDE:tä käynnistetään
+Comment[fr]=KDE est en cours de démarrage
+Comment[fy]=KDE set útein
+Comment[ga]=Tá KDE ag tosú.
+Comment[gl]=KDE está a Iniciar-se
+Comment[he]=×יתחול KDE בעיצומו
+Comment[hi]=केडीई पà¥à¤°à¤¾à¤°à¤‚भ हो रहा है
+Comment[hr]=Podizanje KDE
+Comment[hsb]=KDE so startuje
+Comment[hu]=A KDE elindul
+Comment[id]=KDE mulai dijalankan
+Comment[is]=KDE er að ræsa
+Comment[it]=Avvio di KDE
+Comment[ja]=KDE 起動中
+Comment[ka]=KDE-ს დáƒáƒ¬áƒ§áƒ”ბáƒ
+Comment[kk]=KDE жұмыÑын баÑтауда
+Comment[km]=KDE កំពុង​ចាប់ផ្ážáž¾áž˜
+Comment[ku]=KDE dest pê dike
+Comment[lb]=KDE gëtt gestart
+Comment[lt]=KDE pradeda darbÄ…
+Comment[lv]=Tiek startēts KDE
+Comment[mk]=KDE Ñе вклучува
+Comment[ms]=KDE sedang bermula
+Comment[nb]=KDE starter
+Comment[nds]=KDE warrt start
+Comment[ne]=KDE सà¥à¤°à¥à¤†à¤¤ हà¥à¤¦à¥ˆà¤›
+Comment[nl]=KDE is aan het opstarten
+Comment[nn]=KDE startar
+Comment[pa]=KDE ਸ਼à©à¨°à©‚ ਹੋ ਰਿਹਾ ਹੈ
+Comment[pl]=Uruchomienie KDE
+Comment[pt]=O KDE está a arrancar
+Comment[pt_BR]=KDE está iniciando
+Comment[ro]=KDE porneÅŸte
+Comment[ru]=ЗапуÑк KDE
+Comment[rw]=KDE iri gutangira
+Comment[se]=KDE vuolgigoahtá johtui
+Comment[sk]=KDE sa spúšťa
+Comment[sl]=KDE se zaganja
+Comment[sr]=KDE Ñе покреће
+Comment[sr@Latn]=KDE se pokreće
+Comment[sv]=KDE startas
+Comment[ta]=கேடிஇ ஆரமà¯à®ªà®¿à®•à¯à®•à®¿à®±à®¤à¯
+Comment[te]=కెడిఈ మొదవà±à°¤à±à°‚ది
+Comment[tg]=Оғози KDE
+Comment[th]=KDE à¸à¸³à¸¥à¸±à¸‡à¹€à¸£à¸´à¹ˆà¸¡à¸à¸²à¸£à¸—ำงาน
+Comment[tr]=KDE masaüstü başlıyor
+Comment[tt]=KDE yöklänä
+Comment[uk]=Триває запуÑк KDE
+Comment[uz]=KDE ishga tushmoqda
+Comment[uz@cyrillic]=KDE ишга тушмоқда
+Comment[vi]=KDE đang khởi chạy.
+Comment[zh_CN]=KDE 正在å¯åŠ¨
+Comment[zh_HK]=KDE 正在啟動
+Comment[zh_TW]=KDE 正在啟動
+default_presentation=1
+default_sound=KDE_Startup_1.ogg
+
+[exitkde]
+Name=Logout
+Name[af]=Teken af
+Name[ar]=الخروج
+Name[az]=Çıxış
+Name[be]=ЗаканчÑнне ÑеанÑу
+Name[bg]=Изход от ÑиÑтемата
+Name[bn]=লগ-আউট
+Name[br]=Kuitaat
+Name[bs]=Odjava
+Name[ca]=Sortida
+Name[cs]=Odhlášení
+Name[csb]=Wëlogòwanié
+Name[cy]=Allgofnodi
+Name[da]=Log af
+Name[de]=Abmelden
+Name[el]=ΑποσÏνδεση
+Name[eo]=Elsaluto
+Name[es]=Salida
+Name[et]=Väljalogimine
+Name[eu]=Amaitu saioa
+Name[fa]=خروج
+Name[fi]=Kirjaudu ulos
+Name[fo]=Útrita
+Name[fr]=Fin de session
+Name[fy]=Ofmelde
+Name[ga]=Logáil Amach
+Name[he]=יצי××” מהמערכת
+Name[hi]=लॉगआउट
+Name[hr]=Odjava
+Name[hsb]=Wotzjewjenje
+Name[hu]=Kijelentkezés
+Name[is]=Stimpla út
+Name[it]=Uscita
+Name[ja]=ログアウト
+Name[ka]=გáƒáƒ›áƒáƒ¡áƒ•áƒšáƒ
+Name[kk]=Шығу
+Name[km]=áž…áŸáž‰
+Name[ko]=로그아웃
+Name[ku]=Derketin
+Name[lb]=Ofmellen
+Name[lt]=IÅ¡siregistravimas
+Name[lv]=Atteikties
+Name[mk]=Одјавување
+Name[mn]=Хаалгах
+Name[ms]=Log keluar
+Name[mt]=Temm is-sessjoni
+Name[nb]=Logg ut
+Name[nds]=Afmellen
+Name[ne]=लगआउट
+Name[nl]=Afmelden
+Name[nn]=Logg ut
+Name[nso]=Etswa
+Name[oc]=Desconneccion
+Name[pa]=ਲਾਗਆਉਟ
+Name[pl]=Wylogowanie
+Name[pt]=Fim de sessão
+Name[pt_BR]=Sair
+Name[ro]=IeÅŸire
+Name[ru]=Выход из KDE
+Name[rw]=Gusohoka
+Name[se]=OlggosÄáliheapmi
+Name[sk]=Odhlásenie
+Name[sl]=Odjava
+Name[sq]=Dilni
+Name[sr]=Одјављивање
+Name[sr@Latn]=Odjavljivanje
+Name[ss]=Phuma
+Name[sv]=Logga ut
+Name[ta]=à®®à¯à®Ÿà®¿à®¤à¯à®¤à®²à¯
+Name[te]=లాగౌటà±
+Name[tg]=Баромад аз KDE
+Name[th]=ล็อà¸à¹€à¸­à¸²à¸•à¹Œ
+Name[tr]=Çıkış
+Name[tt]=Çığış
+Name[uk]=Кінець ÑеанÑу
+Name[uz]=Chiqish
+Name[uz@cyrillic]=Чиқиш
+Name[ven]=U litsha u shumisa khomupwutha
+Name[vi]=Äăng xuất
+Name[wa]=Dislodjaedje
+Name[xh]=Phuma ngaphandle
+Name[zh_CN]=注消
+Name[zh_HK]=登出
+Name[zh_TW]=登出
+Name[zu]=Phumela ngaphandle
+Comment=KDE is exiting
+Comment[af]=KDE is besig om toe te maak
+Comment[ar]=جاري إيقا٠KDE
+Comment[be]=Выхад з KDE
+Comment[bg]=Спиране на ÑиÑтемата
+Comment[bn]=কে.ডি.ই. বনà§à¦§ করা হচà§à¦›à§‡
+Comment[br]=Emañ o kuitaat KDE
+Comment[bs]=KDE se zatvara
+Comment[ca]=S'està aturant el KDE
+Comment[cs]=UkonÄuje se prostÅ™edí KDE
+Comment[csb]=Zakùńczenié KDE
+Comment[da]=KDE er ved at afslutte
+Comment[de]=KDE wird beendet
+Comment[el]=Το KDE τεÏματίζει
+Comment[eo]=KDE estas finata
+Comment[es]=KDE está terminando
+Comment[et]=KDE lõpetab töö
+Comment[eu]=KDE bukatzen ari da
+Comment[fa]=KDE در حال خروج است
+Comment[fi]=KDE:tä sammutetaan
+Comment[fr]=KDE est en cours d'arrêt
+Comment[fy]=KDE giet nei de útgong
+Comment[ga]=Tá KDE ag stopadh.
+Comment[gl]=KDE está Saindo
+Comment[he]=היצי××” מ־KDE בעיצומה
+Comment[hi]=केडीई बंद हो रहा है
+Comment[hr]=Izlazak KDE
+Comment[hsb]=KDE so zakónÄi
+Comment[hu]=A KDE kilép
+Comment[id]=KDE sedang diakhiri
+Comment[is]=KDE er að hætta
+Comment[it]=Uscita da KDE
+Comment[ja]=KDE 終了中
+Comment[ka]=KDE-დáƒáƒœ გáƒáƒ›áƒáƒ¡áƒ•áƒšáƒ
+Comment[kk]=KDE жүйеÑінен шығу
+Comment[km]=KDE កំពុង​បិទ
+Comment[lb]=KDE gëtt zougemat
+Comment[lt]=KDE baigia darbÄ…
+Comment[lv]=KDE beidz darbu
+Comment[mk]=KDE излегува
+Comment[ms]=KDE sedang keluar
+Comment[nb]=KDE avslutter
+Comment[nds]=KDE warrt utmaakt
+Comment[ne]=KDE अनà¥à¤¤à¥à¤¯ हà¥à¤à¤¦à¥ˆà¤›
+Comment[nl]=KDE is aan het afsluiten
+Comment[nn]=KDE avsluttar
+Comment[pa]=KDE ਸਮਾਪਤ ਹੋ ਰਿਹਾ ਹੈ
+Comment[pl]=Zakończenie KDE
+Comment[pt]=O KDE está a terminar
+Comment[pt_BR]=KDE está finalizando
+Comment[ro]=KDE se termină
+Comment[ru]=Выход из KDE
+Comment[rw]=KDE iri gufunga
+Comment[se]=KDE heaitigođii
+Comment[sk]=KDE sa ukonÄuje
+Comment[sl]=KDE se konÄuje
+Comment[sr]=KDE Ñе завршава
+Comment[sr@Latn]=KDE se završava
+Comment[sv]=KDE avslutas
+Comment[ta]=கேடிஇ வெளிசà¯à®šà¯†à®²à¯à®•à®¿à®±à®¤à¯
+Comment[te]=కెడిఈ నిషà±à°•à±à°°à°®à°¿à°¸à±à°¤à±à°‚ది
+Comment[tg]=Баромад аз KDE
+Comment[th]=à¸à¸³à¸¥à¸±à¸‡à¸­à¸­à¸à¸ˆà¸²à¸ KDE
+Comment[tr]=KDE Masaüstünden çıkılıyor
+Comment[tt]=KDE tuqtatıla
+Comment[uk]=Триває Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ KDE
+Comment[uz]=KDE ishini yakunlamoqda
+Comment[uz@cyrillic]=KDE ишини Ñкунламоқда
+Comment[vi]=KDE đang thoát.
+Comment[zh_CN]=KDE 正在退出
+Comment[zh_HK]=KDE 正在çµæŸ
+Comment[zh_TW]=KDE 正在çµæŸ
+default_presentation=1
+default_sound=KDE_Logout_3.ogg
+
+[cancellogout]
+Name=Logout canceled
+Name[bg]=Излизането от ÑиÑтемата отменено
+Name[ca]=S'ha anul·lat la desconnexió
+Name[cs]=Odhlášení zrušeno
+Name[csb]=Wëlogòwanié òprzestóné
+Name[da]=Log af annulleret
+Name[de]=Abmelden abgebrochen
+Name[el]=Η αποσÏνδεση ακυÏώθηκε
+Name[eo]=Elsaluto estis rezignita
+Name[es]=Salida cancelada
+Name[et]=Väljalogimine katkestatud
+Name[fi]=Uloskirjautuminen peruttu
+Name[fr]=Annulation de la déconnexion
+Name[fy]=Ofmelding ôfbrutsen
+Name[hr]=Odjavljivanje prekinuto
+Name[hu]=Kijelentkezés megszakítva
+Name[is]=Hætt við útstimplun
+Name[it]=Uscita annullata
+Name[ja]=ログアウトãŒã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸ
+Name[ka]=გáƒáƒ›áƒáƒ¡áƒ•áƒšáƒ გáƒáƒ£áƒ¥áƒ›áƒ“áƒ
+Name[kk]=Шығу доғарылды
+Name[km]=ការ​ចáŸáž‰â€‹áž”ាន​បោះបង់
+Name[lt]=IÅ¡siregistravimas nutrauktas
+Name[mk]=Откажано одјавување
+Name[nb]=Avbrutt utlogging
+Name[nds]=Afmellen afbraken
+Name[nl]=Afmelden geannuleerd
+Name[nn]=Utlogging avbroten
+Name[pa]=ਲਾਗਆਉਟ ਰੱਦ ਕੀਤਾ ਗਿਆ
+Name[pl]=Wylogowanie anulowane
+Name[pt]=Encerramento cancelado
+Name[pt_BR]=Logout cancelado
+Name[ru]=Выход из KDE прерван
+Name[sk]=Odhlásenie zrušené
+Name[sl]=Odjava preklicana
+Name[sr]=Одјављивање отказано
+Name[sr@Latn]=Odjavljivanje otkazano
+Name[sv]=Utloggning avbruten
+Name[te]=లాగౌటౠరదà±à°¦à±à°šà±‡à°¯à°¬à°¡à°¿à°¨à°¦à°¿
+Name[tg]=Баромадан аз KDE қатъ шуд
+Name[th]=ยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸¥à¹‡à¸­à¸à¹€à¸­à¸²à¸•à¹Œ
+Name[tr]=Oturumu kapatma iÅŸlemi iptal edildi
+Name[uk]=Вихід ÑкаÑовано
+Name[uz]=Chiqish bekor qilindi
+Name[uz@cyrillic]=Чиқиш бекор қилинди
+Name[zh_CN]=注消已å–消
+Name[zh_TW]=å–消登出
+Comment=KDE logout was canceled
+Comment[bg]=Излизането от KDE беше отменено
+Comment[ca]=S'ha anul·lat la desconnexió del KDE
+Comment[cs]=Odhlášení z KDE bylo zrušeno
+Comment[csb]=Logòwanié KDE òprzestóné
+Comment[da]=log af fra KDE blev annulleret
+Comment[de]=Das Abmelden von KDE wurde abgebrochen
+Comment[el]=Η αποσÏνδεση από το KDE ακυÏώθηκε
+Comment[eo]=KDE-elsaluto estas rezignita
+Comment[es]=La salida de KDE fue cancelada
+Comment[et]=KDE väljalogimine katkestati
+Comment[fi]=KDE:n uloskirjautuminen on peruttu
+Comment[fr]=La déconnexion de KDE a été annulée
+Comment[fy]=KDE ôfmelding wie ôfbrutsen
+Comment[hr]=KDE odjavljivanje je prekinuto
+Comment[hu]=A KDE-s kijelentkezés megszakadt
+Comment[is]=Hætt var við KDE útstimplun
+Comment[it]=L'uscita da KDE è stata annullata
+Comment[ja]=KDE ã‹ã‚‰ã®ãƒ­ã‚°ã‚¢ã‚¦ãƒˆãŒã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸ
+Comment[ka]=KDED გáƒáƒ›áƒáƒ¡áƒ•áƒšáƒ გáƒáƒ£áƒ¥áƒ›áƒ“áƒ
+Comment[kk]=KDE-ден шығу доғарылды
+Comment[km]=ការ​ចáŸáž‰â€‹ážšáž”ស់ KDE ážáŸ’រូវ​បាន​បោះបង់
+Comment[lt]=Išsiregistravimas iš KDE buvo nutrauktas
+Comment[mk]=Одјавувањето од KDE е откажано
+Comment[nb]=KDE utlogging ble avbrutt
+Comment[nds]=Afmellen vun KDE wöör afbraken
+Comment[nl]=Uitloggen KDE was geannuleerd
+Comment[nn]=KDE-utlogginga vart avbroten
+Comment[pa]=KDE ਲਾਗ-ਆਉਟ ਰੱਦ ਕੀਤਾ ਗਿਆ ਹੈ
+Comment[pl]=Wylogowanie z KDE zostało anulowane
+Comment[pt]=O encerramento da sessão do KDE foi cancelado
+Comment[pt_BR]=Logout do KDE foi cancelado
+Comment[ru]=Выход из KDE прерван
+Comment[sk]=Odhlásenie z KDE bolo zrušené
+Comment[sl]=Odjava iz KDE je bila preklicana
+Comment[sr]=Одјављивање из KDE-а је отказано
+Comment[sr@Latn]=Odjavljivanje iz KDE-a je otkazano
+Comment[sv]=Utloggning från KDE avbröts
+Comment[te]=కెడిఈ లాగౌటౠరదà±à°¦à±à°šà±‡à°¯à°¬à°¡à°¿à°¨à°¦à°¿
+Comment[tg]=Баромадан аз KDE қатъ карда шуд
+Comment[th]=à¸à¸²à¸£à¸¥à¹‡à¸­à¸à¹€à¸­à¸²à¸—์ออà¸à¸ˆà¸²à¸ KDE ถูà¸à¸¢à¸à¹€à¸¥à¸´à¸
+Comment[tr]=KDE oturumunu kapatma iÅŸlemi iptal edildi
+Comment[uk]=Вихід з KDE ÑкаÑовано
+Comment[uz]=KDE'dan chiqish bekor qilindi
+Comment[uz@cyrillic]=KDE'дан чиқиш бекор қилинди
+Comment[zh_CN]=KDE 注销已å–消
+Comment[zh_TW]=KDE 登出動作已被å–消
+default_presentation=16
+default_sound=
+
+[printerror]
+Name=Print error
+Name[af]=Druk fout
+Name[ar]=خطأ ÙÙŠ الطباعة
+Name[az]=Çap Edici xətası
+Name[be]=Памылка друку
+Name[bg]=Грешка при печат
+Name[bn]=মà§à¦¦à§à¦°à¦£ তà§à¦°à§à¦Ÿà¦¿
+Name[br]=Fazi en ur moulañ
+Name[bs]=Greška pri štampanju
+Name[ca]=Error d'impressió
+Name[cs]=Chyba tisku
+Name[csb]=Fela drëkù
+Name[cy]=Gwall argraffu
+Name[da]=Udskriftsfejl
+Name[de]=Fehler beim Drucken
+Name[el]=Σφάλμα εκτÏπωσης
+Name[eo]=Preseraro
+Name[es]=Error de impresión
+Name[et]=Viga trükkimisel
+Name[eu]=Inprimatze-errorea
+Name[fa]=خطای چاپ
+Name[fi]=Tulostusvirhe
+Name[fr]=Problème d'impression
+Name[fy]=Printflater
+Name[ga]=Earráid phriontála
+Name[gl]=Error de impresión
+Name[he]=שגי×ת הדפסה
+Name[hi]=छपाई तà¥à¤°à¥à¤Ÿà¤¿
+Name[hr]=Pogreška ispisa
+Name[hsb]=Ćišćenski zmylk
+Name[hu]=Nyomtatási hiba
+Name[id]=Kesalahan pencetakan
+Name[is]=Prentunarvilla
+Name[it]=Errore di stampa
+Name[ja]=å°åˆ·ã‚¨ãƒ©ãƒ¼
+Name[ka]=ბეჭდვის შეცდáƒáƒ›áƒ
+Name[kk]=БаÑып шығару қатеÑÑ–
+Name[km]=កំហុស​បោះពុម្ព
+Name[ko]=ì¸ì‡„ 오류
+Name[lb]=Dréckfeeler
+Name[lt]=Spausdinimo klaida
+Name[lv]=Drukas kļūda
+Name[mk]=Грешка при печатење
+Name[mn]=Ð¥ÑвлÑÑ…Ñд алдаа
+Name[ms]= Ralat cetak
+Name[mt]=Problema fl-ipprintjar
+Name[nb]=Skriverfeil
+Name[nds]=Fehler bi't Drucken
+Name[ne]=मà¥à¤¦à¥à¤°à¤£ तà¥à¤°à¥à¤Ÿà¤¿
+Name[nl]=Print fout
+Name[nn]=Utskriftsfeil
+Name[nso]=Bothata bja kgatiso
+Name[pa]=ਪà©à¨°à¨¿à©°à¨Ÿà¨° ਗਲਤੀ
+Name[pl]=BÅ‚Ä…d wydruku
+Name[pt]=Erro de impressão
+Name[pt_BR]=Erro de Impressão
+Name[ro]=Eroare tipărire
+Name[ru]=Ошибка печати
+Name[rw]=Ikosa ryo gucapa
+Name[se]=Čálihanmeattáhus
+Name[sk]=Chyba tlaÄe
+Name[sl]=Napaka pri tiskanju
+Name[sq]=Gabim shtypi
+Name[sr]=Грешка у штампању
+Name[sr@Latn]=Greška u štampanju
+Name[ss]=Liphutsa lekushicelela
+Name[sv]=Skrivarfel
+Name[ta]=அசà¯à®šà¯à®¤à¯ தவறà¯
+Name[te]=à°ªà±à°°à°šà±à°°à°£ దొషం
+Name[tg]=Хатои чоп
+Name[th]=à¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œà¸œà¸´à¸”พลาด
+Name[tr]=Yazdırma hatası
+Name[tt]=Bastıru xatası
+Name[uk]=Помилка друку
+Name[uz]=Bosib chiqarish xatosi
+Name[uz@cyrillic]=БоÑиб чиқариш хатоÑи
+Name[ven]=Vhukhakhi hau phirintha
+Name[vi]=Lá»—i in
+Name[wa]=Aroke d' imprimaedje
+Name[xh]=Imposiso yoshicilelo
+Name[zh_CN]=打å°é”™è¯¯
+Name[zh_HK]=列å°éŒ¯èª¤
+Name[zh_TW]=列å°éŒ¯èª¤
+Name[zu]=Iphutha lokushicelela
+Comment=A print error has occurred
+Comment[af]='n Druk fout het voorgekom
+Comment[ar]=حدث خطأ ÙÙŠ الطباعة
+Comment[az]=Çap xətası baş verdi
+Comment[be]=ÐдбылаÑÑ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ° друку
+Comment[bg]=Грешка при печат
+Comment[bn]=ছাপানোয় সমসà§à¦¯à¦¾ দেখা দিয়েছে
+Comment[br]=Degouezhet ez eus ar fazi gant ar voullerez
+Comment[bs]=Došlo je do greške pri štampanju
+Comment[ca]=Hi ha hagut un error d'impressió
+Comment[cs]=Došlo k chybě tisku
+Comment[csb]=Wëskrzëniwô sã fela drëkù
+Comment[cy]=Mae gwall argraffu wedi digwydd
+Comment[da]=Der opstod en udskriftsfejl
+Comment[de]=Beim Drucken ist ein Fehler aufgetreten
+Comment[el]=ΠÏοέκυψε ένα σφάλμα εκτÏπωσης
+Comment[eo]=Okazis preseraro
+Comment[es]=Se ha producido un error de impresión.
+Comment[et]=Viga trükkimisel
+Comment[eu]=Inprimatze-errorea gertatu da
+Comment[fa]=خطای چاپی رخ داده است
+Comment[fi]=Tapahtui tulostusvirhe
+Comment[fr]=Un problème d'impression est survenu
+Comment[fy]=In printflater had him foardyn
+Comment[ga]=Tharla earráid phriontála
+Comment[gl]=Ocorreu un erro de impresión
+Comment[he]=×ירעה שגי×ת הדפסה
+Comment[hi]=छापने में à¤à¤• तà¥à¤°à¥à¤Ÿà¤¿ हà¥à¤ˆ
+Comment[hr]=Tijekom ispisivanje došlo je do pogreške
+Comment[hsb]=Zmylk je so stał při ćišćenju
+Comment[hu]=Hiba történt nyomtatás közben
+Comment[id]=Telah terjadi kesalahan pencetakan
+Comment[is]=Prentunarvilla átti sér stað
+Comment[it]=Si è verificato un errore di stampa
+Comment[ja]=å°åˆ·ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ
+Comment[ka]=ბეჭდვის შეცდáƒáƒ›áƒ
+Comment[kk]=БаÑып шығару кезде қате пайда болды
+Comment[km]=កំហុស​បោះពុម្ព​មួយ​បាន​កើážáž¡áž¾áž„
+Comment[ko]=ì¸ì‡„ 오류가 ìƒê²¼ìŠµë‹ˆë‹¤
+Comment[lb]=En Dréckfeeler ass opgetrueden
+Comment[lt]=Įvyko spausdinimo klaida
+Comment[lv]=Notikusi drukas kļūda
+Comment[mk]=Се Ñлучи грешка при печатење
+Comment[mn]=Ð¥ÑвлÑÑ…Ñд алдаа гарлаа
+Comment[ms]=Ralat cetak berlaku
+Comment[nb]=En skriverfeil har oppstått
+Comment[nds]=Bi't Drucken hett dat en Fehler geven
+Comment[ne]=मà¥à¤¦à¥à¤°à¤£ तà¥à¤°à¥à¤Ÿà¤¿ देखापरà¥à¤¯à¥‹
+Comment[nl]=Er deed zich een afdrukfout voor
+Comment[nn]=Feil ved utskrift
+Comment[pa]=ਇੱਕ ਪà©à¨°à¨¿à©°à¨Ÿà¨° ਗਲਤੀ ਹੈ
+Comment[pl]=Wystąpił błąd drukowania
+Comment[pt]=Ocorreu um erro de impressão
+Comment[pt_BR]=Ocorreu um erro de impressão
+Comment[ro]=A apărut o eroare la tipărire
+Comment[ru]=Ошибка при печати
+Comment[rw]=Ikosa ryo gucapa ryagaragaye
+Comment[se]=Čálihanmeattáhus dáhpáhuvai
+Comment[sk]=Nastala chyba tlaÄe
+Comment[sl]=Nastala je napaka pri tiskanju
+Comment[sq]=Ka ndodhur një gabim shtypi
+Comment[sr]=Догодила Ñе грешка током штампања
+Comment[sr@Latn]=Dogodila se greška tokom štampanja
+Comment[sv]=Utskriftsfel har inträffat
+Comment[ta]=அசà¯à®šà¯à®¤à¯ தவறொனà¯à®±à¯ நேரà¯à®¨à¯à®¤à®¿à®°à¯à®•à¯à®•à®¿à®±à®¤à¯
+Comment[te]=à°’à°• à°ªà±à°°à°šà±à°°à°£ దొషం వచà±à°šà°¿à°‚ది
+Comment[tg]=Хатои чопкунӣ пайдо шуд
+Comment[th]=เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œ
+Comment[tr]=Bir yazdırma hatası oluştu
+Comment[tt]=Bastıru xatası bulıp çıqtı
+Comment[uk]=Виникла помилка друку
+Comment[uz]=Bosib chiqarish xatosi roʻy berdi
+Comment[uz@cyrillic]=БоÑиб чиқариш хатоÑи рўй берди
+Comment[vi]=Gặp lỗi in
+Comment[wa]=Åk n' a nén stî tot-z imprimant
+Comment[zh_CN]=å‘生了打å°é”™è¯¯
+Comment[zh_HK]=列å°æ™‚發生錯誤
+Comment[zh_TW]=列å°æ™‚發生錯誤
+default_presentation=2
+level=8
+
+[messageInformation]
+Name=Information message
+Name[af]=Inligting boodskap
+Name[ar]=رسالة المعلومات
+Name[az]=Mə'lumat ismarışı
+Name[be]=Інфармацыйнае паведамленне
+Name[bg]=ИнформациÑ
+Name[bn]=তথà§à¦¯à¦¬à¦¾à¦°à§à¦¤à¦¾
+Name[br]=Kemennad a titouroù
+Name[bs]=Informativna poruka
+Name[ca]=Missatge informatiu
+Name[cs]=InformaÄní zpráva
+Name[csb]=Wëdowiédny kòmùnikat
+Name[cy]=Neges gwybodaeth
+Name[da]=Informationsbesked
+Name[de]=Information
+Name[el]=Μήνυμα πληÏοφοÏίας
+Name[eo]=Informa mesaÄo
+Name[es]=Mensaje de información
+Name[et]=Informatiivne teade
+Name[eu]=Informazioaren mezua
+Name[fa]=پیام اطلاعاتی
+Name[fi]=Tiedoitusviesti
+Name[fr]=Message d'information
+Name[fy]=Ynformaasje berjocht
+Name[ga]=Teachtaireacht Eolais
+Name[gl]=Mensaxe de información
+Name[he]=הודעת מידע
+Name[hi]=सूचनातà¥à¤®à¤• संदेश
+Name[hr]=Poruka s podacima
+Name[hsb]=Informaciska zdźělenka
+Name[hu]=Tájékoztató üzenet
+Name[id]=Pesan informasi
+Name[is]=Til fróðleiks
+Name[it]=Messaggio informativo
+Name[ja]=情報メッセージ
+Name[ka]=სáƒáƒ˜áƒœáƒ¤áƒáƒ áƒ›áƒáƒªáƒ˜áƒ შეტყáƒáƒ‘ინებáƒ
+Name[kk]=Ðқпараттық хабар
+Name[km]=សារ​ដំណឹង
+Name[ko]=정보 메세지
+Name[lb]=Informatioun
+Name[lt]=Informacinis pranešimas
+Name[lv]=Informatīvs paziņojums
+Name[mk]=Информативна порака
+Name[mn]=ÐœÑдÑÑллийн мÑдÑÑ
+Name[ms]=Mesej maklumat
+Name[nb]=Informasjonsmelding
+Name[nds]=Informatschoon
+Name[ne]=सूचना सनà¥à¤¦à¥‡à¤¶
+Name[nl]=Informatiebericht
+Name[nn]=Informasjonsmelding
+Name[pa]=ਜਾਣਕਾਰੀ ਸà©à¨¨à©‡à¨¹à©‡
+Name[pl]=Komunikat informacyjny
+Name[pt]=Mensagem de informação
+Name[pt_BR]=Mensagem de informações
+Name[ro]=Mesaj informaţional
+Name[ru]=Информационное Ñообщение
+Name[rw]=Ubutumwa bwo kumenyesha
+Name[se]=Diehtu
+Name[sk]=Informácia
+Name[sl]=Informativno sporoÄilo
+Name[sq]=Porosi informimi
+Name[sr]=Информациона порука
+Name[sr@Latn]=Informaciona poruka
+Name[sv]=Informationsmeddelande
+Name[ta]=தகவல௠செயà¯à®¤à®¿
+Name[te]=సమాచార సందేశం
+Name[tg]=Хабари иттилоотӣ
+Name[th]=ข้อความà¹à¸ˆà¹‰à¸‡à¸‚้อมูล
+Name[tr]=Bilgi mesajı
+Name[tt]=Belderü xäbäre
+Name[uk]=Інформаційне повідомленнÑ
+Name[uz]=Maʼlumot xabari
+Name[uz@cyrillic]=Маълумот хабари
+Name[vi]=Thông điệp thông tin
+Name[wa]=Messaedje d' informåcion
+Name[zh_CN]=ä¿¡æ¯æ€§æ¶ˆæ¯
+Name[zh_HK]=一般訊æ¯
+Name[zh_TW]=資訊訊æ¯
+Comment=An information message is being shown
+Comment[af]='n Informasie boodskap word vertoon
+Comment[ar]=تظهر الآن رسالة معلوماتية
+Comment[az]=Mə'lumat ismarışı göstərilir
+Comment[be]=Паказана інфармацыйнае паведамленне
+Comment[bg]=Показване на уведомително Ñъобщение (ИнформациÑ)
+Comment[bn]=à¦à¦•à¦Ÿà¦¿ তথà§à¦¯à¦¬à¦¾à¦°à§à¦¤à¦¾ পà§à¦°à¦¦à¦°à§à¦¶à¦¿à¦¤ হচà§à¦›à§‡
+Comment[bs]=Prikazana je informativna poruka
+Comment[ca]=Mostrarà un missatge informatiu
+Comment[cs]=InformaÄní zpráva je zobrazena
+Comment[csb]=Wëskrzëniwô sã wëdowiédny kòmùnikat
+Comment[cy]=Dangosir neges gwybodaeth
+Comment[da]=En informationsbesked er ved at blive vist
+Comment[de]=Anzeige einer Info-Nachricht
+Comment[el]=Ένα μήνυμα πληÏοφοÏίας εμφανίζεται
+Comment[eo]=Informa mesaÄo estas montrata
+Comment[es]=Se está mostrando un mensaje de información
+Comment[et]=Näidatakse informatiivset teadet
+Comment[eu]=Informazioren mezua erakusten ari da
+Comment[fa]=پیام اطلاعاتی نمایش داده می‌شود
+Comment[fi]=Näytetään tiedotusviesti
+Comment[fr]=Un message d'information est affiché actuellement
+Comment[fy]=In ynformaasje berjocht lit him sjen
+Comment[ga]=Tá teachtaireacht eolais á taispeáint
+Comment[gl]=Está-se a mostrar unha mensaxe de información
+Comment[he]=מוצגת הדעת מידע
+Comment[hi]=à¤à¤• जानकारी परक सूचना दिखाई जा रही है
+Comment[hr]=Prikazana je poruka s podacima
+Comment[hsb]=Informaciska zdźělenka so pokazuje
+Comment[hu]=Tájékoztató üzenet látszik
+Comment[id]=Pesan informasi sedang ditampilkan
+Comment[is]=Skilaboð notandanum til fróðleiks
+Comment[it]=Viene mostrato un messaggio informativo
+Comment[ja]=情報メッセージを表示ã—ã¾ã™
+Comment[ka]=სáƒáƒ˜áƒœáƒ¤áƒáƒ áƒ›áƒáƒªáƒ˜áƒ შეტყáƒáƒ‘ინების ჩვენებáƒ
+Comment[kk]=Ðқпараттық хабар көрÑетілуде
+Comment[km]=កំពុង​បង្ហាញ​សារ​ដំណឹង​មួយ
+Comment[ko]=정보 메세지가 보입니다
+Comment[lb]=Eng Informatiounsnoricht gëtt ugewisen
+Comment[lt]=Rodomas informacinis pranešimas
+Comment[lv]=Tiek rÄdÄ«ts informatÄ«vs paziņojums
+Comment[mk]=Прикажана е информативна порака
+Comment[mn]=Харуулж байхад мÑдÑÑллийн мÑдÑÑ
+Comment[ms]=Mesej yang dipaparkan
+Comment[nb]=En informasjonsmelding blir vist
+Comment[nds]=En Informatschoon warrt wiest
+Comment[ne]=सूचना सनà¥à¤¦à¥‡à¤¶ देखिरहेको छ
+Comment[nl]=Er wordt een informatiebericht getoond
+Comment[nn]=Ei informasjonsmelding vert vist
+Comment[pa]=ਇੱਕ ਜਾਣਕਾਰੀ ਸà©à¨¨à©‡à¨¹à¨¾ ਹੇਠਾਂ ਵੇਖਿਆ ਗਿਆ ਹੈ
+Comment[pl]=Pokazywany jest komunikat informacyjny
+Comment[pt]=Está a ser mostrada uma mensagem informativa
+Comment[pt_BR]=Uma mensagem de informação está sendo mostrada
+Comment[ro]=A fost afişat un mesaj informaţional
+Comment[ru]=Вывод информационного ÑообщениÑ
+Comment[rw]=Ubutumwa bwo kumenyesha bwerekanwe
+Comment[se]=Diehtu Äájehuvvo
+Comment[sk]=Je zobrazená informácia
+Comment[sl]=Prikazano je informativno sporoÄilo
+Comment[sq]=Një porosi informimi është paraqitur
+Comment[sr]=Приказана је информативна порука
+Comment[sr@Latn]=Prikazana je informativna poruka
+Comment[sv]=Informationsmeddelande visas
+Comment[ta]=ஒர௠தகவல௠செயà¯à®¤à®¿ காணà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯
+Comment[te]=à°’à°• సమాచార సందేశం చూపించబడà±à°¤à±à°‚ది
+Comment[tg]=Хабари иттилоотӣ нишон дода иÑтодааÑÑ‚
+Comment[th]=à¸à¸³à¸¥à¸±à¸‡à¹à¸ªà¸”งข้อความà¹à¸ˆà¹‰à¸‡à¸‚้อมูล
+Comment[tr]=Bir bilgi mesajı gösterildi
+Comment[tt]=Belderü xäbäre kürsätelä
+Comment[uk]=ПоказуєтьÑÑ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ð²Ð½Ðµ повідомленнÑ
+Comment[uz]=Maʼlumot xabari koʻrsatildi
+Comment[uz@cyrillic]=Маълумот хабари кўрÑатилди
+Comment[vi]=Một thông điệp thông in đang được hiển thị.
+Comment[wa]=On messaedje d' informåcion est håyné
+Comment[zh_CN]=正在显示信æ¯æ€§æ¶ˆæ¯
+Comment[zh_HK]=顯示一般訊æ¯
+Comment[zh_TW]=資訊訊æ¯å·²é¡¯ç¤º
+default_sound=KDE_Chimes_2.ogg
+default_presentation=65
+nopresentation=18
+
+[messageWarning]
+Name=Warning message
+Name[af]=Waarskuwing boodskap
+Name[ar]=رسالة تحذيرية
+Name[az]=Xəbərdarlıq ismarışı
+Name[be]=ПапÑÑ€Ñджанне
+Name[bg]=Предупреждение
+Name[bn]=সতরà§à¦•à¦¬à¦¾à¦°à§à¦¤à¦¾
+Name[bs]=Poruka upozorenja
+Name[ca]=Missatge d'avís
+Name[cs]=Varovná zpráva
+Name[csb]=Òstrzegawczi kòmùnikat
+Name[cy]=Neges rhybudd
+Name[da]=Advarselsbesked
+Name[de]=Warnung
+Name[el]=Μήνυμα Ï€Ïοειδοποίησης
+Name[eo]=Averta mesaÄo
+Name[es]=Mensaje de aviso
+Name[et]=Hoiatav teade
+Name[eu]=Abisuaren mezua
+Name[fa]=پیام اخطار
+Name[fi]=Varoitusviesti
+Name[fr]=Message d'avertissement
+Name[fy]=Warskôgings berjocht
+Name[ga]=Teachtaireacht Rabhaidh
+Name[gl]=Mensaxe de aviso
+Name[he]=הודעת הזהרה
+Name[hi]=चेतावनी संदेश
+Name[hr]=Poruka upozorenja
+Name[hsb]=Warnowanska zdźělenka
+Name[hu]=Figyelmeztető üzenet
+Name[id]=Pesan peringatan
+Name[is]=Aðvörun
+Name[it]=Messaggio di avvertimento
+Name[ja]=警告メッセージ
+Name[ka]=გáƒáƒ¤áƒ áƒ—ხილებáƒ
+Name[kk]=ЕÑкерту хабары
+Name[km]=សារ​ព្រមាន
+Name[ko]=경고 메세지
+Name[lb]=Warnung
+Name[lt]=Perspėjantis pranešimas
+Name[lv]=BrÄ«dinÄjums
+Name[mk]=Предупредувачка порака
+Name[mn]=Сануулга мÑдÑÑ
+Name[ms]=Mesej amaran
+Name[nb]=Varselmelding
+Name[nds]=Wohrschoen
+Name[ne]=चेतावनी सनà¥à¤¦à¥‡à¤¶
+Name[nl]=Waarschuwingsbericht
+Name[nn]=Varselmelding
+Name[pa]=ਚੇਤਾਵਨੀ ਸà©à¨¨à©‡à¨¹à¨¾
+Name[pl]=Komunikat ostrzegawczy
+Name[pt]=Mensagem de aviso
+Name[pt_BR]=Mensagem de Aviso
+Name[ro]=Mesaj de avertizare
+Name[ru]=Предупреждение
+Name[rw]=Ubutumwa bw'iburira
+Name[se]=Váruhus
+Name[sk]=Varovanie
+Name[sl]=Opozorilno sporoÄilo
+Name[sq]=Porosi vërejtjeje
+Name[sr]=Упозоравајућа порука
+Name[sr@Latn]=Upozoravajuća poruka
+Name[sv]=Varningsmeddelande
+Name[ta]=எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆà®šà¯ செயà¯à®¤à®¿
+Name[te]=హెచà±à°šà°°à°¿à°• సందేశం
+Name[tg]=Огоҳӣ
+Name[th]=ข้อความà¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™
+Name[tr]=Uyarı mesajı
+Name[tt]=Kisätü xäbäre
+Name[uk]=ПопередженнÑ
+Name[uz]=Ogohnoma xabari
+Name[uz@cyrillic]=Огоҳнома хабари
+Name[vi]=Thông điệp cảnh báo
+Name[wa]=Messaedje d' adviertixhmint
+Name[zh_CN]=警告消æ¯
+Name[zh_HK]=警告訊æ¯
+Name[zh_TW]=警告訊æ¯
+Comment=A warning message is being shown
+Comment[af]='n Waarskuwing boodskap word vertoon
+Comment[ar]=تظهر الآن رسالة تحذيرية
+Comment[az]=Xəbərdarlıq ismarışı göstərilir
+Comment[be]=Паказана папÑÑ€Ñджанне
+Comment[bg]=Показване на предупредително Ñъобщение (Предупреждение)
+Comment[bn]=à¦à¦•à¦Ÿà¦¿ সতরà§à¦•à¦¬à¦¾à¦°à§à¦¤à¦¾ পà§à¦°à¦¦à¦°à§à¦¶à¦¿à¦¤ হচà§à¦›à§‡
+Comment[bs]=Prikazana je poruka upozorenja
+Comment[ca]=Mostrarà un missatge d'avís
+Comment[cs]=Varovná zpráva je zobrazena
+Comment[csb]=Wëskrzëniwô sã òstrzegawczi kòmùnikat
+Comment[cy]=Dangosir neges rhybudd
+Comment[da]=En advarselsbesked er ved at blive vist
+Comment[de]=Anzeige einer Warnungs-Nachricht
+Comment[el]=Ένα μήνυμα Ï€Ïοειδοποίησης εμφανίζεται
+Comment[eo]=Averta mesaÄo estas montrata
+Comment[es]=Se está mostrando un mensaje de aviso
+Comment[et]=Näidatakse hoiatavat teadet
+Comment[eu]=Abisuaren mezua erakusten ari da
+Comment[fa]=پیام اخطار نمایش داده می‌شود
+Comment[fi]=Näytetään varoitusviesti
+Comment[fr]=Un message d'avertissement est affiché actuellement
+Comment[fy]=In warskôgings berjocht lit him sjen
+Comment[ga]=Tá teachtaireacht rabhaidh á taispeáint
+Comment[gl]=Está-se a mostrar unha mensaxe de aviso
+Comment[he]=מוצגת הדעת הזהרה
+Comment[hi]=à¤à¤• चेतावनी सूचना दिखाई जा रही है
+Comment[hr]=Prikazana je upozoravajuća poruka
+Comment[hsb]=Warnowanska zdźělenka so pokazuje
+Comment[hu]=Figyelmeztető üzenet látszik
+Comment[id]=Pesan peringatan sedang ditampilkan
+Comment[is]=Aðvörun til notanda
+Comment[it]=Viene mostrato un messaggio di avvertimento
+Comment[ja]=警告メッセージを表示ã—ã¾ã™
+Comment[ka]=გáƒáƒ¤áƒ áƒ—ხილების ჩვენებáƒ
+Comment[kk]=ЕÑкерту хабары көрÑтілуде
+Comment[km]=កំពុង​បង្ហាញ​សារ​ព្រមាន​មួយ
+Comment[ko]=경고 메세지가 보입니다
+Comment[lb]=Eng Warnungsnoricht gëtt ugewisen
+Comment[lt]=Rodomas perspėjantis pranešimas
+Comment[lv]=Tiek rÄdÄ«ts brÄ«dinÄjums
+Comment[mk]=Прикажана е предупредувачка порака
+Comment[mn]=Харуулж байхад Ñануулга
+Comment[ms]=Mesej amaran yang dipaparkan
+Comment[nb]=En varselmelding blir vist
+Comment[nds]=En Wohrschoen warrt wiest
+Comment[ne]=चेतावनी सनà¥à¤¦à¥‡à¤¶ देखिरहेको छ
+Comment[nl]=Er wordt een waarschuwingsbericht getoond
+Comment[nn]=Ei varselmelding vert vist
+Comment[pa]=ਇੱਕ ਚੇਤਾਵਨੀ ਸà©à¨¨à©‡à¨¹à¨¾ ਹੇਠਾਂ ਵੇਖਿਆ ਗਿਆ ਹੈ
+Comment[pl]=Pokazywany jest komunikat ostrzegawczy
+Comment[pt]=Está a ser mostrada uma mensagem de aviso
+Comment[pt_BR]=Uma mensagem de aviso está sendo mostrada
+Comment[ro]=A fost afiÅŸat un mesaj de avertizare
+Comment[ru]=Вывод предупреждениÑ
+Comment[rw]=Ubutumwa bw'iburira bwerekanwe
+Comment[se]=Váruhus Äájehuvvo
+Comment[sk]=Je zobrazené varovanie
+Comment[sl]=Prikazano je opozorilno sporoÄilo
+Comment[sq]=Një porosi vërejtjeje është paraqitur
+Comment[sr]=Приказана је упозоравајућа порука
+Comment[sr@Latn]=Prikazana je upozoravajuća poruka
+Comment[sv]=Varningsmeddelande visas
+Comment[ta]=ஒர௠எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆ செயà¯à®¤à®¿ காணà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯
+Comment[te]=à°’à°• హెచà±à°šà°°à°¿à°• సందేశం చూపించబడà±à°¤à±à°‚ది
+Comment[tg]=Хурӯҷи огоҳӣ
+Comment[th]=à¸à¸³à¸¥à¸±à¸‡à¹à¸ªà¸”งข้อความà¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™
+Comment[tr]=Bir uyarı mesajı gösterildi
+Comment[tt]=Kisätü xäbäre kürsätelä
+Comment[uk]=ПоказуєтьÑÑ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· попередженнÑм
+Comment[uz]=Ogohnoma xabari koʻrsatildi
+Comment[uz@cyrillic]=Огоҳнома хабари кўрÑатилди
+Comment[vi]=Một thông điệp cảnh báo đang được hiển thị.
+Comment[wa]=On messaedje d' adviertixhmint est håyné
+Comment[zh_CN]=正在显示警告消æ¯
+Comment[zh_HK]=顯示警告訊æ¯
+Comment[zh_TW]=警告訊æ¯å·²é¡¯ç¤º
+default_sound=KDE_Error_1.ogg
+default_presentation=65
+nopresentation=18
+level=2
+
+[messageCritical]
+Name=Critical message
+Name[af]=Kritiese boodskap
+Name[ar]=رسالة هامَة
+Name[az]=Kritik ismarış
+Name[be]=Важнае паведамленне
+Name[bg]=Грешка
+Name[bn]=গà§à¦°à§à¦¤à§à¦¬à¦ªà§‚রà§à¦£ বারà§à¦¤à¦¾
+Name[bs]=KritiÄna poruka
+Name[ca]=Missatge crític
+Name[cs]=Kritická zpráva
+Name[csb]=Kòmunikat kriticzny felë
+Name[cy]=Neges critigol
+Name[da]=Kritisk besked
+Name[de]=Kritisches Ereignis
+Name[el]=ΚÏίσιμο μήνυμα
+Name[eo]=Averta mesaÄo
+Name[es]=Mensaje crítico
+Name[et]=Kriitiline teade
+Name[eu]=Mezu kritikoa
+Name[fa]=پیام بحرانی
+Name[fi]=Kriittinen viesti
+Name[fr]=Message critique
+Name[fy]=krityk berjocht
+Name[ga]=Teachtaireaacht chriticiúil
+Name[gl]=Mensaxe crítica
+Name[he]=הודעה קריטית
+Name[hi]=महतà¥à¤µà¤ªà¥‚रà¥à¤£ संदेश
+Name[hr]=KritiÄna poruka
+Name[hsb]=Kritiska zdźělenka
+Name[hu]=Kritikus hibaüzenet
+Name[id]=Pesan kritis
+Name[is]=Alvarleg aðvörun
+Name[it]=Messaggio critico
+Name[ja]=クリティカルメッセージ
+Name[ka]=კრიტიკული შეცდáƒáƒ›áƒ
+Name[kk]=ДағдарыÑÑ‚Ñ‹ хабар
+Name[km]=សារ​សំážáž¶áž“់
+Name[ko]=중요 메세지
+Name[lb]=Kritesch Noricht
+Name[lt]=Kritinis pranešimas
+Name[lv]=Kritisks paziņojums
+Name[mk]=Критична порака
+Name[mn]=ШүүмжлÑлт мÑдÑÑ
+Name[ms]=Mesej Kritikal
+Name[nb]=Kritisk melding
+Name[nds]=Malöör
+Name[ne]=आलोचनातà¥à¤®à¤• सनà¥à¤¦à¥‡à¤¶
+Name[nl]=Kritiek bericht
+Name[nn]=Kritisk melding
+Name[pa]=ਘਾਤਕ ਸà©à¨¨à©‡à¨¹à¨¾
+Name[pl]=Komunikat błędu krytycznego
+Name[pt]=Mensagem crítica
+Name[pt_BR]=Mensagem Crítica
+Name[ro]=Mesaj situaţie critică
+Name[ru]=КритичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°
+Name[rw]=Ubutumwa bunenga
+Name[sk]=Kritická správa
+Name[sl]=KritiÄno sporoÄilo
+Name[sq]=Porosi Kritik
+Name[sr]=Критична порука
+Name[sr@Latn]=KritiÄna poruka
+Name[sv]=Kritiskt meddelande
+Name[ta]=இகà¯à®•à®Ÿà¯à®Ÿà®¾à®© செயà¯à®¤à®¿
+Name[te]=కీలక సందేశం
+Name[tg]=Хатои хатарнок
+Name[th]=ข้อความวิà¸à¸¤à¸•à¸´
+Name[tr]=Kritik hata mesajı
+Name[tt]=Kisken xäl xäbäre
+Name[uk]=Критична помилка
+Name[uz]=Muammo xabari
+Name[uz@cyrillic]=Муаммо хабари
+Name[vi]=Thông điệp tới hạn
+Name[wa]=Messaedje critike
+Name[zh_CN]=关键消æ¯
+Name[zh_HK]=åš´é‡è­¦å‘Šè¨Šæ¯
+Name[zh_TW]=åš´é‡è­¦å‘Šè¨Šæ¯
+Comment=A critical message is being shown
+Comment[af]='n Kritiese boodskap word vertoon
+Comment[ar]=تظهر الآن رسالة مهمَة
+Comment[az]=Kritik ismarış göstərilir
+Comment[be]=Паказана важнае паведамленне
+Comment[bg]=Показване на Ñъобщение за грешка (Грешка)
+Comment[bn]=à¦à¦•à¦Ÿà¦¿ গà§à¦°à§à¦¤à¦° বারà§à¦¤à¦¾ পà§à¦°à¦¦à¦°à§à¦¶à¦¿à¦¤ হচà§à¦›à§‡
+Comment[bs]=Prikazana je kritiÄna poruka
+Comment[ca]=Mostrarà un missatge crític
+Comment[cs]=Kritická zpráva je zobrazena
+Comment[csb]=Wëskrzëniwô sã kòmunikat kriticzny felë
+Comment[cy]=Dangosir neges critigol
+Comment[da]=En kritisk besked er ved at blive vist
+Comment[de]=Anzeige einer Nachricht zu einem kritischen Ereignis
+Comment[el]=Ένα κÏίσιμο μήνυμα εμφανίζεται
+Comment[eo]=Gravega mesaÄo estas montrata
+Comment[es]=Se está mostrando un mensaje crítico
+Comment[et]=Näidatakse kriitilist teadet
+Comment[eu]=Mezu kritikoa erakusten ari da
+Comment[fa]=پیام بحرانی نمایش داده می‌شود
+Comment[fi]=Näytetään kriittinen viesti
+Comment[fr]=Un message critique est affiché actuellement
+Comment[fy]=In krityk berjocht let him sjen
+Comment[ga]=Tá teachtaireacht chriticiúil á taispeáint
+Comment[gl]=Está-se a mostrar unha mensaxe crítica
+Comment[he]=מוצגת הודעה קריטית
+Comment[hi]=à¤à¤• महतà¥à¤µà¤ªà¥‚रà¥à¤£ सूचना दिखाई जा रही है
+Comment[hr]=Prikazana je kritiÄna poruka
+Comment[hsb]=Kritiska zdźělenka so pokazuje
+Comment[hu]=Kritikus hibaüzenet látszik
+Comment[id]=Pesan kritis sedang ditampilkan
+Comment[is]=Alvarleg skilaboð
+Comment[it]=Viene mostrato un messaggio critico
+Comment[ja]=クリティカルメッセージを表示ã—ã¾ã™
+Comment[ka]=კრიტიკული შეცდáƒáƒ›áƒ˜áƒ¡ ჩვენებáƒ
+Comment[kk]=ДағдарыÑÑ‚Ñ‹ хабар көрÑетілуде
+Comment[km]=កំពុង​បង្ហាញ​សារ​សំážáž¶áž“់​មួយ
+Comment[ko]=중요 메세지가 보입니다
+Comment[lb]=Eng kritesch Noricht gëtt ugewisen
+Comment[lt]=Rodomas kritinis pranešimas
+Comment[lv]=Tiek rÄdÄ«ts kritisks paziņojums
+Comment[mk]=Прикажана е критична порака
+Comment[mn]=Харуулж байхад шүүмжилÑлт Ñануулга
+Comment[ms]=Mesej kritikal yang dipaparkan
+Comment[nb]=En kritisk melding blir vist
+Comment[nds]=En kritische Naricht warrt wiest
+Comment[ne]=आलोचनातà¥à¤®à¤• सनà¥à¤¦à¥‡à¤¶ देखिरहेको छ
+Comment[nl]=Er wordt een kritiek bericht getoond
+Comment[nn]=Ei kritisk melding vert vist
+Comment[pa]=ਇੱਕ ਘਾਤਕ ਸà©à¨¨à©‡à¨¹à¨¾ ਹੇਠਾਂ ਵੇਖਿਆ ਗਿਆ ਹੈ
+Comment[pl]=Pokazywany jest komunikat o błędzie krytycznym
+Comment[pt]=Está a ser mostrada uma mensagem crítica
+Comment[pt_BR]=Uma mensagem crítica está sendo mostrada
+Comment[ro]=A fost afişat un mesaj de situaţie critică
+Comment[ru]=Вывод критичеÑкого ÑообщениÑ
+Comment[rw]=Ubutumwa bunenga bwerekanwe
+Comment[sk]=Je zobrazená kritická správa
+Comment[sl]=Prikazano je kritiÄno sporoÄilo
+Comment[sq]=Një porosi kritike është paraqitur
+Comment[sr]=Приказана је критична порука
+Comment[sr@Latn]=Prikazana je kritiÄna poruka
+Comment[sv]=Kritiskt meddelande visas
+Comment[ta]=ஒர௠மாறà¯à®¨à®¿à®²à¯ˆà®¯à®¾à®© செயà¯à®¤à®¿ காணà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯
+Comment[te]=à°’à°• కీలక సందేశం చూపించబడà±à°¤à±à°‚ది
+Comment[tg]=Хурӯҷи иттилоъи хатарнок
+Comment[th]=à¸à¸³à¸¥à¸±à¸‡à¹à¸ªà¸”งข้อความวิà¸à¸¤à¸•à¸´
+Comment[tr]=Bir kritik mesaj gösterildi
+Comment[tt]=Kisken xäl xäbäre kürsätelä
+Comment[uk]=ПоказуєтьÑÑ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ критичну помилку
+Comment[uz]=Muammo xabari koʻrsatildi
+Comment[uz@cyrillic]=Муаммо хабари кўрÑатилди
+Comment[vi]=Má»™t thông Ä‘iệp vá» trÆ°á»ng hợp tá»›i hạn Ä‘ang được hiển thị.
+Comment[wa]=On messaedje critike est håyné
+Comment[zh_CN]=正在显示关键消æ¯
+Comment[zh_HK]=顯示嚴é‡è­¦å‘Šè¨Šæ¯
+Comment[zh_TW]=åš´é‡çš„警告訊æ¯å·²é¡¯ç¤º
+default_sound=KDE_Glass_Break.ogg
+default_presentation=65
+nopresentation=18
+level=4
+
+[messageboxQuestion]
+Name=Question
+Name[af]=Vraag
+Name[ar]=سؤال
+Name[az]=Sual
+Name[be]=Запыт
+Name[bg]=ВъпроÑ
+Name[bn]=পà§à¦°à¦¶à§à¦¨
+Name[br]=Goulenn
+Name[bs]=Pitanje
+Name[ca]=Pregunta
+Name[cs]=Dotaz
+Name[csb]=Pëtanié
+Name[cy]=Cwestiwn
+Name[da]=Spørgsmål
+Name[de]=Frage
+Name[el]=ΕÏώτηση
+Name[eo]=Demando
+Name[es]=Pregunta
+Name[et]=Küsimus
+Name[eu]=Galdera
+Name[fa]=سؤال
+Name[fi]=Kysymys
+Name[fy]=Fraach
+Name[ga]=Ceist
+Name[gl]=Pergunta
+Name[he]=ש×לה
+Name[hi]=पà¥à¤°à¤¶à¥à¤¨
+Name[hr]=Pitanje
+Name[hsb]=Prašenje
+Name[hu]=Kérdés
+Name[id]=Pertanyaan
+Name[is]=Spurning
+Name[it]=Domanda
+Name[ja]=質å•
+Name[ka]=შეკითხვáƒ
+Name[kk]=Сұрақ
+Name[km]=សំណួរ
+Name[ko]=물ìŒ
+Name[ku]=Pirs
+Name[lb]=Fro
+Name[lt]=Klausimas
+Name[lv]=JautÄjums
+Name[mk]=Прашање
+Name[mn]=ÐÑуулт
+Name[ms]=Soalan
+Name[nb]=Spørsmål
+Name[nds]=Fraag
+Name[ne]=पà¥à¤°à¤¶à¥à¤¨
+Name[nl]=Vraag
+Name[nn]=Spørsmål
+Name[pa]=ਸਵਾਲ
+Name[pl]=Komunikat z pytaniem
+Name[pt]=Pergunta
+Name[pt_BR]=Questão
+Name[ro]=ÃŽntrebare
+Name[ru]=ВопроÑ
+Name[rw]=Ikibazo
+Name[se]=Gažaldat
+Name[sk]=Otázka
+Name[sl]=Vprašanje
+Name[sq]=Pyetje
+Name[sr]=Питање
+Name[sr@Latn]=Pitanje
+Name[sv]=Fråga
+Name[ta]=கேளà¯à®µà®¿
+Name[te]=à°ªà±à°°à°¶à±à°¨
+Name[tg]=Савол
+Name[th]=คำถาม
+Name[tr]=Soru
+Name[tt]=Soraw
+Name[uk]=ЗапитаннÑ
+Name[uz]=Savol
+Name[uz@cyrillic]=Савол
+Name[vi]=Câu há»i
+Name[wa]=Kesse
+Name[zh_CN]=问题
+Name[zh_HK]=æå•
+Name[zh_TW]=å•é¡Œ
+Comment=A question is being asked
+Comment[af]='n Vraag word gevra
+Comment[ar]=هناك سؤال يتم سؤاله
+Comment[az]=Sual ismarışı göstərilir
+Comment[be]=Зададзена пытанне
+Comment[bg]=Показване на въпроÑително Ñъобщение (ВъпроÑ)
+Comment[bn]=à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¶à§à¦¨ করা হচà§à¦›à§‡
+Comment[br]=Emañ o c'houlleniñ ur goulenn
+Comment[bs]=Postavljeno je pitanje
+Comment[ca]=Farà una pregunta
+Comment[cs]=Je položena otázka
+Comment[csb]=Zadóné je pëtanié
+Comment[cy]=Gofynnir cwestiwn
+Comment[da]=Et spørgsmål er ved at blive stillet
+Comment[de]=Anzeige einer Frage
+Comment[el]=Γίνεται μια εÏώτηση
+Comment[eo]=Demando estas demandata
+Comment[es]=Se está haciendo una pregunta
+Comment[et]=Esitatakse küsimus
+Comment[eu]=Galdera egiten ari da
+Comment[fa]=سؤالی پرسیده می‌شود
+Comment[fi]=Kysytään kysymys
+Comment[fr]=Une question est posée actuellement
+Comment[fy]=In fraach is stelt
+Comment[ga]=Tá ceist á cur.
+Comment[gl]=Está-se a facer unha pergunta
+Comment[he]=נש×לת ש×לה
+Comment[hi]=à¤à¤• पà¥à¤°à¤¶à¥à¤¨ पूछा गया है
+Comment[hr]=Postavljeno je pitanje
+Comment[hsb]=PraÅ¡a so za nÄ›Äim
+Comment[hu]=Kérdés a felhasználóhoz
+Comment[id]=Pertanyaan sedang diajukan
+Comment[is]=Spurt er
+Comment[it]=Viene posta una domanda
+Comment[ja]=質å•ãŒå‡ºã•ã‚Œã¦ã„ã¾ã™
+Comment[ka]=შეკითხვის დáƒáƒ¡áƒ›áƒ
+Comment[kk]=Сұрақ койылуда
+Comment[km]=កំពុង​សួរ​សំណួរ​មួយ
+Comment[ko]=물어보겠습니다
+Comment[lb]=Eng Fro gëtt ugewisen
+Comment[lt]=Užduodamas klausimas
+Comment[lv]=Tiek uzdots jautÄjums
+Comment[mk]=ПоÑтавено е прашање
+Comment[mn]=ÐÑуулт тавигдаж байна
+Comment[ms]=Soalan yang ditanya
+Comment[nb]=Et spørsmål blir stillt
+Comment[nds]=En Fraag warrt stellt
+Comment[ne]=पà¥à¤°à¤¶à¥à¤¨ सोधिराखेको छ
+Comment[nl]=Er wordt een vraag gesteld
+Comment[nn]=Eit spørsmål vert spurd
+Comment[pa]=ਇੱਕ ਸਵਾਲ ਪà©à¨›à¨¿à¨† ਜਾ ਰਿਹਾ ਹੈ
+Comment[pl]=Zadawane jest pytanie
+Comment[pt]=Está´a ser feita uma pergunta
+Comment[pt_BR]=Uma pergunta está sendo feita
+Comment[ro]=A fost pusă o întrebare
+Comment[ru]=Вывод вопроÑа
+Comment[rw]=Ikibazo cyabajijwe
+Comment[se]=Gažaldat jearahuvvo
+Comment[sk]=Je zobrazená otázka
+Comment[sl]=Postavljeno je vprašanje
+Comment[sq]=Një pyetje është duke u pyetur
+Comment[sr]=ПоÑтављено је питање
+Comment[sr@Latn]=Postavljeno je pitanje
+Comment[sv]=Fråga ställs
+Comment[ta]=ஒர௠கேளà¯à®µà®¿ கேடà¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯
+Comment[te]=à°ªà±à°°à°¶à±à°¨ అడగబడà±à°¤à±à°¨à±à°¨à°¦à°¿
+Comment[tg]=Ҷавоби Ñавол
+Comment[th]=à¸à¸³à¸¥à¸±à¸‡à¸–ามคำถาม
+Comment[tr]=Bir soru soruldu
+Comment[tt]=Ber soraw birelde
+Comment[uk]=ПоказуєтьÑÑ Ð·Ð°Ð¿Ð¸Ñ‚Ð°Ð½Ð½Ñ
+Comment[uz]=Savol berildi
+Comment[uz@cyrillic]=Савол берилди
+Comment[vi]=Má»™t câu Ä‘ang được há»i.
+Comment[wa]=Ene kesse est dmandêye
+Comment[zh_CN]=正在æé—®
+Comment[zh_HK]=顯示æå•è¨Šæ¯
+Comment[zh_TW]=å•é¡Œè©¢å•ä¸­
+default_sound=KDE_Vox_Ahem.ogg
+default_presentation=65
+nopresentation=18
+
+
diff --git a/kdecore/fakes.c b/kdecore/fakes.c
new file mode 100644
index 000000000..481eb6880
--- /dev/null
+++ b/kdecore/fakes.c
@@ -0,0 +1,363 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2000 The KDE Project
+
+ unsetenv() taken from the GNU C Library.
+ Copyright (C) 1992,1995-1999,2000-2002 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kdelibs_export.h"
+
+#include <config.h>
+
+#ifdef _WIN32
+#include <kde_file_win.h>
+#define KDE_open kdewin32_open
+#define KDE_mkdir kdewin32_mkdir
+#else
+#define KDE_open open
+#define KDE_mkdir mkdir
+#endif
+
+#ifndef HAVE_SETENV
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+KDECORE_EXPORT int setenv(const char *name, const char *value, int overwrite) {
+ int i;
+ char * a;
+
+ if (!overwrite && getenv(name)) return 0;
+
+ i = strlen(name) + strlen(value) + 2;
+ a = (char*)malloc(i);
+ if (!a) return 1;
+
+ strcpy(a, name);
+ strcat(a, "=");
+ strcat(a, value);
+
+ return putenv(a);
+}
+#endif /* !HAVE_SETENV */
+
+#ifndef HAVE_UNSETENV
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifndef environ
+extern char ** environ;
+#endif
+
+KDECORE_EXPORT void unsetenv (name)
+ const char *name;
+{
+ size_t len;
+ char **ep;
+
+ if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+ {
+ errno = EINVAL;
+ return;
+ }
+
+ len = strlen (name);
+
+ ep = environ;
+ while (*ep != NULL)
+ if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
+ {
+ /* Found it. Remove this pointer by moving later ones back. */
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case NAME appears again. */
+ }
+ else
+ ++ep;
+
+}
+
+#endif /* !HAVE_UNSETENV */
+
+#ifndef HAVE_USLEEP
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef __cplusplus /* this is supposed to be a C source file but still.. */
+extern "C" {
+#endif
+
+void usleep(unsigned int usec) {
+ struct timeval _usleep_tv;
+ _usleep_tv.tv_sec = usec/1000000;
+ _usleep_tv.tv_usec = usec%1000000;
+ select(0,0,0,0,&_usleep_tv);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !HAVE_USLEEP */
+
+#ifndef HAVE_RANDOM
+long int random()
+{
+ return lrand48();
+}
+
+void srandom(unsigned int seed)
+{
+ srand48(seed);
+}
+#endif
+
+#ifndef HAVE_SETEUID
+int seteuid(uid_t euid)
+{
+ return setreuid(-1, euid); /* Well, if you have neither you are in trouble :) */
+}
+#endif
+
+#ifndef HAVE_MKSTEMPS
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+
+/* this is based on code taken from the GNU libc, distributed under the LGPL license */
+
+/* Generate a unique temporary file name from TEMPLATE.
+
+ TEMPLATE has the form:
+
+ <path>/ccXXXXXX<suffix>
+
+ SUFFIX_LEN tells us how long <suffix> is (it can be zero length).
+
+ The last six characters of TEMPLATE before <suffix> must be "XXXXXX";
+ they are replaced with a string that makes the filename unique.
+
+ Returns a file descriptor open on the file for reading and writing. */
+
+KDECORE_EXPORT int mkstemps (char* _template, int suffix_len)
+{
+ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ char *XXXXXX;
+ int len;
+ int count;
+ int value;
+
+ len = strlen (_template);
+
+ if ((int) len < 6 + suffix_len || strncmp (&_template[len - 6 - suffix_len], "XXXXXX", 6))
+ return -1;
+
+ XXXXXX = &_template[len - 6 - suffix_len];
+
+ value = rand();
+ for (count = 0; count < 256; ++count)
+ {
+ int v = value;
+ int fd;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ fd = KDE_open (_template, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (fd >= 0)
+ /* The file does not exist. */
+ return fd;
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
+ }
+ /* We return the null string if we can't find a unique file name. */
+ _template[0] = '\0';
+ return -1;
+}
+
+#endif /* !HAVE_MKSTEMPS */
+
+#ifndef HAVE_MKSTEMP
+KDECORE_EXPORT int mkstemp (char* _template)
+{
+ return mkstemps( _template, 0 );
+}
+#endif
+
+#ifndef HAVE_MKDTEMP
+
+#ifndef HAVE_MKSTEMPS
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#endif
+
+/* Generate a unique temporary directory name from TEMPLATE.
+
+ TEMPLATE has the form:
+
+ <path>/ccXXXXXX
+
+
+ The last six characters of TEMPLATE must be "XXXXXX";
+ they are replaced with a string that makes the filename unique.
+
+ Returns a file descriptor open on the file for reading and writing. */
+
+KDECORE_EXPORT char* mkdtemp (char* _template)
+{
+ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ char *XXXXXX;
+ int len;
+ int count;
+ int value;
+
+ len = strlen (_template);
+
+ if ((int) len < 6 || strncmp (&_template[len - 6], "XXXXXX", 6))
+ return 0;
+
+ XXXXXX = &_template[len - 6];
+
+ value = rand();
+ for (count = 0; count < 256; ++count)
+ {
+ int v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
+
+ if (!KDE_mkdir(_template,0700))
+ return _template;
+ }
+ return 0;
+}
+#endif /* !HAVE_MKDTEMP */
+
+#ifndef HAVE_REVOKE
+#include <errno.h>
+#ifndef ENOTSUP
+#define ENOTSUP 134 /* Not supported */
+#endif
+KDECORE_EXPORT int revoke(const char *tty)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+KDECORE_EXPORT unsigned long strlcpy(char* d, const char* s, unsigned long bufsize)
+{
+ unsigned long len, ret = strlen(s);
+
+ if (ret >= bufsize) {
+ if (bufsize) {
+ len = bufsize - 1;
+ memcpy(d, s, len);
+ d[len] = '\0';
+ }
+ } else
+ memcpy(d, s, ret + 1);
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+KDECORE_EXPORT unsigned long strlcat(char* d, const char* s, unsigned long bufsize)
+{
+ char *cp;
+ unsigned long ret, len1, len2 = strlen(s);
+
+ cp = memchr (d, '\0', bufsize);
+ if (!cp)
+ return bufsize + len2;
+ len1 = cp - d;
+ ret = len1 + len2;
+ if (ret >= bufsize) {
+ len2 = bufsize - len1 - 1;
+ memcpy(cp, s, len2);
+ cp[len2] = '\0';
+ } else
+ memcpy(cp, s, len2 + 1);
+
+ return ret;
+}
+#endif
diff --git a/kdecore/fixx11h.h b/kdecore/fixx11h.h
new file mode 100644
index 000000000..ec8e53ab9
--- /dev/null
+++ b/kdecore/fixx11h.h
@@ -0,0 +1,233 @@
+//#ifdef don't do this, this file is supposed to be included
+//#define multiple times
+
+/* Usage:
+
+ If you get compile errors caused by X11 includes (the line
+ where first error appears contains word like None, Unsorted,
+ Below, etc.), put #include <fixx11h.h> in the .cpp file
+ (not .h file!) between the place where X11 headers are
+ included and the place where the file with compile
+ error is included (or the place where the compile error
+ in the .cpp file occurs).
+
+ This file remaps X11 #defines to const variables or
+ inline functions. The side effect may be that these
+ symbols may now refer to different variables
+ (e.g. if X11 #defined NoButton, after this file
+ is included NoButton would no longer be X11's
+ NoButton, but Qt::NoButton instead). At this time,
+ there's no conflict known that could cause problems.
+
+ The original X11 symbols are still accessible
+ (e.g. for None) as X::None, XNone, and also still
+ None, unless name lookup finds different None
+ first (in the current class, etc.)
+
+ Use 'Unsorted', 'Bool' and 'index' as templates.
+
+*/
+
+namespace X
+{
+
+// template --->
+// Affects: Should be without side effects.
+#ifdef Unsorted
+#ifndef FIXX11H_Unsorted
+#define FIXX11H_Unsorted
+const int XUnsorted = Unsorted;
+#undef Unsorted
+const int Unsorted = XUnsorted;
+#endif
+#undef Unsorted
+#endif
+// template <---
+
+// Affects: Should be without side effects.
+#ifdef None
+#ifndef FIXX11H_None
+#define FIXX11H_None
+const XID XNone = None;
+#undef None
+const XID None = XNone;
+#endif
+#undef None
+#endif
+
+// template --->
+// Affects: Should be without side effects.
+#ifdef Bool
+#ifndef FIXX11H_Bool
+#define FIXX11H_Bool
+typedef Bool XBool;
+#undef Bool
+typedef XBool Bool;
+#endif
+#undef Bool
+#endif
+// template <---
+
+// Affects: Should be without side effects.
+#ifdef KeyPress
+#ifndef FIXX11H_KeyPress
+#define FIXX11H_KeyPress
+const int XKeyPress = KeyPress;
+#undef KeyPress
+const int KeyPress = XKeyPress;
+#endif
+#undef KeyPress
+#endif
+
+// Affects: Should be without side effects.
+#ifdef KeyRelease
+#ifndef FIXX11H_KeyRelease
+#define FIXX11H_KeyRelease
+const int XKeyRelease = KeyRelease;
+#undef KeyRelease
+const int KeyRelease = XKeyRelease;
+#endif
+#undef KeyRelease
+#endif
+
+// Affects: Should be without side effects.
+#ifdef Above
+#ifndef FIXX11H_Above
+#define FIXX11H_Above
+const int XAbove = Above;
+#undef Above
+const int Above = XAbove;
+#endif
+#undef Above
+#endif
+
+// Affects: Should be without side effects.
+#ifdef Below
+#ifndef FIXX11H_Below
+#define FIXX11H_Below
+const int XBelow = Below;
+#undef Below
+const int Below = XBelow;
+#endif
+#undef Below
+#endif
+
+// Affects: Should be without side effects.
+#ifdef FocusIn
+#ifndef FIXX11H_FocusIn
+#define FIXX11H_FocusIn
+const int XFocusIn = FocusIn;
+#undef FocusIn
+const int FocusIn = XFocusIn;
+#endif
+#undef FocusIn
+#endif
+
+// Affects: Should be without side effects.
+#ifdef FocusOut
+#ifndef FIXX11H_FocusOut
+#define FIXX11H_FocusOut
+const int XFocusOut = FocusOut;
+#undef FocusOut
+const int FocusOut = XFocusOut;
+#endif
+#undef FocusOut
+#endif
+
+// Affects: Should be without side effects.
+#ifdef Always
+#ifndef FIXX11H_Always
+#define FIXX11H_Always
+const int XAlways = Always;
+#undef Always
+const int Always = XAlways;
+#endif
+#undef Always
+#endif
+
+// Affects: Should be without side effects.
+#ifdef Success
+#ifndef FIXX11H_Success
+#define FIXX11H_Success
+const int XSuccess = Success;
+#undef Success
+const int Success = XSuccess;
+#endif
+#undef Success
+#endif
+
+// Affects: Should be without side effects.
+#ifdef GrayScale
+#ifndef FIXX11H_GrayScale
+#define FIXX11H_GrayScale
+const int XGrayScale = GrayScale;
+#undef GrayScale
+const int GrayScale = XGrayScale;
+#endif
+#undef GrayScale
+#endif
+
+// Affects: Should be without side effects.
+#ifdef Status
+#ifndef FIXX11H_Status
+#define FIXX11H_Status
+typedef Status XStatus;
+#undef Status
+typedef XStatus Status;
+#endif
+#undef Status
+#endif
+
+// Affects: Should be without side effects.
+#ifdef CursorShape
+#ifndef FIXX11H_CursorShape
+#define FIXX11H_CursorShape
+const int XCursorShape = CursorShape;
+#undef CursorShape
+const int CursorShape = CursorShape;
+#endif
+#undef CursorShape
+#endif
+
+// template --->
+// Affects: Should be without side effects.
+#ifdef index
+#ifndef FIXX11H_index
+#define FIXX11H_index
+inline
+char* Xindex( const char* s, int c )
+ {
+ return index( s, c );
+ }
+#undef index
+inline
+char* index( const char* s, int c )
+ {
+ return Xindex( s, c );
+ }
+#endif
+#undef index
+#endif
+// template <---
+
+#ifdef rindex
+// Affects: Should be without side effects.
+#ifndef FIXX11H_rindex
+#define FIXX11H_rindex
+inline
+char* Xrindex( const char* s, int c )
+ {
+ return rindex( s, c );
+ }
+#undef rindex
+inline
+char* rindex( const char* s, int c )
+ {
+ return Xrindex( s, c );
+ }
+#endif
+#undef rindex
+#endif
+}
+
+using namespace X;
diff --git a/kdecore/generate_keys.sh b/kdecore/generate_keys.sh
new file mode 100755
index 000000000..d0fea1cdd
--- /dev/null
+++ b/kdecore/generate_keys.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+## This script extracts the key names from the QT header
+##
+## Copyright (c) 1999 Nicolas HADACEK (hadacek@kde.org)
+## Distributed under the GNU General Public License
+
+# remove files
+rm -f kckey.h kckey.cpp kckey_a
+
+# extract key names and code from QT header
+sed -n '/enum Key/!d
+ :1
+ N
+ /}/!b1
+ p' $1 \
+| sed -n '/=/p' \
+| sed -n 's/\s*Key_/{ "/
+ s/,.*$/ },/
+ s/ =/",/
+ s/Key_/Qt::Key_/
+ $s/.*/& }/
+ p' \
+> kckey_a
+list=`grep '{ "' kckey_a | sed -e 's#.*{ "\([^"]*\)".*#\1#'`
+for i in $list; do
+ if grep -q "i18n(\"QAccel\", \"$i\");" ../common_texts.cpp; then
+ sed -e "s#^\(.*\"$i\",.*\$\)#\1 // translated#" kckey_a > kckey_a.new && mv kckey_a.new kckey_a
+ fi
+done
+
+# write header file
+begin_line="// This file has been automatically generated by \"generate_keys.sh\""
+echo -e $begin_line \
+ "\n// Distributed under the GNU Library General Public License" \
+ "\n#ifndef KCKEY_H" \
+ "\n#define KCKEY_H" \
+ "\n\ntypedef struct {" \
+ "\n\tconst char *name;" \
+ "\n\tint code;" \
+ "\n} KKeys;" \
+ "\n\n#define MAX_KEY_LENGTH 15 // should be calculated (gawk ?)" \
+ "\n#define MAX_KEY_MODIFIER_LENGTH 21 // \"SHIFT + CRTL + ALT + \" : " \
+ "\n#define MAX_FCTN_LENGTH 50 // arbitrary limit" \
+ "\n#define NB_KEYS " `cat kckey_a | wc -l` \
+ "\nextern const KKeys kde_KKEYS[NB_KEYS];" \
+ "\n\n#endif" \
+> kckey.h
+
+# write source file
+echo -e $begin_line \
+ "\n// Distributed under the GNU Library General Public License" \
+ "\n\n#include <qnamespace.h>" \
+ "\n#include \"kckey.h\"" \
+ "\n\nconst KKeys kde_KKEYS[NB_KEYS] = {" \
+> kckey.cpp
+
+cat kckey_a >> kckey.cpp
+
+echo -e "};" >> kckey.cpp
+
+# cleaning
+rm -f kckey_a
diff --git a/kdecore/kaboutdata.cpp b/kdecore/kaboutdata.cpp
new file mode 100644
index 000000000..aca080837
--- /dev/null
+++ b/kdecore/kaboutdata.cpp
@@ -0,0 +1,512 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Espen Sand (espen@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include <kaboutdata.h>
+#include <kstandarddirs.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+QString
+KAboutPerson::name() const
+{
+ return QString::fromUtf8(mName);
+}
+
+QString
+KAboutPerson::task() const
+{
+ if (mTask && *mTask)
+ return i18n(mTask);
+ else
+ return QString::null;
+}
+
+QString
+KAboutPerson::emailAddress() const
+{
+ return QString::fromUtf8(mEmailAddress);
+}
+
+
+QString
+KAboutPerson::webAddress() const
+{
+ return QString::fromUtf8(mWebAddress);
+}
+
+
+KAboutTranslator::KAboutTranslator(const QString & name,
+ const QString & emailAddress)
+{
+ mName=name;
+ mEmail=emailAddress;
+}
+
+QString KAboutTranslator::name() const
+{
+ return mName;
+}
+
+QString KAboutTranslator::emailAddress() const
+{
+ return mEmail;
+}
+
+class KAboutDataPrivate
+{
+public:
+ KAboutDataPrivate()
+ : translatorName("_: NAME OF TRANSLATORS\nYour names")
+ , translatorEmail("_: EMAIL OF TRANSLATORS\nYour emails")
+ , productName(0)
+ , programLogo(0)
+ , customAuthorTextEnabled(false)
+ , mTranslatedProgramName( 0 )
+ {}
+ ~KAboutDataPrivate()
+ {
+ delete programLogo;
+ delete[] mTranslatedProgramName;
+ }
+ const char *translatorName;
+ const char *translatorEmail;
+ const char *productName;
+ QImage* programLogo;
+ QString customAuthorPlainText, customAuthorRichText;
+ bool customAuthorTextEnabled;
+ const char *mTranslatedProgramName;
+};
+
+
+
+KAboutData::KAboutData( const char *appName,
+ const char *programName,
+ const char *version,
+ const char *shortDescription,
+ int licenseType,
+ const char *copyrightStatement,
+ const char *text,
+ const char *homePageAddress,
+ const char *bugsEmailAddress
+ ) :
+ mProgramName( programName ),
+ mVersion( version ),
+ mShortDescription( shortDescription ),
+ mLicenseKey( licenseType ),
+ mCopyrightStatement( copyrightStatement ),
+ mOtherText( text ),
+ mHomepageAddress( homePageAddress ),
+ mBugEmailAddress( bugsEmailAddress ),
+ mLicenseText (0)
+{
+ d = new KAboutDataPrivate;
+
+ if( appName ) {
+ const char *p = strrchr(appName, '/');
+ if( p )
+ mAppName = p+1;
+ else
+ mAppName = appName;
+ } else
+ mAppName = 0;
+}
+
+KAboutData::~KAboutData()
+{
+ if (mLicenseKey == License_File)
+ delete [] mLicenseText;
+ delete d;
+}
+
+void
+KAboutData::addAuthor( const char *name, const char *task,
+ const char *emailAddress, const char *webAddress )
+{
+ mAuthorList.append(KAboutPerson(name,task,emailAddress,webAddress));
+}
+
+void
+KAboutData::addCredit( const char *name, const char *task,
+ const char *emailAddress, const char *webAddress )
+{
+ mCreditList.append(KAboutPerson(name,task,emailAddress,webAddress));
+}
+
+void
+KAboutData::setTranslator( const char *name, const char *emailAddress)
+{
+ d->translatorName=name;
+ d->translatorEmail=emailAddress;
+}
+
+void
+KAboutData::setLicenseText( const char *licenseText )
+{
+ mLicenseText = licenseText;
+ mLicenseKey = License_Custom;
+}
+
+void
+KAboutData::setLicenseTextFile( const QString &file )
+{
+ mLicenseText = qstrdup(QFile::encodeName(file));
+ mLicenseKey = License_File;
+}
+
+void
+KAboutData::setAppName( const char *appName )
+{
+ mAppName = appName;
+}
+
+void
+KAboutData::setProgramName( const char* programName )
+{
+ mProgramName = programName;
+ translateInternalProgramName();
+}
+
+void
+KAboutData::setVersion( const char* version )
+{
+ mVersion = version;
+}
+
+void
+KAboutData::setShortDescription( const char *shortDescription )
+{
+ mShortDescription = shortDescription;
+}
+
+void
+KAboutData::setLicense( LicenseKey licenseKey)
+{
+ mLicenseKey = licenseKey;
+}
+
+void
+KAboutData::setCopyrightStatement( const char *copyrightStatement )
+{
+ mCopyrightStatement = copyrightStatement;
+}
+
+void
+KAboutData::setOtherText( const char *otherText )
+{
+ mOtherText = otherText;
+}
+
+void
+KAboutData::setHomepage( const char *homepage )
+{
+ mHomepageAddress = homepage;
+}
+
+void
+KAboutData::setBugAddress( const char *bugAddress )
+{
+ mBugEmailAddress = bugAddress;
+}
+
+void
+KAboutData::setProductName( const char *productName )
+{
+ d->productName = productName;
+}
+
+const char *
+KAboutData::appName() const
+{
+ return mAppName;
+}
+
+const char *
+KAboutData::productName() const
+{
+ if (d->productName)
+ return d->productName;
+ else
+ return appName();
+}
+
+QString
+KAboutData::programName() const
+{
+ if (mProgramName && *mProgramName)
+ return i18n(mProgramName);
+ else
+ return QString::null;
+}
+
+const char*
+KAboutData::internalProgramName() const
+{
+ if (d->mTranslatedProgramName)
+ return d->mTranslatedProgramName;
+ else
+ return mProgramName;
+}
+
+// KCrash should call as few things as possible and should avoid e.g. malloc()
+// because it may deadlock. Since i18n() needs it, when KLocale is available
+// the i18n() call will be done here in advance.
+void
+KAboutData::translateInternalProgramName() const
+{
+ delete[] d->mTranslatedProgramName;
+ d->mTranslatedProgramName = 0;
+ if( KGlobal::locale() )
+ d->mTranslatedProgramName = qstrdup( programName().utf8());
+}
+
+QImage
+KAboutData::programLogo() const
+{
+ return d->programLogo ? (*d->programLogo) : QImage();
+}
+
+void
+KAboutData::setProgramLogo(const QImage& image)
+{
+ if (!d->programLogo)
+ d->programLogo = new QImage( image );
+ else
+ *d->programLogo = image;
+}
+
+QString
+KAboutData::version() const
+{
+ return QString::fromLatin1(mVersion);
+}
+
+QString
+KAboutData::shortDescription() const
+{
+ if (mShortDescription && *mShortDescription)
+ return i18n(mShortDescription);
+ else
+ return QString::null;
+}
+
+QString
+KAboutData::homepage() const
+{
+ return QString::fromLatin1(mHomepageAddress);
+}
+
+QString
+KAboutData::bugAddress() const
+{
+ return QString::fromLatin1(mBugEmailAddress);
+}
+
+const QValueList<KAboutPerson>
+KAboutData::authors() const
+{
+ return mAuthorList;
+}
+
+const QValueList<KAboutPerson>
+KAboutData::credits() const
+{
+ return mCreditList;
+}
+
+const QValueList<KAboutTranslator>
+KAboutData::translators() const
+{
+ QValueList<KAboutTranslator> personList;
+
+ if(d->translatorName == 0)
+ return personList;
+
+ QStringList nameList;
+ QStringList emailList;
+
+ QString names = i18n(d->translatorName);
+ if(names != QString::fromUtf8(d->translatorName))
+ {
+ nameList = QStringList::split(',',names);
+ }
+
+
+ if(d->translatorEmail)
+ {
+ QString emails = i18n(d->translatorEmail);
+
+ if(emails != QString::fromUtf8(d->translatorEmail))
+ {
+ emailList = QStringList::split(',',emails,true);
+ }
+ }
+
+
+ QStringList::Iterator nit;
+ QStringList::Iterator eit=emailList.begin();
+
+ for(nit = nameList.begin(); nit != nameList.end(); ++nit)
+ {
+ QString email;
+ if(eit != emailList.end())
+ {
+ email=*eit;
+ ++eit;
+ }
+
+ QString name=*nit;
+
+ personList.append(KAboutTranslator(name.stripWhiteSpace(), email.stripWhiteSpace()));
+ }
+
+ return personList;
+}
+
+QString
+KAboutData::aboutTranslationTeam()
+{
+ return i18n("replace this with information about your translation team",
+ "<p>KDE is translated into many languages thanks to the work "
+ "of the translation teams all over the world.</p>"
+ "<p>For more information on KDE internationalization "
+ "visit <a href=\"http://l10n.kde.org\">http://l10n.kde.org</a></p>"
+ );
+}
+
+QString
+KAboutData::otherText() const
+{
+ if (mOtherText && *mOtherText)
+ return i18n(mOtherText);
+ else
+ return QString::null;
+}
+
+
+QString
+KAboutData::license() const
+{
+ QString result;
+ if (!copyrightStatement().isEmpty())
+ result = copyrightStatement() + "\n\n";
+
+ QString l;
+ QString f;
+ switch ( mLicenseKey )
+ {
+ case License_File:
+ f = QFile::decodeName(mLicenseText);
+ break;
+ case License_GPL_V2:
+ l = "GPL v2";
+ f = locate("data", "LICENSES/GPL_V2");
+ break;
+ case License_LGPL_V2:
+ l = "LGPL v2";
+ f = locate("data", "LICENSES/LGPL_V2");
+ break;
+ case License_BSD:
+ l = "BSD License";
+ f = locate("data", "LICENSES/BSD");
+ break;
+ case License_Artistic:
+ l = "Artistic License";
+ f = locate("data", "LICENSES/ARTISTIC");
+ break;
+ case License_QPL_V1_0:
+ l = "QPL v1.0";
+ f = locate("data", "LICENSES/QPL_V1.0");
+ break;
+ case License_Custom:
+ if (mLicenseText && *mLicenseText)
+ return( i18n(mLicenseText) );
+ // fall through
+ default:
+ result += i18n("No licensing terms for this program have been specified.\n"
+ "Please check the documentation or the source for any\n"
+ "licensing terms.\n");
+ return result;
+ }
+
+ if (!l.isEmpty())
+ result += i18n("This program is distributed under the terms of the %1.").arg( l );
+
+ if (!f.isEmpty())
+ {
+ QFile file(f);
+ if (file.open(IO_ReadOnly))
+ {
+ result += '\n';
+ result += '\n';
+ QTextStream str(&file);
+ result += str.read();
+ }
+ }
+
+ return result;
+}
+
+QString
+KAboutData::copyrightStatement() const
+{
+ if (mCopyrightStatement && *mCopyrightStatement)
+ return i18n(mCopyrightStatement);
+ else
+ return QString::null;
+}
+
+QString
+KAboutData::customAuthorPlainText() const
+{
+ return d->customAuthorPlainText;
+}
+
+QString
+KAboutData::customAuthorRichText() const
+{
+ return d->customAuthorRichText;
+}
+
+bool
+KAboutData::customAuthorTextEnabled() const
+{
+ return d->customAuthorTextEnabled;
+}
+
+void
+KAboutData::setCustomAuthorText(const QString &plainText, const QString &richText)
+{
+ d->customAuthorPlainText = plainText;
+ d->customAuthorRichText = richText;
+
+ d->customAuthorTextEnabled = true;
+}
+
+void
+KAboutData::unsetCustomAuthorText()
+{
+ d->customAuthorPlainText = QString::null;
+ d->customAuthorRichText = QString::null;
+
+ d->customAuthorTextEnabled = false;
+}
+
diff --git a/kdecore/kaboutdata.h b/kdecore/kaboutdata.h
new file mode 100644
index 000000000..4a5c863fa
--- /dev/null
+++ b/kdecore/kaboutdata.h
@@ -0,0 +1,629 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Espen Sand (espen@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <qvaluelist.h>
+#include <qstring.h>
+#include <qimage.h>
+#include <klocale.h>
+
+#ifndef _KABOUTDATA_H_
+#define _KABOUTDATA_H_
+
+class KAboutPersonPrivate;
+class KAboutDataPrivate;
+
+/**
+ * This structure is used to store information about a person or developer.
+ * It can store the person's name, a task, an email address and a
+ * link to a home page. This class is intended for use in the
+ * KAboutData class, but it can be used elsewhere as well.
+ * Normally you should at least define the person's name.
+ *
+ * Example Usage within a main():
+ *
+ * \code
+ * KAboutData about("khello", I18N_NOOP("KHello"), "0.1",
+ * I18N_NOOP("A KDE version of Hello, world!"),
+ * KAboutData::License_LGPL,
+ * I18N_NOOP("Copyright (c) 2003 Developer"));
+ *
+ * about.addAuthor("Joe Developer", I18N_NOOP("developer"), "joe@host.com", 0);
+ * about.addCredit("Joe User", I18N_NOOP("A lot of bug reports"),
+ * "joe.user@host.org", 0);
+ * KCmdLineArgs::init(argc, argv, &about);
+ * \endcode
+ */
+class KDECORE_EXPORT KAboutPerson
+{
+public:
+ /**
+ * Convenience constructor
+ *
+ * @param name The name of the person.
+ *
+ * @param task The task of this person. This string should be
+ * marked for translation, e.g.
+ * I18N_NOOP("Task description....")
+ *
+ * @param emailAddress The email address of the person.
+ *
+ * @param webAddress Home page of the person.
+ */
+ KAboutPerson( const char *name, const char *task,
+ const char *emailAddress, const char *webAddress )
+ {
+ mName = name;
+ mTask = task;
+ mEmailAddress = emailAddress;
+ mWebAddress = webAddress;
+ }
+ /**
+ * @internal
+ * Don't use. Required by QValueList
+ */
+ KAboutPerson() {}
+
+ /**
+ * The person's name
+ * @return the person's name (can be QString::null, if it has been
+ * constructed with a null name)
+ */
+ QString name() const;
+
+ /**
+ * The person's task
+ * @return the person's task (can be QString::null, if it has been
+ * constructed with a null task)
+ */
+ QString task() const;
+
+ /**
+ * The person's email address
+ * @return the person's email address (can be QString::null, if it has been
+ * constructed with a null email)
+ */
+ QString emailAddress() const;
+
+ /**
+ * The home page or a relevant link
+ * @return the persons home page (can be QString::null, if it has been
+ * constructed with a null home page)
+ */
+ QString webAddress() const;
+
+private:
+ const char *mName;
+ const char *mTask;
+ const char *mEmailAddress;
+ const char *mWebAddress;
+
+ KAboutPersonPrivate *d;
+};
+
+class KAboutTranslatorPrivate;
+/**
+ * This structure is used to store information about a translator.
+ * It can store the translator's name and an email address.
+ * This class is intended for use in the KAboutData class,
+ * but it can be used elsewhere as well.
+ * Normally you should at least define the translator's name.
+ *
+ * It's not possible to use KAboutPerson for this, because
+ * KAboutPerson stores internally only const char* pointers, but the
+ * translator information is generated dynamically from the translation
+ * of a dummy string.
+*/
+class KDECORE_EXPORT KAboutTranslator
+{
+public:
+ /**
+ * Convenience constructor
+ *
+ * @param name The name of the person.
+ *
+ * @param emailAddress The email address of the person.
+ */
+ KAboutTranslator(const QString & name=QString::null,
+ const QString & emailAddress=QString::null);
+
+ /**
+ * The translator's name
+ * @return the translators's name (can be QString::null, if it has been
+ * constructed with a null name)
+ */
+ QString name() const;
+
+ /**
+ * The translator's email
+ * @return the translator's email address (can be QString::null, if it has been
+ * constructed with a null email)
+ */
+ QString emailAddress() const;
+
+private:
+ QString mName;
+ QString mEmail;
+ KAboutTranslatorPrivate* d;
+};
+
+
+/**
+ * This class is used to store information about a program. It can store
+ * such values as version number, program name, home page, email address
+ * for bug reporting, multiple authors and contributors
+ * (using KAboutPerson), license and copyright information.
+ *
+ * Currently, the values set here are shown by the "About" box
+ * (see KAboutDialog), used by the bug report dialog (see KBugReport),
+ * and by the help shown on command line (see KCmdLineArgs).
+ *
+ * @short Holds information needed by the "About" box and other
+ * classes.
+ * @author Espen Sand (espen@kde.org), David Faure (faure@kde.org)
+ */
+class KDECORE_EXPORT KAboutData
+{
+ public:
+ /**
+ * Descibes the license of the software.
+ */
+ enum LicenseKey
+ {
+ License_Custom = -2,
+ License_File = -1,
+ License_Unknown = 0,
+ License_GPL = 1,
+ License_GPL_V2 = 1,
+ License_LGPL = 2,
+ License_LGPL_V2 = 2,
+ License_BSD = 3,
+ License_Artistic = 4,
+ License_QPL = 5,
+ License_QPL_V1_0 = 5
+ };
+
+ public:
+ /**
+ * Constructor.
+ *
+ * @param appName The program name used internally. Example: "kedit"
+ *
+ * @param programName A displayable program name string. This string
+ * should be marked for translation. Example: I18N_NOOP("KEdit")
+ *
+ * @param version The program version string.
+ *
+ * @param shortDescription A short description of what the program does.
+ * This string should be marked for translation.
+ * Example: I18N_NOOP("A simple text editor.")
+ *
+ * @param licenseType The license identifier. Use setLicenseText if
+ * you use a license not predefined here.
+ *
+ * @param copyrightStatement A copyright statement, that can look like this:
+ * "(c) 1999-2000, Name". The string specified here is not modified
+ * in any manner. The author information from addAuthor is not
+ * used.
+ *
+ * @param text Some free form text, that can contain any kind of
+ * information. The text can contain newlines. This string
+ * should be marked for translation.
+ *
+ * @param homePageAddress The program homepage string.
+ * Start the address with "http://". "http://some.domain" is
+ * is correct, "some.domain" is not.
+ *
+ * @param bugsEmailAddress The bug report email address string.
+ * This defaults to the kde.org bug system.
+ *
+ */
+ KAboutData( const char *appName,
+ const char *programName,
+ const char *version,
+ const char *shortDescription = 0,
+ int licenseType = License_Unknown,
+ const char *copyrightStatement = 0,
+ const char *text = 0,
+ const char *homePageAddress = 0,
+ const char *bugsEmailAddress = "submit@bugs.kde.org"
+ );
+
+ ~KAboutData();
+
+ /**
+ * Defines an author. You can call this function as many times you
+ * need. Each entry is appended to a list. The person in the first entry
+ * is assumed to be the leader of the project.
+ *
+ * @param name The developer's name in UTF-8 encoding.
+ *
+ * @param task What the person is responsible for. This text can contain
+ * newlines. It should be marked for translation like this:
+ * I18N_NOOP("Task description..."). Can be 0.
+ *
+ * @param emailAddress An Email address where the person can be reached.
+ * Can be 0.
+ *
+ * @param webAddress The person's homepage or a relevant link.
+ * Start the address with "http://". "http://some.domain" is
+ * correct, "some.domain" is not. Can be 0.
+ *
+ */
+ void addAuthor( const char *name,
+ const char *task=0,
+ const char *emailAddress=0,
+ const char *webAddress=0 );
+
+ /**
+ * Defines a person that deserves credit. You can call this function
+ * as many times you need. Each entry is appended to a list.
+ *
+ * @param name The person's name in UTF-8 encoding.
+ *
+ * @param task What the person has done to deserve the honor. The
+ * text can contain newlines. It should be marked for
+ * translation like this: I18N_NOOP("Task description...")
+ * Can be 0.
+ *
+ * @param emailAddress An Email address when the person can be reached.
+ * Can be 0.
+ *
+ * @param webAddress The person's homepage or a relevant link.
+ * Start the address with "http://". "http://some.domain" is
+ * is correct, "some.domain" is not. Can be 0.
+ *
+ */
+ void addCredit( const char *name,
+ const char *task=0,
+ const char *emailAddress=0,
+ const char *webAddress=0 );
+
+ /**
+ * Sets the name of the translator of the gui. Since this depends
+ * on the language, just use a dummy text marked for translation.
+ *
+ * For example:
+ * \code
+ * setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\\nYour names")
+ * ,I18N_NOOP("_: EMAIL OF TRANSLATORS\\nYour emails"));
+ * \endcode
+ *
+ * The translator can then translate this dummy text with his name
+ * or with a list of names separated with ",".
+ * If there is no translation or the application is used with the
+ * default language, this function call is ignored.
+ *
+ * Note: If you are using the default KDE automake environment,
+ * there is no need to use this function, because the two
+ * default strings above are added to the applications po file
+ * automatically.
+ *
+ * @param name the name of the translator
+ * @param emailAddress the email address of the translator
+ * @see KAboutTranslator
+ */
+ void setTranslator(const char* name, const char* emailAddress);
+
+ /**
+ * Defines a license text.
+ *
+ * The text will be translated if it got marked for
+ * translations with the I18N_NOOP() macro.
+ *
+ * Example:
+ * \code
+ * setLicenseText( I18N_NOOP("This is my license"));
+ * \endcode
+ *
+ * NOTE: No copy of the text is made.
+ *
+ * @param license The license text in utf8 encoding.
+ */
+ void setLicenseText( const char *license );
+
+ /**
+ * Defines a license text.
+ *
+ * @param file File containing the license text.
+ */
+ void setLicenseTextFile( const QString &file );
+
+ /**
+ * Defines the program name used internally.
+ *
+ * @param appName The application name. Example: "kate".
+ */
+ void setAppName( const char *appName );
+
+ /**
+ * Defines the displayable program name string.
+ *
+ * @param programName The program name. This string should be
+ * marked for translation.
+ * Example: I18N_NOOP("Advanced Text Editor").
+ * @since 3.2
+ */
+ void setProgramName( const char* programName );
+
+ /**
+ * Defines the program logo.
+ * Use this if you need to have application logo
+ * in AboutData other than application icon.
+ *
+ * @param image logo image.
+ * @see programLogo()
+ * @since 3.4
+ */
+ void setProgramLogo(const QImage& image);
+
+ /**
+ * Defines the program version string.
+ *
+ * @param version The program version.
+ */
+ void setVersion( const char* version );
+
+ /**
+ * Defines a short description of what the program does.
+ *
+ * @param shortDescription The program description This string should be marked
+ * for translation. Example: I18N_NOOP("An advanced text editor
+ * with syntax highlithing support.").
+ */
+ void setShortDescription( const char *shortDescription );
+
+ /**
+ * Defines the license identifier.
+ *
+ * @param licenseKey The license identifier.
+ */
+ void setLicense( LicenseKey licenseKey);
+
+ /**
+ * Defines the copyright statement to show when displaying the license.
+ *
+ * @param copyrightStatement A copyright statement, that can look like
+ * this: "(c) 1999-2000, Name". The string specified here is not
+ * modified in any manner. The author information from addAuthor
+ * is not used.
+ */
+ void setCopyrightStatement( const char *copyrightStatement );
+
+ /**
+ * Defines the additional text to show in the about dialog.
+ *
+ * @param otherText Some free form text, that can contain any kind of
+ * information. The text can contain newlines. This string
+ * should be marked for translation.
+ */
+ void setOtherText( const char *otherText );
+
+ /**
+ * Defines the program homepage.
+ *
+ * @param homepage The program homepage string.
+ * Start the address with "http://". "http://kate.kde.org" is
+ * is correct, "kde.kde.org" is not.
+ */
+ void setHomepage( const char *homepage );
+
+ /**
+ * Defines the address where bug reports should be sent.
+ *
+ * @param bugAddress The bug report email address string.
+ * This defaults to the kde.org bug system.
+ */
+ void setBugAddress( const char *bugAddress );
+
+ /**
+ * Defines the product name wich will be used in the KBugReport dialog.
+ * By default it's the appName, but you can overwrite it here to provide
+ * support for special components e.g. 'product/component' like
+ * 'kontact/summary'.
+ *
+ * @param name The name of product
+ */
+ void setProductName( const char *name );
+
+ /**
+ * Returns the application's internal name.
+ * @return the internal program name.
+ */
+ const char *appName() const;
+
+ /**
+ * Returns the application's product name, which will be used in KBugReport
+ * dialog. By default it returns appName(), otherwise the one which is set
+ * with setProductName()
+ *
+ * @return the product name.
+ */
+ const char *productName() const;
+
+ /**
+ * Returns the translated program name.
+ * @return the program name (translated).
+ */
+ QString programName() const;
+
+ /**
+ * @internal
+ */
+ const char* internalProgramName() const;
+ /**
+ * @internal
+ */
+ void translateInternalProgramName() const;
+
+ /**
+ * Returns the program logo image.
+ * @return the program logo data or null image if there is
+ * no custom application logo defined.
+ * @since 3.4
+ */
+ QImage programLogo() const;
+
+ /**
+ * Returns the program's version.
+ * @return the version string.
+ */
+ QString version() const;
+
+ /**
+ * @internal
+ */
+ const char* internalVersion() const { return mVersion; }
+
+ /**
+ * Returns a short, translated description.
+ * @return the short description (translated). Can be
+ * QString::null if not set.
+ */
+ QString shortDescription() const;
+
+ /**
+ * Returns the application homepage.
+ * @return the application homepage URL. Can be QString::null if
+ * not set.
+ */
+ QString homepage() const;
+
+ /**
+ * Returns the email address for bugs.
+ * @return the email address where to report bugs.
+ */
+ QString bugAddress() const;
+
+ /**
+ * @internal
+ */
+ const char* internalBugAddress() const { return mBugEmailAddress; }
+
+ /**
+ * Returns a list of authors.
+ * @return author information (list of persons).
+ */
+ const QValueList<KAboutPerson> authors() const;
+
+ /**
+ * Returns a list of persons who contributed.
+ * @return credit information (list of persons).
+ */
+ const QValueList<KAboutPerson> credits() const;
+
+ /**
+ * Returns a list of translators.
+ * @return translators information (list of persons)
+ */
+ const QValueList<KAboutTranslator> translators() const;
+
+ /**
+ * Returns a message about the translation team.
+ * @return a message about the translation team
+ */
+ static QString aboutTranslationTeam();
+
+ /**
+ * Returns a translated, free form text.
+ * @return the free form text (translated). Can be QString::null if not set.
+ */
+ QString otherText() const;
+
+ /**
+ * Returns the license. If the licenseType argument of the constructor has been
+ * used, any text defined by setLicenseText is ignored,
+ * and the standard text for the chosen license will be returned.
+ *
+ * @return The license text.
+ */
+ QString license() const;
+
+ /**
+ * Returns the copyright statement.
+ * @return the copyright statement. Can be QString::null if not set.
+ */
+ QString copyrightStatement() const;
+
+ /**
+ * Returns the plain text displayed around the list of authors instead
+ * of the default message telling users to send bug reports to bugAddress().
+ *
+ * @return the plain text displayed around the list of authors instead
+ * of the default message. Can be QString::null.
+ */
+ QString customAuthorPlainText() const;
+
+ /**
+ * Returns the rich text displayed around the list of authors instead
+ * of the default message telling users to send bug reports to bugAddress().
+ *
+ * @return the rich text displayed around the list of authors instead
+ * of the default message. Can be QString::null.
+ */
+ QString customAuthorRichText() const;
+
+ /**
+ * Returns whether custom text should be displayed around the list of
+ * authors.
+ *
+ * @return whether custom text should be displayed around the list of
+ * authors.
+ */
+ bool customAuthorTextEnabled() const;
+
+ /**
+ * Sets the custom text displayed around the list of authors instead
+ * of the default message telling users to send bug reports to bugAddress().
+ *
+ * @param plainText The plain text.
+ * @param richText The rich text.
+ *
+ * Both parameters can be QString::null to not display any message at
+ * all. Call unsetCustomAuthorText() to revert to the default mesage.
+ */
+ void setCustomAuthorText(const QString &plainText, const QString &richText);
+
+ /**
+ * Clears any custom text displayed around the list of authors and falls
+ * back to the default message telling users to send bug reports to
+ * bugAddress().
+ */
+ void unsetCustomAuthorText();
+
+ private:
+ const char *mAppName;
+ const char *mProgramName;
+ const char *mVersion;
+ const char *mShortDescription;
+ int mLicenseKey;
+ const char *mCopyrightStatement;
+ const char *mOtherText;
+ const char *mHomepageAddress;
+ const char *mBugEmailAddress;
+ QValueList<KAboutPerson> mAuthorList;
+ QValueList<KAboutPerson> mCreditList;
+ const char *mLicenseText;
+
+ KAboutDataPrivate *d;
+};
+
+#endif
+
diff --git a/kdecore/kaccel.cpp b/kdecore/kaccel.cpp
new file mode 100644
index 000000000..461666d31
--- /dev/null
+++ b/kdecore/kaccel.cpp
@@ -0,0 +1,660 @@
+/*
+ Copyright (c) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kaccel.h"
+
+#include <qaccel.h>
+#include <qguardedptr.h>
+#include <qpopupmenu.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qtimer.h>
+
+#include "kaccelbase.h"
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kshortcut.h>
+
+#include "kaccelprivate.h"
+
+#ifdef Q_WS_X11
+# include <X11/Xlib.h>
+# ifdef KeyPress // needed for --enable-final
+ // defined by X11 headers
+ const int XKeyPress = KeyPress;
+# undef KeyPress
+# endif
+#endif
+
+// TODO: Put in kaccelbase.cpp
+//---------------------------------------------------------------------
+// KAccelEventHandler
+//---------------------------------------------------------------------
+//
+// In KAccelEventHandler::x11Event we do our own X11 keyboard event handling
+// This allows us to map the Win key to Qt::MetaButton, Qt does not know about
+// the Win key.
+//
+// KAccelEventHandler::x11Event will generate an AccelOverride event. The
+// AccelOverride event is abused a bit to ensure that KAccelPrivate::eventFilter
+// (as an event filter on the toplevel widget) will get the key event first
+// (in the form of AccelOverride) before any of the intermediate widgets are
+// able to process it.
+//
+// Qt normally sends an AccelOverride, Accel and then a KeyPress event.
+// A widget can accept the AccelOverride event in which case the Accel event will be
+// skipped and the KeyPress is followed immediately.
+// If the Accel event is accepted, no KeyPress event will follow.
+//
+// KAccelEventHandler::x11Event converts a X11 keyboard event into an AccelOverride
+// event, there are now two possibilities:
+//
+// 1) If KAccel intercepts the AccelOverride we are done and can consider the X11
+// keyboard event as handled.
+// 2) If another widget accepts the AccelOverride, it will expect to get a normal
+// Qt generated KeyPress event afterwards. So we let Qt handle the X11 keyboard event
+// again. However, this will first generate an AccelOverride event, and we already
+// had send that one. To compnesate for this, the global event filter in KApplication
+// is instructed to eat the next AccelOveride event. Qt will then send a normal KeyPress
+// event and from then on everything is normal again.
+//
+// kde_g_bKillAccelOverride is used to tell KApplication::notify to eat the next
+// AccelOverride event.
+
+bool kde_g_bKillAccelOverride = false;
+
+class KAccelEventHandler : public QWidget
+{
+ public:
+ static KAccelEventHandler* self()
+ {
+ if( !g_pSelf )
+ g_pSelf = new KAccelEventHandler;
+ return g_pSelf;
+ }
+
+ static void accelActivated( bool b ) { g_bAccelActivated = b; }
+
+ private:
+ KAccelEventHandler();
+
+# ifdef Q_WS_X11
+ bool x11Event( XEvent* pEvent );
+# endif
+
+ static KAccelEventHandler* g_pSelf;
+ static bool g_bAccelActivated;
+};
+
+KAccelEventHandler* KAccelEventHandler::g_pSelf = 0;
+bool KAccelEventHandler::g_bAccelActivated = false;
+
+KAccelEventHandler::KAccelEventHandler()
+ : QWidget( 0, "KAccelEventHandler" )
+{
+# ifdef Q_WS_X11
+ if ( kapp )
+ kapp->installX11EventFilter( this );
+# endif
+}
+
+#ifdef Q_WS_X11
+bool qt_try_modal( QWidget *, XEvent * );
+
+bool KAccelEventHandler::x11Event( XEvent* pEvent )
+{
+ if( QWidget::keyboardGrabber() || !kapp->focusWidget() )
+ return false;
+
+ if ( !qt_try_modal(kapp->focusWidget(), pEvent) )
+ return false;
+
+ if( pEvent->type == XKeyPress ) {
+ KKeyNative keyNative( pEvent );
+ KKey key( keyNative );
+ key.simplify();
+ int keyCodeQt = key.keyCodeQt();
+ int state = 0;
+ if( key.modFlags() & KKey::SHIFT ) state |= Qt::ShiftButton;
+ if( key.modFlags() & KKey::CTRL ) state |= Qt::ControlButton;
+ if( key.modFlags() & KKey::ALT ) state |= Qt::AltButton;
+ if( key.modFlags() & KKey::WIN ) state |= Qt::MetaButton;
+
+ QKeyEvent ke( QEvent::AccelOverride, keyCodeQt, 0, state );
+ ke.ignore();
+
+ g_bAccelActivated = false;
+ kapp->sendEvent( kapp->focusWidget(), &ke );
+
+ // If the Override event was accepted from a non-KAccel widget,
+ // then kill the next AccelOverride in KApplication::notify.
+ if( ke.isAccepted() && !g_bAccelActivated )
+ kde_g_bKillAccelOverride = true;
+
+ // Stop event processing if a KDE accelerator was activated.
+ return g_bAccelActivated;
+ }
+
+ return false;
+}
+#endif // Q_WS_X11
+
+//---------------------------------------------------------------------
+// KAccelPrivate
+//---------------------------------------------------------------------
+
+KAccelPrivate::KAccelPrivate( KAccel* pParent, QWidget* pWatch )
+: KAccelBase( KAccelBase::QT_KEYS )
+{
+ //kdDebug(125) << "KAccelPrivate::KAccelPrivate( pParent = " << pParent << " ): this = " << this << endl;
+ m_pAccel = pParent;
+ m_pWatch = pWatch;
+ m_bAutoUpdate = true;
+ connect( (QAccel*)m_pAccel, SIGNAL(activated(int)), this, SLOT(slotKeyPressed(int)) );
+
+#ifdef Q_WS_X11 //only makes sense if KAccelEventHandler is working
+ if( m_pWatch )
+ m_pWatch->installEventFilter( this );
+#endif
+ KAccelEventHandler::self();
+}
+
+void KAccelPrivate::setEnabled( bool bEnabled )
+{
+ m_bEnabled = bEnabled;
+ ((QAccel*)m_pAccel)->setEnabled( bEnabled );
+}
+
+bool KAccelPrivate::setEnabled( const QString& sAction, bool bEnable )
+{
+ kdDebug(125) << "KAccelPrivate::setEnabled( \"" << sAction << "\", " << bEnable << " ): this = " << this << endl;
+ KAccelAction* pAction = actionPtr( sAction );
+ if( !pAction )
+ return false;
+ if( pAction->isEnabled() == bEnable )
+ return true;
+
+ pAction->setEnabled( bEnable );
+
+ QMap<int, KAccelAction*>::const_iterator it = m_mapIDToAction.begin();
+ for( ; it != m_mapIDToAction.end(); ++it ) {
+ if( *it == pAction )
+ ((QAccel*)m_pAccel)->setItemEnabled( it.key(), bEnable );
+ }
+ return true;
+}
+
+bool KAccelPrivate::removeAction( const QString& sAction )
+{
+ // FIXME: getID() doesn't contains any useful
+ // information! Use mapIDToAction. --ellis, 2/May/2002
+ // Or maybe KAccelBase::remove() takes care of QAccel indirectly...
+ KAccelAction* pAction = actions().actionPtr( sAction );
+ if( pAction ) {
+ int nID = pAction->getID();
+ //bool b = actions().removeAction( sAction );
+ bool b = KAccelBase::remove( sAction );
+ ((QAccel*)m_pAccel)->removeItem( nID );
+ return b;
+ } else
+ return false;
+}
+
+bool KAccelPrivate::emitSignal( KAccelBase::Signal signal )
+{
+ if( signal == KAccelBase::KEYCODE_CHANGED ) {
+ m_pAccel->emitKeycodeChanged();
+ return true;
+ }
+ return false;
+}
+
+bool KAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
+{
+ uint keyQt = key.keyCodeQt();
+ int nID = ((QAccel*)m_pAccel)->insertItem( keyQt );
+ m_mapIDToAction[nID] = &action;
+ m_mapIDToKey[nID] = keyQt;
+
+ if( action.objSlotPtr() && action.methodSlotPtr() ) {
+#ifdef Q_WS_WIN /** @todo TEMP: new implementation (commit #424926) didn't work */
+ ((QAccel*)m_pAccel)->connectItem( nID, action.objSlotPtr(), action.methodSlotPtr() );
+#else
+ ((QAccel*)m_pAccel)->connectItem( nID, this, SLOT(slotKeyPressed(int)));
+#endif
+ if( !action.isEnabled() )
+ ((QAccel*)m_pAccel)->setItemEnabled( nID, false );
+ }
+
+ kdDebug(125) << "KAccelPrivate::connectKey( \"" << action.name() << "\", " << key.key().toStringInternal() << " = 0x" << QString::number(keyQt,16) << " ): id = " << nID << " m_pObjSlot = " << action.objSlotPtr() << endl;
+ //kdDebug(125) << "m_pAccel = " << m_pAccel << endl;
+ return nID != 0;
+}
+
+bool KAccelPrivate::connectKey( const KKeyServer::Key& key )
+{
+ uint keyQt = key.keyCodeQt();
+ int nID = ((QAccel*)m_pAccel)->insertItem( keyQt );
+
+ m_mapIDToKey[nID] = keyQt;
+
+ kdDebug(125) << "KAccelPrivate::connectKey( " << key.key().toStringInternal() << " = 0x" << QString::number(keyQt,16) << " ): id = " << nID << endl;
+ return nID != 0;
+}
+
+bool KAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
+{
+ int keyQt = key.keyCodeQt();
+ QMap<int, int>::iterator it = m_mapIDToKey.begin();
+ for( ; it != m_mapIDToKey.end(); ++it ) {
+ //kdDebug(125) << "m_mapIDToKey[" << it.key() << "] = " << QString::number(*it,16) << " == " << QString::number(keyQt,16) << endl;
+ if( *it == keyQt ) {
+ int nID = it.key();
+ kdDebug(125) << "KAccelPrivate::disconnectKey( \"" << action.name() << "\", 0x" << QString::number(keyQt,16) << " ) : id = " << nID << " m_pObjSlot = " << action.objSlotPtr() << endl;
+ ((QAccel*)m_pAccel)->removeItem( nID );
+ m_mapIDToAction.remove( nID );
+ m_mapIDToKey.remove( it );
+ return true;
+ }
+ }
+ //kdWarning(125) << kdBacktrace() << endl;
+ kdWarning(125) << "Didn't find key in m_mapIDToKey." << endl;
+ return false;
+}
+
+bool KAccelPrivate::disconnectKey( const KKeyServer::Key& key )
+{
+ int keyQt = key.keyCodeQt();
+ kdDebug(125) << "KAccelPrivate::disconnectKey( 0x" << QString::number(keyQt,16) << " )" << endl;
+ QMap<int, int>::iterator it = m_mapIDToKey.begin();
+ for( ; it != m_mapIDToKey.end(); ++it ) {
+ if( *it == keyQt ) {
+ ((QAccel*)m_pAccel)->removeItem( it.key() );
+ m_mapIDToKey.remove( it );
+ return true;
+ }
+ }
+ //kdWarning(125) << kdBacktrace() << endl;
+ kdWarning(125) << "Didn't find key in m_mapIDTokey." << endl;
+ return false;
+}
+
+void KAccelPrivate::slotKeyPressed( int id )
+{
+ kdDebug(125) << "KAccelPrivate::slotKeyPressed( " << id << " )" << endl;
+
+ if( m_mapIDToKey.contains( id ) ) {
+ KKey key = m_mapIDToKey[id];
+ KKeySequence seq( key );
+ QPopupMenu* pMenu = createPopupMenu( m_pWatch, seq );
+
+ // If there was only one action mapped to this key,
+ // and that action is not a multi-key shortcut,
+ // then activated it without popping up the menu.
+ // This is needed for when there are multiple actions
+ // with the same shortcut where all but one is disabled.
+ // pMenu->count() also counts the menu title, so one shortcut will give count = 2.
+ if( pMenu->count() == 2 && pMenu->accel(1).isEmpty() ) {
+ int iAction = pMenu->idAt(1);
+ slotMenuActivated( iAction );
+ } else {
+ connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuActivated(int)) );
+ pMenu->exec( m_pWatch->mapToGlobal( QPoint( 0, 0 ) ) );
+ disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuActivated(int)) );
+ }
+ delete pMenu;
+ }
+}
+
+void KAccelPrivate::slotShowMenu()
+{
+}
+
+void KAccelPrivate::slotMenuActivated( int iAction )
+{
+ kdDebug(125) << "KAccelPrivate::slotMenuActivated( " << iAction << " )" << endl;
+ KAccelAction* pAction = actions().actionPtr( iAction );
+#ifdef Q_WS_WIN /** @todo TEMP: new implementation (commit #424926) didn't work */
+ if( pAction ) {
+ connect( this, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
+ emit menuItemActivated();
+ disconnect( this, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
+ }
+#else
+ emitActivatedSignal( pAction );
+#endif
+}
+
+bool KAccelPrivate::eventFilter( QObject* /*pWatched*/, QEvent* pEvent )
+{
+ if( pEvent->type() == QEvent::AccelOverride && m_bEnabled ) {
+ QKeyEvent* pKeyEvent = (QKeyEvent*) pEvent;
+ KKey key( pKeyEvent );
+ kdDebug(125) << "KAccelPrivate::eventFilter( AccelOverride ): this = " << this << ", key = " << key.toStringInternal() << endl;
+ int keyCodeQt = key.keyCodeQt();
+ QMap<int, int>::iterator it = m_mapIDToKey.begin();
+ for( ; it != m_mapIDToKey.end(); ++it ) {
+ if( (*it) == keyCodeQt ) {
+ int nID = it.key();
+ kdDebug(125) << "shortcut found!" << endl;
+ if( m_mapIDToAction.contains( nID ) ) {
+ // TODO: reduce duplication between here and slotMenuActivated
+ KAccelAction* pAction = m_mapIDToAction[nID];
+ if( !pAction->isEnabled() )
+ continue;
+#ifdef Q_WS_WIN /** @todo TEMP: new implementation (commit #424926) didn't work */
+ QGuardedPtr<KAccelPrivate> me = this;
+ connect( this, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
+ emit menuItemActivated();
+ if (me) {
+ disconnect( me, SIGNAL(menuItemActivated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
+ }
+#else
+ emitActivatedSignal( pAction );
+#endif
+ } else
+ slotKeyPressed( nID );
+
+ pKeyEvent->accept();
+ KAccelEventHandler::accelActivated( true );
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#ifndef Q_WS_WIN /** @todo TEMP: new implementation (commit #424926) didn't work */
+void KAccelPrivate::emitActivatedSignal( KAccelAction* pAction )
+{
+ if( pAction ) {
+ QGuardedPtr<KAccelPrivate> me = this;
+ QRegExp reg( "([ ]*KAccelAction.*)" );
+ if( reg.search( pAction->methodSlotPtr()) >= 0 ) {
+ connect( this, SIGNAL(menuItemActivated(KAccelAction*)),
+ pAction->objSlotPtr(), pAction->methodSlotPtr() );
+ emit menuItemActivated( pAction );
+ if (me)
+ disconnect( me, SIGNAL(menuItemActivated(KAccelAction*)),
+ pAction->objSlotPtr(), pAction->methodSlotPtr() );
+ } else {
+ connect( this, SIGNAL(menuItemActivated()),
+ pAction->objSlotPtr(), pAction->methodSlotPtr() );
+ emit menuItemActivated();
+ if (me)
+ disconnect( me, SIGNAL(menuItemActivated()),
+ pAction->objSlotPtr(), pAction->methodSlotPtr() );
+
+ }
+ }
+}
+#endif
+
+//---------------------------------------------------------------------
+// KAccel
+//---------------------------------------------------------------------
+
+KAccel::KAccel( QWidget* pParent, const char* psName )
+: QAccel( pParent, (psName) ? psName : "KAccel-QAccel" )
+{
+ kdDebug(125) << "KAccel( pParent = " << pParent << ", psName = " << psName << " ): this = " << this << endl;
+ d = new KAccelPrivate( this, pParent );
+}
+
+KAccel::KAccel( QWidget* watch, QObject* pParent, const char* psName )
+: QAccel( watch, pParent, (psName) ? psName : "KAccel-QAccel" )
+{
+ kdDebug(125) << "KAccel( watch = " << watch << ", pParent = " << pParent << ", psName = " << psName << " ): this = " << this << endl;
+ if( !watch )
+ kdDebug(125) << kdBacktrace() << endl;
+ d = new KAccelPrivate( this, watch );
+}
+
+KAccel::~KAccel()
+{
+ kdDebug(125) << "~KAccel(): this = " << this << endl;
+ delete d;
+}
+
+KAccelActions& KAccel::actions() { return d->actions(); }
+const KAccelActions& KAccel::actions() const { return d->actions(); }
+bool KAccel::isEnabled() { return d->isEnabled(); }
+void KAccel::setEnabled( bool bEnabled ) { d->setEnabled( bEnabled ); }
+bool KAccel::setAutoUpdate( bool bAuto ) { return d->setAutoUpdate( bAuto ); }
+
+KAccelAction* KAccel::insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ return d->insert( sAction, sLabel, sWhatsThis,
+ cutDef, cutDef,
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+}
+
+KAccelAction* KAccel::insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef3, const KShortcut& cutDef4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ return d->insert( sAction, sLabel, sWhatsThis,
+ cutDef3, cutDef4,
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+}
+
+KAccelAction* KAccel::insert( const char* psAction, const KShortcut& cutDef,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ return d->insert( psAction, i18n(psAction), QString::null,
+ cutDef, cutDef,
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+}
+
+KAccelAction* KAccel::insert( KStdAccel::StdAccel id,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ QString sAction = KStdAccel::name( id );
+ if( sAction.isEmpty() )
+ return 0;
+
+ KAccelAction* pAction = d->insert( sAction, KStdAccel::label( id ), KStdAccel::whatsThis( id ),
+ KStdAccel::shortcutDefault3( id ), KStdAccel::shortcutDefault4( id ),
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+ if( pAction )
+ pAction->setShortcut( KStdAccel::shortcut( id ) );
+
+ return pAction;
+}
+
+bool KAccel::remove( const QString& sAction )
+ { return d->removeAction( sAction ); }
+bool KAccel::updateConnections()
+ { return d->updateConnections(); }
+
+const KShortcut& KAccel::shortcut( const QString& sAction ) const
+{
+ const KAccelAction* pAction = actions().actionPtr( sAction );
+ return (pAction) ? pAction->shortcut() : KShortcut::null();
+}
+
+bool KAccel::setSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot )
+ { return d->setActionSlot( sAction, pObjSlot, psMethodSlot ); }
+
+bool KAccel::setEnabled( const QString& sAction, bool bEnable )
+ { return d->setEnabled( sAction, bEnable ); }
+
+bool KAccel::setShortcut( const QString& sAction, const KShortcut& cut )
+{
+ kdDebug(125) << "KAccel::setShortcut( \"" << sAction << "\", " << cut.toStringInternal() << " )" << endl;
+ KAccelAction* pAction = actions().actionPtr( sAction );
+ if( pAction ) {
+ if( pAction->shortcut() != cut )
+ return d->setShortcut( sAction, cut );
+ return true;
+ }
+ return false;
+}
+
+const QString& KAccel::configGroup() const
+ { return d->configGroup(); }
+// for kdegames/ksirtet
+void KAccel::setConfigGroup( const QString& s )
+ { d->setConfigGroup( s ); }
+
+bool KAccel::readSettings( KConfigBase* pConfig )
+{
+ d->readSettings( pConfig );
+ return true;
+}
+
+bool KAccel::writeSettings( KConfigBase* pConfig ) const
+ { d->writeSettings( pConfig ); return true; }
+
+void KAccel::emitKeycodeChanged()
+{
+ kdDebug(125) << "KAccel::emitKeycodeChanged()" << endl;
+ emit keycodeChanged();
+}
+
+#ifndef KDE_NO_COMPAT
+//------------------------------------------------------------
+// Obsolete methods -- for backward compatibility
+//------------------------------------------------------------
+
+bool KAccel::insertItem( const QString& sLabel, const QString& sAction,
+ const char* cutsDef,
+ int /*nIDMenu*/, QPopupMenu *, bool bConfigurable )
+{
+ KShortcut cut( cutsDef );
+ bool b = d->insert( sAction, sLabel, QString::null,
+ cut, cut,
+ 0, 0,
+ bConfigurable ) != 0;
+ return b;
+}
+
+bool KAccel::insertItem( const QString& sLabel, const QString& sAction,
+ int key,
+ int /*nIDMenu*/, QPopupMenu*, bool bConfigurable )
+{
+ KShortcut cut;
+ cut.init( QKeySequence(key) );
+ KAccelAction* pAction = d->insert( sAction, sLabel, QString::null,
+ cut, cut,
+ 0, 0,
+ bConfigurable );
+ return pAction != 0;
+}
+
+// Used in kdeutils/kjots
+bool KAccel::insertStdItem( KStdAccel::StdAccel id, const QString& sLabel )
+{
+ KAccelAction* pAction = d->insert( KStdAccel::name( id ), sLabel, QString::null,
+ KStdAccel::shortcutDefault3( id ), KStdAccel::shortcutDefault4( id ),
+ 0, 0 );
+ if( pAction )
+ pAction->setShortcut( KStdAccel::shortcut( id ) );
+
+ return true;
+}
+
+bool KAccel::connectItem( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot, bool bActivate )
+{
+ kdDebug(125) << "KAccel::connectItem( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )" << endl;
+ if( bActivate == false )
+ d->setActionEnabled( sAction, false );
+ bool b = setSlot( sAction, pObjSlot, psMethodSlot );
+ if( bActivate == true )
+ d->setActionEnabled( sAction, true );
+ return b;
+}
+
+bool KAccel::removeItem( const QString& sAction )
+ { return d->removeAction( sAction ); }
+
+bool KAccel::setItemEnabled( const QString& sAction, bool bEnable )
+ { return setEnabled( sAction, bEnable ); }
+
+void KAccel::changeMenuAccel( QPopupMenu *menu, int id, const QString& action )
+{
+ KAccelAction* pAction = actions().actionPtr( action );
+ QString s = menu->text( id );
+ if( !pAction || s.isEmpty() )
+ return;
+
+ int i = s.find( '\t' );
+
+ QString k = pAction->shortcut().seq(0).toString();
+ if( k.isEmpty() )
+ return;
+
+ if ( i >= 0 )
+ s.replace( i+1, s.length()-i, k );
+ else {
+ s += '\t';
+ s += k;
+ }
+
+ QPixmap *pp = menu->pixmap(id);
+ if( pp && !pp->isNull() )
+ menu->changeItem( *pp, s, id );
+ else
+ menu->changeItem( s, id );
+}
+
+void KAccel::changeMenuAccel( QPopupMenu *menu, int id, KStdAccel::StdAccel accel )
+{
+ changeMenuAccel( menu, id, KStdAccel::name( accel ) );
+}
+
+int KAccel::stringToKey( const QString& sKey )
+{
+ return KKey( sKey ).keyCodeQt();
+}
+
+int KAccel::currentKey( const QString& sAction ) const
+{
+ KAccelAction* pAction = d->actionPtr( sAction );
+ if( pAction )
+ return pAction->shortcut().keyCodeQt();
+ return 0;
+}
+
+QString KAccel::findKey( int key ) const
+{
+ KAccelAction* pAction = d->actionPtr( KKey(key) );
+ if( pAction )
+ return pAction->name();
+ else
+ return QString::null;
+}
+#endif // !KDE_NO_COMPAT
+
+void KAccel::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kaccel.moc"
+#include "kaccelprivate.moc"
diff --git a/kdecore/kaccel.h b/kdecore/kaccel.h
new file mode 100644
index 000000000..84c938ea4
--- /dev/null
+++ b/kdecore/kaccel.h
@@ -0,0 +1,390 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KACCEL_H
+#define _KACCEL_H
+
+#include <qaccel.h>
+#include <kshortcut.h>
+#include <kstdaccel.h>
+#include "kdelibs_export.h"
+
+class QPopupMenu; // for obsolete insertItem() methods below
+class QWidget;
+class KAccelAction;
+class KAccelActions;
+class KConfigBase;
+
+class KAccelPrivate;
+/**
+ * Handle shortcuts.
+ *
+ * Allow a user to configure shortcuts
+ * through application configuration files or through the
+ * KKeyChooser GUI.
+ *
+ * A KAccel contains a list of accelerator actions.
+ *
+ * For example, CTRL+Key_P could be a shortcut for printing a document. The key
+ * codes are listed in qnamespace.h. "Print" could be the action name for printing.
+ * The action name identifies the shortcut in configuration files and the
+ * KKeyChooser GUI.
+ *
+ * A KAccel object handles key events sent to its parent widget and to all
+ * children of this parent widget. The most recently created KAccel object
+ * has precedence over any KAccel objects created before it.
+ * When a shortcut pressed, KAccel calls the slot to which it has been
+ * connected. If you want to set global accelerators, independent of the window
+ * which has the focus, use KGlobalAccel.
+ *
+ * Reconfiguration of a given shortcut can be prevented by specifying
+ * that an accelerator item is not configurable when it is inserted. A special
+ * group of non-configurable key bindings are known as the
+ * standard accelerators.
+ *
+ * The standard accelerators appear repeatedly in applications for
+ * standard document actions such as printing and saving. A convenience method is
+ * available to insert and connect these accelerators which are configurable on
+ * a desktop-wide basis.
+ *
+ * It is possible for a user to choose to have no key associated with
+ * an action.
+ *
+ * The translated first argument for insertItem() is used only
+ * in the configuration dialog.
+ *\code
+ * KAccel* pAccel = new KAccel( this );
+ *
+ * // Insert an action "Scroll Up" which is associated with the "Up" key:
+ * pAccel->insert( "Scroll Up", i18n("Scroll up"),
+ * i18n("Scroll up the current document by one line."),
+ * Qt::Key_Up, this, SLOT(slotScrollUp()) );
+ * // Insert an standard acclerator action.
+ * pAccel->insert( KStdAccel::Print, this, SLOT(slotPrint()) );
+ *
+ * // Update the shortcuts by read any user-defined settings from the
+ * // application's config file.
+ * pAccel->readSettings();
+ * \endcode
+ *
+ * @short Configurable shortcut support for widgets.
+ * @see KGlobalAccel
+ * @see KAccelShortcutList
+ * @see KKeyChooser
+ * @see KKeyDialog
+ */
+
+class KDECORE_EXPORT KAccel : public QAccel
+{
+ Q_OBJECT
+ public:
+ /**
+ * Creates a new KAccel that watches @p pParent, which is also
+ * the QObject's parent.
+ *
+ * @param pParent the parent and widget to watch for key strokes
+ * @param psName the name of the QObject
+ */
+ KAccel( QWidget* pParent, const char* psName = 0 );
+
+ /**
+ * Creates a new KAccel that watches @p watch.
+ *
+ * @param watch the widget to watch for key strokes
+ * @param parent the parent of the QObject
+ * @param psName the name of the QObject
+ */
+ KAccel( QWidget* watch, QObject* parent, const char* psName = 0 );
+ virtual ~KAccel();
+
+ /**
+ * @internal
+ * Returns the KAccel's @p KAccelActions, a list of @p KAccelAction.
+ * @return the KAccelActions of the KAccel
+ */
+ KAccelActions& actions();
+
+ /**
+ * @internal
+ * Returns the KAccel's @p KAccelActions, a list of @p KAccelAction.
+ * @return the KAccelActions of the KAccel
+ */
+ const KAccelActions& actions() const;
+
+ /**
+ * Checks whether the KAccel is active.
+ * @return true if the QAccel is enabled
+ */
+ bool isEnabled();
+
+ /**
+ * Enables or disables the KAccel.
+ * @param bEnabled true to enable, false to disable
+ */
+ void setEnabled( bool bEnabled );
+
+ /**
+ * Enable auto-update of connections. This means that the signals
+ * are automatically disconnected when you disable an action, and
+ * re-enabled when you enable it. By default auto update is turned
+ * on. If you disable auto-update, you need to call
+ * updateConnections() after changing actions.
+ *
+ * @param bAuto true to enable, false to disable
+ * @return the value of the flag before this call
+ */
+ bool setAutoUpdate( bool bAuto );
+
+ /**
+ * Create an accelerator action.
+ *
+ * Usage:
+ *\code
+ * insert( "Do Something", i18n("Do Something"),
+ * i18n("This action allows you to do something really great with this program to "
+ * "the currently open document."),
+ * ALT+Key_D, this, SLOT(slotDoSomething()) );
+ *\endcode
+ *
+ * @param sAction The internal name of the action.
+ * @param sLabel An i18n'ized short description of the action displayed when
+ * using KKeyChooser to reconfigure the shortcuts.
+ * @param sWhatsThis An extended description of the action.
+ * @param cutDef The default shortcut.
+ * @param pObjSlot Pointer to the slot object.
+ * @param psMethodSlot Pointer to the slot method.
+ * @param bConfigurable Allow the user to change this shortcut if set to 'true'.
+ * @param bEnabled The action will be activated by the shortcut if set to 'true'.
+ */
+ KAccelAction* insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable = true, bool bEnabled = true );
+ /**
+ * Same as first insert(), but with separate shortcuts defined for
+ * 3- and 4- modifier defaults.
+ */
+ KAccelAction* insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef3, const KShortcut& cutDef4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable = true, bool bEnabled = true );
+ /**
+ * This is an overloaded function provided for convenience.
+ * The advantage of this is when you want to use the same text for the name
+ * of the action as for the user-visible label.
+ *
+ * Usage:
+ * \code
+ * insert( i18n("Do Something"), ALT+Key_D, this, SLOT(slotDoSomething()) );
+ * \endcode
+ *
+ * @param psAction The name AND label of the action.
+ * @param cutDef The default shortcut for this action.
+ * @param pObjSlot Pointer to the slot object.
+ * @param psMethodSlot Pointer to the slot method.
+ * @param bConfigurable Allow the user to change this shortcut if set to 'true'.
+ * @param bEnabled The action will be activated by the shortcut if set to 'true'.
+ */
+ KAccelAction* insert( const char* psAction, const KShortcut& cutDef,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable = true, bool bEnabled = true );
+ /**
+ * Similar to the first insert() method, but with the action
+ * name, short description, help text, and default shortcuts all
+ * set according to one of the standard accelerators.
+ * @see KStdAccel.
+ */
+ KAccelAction* insert( KStdAccel::StdAccel id,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable = true, bool bEnabled = true );
+
+ /**
+ * Removes the accelerator action identified by the name.
+ * Remember to also call updateConnections().
+ * @param sAction the name of the action to remove
+ * @return true if successful, false otherwise
+ */
+ bool remove( const QString& sAction );
+
+ /**
+ * Updates the connections of the accelerations after changing them.
+ * This is only necessary if you have disabled auto updates which are
+ * on by default.
+ * @return true if successful, false otherwise
+ * @see setAutoUpdate()
+ * @see getAutoUpdate()
+ */
+ bool updateConnections();
+
+ /**
+ * Return the shortcut associated with the action named by @p sAction.
+ * @param sAction the name of the action
+ * @return the action's shortcut, or a null shortcut if not found
+ */
+ const KShortcut& shortcut( const QString& sAction ) const;
+
+ /**
+ * Set the shortcut to be associated with the action named by @p sAction.
+ * @param sAction the name of the action
+ * @param shortcut the shortcut to set
+ * @return true if successful, false otherwise
+ */
+ bool setShortcut( const QString& sAction, const KShortcut &shortcut );
+
+ /**
+ * Set the slot to be called when the shortcut of the action named
+ * by @p sAction is pressed.
+ * @param sAction the name of the action
+ * @param pObjSlot the owner of the slot
+ * @param psMethodSlot the name of the slot
+ * @return true if successful, false otherwise
+ */
+ bool setSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot );
+ /**
+ * Enable or disable the action named by @p sAction.
+ * @param sAction the action to en-/disable
+ * @param bEnabled true to enable, false to disable
+ * @return true if successful, false otherwise
+ */
+ bool setEnabled( const QString& sAction, bool bEnabled );
+
+ /**
+ * Returns the configuration group of the settings.
+ * @return the configuration group
+ * @see KConfig
+ */
+ const QString& configGroup() const;
+
+ /**
+ * Returns the configuration group of the settings.
+ * @param name the new configuration group
+ * @see KConfig
+ */
+ void setConfigGroup( const QString &name );
+
+ /**
+ * Read all shortcuts from @p pConfig, or (if @p pConfig
+ * is zero) from the application's configuration file
+ * KGlobal::config().
+ *
+ * The group in which the configuration is stored can be
+ * set with setConfigGroup().
+ * @param pConfig the configuration file, or 0 for the application
+ * configuration file
+ * @return true if successful, false otherwise
+ */
+ bool readSettings( KConfigBase* pConfig = 0 );
+ /**
+ * Write the current shortcuts to @p pConfig,
+ * or (if @p pConfig is zero) to the application's
+ * configuration file.
+ * @param pConfig the configuration file, or 0 for the application
+ * configuration file
+ * @return true if successful, false otherwise
+ */
+ bool writeSettings( KConfigBase* pConfig = 0 ) const;
+
+ /**
+ * Emits the keycodeChanged() signal.
+ */
+ void emitKeycodeChanged();
+
+ signals:
+ /**
+ * Emitted when one of the key codes has changed.
+ */
+ void keycodeChanged();
+
+#ifndef KDE_NO_COMPAT
+ public:
+ // Source compatibility to KDE 2.x
+ /**
+ * @deprecated use insert
+ */
+ bool insertItem( const QString& sLabel, const QString& sAction,
+ const char* psKey,
+ int nIDMenu = 0, QPopupMenu* pMenu = 0, bool bConfigurable = true ) KDE_DEPRECATED;
+ /**
+ * @deprecated use insert
+ */
+ bool insertItem( const QString& sLabel, const QString& sAction,
+ int key,
+ int nIDMenu = 0, QPopupMenu* pMenu = 0, bool bConfigurable = true ) KDE_DEPRECATED;
+ /**
+ * @deprecated use insert
+ */
+ bool insertStdItem( KStdAccel::StdAccel id, const QString& descr = QString::null ) KDE_DEPRECATED;
+ /**
+ * @deprecated use insert
+ */
+ bool connectItem( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot, bool bActivate = true ) KDE_DEPRECATED;
+ /**
+ * @deprecated use insert( accel, pObjSlot, psMethodSlot );
+ *
+ */
+ KDE_DEPRECATED bool connectItem( KStdAccel::StdAccel accel, const QObject* pObjSlot, const char* psMethodSlot )
+ { return insert( accel, pObjSlot, psMethodSlot ); }
+ /**
+ * @deprecated use remove
+ */
+ bool removeItem( const QString& sAction ) KDE_DEPRECATED;
+ /**
+ * @deprecated
+ */
+ bool setItemEnabled( const QString& sAction, bool bEnable ) KDE_DEPRECATED;
+ /**
+ * @deprecated see KDE3PORTING.html
+ */
+ void changeMenuAccel( QPopupMenu *menu, int id, const QString& action ) KDE_DEPRECATED;
+ /**
+ * @deprecated see KDE3PORTING.html
+ */
+ void changeMenuAccel( QPopupMenu *menu, int id, KStdAccel::StdAccel accel ) KDE_DEPRECATED;
+ /**
+ * @deprecated
+ */
+ static int stringToKey( const QString& ) KDE_DEPRECATED;
+
+ /**
+ * @deprecated Use shortcut().
+ *
+ * Retrieve the key code of the accelerator item with the action name
+ * @p action, or zero if either the action name cannot be
+ * found or the current key is set to no key.
+ */
+ int currentKey( const QString& action ) const KDE_DEPRECATED;
+
+ /**
+ * @deprecated Use actions().actionPtr().
+ *
+ * Return the name of the accelerator item with the keycode @p key,
+ * or QString::null if the item cannot be found.
+ */
+ QString findKey( int key ) const KDE_DEPRECATED;
+#endif // !KDE_NO_COMPAT
+
+ protected:
+ /** \internal */
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class KAccelPrivate* d;
+ friend class KAccelPrivate;
+};
+
+#endif // _KACCEL_H
diff --git a/kdecore/kaccelaction.cpp b/kdecore/kaccelaction.cpp
new file mode 100644
index 000000000..de805d2fc
--- /dev/null
+++ b/kdecore/kaccelaction.cpp
@@ -0,0 +1,565 @@
+/*
+ Copyright (C) 1998 Mark Donohoe <donohoe@kde.org>
+ Copyright (C) 1997-2000 Nicolas Hadacek <hadacek@kde.org>
+ Copyright (C) 1998 Matthias Ettrich <ettrich@kde.org>
+ Copyright (c) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kaccelaction.h"
+#include "kaccelbase.h" // for KAccelBase::slotRemoveAction() & emitSignal()
+
+#include <qkeycode.h>
+
+#include <kconfig.h>
+#include "kckey.h"
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kkeynative.h>
+#include <klocale.h>
+#include <kshortcutlist.h>
+
+//---------------------------------------------------------------------
+// KAccelAction
+//---------------------------------------------------------------------
+
+class KAccelActionPrivate
+{
+ public:
+ uint m_nConnections;
+};
+
+KAccelAction::KAccelAction()
+{
+ //kdDebug(125) << "KAccelAction(): this = " << this << endl;
+ d = new KAccelActionPrivate;
+ m_pObjSlot = 0;
+ m_psMethodSlot = 0;
+ m_bConfigurable = true;
+ m_bEnabled = true;
+ m_nIDAccel = 0;
+ d->m_nConnections = 0;
+}
+
+KAccelAction::KAccelAction( const KAccelAction& action )
+{
+ //kdDebug(125) << "KAccelAction( copy from \"" << action.m_sName << "\" ): this = " << this << endl;
+ d = new KAccelActionPrivate;
+ *this = action;
+}
+
+KAccelAction::KAccelAction( const QString& sName, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef3, const KShortcut& cutDef4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ //kdDebug(125) << "KAccelAction( \"" << sName << "\" ): this = " << this << endl;
+ d = new KAccelActionPrivate;
+ init( sName, sLabel, sWhatsThis,
+ cutDef3, cutDef4,
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+}
+
+KAccelAction::~KAccelAction()
+{
+ //kdDebug(125) << "\t\t\tKAccelAction::~KAccelAction( \"" << m_sName << "\" ): this = " << this << endl;
+ delete d;
+}
+
+void KAccelAction::clear()
+{
+ m_cut.clear();
+ m_pObjSlot = 0;
+ m_psMethodSlot = 0;
+ m_bConfigurable = true;
+ m_bEnabled = true;
+ m_nIDAccel = 0;
+ d->m_nConnections = 0;
+}
+
+bool KAccelAction::init( const QString& sName, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ m_sName = sName;
+ m_sLabel = sLabel;
+ m_sWhatsThis = sWhatsThis;
+ m_cutDefault3 = rgCutDefaults3;
+ m_cutDefault4 = rgCutDefaults4;
+ m_pObjSlot = pObjSlot;
+ m_psMethodSlot = psMethodSlot;
+ m_bConfigurable = bConfigurable;
+ m_bEnabled = bEnabled;
+ m_nIDAccel = 0;
+ m_cut = shortcutDefault();
+ d->m_nConnections = 0;
+ if( !m_bEnabled )
+ kdDebug(125) << "KAccelAction::init( \"" << sName << "\" ): created with enabled = false" << endl;
+ return true;
+}
+
+KAccelAction& KAccelAction::operator =( const KAccelAction& action )
+{
+ m_sName = action.m_sName;
+ m_sLabel = action.m_sLabel;
+ m_sWhatsThis = action.m_sWhatsThis;
+ m_cutDefault3 = action.m_cutDefault3;
+ m_cutDefault4 = action.m_cutDefault4;
+ m_pObjSlot = action.m_pObjSlot;
+ m_psMethodSlot = action.m_psMethodSlot;
+ m_bConfigurable = action.m_bConfigurable;
+ m_bEnabled = action.m_bEnabled;
+ m_nIDAccel = action.m_nIDAccel;
+ m_cut = action.m_cut;
+ d->m_nConnections = action.d->m_nConnections;
+
+ return *this;
+}
+
+void KAccelAction::setName( const QString& s )
+ { m_sName = s; }
+void KAccelAction::setLabel( const QString& s )
+ { m_sLabel = s; }
+void KAccelAction::setWhatsThis( const QString& s )
+ { m_sWhatsThis = s; }
+
+bool KAccelAction::setShortcut( const KShortcut& cut )
+{
+ m_cut = cut;
+ return true;
+}
+
+void KAccelAction::setSlot( const QObject* pObjSlot, const char* psMethodSlot )
+{
+ m_pObjSlot = pObjSlot;
+ m_psMethodSlot = psMethodSlot;
+}
+
+void KAccelAction::setConfigurable( bool b )
+ { m_bConfigurable = b; }
+void KAccelAction::setEnabled( bool b )
+ { m_bEnabled = b; }
+
+QString KAccelAction::toString() const
+ { return m_cut.toString(); }
+
+QString KAccelAction::toStringInternal() const
+ { return m_cut.toStringInternal( &shortcutDefault() ); }
+
+bool KAccelAction::setKeySequence( uint i, const KKeySequence& seq )
+{
+ if( i < m_cut.count() ) {
+ m_cut.setSeq( i, seq );
+ return true;
+ } else if( i == m_cut.count() )
+ return m_cut.append( seq );
+ return false;
+}
+
+void KAccelAction::clearShortcut()
+{
+ m_cut.clear();
+}
+
+bool KAccelAction::contains( const KKeySequence& seq )
+{
+ return m_cut.contains( seq );
+ for( uint i = 0; i < m_cut.count(); i++ ) {
+ if( m_cut.seq(i) == seq )
+ return true;
+ }
+ return false;
+}
+
+const KShortcut& KAccelAction::shortcutDefault() const
+ { return (useFourModifierKeys()) ? m_cutDefault4 : m_cutDefault3; }
+bool KAccelAction::isConnected() const
+ { return d->m_nConnections; }
+void KAccelAction::incConnections()
+ { d->m_nConnections++; }
+void KAccelAction::decConnections()
+ { if( d->m_nConnections > 0 ) d->m_nConnections--; }
+
+// Indicate whether to default to the 3- or 4- modifier keyboard schemes
+int KAccelAction::g_bUseFourModifierKeys = -1;
+
+bool KAccelAction::useFourModifierKeys()
+{
+ if( KAccelAction::g_bUseFourModifierKeys == -1 ) {
+ // Read in whether to use 4 modifier keys
+ KConfigGroupSaver cgs( KGlobal::config(), "Keyboard" );
+ bool b = KGlobal::config()->readBoolEntry( "Use Four Modifier Keys", false );
+ KAccelAction::g_bUseFourModifierKeys = b && KKeyNative::keyboardHasWinKey();
+ }
+ return KAccelAction::g_bUseFourModifierKeys == 1;
+}
+
+void KAccelAction::useFourModifierKeys( bool b )
+{
+ if( KAccelAction::g_bUseFourModifierKeys != (int)b ) {
+ KAccelAction::g_bUseFourModifierKeys = b && KKeyNative::keyboardHasWinKey();
+ // If we're 'turning off' the meta key or, if we're turning it on,
+ // the keyboard must actually have a meta key.
+ if( b && !KKeyNative::keyboardHasWinKey() )
+ kdDebug(125) << "Tried to use four modifier keys on a keyboard layout without a Meta key.\n";
+ }
+ KConfigGroupSaver cgs( KGlobal::config(), "Keyboard" );
+ KGlobal::config()->writeEntry( "Use Four Modifier Keys", KAccelAction::g_bUseFourModifierKeys, true, true);
+
+ kdDebug(125) << "bUseFourModifierKeys = " << KAccelAction::g_bUseFourModifierKeys << endl;
+}
+
+//---------------------------------------------------------------------
+// KAccelActions
+//---------------------------------------------------------------------
+
+class KAccelActionsPrivate
+{
+ public:
+};
+
+KAccelActions::KAccelActions()
+{
+ kdDebug(125) << "KAccelActions(): this = " << this << endl;
+ initPrivate( 0 );
+}
+
+KAccelActions::KAccelActions( const KAccelActions& actions )
+{
+ kdDebug(125) << "KAccelActions( actions = " << &actions << " ): this = " << this << endl;
+ initPrivate( 0 );
+ init( actions );
+}
+
+KAccelActions::KAccelActions( KAccelBase* pKAccelBase )
+{
+ kdDebug(125) << "KAccelActions( KAccelBase = " << pKAccelBase << " ): this = " << this << endl;
+ initPrivate( pKAccelBase );
+}
+
+KAccelActions::~KAccelActions()
+{
+ //kdDebug(125) << "KAccelActions::~KAccelActions(): this = " << this << endl;
+ clear();
+ //delete d;
+}
+
+void KAccelActions::initPrivate( KAccelBase* pKAccelBase )
+{
+ m_pKAccelBase = pKAccelBase;
+ m_nSizeAllocated = m_nSize = 0;
+ m_prgActions = 0;
+ //d = new KAccelActionsPrivate;
+}
+
+void KAccelActions::clear()
+{
+ kdDebug(125) << "\tKAccelActions::clear()" << endl;
+ for( uint i = 0; i < m_nSize; i++ )
+ delete m_prgActions[i];
+ delete[] m_prgActions;
+
+ m_nSizeAllocated = m_nSize = 0;
+ m_prgActions = 0;
+}
+
+bool KAccelActions::init( const KAccelActions& actions )
+{
+ clear();
+ resize( actions.count() );
+ for( uint i = 0; i < m_nSize; i++ ) {
+ KAccelAction* pAction = actions.m_prgActions[i];
+ if( pAction )
+ m_prgActions[i] = new KAccelAction( *pAction );
+ else
+ m_prgActions[i] = 0;
+ }
+
+ return true;
+}
+
+bool KAccelActions::init( KConfigBase& config, const QString& sGroup )
+{
+ kdDebug(125) << "KAccelActions::init( " << sGroup << " )" << endl;
+ QMap<QString, QString> mapEntry = config.entryMap( sGroup );
+ resize( mapEntry.count() );
+
+ QMap<QString, QString>::Iterator it( mapEntry.begin() );
+ for( uint i = 0; it != mapEntry.end(); ++it, i++ ) {
+ QString sShortcuts = *it;
+ KShortcut cuts;
+
+ kdDebug(125) << it.key() << " = " << sShortcuts << endl;
+ if( !sShortcuts.isEmpty() && sShortcuts != "none" )
+ cuts.init( sShortcuts );
+
+ m_prgActions[i] = new KAccelAction( it.key(), it.key(), it.key(),
+ cuts, cuts,
+ 0, 0, // pObjSlot, psMethodSlot,
+ true, false ); // bConfigurable, bEnabled
+ }
+
+ return true;
+}
+
+void KAccelActions::resize( uint nSize )
+{
+ if( nSize > m_nSizeAllocated ) {
+ uint nSizeAllocated = ((nSize/10) + 1) * 10;
+ KAccelAction** prgActions = new KAccelAction* [nSizeAllocated];
+
+ // Copy pointers over to new array
+ for( uint i = 0; i < m_nSizeAllocated; i++ )
+ prgActions[i] = m_prgActions[i];
+
+ // Null out new pointers
+ for( uint i = m_nSizeAllocated; i < nSizeAllocated; i++ )
+ prgActions[i] = 0;
+
+ delete[] m_prgActions;
+ m_prgActions = prgActions;
+ m_nSizeAllocated = nSizeAllocated;
+ }
+
+ m_nSize = nSize;
+}
+
+void KAccelActions::insertPtr( KAccelAction* pAction )
+{
+ resize( m_nSize + 1 );
+ m_prgActions[m_nSize-1] = pAction;
+}
+
+void KAccelActions::updateShortcuts( KAccelActions& actions2 )
+{
+ kdDebug(125) << "KAccelActions::updateShortcuts()" << endl;
+ bool bChanged = false;
+
+ for( uint i = 0; i < m_nSize; i++ ) {
+ KAccelAction* pAction = m_prgActions[i];
+ if( pAction && pAction->m_bConfigurable ) {
+ KAccelAction* pAction2 = actions2.actionPtr( pAction->m_sName );
+ if( pAction2 ) {
+ QString sOld = pAction->m_cut.toStringInternal();
+ pAction->m_cut = pAction2->m_cut;
+ kdDebug(125) << "\t" << pAction->m_sName
+ << " found: " << sOld
+ << " => " << pAction2->m_cut.toStringInternal()
+ << " = " << pAction->m_cut.toStringInternal() << endl;
+ bChanged = true;
+ }
+ }
+ }
+
+ if( bChanged )
+ emitKeycodeChanged();
+}
+
+int KAccelActions::actionIndex( const QString& sAction ) const
+{
+ for( uint i = 0; i < m_nSize; i++ ) {
+ if( m_prgActions[i] == 0 )
+ kdWarning(125) << "KAccelActions::actionPtr( " << sAction << " ): encountered null pointer at m_prgActions[" << i << "]" << endl;
+ else if( m_prgActions[i]->m_sName == sAction )
+ return (int) i;
+ }
+ return -1;
+}
+
+KAccelAction* KAccelActions::actionPtr( uint i )
+{
+ return m_prgActions[i];
+}
+
+const KAccelAction* KAccelActions::actionPtr( uint i ) const
+{
+ return m_prgActions[i];
+}
+
+KAccelAction* KAccelActions::actionPtr( const QString& sAction )
+{
+ int i = actionIndex( sAction );
+ return (i >= 0) ? m_prgActions[i] : 0;
+}
+
+const KAccelAction* KAccelActions::actionPtr( const QString& sAction ) const
+{
+ int i = actionIndex( sAction );
+ return (i >= 0) ? m_prgActions[i] : 0;
+}
+
+KAccelAction* KAccelActions::actionPtr( KKeySequence cut )
+{
+ for( uint i = 0; i < m_nSize; i++ ) {
+ if( m_prgActions[i] == 0 )
+ kdWarning(125) << "KAccelActions::actionPtr( " << cut.toStringInternal() << " ): encountered null pointer at m_prgActions[" << i << "]" << endl;
+ else if( m_prgActions[i]->contains( cut ) )
+ return m_prgActions[i];
+ }
+ return 0;
+}
+
+KAccelAction& KAccelActions::operator []( uint i )
+{
+ return *actionPtr( i );
+}
+
+const KAccelAction& KAccelActions::operator []( uint i ) const
+{
+ return *actionPtr( i );
+}
+
+KAccelAction* KAccelActions::insert( const QString& sName, const QString& sLabel )
+{
+ if( actionPtr( sName ) ) {
+ kdWarning(125) << "KAccelActions::insertLabel( " << sName << ", " << sLabel << " ): action with same name already present." << endl;
+ return 0;
+ }
+
+ KAccelAction* pAction = new KAccelAction;
+ pAction->m_sName = sName;
+ pAction->m_sLabel = sLabel;
+ pAction->m_bConfigurable = false;
+ pAction->m_bEnabled = false;
+
+ insertPtr( pAction );
+ return pAction;
+}
+
+KAccelAction* KAccelActions::insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ //kdDebug(125) << "KAccelActions::insert()2 begin" << endl;
+ if( actionPtr( sAction ) ) {
+ kdWarning(125) << "KAccelActions::insert( " << sAction << " ): action with same name already present." << endl;
+ return 0;
+ }
+
+ KAccelAction* pAction = new KAccelAction(
+ sAction, sLabel, sWhatsThis,
+ rgCutDefaults3, rgCutDefaults4,
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+ insertPtr( pAction );
+
+ //kdDebug(125) << "KAccelActions::insert()2 end" << endl;
+ return pAction;
+}
+
+bool KAccelActions::remove( const QString& sAction )
+{
+ kdDebug(125) << "KAccelActions::remove( \"" << sAction << "\" ): this = " << this << " m_pKAccelBase = " << m_pKAccelBase << endl;
+
+ int iAction = actionIndex( sAction );
+ if( iAction < 0 )
+ return false;
+
+ if( m_pKAccelBase )
+ m_pKAccelBase->slotRemoveAction( m_prgActions[iAction] );
+ delete m_prgActions[iAction];
+
+ for( uint i = iAction; i < m_nSize - 1; i++ )
+ m_prgActions[i] = m_prgActions[i+1];
+ m_nSize--;
+
+ return true;
+}
+
+bool KAccelActions::readActions( const QString& sConfigGroup, KConfigBase* pConfig )
+{
+ KAccelShortcutList accelList(*this, false);
+ return accelList.readSettings( sConfigGroup, pConfig );
+}
+
+/*
+ 1) KAccelAction = "Something"
+ 1) KKeySequence = "Meta+X,Asterisk"
+ 1) KAccelSequence = "Meta+X"
+ 1) KKeySequence = Meta+X
+ 2) KAccelSequence = "Asterisk"
+ 1) KKeySequence = Shift+8 (English layout)
+ 2) KKeySequence = Keypad_Asterisk
+ 2) KKeySequence = "Alt+F2"
+ 1) KAccelSequence = "Alt+F2"
+ 1) KKeySequence = Alt+F2
+ -> "Something=Meta+X,Asterisk;Alt+F2"
+*/
+bool KAccelActions::writeActions( const QString &sGroup, KConfigBase* pConfig,
+ bool bWriteAll, bool bGlobal ) const
+{
+ kdDebug(125) << "KAccelActions::writeActions( " << sGroup << ", " << pConfig << ", " << bWriteAll << ", " << bGlobal << " )" << endl;
+ if( !pConfig )
+ pConfig = KGlobal::config();
+ KConfigGroupSaver cs( pConfig, sGroup );
+
+ for( uint i = 0; i < m_nSize; i++ ) {
+ if( m_prgActions[i] == 0 ) {
+ kdWarning(125) << "KAccelActions::writeActions(): encountered null pointer at m_prgActions[" << i << "]" << endl;
+ continue;
+ }
+ const KAccelAction& action = *m_prgActions[i];
+
+ QString s;
+ bool bConfigHasAction = !pConfig->readEntry( action.m_sName ).isEmpty();
+ bool bSameAsDefault = true;
+ bool bWriteAction = false;
+
+ if( action.m_bConfigurable ) {
+ s = action.toStringInternal();
+ bSameAsDefault = (action.m_cut == action.shortcutDefault());
+
+ //if( bWriteAll && s.isEmpty() )
+ if( s.isEmpty() )
+ s = "none";
+
+ // If we're using a global config or this setting
+ // differs from the default, then we want to write.
+ if( bWriteAll || !bSameAsDefault )
+ bWriteAction = true;
+
+ if( bWriteAction ) {
+ kdDebug(125) << "\twriting " << action.m_sName << " = " << s << endl;
+ // Is passing bGlobal irrelevant, since if it's true,
+ // then we're using the global config anyway? --ellis
+ pConfig->writeEntry( action.m_sName, s, true, bGlobal );
+ }
+ // Otherwise, this key is the same as default
+ // but exists in config file. Remove it.
+ else if( bConfigHasAction ) {
+ kdDebug(125) << "\tremoving " << action.m_sName << " because == default" << endl;
+ pConfig->deleteEntry( action.m_sName, bGlobal );
+ }
+
+ }
+ }
+
+ pConfig->sync();
+ return true;
+}
+
+void KAccelActions::emitKeycodeChanged()
+{
+ if( m_pKAccelBase )
+ m_pKAccelBase->emitSignal( KAccelBase::KEYCODE_CHANGED );
+}
+
+uint KAccelActions::count() const
+ { return m_nSize; }
diff --git a/kdecore/kaccelaction.h b/kdecore/kaccelaction.h
new file mode 100644
index 000000000..4164ca518
--- /dev/null
+++ b/kdecore/kaccelaction.h
@@ -0,0 +1,576 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KACCELACTION_H
+#define _KACCELACTION_H
+
+#include <qmap.h>
+#include <qptrvector.h>
+#include <qstring.h>
+#include <qvaluevector.h>
+
+#include <kshortcut.h>
+
+class KAccelBase;
+
+class QObject;
+class KConfig;
+class KConfigBase;
+
+/**
+ * @internal
+ * A KAccelAction prepresents an action that can be executed using
+ * an accelerator key. Each KAccelAction has a name, a label, a
+ * "What's this" string and a KShortcut. The user can configure and
+ * enable/disable them using KKeyDialog.
+ *
+ * \code
+ * 1) KAccelAction = "Run Command"
+ * Default3 = "Alt+F2"
+ * Default4 = "Meta+Enter;Alt+F2"
+ * 1) KShortcut = "Meta+Enter"
+ * 1) KKeySequence = "Meta+Enter"
+ * 1) KKey = "Meta+Enter"
+ * 1) Meta+Enter
+ * 2) Meta+Keypad_Enter
+ * 2) KShortcut = "Alt+F2"
+ * 1) KKeySequence = "Alt+F2"
+ * 1) Alt+F2
+ * 2) KAccelAction = "Something"
+ * Default3 = ""
+ * Default4 = ""
+ * 1) KShortcut = "Meta+X,Asterisk"
+ * 1) KKeySequence = "Meta+X,Asterisk"
+ * 1) KKey = "Meta+X"
+ * 1) Meta+X
+ * 2) KKey = "Asterisk"
+ * 1) Shift+8 (English layout)
+ * 2) Keypad_Asterisk
+ * \endcode
+ * @short An accelerator action
+ * @see KAccel
+ * @see KGlobalAccel
+ * @see KKeyChooser
+ * @see KKeyDialog
+ */
+class KDECORE_EXPORT KAccelAction
+{
+ public:
+ /**
+ * Creates an empty KAccelAction.
+ * @see clear()
+ */
+ KAccelAction();
+
+ /**
+ * Copy constructor.
+ */
+ KAccelAction( const KAccelAction& );
+
+ /**
+ * Creates a new KAccelAction.
+ * @param sName the name of the accelerator
+ * @param sLabel the label of the accelerator (i18n!)
+ * @param sWhatsThis the What's This text (18n!)
+ * @param cutDef3 the default shortcut for 3 modifier systems
+ * @param cutDef4 the default shortcut for 4 modifier systems
+ * @param pObjSlot the receiver of a signal when the key has been
+ * pressed
+ * @param psMethodSlot the slot to connect for key presses. Receives
+ * an int, as set by setID(), as only argument
+ * @param bConfigurable if true the user can configure the shortcut
+ * @param bEnabled true if the accelerator should be enabled
+ */
+ KAccelAction( const QString& sName, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef3, const KShortcut& cutDef4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled );
+ ~KAccelAction();
+
+ /**
+ * Clears the accelerator.
+ */
+ void clear();
+
+ /**
+ * Re-initialized the KAccelAction.
+ * @param sName the name of the accelerator
+ * @param sLabel the label of the accelerator (i18n!)
+ * @param sWhatsThis the What's This text (18n!)
+ * @param cutDef3 the default shortcut for 3 modifier systems
+ * @param cutDef4 the default shortcut for 4 modifier systems
+ * @param pObjSlot the receiver of a signal when the key has been
+ * pressed
+ * @param psMethodSlot the slot to connect for key presses. Receives
+ * an int, as set by setID(), as only argument
+ * @param bConfigurable if true the user can configure the shortcut
+ * @param bEnabled true if the accelerator should be enabled
+ * @return true if successful, false otherwise
+ */
+ bool init( const QString& sName, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef3, const KShortcut& cutDef4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled );
+
+ /**
+ * Copies this KAccelAction.
+ */
+ KAccelAction& operator=( const KAccelAction& );
+
+ /**
+ * Returns the name of the accelerator action.
+ * @return the name of the accelerator action, can be null if not
+ * set
+ */
+ const QString& name() const { return m_sName; }
+
+ /**
+ * Returns the label of the accelerator action.
+ * @return the label of the accelerator action, can be null if
+ * not set
+ */
+ const QString& label() const { return m_sLabel; }
+
+ /**
+ * Returns the What's This text of the accelerator action.
+ * @return the What's This text of the accelerator action, can be
+ * null if not set
+ */
+ const QString& whatsThis() const { return m_sWhatsThis; }
+
+ /**
+ * The shortcut that is actually used (may be used configured).
+ * @return the shortcut of the KAccelAction, can be null if not set
+ * @see shortcutDefault()
+ */
+ const KShortcut& shortcut() const { return m_cut; }
+
+ /**
+ * The default shortcut for this system.
+ * @return the default shortcut on this system, can be null if not set
+ * @see shortcut()
+ * @see shortcutDefault3()
+ * @see shortcutDefault4()
+ */
+ const KShortcut& shortcutDefault() const;
+
+ /**
+ * The default shortcut for 3 modifier systems.
+ * @return the default shortcut for 3 modifier systems, can be null
+ * if not set
+ * @see shortcutDefault()
+ * @see shortcutDefault4()
+ * @see useFourModifierKeys()
+ */
+ const KShortcut& shortcutDefault3() const { return m_cutDefault3; }
+
+ /**
+ * The default shortcut for 4 modifier systems.
+ * @return the default shortcut for 4 modifier systems, can be null
+ * if not set
+ * @see shortcutDefault()
+ * @see shortcutDefault3()
+ * @see useFourModifierKeys()
+ */
+ const KShortcut& shortcutDefault4() const { return m_cutDefault4; }
+
+ /**
+ * Returns the receiver of signals.
+ * @return the receiver of signals (can be 0 if not set)
+ */
+ const QObject* objSlotPtr() const { return m_pObjSlot; }
+
+ /**
+ * Returns the slot for the signal.
+ * @return the slot for the signal
+ */
+ const char* methodSlotPtr() const { return m_psMethodSlot; }
+
+ /**
+ * Checks whether the user can configure the action.
+ * @return true if configurable, false otherwise
+ */
+ bool isConfigurable() const { return m_bConfigurable; }
+
+ /**
+ * Checks whether the action is enabled.
+ * @return true if enabled, false otherwise
+ */
+ bool isEnabled() const { return m_bEnabled; }
+
+ /**
+ * Sets the name of the accelerator action.
+ * @param name the new name
+ */
+ void setName( const QString& name );
+
+ /**
+ * Sets the user-readable label of the accelerator action.
+ * @param label the new label (i18n!)
+ */
+ void setLabel( const QString& label );
+
+ /**
+ * Sets the What's This text for the accelerator action.
+ * @param whatsThis the new What's This text (i18n!)
+ */
+ void setWhatsThis( const QString& whatsThis );
+
+ /**
+ * Sets the new shortcut of the accelerator action.
+ * @param rgCuts the shortcut to set
+ * @return true if successful, false otherwise
+ */
+ bool setShortcut( const KShortcut& rgCuts );
+
+ /**
+ * Sets the slot of the accelerator action.
+ * @param pObjSlot the receiver object of the signal
+ * @param psMethodSlot the slot for the signal
+ */
+ void setSlot( const QObject* pObjSlot, const char* psMethodSlot );
+
+ /**
+ * Enables or disabled configuring the action.
+ * @param configurable true to enable configurability, false to disable
+ */
+ void setConfigurable( bool configurable );
+
+ /**
+ * Enables or disabled the action.
+ * @param enable true to enable the action, false to disable
+ */
+ void setEnabled( bool enable );
+
+ /**
+ * Retrieves the id set using setID.
+ * @return the id of the accelerator action
+ */
+ int getID() const { return m_nIDAccel; }
+
+ /**
+ * Allows you to set an id that will be used as the action
+ * signal's argument.
+ *
+ * @param n the new id
+ * @see getID()
+ */
+ void setID( int n ) { m_nIDAccel = n; }
+
+ /**
+ * Checkes whether the action is connected (emits signals).
+ * @return true if connected, false otherwise
+ */
+ bool isConnected() const;
+
+ /**
+ * Sets a key sequence of the action's shortcut.
+ * @param i the position of the sequence
+ * @param keySeq the new new sequence
+ * @return true if successful, false otherwise
+ * @see KShortcut::setSeq()
+ */
+ bool setKeySequence( uint i, const KKeySequence &keySeq );
+
+ /**
+ * Clears the action's shortcut. It will not contain any sequences after
+ * calling this method.
+ * @see KShortcut::clear()
+ */
+ void clearShortcut();
+
+ /**
+ * Checks whether the action's shortcut contains the given key sequence.
+ * @param keySeq the key sequence to check
+ * @return true if the shortcut contains the given sequence
+ * @see KShortcut::contains()
+ */
+ bool contains( const KKeySequence &keySeq );
+
+ /**
+ * Returns the string representation of the action's shortcut.
+ * @return the string representation of the action's shortcut.
+ * @see KShortcut::toString()
+ */
+ QString toString() const;
+
+ /**
+ * @internal
+ */
+ QString toStringInternal() const;
+
+ /**
+ * Returns true if four modifier keys will be used.
+ * @return true if four modifier keys will be used.
+ */
+ static bool useFourModifierKeys();
+
+ /**
+ * Selects 3 or 4 modifier default shortcuts.
+ * @param use true to use 4 modifier shortcuts, false to use
+ * 3 modifier shortcuts
+ */
+ static void useFourModifierKeys( bool use );
+
+ protected:
+ QString m_sName /**< Name of accel. @sa setName() */,
+ m_sLabel /**< Label of accel. User-visible. */,
+ m_sWhatsThis /**< WhatsThis help for accel. User-visible. */;
+ KShortcut m_cut /**< Shortcut actually assigned. */;
+ KShortcut m_cutDefault3 /**< Default shortcut in 3-modifier layout */,
+ m_cutDefault4 /**< Default shortcur in 4-modifier layout */;
+ const QObject* m_pObjSlot /**< Object we will send signals to. */;
+ const char* m_psMethodSlot /**< Slot we send signals to, in m_pObjSlot */;
+ bool m_bConfigurable /**< Can this accel be configured by the user? */,
+ m_bEnabled /**< Is this accel enabled? */;
+ int m_nIDAccel /**< Id of this accel, from the list of IDs */;
+ uint m_nConnections /**< Number of connections to this accel. */ ;
+
+ /** @internal Increment the number of connections to this accel. */
+ void incConnections();
+ /** @internal Decrement the number of connections to this accel (bouded by zero). */
+ void decConnections();
+
+ private:
+ static int g_bUseFourModifierKeys;
+ class KAccelActionPrivate* d;
+
+ friend class KAccelActions;
+ friend class KAccelBase;
+};
+
+//---------------------------------------------------------------------
+// KAccelActions
+//---------------------------------------------------------------------
+
+/**
+ * @internal
+ * This class represents a collection of KAccelAction objects.
+ *
+ * @short A collection of accelerator actions
+ * @see KAccelAction
+ */
+class KDECORE_EXPORT KAccelActions
+{
+ public:
+ /**
+ * Creates a new, empty KAccelActions object.
+ */
+ KAccelActions();
+
+ /**
+ * Copy constructor (deep copy).
+ */
+ KAccelActions( const KAccelActions& );
+ virtual ~KAccelActions();
+
+ /**
+ * Removes all items from this collection.
+ */
+ void clear();
+
+ /**
+ * Initializes this object with the given actions.
+ * It will make a deep copy of all actions.
+ * @param actions the actions to copy
+ * @return true if successful, false otherwise
+ */
+ bool init( const KAccelActions &actions );
+
+ /**
+ * Loads the actions from the given configuration file.
+ *
+ * @param config the configuration file to load from
+ * @param sGroup the group in the configuration file
+ * @return true if successful, false otherwise
+ */
+ bool init( KConfigBase& config, const QString& sGroup );
+
+ /**
+ * Updates the shortcuts of all actions in this object
+ * with the shortcuts from the given object.
+ * @param shortcuts the collection that contains the new
+ * shortcuts
+ */
+ void updateShortcuts( KAccelActions &shortcuts );
+
+ /**
+ * Retrieves the index of the action with the given name.
+ * @param sAction the action to search
+ * @return the index of the action, or -1 if not found
+ */
+ int actionIndex( const QString& sAction ) const;
+
+ /**
+ * Returns the action with the given @p index.
+ * @param index the index of an action. You must not
+ * use an index that is too high.
+ * @return the KAccelAction with the given index
+ * @see count()
+ */
+ KAccelAction* actionPtr( uint index );
+
+ /**
+ * Returns the action with the given @p index.
+ * @param index the index of an action. You must not
+ * use an index that is too high.
+ * @return the KAccelAction with the given index
+ * @see count()
+ */
+ const KAccelAction* actionPtr( uint index ) const;
+
+ /**
+ * Returns the action with the given name.
+ * @param sAction the name of the action to search
+ * @return the KAccelAction with the given name, or 0
+ * if not found
+ */
+ KAccelAction* actionPtr( const QString& sAction );
+
+ /**
+ * Returns the action with the given name.
+ * @param sAction the name of the action to search
+ * @return the KAccelAction with the given name, or 0
+ * if not found
+ */
+ const KAccelAction* actionPtr( const QString& sAction ) const;
+
+ /**
+ * Returns the action with the given key sequence.
+ * @param cut the sequence to search for
+ * @return the KAccelAction with the given sequence, or 0
+ * if not found
+ */
+ KAccelAction* actionPtr( KKeySequence cut );
+
+ /**
+ * Returns the action with the given @p index.
+ * @param index the index of an action. You must not
+ * use an index that is too high.
+ * @return the KAccelAction with the given index
+ * @see actionPtr()
+ * @see count()
+ */
+ KAccelAction& operator []( uint index );
+
+ /**
+ * Returns the action with the given @p index.
+ * @param index the index of an action. You must not
+ * use an index that is too high.
+ * @return the KAccelAction with the given index
+ * @see actionPtr()
+ * @see count()
+ */
+ const KAccelAction& operator []( uint index ) const;
+
+ /**
+ * Inserts an action into the collection.
+ * @param sAction the name of the accelerator
+ * @param sLabel the label of the accelerator (i18n!)
+ * @param sWhatsThis the What's This text (18n!)
+ * @param rgCutDefaults3 the default shortcut for 3 modifier systems
+ * @param rgCutDefaults4 the default shortcut for 4 modifier systems
+ * @param pObjSlot the receiver of a signal when the key has been
+ * pressed
+ * @param psMethodSlot the slot to connect for key presses. Receives
+ * an int, as set by setID(), as only argument
+ * @param bConfigurable if true the user can configure the shortcut
+ * @param bEnabled if true the accelerator should be enabled
+ * @return the new action
+ */
+ KAccelAction* insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4,
+ const QObject* pObjSlot = 0, const char* psMethodSlot = 0,
+ bool bConfigurable = true, bool bEnabled = true );
+
+ /**
+ * Inserts an action into the collection.
+ * @param sName the name of the accelerator
+ * @param sLabel the label of the accelerator (i18n!)
+ * @return the new action
+ */
+ KAccelAction* insert( const QString& sName, const QString& sLabel );
+
+ /**
+ * Removes the given action.
+ * @param sAction the name of the action.
+ * @return true if successful, false otherwise
+ */
+ bool remove( const QString& sAction );
+
+ /**
+ * Loads the actions from the given configuration file.
+ *
+ * @param sConfigGroup the group in the configuration file
+ * @param pConfig the configuration file to load from
+ * @return true if successful, false otherwise
+ */
+ bool readActions( const QString& sConfigGroup = "Shortcuts", KConfigBase* pConfig = 0 );
+
+ /**
+ * Writes the actions to the given configuration file.
+ *
+ * @param sConfigGroup the group in the configuration file
+ * @param pConfig the configuration file to save to
+ * @param bWriteAll true to write all actions
+ * @param bGlobal true to write to the global configuration file
+ * @return true if successful, false otherwise
+ */
+ bool writeActions( const QString& sConfigGroup = "Shortcuts", KConfigBase* pConfig = 0,
+ bool bWriteAll = false, bool bGlobal = false ) const;
+
+ /**
+ * Emit a keycodeChanged signal.
+ */
+ void emitKeycodeChanged();
+
+ /**
+ * Returns the number of actions in the collection.
+ * @return the number of actions
+ */
+ uint count() const;
+
+ protected:
+ /** Base object that proxies signals from us. */
+ KAccelBase* m_pKAccelBase;
+ /** Array of actions we're hanging on to. */
+ KAccelAction** m_prgActions;
+ uint m_nSizeAllocated /**< Allocated size of the array. */,
+ m_nSize /**< Amount in use. */ ;
+
+ /**
+ * Resize the list to the given number @p new_size of entries.
+ * @todo Can you make it smaller?
+ * @todo Implementation seems to break m_nSize.
+ */
+ void resize( uint new_size );
+ /** Add a action to this collection. @todo Document ownership. */
+ void insertPtr( KAccelAction* );
+
+ private:
+ class KAccelActionsPrivate* d;
+
+ KAccelActions( KAccelBase* );
+ void initPrivate( KAccelBase* );
+ KAccelActions& operator =( KAccelActions& );
+
+ friend class KAccelBase;
+};
+
+#endif // _KACCELACTION_H
diff --git a/kdecore/kaccelbase.cpp b/kdecore/kaccelbase.cpp
new file mode 100644
index 000000000..d8d0c36da
--- /dev/null
+++ b/kdecore/kaccelbase.cpp
@@ -0,0 +1,616 @@
+/*
+ Copyright (C) 1997-2000 Nicolas Hadacek <hadacek@kde.org>
+ Copyright (C) 1998 Mark Donohoe <donohoe@kde.org>
+ Copyright (C) 1998 Matthias Ettrich <ettrich@kde.org>
+ Copyright (c) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kaccelbase.h"
+
+#include <qkeycode.h>
+#include <qlabel.h>
+#include <qpopupmenu.h>
+
+#include <kconfig.h>
+#include "kckey.h"
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kkeynative.h>
+#include "kkeyserver.h"
+#include <klocale.h>
+#include "kshortcutmenu.h"
+
+//---------------------------------------------------------------------
+// class KAccelBase::ActionInfo
+//---------------------------------------------------------------------
+
+//---------------------------------------------------------------------
+// class KAccelBase
+//---------------------------------------------------------------------
+
+KAccelBase::KAccelBase( int fInitCode )
+: m_rgActions( this )
+{
+ kdDebug(125) << "KAccelBase(): this = " << this << endl;
+ m_bNativeKeys = fInitCode & NATIVE_KEYS;
+ m_bEnabled = true;
+ m_sConfigGroup = "Shortcuts";
+ m_bConfigIsGlobal = false;
+ m_bAutoUpdate = false;
+ mtemp_pActionRemoving = 0;
+}
+
+KAccelBase::~KAccelBase()
+{
+ kdDebug(125) << "~KAccelBase(): this = " << this << endl;
+}
+
+uint KAccelBase::actionCount() const { return m_rgActions.count(); }
+KAccelActions& KAccelBase::actions() { return m_rgActions; }
+bool KAccelBase::isEnabled() const { return m_bEnabled; }
+// see KGlobalAccel::blockShortcuts() stuff - it's to temporarily block
+// all global shortcuts, so that the key grabs are released, but from the app's
+// point of view the KGlobalAccel is still enabled, so KGlobalAccel needs
+// to disable key grabbing even if enabled
+bool KAccelBase::isEnabledInternal() const { return isEnabled(); }
+
+KAccelAction* KAccelBase::actionPtr( const QString& sAction )
+ { return m_rgActions.actionPtr( sAction ); }
+
+const KAccelAction* KAccelBase::actionPtr( const QString& sAction ) const
+ { return m_rgActions.actionPtr( sAction ); }
+
+KAccelAction* KAccelBase::actionPtr( const KKeyServer::Key& key )
+{
+ if( !m_mapKeyToAction.contains( key ) )
+ return 0;
+ // Note: If more than one action is connected to a single key, nil will be returned.
+ return m_mapKeyToAction[key].pAction;
+}
+
+KAccelAction* KAccelBase::actionPtr( const KKey& key )
+{
+ KKeyServer::Key k2;
+ k2.init( key, !m_bNativeKeys );
+ return actionPtr( k2 );
+}
+
+void KAccelBase::setConfigGroup( const QString& sConfigGroup )
+ { m_sConfigGroup = sConfigGroup; }
+
+void KAccelBase::setConfigGlobal( bool global )
+ { m_bConfigIsGlobal = global; }
+
+bool KAccelBase::setActionEnabled( const QString& sAction, bool bEnable )
+{
+ KAccelAction* pAction = actionPtr( sAction );
+ if( pAction ) {
+ if( pAction->m_bEnabled != bEnable ) {
+ kdDebug(125) << "KAccelBase::setActionEnabled( " << sAction << ", " << bEnable << " )" << endl;
+ pAction->m_bEnabled = bEnable;
+ if( m_bAutoUpdate ) {
+ // FIXME: the action may already have it's connections inserted!
+ if( bEnable )
+ insertConnection( pAction );
+ else if( pAction->isConnected() )
+ removeConnection( pAction );
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool KAccelBase::setAutoUpdate( bool bAuto )
+{
+ kdDebug(125) << "KAccelBase::setAutoUpdate( " << bAuto << " ): m_bAutoUpdate on entrance = " << m_bAutoUpdate << endl;
+ bool b = m_bAutoUpdate;
+ if( !m_bAutoUpdate && bAuto )
+ updateConnections();
+ m_bAutoUpdate = bAuto;
+ return b;
+}
+
+KAccelAction* KAccelBase::insert( const QString& sAction, const QString& sDesc, const QString& sHelp,
+ const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ //kdDebug(125) << "KAccelBase::insert() begin" << endl;
+ KAccelAction* pAction = m_rgActions.insert(
+ sAction, sDesc, sHelp,
+ rgCutDefaults3, rgCutDefaults4,
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+
+ if( pAction && m_bAutoUpdate )
+ insertConnection( pAction );
+
+ //kdDebug(125) << "KAccelBase::insert() end" << endl;
+ return pAction;
+}
+
+KAccelAction* KAccelBase::insert( const QString& sName, const QString& sDesc )
+ { return m_rgActions.insert( sName, sDesc ); }
+
+bool KAccelBase::remove( const QString& sAction )
+{
+ return m_rgActions.remove( sAction );
+}
+
+void KAccelBase::slotRemoveAction( KAccelAction* pAction )
+{
+ removeConnection( pAction );
+}
+
+bool KAccelBase::setActionSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot )
+{
+ kdDebug(125) << "KAccelBase::setActionSlot( " << sAction << ", " << pObjSlot << ", " << psMethodSlot << " )\n";
+ KAccelAction* pAction = m_rgActions.actionPtr( sAction );
+ if( pAction ) {
+ // If there was a previous connection, remove it.
+ if( m_bAutoUpdate && pAction->isConnected() ) {
+ kdDebug(125) << "\tm_pObjSlot = " << pAction->m_pObjSlot << " m_psMethodSlot = " << pAction->m_psMethodSlot << endl;
+ removeConnection( pAction );
+ }
+
+ pAction->m_pObjSlot = pObjSlot;
+ pAction->m_psMethodSlot = psMethodSlot;
+
+ // If we're setting a connection,
+ if( m_bAutoUpdate && pObjSlot && psMethodSlot )
+ insertConnection( pAction );
+
+ return true;
+ } else
+ return false;
+}
+
+/*
+KAccelBase
+ Run Command=Meta+Enter;Alt+F2
+ KAccelAction = "Run Command"
+ 1) KAccelKeySeries = "Meta+Enter"
+ 1a) Meta+Enter
+ 1b) Meta+Keypad_Enter
+ 2) KAccelKeySeries = "Alt+F2"
+ 1a) Alt+F2
+
+ Konqueror=Meta+I,I
+ KAccelAction = "Konqueror"
+ 1) KAccelKeySeries = "Meta+I,I"
+ 1a) Meta+I
+ 2a) I
+
+ Something=Meta+Asterisk,X
+ KAccelAction = "Something"
+ 1) KAccelKeySeries = "Meta+Asterisk,X"
+ 1a) Meta+Shift+8
+ 1b) Meta+Keypad_8
+ 2a) X
+
+read in a config entry
+ split by ';'
+ find key sequences to disconnect
+ find new key sequences to connect
+check for conflicts with implicit keys
+ disconnect conflicting implicit keys
+connect new key sequences
+*/
+/*
+{
+ For {
+ for( KAccelAction::iterator itAction = m_rgActions.begin(); itAction != m_rgActions.end(); ++itAction ) {
+ KAccelAction& action = *itAction;
+ for( KAccelSeries::iterator itSeries = action.m_rgSeries.begin(); itSeries != action.m_rgSeries.end(); ++itSeries ) {
+ KAccelSeries& series = *itSeries;
+ if(
+ }
+ }
+ }
+ Sort by: iVariation, iSequence, iSeries, iAction
+
+ 1) KAccelAction = "Run Command"
+ 1) KAccelKeySeries = "Meta+Enter"
+ 1a) Meta+Enter
+ 1b) Meta+Keypad_Enter
+ 2) KAccelKeySeries = "Alt+F2"
+ 1a) Alt+F2
+
+ 2) KAccelAction = "Enter Calculation"
+ 1) KAccelKeySeries = "Meta+Keypad_Enter"
+ 1a) Meta+Keypad_Enter
+
+ List =
+ Meta+Enter -> 1, 1, 1a
+ Meta+Keypad_Enter -> 2, 1, 1a
+ Alt+F2 -> 1, 2, 1a
+ [Meta+Keypad_Enter] -> [1, 1, 1b]
+
+}
+*/
+
+#ifdef Q_WS_X11
+struct KAccelBase::X
+{
+ uint iAction, iSeq, iVari;
+ KKeyServer::Key key;
+
+ X() {}
+ X( uint _iAction, uint _iSeq, uint _iVari, const KKeyServer::Key& _key )
+ { iAction = _iAction; iSeq = _iSeq; iVari = _iVari; key = _key; }
+
+ int compare( const X& x )
+ {
+ int n = key.compare( x.key );
+ if( n != 0 ) return n;
+ if( iVari != x.iVari ) return iVari - x.iVari;
+ if( iSeq != x.iSeq ) return iSeq - x.iSeq;
+ return 0;
+ }
+
+ bool operator <( const X& x ) { return compare( x ) < 0; }
+ bool operator >( const X& x ) { return compare( x ) > 0; }
+ bool operator <=( const X& x ) { return compare( x ) <= 0; }
+};
+#endif //Q_WS_X11
+
+/*
+#1 Ctrl+A
+#2 Ctrl+A
+#3 Ctrl+B
+ ------
+ Ctrl+A => Null
+ Ctrl+B => #3
+
+#1 Ctrl+A
+#1 Ctrl+B;Ctrl+A
+ ------
+ Ctrl+A => #1
+ Ctrl+B => #2
+
+#1 Ctrl+A
+#1 Ctrl+B,C
+#1 Ctrl+B,D
+ ------
+ Ctrl+A => #1
+ Ctrl+B => Null
+
+#1 Ctrl+A
+#2 Ctrl+Plus(Ctrl+KP_Add)
+ ------
+ Ctrl+A => #1
+ Ctrl+Plus => #2
+ Ctrl+KP_Add => #2
+
+#1 Ctrl+Plus(Ctrl+KP_Add)
+#2 Ctrl+KP_Add
+ ------
+ Ctrl+Plus => #1
+ Ctrl+KP_Add => #2
+
+#1 Ctrl+Plus(Ctrl+KP_Add)
+#2 Ctrl+A;Ctrl+KP_Add
+ ------
+ Ctrl+A => #2
+ Ctrl+Plus => #1
+ Ctrl+KP_Add => #2
+*/
+
+bool KAccelBase::updateConnections()
+{
+#ifdef Q_WS_X11
+ kdDebug(125) << "KAccelBase::updateConnections() this = " << this << endl;
+ // Retrieve the list of keys to be connected, sorted by priority.
+ // (key, variation, seq)
+ QValueVector<X> rgKeys;
+ createKeyList( rgKeys );
+ m_rgActionsNonUnique.clear();
+
+ KKeyToActionMap mapKeyToAction;
+ for( uint i = 0; i < rgKeys.size(); i++ ) {
+ X& x = rgKeys[i];
+ KKeyServer::Key& key = x.key;
+ ActionInfo info;
+ bool bNonUnique = false;
+
+ info.pAction = m_rgActions.actionPtr( x.iAction );
+ info.iSeq = x.iSeq;
+ info.iVariation = x.iVari;
+
+ // If this is a multi-key shortcut,
+ if( info.pAction->shortcut().seq(info.iSeq).count() > 1 )
+ bNonUnique = true;
+ // If this key is requested by more than one action,
+ else if( i < rgKeys.size() - 1 && key == rgKeys[i+1].key ) {
+ // If multiple actions requesting this key
+ // have the same priority as the first one,
+ if( info.iVariation == rgKeys[i+1].iVari && info.iSeq == rgKeys[i+1].iSeq )
+ bNonUnique = true;
+
+ kdDebug(125) << "key conflict = " << key.key().toStringInternal()
+ << " action1 = " << info.pAction->name()
+ << " action2 = " << m_rgActions.actionPtr( rgKeys[i+1].iAction )->name()
+ << " non-unique = " << bNonUnique << endl;
+
+ // Skip over the other records with this same key.
+ while( i < rgKeys.size() - 1 && key == rgKeys[i+1].key )
+ i++;
+ }
+
+ if( bNonUnique ) {
+ // Remove connection to single action if there is one
+ if( m_mapKeyToAction.contains( key ) ) {
+ KAccelAction* pAction = m_mapKeyToAction[key].pAction;
+ if( pAction ) {
+ m_mapKeyToAction.remove( key );
+ disconnectKey( *pAction, key );
+ pAction->decConnections();
+ m_rgActionsNonUnique.append( pAction );
+ }
+ }
+ // Indicate that no single action is associated with this key.
+ m_rgActionsNonUnique.append( info.pAction );
+ info.pAction = 0;
+ }
+
+ //kdDebug(125) << "mapKeyToAction[" << key.toStringInternal() << "] = " << info.pAction << endl;
+ mapKeyToAction[key] = info;
+ }
+
+ // Disconnect keys which no longer have bindings:
+ for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
+ const KKeyServer::Key& key = it.key();
+ KAccelAction* pAction = (*it).pAction;
+ // If this key is longer used or it points to a different action now,
+ if( !mapKeyToAction.contains( key ) || mapKeyToAction[key].pAction != pAction ) {
+ if( pAction ) {
+ disconnectKey( *pAction, key );
+ pAction->decConnections();
+ } else
+ disconnectKey( key );
+ }
+ }
+
+ // Connect any unconnected keys:
+ // In other words, connect any keys which are present in the
+ // new action map, but which are _not_ present in the old one.
+ for( KKeyToActionMap::iterator it = mapKeyToAction.begin(); it != mapKeyToAction.end(); ++it ) {
+ const KKeyServer::Key& key = it.key();
+ KAccelAction* pAction = (*it).pAction;
+ if( !m_mapKeyToAction.contains( key ) || m_mapKeyToAction[key].pAction != pAction ) {
+ // TODO: Decide what to do if connect fails.
+ // Probably should remove this item from map.
+ if( pAction ) {
+ if( connectKey( *pAction, key ) )
+ pAction->incConnections();
+ } else
+ connectKey( key );
+ }
+ }
+
+ // Store new map.
+ m_mapKeyToAction = mapKeyToAction;
+
+#ifndef NDEBUG
+ for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
+ kdDebug(125) << "Key: " << it.key().key().toStringInternal() << " => '"
+ << (((*it).pAction) ? (*it).pAction->name() : QString::null) << "'" << endl;
+ }
+#endif
+#endif //Q_WS_X11
+ return true;
+}
+
+#ifdef Q_WS_X11
+// Construct a list of keys to be connected, sorted highest priority first.
+void KAccelBase::createKeyList( QValueVector<struct X>& rgKeys )
+{
+ //kdDebug(125) << "KAccelBase::createKeyList()" << endl;
+ if( !isEnabledInternal())
+ return;
+
+ // create the list
+ // For each action
+ for( uint iAction = 0; iAction < m_rgActions.count(); iAction++ ) {
+ KAccelAction* pAction = m_rgActions.actionPtr( iAction );
+ if( pAction && pAction->m_pObjSlot && pAction->m_psMethodSlot && pAction != mtemp_pActionRemoving ) {
+ // For each key sequence associated with action
+ for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
+ const KKeySequence& seq = pAction->shortcut().seq(iSeq);
+ if( seq.count() > 0 ) {
+ KKeyServer::Variations vars;
+ vars.init( seq.key(0), !m_bNativeKeys );
+ for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
+ if( vars.key(iVari).code() && vars.key(iVari).sym() )
+ rgKeys.push_back( X( iAction, iSeq, iVari, vars.key( iVari ) ) );
+ //kdDebug(125) << "\t" << pAction->name() << ": " << vars.key(iVari).toStringInternal() << endl;
+ }
+ }
+ //else
+ // kdDebug(125) << "\t*" << pAction->name() << ":" << endl;
+ }
+ }
+ }
+
+ // sort by priority: iVariation[of first key], iSequence, iAction
+ qHeapSort( rgKeys.begin(), rgKeys.end() );
+}
+#endif //Q_WS_X11
+
+bool KAccelBase::insertConnection( KAccelAction* pAction )
+{
+ if( !pAction->m_pObjSlot || !pAction->m_psMethodSlot )
+ return true;
+
+ kdDebug(125) << "KAccelBase::insertConnection( " << pAction << "=\"" << pAction->m_sName << "\"; shortcut = " << pAction->shortcut().toStringInternal() << " ) this = " << this << endl;
+
+ // For each sequence associated with the given action:
+ for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
+ // Get the first key of the sequence.
+ KKeyServer::Variations vars;
+ vars.init( pAction->shortcut().seq(iSeq).key(0), !m_bNativeKeys );
+ for( uint iVari = 0; iVari < vars.count(); iVari++ ) {
+ const KKeyServer::Key& key = vars.key( iVari );
+
+ //if( !key.isNull() ) {
+ if( key.sym() ) {
+ if( !m_mapKeyToAction.contains( key ) ) {
+ // If this is a single-key shortcut,
+ if( pAction->shortcut().seq(iSeq).count() == 1 ) {
+ m_mapKeyToAction[key] = ActionInfo( pAction, iSeq, iVari );
+ if( connectKey( *pAction, key ) )
+ pAction->incConnections();
+ }
+ // Else this is a multi-key shortcut,
+ else {
+ m_mapKeyToAction[key] = ActionInfo( 0, 0, 0 );
+ // Insert into non-unique list if it's not already there.
+ if( m_rgActionsNonUnique.findIndex( pAction ) == -1 )
+ m_rgActionsNonUnique.append( pAction );
+ if( connectKey( key ) )
+ pAction->incConnections();
+ }
+ } else {
+ // There is a key conflict. A full update
+ // check is necessary.
+ // TODO: make this more efficient where possible.
+ if( m_mapKeyToAction[key].pAction != pAction
+ && m_mapKeyToAction[key].pAction != 0 ) {
+ kdDebug(125) << "Key conflict with action = " << m_mapKeyToAction[key].pAction->name()
+ << " key = " << key.key().toStringInternal() << " : call updateConnections()" << endl;
+ return updateConnections();
+ }
+ }
+ }
+ }
+ }
+
+ //kdDebug(125) << "\tActions = " << m_rgActions.size() << endl;
+ //for( KAccelActions::const_iterator it = m_rgActions.begin(); it != m_rgActions.end(); ++it ) {
+ // kdDebug(125) << "\t" << &(*it) << " '" << (*it).m_sName << "'" << endl;
+ //}
+
+ //kdDebug(125) << "\tKeys = " << m_mapKeyToAction.size() << endl;
+ //for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it ) {
+ // //kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << (*it)->m_sName << "'" << endl;
+ // kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << *it << "'" << endl;
+ // kdDebug(125) << "\t\t'" << (*it)->m_sName << "'" << endl;
+ //}
+
+ return true;
+}
+
+bool KAccelBase::removeConnection( KAccelAction* pAction )
+{
+ kdDebug(125) << "KAccelBase::removeConnection( " << pAction << " = \"" << pAction->m_sName << "\"; shortcut = " << pAction->m_cut.toStringInternal() << " ): this = " << this << endl;
+
+ //for( KKeyToActionMap::iterator it = m_mapKeyToAction.begin(); it != m_mapKeyToAction.end(); ++it )
+ // kdDebug(125) << "\tKey: " << it.key().toString() << " => '" << (*it)->m_sName << "'" << " " << *it << endl;
+
+ if( m_rgActionsNonUnique.findIndex( pAction ) >= 0 ) {
+ mtemp_pActionRemoving = pAction;
+ bool b = updateConnections();
+ mtemp_pActionRemoving = 0;
+ return b;
+ }
+
+ KKeyToActionMap::iterator it = m_mapKeyToAction.begin();
+ while( it != m_mapKeyToAction.end() ) {
+ KKeyServer::Key key = it.key();
+ ActionInfo* pInfo = &(*it);
+
+ // If the given action is connected to this key,
+ if( pAction == pInfo->pAction ) {
+ disconnectKey( *pAction, key );
+ pAction->decConnections();
+
+ KKeyToActionMap::iterator itRemove = it++;
+ m_mapKeyToAction.remove( itRemove );
+ } else
+ ++it;
+ }
+ return true;
+}
+
+bool KAccelBase::setShortcut( const QString& sAction, const KShortcut& cut )
+{
+ KAccelAction* pAction = actionPtr( sAction );
+ if( pAction ) {
+ if( m_bAutoUpdate )
+ removeConnection( pAction );
+
+ pAction->setShortcut( cut );
+
+ if( m_bAutoUpdate && !pAction->shortcut().isNull() )
+ insertConnection( pAction );
+ return true;
+ } else
+ return false;
+}
+
+void KAccelBase::readSettings( KConfigBase* pConfig )
+{
+ m_rgActions.readActions( m_sConfigGroup, pConfig );
+ if( m_bAutoUpdate )
+ updateConnections();
+}
+
+void KAccelBase::writeSettings( KConfigBase* pConfig ) const
+{
+ m_rgActions.writeActions( m_sConfigGroup, pConfig, m_bConfigIsGlobal, m_bConfigIsGlobal );
+}
+
+QPopupMenu* KAccelBase::createPopupMenu( QWidget* pParent, const KKeySequence& seq )
+{
+ KShortcutMenu* pMenu = new KShortcutMenu( pParent, &actions(), seq );
+
+ bool bActionInserted = false;
+ bool bInsertSeparator = false;
+ for( uint i = 0; i < actionCount(); i++ ) {
+ const KAccelAction* pAction = actions().actionPtr( i );
+
+ if( !pAction->isEnabled() )
+ continue;
+
+ // If an action has already been inserted into the menu
+ // and we have a label instead of an action here,
+ // then indicate that we should insert a separator before the next menu entry.
+ if( bActionInserted && !pAction->isConfigurable() && pAction->name().contains( ':' ) )
+ bInsertSeparator = true;
+
+ for( uint iSeq = 0; iSeq < pAction->shortcut().count(); iSeq++ ) {
+ const KKeySequence& seqAction = pAction->shortcut().seq(iSeq);
+ if( seqAction.startsWith( seq ) ) {
+ if( bInsertSeparator ) {
+ pMenu->insertSeparator();
+ bInsertSeparator = false;
+ }
+
+ pMenu->insertAction( i, seqAction );
+
+ //kdDebug(125) << "sLabel = " << sLabel << ", seq = " << (QString)seqMenu.qt() << ", i = " << i << endl;
+ //kdDebug(125) << "pMenu->accel(" << i << ") = " << (QString)pMenu->accel(i) << endl;
+ bActionInserted = true;
+ break;
+ }
+ }
+ }
+ pMenu->updateShortcuts();
+ return pMenu;
+}
diff --git a/kdecore/kaccelbase.h b/kdecore/kaccelbase.h
new file mode 100644
index 000000000..c1fe515e6
--- /dev/null
+++ b/kdecore/kaccelbase.h
@@ -0,0 +1,282 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KACCELBASE_H
+#define _KACCELBASE_H
+
+#include <qmap.h>
+#include <qptrvector.h>
+#include <qstring.h>
+#include <qvaluevector.h>
+#include <qvaluelist.h>
+
+#include "kaccelaction.h"
+#include "kkeyserver.h"
+
+class QPopupMenu;
+class QWidget;
+
+//----------------------------------------------------
+
+/**
+ * @internal
+ * Handle keyboard accelerators.
+ *
+ * Allow an user to configure
+ * key bindings through application configuration files or through the
+ * KKeyChooser GUI.
+ *
+ * A KAccel contains a list of accelerator items. Each accelerator item
+ * consists of an action name and a keyboard code combined with modifiers
+ * (Shift, Ctrl and Alt.)
+ *
+ * For example, "Ctrl+P" could be a shortcut for printing a document. The key
+ * codes are listed in ckey.h. "Print" could be the action name for printing.
+ * The action name identifies the key binding in configuration files and the
+ * KKeyChooser GUI.
+ *
+ * When pressed, an accelerator key calls the slot to which it has been
+ * connected. Accelerator items can be connected so that a key will activate
+ * two different slots.
+ *
+ * A KAccel object handles key events sent to its parent widget and to all
+ * children of this parent widget.
+ *
+ * Key binding reconfiguration during run time can be prevented by specifying
+ * that an accelerator item is not configurable when it is inserted. A special
+ * group of non-configurable key bindings are known as the
+ * standard accelerators.
+ *
+ * The standard accelerators appear repeatedly in applications for
+ * standard document actions such as printing and saving. Convenience methods are
+ * available to insert and connect these accelerators which are configurable on
+ * a desktop-wide basis.
+ *
+ * It is possible for a user to choose to have no key associated with
+ * an action.
+ *
+ * The translated first argument for insertItem() is used only
+ * in the configuration dialog.
+ *\code
+ * KAccel *a = new KAccel( myWindow );
+ * // Insert an action "Scroll Up" which is associated with the "Up" key:
+ * a->insertItem( i18n("Scroll Up"), "Scroll Up", "Up" );
+ * // Insert an action "Scroll Down" which is not associated with any key:
+ * a->insertItem( i18n("Scroll Down"), "Scroll Down", 0);
+ * a->connectItem( "Scroll up", myWindow, SLOT( scrollUp() ) );
+ * // a->insertStdItem( KStdAccel::Print ); //not necessary, since it
+ * // is done automatially with the
+ * // connect below!
+ * a->connectItem(KStdAccel::Print, myWindow, SLOT( printDoc() ) );
+ *
+ * a->readSettings();
+ *\endcode
+ *
+ * If a shortcut has a menu entry as well, you could insert them like
+ * this. The example is again the KStdAccel::Print from above.
+ *
+ * \code
+ * int id;
+ * id = popup->insertItem("&Print",this, SLOT(printDoc()));
+ * a->changeMenuAccel(popup, id, KStdAccel::Print );
+ * \endcode
+ *
+ * If you want a somewhat "exotic" name for your standard print action, like
+ * id = popup->insertItem(i18n("Print &Document"),this, SLOT(printDoc()));
+ * it might be a good idea to insert the standard action before as
+ * a->insertStdItem( KStdAccel::Print, i18n("Print Document") )
+ * as well, so that the user can easily find the corresponding function.
+ *
+ * This technique works for other actions as well. Your "scroll up" function
+ * in a menu could be done with
+ *
+ * \code
+ * id = popup->insertItem(i18n"Scroll &up",this, SLOT(scrollUp()));
+ * a->changeMenuAccel(popup, id, "Scroll Up" );
+ * \endcode
+ *
+ * Please keep the order right: First insert all functions in the
+ * acceleratior, then call a -> readSettings() and @em then build your
+ * menu structure.
+ *
+ * @short Configurable key binding support.
+ */
+
+class KDECORE_EXPORT KAccelBase
+{
+ public:
+ /** Initialization mode of the KAccelBase, used in constructor. */
+ enum Init { QT_KEYS = 0x00, NATIVE_KEYS = 0x01 };
+
+ /** Enum for kinds of signals which may be emitted. */
+ enum Signal { KEYCODE_CHANGED };
+
+ /** Constructor. @p fInitCode should be a bitwise OR of
+ * values from the Init enum.
+ */
+ KAccelBase( int fInitCode );
+ virtual ~KAccelBase();
+
+ /** Returns number of actions in this handler. */
+ uint actionCount() const;
+ /** Returns a list of all the actions in this handler. */
+ KAccelActions& actions();
+ /** Returns whether this accelerator handler is enabled or not. */
+ bool isEnabled() const;
+
+ /** Returns a pointer to the KAccelAction named @p sAction. */
+ KAccelAction* actionPtr( const QString& sAction );
+ /** Const version of the above. */
+ const KAccelAction* actionPtr( const QString& sAction ) const;
+ /** Returns a pointer to the KAccelAction associated with
+ * the key @p key. This function takes into account the
+ * key mapping defined in the constructor.
+ *
+ * May return 0 if no (or more than one)
+ * action is associated with the key.
+ */
+ KAccelAction* actionPtr( const KKey& key );
+ /** Basically the same as above, except a KKeyServer::Key
+ * already has a key mapping defined (either NATIVE_KEYS or not).
+ */
+ KAccelAction* actionPtr( const KKeyServer::Key& key );
+
+ /** Returns the name of the configuration group these
+ * accelerators are stored in. The default is "Shortcuts".
+ */
+ const QString& configGroup() const { return m_sConfigGroup; }
+ /** Set the group (in the configuration file) for storing
+ * accelerators.
+ */
+ void setConfigGroup( const QString& group );
+ void setConfigGlobal( bool global );
+ /** Enables or disables the accelerator.
+ * @param bEnabled determines whether the accelerator should be enabled or
+ * disabled.
+ */
+ virtual void setEnabled( bool bEnabled ) = 0;
+ /** Returns whether autoupdate is enabled for these accelerators. */
+ bool getAutoUpdate() { return m_bAutoUpdate; }
+ /** Enables (or disables) autoupdate for these accelerators.
+ * @return the value of autoupdate before the call.
+ */
+ bool setAutoUpdate( bool bAuto );
+
+// Procedures for manipulating Actions.
+ //void clearActions();
+
+ KAccelAction* insert( const QString& sName, const QString& sDesc );
+ KAccelAction* insert(
+ const QString& sAction, const QString& sDesc, const QString& sHelp,
+ const KShortcut& rgCutDefaults3, const KShortcut& rgCutDefaults4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable = true, bool bEnabled = true );
+ bool remove( const QString& sAction );
+ bool setActionSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot );
+
+ bool updateConnections();
+
+ bool setShortcut( const QString& sAction, const KShortcut& cut );
+
+// Modify individual Action sub-items
+ bool setActionEnabled( const QString& sAction, bool bEnable );
+
+ /**
+ * Read all key associations from @p config, or (if @p config
+ * is zero) from the application's configuration file
+ * KGlobal::config().
+ *
+ * The group in which the configuration is stored can be
+ * set with setConfigGroup().
+ */
+ void readSettings( KConfigBase* pConfig = 0 );
+
+ /**
+ * Write the current configurable associations to @p config,
+ * or (if @p config is zero) to the application's
+ * configuration file.
+ */
+ void writeSettings( KConfigBase* pConfig = 0 ) const;
+
+ QPopupMenu* createPopupMenu( QWidget* pParent, const KKeySequence& );
+
+ // Protected methods
+ protected:
+ void slotRemoveAction( KAccelAction* );
+
+ struct X;
+
+ /** Constructs a list of keys to be connected, sorted highest priority first.
+ * @param rgKeys constructed list of keys
+ */
+ void createKeyList( QValueVector<struct X>& rgKeys );
+ bool insertConnection( KAccelAction* );
+ bool removeConnection( KAccelAction* );
+
+ /** Emits a signal.
+ * @param signal signal to be emitted
+ */
+ virtual bool emitSignal( Signal signal ) = 0;
+ /** Defines a key which activates the accelerator and executes the action
+ * @param action action to be executed when key is pressed
+ * @param key key which causes the action to be executed
+ */
+ virtual bool connectKey( KAccelAction& action, const KKeyServer::Key& key ) = 0;
+ /** Defines a key which activates the accelerator
+ * @param key key which causes the action to be executed
+ */
+ virtual bool connectKey( const KKeyServer::Key& key) = 0;
+ /** Removes the key from accelerator so it no longer executes the action
+ */
+ virtual bool disconnectKey( KAccelAction&, const KKeyServer::Key& ) = 0;
+ /** Removes the key from accelerator
+ */
+ virtual bool disconnectKey( const KKeyServer::Key& ) = 0;
+
+ protected:
+ virtual bool isEnabledInternal() const;
+ struct ActionInfo
+ {
+ KAccelAction* pAction;
+ uint iSeq, iVariation;
+ //ActionInfo* pInfoNext; // nil if only one action uses this key.
+
+ ActionInfo() { pAction = 0; iSeq = 0xffff; iVariation = 0xffff; }
+ ActionInfo( KAccelAction* _pAction, uint _iSeq, uint _iVariation )
+ { pAction = _pAction; iSeq = _iSeq; iVariation = _iVariation; }
+ };
+ typedef QMap<KKeyServer::Key, ActionInfo> KKeyToActionMap;
+
+ KAccelActions m_rgActions;
+ KKeyToActionMap m_mapKeyToAction;
+ QValueList<KAccelAction*> m_rgActionsNonUnique;
+ bool m_bNativeKeys; // Use native key codes instead of Qt codes
+ bool m_bEnabled;
+ bool m_bConfigIsGlobal;
+ QString m_sConfigGroup;
+ bool m_bAutoUpdate;
+ KAccelAction* mtemp_pActionRemoving;
+
+ private:
+ KAccelBase& operator =( const KAccelBase& );
+
+ friend class KAccelActions;
+};
+
+#endif // _KACCELBASE_H
diff --git a/kdecore/kaccelmanager.cpp b/kdecore/kaccelmanager.cpp
new file mode 100644
index 000000000..b0aaab4f3
--- /dev/null
+++ b/kdecore/kaccelmanager.cpp
@@ -0,0 +1,871 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Hölzer-Klüpfel <mhk@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kaccelmanager.h"
+
+#include <qapplication.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qmenubar.h>
+#include <qmemarray.h>
+#include <qmetaobject.h>
+#include <qmainwindow.h>
+#include <qobjectlist.h>
+#include <qpopupmenu.h>
+#include <qptrlist.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qtabbar.h>
+#include <qtextview.h>
+#include <qwidget.h>
+#include <qwidgetstack.h>
+
+#include <kstdaction.h>
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+
+
+#include "kaccelmanager_private.h"
+#include "../kdeui/kstdaction_p.h"
+
+
+/*********************************************************************
+
+ class Item - helper class containing widget information
+
+ This class stores information about the widgets the need accelerators,
+ as well as about their relationship.
+
+ *********************************************************************/
+
+
+
+/*********************************************************************
+
+ class KAcceleratorManagerPrivate - internal helper class
+
+ This class does all the work to find accelerators for a hierarchy of
+ widgets.
+
+ *********************************************************************/
+
+
+class KAcceleratorManagerPrivate
+{
+public:
+
+ static void manage(QWidget *widget);
+ static bool programmers_mode;
+ static bool standardName(const QString &str);
+
+ static bool checkChange(const KAccelString &as) {
+ QString t2 = as.accelerated();
+ QString t1 = as.originalText();
+ if (t1 != t2)
+ {
+ if (as.accel() == -1) {
+ removed_string += "<tr><td>" + QStyleSheet::escape(t1) + "</td></tr>";
+ } else if (as.originalAccel() == -1) {
+ added_string += "<tr><td>" + QStyleSheet::escape(t2) + "</td></tr>";
+ } else {
+ changed_string += "<tr><td>" + QStyleSheet::escape(t1) + "</td>";
+ changed_string += "<td>" + QStyleSheet::escape(t2) + "</td></tr>";
+ }
+ return true;
+ }
+ return false;
+ }
+ static QString changed_string;
+ static QString added_string;
+ static QString removed_string;
+ static QMap<QWidget *, int> ignored_widgets;
+
+private:
+ class Item;
+public:
+ typedef QPtrList<Item> ItemList;
+
+private:
+ static void traverseChildren(QWidget *widget, Item *item);
+
+ static void manageWidget(QWidget *widget, Item *item);
+ static void manageMenuBar(QMenuBar *mbar, Item *item);
+ static void manageTabBar(QTabBar *bar, Item *item);
+
+ static void calculateAccelerators(Item *item, QString &used);
+
+ class Item
+ {
+ public:
+
+ Item() : m_widget(0), m_children(0), m_index(-1) {}
+ ~Item();
+
+ void addChild(Item *item);
+
+ QWidget *m_widget;
+ KAccelString m_content;
+ ItemList *m_children;
+ int m_index;
+
+ };
+};
+
+
+bool KAcceleratorManagerPrivate::programmers_mode = false;
+QString KAcceleratorManagerPrivate::changed_string;
+QString KAcceleratorManagerPrivate::added_string;
+QString KAcceleratorManagerPrivate::removed_string;
+static QStringList *kaccmp_sns = 0;
+static KStaticDeleter<QStringList> kaccmp_sns_d;
+QMap<QWidget*, int> KAcceleratorManagerPrivate::ignored_widgets;
+
+bool KAcceleratorManagerPrivate::standardName(const QString &str)
+{
+ if (!kaccmp_sns)
+ kaccmp_sns_d.setObject(kaccmp_sns, new QStringList(KStdAction::internal_stdNames()));
+ return kaccmp_sns->contains(str);
+}
+
+KAcceleratorManagerPrivate::Item::~Item()
+{
+ delete m_children;
+}
+
+
+void KAcceleratorManagerPrivate::Item::addChild(Item *item)
+{
+ if (!m_children) {
+ m_children = new ItemList;
+ m_children->setAutoDelete(true);
+ }
+
+ m_children->append(item);
+}
+
+void KAcceleratorManagerPrivate::manage(QWidget *widget)
+{
+ if (!widget)
+ {
+ kdDebug(131) << "null pointer given to manage" << endl;
+ return;
+ }
+
+ if (dynamic_cast<QPopupMenu*>(widget))
+ {
+ // create a popup accel manager that can deal with dynamic menus
+ KPopupAccelManager::manage(static_cast<QPopupMenu*>(widget));
+ return;
+ }
+
+ Item *root = new Item;
+
+ manageWidget(widget, root);
+
+ QString used;
+ calculateAccelerators(root, used);
+ delete root;
+}
+
+
+void KAcceleratorManagerPrivate::calculateAccelerators(Item *item, QString &used)
+{
+ if (!item->m_children)
+ return;
+
+ // collect the contents
+ KAccelStringList contents;
+ for (Item *it = item->m_children->first(); it != 0;
+ it = item->m_children->next())
+ {
+ contents << it->m_content;
+ }
+
+ // find the right accelerators
+ KAccelManagerAlgorithm::findAccelerators(contents, used);
+
+ // write them back into the widgets
+ int cnt = -1;
+ for (Item *it = item->m_children->first(); it != 0;
+ it = item->m_children->next())
+ {
+ cnt++;
+
+ QTabBar *tabBar = dynamic_cast<QTabBar*>(it->m_widget);
+ if (tabBar)
+ {
+ if (checkChange(contents[cnt]))
+ tabBar->tabAt(it->m_index)->setText(contents[cnt].accelerated());
+ continue;
+ }
+ QMenuBar *menuBar = dynamic_cast<QMenuBar*>(it->m_widget);
+ if (menuBar)
+ {
+ if (it->m_index >= 0)
+ {
+ QMenuItem *mitem = menuBar->findItem(menuBar->idAt(it->m_index));
+ if (mitem)
+ {
+ checkChange(contents[cnt]);
+ mitem->setText(contents[cnt].accelerated());
+ }
+ continue;
+ }
+ }
+ // we possibly reserved an accel, but we won't set it as it looks silly
+ if ( dynamic_cast<QGroupBox*>( it->m_widget ) )
+ continue;
+ // links look weird with ampersands
+ if ( dynamic_cast<QLabel*>( it->m_widget ) && it->m_widget->inherits("KURLLabel") )
+ continue;
+
+ int tprop = it->m_widget->metaObject()->findProperty("text", true);
+ if (tprop != -1) {
+ if (checkChange(contents[cnt]))
+ it->m_widget->setProperty("text", contents[cnt].accelerated());
+ } else {
+ tprop = it->m_widget->metaObject()->findProperty("title", true);
+ if (tprop != -1 && checkChange(contents[cnt]))
+ it->m_widget->setProperty("title", contents[cnt].accelerated());
+ }
+ }
+
+ // calculate the accelerators for the children
+ for (Item *it = item->m_children->first(); it != 0;
+ it = item->m_children->next())
+ {
+ if (it->m_widget && it->m_widget->isVisibleTo( item->m_widget ) )
+ calculateAccelerators(it, used);
+ }
+}
+
+
+void KAcceleratorManagerPrivate::traverseChildren(QWidget *widget, Item *item)
+{
+ QObjectList *childList = widget->queryList("QWidget", 0, false, false);
+ for ( QObject *it = childList->first(); it; it = childList->next() )
+ {
+ QWidget *w = static_cast<QWidget*>(it);
+
+ if ( !w->isVisibleTo( widget ) || ( w->isTopLevel() && dynamic_cast<QPopupMenu*>(w) == NULL ) )
+ continue;
+
+ if ( KAcceleratorManagerPrivate::ignored_widgets.find( w ) != KAcceleratorManagerPrivate::ignored_widgets.end() )
+ continue;
+
+ manageWidget(w, item);
+ }
+ delete childList;
+}
+
+void KAcceleratorManagerPrivate::manageWidget(QWidget *w, Item *item)
+{
+ // first treat the special cases
+
+ QTabBar *tabBar = dynamic_cast<QTabBar*>(w);
+ if (tabBar)
+ {
+ manageTabBar(tabBar, item);
+ return;
+ }
+
+ QWidgetStack *wds = dynamic_cast<QWidgetStack*>( w );
+ if ( wds )
+ {
+ QWidgetStackAccelManager::manage( wds );
+ // return;
+ }
+
+ QPopupMenu *popupMenu = dynamic_cast<QPopupMenu*>(w);
+ if (popupMenu)
+ {
+ // create a popup accel manager that can deal with dynamic menus
+ KPopupAccelManager::manage(popupMenu);
+ return;
+ }
+
+ QWidgetStack *wdst = dynamic_cast<QWidgetStack*>( w );
+ if ( wdst )
+ {
+ QWidgetStackAccelManager::manage( wdst );
+ // return;
+ }
+
+ QMenuBar *menuBar = dynamic_cast<QMenuBar*>(w);
+ if (menuBar)
+ {
+ manageMenuBar(menuBar, item);
+ return;
+ }
+
+ if (dynamic_cast<QComboBox*>(w) || dynamic_cast<QLineEdit*>(w) ||
+ dynamic_cast<QTextEdit*>(w) || dynamic_cast<QTextView*>(w) ||
+ dynamic_cast<QSpinBox*>(w) || w->qt_cast( "KMultiTabBar" ))
+ return;
+
+ // now treat 'ordinary' widgets
+ QLabel *label = dynamic_cast<QLabel*>(w);
+ if ( label ) {
+ if ( !label->buddy() )
+ label = 0;
+ else {
+ if ( label->textFormat() == Qt::RichText ||
+ ( label->textFormat() == Qt::AutoText &&
+ QStyleSheet::mightBeRichText( label->text() ) ) )
+ label = 0;
+ }
+ }
+
+ if (w->isFocusEnabled() || label || dynamic_cast<QGroupBox*>(w) || dynamic_cast<QRadioButton*>( w ))
+ {
+ QString content;
+ QVariant variant;
+ int tprop = w->metaObject()->findProperty("text", true);
+ if (tprop != -1) {
+ const QMetaProperty* p = w->metaObject()->property( tprop, true );
+ if ( p && p->isValid() )
+ w->qt_property( tprop, 1, &variant );
+ else
+ tprop = -1;
+ }
+
+ if (tprop == -1) {
+ tprop = w->metaObject()->findProperty("title", true);
+ if (tprop != -1) {
+ const QMetaProperty* p = w->metaObject()->property( tprop, true );
+ if ( p && p->isValid() )
+ w->qt_property( tprop, 1, &variant );
+ }
+ }
+
+ if (variant.isValid())
+ content = variant.toString();
+
+ if (!content.isEmpty())
+ {
+ Item *i = new Item;
+ i->m_widget = w;
+
+ // put some more weight on the usual action elements
+ int weight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
+ if (dynamic_cast<QPushButton*>(w) || dynamic_cast<QCheckBox*>(w) || dynamic_cast<QRadioButton*>(w) || dynamic_cast<QLabel*>(w))
+ weight = KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT;
+
+ // don't put weight on group boxes, as usually the contents are more important
+ if (dynamic_cast<QGroupBox*>(w))
+ weight = KAccelManagerAlgorithm::GROUP_BOX_WEIGHT;
+
+ // put a lot of extra weight on the KDialogBaseButton's
+ if (w->inherits("KDialogBaseButton"))
+ weight += KAccelManagerAlgorithm::DIALOG_BUTTON_EXTRA_WEIGHT;
+
+ i->m_content = KAccelString(content, weight);
+ item->addChild(i);
+ }
+ }
+ traverseChildren(w, item);
+}
+
+void KAcceleratorManagerPrivate::manageTabBar(QTabBar *bar, Item *item)
+{
+ for (int i=0; i<bar->count(); i++)
+ {
+ QString content = bar->tabAt(i)->text();
+ if (content.isEmpty())
+ continue;
+
+ Item *it = new Item;
+ item->addChild(it);
+ it->m_widget = bar;
+ it->m_index = i;
+ it->m_content = KAccelString(content);
+ }
+}
+
+void KAcceleratorManagerPrivate::manageMenuBar(QMenuBar *mbar, Item *item)
+{
+ QMenuItem *mitem;
+ QString s;
+
+ for (uint i=0; i<mbar->count(); ++i)
+ {
+ mitem = mbar->findItem(mbar->idAt(i));
+ if (!mitem)
+ continue;
+
+ // nothing to do for separators
+ if (mitem->isSeparator())
+ continue;
+
+ s = mitem->text();
+ if (!s.isEmpty())
+ {
+ Item *it = new Item;
+ item->addChild(it);
+ it->m_content =
+ KAccelString(s,
+ // menu titles are important, so raise the weight
+ KAccelManagerAlgorithm::MENU_TITLE_WEIGHT);
+
+ it->m_widget = mbar;
+ it->m_index = i;
+ }
+
+ // have a look at the popup as well, if present
+ if (mitem->popup())
+ KPopupAccelManager::manage(mitem->popup());
+ }
+}
+
+
+/*********************************************************************
+
+ class KAcceleratorManager - main entry point
+
+ This class is just here to provide a clean public API...
+
+ *********************************************************************/
+
+void KAcceleratorManager::manage(QWidget *widget)
+{
+ KAcceleratorManager::manage(widget, false);
+}
+
+void KAcceleratorManager::manage(QWidget *widget, bool programmers_mode)
+{
+ kdDebug(131) << "KAcceleratorManager::manage\n";
+ KAcceleratorManagerPrivate::changed_string = QString::null;
+ KAcceleratorManagerPrivate::added_string = QString::null;
+ KAcceleratorManagerPrivate::removed_string = QString::null;
+ KAcceleratorManagerPrivate::programmers_mode = programmers_mode;
+ KAcceleratorManagerPrivate::manage(widget);
+}
+
+void KAcceleratorManager::last_manage(QString &added, QString &changed, QString &removed)
+{
+ added = KAcceleratorManagerPrivate::added_string;
+ changed = KAcceleratorManagerPrivate::changed_string;
+ removed = KAcceleratorManagerPrivate::removed_string;
+}
+
+
+/*********************************************************************
+
+ class KAccelString - a string with weighted characters
+
+ *********************************************************************/
+
+KAccelString::KAccelString(const QString &input, int initialWeight)
+ : m_pureText(input), m_weight()
+{
+ m_orig_accel = m_pureText.find("(!)&");
+ if (m_orig_accel != -1)
+ m_pureText.remove(m_orig_accel, 4);
+
+ m_orig_accel = m_pureText.find("(&&)");
+ if (m_orig_accel != -1)
+ m_pureText.replace(m_orig_accel, 4, "&");
+
+ m_origText = m_pureText;
+
+ if (m_pureText.contains('\t'))
+ m_pureText = m_pureText.left(m_pureText.find('\t'));
+
+ m_orig_accel = m_accel = stripAccelerator(m_pureText);
+
+ if (initialWeight == -1)
+ initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
+
+ calculateWeights(initialWeight);
+
+ // dump();
+}
+
+
+QString KAccelString::accelerated() const
+{
+ QString result = m_origText;
+ if (result.isEmpty())
+ return result;
+
+ if (KAcceleratorManagerPrivate::programmers_mode)
+ {
+ if (m_accel != m_orig_accel) {
+ int oa = m_orig_accel;
+
+ if (m_accel >= 0) {
+ result.insert(m_accel, "(!)&");
+ if (m_accel < m_orig_accel)
+ oa += 4;
+ }
+ if (m_orig_accel >= 0)
+ result.replace(oa, 1, "(&&)");
+ }
+ } else {
+ if (m_accel >= 0 && m_orig_accel != m_accel) {
+ result.remove(m_orig_accel, 1);
+ result.insert(m_accel, "&");
+ }
+ }
+ return result;
+}
+
+
+QChar KAccelString::accelerator() const
+{
+ if ((m_accel < 0) || (m_accel > (int)m_pureText.length()))
+ return QChar();
+
+ return m_pureText[m_accel].lower();
+}
+
+
+void KAccelString::calculateWeights(int initialWeight)
+{
+ m_weight.resize(m_pureText.length());
+
+ uint pos = 0;
+ bool start_character = true;
+
+ while (pos<m_pureText.length())
+ {
+ QChar c = m_pureText[pos];
+
+ int weight = initialWeight+1;
+
+ // add special weight to first character
+ if (pos == 0)
+ weight += KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT;
+
+ // add weight to word beginnings
+ if (start_character)
+ {
+ weight += KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT;
+ start_character = false;
+ }
+
+ // add decreasing weight to left characters
+ if (pos < 50)
+ weight += (50-pos);
+
+ // try to preserve the wanted accelarators
+ if ((int)pos == accel()) {
+ weight += KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT;
+ // kdDebug(131) << "wanted " << m_pureText << " " << KAcceleratorManagerPrivate::standardName(m_origText) << endl;
+ if (KAcceleratorManagerPrivate::standardName(m_origText)) {
+ weight += KAccelManagerAlgorithm::STANDARD_ACCEL;
+ }
+ }
+
+ // skip non typeable characters
+ if (!c.isLetterOrNumber())
+ {
+ weight = 0;
+ start_character = true;
+ }
+
+ m_weight[pos] = weight;
+
+ ++pos;
+ }
+}
+
+
+int KAccelString::stripAccelerator(QString &text)
+{
+ // Note: this code is derived from QAccel::shortcutKey
+ int p = 0;
+
+ while (p >= 0)
+ {
+ p = text.find('&', p)+1;
+
+ if (p <= 0 || p >= (int)text.length())
+ return -1;
+
+ if (text[p] != '&')
+ {
+ QChar c = text[p];
+ if (c.isPrint())
+ {
+ text.remove(p-1,1);
+ return p-1;
+ }
+ }
+
+ p++;
+ }
+
+ return -1;
+}
+
+
+int KAccelString::maxWeight(int &index, const QString &used)
+{
+ int max = 0;
+ index = -1;
+
+ for (uint pos=0; pos<m_pureText.length(); ++pos)
+ if (used.find(m_pureText[pos], 0, FALSE) == -1 && m_pureText[pos].latin1() != 0)
+ if (m_weight[pos] > max)
+ {
+ max = m_weight[pos];
+ index = pos;
+ }
+
+ return max;
+}
+
+
+void KAccelString::dump()
+{
+ QString s;
+ for (uint i=0; i<m_weight.count(); ++i)
+ s += QString("%1(%2) ").arg(pure()[i]).arg(m_weight[i]);
+ kdDebug() << "s " << s << endl;
+}
+
+
+/*********************************************************************
+
+ findAccelerators - the algorithm determining the new accelerators
+
+ The algorithm is very crude:
+
+ * each character in each widget text is assigned a weight
+ * the character with the highest weight over all is picked
+ * that widget is removed from the list
+ * the weights are recalculated
+ * the process is repeated until no more accelerators can be found
+
+ The algorithm has some advantages:
+
+ * it favors 'nice' accelerators (first characters in a word, etc.)
+ * it is quite fast, O(N²)
+ * it is easy to understand :-)
+
+ The disadvantages:
+
+ * it does not try to find as many accelerators as possible
+
+ TODO:
+
+ * The result is always correct, but not neccesarily optimal. Perhaps
+ it would be a good idea to add another algorithm with higher complexity
+ that gets used when this one fails, i.e. leaves widgets without
+ accelerators.
+
+ * The weights probably need some tweaking so they make more sense.
+
+ *********************************************************************/
+
+void KAccelManagerAlgorithm::findAccelerators(KAccelStringList &result, QString &used)
+{
+ kdDebug(131) << "findAccelerators\n";
+ KAccelStringList accel_strings = result;
+
+ // initally remove all accelerators
+ for (KAccelStringList::Iterator it = result.begin(); it != result.end(); ++it) {
+ (*it).setAccel(-1);
+ }
+
+ // pick the highest bids
+ for (uint cnt=0; cnt<accel_strings.count(); ++cnt)
+ {
+ int max = 0, index = -1, accel = -1;
+
+ // find maximum weight
+ for (uint i=0; i<accel_strings.count(); ++i)
+ {
+ int a;
+ int m = accel_strings[i].maxWeight(a, used);
+ if (m>max)
+ {
+ max = m;
+ index = i;
+ accel = a;
+ }
+ }
+
+ // stop if no more accelerators can be found
+ if (index < 0)
+ return;
+
+ // insert the accelerator
+ if (accel >= 0)
+ {
+ result[index].setAccel(accel);
+ used.append(result[index].accelerator());
+ }
+
+ // make sure we don't visit this one again
+ accel_strings[index] = KAccelString();
+ }
+}
+
+
+/*********************************************************************
+
+ class KPopupAccelManager - managing QPopupMenu widgets dynamically
+
+ *********************************************************************/
+
+KPopupAccelManager::KPopupAccelManager(QPopupMenu *popup)
+ : QObject(popup), m_popup(popup), m_count(-1)
+{
+ aboutToShow(); // do one check and then connect to show
+ connect(popup, SIGNAL(aboutToShow()), SLOT(aboutToShow()));
+}
+
+
+void KPopupAccelManager::aboutToShow()
+{
+ // Note: we try to be smart and avoid recalculating the accelerators
+ // whenever possible. Unfortunately, there is no way to know if an
+ // item has been added or removed, so we can not do much more than
+ // to compare the items each time the menu is shown :-(
+
+ if (m_count != (int)m_popup->count())
+ {
+ findMenuEntries(m_entries);
+ calculateAccelerators();
+ m_count = m_popup->count();
+ }
+ else
+ {
+ KAccelStringList entries;
+ findMenuEntries(entries);
+ if (entries != m_entries)
+ {
+ m_entries = entries;
+ calculateAccelerators();
+ }
+ }
+}
+
+
+void KPopupAccelManager::calculateAccelerators()
+{
+ // find the new accelerators
+ QString used;
+ KAccelManagerAlgorithm::findAccelerators(m_entries, used);
+
+ // change the menu entries
+ setMenuEntries(m_entries);
+}
+
+
+void KPopupAccelManager::findMenuEntries(KAccelStringList &list)
+{
+ QMenuItem *mitem;
+ QString s;
+
+ list.clear();
+
+ // read out the menu entries
+ for (uint i=0; i<m_popup->count(); i++)
+ {
+ mitem = m_popup->findItem(m_popup->idAt(i));
+ if (mitem->isSeparator())
+ continue;
+
+ s = mitem->text();
+
+ // in full menus, look at entries with global accelerators last
+ int weight = 50;
+ if (s.contains('\t'))
+ weight = 0;
+
+ list.append(KAccelString(s, weight));
+
+ // have a look at the popup as well, if present
+ if (mitem->popup())
+ KPopupAccelManager::manage(mitem->popup());
+ }
+}
+
+
+void KPopupAccelManager::setMenuEntries(const KAccelStringList &list)
+{
+ QMenuItem *mitem;
+
+ uint cnt = 0;
+ for (uint i=0; i<m_popup->count(); i++)
+ {
+ mitem = m_popup->findItem(m_popup->idAt(i));
+ if (mitem->isSeparator())
+ continue;
+
+ if (KAcceleratorManagerPrivate::checkChange(list[cnt]))
+ mitem->setText(list[cnt].accelerated());
+ cnt++;
+ }
+}
+
+
+void KPopupAccelManager::manage(QPopupMenu *popup)
+{
+ // don't add more than one manager to a popup
+ if (popup->child(0, "KPopupAccelManager", false) == 0 )
+ new KPopupAccelManager(popup);
+}
+
+void QWidgetStackAccelManager::manage( QWidgetStack *stack )
+{
+ if ( stack->child( 0, "QWidgetStackAccelManager", false ) == 0 )
+ new QWidgetStackAccelManager( stack );
+}
+
+QWidgetStackAccelManager::QWidgetStackAccelManager(QWidgetStack *stack)
+ : QObject(stack), m_stack(stack)
+{
+ aboutToShow(stack->visibleWidget()); // do one check and then connect to show
+ connect(stack, SIGNAL(aboutToShow(QWidget *)), SLOT(aboutToShow(QWidget *)));
+}
+
+bool QWidgetStackAccelManager::eventFilter ( QObject * watched, QEvent * e )
+{
+ if ( e->type() == QEvent::Show && qApp->activeWindow() ) {
+ KAcceleratorManager::manage( qApp->activeWindow() );
+ watched->removeEventFilter( this );
+ }
+ return false;
+}
+
+void QWidgetStackAccelManager::aboutToShow(QWidget *child)
+{
+ if (!child)
+ {
+ kdDebug(131) << "null pointer given to aboutToShow" << endl;
+ return;
+ }
+
+ child->installEventFilter( this );
+}
+
+void KAcceleratorManager::setNoAccel( QWidget *widget )
+{
+ KAcceleratorManagerPrivate::ignored_widgets[widget] = 1;
+}
+
+#include "kaccelmanager_private.moc"
diff --git a/kdecore/kaccelmanager.h b/kdecore/kaccelmanager.h
new file mode 100644
index 000000000..7619d2e29
--- /dev/null
+++ b/kdecore/kaccelmanager.h
@@ -0,0 +1,88 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Hoelzer-Kluepfel <mhk@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef __K_ACCELMANAGER_H__
+#define __K_ACCELMANAGER_H__
+
+
+class QWidget;
+class QString;
+
+#include <kdelibs_export.h>
+
+/**
+ * KDE Accelerator manager.
+ *
+ * This class can be used to find a valid and working set of
+ * accelerators for any widget.
+ *
+ * @author Matthias Hoelzer-Kluepfel <mhk@kde.org>
+ * @since 3.1
+*/
+
+class KDECORE_EXPORT KAcceleratorManager
+{
+public:
+
+ /**
+ * Manages the accelerators of a widget.
+ *
+ * Call this function on the top widget of the hierarchy you
+ * want to manage. It will fix the accelerators of the child widgets so
+ * there are never duplicate accelerators. It also tries to put
+ * accelerators on as many widgets as possible.
+ *
+ * The algorithm used tries to take the existing accelerators into
+ * account, as well as the class of each widget. Hopefully, the result
+ * is close to what you would assign manually.
+ *
+ * QPopupMenu's are managed dynamically, so when you add or remove entries,
+ * the accelerators are reassigned. If you add or remove widgets to your
+ * toplevel widget, you will have to call manage again to fix the
+ * accelerators.
+ *
+ * @param widget The toplevel widget you want to manage.
+ */
+
+ static void manage(QWidget *widget);
+
+ /**
+ * Does the same as the above function, but puts hints in the GUI so the
+ * programmer can enhance his program.
+ *
+ * TODO KDE4: merge with the above
+ * @param widget The toplevel widget you want to manage.
+ * @param programmers_mode if true, KAcceleratorManager adds (&) for removed
+ * accels and & before added accels
+ */
+ static void manage(QWidget *widget, bool programmers_mode);
+
+ /** \internal returns the result of the last manage operation. */
+ static void last_manage(QString &added, QString &changed, QString &removed);
+
+ /**
+ * Use this method for a widget (and its children) you want no accels to be set on.
+ * @since 3.4
+ */
+ static void setNoAccel( QWidget *widget );
+};
+
+
+#endif
diff --git a/kdecore/kaccelmanager_private.h b/kdecore/kaccelmanager_private.h
new file mode 100644
index 000000000..74c844e1d
--- /dev/null
+++ b/kdecore/kaccelmanager_private.h
@@ -0,0 +1,196 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Hoelzer-Kluepfel <mhk@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef __KACCELMANAGER_PRIVATE_H__
+#define __KACCELMANAGER_PRIVATE_H__
+
+
+#include <qstring.h>
+#include <qmemarray.h>
+#include <qvaluelist.h>
+#include <qobject.h>
+
+class QWidgetStack;
+
+/**
+ * A string class handling accelerators.
+ *
+ * This class contains a string and knowledge about accelerators.
+ * It keeps a list weights, telling how valuable each character
+ * would be as an accelerator.
+ *
+ * @author Matthias Hoelzer-Kluepfel <mhk@kde.org>
+*/
+
+class KAccelString
+{
+public:
+
+ KAccelString() : m_pureText(), m_accel(-1) {}
+ KAccelString(const QString &input, int initalWeight=-1);
+
+ void calculateWeights(int initialWeight);
+
+ const QString &pure() const { return m_pureText; }
+ QString accelerated() const;
+
+ int accel() const { return m_accel; }
+ void setAccel(int accel) { m_accel = accel; }
+
+ int originalAccel() const { return m_orig_accel; }
+ QString originalText() const { return m_origText; }
+
+ QChar accelerator() const;
+
+ int maxWeight(int &index, const QString &used);
+
+ bool operator == (const KAccelString &c) const { return m_pureText == c.m_pureText && m_accel == c.m_accel && m_orig_accel == c.m_orig_accel; }
+
+
+private:
+
+ int stripAccelerator(QString &input);
+
+ void dump();
+
+ QString m_pureText, m_origText;
+ int m_accel, m_orig_accel;
+ QMemArray<int> m_weight;
+
+};
+
+
+typedef QValueList<KAccelString> KAccelStringList;
+
+
+/**
+ * This class encapsulates the algorithm finding the 'best'
+ * distribution of accelerators in a hierarchy of widgets.
+ *
+ * @author Matthias Hoelzer-Kluepfel <mhk@kde.org>
+*/
+
+class KAccelManagerAlgorithm
+{
+public:
+
+ /// Constants used in the algorithm
+ enum {
+ /// Default control weight
+ DEFAULT_WEIGHT = 50,
+ /// Additional weight for first character in string
+ FIRST_CHARACTER_EXTRA_WEIGHT = 50,
+ /// Additional weight for the beginning of a word
+ WORD_BEGINNING_EXTRA_WEIGHT = 50,
+ /// Additional weight for the dialog buttons (large, we basically never want these reassigned)
+ DIALOG_BUTTON_EXTRA_WEIGHT = 300,
+ /// Additional weight for a 'wanted' accelerator
+ WANTED_ACCEL_EXTRA_WEIGHT = 150,
+ /// Default weight for an 'action' widget (ie, pushbuttons)
+ ACTION_ELEMENT_WEIGHT = 50,
+ /// Default weight for group boxes (low priority)
+ GROUP_BOX_WEIGHT = -2000,
+ /// Default weight for menu titles
+ MENU_TITLE_WEIGHT = 250,
+ /// Additional weight for KDE standard accelerators
+ STANDARD_ACCEL = 300
+ };
+
+ /// Method to call to find the best distribution of accelerators.
+ static void findAccelerators(KAccelStringList &result, QString &used);
+
+};
+
+
+class QPopupMenu;
+
+
+/**
+ * This class manages a popup menu. It will notice if entries have been
+ * added or changed, and will recalculate the accelerators accordingly.
+ *
+ * This is necessary for dynamic menus like for example in kicker.
+ *
+ * @author Matthias Hoelzer-Kluepfel <mhk@kde.org>
+*/
+
+class KPopupAccelManager : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ static void manage(QPopupMenu *popup);
+
+
+protected:
+
+ KPopupAccelManager(QPopupMenu *popup);
+
+
+private slots:
+
+ void aboutToShow();
+
+
+private:
+
+ void calculateAccelerators();
+
+ void findMenuEntries(KAccelStringList &list);
+ void setMenuEntries(const KAccelStringList &list);
+
+ QPopupMenu *m_popup;
+ KAccelStringList m_entries;
+ int m_count;
+
+};
+
+
+class QWidgetStackAccelManager : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ static void manage(QWidgetStack *popup);
+
+
+protected:
+
+ QWidgetStackAccelManager(QWidgetStack *popup);
+
+
+private slots:
+
+ void aboutToShow(QWidget *);
+ bool eventFilter ( QObject * watched, QEvent * e );
+
+private:
+
+ void calculateAccelerators();
+
+ QWidgetStack *m_stack;
+ KAccelStringList m_entries;
+
+};
+
+
+#endif
diff --git a/kdecore/kaccelprivate.h b/kdecore/kaccelprivate.h
new file mode 100644
index 000000000..7938aca0c
--- /dev/null
+++ b/kdecore/kaccelprivate.h
@@ -0,0 +1,53 @@
+#ifndef __KACCELPRIVATE_H
+#define __KACCELPRIVATE_H
+
+#include "kkeyserver_x11.h"
+#include <qtimer.h>
+
+class KAccelAction;
+
+/**
+ * @internal
+ */
+class KDECORE_EXPORT KAccelPrivate : public QObject, public KAccelBase
+{
+ Q_OBJECT
+ public:
+ KAccel* m_pAccel;
+ QWidget* m_pWatch;
+ QMap<int, int> m_mapIDToKey;
+ QMap<int, KAccelAction*> m_mapIDToAction;
+ QTimer m_timerShowMenu;
+
+ KAccelPrivate( KAccel* pParent, QWidget* pWatch );
+
+ virtual void setEnabled( bool bEnabled );
+
+ bool setEnabled( const QString& sAction, bool bEnable );
+
+ virtual bool removeAction( const QString& sAction );
+
+ virtual bool emitSignal( KAccelBase::Signal signal );
+ virtual bool connectKey( KAccelAction& action, const KKeyServer::Key& key );
+ virtual bool connectKey( const KKeyServer::Key& key );
+ virtual bool disconnectKey( KAccelAction& action, const KKeyServer::Key& key );
+ virtual bool disconnectKey( const KKeyServer::Key& key );
+
+ signals:
+ void menuItemActivated();
+ void menuItemActivated(KAccelAction*);
+
+ private:
+#ifndef Q_WS_WIN /** @todo TEMP: new implementation (commit #424926) didn't work */
+ void emitActivatedSignal(KAccelAction*);
+#endif
+
+ private slots:
+ void slotKeyPressed( int id );
+ void slotShowMenu();
+ void slotMenuActivated( int iAction );
+
+ bool eventFilter( QObject* pWatched, QEvent* pEvent ); // virtual method from QObject
+};
+
+#endif // !__KACCELPRIVATE_H
diff --git a/kdecore/kallocator.cpp b/kdecore/kallocator.cpp
new file mode 100644
index 000000000..6ad524dec
--- /dev/null
+++ b/kdecore/kallocator.cpp
@@ -0,0 +1,260 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2002 Michael Matz (matz@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/* Fast zone memory allocator with deallocation support, for use as obstack
+ or as general purpose allocator. It does no compaction. If the usage
+ pattern is non-optimal it might waste some memory while running. E.g.
+ allocating many small things at once, and then deallocating only every
+ second one, there is a high chance, that actually no memory is freed. */
+// $Id$
+
+#include "kallocator.h"
+#include <kdebug.h>
+
+class KZoneAllocator::MemBlock
+{
+ public:
+ MemBlock(size_t s) : size(s), ref(0), older(0), newer(0)
+ { begin = new char[s]; }
+ ~MemBlock() { delete [] begin; }
+ bool is_in(void *ptr) const {return !(begin > (char *)ptr
+ || (begin + size) <= (char *)ptr); }
+ size_t size;
+ unsigned int ref;
+ char *begin;
+ MemBlock *older;
+ MemBlock *newer;
+};
+
+KZoneAllocator::KZoneAllocator(unsigned long _blockSize)
+: currentBlock(0), blockSize(1), blockOffset(0), log2(0), num_blocks(0),
+ hashList(0), hashSize(0), hashDirty(true)
+{
+ while (blockSize < _blockSize)
+ blockSize <<= 1, log2++;
+ /* Make sure, that a block is allocated at the first time allocate()
+ is called (even with a 0 size). */
+ blockOffset = blockSize + 1;
+}
+
+KZoneAllocator::~KZoneAllocator()
+{
+ unsigned int count = 0;
+ if (hashList) {
+ /* No need to maintain the different lists in hashList[] anymore.
+ I.e. no need to use delBlock(). */
+ for (unsigned int i = 0; i < hashSize; i++)
+ delete hashList[i];
+ delete [] hashList;
+ hashList = 0;
+ }
+ MemBlock *next;
+ for (; currentBlock; currentBlock = next) {
+ next = currentBlock->older;
+ delete currentBlock;
+ count++;
+ }
+#ifndef NDEBUG // as this is called quite late in the app, we don't care
+ // to use kdDebug
+ if (count > 1)
+ qDebug("zone still contained %d blocks", count);
+#endif
+}
+
+void KZoneAllocator::insertHash(MemBlock *b)
+{
+ unsigned long adr = ((unsigned long)b->begin) & (~(blockSize - 1));
+ unsigned long end = ((unsigned long)b->begin) + blockSize;
+ while (adr < end) {
+ unsigned long key = adr >> log2;
+ key = key & (hashSize - 1);
+ if (!hashList[key])
+ hashList[key] = new QValueList<MemBlock *>;
+ hashList[key]->append(b);
+ adr += blockSize;
+ }
+}
+
+/** Add a new memory block to the pool of blocks,
+ and reorganize the hash lists if needed.
+ @param b block to add
+ @internal
+*/
+void KZoneAllocator::addBlock(MemBlock *b)
+{
+ b->newer = 0;
+ b->older = currentBlock;
+ if (currentBlock)
+ b->older->newer = b;
+ currentBlock = b;
+ num_blocks++;
+ /* If we either have no hashList at all, or since it's last construction
+ there are now many more blocks we reconstruct the list. But don't
+ make it larger than a certain maximum. */
+ if (hashList && ((num_blocks / 4) > hashSize && hashSize < 64*1024))
+ hashDirty = true;
+ /* Only insert this block into the hashlists, if we aren't going to
+ reconstruct them anyway. */
+ if (hashList && !hashDirty)
+ insertHash (b);
+}
+
+/** Reinitialize hash list. @internal */
+void KZoneAllocator::initHash()
+{
+ if (hashList) {
+ for (unsigned int i = 0; i < hashSize; i++)
+ delete hashList[i];
+ delete [] hashList;
+ hashList = 0;
+ }
+ hashSize = 1;
+ while (hashSize < num_blocks)
+ hashSize <<= 1;
+ if (hashSize < 1024)
+ hashSize = 1024;
+ if (hashSize > 64*1024)
+ hashSize = 64*1024;
+ hashList = new QValueList<MemBlock *> *[hashSize];
+ memset (hashList, 0, sizeof(QValueList<MemBlock*> *) * hashSize);
+ hashDirty = false;
+ for (MemBlock *b = currentBlock; b; b = b->older)
+ insertHash(b);
+}
+
+/** Delete a memory block. This @em really returns the memory to the heap.
+ @param b block to delete
+ @internal
+*/
+void KZoneAllocator::delBlock(MemBlock *b)
+{
+ /* Update also the hashlists if we aren't going to reconstruct them
+ soon. */
+ if (hashList && !hashDirty) {
+ unsigned long adr = ((unsigned long)b->begin) & (~(blockSize - 1));
+ unsigned long end = ((unsigned long)b->begin) + blockSize;
+ while (adr < end) {
+ unsigned long key = adr >> log2;
+ key = key & (hashSize - 1);
+ if (hashList[key]) {
+ QValueList<MemBlock *> *list = hashList[key];
+ QValueList<MemBlock *>::Iterator it = list->begin();
+ QValueList<MemBlock *>::Iterator endit = list->end();
+ for (; it != endit; ++it)
+ if (*it == b) {
+ list->remove(it);
+ break;
+ }
+ }
+ adr += blockSize;
+ }
+ }
+ if (b->older)
+ b->older->newer = b->newer;
+ if (b->newer)
+ b->newer->older = b->older;
+ if (b == currentBlock) {
+ currentBlock = 0;
+ blockOffset = blockSize;
+ }
+ delete b;
+ num_blocks--;
+}
+
+void *
+KZoneAllocator::allocate(size_t _size)
+{
+ // Use the size of (void *) as alignment
+ const size_t alignment = sizeof(void *) - 1;
+ _size = (_size + alignment) & ~alignment;
+
+ if ((unsigned long) _size + blockOffset > blockSize)
+ {
+ if (_size > blockSize) {
+ qDebug("KZoneAllocator: allocating more than %lu bytes", blockSize);
+ return 0;
+ }
+ addBlock(new MemBlock(blockSize));
+ blockOffset = 0;
+ //qDebug ("Allocating block #%d (%x)\n", num_blocks, currentBlock->begin);
+ }
+ void *result = (void *)(currentBlock->begin+blockOffset);
+ currentBlock->ref++;
+ blockOffset += _size;
+ return result;
+}
+
+void
+KZoneAllocator::deallocate(void *ptr)
+{
+ if (hashDirty)
+ initHash();
+
+ unsigned long key = (((unsigned long)ptr) >> log2) & (hashSize - 1);
+ QValueList<MemBlock *> *list = hashList[key];
+ if (!list) {
+ /* Can happen with certain usage pattern of intermixed free_since()
+ and deallocate(). */
+ //qDebug("Uhoh");
+ return;
+ }
+ QValueList<MemBlock*>::ConstIterator it = list->begin();
+ QValueList<MemBlock*>::ConstIterator endit = list->end();
+ for (; it != endit; ++it) {
+ MemBlock *cur = *it;
+ if (cur->is_in(ptr)) {
+ if (!--cur->ref) {
+ if (cur != currentBlock)
+ delBlock (cur);
+ else
+ blockOffset = 0;
+ }
+ return;
+ }
+ }
+ /* Can happen with certain usage pattern of intermixed free_since()
+ and deallocate(). */
+ //qDebug("Uhoh2");
+}
+
+void
+KZoneAllocator::free_since(void *ptr)
+{
+ /* If we have a hashList and it's not yet dirty, see, if we will dirty
+ it by removing too many blocks. This will make the below delBlock()s
+ faster. */
+ if (hashList && !hashDirty)
+ {
+ const MemBlock *b;
+ unsigned int removed = 0;
+ for (b = currentBlock; b; b = b->older, removed++)
+ if (b->is_in (ptr))
+ break;
+ if (hashSize >= 4 * (num_blocks - removed))
+ hashDirty = true;
+ }
+ while (currentBlock && !currentBlock->is_in(ptr)) {
+ currentBlock = currentBlock->older;
+ delBlock (currentBlock->newer);
+ }
+ blockOffset = ((char*)ptr) - currentBlock->begin;
+}
diff --git a/kdecore/kallocator.h b/kdecore/kallocator.h
new file mode 100644
index 000000000..755926c81
--- /dev/null
+++ b/kdecore/kallocator.h
@@ -0,0 +1,140 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2002 Michael Matz (matz@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+//----------------------------------------------------------------------------
+//
+// KDE Memory Allocator
+
+#ifndef KALLOCATOR_H
+#define KALLOCATOR_H
+
+#include <qvaluelist.h>
+#include "kdelibs_export.h"
+
+class KZoneAllocatorPrivate;
+
+
+/**
+ * Memory allocator for large groups of small objects.
+ * This should be used for large groups of objects that are created and
+ * destroyed together. When used carefully for this purpose it is faster
+ * and more memory efficient than malloc. Additionally to a usual obstack
+ * like allocator you can also free the objects individually. Because it
+ * does no compaction it still is faster then malloc()/free(). Depending
+ * on the exact usage pattern that might come at the expense of some
+ * memory though.
+ * @author Waldo Bastian <bastian@kde.org>, Michael Matz <matz@kde.org>
+ */
+class KDECORE_EXPORT KZoneAllocator
+{
+public:
+ /**
+ * Creates a KZoneAllocator object.
+ * @param _blockSize Size in bytes of the blocks requested from malloc.
+ */
+ KZoneAllocator(unsigned long _blockSize = 8*1024);
+
+ /**
+ * Destructs the ZoneAllocator and free all memory allocated by it.
+ */
+ ~KZoneAllocator();
+
+ /**
+ * Allocates a memory block.
+ * @param _size Size in bytes of the memory block. Memory is aligned to
+ * the size of a pointer.
+ */
+ void* allocate(size_t _size);
+
+ /**
+ * Gives back a block returned by allocate() to the zone
+ * allocator, and possibly deallocates the block holding it (when it's
+ * empty). The first deallocate() after many allocate() calls
+ * (or the first at all) builds an internal data structure for speeding
+ * up deallocation. The consistency of that structure is maintained
+ * from then on (by allocate() and deallocate()) unless many
+ * more objects are allocated without any intervening deallocation, in
+ * which case it's thrown away and rebuilt at the next deallocate().
+ *
+ * The effect of this is, that such initial deallocate() calls take
+ * more time then the normal calls, and that after this list is built, i.e.
+ * generally if deallocate() is used at all, also allocate() is a
+ * little bit slower. This means, that if you want to squeeze out the last
+ * bit performance you would want to use KZoneAllocator as an obstack, i.e.
+ * just use the functions allocate() and free_since(). All the
+ * remaining memory is returned to the system if the zone allocator
+ * is destroyed.
+ * @param ptr Pointer as returned by allocate().
+ */
+ void deallocate(void *ptr);
+
+ /**
+ * Deallocate many objects at once.
+ * free_since() deallocates all objects allocated after @p ptr,
+ * @em including @p ptr itself.
+ *
+ * The intended use is something along the lines of:
+ * \code
+ * KZoneAllocator alloc(8192);
+ * void *remember_me = alloc.allocate(0);
+ * for (int i = 0; i < 1000; i++)
+ * do_something_with (alloc.allocate(12));
+ * alloc.free_since (remember_me);
+ * \endcode
+ * Note, that we don't need to remember all the pointers to the 12-byte
+ * objects for freeing them. The free_since() does deallocate them
+ * all at once.
+ * @param ptr Pointer as returned by allocate(). It acts like
+ * a kind of mark of a certain position in the stack of all objects,
+ * off which you can throw away everything above that mark.
+ */
+ void free_since(void *ptr);
+
+protected:
+ /** A single chunk of memory from the heap. @internal */
+ class MemBlock;
+ /**< A list of chunks. @internal */
+ typedef QValueList<MemBlock *> MemList;
+ void addBlock(MemBlock *b);
+ void delBlock(MemBlock *b);
+ void insertHash(MemBlock *b);
+ void initHash();
+ /** One block is 'current' to satisfy requests. @internal */
+ MemBlock *currentBlock;
+ /** Store block size from constructor. @internal */
+ unsigned long blockSize;
+ /** Store offset into current block; size-offset is free. @internal */
+ unsigned long blockOffset;
+ /** base-2 log of the block size. @internal */
+ unsigned int log2;
+ /** Count total number of allocated blocks. @internal */
+ unsigned int num_blocks;
+ /** Collection of lists of blocks, for lookups. @internal */
+ MemList **hashList;
+ /** Count of hashes. @internal */
+ unsigned int hashSize;
+ /** Flag the hashes as in need of reorganization. @internal */
+ bool hashDirty;
+private:
+ KZoneAllocatorPrivate *d;
+};
+
+#endif
diff --git a/kdecore/kapp.h b/kdecore/kapp.h
new file mode 100644
index 000000000..c51c463a0
--- /dev/null
+++ b/kdecore/kapp.h
@@ -0,0 +1,6 @@
+// kapp.h is the old name. Use #include <kapplication.h> from now on
+#ifdef KDE_NO_COMPAT
+#error include <kapplication.h> instead of <kapp.h>
+#else
+#include <kapplication.h>
+#endif
diff --git a/kdecore/kappdcopiface.cpp b/kdecore/kappdcopiface.cpp
new file mode 100644
index 000000000..f6e2f0e63
--- /dev/null
+++ b/kdecore/kappdcopiface.cpp
@@ -0,0 +1,66 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Ian Reinhart Geiser <geiseri@yahoo.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Lesser 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 Lesser 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 "kappdcopiface.h"
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kglobal.h>
+#include <kconfig.h>
+
+
+KAppDCOPInterface::KAppDCOPInterface(KApplication * theKApp)
+ : DCOPObject( "MainApplication-Interface")
+{
+ m_KApplication = theKApp;
+}
+
+KAppDCOPInterface::~KAppDCOPInterface()
+{
+}
+
+void KAppDCOPInterface::disableSessionManagement()
+{
+
+}
+
+QCString KAppDCOPInterface::startupId()
+{
+ return "";
+}
+
+QCString KAppDCOPInterface::caption()
+{
+ return "";
+}
+
+void KAppDCOPInterface::quit()
+{
+ m_KApplication->quit();
+}
+
+void KAppDCOPInterface::updateUserTimestamp( ulong time )
+{
+ m_KApplication->updateUserTimestamp( time );
+}
+
+void KAppDCOPInterface::reparseConfiguration()
+{
+ KGlobal::config()->reparseConfiguration();
+}
+
diff --git a/kdecore/kappdcopiface.h b/kdecore/kappdcopiface.h
new file mode 100644
index 000000000..e5490bb95
--- /dev/null
+++ b/kdecore/kappdcopiface.h
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Ian Reinhart Geiser <geiseri@yahoo.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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 Library 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 KAPPDCOP_INTERFACE_H
+#define KAPPDCOP_INTERFACE_H
+
+#include <dcopobject.h>
+#include <qstringlist.h>
+#include <qcstring.h>
+#include <dcopref.h>
+#include "kdelibs_export.h"
+
+class KApplication;
+
+/**
+This is the main interface to the KApplication. This will provide a consistant
+dcop interface to all KDE applications that use it.
+@short DCOP interface to KApplication.
+@author Ian Reinhart Geiser <geiseri@yahoo.com>
+*/
+class KDECORE_EXPORT KAppDCOPInterface : virtual public DCOPObject
+{
+K_DCOP
+
+public:
+ /**
+ Construct a new interface object.
+ @param theKapp - The parent KApplication object
+ that will provide us with the functional interface.
+ */
+ KAppDCOPInterface( KApplication * theKapp );
+ /**
+ Destructor
+ Cleans up the dcop connection.
+ **/
+ ~KAppDCOPInterface();
+k_dcop:
+ /**
+ Disable current applications session management
+ **/
+ void disableSessionManagement();
+
+ QCString startupId();
+ QCString caption();
+
+ void quit();
+
+ void reparseConfiguration();
+
+ void updateUserTimestamp( ulong time );
+
+private:
+ KApplication *m_KApplication;
+};
+
+#endif
+
+
diff --git a/kdecore/kapplication.cpp b/kdecore/kapplication.cpp
new file mode 100644
index 000000000..59ff86745
--- /dev/null
+++ b/kdecore/kapplication.cpp
@@ -0,0 +1,3272 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ Copyright (C) 1998, 1999, 2000 KDE Team
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#undef QT_NO_TRANSLATION
+#include <qtranslator.h>
+#define QT_NO_TRANSLATION
+#include <qdir.h>
+#include <qptrcollection.h>
+#include <qwidgetlist.h>
+#include <qstrlist.h>
+#include <qfile.h>
+#include <qmessagebox.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qlineedit.h>
+#include <qtextedit.h>
+#include <qsessionmanager.h>
+#include <qptrlist.h>
+#include <qtimer.h>
+#include <qstylesheet.h>
+#include <qpixmapcache.h>
+#include <qtooltip.h>
+#include <qstylefactory.h>
+#include <qmetaobject.h>
+#ifndef QT_NO_SQL
+#include <qsqlpropertymap.h>
+#endif
+
+#undef QT_NO_TRANSLATION
+#include "kapplication.h"
+#define QT_NO_TRANSLATION
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstyle.h>
+#include <kiconloader.h>
+#include <kclipboard.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kglobalsettings.h>
+#include <kcrash.h>
+#include <kdatastream.h>
+#include <klibloader.h>
+#include <kmimesourcefactory.h>
+#include <kstdaccel.h>
+#include <kaccel.h>
+#include "kcheckaccelerators.h"
+#include <qptrdict.h>
+#include <kmacroexpander.h>
+#include <kshell.h>
+#include <kprotocolinfo.h>
+#include <kkeynative.h>
+#include <kmdcodec.h>
+#include <kglobalaccel.h>
+
+#if defined Q_WS_X11
+#include <kstartupinfo.h>
+#endif
+
+#include <dcopclient.h>
+#include <dcopref.h>
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <sys/wait.h>
+
+#ifndef Q_WS_WIN
+#include "kwin.h"
+#endif
+
+#include <fcntl.h>
+#include <stdlib.h> // getenv(), srand(), rand()
+#include <signal.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#if defined Q_WS_X11
+//#ifndef Q_WS_QWS //FIXME(E): NetWM should talk to QWS...
+#include <netwm.h>
+#endif
+
+#include "kprocctrl.h"
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifdef Q_WS_X11
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/SM/SMlib.h>
+#include <fixx11h.h>
+#endif
+
+#ifndef Q_WS_WIN
+#include <KDE-ICE/ICElib.h>
+#else
+typedef void* IceIOErrorHandler;
+#include <windows.h>
+//KDE4: remove
+#define Button1Mask (1<<8)
+#define Button2Mask (1<<9)
+#define Button3Mask (1<<10)
+#endif
+
+#ifdef Q_WS_X11
+#define DISPLAY "DISPLAY"
+#elif defined(Q_WS_QWS)
+#define DISPLAY "QWS_DISPLAY"
+#endif
+
+#if defined Q_WS_X11
+#include <kipc.h>
+#endif
+
+#ifdef Q_WS_MACX
+#include <Carbon/Carbon.h>
+#include <qimage.h>
+#endif
+
+#include "kappdcopiface.h"
+
+// exported for kdm kfrontend
+KDE_EXPORT bool kde_have_kipc = true; // magic hook to disable kipc in kdm
+bool kde_kiosk_exception = false; // flag to disable kiosk restrictions
+bool kde_kiosk_admin = false;
+
+KApplication* KApplication::KApp = 0L;
+bool KApplication::loadedByKdeinit = false;
+DCOPClient *KApplication::s_DCOPClient = 0L;
+bool KApplication::s_dcopClientNeedsPostInit = false;
+
+#ifdef Q_WS_X11
+static Atom atom_DesktopWindow;
+static Atom atom_NetSupported;
+extern Time qt_x_time;
+extern Time qt_x_user_time;
+static Atom kde_xdnd_drop;
+#endif
+
+// duplicated from patched Qt, so that there won't be unresolved symbols if Qt gets
+// replaced by unpatched one
+KDECORE_EXPORT bool qt_qclipboard_bailout_hack = false;
+
+template class QPtrList<KSessionManaged>;
+
+#ifdef Q_WS_X11
+extern "C" {
+static int kde_xio_errhandler( Display * dpy )
+{
+ return kapp->xioErrhandler( dpy );
+}
+
+static int kde_x_errhandler( Display *dpy, XErrorEvent *err )
+{
+ return kapp->xErrhandler( dpy, err );
+}
+
+}
+
+extern "C" {
+static void kde_ice_ioerrorhandler( IceConn conn )
+{
+ if(kapp)
+ kapp->iceIOErrorHandler( conn );
+ // else ignore the error for now
+}
+}
+#endif
+
+#ifdef Q_WS_WIN
+void KApplication_init_windows(bool GUIenabled);
+
+class QAssistantClient;
+#endif
+
+/*
+ Private data to make keeping binary compatibility easier
+ */
+class KApplicationPrivate
+{
+public:
+ KApplicationPrivate()
+ : actionRestrictions( false ),
+ refCount( 1 ),
+ oldIceIOErrorHandler( 0 ),
+ checkAccelerators( 0 ),
+ overrideStyle( QString::null ),
+ startup_id( "0" ),
+ app_started_timer( NULL ),
+ m_KAppDCOPInterface( 0L ),
+ session_save( false )
+#ifdef Q_WS_X11
+ ,oldXErrorHandler( NULL )
+ ,oldXIOErrorHandler( NULL )
+#elif defined Q_WS_WIN
+ ,qassistantclient( 0 )
+#endif
+ {
+ }
+
+ ~KApplicationPrivate()
+ {
+#ifdef Q_WS_WIN
+ delete qassistantclient;
+#endif
+ }
+
+
+ bool actionRestrictions : 1;
+ bool guiEnabled : 1;
+ /**
+ * This counter indicates when to exit the application.
+ * It starts at 1, is decremented in KMainWindow when the last window is closed, but
+ * is incremented by operations that should outlive the last window closed
+ * (e.g. a file copy for a file manager, or 'compacting folders on exit' for a mail client).
+ */
+ int refCount;
+ IceIOErrorHandler oldIceIOErrorHandler;
+ KCheckAccelerators* checkAccelerators;
+ QString overrideStyle;
+ QString geometry_arg;
+ QCString startup_id;
+ QTimer* app_started_timer;
+ KAppDCOPInterface *m_KAppDCOPInterface;
+ bool session_save;
+#ifdef Q_WS_X11
+ int (*oldXErrorHandler)(Display*,XErrorEvent*);
+ int (*oldXIOErrorHandler)(Display*);
+#elif defined Q_WS_WIN
+ QAssistantClient* qassistantclient;
+#endif
+
+ class URLActionRule
+ {
+ public:
+#define checkExactMatch(s, b) \
+ if (s.isEmpty()) b = true; \
+ else if (s[s.length()-1] == '!') \
+ { b = false; s.truncate(s.length()-1); } \
+ else b = true;
+#define checkStartWildCard(s, b) \
+ if (s.isEmpty()) b = true; \
+ else if (s[0] == '*') \
+ { b = true; s = s.mid(1); } \
+ else b = false;
+#define checkEqual(s, b) \
+ b = (s == "=");
+
+ URLActionRule(const QString &act,
+ const QString &bProt, const QString &bHost, const QString &bPath,
+ const QString &dProt, const QString &dHost, const QString &dPath,
+ bool perm)
+ : action(act),
+ baseProt(bProt), baseHost(bHost), basePath(bPath),
+ destProt(dProt), destHost(dHost), destPath(dPath),
+ permission(perm)
+ {
+ checkExactMatch(baseProt, baseProtWildCard);
+ checkStartWildCard(baseHost, baseHostWildCard);
+ checkExactMatch(basePath, basePathWildCard);
+ checkExactMatch(destProt, destProtWildCard);
+ checkStartWildCard(destHost, destHostWildCard);
+ checkExactMatch(destPath, destPathWildCard);
+ checkEqual(destProt, destProtEqual);
+ checkEqual(destHost, destHostEqual);
+ }
+
+ bool baseMatch(const KURL &url, const QString &protClass)
+ {
+ if (baseProtWildCard)
+ {
+ if ( !baseProt.isEmpty() && !url.protocol().startsWith(baseProt) &&
+ (protClass.isEmpty() || (protClass != baseProt)) )
+ return false;
+ }
+ else
+ {
+ if ( (url.protocol() != baseProt) &&
+ (protClass.isEmpty() || (protClass != baseProt)) )
+ return false;
+ }
+ if (baseHostWildCard)
+ {
+ if (!baseHost.isEmpty() && !url.host().endsWith(baseHost))
+ return false;
+ }
+ else
+ {
+ if (url.host() != baseHost)
+ return false;
+ }
+ if (basePathWildCard)
+ {
+ if (!basePath.isEmpty() && !url.path().startsWith(basePath))
+ return false;
+ }
+ else
+ {
+ if (url.path() != basePath)
+ return false;
+ }
+ return true;
+ }
+
+ bool destMatch(const KURL &url, const QString &protClass, const KURL &base, const QString &baseClass)
+ {
+ if (destProtEqual)
+ {
+ if ( (url.protocol() != base.protocol()) &&
+ (protClass.isEmpty() || baseClass.isEmpty() || protClass != baseClass) )
+ return false;
+ }
+ else if (destProtWildCard)
+ {
+ if ( !destProt.isEmpty() && !url.protocol().startsWith(destProt) &&
+ (protClass.isEmpty() || (protClass != destProt)) )
+ return false;
+ }
+ else
+ {
+ if ( (url.protocol() != destProt) &&
+ (protClass.isEmpty() || (protClass != destProt)) )
+ return false;
+ }
+ if (destHostWildCard)
+ {
+ if (!destHost.isEmpty() && !url.host().endsWith(destHost))
+ return false;
+ }
+ else if (destHostEqual)
+ {
+ if (url.host() != base.host())
+ return false;
+ }
+ else
+ {
+ if (url.host() != destHost)
+ return false;
+ }
+ if (destPathWildCard)
+ {
+ if (!destPath.isEmpty() && !url.path().startsWith(destPath))
+ return false;
+ }
+ else
+ {
+ if (url.path() != destPath)
+ return false;
+ }
+ return true;
+ }
+
+ QString action;
+ QString baseProt;
+ QString baseHost;
+ QString basePath;
+ QString destProt;
+ QString destHost;
+ QString destPath;
+ bool baseProtWildCard : 1;
+ bool baseHostWildCard : 1;
+ bool basePathWildCard : 1;
+ bool destProtWildCard : 1;
+ bool destHostWildCard : 1;
+ bool destPathWildCard : 1;
+ bool destProtEqual : 1;
+ bool destHostEqual : 1;
+ bool permission;
+ };
+ QPtrList<URLActionRule> urlActionRestrictions;
+
+ QString sessionKey;
+ QString pSessionConfigFile;
+};
+
+
+static QPtrList<QWidget>*x11Filter = 0;
+static bool autoDcopRegistration = true;
+
+void KApplication::installX11EventFilter( QWidget* filter )
+{
+ if ( !filter )
+ return;
+ if (!x11Filter)
+ x11Filter = new QPtrList<QWidget>;
+ connect ( filter, SIGNAL( destroyed() ), this, SLOT( x11FilterDestroyed() ) );
+ x11Filter->append( filter );
+}
+
+void KApplication::x11FilterDestroyed()
+{
+ removeX11EventFilter( static_cast< const QWidget* >( sender()));
+}
+
+void KApplication::removeX11EventFilter( const QWidget* filter )
+{
+ if ( !x11Filter || !filter )
+ return;
+ x11Filter->removeRef( filter );
+ if ( x11Filter->isEmpty() ) {
+ delete x11Filter;
+ x11Filter = 0;
+ }
+}
+
+// FIXME: remove this when we've get a better method of
+// customizing accelerator handling -- hopefully in Qt.
+// For now, this is set whenever an accelerator is overridden
+// in KAccelEventHandler so that the AccelOverride isn't sent twice. -- ellis, 19/10/02
+extern bool kde_g_bKillAccelOverride;
+
+bool KApplication::notify(QObject *receiver, QEvent *event)
+{
+ QEvent::Type t = event->type();
+ if (kde_g_bKillAccelOverride)
+ {
+ kde_g_bKillAccelOverride = false;
+ // Indicate that the accelerator has been overridden.
+ if (t == QEvent::AccelOverride)
+ {
+ static_cast<QKeyEvent *>(event)->accept();
+ return true;
+ }
+ else
+ kdWarning(125) << "kde_g_bKillAccelOverride set, but received an event other than AccelOverride." << endl;
+ }
+
+ if ((t == QEvent::AccelOverride) || (t == QEvent::KeyPress))
+ {
+ static const KShortcut& _selectAll = KStdAccel::selectAll();
+ QLineEdit *edit = ::qt_cast<QLineEdit *>(receiver);
+ if (edit)
+ {
+ // We have a keypress for a lineedit...
+ QKeyEvent *kevent = static_cast<QKeyEvent *>(event);
+ KKey key(kevent);
+ if (_selectAll.contains(key))
+ {
+ if (t == QEvent::KeyPress)
+ {
+ edit->selectAll();
+ return true;
+ }
+ else
+ {
+ kevent->accept();
+ }
+ }
+ // Ctrl-U deletes from start of line.
+ if (key == KKey(Qt::CTRL + Qt::Key_U))
+ {
+ if (t == QEvent::KeyPress)
+ {
+ if (!edit->isReadOnly())
+ {
+ QString t(edit->text());
+ t = t.mid(edit->cursorPosition());
+ edit->validateAndSet(t, 0, 0, 0);
+ }
+ return true;
+ }
+ else
+ {
+ kevent->accept();
+ }
+
+ }
+ }
+ QTextEdit *medit = ::qt_cast<QTextEdit *>(receiver);
+ if (medit)
+ {
+ // We have a keypress for a multilineedit...
+ QKeyEvent *kevent = static_cast<QKeyEvent *>(event);
+ if (_selectAll.contains(KKey(kevent)))
+ {
+ if (t == QEvent::KeyPress)
+ {
+ medit->selectAll();
+ return true;
+ }
+ else
+ {
+ kevent->accept();
+ }
+ }
+ }
+ }
+ if( t == QEvent::Show && receiver->isWidgetType())
+ {
+ QWidget* w = static_cast< QWidget* >( receiver );
+#if defined Q_WS_X11
+ if( w->isTopLevel() && !startupId().isEmpty() && !static_cast<QShowEvent*>(event)->spontaneous()) // TODO better done using window group leader?
+ KStartupInfo::setWindowStartupId( w->winId(), startupId());
+#endif
+ if( w->isTopLevel() && !w->testWFlags( WX11BypassWM ) && !w->isPopup() && !event->spontaneous())
+ {
+ if( d->app_started_timer == NULL )
+ {
+ d->app_started_timer = new QTimer( this, "app_started_timer" );
+ connect( d->app_started_timer, SIGNAL( timeout()), SLOT( checkAppStartedSlot()));
+ }
+ if( !d->app_started_timer->isActive())
+ d->app_started_timer->start( 0, true );
+ }
+ if( w->isTopLevel() && ( w->icon() == NULL || w->icon()->isNull()))
+ {
+ // icon() cannot be null pixmap, it'll be the "unknown" icon - so check if there is this application icon
+ static QPixmap* ic = NULL;
+ if( ic == NULL )
+ ic = new QPixmap( KGlobal::iconLoader()->loadIcon( iconName(),
+ KIcon::NoGroup, 0, KIcon::DefaultState, NULL, true ));
+ if( !ic->isNull())
+ {
+ w->setIcon( *ic );
+#if defined Q_WS_X11
+ KWin::setIcons( w->winId(), *ic, miniIcon());
+#endif
+ }
+ }
+ }
+ return QApplication::notify(receiver, event);
+}
+
+void KApplication::checkAppStartedSlot()
+{
+#if defined Q_WS_X11
+ KStartupInfo::handleAutoAppStartedSending();
+#endif
+}
+
+// the help class for session management communication
+static QPtrList<KSessionManaged>* sessionClients()
+{
+ static QPtrList<KSessionManaged>* session_clients = 0L;
+ if ( !session_clients )
+ session_clients = new QPtrList<KSessionManaged>;
+ return session_clients;
+}
+
+/*
+ Auxiliary function to calculate a a session config name used for the
+ instance specific config object.
+ Syntax: "session/<appname>_<sessionId>"
+ */
+QString KApplication::sessionConfigName() const
+{
+ QString sessKey = sessionKey();
+ if ( sessKey.isEmpty() && !d->sessionKey.isEmpty() )
+ sessKey = d->sessionKey;
+ return QString("session/%1_%2_%3").arg(name()).arg(sessionId()).arg(sessKey);
+}
+
+#ifdef Q_WS_X11
+static SmcConn mySmcConnection = 0;
+static SmcConn tmpSmcConnection = 0;
+#else
+// FIXME(E): Implement for Qt Embedded
+// Possibly "steal" XFree86's libSM?
+#endif
+static QTime* smModificationTime = 0;
+
+KApplication::KApplication( int& argc, char** argv, const QCString& rAppName,
+ bool allowStyles, bool GUIenabled ) :
+ QApplication( argc, argv, GUIenabled ), KInstance(rAppName),
+#ifdef Q_WS_X11
+ display(0L),
+#endif
+ d (new KApplicationPrivate())
+{
+ aIconPixmap.pm.icon = 0L;
+ aIconPixmap.pm.miniIcon = 0L;
+ read_app_startup_id();
+ if (!GUIenabled)
+ allowStyles = false;
+ useStyles = allowStyles;
+ Q_ASSERT (!rAppName.isEmpty());
+ setName(rAppName);
+
+ installSigpipeHandler();
+ KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
+ parseCommandLine( );
+ init(GUIenabled);
+ d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
+}
+
+KApplication::KApplication( bool allowStyles, bool GUIenabled ) :
+ QApplication( *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv(),
+ GUIenabled ),
+ KInstance( KCmdLineArgs::about),
+#ifdef Q_WS_X11
+ display(0L),
+#endif
+ d (new KApplicationPrivate)
+{
+ aIconPixmap.pm.icon = 0L;
+ aIconPixmap.pm.miniIcon = 0L;
+ read_app_startup_id();
+ if (!GUIenabled)
+ allowStyles = false;
+ useStyles = allowStyles;
+ setName( instanceName() );
+
+ installSigpipeHandler();
+ parseCommandLine( );
+ init(GUIenabled);
+ d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
+}
+
+#ifdef Q_WS_X11
+KApplication::KApplication( Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap,
+ bool allowStyles ) :
+ QApplication( dpy, *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv(),
+ visual, colormap ),
+ KInstance( KCmdLineArgs::about), display(0L), d (new KApplicationPrivate)
+{
+ aIconPixmap.pm.icon = 0L;
+ aIconPixmap.pm.miniIcon = 0L;
+ read_app_startup_id();
+ useStyles = allowStyles;
+ setName( instanceName() );
+ installSigpipeHandler();
+ parseCommandLine( );
+ init( true );
+ d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
+}
+
+KApplication::KApplication( Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap,
+ bool allowStyles, KInstance * _instance ) :
+ QApplication( dpy, *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv(),
+ visual, colormap ),
+ KInstance( _instance ), display(0L), d (new KApplicationPrivate)
+{
+ aIconPixmap.pm.icon = 0L;
+ aIconPixmap.pm.miniIcon = 0L;
+ read_app_startup_id();
+ useStyles = allowStyles;
+ setName( instanceName() );
+ installSigpipeHandler();
+ parseCommandLine( );
+ init( true );
+ d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
+}
+#endif
+
+KApplication::KApplication( bool allowStyles, bool GUIenabled, KInstance* _instance ) :
+ QApplication( *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv(),
+ GUIenabled ),
+ KInstance( _instance ),
+#ifdef Q_WS_X11
+ display(0L),
+#endif
+ d (new KApplicationPrivate)
+{
+ aIconPixmap.pm.icon = 0L;
+ aIconPixmap.pm.miniIcon = 0L;
+ read_app_startup_id();
+ if (!GUIenabled)
+ allowStyles = false;
+ useStyles = allowStyles;
+ setName( instanceName() );
+
+ installSigpipeHandler();
+ parseCommandLine( );
+ init(GUIenabled);
+ d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
+}
+
+#ifdef Q_WS_X11
+KApplication::KApplication(Display *display, int& argc, char** argv, const QCString& rAppName,
+ bool allowStyles, bool GUIenabled ) :
+ QApplication( display ), KInstance(rAppName),
+ display(0L),
+ d (new KApplicationPrivate())
+{
+ aIconPixmap.pm.icon = 0L;
+ aIconPixmap.pm.miniIcon = 0L;
+ read_app_startup_id();
+ if (!GUIenabled)
+ allowStyles = false;
+ useStyles = allowStyles;
+
+ Q_ASSERT (!rAppName.isEmpty());
+ setName(rAppName);
+
+ installSigpipeHandler();
+ KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
+ parseCommandLine( );
+ init(GUIenabled);
+ d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
+}
+#endif
+
+int KApplication::xioErrhandler( Display* dpy )
+{
+ if(kapp)
+ {
+ emit shutDown();
+#ifdef Q_WS_X11
+ d->oldXIOErrorHandler( dpy );
+#else
+ Q_UNUSED(dpy);
+#endif
+ }
+ exit( 1 );
+ return 0;
+}
+
+int KApplication::xErrhandler( Display* dpy, void* err_ )
+{ // no idea how to make forward decl. for XErrorEvent
+#ifdef Q_WS_X11
+ XErrorEvent* err = static_cast< XErrorEvent* >( err_ );
+ if(kapp)
+ {
+ // add KDE specific stuff here
+ d->oldXErrorHandler( dpy, err );
+ }
+#endif
+ return 0;
+}
+
+void KApplication::iceIOErrorHandler( _IceConn *conn )
+{
+ emit shutDown();
+
+#ifdef Q_WS_X11
+ if ( d->oldIceIOErrorHandler != NULL )
+ (*d->oldIceIOErrorHandler)( conn );
+#endif
+ exit( 1 );
+}
+
+class KDETranslator : public QTranslator
+{
+public:
+ KDETranslator(QObject *parent) : QTranslator(parent, "kdetranslator") {}
+ virtual QTranslatorMessage findMessage(const char* context,
+ const char *sourceText,
+ const char* message) const
+ {
+ QTranslatorMessage res;
+ res.setTranslation(KGlobal::locale()->translateQt(context, sourceText, message));
+ return res;
+ }
+};
+
+void KApplication::init(bool GUIenabled)
+{
+ d->guiEnabled = GUIenabled;
+ if ((getuid() != geteuid()) ||
+ (getgid() != getegid()))
+ {
+ fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
+ ::exit(127);
+ }
+
+ KProcessController::ref();
+
+ (void) KClipboardSynchronizer::self();
+
+ QApplication::setDesktopSettingsAware( false );
+
+ KApp = this;
+
+
+#ifdef Q_WS_X11 //FIXME(E)
+ // create all required atoms in _one_ roundtrip to the X server
+ if ( GUIenabled ) {
+ const int max = 20;
+ Atom* atoms[max];
+ char* names[max];
+ Atom atoms_return[max];
+ int n = 0;
+
+ atoms[n] = &kipcCommAtom;
+ names[n++] = (char *) "KIPC_COMM_ATOM";
+
+ atoms[n] = &atom_DesktopWindow;
+ names[n++] = (char *) "KDE_DESKTOP_WINDOW";
+
+ atoms[n] = &atom_NetSupported;
+ names[n++] = (char *) "_NET_SUPPORTED";
+
+ atoms[n] = &kde_xdnd_drop;
+ names[n++] = (char *) "XdndDrop";
+
+ XInternAtoms( qt_xdisplay(), names, n, false, atoms_return );
+
+ for (int i = 0; i < n; i++ )
+ *atoms[i] = atoms_return[i];
+ }
+#endif
+
+ dcopAutoRegistration();
+ dcopClientPostInit();
+
+ smw = 0;
+
+ // Initial KIPC event mask.
+#if defined Q_WS_X11
+ kipcEventMask = (1 << KIPC::StyleChanged) | (1 << KIPC::PaletteChanged) |
+ (1 << KIPC::FontChanged) | (1 << KIPC::BackgroundChanged) |
+ (1 << KIPC::ToolbarStyleChanged) | (1 << KIPC::SettingsChanged) |
+ (1 << KIPC::ClipboardConfigChanged) | (1 << KIPC::BlockShortcuts);
+#endif
+
+ // Trigger creation of locale.
+ (void) KGlobal::locale();
+
+ KConfig* config = KGlobal::config();
+ d->actionRestrictions = config->hasGroup("KDE Action Restrictions" ) && !kde_kiosk_exception;
+ // For brain-dead configurations where the user's local config file is not writable.
+ // * We use kdialog to warn the user, so we better not generate warnings from
+ // kdialog itself.
+ // * Don't warn if we run with a read-only $HOME
+ QCString readOnly = getenv("KDE_HOME_READONLY");
+ if (readOnly.isEmpty() && (qstrcmp(name(), "kdialog") != 0))
+ {
+ KConfigGroupSaver saver(config, "KDE Action Restrictions");
+ if (config->readBoolEntry("warn_unwritable_config",true))
+ config->checkConfigFilesWritable(true);
+ }
+
+ if (GUIenabled)
+ {
+#ifdef Q_WS_X11
+ // this is important since we fork() to launch the help (Matthias)
+ fcntl(ConnectionNumber(qt_xdisplay()), F_SETFD, FD_CLOEXEC);
+ // set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias)
+ d->oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
+ d->oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
+#endif
+
+ connect( this, SIGNAL( aboutToQuit() ), this, SIGNAL( shutDown() ) );
+
+#ifdef Q_WS_X11 //FIXME(E)
+ display = desktop()->x11Display();
+#endif
+
+ {
+ QStringList plugins = KGlobal::dirs()->resourceDirs( "qtplugins" );
+ QStringList::Iterator it = plugins.begin();
+ while (it != plugins.end()) {
+ addLibraryPath( *it );
+ ++it;
+ }
+
+ }
+ kdisplaySetStyle();
+ kdisplaySetFont();
+// kdisplaySetPalette(); done by kdisplaySetStyle
+ propagateSettings(SETTINGS_QT);
+
+ // Set default mime-source factory
+ // XXX: This is a hack. Make our factory the default factory, but add the
+ // previous default factory to the list of factories. Why? When the default
+ // factory can't resolve something, it iterates in the list of factories.
+ // But it QWhatsThis only uses the default factory. So if there was already
+ // a default factory (which happens when using an image library using uic),
+ // we prefer KDE's factory and so we put that old default factory in the
+ // list and use KDE as the default. This may speed up things as well.
+ QMimeSourceFactory* oldDefaultFactory = QMimeSourceFactory::takeDefaultFactory();
+ QMimeSourceFactory::setDefaultFactory( mimeSourceFactory() );
+ if ( oldDefaultFactory ) {
+ QMimeSourceFactory::addFactory( oldDefaultFactory );
+ }
+
+ d->checkAccelerators = new KCheckAccelerators( this );
+ }
+
+#ifdef Q_WS_MACX
+ if (GUIenabled) {
+ QPixmap pixmap = KGlobal::iconLoader()->loadIcon( KCmdLineArgs::appName(),
+ KIcon::NoGroup, KIcon::SizeLarge, KIcon::DefaultState, 0L, false );
+ if (!pixmap.isNull()) {
+ QImage i = pixmap.convertToImage().convertDepth(32).smoothScale(40, 40);
+ for(int y = 0; y < i.height(); y++) {
+ uchar *l = i.scanLine(y);
+ for(int x = 0; x < i.width(); x+=4)
+ *(l+x) = 255;
+ }
+ CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
+ CGDataProviderRef dp = CGDataProviderCreateWithData(NULL,
+ i.bits(), i.numBytes(), NULL);
+ CGImageRef ir = CGImageCreate(i.width(), i.height(), 8, 32, i.bytesPerLine(),
+ cs, kCGImageAlphaNoneSkipFirst, dp,
+ 0, 0, kCGRenderingIntentDefault);
+ //cleanup
+ SetApplicationDockTileImage(ir);
+ CGImageRelease(ir);
+ CGColorSpaceRelease(cs);
+ CGDataProviderRelease(dp);
+ }
+ }
+#endif
+
+
+ // save and restore the RTL setting, as installTranslator calls qt_detectRTLLanguage,
+ // which makes it impossible to use the -reverse cmdline switch with KDE apps
+ bool rtl = reverseLayout();
+ installTranslator(new KDETranslator(this));
+ setReverseLayout( rtl );
+ if (i18n( "_: Dear Translator! Translate this string to the string 'LTR' in "
+ "left-to-right languages (as english) or to 'RTL' in right-to-left "
+ "languages (such as Hebrew and Arabic) to get proper widget layout." ) == "RTL")
+ setReverseLayout( !rtl );
+
+ // install appdata resource type
+ KGlobal::dirs()->addResourceType("appdata", KStandardDirs::kde_default("data")
+ + QString::fromLatin1(name()) + '/');
+ pSessionConfig = 0L;
+ bSessionManagement = true;
+
+#ifdef Q_WS_X11
+ // register a communication window for desktop changes (Matthias)
+ if (GUIenabled && kde_have_kipc )
+ {
+ smw = new QWidget(0,0);
+ long data = 1;
+ XChangeProperty(qt_xdisplay(), smw->winId(),
+ atom_DesktopWindow, atom_DesktopWindow,
+ 32, PropModeReplace, (unsigned char *)&data, 1);
+ }
+ d->oldIceIOErrorHandler = IceSetIOErrorHandler( kde_ice_ioerrorhandler );
+#elif defined(Q_WS_WIN)
+ KApplication_init_windows(GUIenabled);
+#else
+ // FIXME(E): Implement for Qt Embedded
+#endif
+}
+
+static int my_system (const char *command) {
+ int pid, status;
+
+ pid = fork();
+ if (pid == -1)
+ return -1;
+ if (pid == 0) {
+ const char* shell = "/bin/sh";
+ execl(shell, shell, "-c", command, (void *)0);
+ ::_exit(127);
+ }
+ do {
+ if (waitpid(pid, &status, 0) == -1) {
+ if (errno != EINTR)
+ return -1;
+ } else
+ return status;
+ } while(1);
+}
+
+
+DCOPClient *KApplication::dcopClient()
+{
+ if (s_DCOPClient)
+ return s_DCOPClient;
+
+ s_DCOPClient = new DCOPClient();
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
+ if (args && args->isSet("dcopserver"))
+ {
+ s_DCOPClient->setServerAddress( args->getOption("dcopserver"));
+ }
+ if( kapp ) {
+ connect(s_DCOPClient, SIGNAL(attachFailed(const QString &)),
+ kapp, SLOT(dcopFailure(const QString &)));
+ connect(s_DCOPClient, SIGNAL(blockUserInput(bool) ),
+ kapp, SLOT(dcopBlockUserInput(bool)) );
+ }
+ else
+ s_dcopClientNeedsPostInit = true;
+
+ DCOPClient::setMainClient( s_DCOPClient );
+ return s_DCOPClient;
+}
+
+void KApplication::dcopClientPostInit()
+{
+ if( s_dcopClientNeedsPostInit )
+ {
+ s_dcopClientNeedsPostInit = false;
+ connect(s_DCOPClient, SIGNAL(blockUserInput(bool) ),
+ SLOT(dcopBlockUserInput(bool)) );
+ s_DCOPClient->bindToApp(); // Make sure we get events from the DCOPClient.
+ }
+}
+
+void KApplication::dcopAutoRegistration()
+{
+ if (autoDcopRegistration)
+ {
+ ( void ) dcopClient();
+ if( dcopClient()->appId().isEmpty())
+ dcopClient()->registerAs(name());
+ }
+}
+
+void KApplication::disableAutoDcopRegistration()
+{
+ autoDcopRegistration = false;
+}
+
+KConfig* KApplication::sessionConfig()
+{
+ if (pSessionConfig)
+ return pSessionConfig;
+
+ // create an instance specific config object
+ pSessionConfig = new KConfig( sessionConfigName(), false, false);
+ return pSessionConfig;
+}
+
+void KApplication::ref()
+{
+ d->refCount++;
+ //kdDebug() << "KApplication::ref() : refCount = " << d->refCount << endl;
+}
+
+void KApplication::deref()
+{
+ d->refCount--;
+ //kdDebug() << "KApplication::deref() : refCount = " << d->refCount << endl;
+ if ( d->refCount <= 0 )
+ quit();
+}
+
+KSessionManaged::KSessionManaged()
+{
+ sessionClients()->remove( this );
+ sessionClients()->append( this );
+}
+
+KSessionManaged::~KSessionManaged()
+{
+ sessionClients()->remove( this );
+}
+
+bool KSessionManaged::saveState(QSessionManager&)
+{
+ return true;
+}
+
+bool KSessionManaged::commitData(QSessionManager&)
+{
+ return true;
+}
+
+
+void KApplication::disableSessionManagement() {
+ bSessionManagement = false;
+}
+
+void KApplication::enableSessionManagement() {
+ bSessionManagement = true;
+#ifdef Q_WS_X11
+ // Session management support in Qt/KDE is awfully broken.
+ // If konqueror disables session management right after its startup,
+ // and enables it later (preloading stuff), it won't be properly
+ // saved on session shutdown.
+ // I'm not actually sure why it doesn't work, but saveState()
+ // doesn't seem to be called on session shutdown, possibly
+ // because disabling session management after konqueror startup
+ // disabled it somehow. Forcing saveState() here for this application
+ // seems to fix it.
+ if( mySmcConnection ) {
+ SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
+ SmInteractStyleAny,
+ False, False );
+
+ // flush the request
+ IceFlush(SmcGetIceConnection(mySmcConnection));
+ }
+#endif
+}
+
+
+bool KApplication::requestShutDown(
+ ShutdownConfirm confirm, ShutdownType sdtype, ShutdownMode sdmode )
+{
+#ifdef Q_WS_X11
+ QApplication::syncX();
+ /* use ksmserver's dcop interface if necessary */
+ if ( confirm == ShutdownConfirmYes ||
+ sdtype != ShutdownTypeDefault ||
+ sdmode != ShutdownModeDefault )
+ {
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << (int)confirm << (int)sdtype << (int)sdmode;
+ return dcopClient()->send( "ksmserver", "ksmserver",
+ "logout(int,int,int)", data );
+ }
+
+ if ( mySmcConnection ) {
+ // we already have a connection to the session manager, use it.
+ SmcRequestSaveYourself( mySmcConnection, SmSaveBoth, True,
+ SmInteractStyleAny,
+ confirm == ShutdownConfirmNo, True );
+
+ // flush the request
+ IceFlush(SmcGetIceConnection(mySmcConnection));
+ return true;
+ }
+
+ // open a temporary connection, if possible
+
+ propagateSessionManager();
+ QCString smEnv = ::getenv("SESSION_MANAGER");
+ if (smEnv.isEmpty())
+ return false;
+
+ if (! tmpSmcConnection) {
+ char cerror[256];
+ char* myId = 0;
+ char* prevId = 0;
+ SmcCallbacks cb;
+ tmpSmcConnection = SmcOpenConnection( 0, 0, 1, 0,
+ 0, &cb,
+ prevId,
+ &myId,
+ 255,
+ cerror );
+ ::free( myId ); // it was allocated by C
+ if (!tmpSmcConnection )
+ return false;
+ }
+
+ SmcRequestSaveYourself( tmpSmcConnection, SmSaveBoth, True,
+ SmInteractStyleAny, False, True );
+
+ // flush the request
+ IceFlush(SmcGetIceConnection(tmpSmcConnection));
+ return true;
+#else
+ // FIXME(E): Implement for Qt Embedded
+ return false;
+#endif
+}
+
+void KApplication::propagateSessionManager()
+{
+#ifdef Q_WS_X11
+ QCString fName = QFile::encodeName(locateLocal("socket", "KSMserver"));
+ QCString display = ::getenv(DISPLAY);
+ // strip the screen number from the display
+ display.replace(QRegExp("\\.[0-9]+$"), "");
+ int i;
+ while( (i = display.find(':')) >= 0)
+ display[i] = '_';
+
+ fName += "_"+display;
+ QCString smEnv = ::getenv("SESSION_MANAGER");
+ bool check = smEnv.isEmpty();
+ if ( !check && smModificationTime ) {
+ QFileInfo info( fName );
+ QTime current = info.lastModified().time();
+ check = current > *smModificationTime;
+ }
+ if ( check ) {
+ delete smModificationTime;
+ QFile f( fName );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ QFileInfo info ( f );
+ smModificationTime = new QTime( info.lastModified().time() );
+ QTextStream t(&f);
+ t.setEncoding( QTextStream::Latin1 );
+ QString s = t.readLine();
+ f.close();
+ ::setenv( "SESSION_MANAGER", s.latin1(), true );
+ }
+#endif
+}
+
+void KApplication::commitData( QSessionManager& sm )
+{
+ d->session_save = true;
+ bool canceled = false;
+ for (KSessionManaged* it = sessionClients()->first();
+ it && !canceled;
+ it = sessionClients()->next() ) {
+ canceled = !it->commitData( sm );
+ }
+ if ( canceled )
+ sm.cancel();
+
+ if ( sm.allowsInteraction() ) {
+ QWidgetList done;
+ QWidgetList *list = QApplication::topLevelWidgets();
+ bool canceled = false;
+ QWidget* w = list->first();
+ while ( !canceled && w ) {
+ if ( !w->testWState( WState_ForceHide ) && !w->inherits("KMainWindow") ) {
+ QCloseEvent e;
+ sendEvent( w, &e );
+ canceled = !e.isAccepted();
+ if ( !canceled )
+ done.append( w );
+ delete list; // one never knows...
+ list = QApplication::topLevelWidgets();
+ w = list->first();
+ } else {
+ w = list->next();
+ }
+ while ( w && done.containsRef( w ) )
+ w = list->next();
+ }
+ delete list;
+ }
+
+
+ if ( !bSessionManagement )
+ sm.setRestartHint( QSessionManager::RestartNever );
+ else
+ sm.setRestartHint( QSessionManager::RestartIfRunning );
+ d->session_save = false;
+}
+
+static void checkRestartVersion( QSessionManager& sm )
+{
+ Display* dpy = qt_xdisplay();
+ Atom type;
+ int format;
+ unsigned long nitems, after;
+ unsigned char* data;
+ if( XGetWindowProperty( dpy, RootWindow( dpy, 0 ), XInternAtom( dpy, "KDE_FULL_SESSION", False ),
+ 0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data ) == Success ) {
+ if( data != NULL )
+ XFree( data );
+ if( type == XA_STRING && format == 8 ) { // session set, check if KDE_SESSION_VERSION is not set (meaning KDE3)
+ if( XGetWindowProperty( dpy, RootWindow( dpy, 0 ), XInternAtom( dpy, "KDE_SESSION_VERSION", False ),
+ 0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data ) == Success ) {
+ if( data != NULL )
+ XFree( data ); // KDE4 or newer
+ if( type == None )
+ return; // we run in our native session, no need to wrap
+ } else {
+ return; // we run in our native session, no need to wrap
+ }
+ }
+ }
+ QString wrapper = KStandardDirs::findExe( "kde3" );
+ QStringList restartCommand = sm.restartCommand();
+ restartCommand.prepend( wrapper );
+ sm.setRestartCommand( restartCommand );
+}
+
+void KApplication::saveState( QSessionManager& sm )
+{
+ d->session_save = true;
+#ifdef Q_WS_X11
+ static bool firstTime = true;
+ mySmcConnection = (SmcConn) sm.handle();
+
+ if ( !bSessionManagement ) {
+ sm.setRestartHint( QSessionManager::RestartNever );
+ d->session_save = false;
+ return;
+ }
+ else
+ sm.setRestartHint( QSessionManager::RestartIfRunning );
+
+ if ( firstTime ) {
+ firstTime = false;
+ d->session_save = false;
+ return; // no need to save the state.
+ }
+
+ // remove former session config if still existing, we want a new
+ // and fresh one. Note that we do not delete the config file here,
+ // this is done by the session manager when it executes the
+ // discard commands. In fact it would be harmful to remove the
+ // file here, as the session might be stored under a different
+ // name, meaning the user still might need it eventually.
+ if ( pSessionConfig ) {
+ delete pSessionConfig;
+ pSessionConfig = 0;
+ }
+
+ // tell the session manager about our new lifecycle
+ QStringList restartCommand = sm.restartCommand();
+
+ QCString multiHead = getenv("KDE_MULTIHEAD");
+ if (multiHead.lower() == "true") {
+ // if multihead is enabled, we save our -display argument so that
+ // we are restored onto the correct head... one problem with this
+ // is that the display is hard coded, which means we cannot restore
+ // to a different display (ie. if we are in a university lab and try,
+ // try to restore a multihead session, our apps could be started on
+ // someone else's display instead of our own)
+ QCString displayname = getenv(DISPLAY);
+ if (! displayname.isNull()) {
+ // only store the command if we actually have a DISPLAY
+ // environment variable
+ restartCommand.append("-display");
+ restartCommand.append(displayname);
+ }
+ sm.setRestartCommand( restartCommand );
+ }
+
+ checkRestartVersion( sm );
+
+ // finally: do session management
+ emit saveYourself(); // for compatibility
+ bool canceled = false;
+ for (KSessionManaged* it = sessionClients()->first();
+ it && !canceled;
+ it = sessionClients()->next() ) {
+ canceled = !it->saveState( sm );
+ }
+
+ // if we created a new session config object, register a proper discard command
+ if ( pSessionConfig ) {
+ pSessionConfig->sync();
+ QStringList discard;
+ discard << "rm" << locateLocal("config", sessionConfigName());
+ sm.setDiscardCommand( discard );
+ } else {
+ sm.setDiscardCommand( "" );
+ }
+
+ if ( canceled )
+ sm.cancel();
+#else
+ // FIXME(E): Implement for Qt Embedded
+#endif
+ d->session_save = false;
+}
+
+bool KApplication::sessionSaving() const
+{
+ return d->session_save;
+}
+
+void KApplication::startKdeinit()
+{
+#ifndef Q_WS_WIN //TODO
+ KInstance inst( "startkdeinitlock" );
+ KLockFile lock( locateLocal( "tmp", "startkdeinitlock", &inst ));
+ if( lock.lock( KLockFile::LockNoBlock ) != KLockFile::LockOK ) {
+ lock.lock();
+ DCOPClient cl;
+ if( cl.attach())
+ return; // whoever held the lock has already started dcopserver
+ }
+ // Try to launch kdeinit.
+ QString srv = KStandardDirs::findExe(QString::fromLatin1("kdeinit"));
+ if (srv.isEmpty())
+ srv = KStandardDirs::findExe(QString::fromLatin1("kdeinit"), KGlobal::dirs()->kfsstnd_defaultbindir());
+ if (srv.isEmpty())
+ return;
+ if (kapp && (Tty != kapp->type()))
+ setOverrideCursor( Qt::waitCursor );
+ my_system(QFile::encodeName(srv)+" --suicide"+" --new-startup");
+ if (kapp && (Tty != kapp->type()))
+ restoreOverrideCursor();
+#endif
+}
+
+void KApplication::dcopFailure(const QString &msg)
+{
+ static int failureCount = 0;
+ failureCount++;
+ if (failureCount == 1)
+ {
+ startKdeinit();
+ return;
+ }
+ if (failureCount == 2)
+ {
+#ifdef Q_WS_WIN
+ KGlobal::config()->setGroup("General");
+ if (KGlobal::config()->readBoolEntry("ignoreDCOPFailures", false))
+ return;
+#endif
+ QString msgStr(i18n("There was an error setting up inter-process "
+ "communications for KDE. The message returned "
+ "by the system was:\n\n"));
+ msgStr += msg;
+ msgStr += i18n("\n\nPlease check that the \"dcopserver\" program is running!");
+
+ if (Tty != kapp->type())
+ {
+ QMessageBox::critical
+ (
+ kapp->mainWidget(),
+ i18n("DCOP communications error (%1)").arg(kapp->caption()),
+ msgStr,
+ i18n("&OK")
+ );
+ }
+ else
+ {
+ fprintf(stderr, "%s\n", msgStr.local8Bit().data());
+ }
+
+ return;
+ }
+}
+
+static const KCmdLineOptions qt_options[] =
+{
+ //FIXME: Check if other options are specific to Qt/X11
+#ifdef Q_WS_X11
+ { "display <displayname>", I18N_NOOP("Use the X-server display 'displayname'"), 0},
+#else
+ { "display <displayname>", I18N_NOOP("Use the QWS display 'displayname'"), 0},
+#endif
+ { "session <sessionId>", I18N_NOOP("Restore the application for the given 'sessionId'"), 0},
+ { "cmap", I18N_NOOP("Causes the application to install a private color\nmap on an 8-bit display"), 0},
+ { "ncols <count>", I18N_NOOP("Limits the number of colors allocated in the color\ncube on an 8-bit display, if the application is\nusing the QApplication::ManyColor color\nspecification"), 0},
+ { "nograb", I18N_NOOP("tells Qt to never grab the mouse or the keyboard"), 0},
+ { "dograb", I18N_NOOP("running under a debugger can cause an implicit\n-nograb, use -dograb to override"), 0},
+ { "sync", I18N_NOOP("switches to synchronous mode for debugging"), 0},
+ { "fn", 0, 0},
+ { "font <fontname>", I18N_NOOP("defines the application font"), 0},
+ { "bg", 0, 0},
+ { "background <color>", I18N_NOOP("sets the default background color and an\napplication palette (light and dark shades are\ncalculated)"), 0},
+ { "fg", 0, 0},
+ { "foreground <color>", I18N_NOOP("sets the default foreground color"), 0},
+ { "btn", 0, 0},
+ { "button <color>", I18N_NOOP("sets the default button color"), 0},
+ { "name <name>", I18N_NOOP("sets the application name"), 0},
+ { "title <title>", I18N_NOOP("sets the application title (caption)"), 0},
+#ifdef Q_WS_X11
+ { "visual TrueColor", I18N_NOOP("forces the application to use a TrueColor visual on\nan 8-bit display"), 0},
+ { "inputstyle <inputstyle>", I18N_NOOP("sets XIM (X Input Method) input style. Possible\nvalues are onthespot, overthespot, offthespot and\nroot"), 0 },
+ { "im <XIM server>", I18N_NOOP("set XIM server"),0},
+ { "noxim", I18N_NOOP("disable XIM"), 0 },
+#endif
+#ifdef Q_WS_QWS
+ { "qws", I18N_NOOP("forces the application to run as QWS Server"), 0},
+#endif
+ { "reverse", I18N_NOOP("mirrors the whole layout of widgets"), 0},
+ KCmdLineLastOption
+};
+
+static const KCmdLineOptions kde_options[] =
+{
+ { "caption <caption>", I18N_NOOP("Use 'caption' as name in the titlebar"), 0},
+ { "icon <icon>", I18N_NOOP("Use 'icon' as the application icon"), 0},
+ { "miniicon <icon>", I18N_NOOP("Use 'icon' as the icon in the titlebar"), 0},
+ { "config <filename>", I18N_NOOP("Use alternative configuration file"), 0},
+ { "dcopserver <server>", I18N_NOOP("Use the DCOP Server specified by 'server'"), 0},
+ { "nocrashhandler", I18N_NOOP("Disable crash handler, to get core dumps"), 0},
+ { "waitforwm", I18N_NOOP("Waits for a WM_NET compatible windowmanager"), 0},
+ { "style <style>", I18N_NOOP("sets the application GUI style"), 0},
+ { "geometry <geometry>", I18N_NOOP("sets the client geometry of the main widget - see man X for the argument format"), 0},
+ { "smkey <sessionKey>", 0, 0}, // this option is obsolete and exists only to allow smooth upgrades from sessions
+ // saved under Qt 3.0.x -- Qt 3.1.x includes the session key now automatically in
+ // the session id (Simon)
+ KCmdLineLastOption
+};
+
+void
+KApplication::addCmdLineOptions()
+{
+ KCmdLineArgs::addCmdLineOptions(qt_options, "Qt", "qt");
+ KCmdLineArgs::addCmdLineOptions(kde_options, "KDE", "kde");
+}
+
+void KApplication::parseCommandLine( )
+{
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
+
+ if ( !args ) return;
+
+ if (args->isSet("config"))
+ {
+ QString config = QString::fromLocal8Bit(args->getOption("config"));
+ setConfigName(config);
+ }
+
+ if (args->isSet("style"))
+ {
+
+ QStringList styles = QStyleFactory::keys();
+ QString reqStyle(args->getOption("style").lower());
+
+ for (QStringList::ConstIterator it = styles.begin(); it != styles.end(); ++it)
+ if ((*it).lower() == reqStyle)
+ {
+ d->overrideStyle = *it;
+ break;
+ }
+
+ if (d->overrideStyle.isEmpty())
+ fprintf(stderr, "%s", i18n("The style %1 was not found\n").arg(reqStyle).local8Bit().data());
+ }
+
+ if (args->isSet("caption"))
+ {
+ aCaption = QString::fromLocal8Bit(args->getOption("caption"));
+ }
+
+ if (args->isSet("miniicon"))
+ {
+ const char *tmp = args->getOption("miniicon");
+ if (!aIconPixmap.pm.miniIcon) {
+ aIconPixmap.pm.miniIcon = new QPixmap;
+ }
+ *aIconPixmap.pm.miniIcon = SmallIcon(tmp);
+ aMiniIconName = tmp;
+ }
+
+ if (args->isSet("icon"))
+ {
+ const char *tmp = args->getOption("icon");
+ if (!aIconPixmap.pm.icon) {
+ aIconPixmap.pm.icon = new QPixmap;
+ }
+ *aIconPixmap.pm.icon = DesktopIcon( tmp );
+ aIconName = tmp;
+ if (!aIconPixmap.pm.miniIcon) {
+ aIconPixmap.pm.miniIcon = new QPixmap;
+ }
+ if (aIconPixmap.pm.miniIcon->isNull())
+ {
+ *aIconPixmap.pm.miniIcon = SmallIcon( tmp );
+ aMiniIconName = tmp;
+ }
+ }
+
+ bool nocrashhandler = (getenv("KDE_DEBUG") != NULL);
+ if (!nocrashhandler && args->isSet("crashhandler"))
+ {
+ // set default crash handler / set emergency save function to nothing
+ KCrash::setCrashHandler(KCrash::defaultCrashHandler);
+ KCrash::setEmergencySaveFunction(NULL);
+
+ KCrash::setApplicationName(QString(args->appName()));
+ }
+
+#ifdef Q_WS_X11
+ if ( args->isSet( "waitforwm" ) ) {
+ Atom type;
+ (void) desktop(); // trigger desktop creation, we need PropertyNotify events for the root window
+ int format;
+ unsigned long length, after;
+ unsigned char *data;
+ while ( XGetWindowProperty( qt_xdisplay(), qt_xrootwin(), atom_NetSupported,
+ 0, 1, false, AnyPropertyType, &type, &format,
+ &length, &after, &data ) != Success || !length ) {
+ if ( data )
+ XFree( data );
+ XEvent event;
+ XWindowEvent( qt_xdisplay(), qt_xrootwin(), PropertyChangeMask, &event );
+ }
+ if ( data )
+ XFree( data );
+ }
+#else
+ // FIXME(E): Implement for Qt Embedded
+#endif
+
+ if (args->isSet("geometry"))
+ {
+ d->geometry_arg = args->getOption("geometry");
+ }
+
+ if (args->isSet("smkey"))
+ {
+ d->sessionKey = args->getOption("smkey");
+ }
+
+}
+
+QString KApplication::geometryArgument() const
+{
+ return d->geometry_arg;
+}
+
+QPixmap KApplication::icon() const
+{
+ if( !aIconPixmap.pm.icon) {
+ aIconPixmap.pm.icon = new QPixmap;
+ }
+ if( aIconPixmap.pm.icon->isNull()) {
+ *aIconPixmap.pm.icon = DesktopIcon( instanceName() );
+ }
+ return *aIconPixmap.pm.icon;
+}
+
+QString KApplication::iconName() const
+{
+ return aIconName.isNull() ? (QString)instanceName() : aIconName;
+}
+
+QPixmap KApplication::miniIcon() const
+{
+ if (!aIconPixmap.pm.miniIcon) {
+ aIconPixmap.pm.miniIcon = new QPixmap;
+ }
+ if (aIconPixmap.pm.miniIcon->isNull()) {
+ *aIconPixmap.pm.miniIcon = SmallIcon( instanceName() );
+ }
+ return *aIconPixmap.pm.miniIcon;
+}
+
+QString KApplication::miniIconName() const
+{
+ return aMiniIconName.isNull() ? (QString)instanceName() : aMiniIconName;
+}
+
+extern void kDebugCleanup();
+
+KApplication::~KApplication()
+{
+ delete aIconPixmap.pm.miniIcon;
+ aIconPixmap.pm.miniIcon = 0L;
+ delete aIconPixmap.pm.icon;
+ aIconPixmap.pm.icon = 0L;
+ delete d->m_KAppDCOPInterface;
+
+ // First call the static deleters and then call KLibLoader::cleanup()
+ // The static deleters may delete libraries for which they need KLibLoader.
+ // KLibLoader will take care of the remaining ones.
+ KGlobal::deleteStaticDeleters();
+ KLibLoader::cleanUp();
+
+ delete smw;
+
+ // close down IPC
+ delete s_DCOPClient;
+ s_DCOPClient = 0L;
+
+ KProcessController::deref();
+
+#ifdef Q_WS_X11
+ if ( d->oldXErrorHandler != NULL )
+ XSetErrorHandler( d->oldXErrorHandler );
+ if ( d->oldXIOErrorHandler != NULL )
+ XSetIOErrorHandler( d->oldXIOErrorHandler );
+ if ( d->oldIceIOErrorHandler != NULL )
+ IceSetIOErrorHandler( d->oldIceIOErrorHandler );
+#endif
+
+ delete d;
+ KApp = 0;
+
+#ifdef Q_WS_X11
+ mySmcConnection = 0;
+ delete smModificationTime;
+ smModificationTime = 0;
+
+ // close the temporary smc connection
+ if (tmpSmcConnection) {
+ SmcCloseConnection( tmpSmcConnection, 0, 0 );
+ tmpSmcConnection = 0;
+ }
+#else
+ // FIXME(E): Implement for Qt Embedded
+#endif
+}
+
+
+#ifdef Q_WS_X11
+class KAppX11HackWidget: public QWidget
+{
+public:
+ bool publicx11Event( XEvent * e) { return x11Event( e ); }
+};
+#endif
+
+
+
+static bool kapp_block_user_input = false;
+
+void KApplication::dcopBlockUserInput( bool b )
+{
+ kapp_block_user_input = b;
+}
+
+#ifdef Q_WS_X11
+bool KApplication::x11EventFilter( XEvent *_event )
+{
+ switch ( _event->type ) {
+ case ClientMessage:
+ {
+#if KDE_IS_VERSION( 3, 90, 90 )
+#warning This should be already in Qt, check.
+#endif
+ // Workaround for focus stealing prevention not working when dragging e.g. text from KWrite
+ // to KDesktop -> the dialog asking for filename doesn't get activated. This is because
+ // Qt-3.2.x doesn't have concept of qt_x_user_time at all, and Qt-3.3.0b1 passes the timestamp
+ // in the XdndDrop message in incorrect field (and doesn't update qt_x_user_time either).
+ // Patch already sent, future Qt version should have this fixed.
+ if( _event->xclient.message_type == kde_xdnd_drop )
+ { // if the message is XdndDrop
+ if( _event->xclient.data.l[ 1 ] == 1 << 24 // and it's broken the way it's in Qt-3.2.x
+ && _event->xclient.data.l[ 2 ] == 0
+ && _event->xclient.data.l[ 4 ] == 0
+ && _event->xclient.data.l[ 3 ] != 0 )
+ {
+ if( qt_x_user_time == 0
+ || NET::timestampCompare( _event->xclient.data.l[ 3 ], qt_x_user_time ) > 0 )
+ { // and the timestamp looks reasonable
+ qt_x_user_time = _event->xclient.data.l[ 3 ]; // update our qt_x_user_time from it
+ }
+ }
+ else // normal DND, only needed until Qt updates qt_x_user_time from XdndDrop
+ {
+ if( qt_x_user_time == 0
+ || NET::timestampCompare( _event->xclient.data.l[ 2 ], qt_x_user_time ) > 0 )
+ { // the timestamp looks reasonable
+ qt_x_user_time = _event->xclient.data.l[ 2 ]; // update our qt_x_user_time from it
+ }
+ }
+ }
+ }
+ default: break;
+ }
+
+ if ( kapp_block_user_input ) {
+ switch ( _event->type ) {
+ case ButtonPress:
+ case ButtonRelease:
+ case XKeyPress:
+ case XKeyRelease:
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ if (x11Filter) {
+ for (QWidget *w=x11Filter->first(); w; w=x11Filter->next()) {
+ if (((KAppX11HackWidget*) w)->publicx11Event(_event))
+ return true;
+ }
+ }
+
+ if ((_event->type == ClientMessage) &&
+ (_event->xclient.message_type == kipcCommAtom))
+ {
+ XClientMessageEvent *cme = (XClientMessageEvent *) _event;
+
+ int id = cme->data.l[0];
+ int arg = cme->data.l[1];
+ if ((id < 32) && (kipcEventMask & (1 << id)))
+ {
+ switch (id)
+ {
+ case KIPC::StyleChanged:
+ KGlobal::config()->reparseConfiguration();
+ kdisplaySetStyle();
+ break;
+
+ case KIPC::ToolbarStyleChanged:
+ KGlobal::config()->reparseConfiguration();
+ if (useStyles)
+ emit toolbarAppearanceChanged(arg);
+ break;
+
+ case KIPC::PaletteChanged:
+ KGlobal::config()->reparseConfiguration();
+ kdisplaySetPalette();
+ break;
+
+ case KIPC::FontChanged:
+ KGlobal::config()->reparseConfiguration();
+ KGlobalSettings::rereadFontSettings();
+ kdisplaySetFont();
+ break;
+
+ case KIPC::BackgroundChanged:
+ emit backgroundChanged(arg);
+ break;
+
+ case KIPC::SettingsChanged:
+ KGlobal::config()->reparseConfiguration();
+ if (arg == SETTINGS_PATHS)
+ KGlobalSettings::rereadPathSettings();
+ else if (arg == SETTINGS_MOUSE)
+ KGlobalSettings::rereadMouseSettings();
+ propagateSettings((SettingsCategory)arg);
+ break;
+
+ case KIPC::IconChanged:
+ QPixmapCache::clear();
+ KGlobal::config()->reparseConfiguration();
+ KGlobal::instance()->newIconLoader();
+ emit updateIconLoaders();
+ emit iconChanged(arg);
+ break;
+
+ case KIPC::ClipboardConfigChanged:
+ KClipboardSynchronizer::newConfiguration(arg);
+ break;
+
+ case KIPC::BlockShortcuts:
+ KGlobalAccel::blockShortcuts(arg);
+ emit kipcMessage(id, arg); // some apps may do additional things
+ break;
+ }
+ }
+ else if (id >= 32)
+ {
+ emit kipcMessage(id, arg);
+ }
+ return true;
+ }
+ return false;
+}
+#endif // Q_WS_X11
+
+void KApplication::updateUserTimestamp( unsigned long time )
+{
+#if defined Q_WS_X11
+ if( time == 0 )
+ { // get current X timestamp
+ Window w = XCreateSimpleWindow( qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0, 0, 0 );
+ XSelectInput( qt_xdisplay(), w, PropertyChangeMask );
+ unsigned char data[ 1 ];
+ XChangeProperty( qt_xdisplay(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
+ XEvent ev;
+ XWindowEvent( qt_xdisplay(), w, PropertyChangeMask, &ev );
+ time = ev.xproperty.time;
+ XDestroyWindow( qt_xdisplay(), w );
+ }
+ if( qt_x_user_time == 0
+ || NET::timestampCompare( time, qt_x_user_time ) > 0 ) // check time > qt_x_user_time
+ qt_x_user_time = time;
+#endif
+}
+
+unsigned long KApplication::userTimestamp() const
+{
+#if defined Q_WS_X11
+ return qt_x_user_time;
+#else
+ return 0;
+#endif
+}
+
+void KApplication::updateRemoteUserTimestamp( const QCString& dcopId, unsigned long time )
+{
+#if defined Q_WS_X11
+ if( time == 0 )
+ time = qt_x_user_time;
+ DCOPRef( dcopId, "MainApplication-Interface" ).call( "updateUserTimestamp", time );
+#endif
+}
+
+void KApplication::invokeEditSlot( const char *slot )
+{
+ QObject *object = focusWidget();
+ if( !object )
+ return;
+
+ QMetaObject *meta = object->metaObject();
+
+ int idx = meta->findSlot( slot + 1, true );
+ if( idx < 0 )
+ return;
+
+ object->qt_invoke( idx, 0 );
+}
+
+void KApplication::addKipcEventMask(int id)
+{
+ if (id >= 32)
+ {
+ kdDebug(101) << "Cannot use KIPC event mask for message IDs >= 32\n";
+ return;
+ }
+ kipcEventMask |= (1 << id);
+}
+
+void KApplication::removeKipcEventMask(int id)
+{
+ if (id >= 32)
+ {
+ kdDebug(101) << "Cannot use KIPC event mask for message IDs >= 32\n";
+ return;
+ }
+ kipcEventMask &= ~(1 << id);
+}
+
+void KApplication::enableStyles()
+{
+ if (!useStyles)
+ {
+ useStyles = true;
+ applyGUIStyle();
+ }
+}
+
+void KApplication::disableStyles()
+{
+ useStyles = false;
+}
+
+void KApplication::applyGUIStyle()
+{
+ if ( !useStyles ) return;
+
+ KConfigGroup pConfig (KGlobal::config(), "General");
+ QString defaultStyle = KStyle::defaultStyle();
+ QString styleStr = pConfig.readEntry("widgetStyle", defaultStyle);
+
+ if (d->overrideStyle.isEmpty()) {
+ // ### add check whether we already use the correct style to return then
+ // (workaround for Qt misbehavior to avoid double style initialization)
+
+ QStyle* sp = QStyleFactory::create( styleStr );
+
+ // If there is no default style available, try falling back any available style
+ if ( !sp && styleStr != defaultStyle)
+ sp = QStyleFactory::create( defaultStyle );
+ if ( !sp )
+ sp = QStyleFactory::create( *(QStyleFactory::keys().begin()) );
+ setStyle(sp);
+ }
+ else
+ setStyle(d->overrideStyle);
+ // Reread palette from config file.
+ kdisplaySetPalette();
+}
+
+QString KApplication::caption() const
+{
+ // Caption set from command line ?
+ if( !aCaption.isNull() )
+ return aCaption;
+ else
+ // We have some about data ?
+ if ( KGlobal::instance()->aboutData() )
+ return KGlobal::instance()->aboutData()->programName();
+ else
+ // Last resort : application name
+ return name();
+}
+
+
+//
+// 1999-09-20: Espen Sand
+// An attempt to simplify consistent captions.
+//
+QString KApplication::makeStdCaption( const QString &userCaption,
+ bool withAppName, bool modified ) const
+{
+ QString s = userCaption.isEmpty() ? caption() : userCaption;
+
+ // If the document is modified, add '[modified]'.
+ if (modified)
+ s += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]");
+
+ if ( !userCaption.isEmpty() ) {
+ // Add the application name if:
+ // User asked for it, it's not a duplication and the app name (caption()) is not empty
+ if ( withAppName && !caption().isNull() && !userCaption.endsWith(caption()) )
+ s += QString::fromUtf8(" - ") + caption();
+ }
+
+ return s;
+}
+
+QPalette KApplication::createApplicationPalette()
+{
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver saver( config, "General" );
+ return createApplicationPalette( config, KGlobalSettings::contrast() );
+}
+
+QPalette KApplication::createApplicationPalette( KConfig *config, int contrast_ )
+{
+ QColor kde34Background( 239, 239, 239 );
+ QColor kde34Blue( 103,141,178 );
+
+ QColor kde34Button;
+ if ( QPixmap::defaultDepth() > 8 )
+ kde34Button.setRgb( 221, 223, 228 );
+ else
+ kde34Button.setRgb( 220, 220, 220 );
+
+ QColor kde34Link( 0, 0, 238 );
+ QColor kde34VisitedLink( 82, 24, 139 );
+
+ QColor background = config->readColorEntry( "background", &kde34Background );
+ QColor foreground = config->readColorEntry( "foreground", &black );
+ QColor button = config->readColorEntry( "buttonBackground", &kde34Button );
+ QColor buttonText = config->readColorEntry( "buttonForeground", &black );
+ QColor highlight = config->readColorEntry( "selectBackground", &kde34Blue );
+ QColor highlightedText = config->readColorEntry( "selectForeground", &white );
+ QColor base = config->readColorEntry( "windowBackground", &white );
+ QColor baseText = config->readColorEntry( "windowForeground", &black );
+ QColor link = config->readColorEntry( "linkColor", &kde34Link );
+ QColor visitedLink = config->readColorEntry( "visitedLinkColor", &kde34VisitedLink );
+
+ int highlightVal, lowlightVal;
+ highlightVal = 100 + (2*contrast_+4)*16/10;
+ lowlightVal = 100 + (2*contrast_+4)*10;
+
+ QColor disfg = foreground;
+
+ int h, s, v;
+ disfg.hsv( &h, &s, &v );
+ if (v > 128)
+ // dark bg, light fg - need a darker disabled fg
+ disfg = disfg.dark(lowlightVal);
+ else if (disfg != black)
+ // light bg, dark fg - need a lighter disabled fg - but only if !black
+ disfg = disfg.light(highlightVal);
+ else
+ // black fg - use darkgray disabled fg
+ disfg = Qt::darkGray;
+
+
+ QColorGroup disabledgrp(disfg, background,
+ background.light(highlightVal),
+ background.dark(lowlightVal),
+ background.dark(120),
+ background.dark(120), base);
+
+ QColorGroup colgrp(foreground, background, background.light(highlightVal),
+ background.dark(lowlightVal),
+ background.dark(120),
+ baseText, base);
+
+ int inlowlightVal = lowlightVal-25;
+ if(inlowlightVal < 120)
+ inlowlightVal = 120;
+
+ colgrp.setColor(QColorGroup::Highlight, highlight);
+ colgrp.setColor(QColorGroup::HighlightedText, highlightedText);
+ colgrp.setColor(QColorGroup::Button, button);
+ colgrp.setColor(QColorGroup::ButtonText, buttonText);
+ colgrp.setColor(QColorGroup::Midlight, background.light(110));
+ colgrp.setColor(QColorGroup::Link, link);
+ colgrp.setColor(QColorGroup::LinkVisited, visitedLink);
+
+ disabledgrp.setColor(QColorGroup::Button, button);
+
+ QColor disbtntext = buttonText;
+ disbtntext.hsv( &h, &s, &v );
+ if (v > 128)
+ // dark button, light buttonText - need a darker disabled buttonText
+ disbtntext = disbtntext.dark(lowlightVal);
+ else if (disbtntext != black)
+ // light buttonText, dark button - need a lighter disabled buttonText - but only if !black
+ disbtntext = disbtntext.light(highlightVal);
+ else
+ // black button - use darkgray disabled buttonText
+ disbtntext = Qt::darkGray;
+
+ disabledgrp.setColor(QColorGroup::ButtonText, disbtntext);
+ disabledgrp.setColor(QColorGroup::Midlight, background.light(110));
+ disabledgrp.setColor(QColorGroup::Highlight, highlight.dark(120));
+ disabledgrp.setColor(QColorGroup::Link, link);
+ disabledgrp.setColor(QColorGroup::LinkVisited, visitedLink);
+
+ return QPalette(colgrp, disabledgrp, colgrp);
+}
+
+
+void KApplication::kdisplaySetPalette()
+{
+#ifdef Q_WS_MACX
+ //Can I have this on other platforms, please!? --Sam
+ {
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver saver( config, "General" );
+ bool do_not_set_palette = FALSE;
+ if(config->readBoolEntry("nopaletteChange", &do_not_set_palette))
+ return;
+ }
+#endif
+ QApplication::setPalette( createApplicationPalette(), true);
+ emit kdisplayPaletteChanged();
+ emit appearanceChanged();
+}
+
+
+void KApplication::kdisplaySetFont()
+{
+ QApplication::setFont(KGlobalSettings::generalFont(), true);
+ QApplication::setFont(KGlobalSettings::menuFont(), true, "QMenuBar");
+ QApplication::setFont(KGlobalSettings::menuFont(), true, "QPopupMenu");
+ QApplication::setFont(KGlobalSettings::menuFont(), true, "KPopupTitle");
+
+ // "patch" standard QStyleSheet to follow our fonts
+ QStyleSheet* sheet = QStyleSheet::defaultSheet();
+ sheet->item ("pre")->setFontFamily (KGlobalSettings::fixedFont().family());
+ sheet->item ("code")->setFontFamily (KGlobalSettings::fixedFont().family());
+ sheet->item ("tt")->setFontFamily (KGlobalSettings::fixedFont().family());
+
+ emit kdisplayFontChanged();
+ emit appearanceChanged();
+}
+
+
+void KApplication::kdisplaySetStyle()
+{
+ if (useStyles)
+ {
+ applyGUIStyle();
+ emit kdisplayStyleChanged();
+ emit appearanceChanged();
+ }
+}
+
+
+void KApplication::propagateSettings(SettingsCategory arg)
+{
+ KConfigBase* config = KGlobal::config();
+ KConfigGroupSaver saver( config, "KDE" );
+
+ int num = config->readNumEntry("CursorBlinkRate", QApplication::cursorFlashTime());
+ if ((num != 0) && (num < 200))
+ num = 200;
+ if (num > 2000)
+ num = 2000;
+ QApplication::setCursorFlashTime(num);
+ num = config->readNumEntry("DoubleClickInterval", QApplication::doubleClickInterval());
+ QApplication::setDoubleClickInterval(num);
+ num = config->readNumEntry("StartDragTime", QApplication::startDragTime());
+ QApplication::setStartDragTime(num);
+ num = config->readNumEntry("StartDragDist", QApplication::startDragDistance());
+ QApplication::setStartDragDistance(num);
+ num = config->readNumEntry("WheelScrollLines", QApplication::wheelScrollLines());
+ QApplication::setWheelScrollLines(num);
+
+ bool b = config->readBoolEntry("EffectAnimateMenu", false);
+ QApplication::setEffectEnabled( Qt::UI_AnimateMenu, b);
+ b = config->readBoolEntry("EffectFadeMenu", false);
+ QApplication::setEffectEnabled( Qt::UI_FadeMenu, b);
+ b = config->readBoolEntry("EffectAnimateCombo", false);
+ QApplication::setEffectEnabled( Qt::UI_AnimateCombo, b);
+ b = config->readBoolEntry("EffectAnimateTooltip", false);
+ QApplication::setEffectEnabled( Qt::UI_AnimateTooltip, b);
+ b = config->readBoolEntry("EffectFadeTooltip", false);
+ QApplication::setEffectEnabled( Qt::UI_FadeTooltip, b);
+ b = !config->readBoolEntry("EffectNoTooltip", false);
+ QToolTip::setGloballyEnabled( b );
+
+ emit settingsChanged(arg);
+}
+
+void KApplication::installKDEPropertyMap()
+{
+#ifndef QT_NO_SQL
+ static bool installed = false;
+ if (installed) return;
+ installed = true;
+ /**
+ * If you are adding a widget that was missing please
+ * make sure to also add it to KConfigDialogManager's retrieveSettings()
+ * function.
+ * Thanks.
+ */
+ // QSqlPropertyMap takes ownership of the new default map.
+ QSqlPropertyMap *kdeMap = new QSqlPropertyMap;
+ kdeMap->insert( "KColorButton", "color" );
+ kdeMap->insert( "KComboBox", "currentItem" );
+ kdeMap->insert( "KDatePicker", "date" );
+ kdeMap->insert( "KDateWidget", "date" );
+ kdeMap->insert( "KDateTimeWidget", "dateTime" );
+ kdeMap->insert( "KEditListBox", "items" );
+ kdeMap->insert( "KFontCombo", "family" );
+ kdeMap->insert( "KFontRequester", "font" );
+ kdeMap->insert( "KFontChooser", "font" );
+ kdeMap->insert( "KHistoryCombo", "currentItem" );
+ kdeMap->insert( "KListBox", "currentItem" );
+ kdeMap->insert( "KLineEdit", "text" );
+ kdeMap->insert( "KRestrictedLine", "text" );
+ kdeMap->insert( "KSqueezedTextLabel", "text" );
+ kdeMap->insert( "KTextBrowser", "source" );
+ kdeMap->insert( "KTextEdit", "text" );
+ kdeMap->insert( "KURLRequester", "url" );
+ kdeMap->insert( "KPasswordEdit", "password" );
+ kdeMap->insert( "KIntNumInput", "value" );
+ kdeMap->insert( "KIntSpinBox", "value" );
+ kdeMap->insert( "KDoubleNumInput", "value" );
+ // Temp til fixed in QT then enable ifdef with the correct version num
+ kdeMap->insert( "QGroupBox", "checked" );
+ kdeMap->insert( "QTabWidget", "currentPage" );
+ QSqlPropertyMap::installDefaultMap( kdeMap );
+#endif
+}
+
+void KApplication::invokeHelp( const QString& anchor,
+ const QString& _appname) const
+{
+ return invokeHelp( anchor, _appname, "" );
+}
+
+#ifndef Q_WS_WIN
+// for win32 we're using simple help tools like Qt Assistant,
+// see kapplication_win.cpp
+void KApplication::invokeHelp( const QString& anchor,
+ const QString& _appname,
+ const QCString& startup_id ) const
+{
+ QString url;
+ QString appname;
+ if (_appname.isEmpty())
+ appname = name();
+ else
+ appname = _appname;
+
+ if (!anchor.isEmpty())
+ url = QString("help:/%1?anchor=%2").arg(appname).arg(anchor);
+ else
+ url = QString("help:/%1/index.html").arg(appname);
+
+ QString error;
+ if ( !dcopClient()->isApplicationRegistered("khelpcenter") )
+ {
+ if (startServiceByDesktopName("khelpcenter", url, &error, 0, 0, startup_id, false))
+ {
+ if (Tty != kapp->type())
+ QMessageBox::critical(kapp->mainWidget(), i18n("Could not Launch Help Center"),
+ i18n("Could not launch the KDE Help Center:\n\n%1").arg(error), i18n("&OK"));
+ else
+ kdWarning() << "Could not launch help:\n" << error << endl;
+ return;
+ }
+ }
+ else
+ DCOPRef( "khelpcenter", "KHelpCenterIface" ).send( "openUrl", url, startup_id );
+}
+#endif
+
+void KApplication::invokeHTMLHelp( const QString& _filename, const QString& topic ) const
+{
+ kdWarning() << "invoking HTML help is deprecated! use docbook and invokeHelp!\n";
+
+ QString filename;
+
+ if( _filename.isEmpty() )
+ filename = QString(name()) + "/index.html";
+ else
+ filename = _filename;
+
+ QString url;
+ if (!topic.isEmpty())
+ url = QString("help:/%1#%2").arg(filename).arg(topic);
+ else
+ url = QString("help:/%1").arg(filename);
+
+ QString error;
+ if ( !dcopClient()->isApplicationRegistered("khelpcenter") )
+ {
+ if (startServiceByDesktopName("khelpcenter", url, &error, 0, 0, "", false))
+ {
+ if (Tty != kapp->type())
+ QMessageBox::critical(kapp->mainWidget(), i18n("Could not Launch Help Center"),
+ i18n("Could not launch the KDE Help Center:\n\n%1").arg(error), i18n("&OK"));
+ else
+ kdWarning() << "Could not launch help:\n" << error << endl;
+ return;
+ }
+ }
+ else
+ DCOPRef( "khelpcenter", "KHelpCenterIface" ).send( "openUrl", url );
+}
+
+
+void KApplication::invokeMailer(const QString &address, const QString &subject)
+{
+ return invokeMailer(address,subject,"");
+}
+
+void KApplication::invokeMailer(const QString &address, const QString &subject, const QCString& startup_id)
+{
+ invokeMailer(address, QString::null, QString::null, subject, QString::null, QString::null,
+ QStringList(), startup_id );
+}
+
+void KApplication::invokeMailer(const KURL &mailtoURL)
+{
+ return invokeMailer( mailtoURL, "" );
+}
+
+void KApplication::invokeMailer(const KURL &mailtoURL, const QCString& startup_id )
+{
+ return invokeMailer( mailtoURL, startup_id, false);
+}
+
+void KApplication::invokeMailer(const KURL &mailtoURL, const QCString& startup_id, bool allowAttachments )
+{
+ QString address = KURL::decode_string(mailtoURL.path()), subject, cc, bcc, body;
+ QStringList queries = QStringList::split('&', mailtoURL.query().mid(1));
+ QStringList attachURLs;
+ for (QStringList::Iterator it = queries.begin(); it != queries.end(); ++it)
+ {
+ QString q = (*it).lower();
+ if (q.startsWith("subject="))
+ subject = KURL::decode_string((*it).mid(8));
+ else
+ if (q.startsWith("cc="))
+ cc = cc.isEmpty()? KURL::decode_string((*it).mid(3)): cc + ',' + KURL::decode_string((*it).mid(3));
+ else
+ if (q.startsWith("bcc="))
+ bcc = bcc.isEmpty()? KURL::decode_string((*it).mid(4)): bcc + ',' + KURL::decode_string((*it).mid(4));
+ else
+ if (q.startsWith("body="))
+ body = KURL::decode_string((*it).mid(5));
+ else
+ if (allowAttachments && q.startsWith("attach="))
+ attachURLs.push_back(KURL::decode_string((*it).mid(7)));
+ else
+ if (allowAttachments && q.startsWith("attachment="))
+ attachURLs.push_back(KURL::decode_string((*it).mid(11)));
+ else
+ if (q.startsWith("to="))
+ address = address.isEmpty()? KURL::decode_string((*it).mid(3)): address + ',' + KURL::decode_string((*it).mid(3));
+ }
+
+ invokeMailer( address, cc, bcc, subject, body, QString::null, attachURLs, startup_id );
+}
+
+void KApplication::invokeMailer(const QString &to, const QString &cc, const QString &bcc,
+ const QString &subject, const QString &body,
+ const QString & messageFile, const QStringList &attachURLs)
+{
+ return invokeMailer(to,cc,bcc,subject,body,messageFile,attachURLs,"");
+}
+
+#ifndef Q_WS_WIN
+// on win32, for invoking browser we're using win32 API
+// see kapplication_win.cpp
+
+static QStringList splitEmailAddressList( const QString & aStr )
+{
+ // This is a copy of KPIM::splitEmailAddrList().
+ // Features:
+ // - always ignores quoted characters
+ // - ignores everything (including parentheses and commas)
+ // inside quoted strings
+ // - supports nested comments
+ // - ignores everything (including double quotes and commas)
+ // inside comments
+
+ QStringList list;
+
+ if (aStr.isEmpty())
+ return list;
+
+ QString addr;
+ uint addrstart = 0;
+ int commentlevel = 0;
+ bool insidequote = false;
+
+ for (uint index=0; index<aStr.length(); index++) {
+ // the following conversion to latin1 is o.k. because
+ // we can safely ignore all non-latin1 characters
+ switch (aStr[index].latin1()) {
+ case '"' : // start or end of quoted string
+ if (commentlevel == 0)
+ insidequote = !insidequote;
+ break;
+ case '(' : // start of comment
+ if (!insidequote)
+ commentlevel++;
+ break;
+ case ')' : // end of comment
+ if (!insidequote) {
+ if (commentlevel > 0)
+ commentlevel--;
+ else {
+ //kdDebug() << "Error in address splitting: Unmatched ')'"
+ // << endl;
+ return list;
+ }
+ }
+ break;
+ case '\\' : // quoted character
+ index++; // ignore the quoted character
+ break;
+ case ',' :
+ if (!insidequote && (commentlevel == 0)) {
+ addr = aStr.mid(addrstart, index-addrstart);
+ if (!addr.isEmpty())
+ list += addr.simplifyWhiteSpace();
+ addrstart = index+1;
+ }
+ break;
+ }
+ }
+ // append the last address to the list
+ if (!insidequote && (commentlevel == 0)) {
+ addr = aStr.mid(addrstart, aStr.length()-addrstart);
+ if (!addr.isEmpty())
+ list += addr.simplifyWhiteSpace();
+ }
+ //else
+ // kdDebug() << "Error in address splitting: "
+ // << "Unexpected end of address list"
+ // << endl;
+
+ return list;
+}
+
+void KApplication::invokeMailer(const QString &_to, const QString &_cc, const QString &_bcc,
+ const QString &subject, const QString &body,
+ const QString & /*messageFile TODO*/, const QStringList &attachURLs,
+ const QCString& startup_id )
+{
+ KConfig config("emaildefaults");
+
+ config.setGroup("Defaults");
+ QString group = config.readEntry("Profile","Default");
+
+ config.setGroup( QString("PROFILE_%1").arg(group) );
+ QString command = config.readPathEntry("EmailClient");
+
+ QString to, cc, bcc;
+ if (command.isEmpty() || command == QString::fromLatin1("kmail")
+ || command.endsWith("/kmail"))
+ {
+ command = QString::fromLatin1("kmail --composer -s %s -c %c -b %b --body %B --attach %A -- %t");
+ if ( !_to.isEmpty() )
+ {
+ // put the whole address lists into RFC2047 encoded blobs; technically
+ // this isn't correct, but KMail understands it nonetheless
+ to = QString( "=?utf8?b?%1?=" )
+ .arg( KCodecs::base64Encode( _to.utf8(), false ) );
+ }
+ if ( !_cc.isEmpty() )
+ cc = QString( "=?utf8?b?%1?=" )
+ .arg( KCodecs::base64Encode( _cc.utf8(), false ) );
+ if ( !_bcc.isEmpty() )
+ bcc = QString( "=?utf8?b?%1?=" )
+ .arg( KCodecs::base64Encode( _bcc.utf8(), false ) );
+ } else {
+ to = _to;
+ cc = _cc;
+ bcc = _bcc;
+ if( !command.contains( '%' ))
+ command += " %u";
+ }
+
+ if (config.readBoolEntry("TerminalClient", false))
+ {
+ KConfigGroup confGroup( KGlobal::config(), "General" );
+ QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", "konsole");
+ command = preferredTerminal + " -e " + command;
+ }
+
+ QStringList cmdTokens = KShell::splitArgs(command);
+ QString cmd = cmdTokens[0];
+ cmdTokens.remove(cmdTokens.begin());
+
+ KURL url;
+ QStringList qry;
+ if (!to.isEmpty())
+ {
+ QStringList tos = splitEmailAddressList( to );
+ url.setPath( tos.first() );
+ tos.remove( tos.begin() );
+ for (QStringList::ConstIterator it = tos.begin(); it != tos.end(); ++it)
+ qry.append( "to=" + KURL::encode_string( *it ) );
+ }
+ const QStringList ccs = splitEmailAddressList( cc );
+ for (QStringList::ConstIterator it = ccs.begin(); it != ccs.end(); ++it)
+ qry.append( "cc=" + KURL::encode_string( *it ) );
+ const QStringList bccs = splitEmailAddressList( bcc );
+ for (QStringList::ConstIterator it = bccs.begin(); it != bccs.end(); ++it)
+ qry.append( "bcc=" + KURL::encode_string( *it ) );
+ for (QStringList::ConstIterator it = attachURLs.begin(); it != attachURLs.end(); ++it)
+ qry.append( "attach=" + KURL::encode_string( *it ) );
+ if (!subject.isEmpty())
+ qry.append( "subject=" + KURL::encode_string( subject ) );
+ if (!body.isEmpty())
+ qry.append( "body=" + KURL::encode_string( body ) );
+ url.setQuery( qry.join( "&" ) );
+ if ( ! (to.isEmpty() && qry.isEmpty()) )
+ url.setProtocol("mailto");
+
+ QMap<QChar, QString> keyMap;
+ keyMap.insert('t', to);
+ keyMap.insert('s', subject);
+ keyMap.insert('c', cc);
+ keyMap.insert('b', bcc);
+ keyMap.insert('B', body);
+ keyMap.insert('u', url.url());
+
+ QString attachlist = attachURLs.join(",");
+ attachlist.prepend('\'');
+ attachlist.append('\'');
+ keyMap.insert('A', attachlist);
+
+ for (QStringList::Iterator it = cmdTokens.begin(); it != cmdTokens.end(); )
+ {
+ if (*it == "%A")
+ {
+ if (it == cmdTokens.begin()) // better safe than sorry ...
+ continue;
+ QStringList::ConstIterator urlit = attachURLs.begin();
+ QStringList::ConstIterator urlend = attachURLs.end();
+ if ( urlit != urlend )
+ {
+ QStringList::Iterator previt = it;
+ --previt;
+ *it = *urlit;
+ ++it;
+ while ( ++urlit != urlend )
+ {
+ cmdTokens.insert( it, *previt );
+ cmdTokens.insert( it, *urlit );
+ }
+ } else {
+ --it;
+ it = cmdTokens.remove( cmdTokens.remove( it ) );
+ }
+ } else {
+ *it = KMacroExpander::expandMacros(*it, keyMap);
+ ++it;
+ }
+ }
+
+ QString error;
+ // TODO this should check if cmd has a .desktop file, and use data from it, together
+ // with sending more ASN data
+ if (kdeinitExec(cmd, cmdTokens, &error, NULL, startup_id ))
+ if (Tty != kapp->type())
+ QMessageBox::critical(kapp->mainWidget(), i18n("Could not Launch Mail Client"),
+ i18n("Could not launch the mail client:\n\n%1").arg(error), i18n("&OK"));
+ else
+ kdWarning() << "Could not launch mail client:\n" << error << endl;
+}
+#endif
+
+void KApplication::invokeBrowser( const QString &url )
+{
+ return invokeBrowser( url, "" );
+}
+
+#ifndef Q_WS_WIN
+// on win32, for invoking browser we're using win32 API
+// see kapplication_win.cpp
+void KApplication::invokeBrowser( const QString &url, const QCString& startup_id )
+{
+ QString error;
+
+ if (startServiceByDesktopName("kfmclient", url, &error, 0, 0, startup_id, false))
+ {
+ if (Tty != kapp->type())
+ QMessageBox::critical(kapp->mainWidget(), i18n("Could not Launch Browser"),
+ i18n("Could not launch the browser:\n\n%1").arg(error), i18n("&OK"));
+ else
+ kdWarning() << "Could not launch browser:\n" << error << endl;
+ return;
+ }
+}
+#endif
+
+void KApplication::cut()
+{
+ invokeEditSlot( SLOT( cut() ) );
+}
+
+void KApplication::copy()
+{
+ invokeEditSlot( SLOT( copy() ) );
+}
+
+void KApplication::paste()
+{
+ invokeEditSlot( SLOT( paste() ) );
+}
+
+void KApplication::clear()
+{
+ invokeEditSlot( SLOT( clear() ) );
+}
+
+void KApplication::selectAll()
+{
+ invokeEditSlot( SLOT( selectAll() ) );
+}
+
+QCString
+KApplication::launcher()
+{
+ return "klauncher";
+}
+
+static int
+startServiceInternal( const QCString &function,
+ const QString& _name, const QStringList &URLs,
+ QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
+{
+ struct serviceResult
+ {
+ int result;
+ QCString dcopName;
+ QString error;
+ pid_t pid;
+ };
+
+ // Register app as able to send DCOP messages
+ DCOPClient *dcopClient;
+ if (kapp)
+ dcopClient = kapp->dcopClient();
+ else
+ dcopClient = new DCOPClient;
+
+ if (!dcopClient->isAttached())
+ {
+ if (!dcopClient->attach())
+ {
+ if (error)
+ *error = i18n("Could not register with DCOP.\n");
+ if (!kapp)
+ delete dcopClient;
+
+ return -1;
+ }
+ }
+ QByteArray params;
+ QDataStream stream(params, IO_WriteOnly);
+ stream << _name << URLs;
+ QCString replyType;
+ QByteArray replyData;
+ QCString _launcher = KApplication::launcher();
+ QValueList<QCString> envs;
+#ifdef Q_WS_X11
+ if (qt_xdisplay()) {
+ QCString dpystring(XDisplayString(qt_xdisplay()));
+ envs.append( QCString("DISPLAY=") + dpystring );
+ } else if( getenv( "DISPLAY" )) {
+ QCString dpystring( getenv( "DISPLAY" ));
+ envs.append( QCString("DISPLAY=") + dpystring );
+ }
+#endif
+ stream << envs;
+#if defined Q_WS_X11
+ // make sure there is id, so that user timestamp exists
+ stream << ( startup_id.isEmpty() ? KStartupInfo::createNewStartupId() : startup_id );
+#endif
+ if( function.left( 12 ) != "kdeinit_exec" )
+ stream << noWait;
+
+ if (!dcopClient->call(_launcher, _launcher,
+ function, params, replyType, replyData))
+ {
+ if (error)
+ *error = i18n("KLauncher could not be reached via DCOP.\n");
+ if (!kapp)
+ delete dcopClient;
+ return -1;
+ }
+ if (!kapp)
+ delete dcopClient;
+
+ if (noWait)
+ return 0;
+
+ QDataStream stream2(replyData, IO_ReadOnly);
+ serviceResult result;
+ stream2 >> result.result >> result.dcopName >> result.error >> result.pid;
+ if (dcopService)
+ *dcopService = result.dcopName;
+ if (error)
+ *error = result.error;
+ if (pid)
+ *pid = result.pid;
+ return result.result;
+}
+
+int
+KApplication::startServiceByName( const QString& _name, const QString &URL,
+ QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
+{
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return startServiceInternal(
+ "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
+ _name, URLs, error, dcopService, pid, startup_id, noWait);
+}
+
+int
+KApplication::startServiceByName( const QString& _name, const QStringList &URLs,
+ QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
+{
+ return startServiceInternal(
+ "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
+ _name, URLs, error, dcopService, pid, startup_id, noWait);
+}
+
+int
+KApplication::startServiceByDesktopPath( const QString& _name, const QString &URL,
+ QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
+{
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return startServiceInternal(
+ "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)",
+ _name, URLs, error, dcopService, pid, startup_id, noWait);
+}
+
+int
+KApplication::startServiceByDesktopPath( const QString& _name, const QStringList &URLs,
+ QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
+{
+ return startServiceInternal(
+ "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)",
+ _name, URLs, error, dcopService, pid, startup_id, noWait);
+}
+
+int
+KApplication::startServiceByDesktopName( const QString& _name, const QString &URL,
+ QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
+{
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return startServiceInternal(
+ "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
+ _name, URLs, error, dcopService, pid, startup_id, noWait);
+}
+
+int
+KApplication::startServiceByDesktopName( const QString& _name, const QStringList &URLs,
+ QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
+{
+ return startServiceInternal(
+ "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
+ _name, URLs, error, dcopService, pid, startup_id, noWait);
+}
+
+int
+KApplication::kdeinitExec( const QString& name, const QStringList &args,
+ QString *error, int *pid )
+{
+ return kdeinitExec( name, args, error, pid, "" );
+}
+
+int
+KApplication::kdeinitExec( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QCString& startup_id )
+{
+ return startServiceInternal("kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)",
+ name, args, error, 0, pid, startup_id, false);
+}
+
+int
+KApplication::kdeinitExecWait( const QString& name, const QStringList &args,
+ QString *error, int *pid )
+{
+ return kdeinitExecWait( name, args, error, pid, "" );
+}
+
+int
+KApplication::kdeinitExecWait( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QCString& startup_id )
+{
+ return startServiceInternal("kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)",
+ name, args, error, 0, pid, startup_id, false);
+}
+
+QString KApplication::tempSaveName( const QString& pFilename ) const
+{
+ QString aFilename;
+
+ if( QDir::isRelativePath(pFilename) )
+ {
+ kdWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
+ aFilename = QFileInfo( QDir( "." ), pFilename ).absFilePath();
+ }
+ else
+ aFilename = pFilename;
+
+ QDir aAutosaveDir( QDir::homeDirPath() + "/autosave/" );
+ if( !aAutosaveDir.exists() )
+ {
+ if( !aAutosaveDir.mkdir( aAutosaveDir.absPath() ) )
+ {
+ // Last chance: use temp dir
+ aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
+ }
+ }
+
+ aFilename.replace( "/", "\\!" ).prepend( "#" ).append( "#" ).prepend( "/" ).prepend( aAutosaveDir.absPath() );
+
+ return aFilename;
+}
+
+
+QString KApplication::checkRecoverFile( const QString& pFilename,
+ bool& bRecover ) const
+{
+ QString aFilename;
+
+ if( QDir::isRelativePath(pFilename) )
+ {
+ kdWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
+ aFilename = QFileInfo( QDir( "." ), pFilename ).absFilePath();
+ }
+ else
+ aFilename = pFilename;
+
+ QDir aAutosaveDir( QDir::homeDirPath() + "/autosave/" );
+ if( !aAutosaveDir.exists() )
+ {
+ if( !aAutosaveDir.mkdir( aAutosaveDir.absPath() ) )
+ {
+ // Last chance: use temp dir
+ aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
+ }
+ }
+
+ aFilename.replace( "/", "\\!" ).prepend( "#" ).append( "#" ).prepend( "/" ).prepend( aAutosaveDir.absPath() );
+
+ if( QFile( aFilename ).exists() )
+ {
+ bRecover = true;
+ return aFilename;
+ }
+ else
+ {
+ bRecover = false;
+ return pFilename;
+ }
+}
+
+
+bool checkAccess(const QString& pathname, int mode)
+{
+ int accessOK = access( QFile::encodeName(pathname), mode );
+ if ( accessOK == 0 )
+ return true; // OK, I can really access the file
+
+ // else
+ // if we want to write the file would be created. Check, if the
+ // user may write to the directory to create the file.
+ if ( (mode & W_OK) == 0 )
+ return false; // Check for write access is not part of mode => bail out
+
+
+ if (!access( QFile::encodeName(pathname), F_OK)) // if it already exists
+ return false;
+
+ //strip the filename (everything until '/' from the end
+ QString dirName(pathname);
+ int pos = dirName.findRev('/');
+ if ( pos == -1 )
+ return false; // No path in argument. This is evil, we won't allow this
+ else if ( pos == 0 ) // don't turn e.g. /root into an empty string
+ pos = 1;
+
+ dirName.truncate(pos); // strip everything starting from the last '/'
+
+ accessOK = access( QFile::encodeName(dirName), W_OK );
+ // -?- Can I write to the accessed diretory
+ if ( accessOK == 0 )
+ return true; // Yes
+ else
+ return false; // No
+}
+
+void KApplication::setTopWidget( QWidget *topWidget )
+{
+ if( !topWidget )
+ return;
+
+ // set the specified caption
+ if ( !topWidget->inherits("KMainWindow") ) { // KMainWindow does this already for us
+ topWidget->setCaption( caption() );
+ }
+
+ // set the specified icons
+ topWidget->setIcon( icon() ); //standard X11
+#if defined Q_WS_X11
+//#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
+ KWin::setIcons(topWidget->winId(), icon(), miniIcon() ); // NET_WM hints for KWin
+
+ // set the app startup notification window property
+ KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
+#endif
+}
+
+QCString KApplication::startupId() const
+{
+ return d->startup_id;
+}
+
+void KApplication::setStartupId( const QCString& startup_id )
+{
+ if( startup_id == d->startup_id )
+ return;
+#if defined Q_WS_X11
+ KStartupInfo::handleAutoAppStartedSending(); // finish old startup notification if needed
+#endif
+ if( startup_id.isEmpty())
+ d->startup_id = "0";
+ else
+ {
+ d->startup_id = startup_id;
+#if defined Q_WS_X11
+ KStartupInfoId id;
+ id.initId( startup_id );
+ long timestamp = id.timestamp();
+ if( timestamp != 0 )
+ updateUserTimestamp( timestamp );
+#endif
+ }
+}
+
+// read the startup notification env variable, save it and unset it in order
+// not to propagate it to processes started from this app
+void KApplication::read_app_startup_id()
+{
+#if defined Q_WS_X11
+ KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
+ KStartupInfo::resetStartupEnv();
+ d->startup_id = id.id();
+#endif
+}
+
+int KApplication::random()
+{
+ static bool init = false;
+ if (!init)
+ {
+ unsigned int seed;
+ init = true;
+ int fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0 || ::read(fd, &seed, sizeof(seed)) != sizeof(seed))
+ {
+ // No /dev/urandom... try something else.
+ srand(getpid());
+ seed = rand()+time(0);
+ }
+ if (fd >= 0) close(fd);
+ srand(seed);
+ }
+ return rand();
+}
+
+QString KApplication::randomString(int length)
+{
+ if (length <=0 ) return QString::null;
+
+ QString str; str.setLength( length );
+ int i = 0;
+ while (length--)
+ {
+ int r=random() % 62;
+ r+=48;
+ if (r>57) r+=7;
+ if (r>90) r+=6;
+ str[i++] = char(r);
+ // so what if I work backwards?
+ }
+ return str;
+}
+
+bool KApplication::authorize(const QString &genericAction)
+{
+ if (!d->actionRestrictions)
+ return true;
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver saver( config, "KDE Action Restrictions" );
+ return config->readBoolEntry(genericAction, true);
+}
+
+bool KApplication::authorizeKAction(const char *action)
+{
+ if (!d->actionRestrictions || !action)
+ return true;
+
+ static const QString &action_prefix = KGlobal::staticQString( "action/" );
+
+ return authorize(action_prefix + action);
+}
+
+bool KApplication::authorizeControlModule(const QString &menuId)
+{
+ if (menuId.isEmpty() || kde_kiosk_exception)
+ return true;
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver saver( config, "KDE Control Module Restrictions" );
+ return config->readBoolEntry(menuId, true);
+}
+
+QStringList KApplication::authorizeControlModules(const QStringList &menuIds)
+{
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver saver( config, "KDE Control Module Restrictions" );
+ QStringList result;
+ for(QStringList::ConstIterator it = menuIds.begin();
+ it != menuIds.end(); ++it)
+ {
+ if (config->readBoolEntry(*it, true))
+ result.append(*it);
+ }
+ return result;
+}
+
+void KApplication::initUrlActionRestrictions()
+{
+ d->urlActionRestrictions.setAutoDelete(true);
+ d->urlActionRestrictions.clear();
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("open", QString::null, QString::null, QString::null, QString::null, QString::null, QString::null, true));
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("list", QString::null, QString::null, QString::null, QString::null, QString::null, QString::null, true));
+// TEST:
+// d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+// ("list", QString::null, QString::null, QString::null, QString::null, QString::null, QString::null, false));
+// d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+// ("list", QString::null, QString::null, QString::null, "file", QString::null, QDir::homeDirPath(), true));
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("link", QString::null, QString::null, QString::null, ":internet", QString::null, QString::null, true));
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("redirect", QString::null, QString::null, QString::null, ":internet", QString::null, QString::null, true));
+
+ // We allow redirections to file: but not from internet protocols, redirecting to file:
+ // is very popular among io-slaves and we don't want to break them
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("redirect", QString::null, QString::null, QString::null, "file", QString::null, QString::null, true));
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("redirect", ":internet", QString::null, QString::null, "file", QString::null, QString::null, false));
+
+ // local protocols may redirect everywhere
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("redirect", ":local", QString::null, QString::null, QString::null, QString::null, QString::null, true));
+
+ // Anyone may redirect to about:
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("redirect", QString::null, QString::null, QString::null, "about", QString::null, QString::null, true));
+
+ // Anyone may redirect to itself, cq. within it's own group
+ d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
+ ("redirect", QString::null, QString::null, QString::null, "=", QString::null, QString::null, true));
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver saver( config, "KDE URL Restrictions" );
+ int count = config->readNumEntry("rule_count");
+ QString keyFormat = QString("rule_%1");
+ for(int i = 1; i <= count; i++)
+ {
+ QString key = keyFormat.arg(i);
+ QStringList rule = config->readListEntry(key);
+ if (rule.count() != 8)
+ continue;
+ QString action = rule[0];
+ QString refProt = rule[1];
+ QString refHost = rule[2];
+ QString refPath = rule[3];
+ QString urlProt = rule[4];
+ QString urlHost = rule[5];
+ QString urlPath = rule[6];
+ QString strEnabled = rule[7].lower();
+
+ bool bEnabled = (strEnabled == "true");
+
+ if (refPath.startsWith("$HOME"))
+ refPath.replace(0, 5, QDir::homeDirPath());
+ else if (refPath.startsWith("~"))
+ refPath.replace(0, 1, QDir::homeDirPath());
+ if (urlPath.startsWith("$HOME"))
+ urlPath.replace(0, 5, QDir::homeDirPath());
+ else if (urlPath.startsWith("~"))
+ urlPath.replace(0, 1, QDir::homeDirPath());
+
+ if (refPath.startsWith("$TMP"))
+ refPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
+ if (urlPath.startsWith("$TMP"))
+ urlPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
+
+ d->urlActionRestrictions.append(new KApplicationPrivate::URLActionRule
+ ( action, refProt, refHost, refPath, urlProt, urlHost, urlPath, bEnabled));
+ }
+}
+
+void KApplication::allowURLAction(const QString &action, const KURL &_baseURL, const KURL &_destURL)
+{
+ if (authorizeURLAction(action, _baseURL, _destURL))
+ return;
+
+ d->urlActionRestrictions.append(new KApplicationPrivate::URLActionRule
+ ( action, _baseURL.protocol(), _baseURL.host(), _baseURL.path(-1),
+ _destURL.protocol(), _destURL.host(), _destURL.path(-1), true));
+}
+
+bool KApplication::authorizeURLAction(const QString &action, const KURL &_baseURL, const KURL &_destURL)
+{
+ if (_destURL.isEmpty())
+ return true;
+
+ bool result = false;
+ if (d->urlActionRestrictions.isEmpty())
+ initUrlActionRestrictions();
+
+ KURL baseURL(_baseURL);
+ baseURL.setPath(QDir::cleanDirPath(baseURL.path()));
+ QString baseClass = KProtocolInfo::protocolClass(baseURL.protocol());
+ KURL destURL(_destURL);
+ destURL.setPath(QDir::cleanDirPath(destURL.path()));
+ QString destClass = KProtocolInfo::protocolClass(destURL.protocol());
+
+ for(KApplicationPrivate::URLActionRule *rule = d->urlActionRestrictions.first();
+ rule; rule = d->urlActionRestrictions.next())
+ {
+ if ((result != rule->permission) && // No need to check if it doesn't make a difference
+ (action == rule->action) &&
+ rule->baseMatch(baseURL, baseClass) &&
+ rule->destMatch(destURL, destClass, baseURL, baseClass))
+ {
+ result = rule->permission;
+ }
+ }
+ return result;
+}
+
+
+uint KApplication::keyboardModifiers()
+{
+#ifdef Q_WS_X11
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ uint keybstate;
+ XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keybstate );
+ return keybstate & 0x00ff;
+#elif defined W_WS_MACX
+ return GetCurrentEventKeyModifiers() & 0x00ff;
+#else
+ //TODO for win32
+ return 0;
+#endif
+}
+
+uint KApplication::mouseState()
+{
+ uint mousestate;
+#ifdef Q_WS_X11
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &mousestate );
+#elif defined(Q_WS_WIN)
+ const bool mousebtn_swapped = GetSystemMetrics(SM_SWAPBUTTON);
+ if (GetAsyncKeyState(VK_LBUTTON))
+ mousestate |= (mousebtn_swapped ? Button3Mask : Button1Mask);
+ if (GetAsyncKeyState(VK_MBUTTON))
+ mousestate |= Button2Mask;
+ if (GetAsyncKeyState(VK_RBUTTON))
+ mousestate |= (mousebtn_swapped ? Button1Mask : Button3Mask);
+#elif defined(Q_WS_MACX)
+ mousestate = GetCurrentEventButtonState();
+#else
+ //TODO: other platforms
+#endif
+ return mousestate & 0xff00;
+}
+
+Qt::ButtonState KApplication::keyboardMouseState()
+{
+ int ret = 0;
+#ifdef Q_WS_X11
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ uint state;
+ XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &state );
+ // transform the same way like Qt's qt_x11_translateButtonState()
+ if( state & Button1Mask )
+ ret |= LeftButton;
+ if( state & Button2Mask )
+ ret |= MidButton;
+ if( state & Button3Mask )
+ ret |= RightButton;
+ if( state & ShiftMask )
+ ret |= ShiftButton;
+ if( state & ControlMask )
+ ret |= ControlButton;
+ if( state & KKeyNative::modX( KKey::ALT ))
+ ret |= AltButton;
+ if( state & KKeyNative::modX( KKey::WIN ))
+ ret |= MetaButton;
+#elif defined(Q_WS_WIN)
+ const bool mousebtn_swapped = GetSystemMetrics(SM_SWAPBUTTON);
+ if (GetAsyncKeyState(VK_LBUTTON))
+ ret |= (mousebtn_swapped ? RightButton : LeftButton);
+ if (GetAsyncKeyState(VK_MBUTTON))
+ ret |= MidButton;
+ if (GetAsyncKeyState(VK_RBUTTON))
+ ret |= (mousebtn_swapped ? LeftButton : RightButton);
+ if (GetAsyncKeyState(VK_SHIFT))
+ ret |= ShiftButton;
+ if (GetAsyncKeyState(VK_CONTROL))
+ ret |= ControlButton;
+ if (GetAsyncKeyState(VK_MENU))
+ ret |= AltButton;
+ if (GetAsyncKeyState(VK_LWIN) || GetAsyncKeyState(VK_RWIN))
+ ret |= MetaButton;
+#else
+ //TODO: other platforms
+#endif
+ return static_cast< ButtonState >( ret );
+}
+
+void KApplication::installSigpipeHandler()
+{
+#ifdef Q_OS_UNIX
+ struct sigaction act;
+ act.sa_handler = SIG_IGN;
+ sigemptyset( &act.sa_mask );
+ act.sa_flags = 0;
+ sigaction( SIGPIPE, &act, 0 );
+#endif
+}
+
+void KApplication::sigpipeHandler(int)
+{
+ int saved_errno = errno;
+ // Using kdDebug from a signal handler is not a good idea.
+#ifndef NDEBUG
+ char msg[1000];
+ sprintf(msg, "*** SIGPIPE *** (ignored, pid = %ld)\n", (long) getpid());
+ write(2, msg, strlen(msg));
+#endif
+
+ // Do nothing.
+ errno = saved_errno;
+}
+
+bool KApplication::guiEnabled()
+{
+ return kapp && kapp->d->guiEnabled;
+}
+
+void KApplication::virtual_hook( int id, void* data )
+{ KInstance::virtual_hook( id, data ); }
+
+void KSessionManaged::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kapplication.moc"
diff --git a/kdecore/kapplication.h b/kdecore/kapplication.h
new file mode 100644
index 000000000..6cffb772f
--- /dev/null
+++ b/kdecore/kapplication.h
@@ -0,0 +1,1476 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ Copyright (c) 1998, 1999 KDE Team
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KAPP_H
+#define _KAPP_H
+
+// Version macros. Never put this further down.
+#include "kdeversion.h"
+#include "kdelibs_export.h"
+
+class KConfig;
+class KCharsets;
+class DCOPClient;
+class DCOPObject;
+
+typedef unsigned long Atom;
+#if !defined(Q_WS_X11)
+typedef void Display;
+#endif
+
+#include <qapplication.h>
+#include <qpixmap.h>
+#include <kinstance.h>
+
+struct _IceConn;
+class QPopupMenu;
+class QStrList;
+class KSessionManaged;
+class KStyle;
+class KURL;
+
+#define kapp KApplication::kApplication()
+
+class KApplicationPrivate;
+
+/**
+* Controls and provides information to all KDE applications.
+*
+* Only one object of this class can be instantiated in a single app.
+* This instance is always accessible via the 'kapp' global variable.
+* See cut() for an example.
+*
+* This class provides the following services to all KDE applications.
+*
+* @li It controls the event queue (see QApplication ).
+* @li It provides the application with KDE resources such as
+* accelerators, common menu entries, a KConfig object. session
+* management events, help invocation etc.
+* @li Installs a signal handler for the SIGCHLD signal in order to
+* avoid zombie children. If you want to catch this signal yourself or
+* don't want it to be caught at all, you have set a new signal handler
+* (or SIG_IGN) after KApplication's constructor has run.
+* @li Installs an empty signal handler for the SIGPIPE signal using
+* installSigpipeHandler(). If you want to catch this signal
+* yourself, you have set a new signal handler after KApplication's
+* constructor has run.
+* @li It can start new services
+*
+*
+* The way a service gets started depends on the 'X-DCOP-ServiceType'
+* entry in the desktop file of the service:
+*
+* There are three possibilities:
+* @li X-DCOP-ServiceType=None (default)
+* Always start a new service,
+* don't wait till the service registers with dcop.
+* @li X-DCOP-ServiceType=Multi
+* Always start a new service,
+* wait until the service has registered with dcop.
+* @li X-DCOP-ServiceType=Unique
+* Only start the service if it isn't already running,
+* wait until the service has registered with dcop.
+*
+* @short Controls and provides information to all KDE applications.
+* @author Matthias Kalle Dalheimer <kalle@kde.org>
+*/
+class KDECORE_EXPORT KApplication : public QApplication, public KInstance
+{
+
+ Q_OBJECT
+public:
+ /** Position of the caption (presumably in the application window's
+ * title bar). This enum appears to be unused.
+ *
+ * @todo Find out if this is used anywhere.
+ */
+ enum CaptionLayout {
+ CaptionAppLast=1 /**< Display the application name last (before document name). */,
+ CaptionAppFirst /**< Display the application name first. */ ,
+ CaptionNoApp /**< Do not display application name at all. */
+ };
+
+ /**
+ * This constructor takes aboutData and command line
+ * arguments from KCmdLineArgs.
+ *
+ * @param allowStyles Set to false to disable the loading on plugin based
+ * styles. This is only useful to applications that do not display a GUI
+ * normally. If you do create an application with @p allowStyles set to false
+ * it normally runs in the background but under special circumstances
+ * displays widgets. Call enableStyles() before displaying any widgets.
+ *
+ * @param GUIenabled Set to false to disable all GUI stuff. This implies
+ * no styles either.
+ */
+ KApplication( bool allowStyles=true, bool GUIenabled=true);
+
+#ifdef Q_WS_X11
+ /**
+ * Constructor. Parses command-line arguments. Use this constructor when you
+ * you need to use a non-default visual or colormap.
+ *
+ * @param display Will be passed to Qt as the X display. The display must be
+ * valid and already opened.
+ *
+ * @param visual A pointer to the X11 visual that should be used by the
+ * appliction. Note that only TrueColor visuals are supported on depths
+ * greater than 8 bpp. If this parameter is NULL, the default visual will
+ * be used instead.
+ *
+ * @param colormap The colormap that should be used by the application. If
+ * this parameter is 0, the default colormap will be used instead.
+ *
+ * @param allowStyles Set to false to disable the loading on plugin based
+ * styles. This is only useful to applications that do not display a GUI
+ * normally. If you do create an application with @p allowStyles set to false
+ * that normally runs in the background but under special circumstances
+ * displays widgets call enableStyles() before displaying any widgets.
+ *
+ * @since KDE 3.3
+ */
+ KApplication(Display *display, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0,
+ bool allowStyles=true);
+
+ /**
+ * Constructor. Parses command-line arguments. Use this constructor to use KApplication
+ * in a Motif or Xt program.
+ *
+ * @param display Will be passed to Qt as the X display. The display must be valid and already
+ * opened.
+ *
+ * @param argc command line argument count
+ *
+ * @param argv command line argument value(s)
+ *
+ * @param rAppName application name. Will be used for finding the
+ * associated message files and icon files, and as the default
+ * registration name for DCOP. This is a mandatory parameter.
+ *
+ * @param allowStyles Set to false to disable the loading on plugin based
+ * styles. This is only useful to applications that do not display a GUI
+ * normally. If you do create an application with @p allowStyles set to false
+ * that normally runs in the background but under special circumstances
+ * displays widgets call enableStyles() before displaying any widgets.
+ *
+ * @param GUIenabled Set to false to disable all GUI stuff. This implies
+ * no styles either.
+ */
+ KApplication(Display *display, int& argc, char** argv, const QCString& rAppName,
+ bool allowStyles=true, bool GUIenabled=true);
+#endif
+
+ /**
+ * @deprecated do not use it at all, it will make your application crash, use KCmdLineArgs
+ *
+ * Constructor. Parses command-line arguments.
+ *
+ * @param argc command line argument count
+ *
+ * @param argv command line argument value(s)
+ *
+ * @param rAppName application name. Will be used for finding the
+ * associated message files and icon files, and as the default
+ * registration name for DCOP. This is a mandatory parameter.
+ *
+ * @param allowStyles Set to false to disable the loading on plugin based
+ * styles. This is only useful to applications that do not display a GUI
+ * normally. If you do create an application with @p allowStyles set to false
+ * that normally runs in the background but under special circumstances
+ * displays widgets call enableStyles() before displaying any widgets.
+ *
+ * @param GUIenabled Set to false to disable all GUI stuff. This implies
+ * no styles either.
+ */
+ // REMOVE FOR KDE 4.0 - using it only gives crashing applications because
+ // KCmdLineArgs::init isn't called
+ KApplication(int& argc, char** argv,
+ const QCString& rAppName, bool allowStyles=true, bool GUIenabled=true) KDE_DEPRECATED;
+
+ /**
+ * Add Qt and KDE command line options to KCmdLineArgs.
+ */
+ static void addCmdLineOptions();
+
+ virtual ~KApplication();
+
+ /**
+ * Returns the current application object.
+ *
+ * This is similar to the global QApplication pointer qApp. It
+ * allows access to the single global KApplication object, since
+ * more than one cannot be created in the same application. It
+ * saves you the trouble of having to pass the pointer explicitly
+ * to every function that may require it.
+ * @return the current application object
+ */
+ static KApplication* kApplication() { return KApp; }
+
+ /**
+ * Returns the application session config object.
+ *
+ * @return A pointer to the application's instance specific
+ * KConfig object.
+ * @see KConfig
+ */
+ KConfig* sessionConfig();
+
+ /**
+ * Is the application restored from the session manager?
+ *
+ * @return If true, this application was restored by the session manager.
+ * Note that this may mean the config object returned by
+ * sessionConfig() contains data saved by a session closedown.
+ * @see sessionConfig()
+ */
+ bool isRestored() const { return QApplication::isSessionRestored(); }
+
+ /**
+ * Disables session management for this application.
+ *
+ * Useful in case your application is started by the
+ * initial "startkde" script.
+ */
+ void disableSessionManagement();
+
+ /**
+ * Enables again session management for this application, formerly
+ * disabled by calling disableSessionManagement(). You usually
+ * shouldn't call this function, as the session management is enabled
+ * by default.
+ */
+ void enableSessionManagement();
+
+ /**
+ * The possible values for the @p confirm parameter of requestShutDown().
+ */
+ enum ShutdownConfirm {
+ /**
+ * Obey the user's confirmation setting.
+ */
+ ShutdownConfirmDefault = -1,
+ /**
+ * Don't confirm, shutdown without asking.
+ */
+ ShutdownConfirmNo = 0,
+ /**
+ * Always confirm, ask even if the user turned it off.
+ */
+ ShutdownConfirmYes = 1
+ };
+
+ /**
+ * The possible values for the @p sdtype parameter of requestShutDown().
+ */
+ enum ShutdownType {
+ /**
+ * Select previous action or the default if it's the first time.
+ */
+ ShutdownTypeDefault = -1,
+ /**
+ * Only log out.
+ */
+ ShutdownTypeNone = 0,
+ /**
+ * Log out and reboot the machine.
+ */
+ ShutdownTypeReboot = 1,
+ /**
+ * Log out and halt the machine.
+ */
+ ShutdownTypeHalt = 2
+ };
+
+ /**
+ * The possible values for the @p sdmode parameter of requestShutDown().
+ */
+ enum ShutdownMode {
+ /**
+ * Select previous mode or the default if it's the first time.
+ */
+ ShutdownModeDefault = -1,
+ /**
+ * Schedule a shutdown (halt or reboot) for the time all active sessions
+ * have exited.
+ */
+ ShutdownModeSchedule = 0,
+ /**
+ * Shut down, if no sessions are active. Otherwise do nothing.
+ */
+ ShutdownModeTryNow = 1,
+ /**
+ * Force shutdown. Kill any possibly active sessions.
+ */
+ ShutdownModeForceNow = 2,
+ /**
+ * Pop up a dialog asking the user what to do if sessions are still active.
+ */
+ ShutdownModeInteractive = 3
+ };
+
+ /**
+ * Asks the session manager to shut the session down.
+ *
+ * Using @p confirm == ShutdownConfirmYes or @p sdtype != ShutdownTypeDefault or
+ * @p sdmode != ShutdownModeDefault causes the use of ksmserver's DCOP
+ * interface. The remaining two combinations use the standard XSMP and
+ * will work with any session manager compliant with it.
+ *
+ * @param confirm Whether to ask the user if he really wants to log out.
+ * ShutdownConfirm
+ * @param sdtype The action to take after logging out. ShutdownType
+ * @param sdmode If/When the action should be taken. ShutdownMode
+ * @return true on success, false if the session manager could not be
+ * contacted.
+ */
+ bool requestShutDown( ShutdownConfirm confirm = ShutdownConfirmDefault,
+ ShutdownType sdtype = ShutdownTypeDefault,
+ ShutdownMode sdmode = ShutdownModeDefault );
+
+ /**
+ * Propagates the network address of the session manager in the
+ * SESSION_MANAGER environment variable so that child processes can
+ * pick it up.
+ *
+ * If SESSION_MANAGER isn't defined yet, the address is searched in
+ * $HOME/.KSMserver.
+ *
+ * This function is called by clients that are started outside the
+ * session ( i.e. before ksmserver is started), but want to launch
+ * other processes that should participate in the session. Examples
+ * are kdesktop or kicker.
+ */
+ void propagateSessionManager();
+
+ /**
+ * Reimplemented for internal purposes, mainly the highlevel
+ * handling of session management with KSessionManaged.
+ * @internal
+ */
+ void commitData( QSessionManager& sm );
+
+ /**
+ * Reimplemented for internal purposes, mainly the highlevel
+ * handling of session management with KSessionManaged.
+ * @internal
+ */
+ void saveState( QSessionManager& sm );
+
+ /**
+ * Returns true if the application is currently saving its session
+ * data (most probably before KDE logout). This is intended for use
+ * mainly in KMainWindow::queryClose() and KMainWindow::queryExit().
+ *
+ * @see KMainWindow::queryClose
+ * @see KMainWindow::queryExit
+ * @since 3.1.1
+ */
+ bool sessionSaving() const;
+
+ /**
+ * Returns a pointer to a DCOPClient for the application.
+ * If a client does not exist yet, it is created when this
+ * function is called.
+ * @return the DCOPClient for the application
+ */
+ static DCOPClient *dcopClient();
+
+ /**
+ * Disable automatic dcop registration
+ * Must be called before creating a KApplication instance to have an effect.
+ */
+ static void disableAutoDcopRegistration();
+
+ /**
+ * Returns a QPixmap with the application icon.
+ * @return the application icon
+ */
+ QPixmap icon() const;
+
+ /**
+ * Returns the name of the application icon.
+ * @return the icon's name
+ */
+ QString iconName() const;
+
+ /**
+ * Returns the mini-icon for the application as a QPixmap.
+ * @return the application's mini icon
+ */
+ QPixmap miniIcon() const;
+
+ /**
+ * Returns the name of the mini-icon for the application.
+ * @return the mini icon's name
+ */
+ QString miniIconName() const;
+
+ /**
+ * Sets the top widget of the application.
+ * This means basically applying the right window caption and
+ * icon. An application may have several top widgets. You don't
+ * need to call this function manually when using KMainWindow.
+ *
+ * @param topWidget A top widget of the application.
+ *
+ * @see icon(), caption()
+ **/
+ void setTopWidget( QWidget *topWidget );
+
+ /**
+ * Invokes the KHelpCenter HTML help viewer from docbook sources.
+ *
+ * @param anchor This has to be a defined anchor in your
+ * docbook sources. If empty the main index
+ * is loaded
+ * @param appname This allows you to show the help of another
+ * application. If empty the current name() is
+ * used
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+ void invokeHelp( const QString& anchor,
+ const QString& appname,
+ const QCString& startup_id ) const;
+
+ // KDE4 merge with above with startup_id = ""
+ void invokeHelp( const QString& anchor = QString::null,
+ const QString& appname = QString::null ) const;
+
+ /**
+ * @deprecated
+ * Invoke the khelpcenter HTML help viewer from HTML sources.
+ * Please use invokeHelp() instead.
+ *
+ * @param aFilename The filename that is to be loaded. Its
+ * location is computed automatically
+ * according to the KFSSTND. If @p aFilename
+ * is empty, the logical appname with .html
+ * appended to it is used.
+ * @param aTopic This allows context-sensitive help. Its
+ * value will be appended to the filename,
+ * prefixed with a "#" (hash) character.
+ */
+ void invokeHTMLHelp( const QString& aFilename, const QString& aTopic = QString::null ) const KDE_DEPRECATED;
+
+ /**
+ * Convenience method; invokes the standard email application.
+ *
+ * @param address The destination address
+ * @param subject Subject string. Can be QString::null.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+ void invokeMailer( const QString &address, const QString &subject, const QCString& startup_id );
+ // KDE4 merge with above with startup_id = ""
+ void invokeMailer( const QString &address, const QString &subject );
+
+ /**
+ * Invokes the standard email application.
+ *
+ * @param mailtoURL A mailto URL.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param allowAttachments whether attachments specified in mailtoURL should be honoured.
+ The default is false; do not honour requests for attachments.
+ */
+ void invokeMailer( const KURL &mailtoURL, const QCString& startup_id, bool allowAttachments );
+ // KDE4 merge with above with allowAttachments = false
+ void invokeMailer( const KURL &mailtoURL, const QCString& startup_id );
+ // KDE4 merge with above with startup_id = ""
+ void invokeMailer( const KURL &mailtoURL );
+
+ /**
+ * Convenience method; invokes the standard email application.
+ *
+ * All parameters are optional.
+ *
+ * @param to The destination address.
+ * @param cc The Cc field
+ * @param bcc The Bcc field
+ * @param subject Subject string
+ * @param body A string containing the body of the mail (exclusive with messageFile)
+ * @param messageFile A file (URL) containing the body of the mail (exclusive with body) - currently unsupported
+ * @param attachURLs List of URLs to be attached to the mail.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+ void invokeMailer(const QString &to, const QString &cc, const QString &bcc,
+ const QString &subject, const QString &body,
+ const QString &messageFile, const QStringList &attachURLs,
+ const QCString& startup_id );
+ // KDE4 merge with above with startup_id = ""
+ void invokeMailer(const QString &to, const QString &cc, const QString &bcc,
+ const QString &subject, const QString &body,
+ const QString &messageFile = QString::null, const QStringList &attachURLs = QStringList());
+
+public slots:
+ /**
+ * Invokes the standard browser.
+ * Note that you should only do this when you know for sure that the browser can
+ * handle the URL (i.e. its mimetype). In doubt, if the URL can point to an image
+ * or anything else than directory or HTML, prefer to use new KRun( url ).
+ *
+ * @param url The destination address
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+ void invokeBrowser( const QString &url, const QCString& startup_id );
+ // KDE4 merge with above with startup_id = ""
+ /**
+ * Invoke the standard browser. Uses a @p startup_id of "" (empty)
+ * and is otherwise the same as the above function.
+ */
+ void invokeBrowser( const QString &url );
+
+ /**
+ * If the widget with focus provides a cut() slot, call that slot. Thus for a
+ * simple application cut can be implemented as:
+ * \code
+ * KStdAction::cut( kapp, SLOT( cut() ), actionCollection() );
+ * \endcode
+ */
+ void cut();
+
+ /**
+ * If the widget with focus provides a copy() slot, call that slot. Thus for a
+ * simple application copy can be implemented as:
+ * \code
+ * KStdAction::copy( kapp, SLOT( copy() ), actionCollection() );
+ * \endcode
+ */
+ void copy();
+
+ /**
+ * If the widget with focus provides a paste() slot, call that slot. Thus for a
+ * simple application copy can be implemented as:
+ * \code
+ * KStdAction::paste( kapp, SLOT( paste() ), actionCollection() );
+ * \endcode
+ */
+ void paste();
+
+ /**
+ * If the widget with focus provides a clear() slot, call that slot. Thus for a
+ * simple application clear() can be implemented as:
+ * \code
+ * new KAction( i18n( "Clear" ), "editclear", 0, kapp, SLOT( clear() ), actionCollection(), "clear" );
+ * \endcode
+ *
+ * Note that for some widgets, this may not provide the intended bahavior. For
+ * example if you make use of the code above and a KListView has the focus, clear()
+ * will clear all of the items in the list. If this is not the intened behavior
+ * and you want to make use of this slot, you can subclass KListView and reimplement
+ * this slot. For example the following code would implement a KListView without this
+ * behavior:
+ *
+ * \code
+ * class MyListView : public KListView {
+ * Q_OBJECT
+ * public:
+ * MyListView( QWidget * parent = 0, const char * name = 0, WFlags f = 0 ) : KListView( parent, name, f ) {}
+ * virtual ~MyListView() {}
+ * public slots:
+ * virtual void clear() {}
+ * };
+ * \endcode
+ */
+ void clear();
+
+ /**
+ * If the widget with focus provides a selectAll() slot, call that slot. Thus for a
+ * simple application select all can be implemented as:
+ * \code
+ * KStdAction::selectAll( kapp, SLOT( selectAll() ), actionCollection() );
+ * \endcode
+ */
+ void selectAll();
+
+public:
+ /**
+ * Returns the DCOP name of the service launcher. This will be something like
+ * klaucher_$host_$uid.
+ * @return the name of the service launcher
+ */
+ static QCString launcher();
+
+ /**
+ * Starts a service based on the (translated) name of the service.
+ * E.g. "Web Browser"
+ *
+ * @param _name the name of the service
+ * @param URL if not empty this URL is passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByName( const QString& _name, const QString &URL,
+ QString *error=0, QCString *dcopService=0, int *pid=0, const QCString &startup_id = "", bool noWait = false );
+
+ /**
+ * Starts a service based on the (translated) name of the service.
+ * E.g. "Web Browser"
+ *
+ * @param _name the name of the service
+ * @param URLs if not empty these URLs will be passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByName( const QString& _name, const QStringList &URLs=QStringList(),
+ QString *error=0, QCString *dcopService=0, int *pid=0, const QCString &startup_id = "", bool noWait = false );
+
+ /**
+ * Starts a service based on the desktop path of the service.
+ * E.g. "Applications/konqueror.desktop" or "/home/user/bla/myfile.desktop"
+ *
+ * @param _name the path of the desktop file
+ * @param URL if not empty this URL is passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopPath( const QString& _name, const QString &URL,
+ QString *error=0, QCString *dcopService=0, int *pid = 0, const QCString &startup_id = "", bool noWait = false );
+
+ /**
+ * Starts a service based on the desktop path of the service.
+ * E.g. "Applications/konqueror.desktop" or "/home/user/bla/myfile.desktop"
+ *
+ * @param _name the path of the desktop file
+ * @param URLs if not empty these URLs will be passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopPath( const QString& _name, const QStringList &URLs=QStringList(),
+ QString *error=0, QCString *dcopService=0, int *pid = 0, const QCString &startup_id = "", bool noWait = false );
+
+ /**
+ * Starts a service based on the desktop name of the service.
+ * E.g. "konqueror"
+ *
+ * @param _name the desktop name of the service
+ * @param URL if not empty this URL is passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopName( const QString& _name, const QString &URL,
+ QString *error=0, QCString *dcopService=0, int *pid = 0, const QCString &startup_id = "", bool noWait = false );
+
+ /**
+ * Starts a service based on the desktop name of the service.
+ * E.g. "konqueror"
+ *
+ * @param _name the desktop name of the service
+ * @param URLs if not empty these URLs will be passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopName( const QString& _name, const QStringList &URLs=QStringList(),
+ QString *error=0, QCString *dcopService=0, int *pid = 0, const QCString &startup_id = "", bool noWait = false );
+
+ /**
+ * Starts a program via kdeinit.
+ *
+ * program name and arguments are converted to according to the
+ * local encoding and passed as is to kdeinit.
+ *
+ * @param name Name of the program to start
+ * @param args Arguments to pass to the program
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int kdeinitExec( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QCString& startup_id );
+ // KDE4 merge with above with startup_id = ""
+ static int kdeinitExec( const QString& name, const QStringList &args=QStringList(),
+ QString *error=0, int *pid = 0 );
+
+ /**
+ * Starts a program via kdeinit and wait for it to finish.
+ *
+ * Like kdeinitExec(), but it waits till the program is finished.
+ * As such it behaves similar to the system(...) function.
+ *
+ * @param name Name of the program to start
+ * @param args Arguments to pass to the program
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int kdeinitExecWait( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QCString& startup_id );
+ // KDE4 merge with above with startup_id = ""
+ static int kdeinitExecWait( const QString& name, const QStringList &args=QStringList(),
+ QString *error=0, int *pid = 0 );
+
+ /**
+ * Returns a text for the window caption.
+ *
+ * This may be set by
+ * "-caption", otherwise it will be equivalent to the name of the
+ * executable.
+ * @return the text for the window caption
+ */
+ QString caption() const;
+
+ /**
+ * @deprecated
+ */
+ KDE_DEPRECATED KStyle* kstyle() const { return 0; }
+
+ /**
+ * Builds a caption that contains the application name along with the
+ * userCaption using a standard layout.
+ *
+ * To make a compliant caption
+ * for your window, simply do: @p setCaption(kapp->makeStdCaption(yourCaption));
+ *
+ * @param userCaption The caption string you want to display in the
+ * window caption area. Do not include the application name!
+ * @param withAppName Indicates that the method shall include or ignore
+ * the application name when making the caption string. You are not
+ * compliant if you set this to @p false.
+ * @param modified If true, a 'modified' sign will be included in the
+ * returned string. This is useful when indicating that a file is
+ * modified, i.e., it contains data that has not been saved.
+ * @return the created caption
+ */
+ QString makeStdCaption( const QString &userCaption,
+ bool withAppName=true, bool modified=false ) const;
+
+ /**
+ * Get a file name in order to make a temporary copy of your document.
+ *
+ * @param pFilename The full path to the current file of your
+ * document.
+ * @return A new filename for auto-saving.
+ */
+ QString tempSaveName( const QString& pFilename ) const;
+
+ /**
+ * Check whether an auto-save file exists for the document you want to
+ * open.
+ *
+ * @param pFilename The full path to the document you want to open.
+ * @param bRecover This gets set to true if there was a recover
+ * file.
+ * @return The full path of the file to open.
+ */
+ QString checkRecoverFile( const QString& pFilename, bool& bRecover ) const;
+
+#ifdef Q_WS_X11
+ /**
+ * Get the X11 display
+ * @return the X11 Display
+ */
+ Display *getDisplay() { return display; }
+#endif
+
+ /**
+ * Enables style plugins.
+ *
+ * This is useful only to applications that normally
+ * do not display a GUI and create the KApplication with
+ * allowStyles set to false.
+ */
+ void enableStyles();
+
+ /**
+ * Disables style plugins.
+ *
+ * Current style plugins do not get unloaded.
+ *
+ * This is only useful when used in combination with enableStyles().
+ */
+ void disableStyles();
+
+ /**
+ * Installs widget filter as global X11 event filter.
+ *
+ * The widget
+ * filter receives XEvents in its standard QWidget::x11Event() function.
+ *
+ * Warning: Only do this when absolutely necessary. An installed X11 filter
+ * can slow things down.
+ **/
+ void installX11EventFilter( QWidget* filter );
+
+ /**
+ * Removes global X11 event filter previously installed by
+ * installX11EventFilter().
+ */
+ void removeX11EventFilter( const QWidget* filter );
+
+ /**
+ * Generates a uniform random number.
+ * @return A truly unpredictable number in the range [0, RAND_MAX)
+ */
+ static int random();
+
+ /**
+ * Generates a random string. It operates in the range [A-Za-z0-9]
+ * @param length Generate a string of this length.
+ * @return the random string
+ */
+ static QString randomString(int length);
+
+ /**
+ * Adds a message type to the KIPC event mask. You can only add "system
+ * messages" to the event mask. These are the messages with id < 32.
+ * Messages with id >= 32 are user messages.
+ * @param id The message id. See KIPC::Message.
+ * @see KIPC
+ * @see removeKipcEventMask()
+ * @see kipcMessage()
+ */
+ void addKipcEventMask(int id);
+
+ /**
+ * Removes a message type from the KIPC event mask. This message will
+ * not be handled anymore.
+ * @param id The message id.
+ * @see KIPC
+ * @see addKipcEventMask()
+ * @see kipcMessage()
+ */
+ void removeKipcEventMask(int id);
+
+ /**
+ * Returns the app startup notification identifier for this running
+ * application.
+ * @return the startup notification identifier
+ */
+ QCString startupId() const;
+
+ /**
+ * @internal
+ * Sets a new value for the application startup notification window property for newly
+ * created toplevel windows.
+ * @param startup_id the startup notification identifier
+ * @see KStartupInfo::setNewStartupId
+ */
+ void setStartupId( const QCString& startup_id );
+
+ /**
+ * Updates the last user action timestamp to the given time, or to the current time,
+ * if 0 is given. Do not use unless you're really sure what you're doing.
+ * Consult focus stealing prevention section in kdebase/kwin/README.
+ * @since 3.2
+ */
+ void updateUserTimestamp( unsigned long time = 0 );
+
+ /**
+ * Returns the last user action timestamp or 0 if no user activity has taken place yet.
+ * @since 3.2.3
+ * @see updateuserTimestamp
+ */
+ unsigned long userTimestamp() const;
+
+ /**
+ * Updates the last user action timestamp in the application registered to DCOP with dcopId
+ * to the given time, or to this application's user time, if 0 is given.
+ * Use before causing user interaction in the remote application, e.g. invoking a dialog
+ * in the application using a DCOP call.
+ * Consult focus stealing prevention section in kdebase/kwin/README.
+ * @since 3.3
+ */
+ void updateRemoteUserTimestamp( const QCString& dcopId, unsigned long time = 0 );
+
+ /**
+ * Returns the argument to --geometry if any, so the geometry can be set
+ * wherever necessary
+ * @return the geometry argument, or QString::null if there is none
+ */
+ QString geometryArgument() const;
+
+ /**
+ * Install a Qt SQL property map with entries for all KDE widgets
+ * Call this in any application using KDE widgets in QSqlForm or QDataView.
+ */
+ void installKDEPropertyMap();
+
+ /**
+ * Returns whether a certain action is authorized
+ * @param genericAction The name of a generic action
+ * @return true if the action is authorized
+ */
+ bool authorize(const QString &genericAction);
+
+ /**
+ * Returns whether a certain KAction is authorized.
+ *
+ * @param action The name of a KAction action. The name is prepended
+ * with "action/" before being passed to authorize()
+ * @return true if the KAction is authorized
+ */
+ bool authorizeKAction(const char *action);
+
+ /**
+ * Returns whether a certain URL related action is authorized.
+ *
+ * @param action The name of the action. Known actions are
+ * list (may be listed (e.g. in file selection dialog)),
+ * link (may be linked to),
+ * open (may open) and
+ * redirect (may be redirected to)
+ * @param baseURL The url where the action originates from
+ * @param destURL The object of the action
+ * @return true when the action is authorized, false otherwise.
+ * @since 3.1
+ */
+ bool authorizeURLAction(const QString &action, const KURL &baseURL, const KURL &destURL);
+
+ /**
+ * Allow a certain URL action. This can be useful if your application
+ * needs to ensure access to an application specific directory that may
+ * otherwise be subject to KIOSK restrictions.
+ * @param action The name of the action.
+ * @param _baseURL The url where the action originates from
+ * @param _destURL The object of the action
+ * @since 3.2
+ */
+ void allowURLAction(const QString &action, const KURL &_baseURL, const KURL &_destURL);
+
+ /**
+ * Returns whether access to a certain control module is authorized.
+ *
+ * @param menuId identifying the control module, e.g. kde-mouse.desktop
+ * @return true if access to the module is authorized, false otherwise.
+ * @since 3.2
+ */
+ bool authorizeControlModule(const QString &menuId);
+
+ /**
+ * Returns whether access to a certain control modules is authorized.
+ *
+ * @param menuIds list of menu-ids of control module,
+ * an example of a menu-id is kde-mouse.desktop.
+ * @return Those control modules for which access has been authorized.
+ * @since 3.2
+ */
+ QStringList authorizeControlModules(const QStringList &menuIds);
+
+ /**
+ * Returns the state of the currently pressed keyboard modifiers (e.g. shift, control, etc.)
+ * and mouse buttons, similarly to QKeyEvent::state() and QMouseEvent::state().
+ * You usually should simply use the information provided by QKeyEvent and QMouseEvent,
+ * but it can be useful to query for the status of the modifiers at another moment
+ * (e.g. some KDE apps do that upon a drop event).
+ * @return the keyboard modifiers and mouse buttons state
+ * @since 3.4
+ */
+ static ButtonState keyboardMouseState();
+
+ // Same values as ShiftMask etc. in X.h
+ enum { ShiftModifier = 1<<0,
+ LockModifier = 1<<1,
+ ControlModifier = 1<<2,
+ Modifier1 = 1<<3,
+ Modifier2 = 1<<4,
+ Modifier3 = 1<<5,
+ Modifier4 = 1<<6,
+ Modifier5 = 1<<7 };
+ /**
+ * @deprecated Use keyboardMouseState()
+ * @since 3.1
+ */
+ static uint keyboardModifiers() KDE_DEPRECATED;
+
+ /** @deprecated Same values as Button1Mask etc. in X.h */
+ enum { Button1Pressed = 1<<8,
+ Button2Pressed = 1<<9,
+ Button3Pressed = 1<<10,
+ Button4Pressed = 1<<11,
+ Button5Pressed = 1<<12 };
+ /**
+ * @deprecated Use keyboardMouseState()
+ * @since 3.1
+ */
+ static uint mouseState() KDE_DEPRECATED;
+
+
+public slots:
+ /**
+ * Tells KApplication about one more operation that should be finished
+ * before the application exits. The standard behavior is to exit on the
+ * "last window closed" event, but some events should outlive the last window closed
+ * (e.g. a file copy for a file manager, or 'compacting folders on exit' for a mail client).
+ */
+ void ref();
+
+ /**
+ * Tells KApplication that one operation such as those described in ref() just finished.
+ * The application exits if the counter is back to 0.
+ */
+ void deref();
+
+protected:
+ /**
+ * @internal Used by KUniqueApplication
+ */
+ KApplication( bool allowStyles, bool GUIenabled, KInstance* _instance );
+
+#ifdef Q_WS_X11
+ /**
+ * @internal Used by KUniqueApplication
+ */
+ KApplication( Display *display, Qt::HANDLE visual, Qt::HANDLE colormap,
+ bool allowStyles, KInstance* _instance );
+
+ /**
+ * Used to catch X11 events
+ */
+ bool x11EventFilter( XEvent * );
+
+ Display *display;
+#endif
+ Atom kipcCommAtom;
+ int kipcEventMask;
+
+ /// Current application object.
+ static KApplication *KApp;
+ int pArgc;
+
+ /**
+ * This method is used internally to determine which edit slots are implemented
+ * by the widget that has the focus, and to invoke those slots if available.
+ *
+ * @param slot is the slot as returned using the SLOT() macro, for example SLOT( cut() )
+ *
+ * This method can be used in KApplication subclasses to implement application wide
+ * edit actions not supported by the KApplication class. For example (in your subclass):
+ *
+ * \code
+ * void MyApplication::deselect()
+ * {
+ * invokeEditSlot( SLOT( deselect() ) );
+ * }
+ * \endcode
+ *
+ * Now in your application calls to MyApplication::deselect() will call this slot on the
+ * focused widget if it provides this slot. You can combine this with KAction with:
+ *
+ * \code
+ * KStdAction::deselect( static_cast<MyApplication *>( kapp ), SLOT( cut() ), actionCollection() );
+ * \endcode
+ *
+ * @see cut()
+ * @see copy()
+ * @see paste()
+ * @see clear()
+ * @see selectAll()
+ *
+ * @since 3.2
+ */
+ void invokeEditSlot( const char *slot );
+
+private slots:
+ void dcopFailure(const QString &);
+ void dcopBlockUserInput( bool );
+ void x11FilterDestroyed();
+ void checkAppStartedSlot();
+
+private:
+ QString sessionConfigName() const;
+ KConfig* pSessionConfig; //instance specific application config object
+ static DCOPClient *s_DCOPClient; // app specific application communication client
+ static bool s_dcopClientNeedsPostInit;
+ QString aCaption; // the name for the window title
+ bool bSessionManagement;
+ struct oldPixmapType { QPixmap a, b; };
+ mutable union {
+ struct {
+ QPixmap *icon, *miniIcon;
+ } pm;
+ char unused[sizeof(oldPixmapType)];
+ } aIconPixmap; // KDE4: remove me
+ QString aIconName;
+ QString aMiniIconName;
+ bool useStyles;
+ QWidget *smw;
+
+ void init( bool GUIenabled );
+
+ void parseCommandLine( ); // Handle KDE arguments (Using KCmdLineArgs)
+
+ void read_app_startup_id();
+
+ void dcopAutoRegistration();
+ void dcopClientPostInit();
+ void initUrlActionRestrictions();
+
+public:
+ /**
+ * @internal
+ */
+ bool notify(QObject *receiver, QEvent *event);
+
+ /**
+ @internal
+ */
+ int xErrhandler( Display*, void* );
+
+ /**
+ @internal
+ */
+ int xioErrhandler( Display* );
+
+ /**
+ * @internal
+ */
+ void iceIOErrorHandler( _IceConn *conn );
+
+ /**
+ * @internal
+ */
+ static bool loadedByKdeinit;
+
+ /**
+ * @internal
+ */
+ static void startKdeinit();
+
+ /**
+ * Valid values for the settingsChanged signal
+ */
+ enum SettingsCategory { SETTINGS_MOUSE, SETTINGS_COMPLETION, SETTINGS_PATHS,
+ SETTINGS_POPUPMENU, SETTINGS_QT, SETTINGS_SHORTCUTS };
+
+ /**
+ * Used to obtain the QPalette that will be used to set the application palette.
+ *
+ * This is only useful for configuration modules such as krdb and should not be
+ * used in normal circumstances.
+ * @return the QPalette
+ * @since 3.1
+ */
+ static QPalette createApplicationPalette();
+
+ /**
+ * @internal
+ * Raw access for use by KDM.
+ */
+ static QPalette createApplicationPalette( KConfig *config, int contrast );
+
+ /**
+ * Installs a handler for the SIGPIPE signal. It is thrown when you write to
+ * a pipe or socket that has been closed.
+ * The handler is installed automatically in the constructor, but you may
+ * need it if your application or component does not have a KApplication
+ * instance.
+ */
+ static void installSigpipeHandler();
+
+ /**
+ * @internal
+ * Whether widgets can be used.
+ *
+ * @since 3.2
+ */
+ static bool guiEnabled();
+
+signals:
+ /**
+ * Emitted when KApplication has changed its palette due to a KControl request.
+ *
+ * Normally, widgets will update their palette automatically, but you
+ * should connect to this to program special behavior.
+ */
+ void kdisplayPaletteChanged();
+
+ /**
+ * Emitted when KApplication has changed its GUI style in response to a KControl request.
+ *
+ * Normally, widgets will update their styles automatically (as they would
+ * respond to an explicit setGUIStyle() call), but you should connect to
+ * this to program special behavior.
+ */
+ void kdisplayStyleChanged();
+
+ /**
+ * Emitted when KApplication has changed its font in response to a KControl request.
+ *
+ * Normally widgets will update their fonts automatically, but you should
+ * connect to this to monitor global font changes, especially if you are
+ * using explicit fonts.
+ *
+ * Note: If you derive from a QWidget-based class, a faster method is to
+ * reimplement QWidget::fontChange(). This is the preferred way
+ * to get informed about font updates.
+ */
+ void kdisplayFontChanged();
+
+ /**
+ * Emitted when KApplication has changed either its GUI style, its font or its palette
+ * in response to a kdisplay request. Normally, widgets will update their styles
+ * automatically, but you should connect to this to program special
+ * behavior. */
+ void appearanceChanged();
+
+ /**
+ * Emitted when the settings for toolbars have been changed. KToolBar will know what to do.
+ */
+ void toolbarAppearanceChanged(int);
+
+ /**
+ * Emitted when the desktop background has been changed by @p kcmdisplay.
+ *
+ * @param desk The desktop whose background has changed.
+ */
+ void backgroundChanged(int desk);
+
+ /**
+ * Emitted when the global settings have been changed - see KGlobalSettings
+ * KApplication takes care of calling reparseConfiguration on KGlobal::config()
+ * so that applications/classes using this only have to re-read the configuration
+ * @param category the category among the enum above
+ */
+ void settingsChanged(int category);
+
+ /**
+ * Emitted when the global icon settings have been changed.
+ * @param group the new group
+ */
+ void iconChanged(int group);
+
+ /**
+ * Emitted when a KIPC user message has been received.
+ * @param id the message id
+ * @param data the data
+ * @see KIPC
+ * @see KIPC::Message
+ * @see addKipcEventMask
+ * @see removeKipcEventMask
+ */
+ void kipcMessage(int id, int data);
+
+ /**
+ Session management asks you to save the state of your application.
+
+ This signal is provided for compatibility only. For new
+ applications, simply use KMainWindow. By reimplementing
+ KMainWindow::queryClose(), KMainWindow::saveProperties() and
+ KMainWindow::readProperties() you can simply handle session
+ management for applications with multiple toplevel windows.
+
+ For purposes without KMainWindow, create an instance of
+ KSessionManaged and reimplement the functions
+ KSessionManaged::commitData() and/or
+ KSessionManaged::saveState()
+
+ If you still want to use this signal, here is what you should do:
+
+ Connect to this signal in order to save your data. Do NOT
+ manipulate the UI in that slot, it is blocked by the session
+ manager.
+
+ Use the sessionConfig() KConfig object to store all your
+ instance specific data.
+
+ Do not do any closing at this point! The user may still select
+ Cancel wanting to continue working with your
+ application. Cleanups could be done after shutDown() (see
+ the following).
+
+ */
+ void saveYourself();
+
+ /** Your application is killed. Either by your program itself,
+ @p xkill or (the usual case) by KDE's logout.
+
+ The signal is particularly useful if your application has to do some
+ last-second cleanups. Note that no user interaction is possible at
+ this state.
+ */
+ void shutDown();
+
+ /**
+ * @internal
+ * Used to notify KIconLoader objects that they need to reload.
+ */
+ void updateIconLoaders();
+
+private:
+ void propagateSettings(SettingsCategory category);
+ void kdisplaySetPalette();
+ void kdisplaySetStyle();
+ void kdisplaySetFont();
+ void applyGUIStyle();
+ static void sigpipeHandler(int);
+
+ int captionLayout;
+
+ KApplication(const KApplication&);
+ KApplication& operator=(const KApplication&);
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KApplicationPrivate* d;
+};
+
+
+/**
+ * \relates KGlobal
+ * Check, if a file may be accessed in a given mode.
+ * This is a wrapper around the access() system call.
+ * checkAccess() calls access() with the given parameters.
+ * If this is OK, checkAccess() returns true. If not, and W_OK
+ * is part of mode, it is checked if there is write access to
+ * the directory. If yes, checkAccess() returns true.
+ * In all other cases checkAccess() returns false.
+ *
+ * Other than access() this function EXPLICITLY ignores non-existant
+ * files if checking for write access.
+ *
+ * @param pathname The full path of the file you want to test
+ * @param mode The access mode, as in the access() system call.
+ * @return Whether the access is allowed, true = Access allowed
+ */
+KDECORE_EXPORT bool checkAccess(const QString& pathname, int mode);
+
+class KSessionManagedPrivate;
+
+/**
+ Provides highlevel access to session management on a per-object
+ base.
+
+ KSessionManaged makes it possible to provide implementations for
+ QApplication::commitData() and QApplication::saveState(), without
+ subclassing KApplication. KMainWindow internally makes use of this.
+
+ You don't need to do anything with this class when using
+ KMainWindow. Instead, use KMainWindow::saveProperties(),
+ KMainWindow::readProperties(), KMainWindow::queryClose(),
+ KMainWindow::queryExit() and friends.
+
+ @short Highlevel access to session management.
+ @author Matthias Ettrich <ettrich@kde.org>
+ */
+class KDECORE_EXPORT KSessionManaged
+{
+public:
+ KSessionManaged();
+ virtual ~KSessionManaged();
+
+ /**
+ See QApplication::saveState() for documentation.
+
+ This function is just a convenience version to avoid subclassing KApplication.
+
+ Return true to indicate a successful state save or false to
+ indicate a problem and to halt the shutdown process (will
+ implicitly call sm.cancel() ).
+ */
+ virtual bool saveState( QSessionManager& sm );
+ /**
+ See QApplication::commitData() for documentation.
+
+ This function is just a convenience version to avoid subclassing KApplication.
+
+ Return true to indicate a successful commit of data or false to
+ indicate a problem and to halt the shutdown process (will
+ implicitly call sm.cancel() ).
+ */
+ virtual bool commitData( QSessionManager& sm );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KSessionManagedPrivate *d;
+};
+
+
+#endif
+
diff --git a/kdecore/kapplication_win.cpp b/kdecore/kapplication_win.cpp
new file mode 100644
index 000000000..dea2a3df1
--- /dev/null
+++ b/kdecore/kapplication_win.cpp
@@ -0,0 +1,117 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kurl.h>
+
+#include "kcheckaccelerators.h"
+#include "kappdcopiface.h"
+
+#include <qassistantclient.h>
+#include <qdir.h>
+
+#include "windows.h"
+#include "shellapi.h"
+
+/**
+ * MS Windows-related actions for KApplication startup.
+ *
+ * - Use Qt translation which will be usable for QFileDialog
+ * and other Qt-only GUIs. The "qt_<language>.qm" file should be stored
+ * in the same place as .po files for a given language.
+ *
+ * @internal
+*/
+void KApplication_init_windows(bool /*GUIenabled*/)
+{
+ QString qt_transl_file = ::locate( "locale", KGlobal::locale()->language()
+ + "/LC_MESSAGES/qt_" + KGlobal::locale()->language() + ".qm" );
+ QTranslator *qt_transl = new QTranslator();
+ if (qt_transl->load( qt_transl_file, ""))
+ kapp->installTranslator( qt_transl );
+ else
+ delete qt_transl;
+}
+
+//unsafe; create kapplication_p.h instead!
+typedef void* IceIOErrorHandler;
+
+class KApplicationPrivate
+{
+public:
+ KApplicationPrivate();
+ ~KApplicationPrivate();
+
+ bool actionRestrictions : 1;
+ bool guiEnabled : 1;
+ int refCount;
+ IceIOErrorHandler oldIceIOErrorHandler;
+ KCheckAccelerators* checkAccelerators;
+ QString overrideStyle;
+ QString geometry_arg;
+ QCString startup_id;
+ QTimer* app_started_timer;
+ KAppDCOPInterface *m_KAppDCOPInterface;
+ bool session_save;
+ QAssistantClient* qassistantclient;
+};
+
+void KApplication::invokeHelp( const QString& anchor,
+ const QString& _appname, const QCString& startup_id ) const
+{
+ if (!d->qassistantclient) {
+ d->qassistantclient = new QAssistantClient(
+ KStandardDirs::findExe( "assistant" ), 0);
+ QStringList args;
+ args << "-profile";
+ args << QDir::convertSeparators( locate("html", QString(name())+"/"+QString(name())+".adp") );
+ d->qassistantclient->setArguments(args);
+ }
+ d->qassistantclient->openAssistant();
+}
+
+// on win32, for invoking browser we're using win32 API
+// see kapplication_win.cpp
+void KApplication::invokeBrowser( const QString &url, const QCString& startup_id )
+{
+ QCString s = url.latin1();
+ const unsigned short *l = (const unsigned short *)s.data();
+ ShellExecuteA(0, "open", s.data(), 0, 0, SW_NORMAL);
+}
+
+void KApplication::invokeMailer(const QString &to, const QString &cc, const QString &bcc,
+ const QString &subject, const QString &body,
+ const QString & /*messageFile TODO*/, const QStringList &attachURLs,
+ const QCString& startup_id )
+{
+ KURL url("mailto:"+to);
+ url.setQuery("?subject="+subject);
+ url.addQueryItem("cc", cc);
+ url.addQueryItem("bcc", bcc);
+ url.addQueryItem("body", body);
+ for (QStringList::ConstIterator it = attachURLs.constBegin(); it != attachURLs.constEnd(); ++it)
+ url.addQueryItem("attach", KURL::encode_string(*it));
+
+ QCString s = url.url().latin1();
+ const unsigned short *l = (const unsigned short *)s.data();
+ ShellExecuteA(0, "open", s.data(), 0, 0, SW_NORMAL);
+}
+
diff --git a/kdecore/kasyncio.cpp b/kdecore/kasyncio.cpp
new file mode 100644
index 000000000..45f588d9c
--- /dev/null
+++ b/kdecore/kasyncio.cpp
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2001 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#include "kasyncio.h"
+
+void KAsyncIO::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kasyncio.moc"
diff --git a/kdecore/kasyncio.h b/kdecore/kasyncio.h
new file mode 100644
index 000000000..c1c3e9a11
--- /dev/null
+++ b/kdecore/kasyncio.h
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2001 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KASYNCIO_H
+#define KASYNCIO_H
+
+
+#include <qobject.h>
+#include <qiodevice.h>
+#include "kdelibs_export.h"
+
+class KAsyncIOPrivate;
+/**
+ * Asynchronous I/O Support
+ *
+ * This abstract class provides basic functionality for asynchronous I/O
+ * support on top of QIODevice.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ * @short Asynchronous I/O support
+ */
+class KDECORE_EXPORT KAsyncIO: public QObject, public QIODevice
+{
+ Q_OBJECT
+protected:
+ KAsyncIO() // cannot be accessed externally
+ { }
+
+private:
+ KAsyncIO(KAsyncIO&);
+
+ KAsyncIO& operator=(KAsyncIO&);
+
+public:
+ /**
+ * Toggles the emission of the readyRead() signal whenever the device
+ * is ready for reading. This is useful if you want to know the first time
+ * the device is ready for reading and you don't want to read it now.
+ * @param enable true to enable, false to disable the readyRead() signal
+ */
+ virtual void enableRead(bool enable) = 0;
+
+ /**
+ * Toggles the emission of the readyWrite() signal whenever the device
+ * is ready for writing. This is useful if you want to know the first time
+ * the device is ready for writing and you don't want to write to it now.
+ * @param enable true to enable, false to disable the readyWrite() signal
+ */
+ virtual void enableWrite(bool enable) = 0;
+
+signals:
+
+ /**
+ * This signal gets sent when the device is ready for reading.
+ */
+ void readyRead();
+
+ /**
+ * This signal gets sent when the device is ready for writing.
+ */
+ void readyWrite();
+protected:
+ /** \internal */
+ virtual void virtual_hook( int id, void* data );
+private:
+ KAsyncIOPrivate* d;
+};
+
+#endif // KASYNCIO_H
diff --git a/kdecore/kaudioplayer.cpp b/kdecore/kaudioplayer.cpp
new file mode 100644
index 000000000..c14b7334b
--- /dev/null
+++ b/kdecore/kaudioplayer.cpp
@@ -0,0 +1,56 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#include "kaudioplayer.h"
+#include "knotifyclient.h"
+
+class KAudioPlayerPrivate {
+public:
+ QString filename;
+
+ KAudioPlayerPrivate(const QString &filename) : filename(filename) { }
+};
+
+KAudioPlayer::KAudioPlayer( const QString& filename,
+ QObject* parent, const char* name ) : QObject(parent,name)
+{
+ d = new KAudioPlayerPrivate(filename);
+}
+
+KAudioPlayer::~KAudioPlayer()
+{
+ delete d;
+}
+
+void KAudioPlayer::play(const QString &filename)
+{
+ KAudioPlayer ap(filename);
+ ap.play();
+}
+
+void KAudioPlayer::play()
+{
+ KNotifyClient::userEvent("KAudioPlayer event",
+ KNotifyClient::Sound,KNotifyClient::Notification,d->filename);
+}
+
+#include "kaudioplayer.moc"
diff --git a/kdecore/kaudioplayer.h b/kdecore/kaudioplayer.h
new file mode 100644
index 000000000..bf77aeb59
--- /dev/null
+++ b/kdecore/kaudioplayer.h
@@ -0,0 +1,93 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#ifndef __KAUDIOPLAYER_H__
+#define __KAUDIOPLAYER_H__
+
+#include <qobject.h>
+#include "kdelibs_export.h"
+
+class KAudioPlayerPrivate;
+/**
+ * This class provides one-shot-and-forget audio playing. You will never
+ * know if what you wanted to play really got played.
+ *
+ * It doesn't require linking any special libraries, as it operates over
+ * DCOP. In the current implementation, it only indirectly communicates
+ * with the aRts soundserver, using knotify as DCOP -> MCOP bridge.
+ *
+ * Due to that fact, if you need "fast" response times, more control or
+ * feedback, use the MCOP interfaces rather than this.
+ *
+ * An example of using this class is:
+ *
+ * \code
+ * KAudioPlayer::play("/var/share/foo.wav");
+ * \endcode
+ *
+ * If you want to use signals & slots, you can do something like:
+ *
+ * \code
+ * KAudioPlayer player("/var/share/foo.wav");
+ * connect(&button, SIGNAL(clicked()), &player, SLOT(play()));
+ * \endcode
+ *
+ */
+//REVISED: hausmann
+class KDECORE_EXPORT KAudioPlayer : public QObject {
+Q_OBJECT
+public:
+ /**
+ * Constructor.
+ *
+ * @param filename Absolute path to the filename of the sound file to play
+ * @param parent A parent QObject for this KAudioPlayer
+ * @param name An internal name for this KAudioPlayer
+ */
+ KAudioPlayer( const QString& filename,
+ QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * Destructor.
+ */
+ ~KAudioPlayer();
+
+ /**
+ * Static play function.
+ *
+ * @param filename Absolute path to the filename of the sound file to play.
+ * if not absolute, goes off KDEDIR/share/sounds/ (preferred)
+ */
+ static void play(const QString &filename);
+
+public slots:
+ /**
+ * Play function as slot.
+ *
+ * Plays the soundfile given to the constructor.
+ */
+ void play();
+private:
+ KAudioPlayerPrivate *d;
+};
+
+#endif // __KAUDIOPLAYER_H__
diff --git a/kdecore/kbufferedio.cpp b/kdecore/kbufferedio.cpp
new file mode 100644
index 000000000..1c46e4f05
--- /dev/null
+++ b/kdecore/kbufferedio.cpp
@@ -0,0 +1,299 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2001 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <qptrlist.h>
+#include <qcstring.h>
+#include "kbufferedio.h"
+
+/**
+ * @section impldetails Implementation Details
+ *
+ * The KBufferedIO class has two purposes: first, it defines an API on how
+ * that classes providing buffered I/O should provide. Next, it implements on
+ * top of that API a generic buffering, that should suffice for most cases.
+ *
+ * The buffering implemented consists of two separate buffer areas, one for
+ * the input (or read) buffer, and one for the output (or write) buffer. Each
+ * of those buffers is implemented through a QList of QByteArrays instead of
+ * simply QByteArrays. The idea is that, instead of having one large, contiguous
+ * buffer area, we have several small ones. Even though this could be seen as
+ * a waste of memory, it makes our life easier, because we can just append a new
+ * QByteArray to the list and not have to worry with copying the rest of the
+ * buffer, should we need to expand.
+ *
+ * This way, we have the capability of unlimited buffering, which can grow to
+ * the extent of available memory.
+ *
+ * For each buffer, we provide three kinds of functions, available as protected
+ * members: consume, feed and size. The size functions calculate the current
+ * size of the buffer, by adding each individual QByteArray size. The feed
+ * functions are used by the I/O functions that receive data from somewhere,
+ * i.e., from the system, in the case of the input buffer, and from the user,
+ * in the case of the output buffer. These two functions are used to give
+ * the buffers more data. And the consume functions are used by the functions
+ * that send out data (to the system, for the write buffer, and to the user,
+ * for the read buffer).
+ *
+ * Note that for your own implementation, you can have your readBlock function
+ * merely call consumeReadBuffer, similarly to peekBlock. As for
+ * the writeBlock function, you'd call feedWriteBuffer.
+ *
+ * Now, the function receiving data from the system will need to simply call
+ * feedReadBuffer, much in the same way of unreadBlock. The tricky part is
+ * for the output function. We do not provide a member function that copies
+ * data from the output buffer into another buffer for sending. We believe that
+ * would be a waste of resources and CPU time, since you'd have to allocate
+ * that buffer, copy data into it and then call the OS, which will likely just
+ * copy data out of it.
+ *
+ * Instead, we found it better to leave it to you to access outBuf member
+ * variable directly and use the buffers there. Should you want to copy that
+ * into a larger buffer before sending, that's up to you.
+ *
+ * Both buffers work in the same way: they're an "array" of buffers, each
+ * concatenated to the other. All data in all buffers is valid data, except
+ * for the first QByteArray, whose valid data starts at inBufIndex/outBufIndex
+ * bytes from the start. That is, the data starts in the first QByteArray buffer
+ * that many bytes from the start and goes on contiguously until the last
+ * QByteArray. This has been decided like that because we didn't want to
+ * create a new QByteArray of the remaining bytes in the first buffer, after
+ * a consume operation, because that could take some time. It is faster
+ * this way, although not really easy.
+ *
+ * If you want to take a look at an implementation of a buffered I/O class,
+ * refer to KExtendedSocket's source code.
+ */
+
+// constructor
+KBufferedIO::KBufferedIO() :
+ inBufIndex(0), outBufIndex(0)
+{
+ inBuf.setAutoDelete(true);
+ outBuf.setAutoDelete(true);
+}
+
+// destructor
+KBufferedIO::~KBufferedIO()
+{
+}
+
+// sets the buffer sizes
+// this implementation doesn't support setting the buffer sizes
+// if any parameter is different than -1 or -2, fail
+bool KBufferedIO::setBufferSize(int rsize, int wsize /* = -2 */)
+{
+ if (wsize != -2 && wsize != -1)
+ return false;
+ if (rsize != -2 && rsize != -1)
+ return false;
+
+ return true;
+}
+
+int KBufferedIO::bytesAvailable() const
+{
+ return readBufferSize();
+}
+
+int KBufferedIO::bytesToWrite() const
+{
+ return writeBufferSize();
+}
+
+// This function will scan the read buffer for a '\n'
+bool KBufferedIO::canReadLine() const
+{
+ if (bytesAvailable() == 0)
+ return false; // no new line in here
+
+ QByteArray* buf;
+
+ // scan each QByteArray for the occurrence of '\n'
+ QPtrList<QByteArray> &buflist = ((KBufferedIO*)this)->inBuf;
+ buf = buflist.first();
+ char *p = buf->data() + inBufIndex;
+ int n = buf->size() - inBufIndex;
+ while (buf != NULL)
+ {
+ while (n--)
+ if (*p++ == '\n')
+ return true;
+ buf = buflist.next();
+ if (buf != NULL)
+ {
+ p = buf->data();
+ n = buf->size();
+ }
+ }
+
+ return false; // no new line found
+}
+
+// unreads the current data
+// that is, writes into the read buffer, at the beginning
+int KBufferedIO::unreadBlock(const char *data, uint len)
+{
+ return feedReadBuffer(len, data, true);
+}
+
+//
+// protected member functions
+//
+
+unsigned KBufferedIO::consumeReadBuffer(unsigned nbytes, char *destbuffer, bool discard)
+{
+ {
+ register unsigned u = readBufferSize();
+ if (nbytes > u)
+ nbytes = u; // we can't consume more than there is
+ }
+
+ QByteArray *buf;
+ unsigned copied = 0;
+ unsigned index = inBufIndex;
+
+ buf = inBuf.first();
+ while (nbytes && buf)
+ {
+ // should we copy it all?
+ unsigned to_copy = buf->size() - index;
+ if (to_copy > nbytes)
+ to_copy = nbytes;
+
+ if (destbuffer)
+ memcpy(destbuffer + copied, buf->data() + index, to_copy);
+ nbytes -= to_copy;
+ copied += to_copy;
+
+ if (buf->size() - index > to_copy)
+ {
+ index += to_copy;
+ break; // we aren't copying everything, that means that's
+ // all the user wants
+ }
+ else
+ {
+ index = 0;
+ if (discard)
+ {
+ inBuf.remove();
+ buf = inBuf.first();
+ }
+ else
+ buf = inBuf.next();
+ }
+ }
+
+ if (discard)
+ inBufIndex = index;
+
+ return copied;
+}
+
+void KBufferedIO::consumeWriteBuffer(unsigned nbytes)
+{
+ QByteArray *buf = outBuf.first();
+ if (buf == NULL)
+ return; // nothing to consume
+
+ if (nbytes < buf->size() - outBufIndex)
+ // we want to consume less than there is in the first buffer
+ outBufIndex += nbytes;
+ else
+ {
+ nbytes -= buf->size() - outBufIndex;
+ outBufIndex = 0;
+ outBuf.remove();
+
+ while ((buf = outBuf.current()) != NULL)
+ if (buf->size() <= nbytes)
+ {
+ nbytes -= buf->size();
+ outBuf.remove();
+ }
+ else
+ {
+ outBufIndex = nbytes;
+ break;
+ }
+ }
+}
+
+unsigned KBufferedIO::feedReadBuffer(unsigned nbytes, const char *buffer, bool atBeginning)
+{
+ if (nbytes == 0)
+ return 0;
+
+ QByteArray *a = new QByteArray(nbytes);
+ a->duplicate(buffer, nbytes);
+
+ if (atBeginning)
+ inBuf.prepend(a);
+ else
+ inBuf.append(a);
+
+ return nbytes;
+}
+
+unsigned KBufferedIO::feedWriteBuffer(unsigned nbytes, const char *buffer)
+{
+ if (nbytes == 0)
+ return 0;
+
+ QByteArray *a = new QByteArray(nbytes);
+ a->duplicate(buffer, nbytes);
+ outBuf.append(a);
+ return nbytes;
+}
+
+unsigned KBufferedIO::readBufferSize() const
+{
+ unsigned count = 0;
+ QByteArray *buf = ((KBufferedIO*)this)->inBuf.first();
+ while (buf != NULL)
+ {
+ count += buf->size();
+ buf = ((KBufferedIO*)this)->inBuf.next();
+ }
+
+ return count - inBufIndex;
+}
+
+unsigned KBufferedIO::writeBufferSize() const
+{
+ unsigned count = 0;
+ QByteArray *buf = ((KBufferedIO*)this)->outBuf.first();
+ while (buf != NULL)
+ {
+ count += buf->size();
+ buf = (const_cast<KBufferedIO*>(this))->outBuf.next();
+ }
+
+ return count - outBufIndex;
+}
+
+void KBufferedIO::virtual_hook( int id, void* data )
+{ KAsyncIO::virtual_hook( id, data ); }
+
+#include "kbufferedio.moc"
diff --git a/kdecore/kbufferedio.h b/kdecore/kbufferedio.h
new file mode 100644
index 000000000..47579738d
--- /dev/null
+++ b/kdecore/kbufferedio.h
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2001 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KBUFFEREDIO_H
+#define KBUFFEREDIO_H
+
+#include <qcstring.h>
+#include <qptrlist.h>
+#include "kasyncio.h"
+
+class KBufferedIOPrivate;
+/**
+ * This abstract class implements basic functionality for buffered
+ * input/output.
+ *
+ * Through the available methods, you can find out how many bytes are
+ * available for reading, how many are still unsent and you can peek at
+ * the buffered data.
+ *
+ * This class was intentionally written to resemble QSocket, because
+ * KExtendedSocket is a subclass of this one. This is so that applications
+ * written using QSocket's buffering characteristics will be more easily
+ * ported to the more powerful KExtendedSocket class.
+ *
+ * KBufferedIO already provides a powerful internal buffering algorithm. However,
+ * this does not include the I/O itself, which must be implemented in
+ * derived classes. Thus, to implement a class that does some I/O, you must
+ * override, in addition to the pure virtual QIODevice methods, these two:
+ * @li closeNow()
+ * @li waitForMore()
+ *
+ * If your derived class reimplements the buffering algorithm, you must then
+ * decide which buffering functions to override. For instance, you may want to
+ * change the protected functions like feedReadBuffer() and consumeReadBuffer().
+ *
+ * @author Thiago Macieira <thiagom@mail.com>
+ * @short Buffered I/O
+ */
+class KDECORE_EXPORT KBufferedIO: public KAsyncIO
+{
+ Q_OBJECT
+
+protected:
+ // no default public constructor
+ KBufferedIO();
+
+public:
+ /**
+ * The modes for closed() signal
+ */
+ enum closeModes
+ {
+ availRead = 0x01,
+ dirtyWrite = 0x02,
+ involuntary = 0x10,
+ delayed = 0x20,
+ closedNow = 0x40
+ };
+
+ /**
+ * Destroys this class. The flushing of the buffers is implementation dependant.
+ * The default implementation discards the contents
+ */
+ virtual ~KBufferedIO();
+
+ /**
+ * Closes the stream now, discarding the contents of the
+ * write buffer. That is, we won't try to flush that
+ * buffer before closing. If you want that buffer to be
+ * flushed, you can call QIODevice::flush(), which is blocking, and
+ * then closeNow, or you can call QIODevice::close() for a delayed
+ * close.
+ */
+ virtual void closeNow() = 0;
+
+ /**
+ * Sets the internal buffer size to value.
+ *
+ * Not all implementations support this.
+ *
+ * The parameters may be 0 to make the class unbuffered or -1
+ * to let the class choose the size (which may be unlimited) or
+ * -2 to leave the buffer size untouched.
+ *
+ * Note that setting the write buffer size to any value smaller than
+ * the current size of the buffer will force it to flush first,
+ * which can make this call blocking.
+ *
+ * The default implementation does not support setting the buffer
+ * sizes. You can only call this function with values -1 for "don't care"
+ * or -2 for "unchanged"
+ * @param rsize the size of the read buffer
+ * @param wsize the size of the write buffer
+ * @return true if setting both was ok. If false is returned, the
+ * buffers were left unchanged.
+ */
+ virtual bool setBufferSize(int rsize, int wsize = -2);
+
+ /**
+ * Returns the number of bytes available for reading in the read buffer
+ * @return the number of bytes available for reading
+ */
+ virtual int bytesAvailable() const;
+
+ /**
+ * Waits for more data to be available and returns the amount of available data then.
+ *
+ * @param msec number of milliseconds to wait, -1 to wait forever
+ * @return -1 if we cannot wait (e.g., that doesn't make sense in this stream)
+ */
+ virtual int waitForMore(int msec) = 0;
+
+ /**
+ * Returns the number of bytes yet to write, still in the write buffer
+ * @return the number of unwritten bytes in the write buffer
+ */
+ virtual int bytesToWrite() const;
+
+ /**
+ * Checks whether there is enough data in the buffer to read a line
+ *
+ * The default implementation reads directly from inBuf, so if your
+ * implementation changes the meaning of that member, then you must override
+ * this function.
+ * @return true when there is enough data in the buffer to read a line
+ */
+ virtual bool canReadLine() const;
+
+ // readBlock, peekBlock and writeBlock are not defined in this class (thus, left
+ // pure virtual) because this does not mean only reading and writing
+ // to the buffers. It may be necessary to do I/O to complete the
+ // transaction (e.g., user wants to read more than is in the buffer).
+ // Reading and writing to the buffer are available for access through
+ // protected member functions
+
+ /**
+ * Reads into the user buffer at most maxlen bytes, but does not
+ * consume that data from the read buffer. This is useful to check
+ * whether we already have the needed data to process something.
+ *
+ * This function may want to try and read more data from the system
+ * provided it won't block.
+ *
+ * @param data the user buffer pointer, at least maxlen bytes long
+ * @param maxlen the maximum length to be peeked
+ * @return the number of bytes actually copied.
+ */
+ virtual int peekBlock(char *data, uint maxlen) = 0;
+
+ /**
+ * Unreads some data. That is, write the data to the beginning of the
+ * read buffer, so that next calls to readBlock or peekBlock will see
+ * this data instead.
+ *
+ * Note not all devices implement this since this could mean a semantic
+ * problem. For instance, sockets are sequential devices, so they won't
+ * accept unreading.
+ * @param data the data to be unread
+ * @param len the size of the data
+ * @return the number of bytes actually unread
+ */
+ virtual int unreadBlock(const char *data, uint len);
+
+signals:
+ /**
+ * This signal gets sent whenever bytes are written from the buffer.
+ * @param nbytes the number of bytes sent.
+ */
+ void bytesWritten(int nbytes);
+
+ // There is no read signal here. We use the readyRead signal inherited
+ // from KAsyncIO for that purpose
+
+ /**
+ * This signal gets sent when the stream is closed. The @p state parameter
+ * will give the current state, in OR-ed bits:
+ * @li availRead: read buffer contains data to be read
+ * @li dirtyWrite: write buffer wasn't empty when the stream closed
+ * @li involuntary: the stream wasn't closed due to user request
+ * (i.e., call to close). Probably remote end closed it
+ * @li delayed: the stream was closed voluntarily by the user, but it
+ * happened only after the write buffer was emptied
+ * @li closedNow: the stream was closed voluntarily by the user, by
+ * explicitly calling closeNow, which means the
+ * write buffer's contents may have been discarded
+ * @param state the state (see function description)
+ */
+ void closed(int state);
+
+protected:
+ /**
+ * For an explanation on how this buffer work, please refer to the comments
+ * at the top of kbufferedio.cpp, @ref impldetails .
+ */
+ QPtrList<QByteArray> inBuf;
+
+ /**
+ * For an explanation on how this buffer work, please refer to the comments
+ * at the top of kbufferedio.cpp, @ref impldetails .
+ */
+ QPtrList<QByteArray> outBuf;
+
+ unsigned inBufIndex /** Offset into first input buffer. */,
+ outBufIndex /** Offset into first output buffer. */ ;
+
+ /**
+ * Consumes data from the input buffer.
+ * That is, this will copy the data stored in the input (read) buffer
+ * into the given @p destbuffer, as much as @p nbytes.
+ * @param nbytes the maximum amount of bytes to copy into the buffer
+ * @param destbuffer the destination buffer into which to copy the data
+ * @param discard whether to discard the copied data after the operation
+ * @return the real amount of data copied. If it is less than
+ * nbytes, then all the buffer was copied.
+ */
+ virtual unsigned consumeReadBuffer(unsigned nbytes, char *destbuffer, bool discard = true);
+
+ /**
+ * Consumes data from the output buffer.
+ * Since this is called whenever we managed to send data out the wire, we
+ * can only discard this amount from the buffer. There is no copying and no
+ * "peeking" for the output buffer.
+ *
+ * Note this function should be called AFTER the data was sent. After it
+ * is called, the data is no longer available in the buffer. And don't pass
+ * wrong nbytes values.
+ * @param nbytes the amount of bytes to discard
+ */
+ virtual void consumeWriteBuffer(unsigned nbytes);
+
+ /**
+ * Feeds data into the input buffer.
+ * This happens when we detected available data in the device and read it.
+
+ * The data will be appended to the buffer or inserted at the beginning,
+ * depending on whether @p atBeginning is set or not.
+ * @param nbytes the number of bytes in the buffer
+ * @param buffer the data that was read
+ * @param atBeginning whether to append or insert at the beginning
+ * @return the number of bytes that have been appended
+ */
+ virtual unsigned feedReadBuffer(unsigned nbytes, const char *buffer, bool atBeginning = false);
+
+ /**
+ * Feeds data into the output buffer.
+ * This happens when the user told us to write some data.
+ * The data will be appended to the buffer.
+ * @param nbytes the number of bytes in the buffer
+ * @param buffer the data that is to be written
+ * @return the number of bytes that have been appended
+ */
+ virtual unsigned feedWriteBuffer(unsigned nbytes, const char *buffer);
+
+ /**
+ * Returns the number of bytes in the read buffer
+ * @return the size of the read buffer in bytes
+ */
+ virtual unsigned readBufferSize() const;
+
+ /**
+ * Returns the number of bytes in the write buffer
+ * @return the size of the write buffer in bytes
+ */
+ virtual unsigned writeBufferSize() const;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KBufferedIOPrivate *d;
+};
+
+#endif // KBUFFEREDIO_H
diff --git a/kdecore/kcalendarsystem.cpp b/kdecore/kcalendarsystem.cpp
new file mode 100644
index 000000000..150dbda1b
--- /dev/null
+++ b/kdecore/kcalendarsystem.cpp
@@ -0,0 +1,146 @@
+/*
+ Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Gregorian calendar system implementation factory for creation of kde calendar
+// systems.
+// Also default gregorian and factory classes
+
+#include <kglobal.h>
+
+#include "kcalendarsystem.h"
+#include "klocale.h"
+
+class KCalendarSystemPrivate
+{
+public:
+ const KLocale * locale;
+};
+
+KCalendarSystem::KCalendarSystem(const KLocale * locale)
+ : d(new KCalendarSystemPrivate)
+{
+ d->locale = locale;
+}
+
+KCalendarSystem::~KCalendarSystem()
+{
+ delete d;
+}
+
+const KLocale * KCalendarSystem::locale() const
+{
+ if ( d->locale )
+ return d->locale;
+
+ return KGlobal::locale();
+}
+
+QString KCalendarSystem::dayString(const QDate & pDate, bool bShort) const
+{
+ QString sResult;
+
+ sResult.setNum(day(pDate));
+ if (!bShort && sResult.length() == 1 )
+ sResult.prepend('0');
+
+ return sResult;
+}
+
+QString KCalendarSystem::monthString(const QDate & pDate, bool bShort) const
+{
+ QString sResult;
+
+ sResult.setNum(month(pDate));
+ if (!bShort && sResult.length() == 1 )
+ sResult.prepend('0');
+
+ return sResult;
+}
+
+QString KCalendarSystem::yearString(const QDate & pDate, bool bShort) const
+{
+ QString sResult;
+
+ sResult.setNum(year(pDate));
+ if (bShort && sResult.length() == 4 )
+ sResult = sResult.right(2);
+
+ return sResult;
+}
+
+static int stringToInteger(const QString & sNum, int & iLength)
+{
+ unsigned int iPos = 0;
+
+ int result = 0;
+ for (; sNum.length() > iPos && sNum.at(iPos).isDigit(); iPos++)
+ {
+ result *= 10;
+ result += sNum.at(iPos).digitValue();
+ }
+
+ iLength = iPos;
+ return result;
+}
+
+
+int KCalendarSystem::dayStringToInteger(const QString & sNum, int & iLength) const
+{
+ return stringToInteger(sNum, iLength);
+}
+
+int KCalendarSystem::monthStringToInteger(const QString & sNum, int & iLength) const
+{
+ return stringToInteger(sNum, iLength);
+}
+
+int KCalendarSystem::yearStringToInteger(const QString & sNum, int & iLength) const
+{
+ return stringToInteger(sNum, iLength);
+}
+
+QString KCalendarSystem::weekDayName (int weekDay, bool shortName) const
+{
+ if ( shortName )
+ switch ( weekDay )
+ {
+ case 1: return locale()->translate("Monday", "Mon");
+ case 2: return locale()->translate("Tuesday", "Tue");
+ case 3: return locale()->translate("Wednesday", "Wed");
+ case 4: return locale()->translate("Thursday", "Thu");
+ case 5: return locale()->translate("Friday", "Fri");
+ case 6: return locale()->translate("Saturday", "Sat");
+ case 7: return locale()->translate("Sunday", "Sun");
+ }
+ else
+ switch ( weekDay )
+ {
+ case 1: return locale()->translate("Monday");
+ case 2: return locale()->translate("Tuesday");
+ case 3: return locale()->translate("Wednesday");
+ case 4: return locale()->translate("Thursday");
+ case 5: return locale()->translate("Friday");
+ case 6: return locale()->translate("Saturday");
+ case 7: return locale()->translate("Sunday");
+ }
+
+ return QString::null;
+}
+
diff --git a/kdecore/kcalendarsystem.h b/kdecore/kcalendarsystem.h
new file mode 100644
index 000000000..a2740492e
--- /dev/null
+++ b/kdecore/kcalendarsystem.h
@@ -0,0 +1,357 @@
+/*
+ Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002-2003 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCALENDARSYSTEM_H
+#define KCALENDARSYSTEM_H
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+class KLocale;
+
+class KCalendarSystemPrivate;
+
+/**
+ * CalendarSystem abstract class, default derived kde gregorian class and
+ * factory class. Provides support for different calendar types for kde
+ * calendar widget and related stuff.
+ *
+ * Derived classes must be created through KCalendarFactory class
+ *
+ * @author Carlos Moro <cfmoro@correo.uniovi.es>
+ * @since 3.2
+ */
+class KDECORE_EXPORT KCalendarSystem
+{
+public:
+ /**
+ * Constructor of abstract calendar class. This will be called by the derived classes.
+ *
+ * @param locale It will use this locale for translations, 0 means global.
+ */
+ KCalendarSystem(const KLocale * locale = 0);
+
+ /**
+ * Descructor.
+ */
+ virtual ~KCalendarSystem();
+
+ /**
+ * Gets specific calendar type year for a given gregorian date
+ *
+ * @param date gregorian date
+ * @return year
+ */
+ virtual int year (const QDate & date) const = 0;
+
+ /**
+ * Converts a date into a year literal
+ *
+ * @param pDate The date to convert
+ * @param bShort If the short version of should be used
+ * @return The year literal of the date
+ */
+ virtual QString yearString(const QDate & pDate, bool bShort) const;
+
+ /**
+ * Converts a year literal of a part of a string into a integer starting at the beginning of the string
+ *
+ * @param sNum The string to parse
+ * @param iLength The number of QChars used, and 0 if no valid symbols was found in the string
+ * @return An integer corresponding to the year
+ */
+ virtual int yearStringToInteger(const QString & sNum, int & iLength) const;
+
+ /**
+ * Gets specific calendar type month for a given gregorian date
+ *
+ * @param date gregorian date
+ * @return month number
+ */
+ virtual int month (const QDate & date) const = 0;
+
+ /**
+ * Converts a date into a month literal
+ *
+ * @param pDate The date to convert
+ * @param bShort If the short version of should be used
+ * @return The month literal of the date
+ */
+ virtual QString monthString(const QDate & pDate, bool bShort) const;
+
+ /**
+ * Converts a month literal of a part of a string into a integer starting at the beginning of the string
+ *
+ * @param sNum The string to parse
+ * @param iLength The number of QChars used, and 0 if no valid symbols was found in the string
+ * @return An integer corresponding to the month
+ */
+ virtual int monthStringToInteger(const QString & sNum, int & iLength) const;
+
+ /**
+ * Gets specific calendar type day number of month for a given date
+ *
+ * @param date gregorian date equivalent to the specific one
+ * @return day of the month
+ */
+ virtual int day (const QDate & date) const = 0;
+
+ /**
+ * Converts a date into a day literal
+ *
+ * @param pDate The date to convert
+ * @param bShort If the short version of should be used
+ * @return The day literal of the date
+ */
+ virtual QString dayString(const QDate & pDate, bool bShort) const;
+
+ /**
+ * Converts a day literal of a part of a string into a integer starting at the beginning of the string
+ *
+ * @param sNum The string to parse
+ * @param iLength The number of QChars used, and 0 if no valid symbols was found in the string
+ * @return An integer corresponding to the day
+ */
+ virtual int dayStringToInteger(const QString & sNum, int & iLength) const;
+
+ /**
+ * Gets specific calendar type number of day of week number for a given
+ * date
+ *
+ * @param date gregorian date
+ * @return day of week
+ */
+ virtual int dayOfWeek (const QDate & date) const = 0;
+
+ /**
+ * Gets specific calendar type day number of year for a given date
+ *
+ * @param date gregorian date equivalent to the specific one
+ * @return day number
+ */
+ virtual int dayOfYear (const QDate & date) const = 0;
+
+ /**
+ * Changes the date's year, month and day. The range of the year, month
+ * and day depends on which calendar is being used.
+ *
+ * @param date Date to change
+ * @param y Year
+ * @param m Month number
+ * @param d Day of month
+ * @return true if the date is valid; otherwise returns false.
+ */
+ virtual bool setYMD(QDate & date, int y, int m, int d) const = 0;
+
+ /**
+ * Returns a QDate object containing a date nyears later.
+ *
+ * @param date The old date
+ * @param nyears The number of years to add
+ * @return The new date
+ */
+ virtual QDate addYears(const QDate & date, int nyears) const = 0;
+
+ /**
+ * Returns a QDate object containing a date nmonths later.
+ *
+ * @param date The old date
+ * @param nmonths The number of months to add
+ * @return The new date
+ */
+ virtual QDate addMonths(const QDate & date, int nmonths) const = 0;
+
+ /**
+ * Returns a QDate object containing a date ndays later.
+ *
+ * @param date The old date
+ * @param ndays The number of days to add
+ * @return The new date
+ */
+ virtual QDate addDays(const QDate & date, int ndays) const = 0;
+
+ /**
+ * Gets specific calendar type number of month for a given year
+ *
+ * @param date The date whose year to use
+ * @return The number of months in that year
+ */
+ virtual int monthsInYear (const QDate & date) const = 0;
+
+ /**
+ * Gets the number of days in date whose years specified.
+ *
+ * @param date Gregorian date equivalent to the specific one
+ * @return The number of days in year
+ */
+ virtual int daysInYear (const QDate & date) const = 0;
+
+ /**
+ * Gets specific calendar type number of days in month for a given date
+ *
+ * @param date gregorian date
+ * @return number of days for month in date
+ */
+ virtual int daysInMonth (const QDate & date) const = 0;
+
+ /**
+ * Gets the number of weeks in a specified year
+ *
+ * @param year the year
+ * @return number of weeks in year
+ */
+ virtual int weeksInYear(int year) const = 0;
+
+ /**
+ * Gets specific calendar type week number for a given date
+ *
+ * @param date gregorian date
+ * @param yearNum The year the date belongs to
+ * @return week number
+ */
+ virtual int weekNumber(const QDate& date, int * yearNum = 0) const = 0;
+
+ /**
+ * Gets specific calendar type month name for a given month number
+ * If an invalid month is specified, QString::null is returned.
+ *
+ * @param month The month number
+ * @param year The year the month belongs to
+ * @param shortName Specifies if the short month name should be used
+ * @return The name of the month
+ */
+ virtual QString monthName (int month, int year, bool shortName = false) const = 0;
+
+ /**
+ * Gets specific calendar type month name for a given gregorian date
+ *
+ * @param date Gregorian date
+ * @param shortName Specifies if the short month name should be used
+ * @return The name of the month
+ */
+ virtual QString monthName (const QDate & date, bool shortName = false ) const = 0;
+
+ /**
+ * Returns a string containing the possessive form of the month name.
+ * ("of January", "of February", etc.)
+ * It's needed in long format dates in some languages.
+ * If an invalid month is specified, QString::null is returned.
+ *
+ * @param month The month number
+ * @param year The year the month belongs to
+ * @param shortName Specifies if the short month name should be used
+ *
+ * @return The possessive form of the name of the month
+ */
+ virtual QString monthNamePossessive(int month, int year, bool shortName = false) const = 0;
+
+ /**
+ * Returns a string containing the possessive form of the month name.
+ * ("of January", "of February", etc.)
+ * It's needed in long format dates in some languages.
+ *
+ * @param date Gregorian date
+ * @param shortName Specifies if the short month name should be used
+ *
+ * @return The possessive form of the name of the month
+ */
+ virtual QString monthNamePossessive(const QDate & date, bool shortName = false) const = 0;
+
+ /**
+ * Gets specific calendar type week day name
+ * If an invalid week day is specified, QString::null is returned.
+ *
+ * @param weekDay number of day in week (1 -> Monday)
+ * @param shortName short or complete day name
+ * @return day name
+ */
+ virtual QString weekDayName (int weekDay, bool shortName = false) const = 0;
+
+ /**
+ * Gets specific calendar type week day name
+ *
+ * @param date the date
+ * @param shortName short or complete day name
+ * @return day name
+ */
+ virtual QString weekDayName (const QDate & date, bool shortName = false) const = 0;
+
+ /**
+ * Gets the first year value supported by specific calendar type
+ * algorithms.
+ *
+ * @return first year supported
+ */
+ virtual int minValidYear () const = 0;
+
+ /**
+ * Gets the maximum year value supported by specific calendar type
+ * algorithms (QDate, 8000)
+ *
+ * @return maximum year supported
+ */
+ virtual int maxValidYear () const = 0;
+
+ /**
+ * Gets the day of the week traditionaly associated with pray
+ *
+ * @return day number
+ */
+ virtual int weekDayOfPray () const = 0;
+
+ /**
+ * Gets the string representing the calendar
+ */
+ virtual QString calendarName() const = 0;
+
+ /**
+ * Gets if the calendar is lunar based
+ *
+ * @return if the calendar is lunar based
+ */
+ virtual bool isLunar() const = 0;
+
+ /**
+ * Gets if the calendar is lunisolar based
+ *
+ * @return if the calendar is lunisolar based
+ */
+ virtual bool isLunisolar() const = 0;
+
+ /**
+ * Gets if the calendar is solar based
+ *
+ * @return if the calendar is solar based
+ */
+ virtual bool isSolar() const = 0;
+
+protected:
+ /**
+ * Gets the locale the calendar uses for translations. Set in
+ * the constructor.
+ */
+ const KLocale * locale() const;
+
+private:
+ KCalendarSystemPrivate * d;
+};
+
+#endif
diff --git a/kdecore/kcalendarsystemfactory.cpp b/kdecore/kcalendarsystemfactory.cpp
new file mode 100644
index 000000000..28c3a6bfa
--- /dev/null
+++ b/kdecore/kcalendarsystemfactory.cpp
@@ -0,0 +1,70 @@
+/*
+ Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002-2003 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Gregorian calendar system implementation factory for creation of kde
+// calendar systems.
+// Also default gregorian and factory classes
+
+#include <kdebug.h>
+
+#include "kcalendarsystemfactory.h"
+
+#include "kcalendarsystemgregorian.h"
+#include "kcalendarsystemhijri.h"
+#include "kcalendarsystemhebrew.h"
+#include "kcalendarsystemjalali.h"
+
+KCalendarSystemFactory::KCalendarSystemFactory()
+{
+ kdDebug(5400) << "Created factory calendar" << endl;
+}
+
+KCalendarSystemFactory::~KCalendarSystemFactory()
+{
+}
+
+KCalendarSystem *KCalendarSystemFactory::create( const QString &calType,
+ const KLocale * locale )
+{
+ if ( calType == "hebrew" )
+ return new KCalendarSystemHebrew(locale);
+ if ( calType == "hijri" )
+ return new KCalendarSystemHijri(locale);
+ if ( calType == "gregorian" )
+ return new KCalendarSystemGregorian(locale);
+ if ( calType == "jalali" )
+ return new KCalendarSystemJalali(locale);
+
+ kdDebug(5400) << "Calendar " << calType << " not found, defaulting to gregorian" << endl;
+
+ // ### HPB: Should it really be a default here?
+ return new KCalendarSystemGregorian(locale);
+}
+
+QStringList KCalendarSystemFactory::calendarSystems()
+{
+ QStringList lst;
+ lst.append("hebrew");
+ lst.append("hijri");
+ lst.append("gregorian");
+ lst.append("jalali");
+
+ return lst;
+}
diff --git a/kdecore/kcalendarsystemfactory.h b/kdecore/kcalendarsystemfactory.h
new file mode 100644
index 000000000..ea41e156e
--- /dev/null
+++ b/kdecore/kcalendarsystemfactory.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCALENDARSYSTEMFACTORY_H
+#define KCALENDARSYSTEMFACTORY_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include "kdelibs_export.h"
+
+class KCalendarSystem;
+class KLocale;
+
+/**
+ * Factory class for calendar types
+ * @author Carlos Moro <cfmoro@correo.uniovi.es>
+ * @since 3.2
+ */
+class KDECORE_EXPORT KCalendarSystemFactory
+{
+public:
+ KCalendarSystemFactory ();
+ ~KCalendarSystemFactory ();
+
+ /**
+ * Gets specific calendar type number of days in previous month for a
+ * given date
+ *
+ * @param calType string identification of the specific calendar type
+ * to be constructed
+ * @param locale Locale used for translations. Use the global locale when
+ * 0 is specified.
+ * @return a KCalendarSystem object
+ */
+ static KCalendarSystem *create (const QString & calType = QString::fromLatin1("gregorian"),
+ const KLocale * locale = 0);
+
+ /**
+ * Gets list of names of supported calendar systems
+ *
+ * @return A QStringList object
+ */
+ static QStringList calendarSystems();
+
+private:
+};
+
+#endif
diff --git a/kdecore/kcalendarsystemgregorian.cpp b/kdecore/kcalendarsystemgregorian.cpp
new file mode 100644
index 000000000..9df2a70a1
--- /dev/null
+++ b/kdecore/kcalendarsystemgregorian.cpp
@@ -0,0 +1,329 @@
+/*
+ Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002-2003 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Derived gregorian kde calendar class
+// Just a schema.
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kcalendarsystemgregorian.h"
+
+KCalendarSystemGregorian::KCalendarSystemGregorian(const KLocale * locale)
+ : KCalendarSystem(locale)
+{
+}
+
+KCalendarSystemGregorian::~KCalendarSystemGregorian()
+{
+}
+
+int KCalendarSystemGregorian::year(const QDate& date) const
+{
+ return date.year();
+}
+
+int KCalendarSystemGregorian::monthsInYear( const QDate & date ) const
+{
+ Q_UNUSED( date )
+
+ return 12;
+}
+
+int KCalendarSystemGregorian::weeksInYear(int year) const
+{
+ QDate temp;
+ temp.setYMD(year, 12, 31);
+
+ // If the last day of the year is in the first week, we have to check the
+ // week before
+ if ( temp.weekNumber() == 1 )
+ temp = temp.addDays(-7);
+
+ return temp.weekNumber();
+}
+
+int KCalendarSystemGregorian::weekNumber(const QDate& date,
+ int * yearNum) const
+{
+ return date.weekNumber(yearNum);
+}
+
+QString KCalendarSystemGregorian::monthName(const QDate& date,
+ bool shortName) const
+{
+ return monthName(month(date), year(date), shortName);
+}
+
+QString KCalendarSystemGregorian::monthNamePossessive(const QDate& date, bool shortName) const
+{
+ return monthNamePossessive(month(date), year(date), shortName);
+}
+
+QString KCalendarSystemGregorian::monthName(int month, int year, bool shortName) const
+{
+ Q_UNUSED(year);
+
+ if ( shortName )
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("January", "Jan");
+ case 2:
+ return locale()->translate("February", "Feb");
+ case 3:
+ return locale()->translate("March", "Mar");
+ case 4:
+ return locale()->translate("April", "Apr");
+ case 5:
+ return locale()->translate("May short", "May");
+ case 6:
+ return locale()->translate("June", "Jun");
+ case 7:
+ return locale()->translate("July", "Jul");
+ case 8:
+ return locale()->translate("August", "Aug");
+ case 9:
+ return locale()->translate("September", "Sep");
+ case 10:
+ return locale()->translate("October", "Oct");
+ case 11:
+ return locale()->translate("November", "Nov");
+ case 12:
+ return locale()->translate("December", "Dec");
+ }
+ else
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("January");
+ case 2:
+ return locale()->translate("February");
+ case 3:
+ return locale()->translate("March");
+ case 4:
+ return locale()->translate("April");
+ case 5:
+ return locale()->translate("May long", "May");
+ case 6:
+ return locale()->translate("June");
+ case 7:
+ return locale()->translate("July");
+ case 8:
+ return locale()->translate("August");
+ case 9:
+ return locale()->translate("September");
+ case 10:
+ return locale()->translate("October");
+ case 11:
+ return locale()->translate("November");
+ case 12:
+ return locale()->translate("December");
+ }
+
+ return QString::null;
+}
+
+QString KCalendarSystemGregorian::monthNamePossessive(int month, int year,
+ bool shortName) const
+{
+ Q_UNUSED(year);
+
+ if ( shortName )
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("of January", "of Jan");
+ case 2:
+ return locale()->translate("of February", "of Feb");
+ case 3:
+ return locale()->translate("of March", "of Mar");
+ case 4:
+ return locale()->translate("of April", "of Apr");
+ case 5:
+ return locale()->translate("of May short", "of May");
+ case 6:
+ return locale()->translate("of June", "of Jun");
+ case 7:
+ return locale()->translate("of July", "of Jul");
+ case 8:
+ return locale()->translate("of August", "of Aug");
+ case 9:
+ return locale()->translate("of September", "of Sep");
+ case 10:
+ return locale()->translate("of October", "of Oct");
+ case 11:
+ return locale()->translate("of November", "of Nov");
+ case 12:
+ return locale()->translate("of December", "of Dec");
+ }
+ else
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("of January");
+ case 2:
+ return locale()->translate("of February");
+ case 3:
+ return locale()->translate("of March");
+ case 4:
+ return locale()->translate("of April");
+ case 5:
+ return locale()->translate("of May long", "of May");
+ case 6:
+ return locale()->translate("of June");
+ case 7:
+ return locale()->translate("of July");
+ case 8:
+ return locale()->translate("of August");
+ case 9:
+ return locale()->translate("of September");
+ case 10:
+ return locale()->translate("of October");
+ case 11:
+ return locale()->translate("of November");
+ case 12:
+ return locale()->translate("of December");
+ }
+
+ return QString::null;
+}
+
+bool KCalendarSystemGregorian::setYMD(QDate & date, int y, int m, int d) const
+{
+ // We don't want Qt to add 1900 to them
+ if ( y >= 0 && y <= 99 )
+ return false;
+
+ // QDate supports gregorian internally
+ return date.setYMD(y, m, d);
+}
+
+QDate KCalendarSystemGregorian::addYears(const QDate & date, int nyears) const
+{
+ return date.addYears(nyears);
+}
+
+QDate KCalendarSystemGregorian::addMonths(const QDate & date, int nmonths) const
+{
+ return date.addMonths(nmonths);
+}
+
+QDate KCalendarSystemGregorian::addDays(const QDate & date, int ndays) const
+{
+ return date.addDays(ndays);
+}
+
+QString KCalendarSystemGregorian::weekDayName(int col, bool shortName) const
+{
+ // ### Should this really be different to each calendar system? Or are we
+ // only going to support weeks with 7 days?
+
+ return KCalendarSystem::weekDayName(col, shortName);
+}
+
+QString KCalendarSystemGregorian::weekDayName(const QDate& date, bool shortName) const
+{
+ return weekDayName(dayOfWeek(date), shortName);
+}
+
+
+int KCalendarSystemGregorian::dayOfWeek(const QDate& date) const
+{
+ return date.dayOfWeek();
+}
+
+int KCalendarSystemGregorian::dayOfYear(const QDate & date) const
+{
+ return date.dayOfYear();
+}
+
+int KCalendarSystemGregorian::daysInMonth(const QDate& date) const
+{
+ return date.daysInMonth();
+}
+
+int KCalendarSystemGregorian::minValidYear() const
+{
+ return 1753; // QDate limit
+}
+
+int KCalendarSystemGregorian::maxValidYear() const
+{
+ return 8000; // QDate limit
+}
+
+int KCalendarSystemGregorian::day(const QDate& date) const
+{
+ return date.day();
+}
+
+int KCalendarSystemGregorian::month(const QDate& date) const
+{
+ return date.month();
+}
+
+int KCalendarSystemGregorian::daysInYear(const QDate& date) const
+{
+ return date.daysInYear();
+}
+
+int KCalendarSystemGregorian::weekDayOfPray() const
+{
+ return 7; // sunday
+}
+
+QString KCalendarSystemGregorian::calendarName() const
+{
+ return QString::fromLatin1("gregorian");
+}
+
+bool KCalendarSystemGregorian::isLunar() const
+{
+ return false;
+}
+
+bool KCalendarSystemGregorian::isLunisolar() const
+{
+ return false;
+}
+
+bool KCalendarSystemGregorian::isSolar() const
+{
+ return true;
+}
+
+int KCalendarSystemGregorian::yearStringToInteger(const QString & sNum, int & iLength) const
+{
+ int iYear;
+ iYear = KCalendarSystem::yearStringToInteger(sNum, iLength);
+
+ // Qt treats a year in the range 0-100 as 1900-1999.
+ // It is nicer for the user if we treat 0-68 as 2000-2068
+ if (iYear < 69)
+ iYear += 2000;
+ else if (iYear < 100)
+ iYear += 1900;
+
+ return iYear;
+}
diff --git a/kdecore/kcalendarsystemgregorian.h b/kdecore/kcalendarsystemgregorian.h
new file mode 100644
index 000000000..7feaf2ebf
--- /dev/null
+++ b/kdecore/kcalendarsystemgregorian.h
@@ -0,0 +1,92 @@
+/*
+ Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCALENDARSYSTEMGREGORIAN_H
+#define KCALENDARSYSTEMGREGORIAN_H
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+#include "kcalendarsystem.h"
+
+class KCalendarSystemGregorianPrivate;
+
+/**
+ * @internal
+ * This is the Gregorian calendar implementation.
+ *
+ * The Gregorian calender is the most used calendar today. The first year in
+ * the calendar is set to the birth of Christ.
+ *
+ * @see KLocale,KCalendarSystem,KCalendarSystemFactory
+ *
+ * @author Carlos Moro <cfmoro@correo.uniovi.es>
+ * @since 3.2
+ */
+class KDECORE_EXPORT KCalendarSystemGregorian: public KCalendarSystem
+{
+public:
+ /** Constructor. Just like KCalendarSystem::KCalendarSystem(). */
+ KCalendarSystemGregorian (const KLocale * locale = 0);
+ virtual ~KCalendarSystemGregorian ();
+
+ virtual int year (const QDate & date) const;
+ virtual int month (const QDate & date) const;
+ virtual int day (const QDate & date) const;
+ virtual int dayOfWeek (const QDate & date) const;
+ virtual int dayOfYear (const QDate & date) const;
+
+ virtual bool setYMD(QDate & date, int y, int m, int d) const;
+
+ virtual QDate addYears(const QDate & date, int nyears) const;
+ virtual QDate addMonths(const QDate & date, int nmonths) const;
+ virtual QDate addDays(const QDate & date, int ndays) const;
+
+ virtual int monthsInYear (const QDate & date) const;
+
+ virtual int daysInYear (const QDate & date) const;
+ virtual int daysInMonth (const QDate & date) const;
+ virtual int weeksInYear(int year) const;
+ virtual int weekNumber(const QDate& date, int * yearNum = 0) const;
+
+ virtual int yearStringToInteger(const QString & sNum, int & iLength) const;
+
+ virtual QString monthName (int month, int year, bool shortName = false) const;
+ virtual QString monthName (const QDate & date, bool shortName = false ) const;
+ virtual QString monthNamePossessive(int month, int year, bool shortName = false) const;
+ virtual QString monthNamePossessive(const QDate & date, bool shortName = false ) const;
+ virtual QString weekDayName (int weekDay, bool shortName = false) const;
+ virtual QString weekDayName (const QDate & date, bool shortName = false) const;
+
+ virtual int minValidYear () const;
+ virtual int maxValidYear () const;
+ virtual int weekDayOfPray () const;
+
+ virtual QString calendarName() const;
+
+ virtual bool isLunar() const;
+ virtual bool isLunisolar() const;
+ virtual bool isSolar() const;
+
+private:
+ KCalendarSystemGregorianPrivate * d;
+};
+
+#endif
diff --git a/kdecore/kcalendarsystemhebrew.cpp b/kdecore/kcalendarsystemhebrew.cpp
new file mode 100644
index 000000000..694261eda
--- /dev/null
+++ b/kdecore/kcalendarsystemhebrew.cpp
@@ -0,0 +1,746 @@
+/*
+ Copyright (c) 2003 Hans Petter Bieker <bieker@kde.org>
+ Calendar conversion routines based on Hdate v6, by Amos
+ Shapir 1978 (rev. 1985, 1992)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Derived hebrew kde calendar class
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kcalendarsystemhebrew.h"
+
+static int hebrewDaysElapsed(int y);
+static QString num2heb(int num, bool includeMillenium);
+
+class h_date
+{
+public:
+ int hd_day;
+ int hd_mon;
+ int hd_year;
+ int hd_dw;
+ int hd_flg;
+};
+
+/*
+ * compute general date structure from hebrew date
+ */
+static class h_date * hebrewToGregorian(int y, int m, int d)
+{
+ static class h_date h;
+ int s;
+
+ y -= 3744;
+ s = hebrewDaysElapsed(y);
+ d += s;
+ s = hebrewDaysElapsed(y + 1) - s; /* length of year */
+
+ if (s > 365 && m > 6 )
+ {
+ --m;
+ d += 30;
+ }
+ d += (59 * (m - 1) + 1) / 2; /* regular months */
+ /* special cases */
+ if (s % 10 > 4 && m > 2) /* long Heshvan */
+ d++;
+ if (s % 10 < 4 && m > 3) /* short Kislev */
+ d--;
+ // ### HPB: Broken in leap years
+ //if (s > 365 && m > 6) /* leap year */
+ // d += 30;
+ d -= 6002;
+
+ y = (d + 36525) * 4 / 146097 - 1;
+ d -= y / 4 * 146097 + (y % 4) * 36524;
+ y *= 100;
+
+ /* compute year */
+ s = (d + 366)*4/1461-1;
+ d -= s/4*1461 + (s % 4)*365;
+ y += s;
+ /* compute month */
+ m = (d + 245)*12/367-7;
+ d -= m*367/12-30;
+ if (++m >= 12) {
+ m -= 12;
+ y++;
+ }
+ h.hd_day = d;
+ h.hd_mon = m;
+ h.hd_year = y;
+ return(&h);
+}
+
+/*
+ * compute date structure from no. of days since 1 Tishrei 3744
+ */
+static class h_date * gregorianToHebrew(int y, int m, int d)
+{
+ static class h_date h;
+ int s;
+
+ if ((m -= 2) <= 0) {
+ m += 12;
+ y--;
+ }
+ /* no. of days, Julian calendar */
+ d += 365*y + y/4 + 367*m/12 + 5968;
+ /* Gregorian calendar */
+ d -= y/100-y/400-2;
+ h.hd_dw = (d + 1) % 7;
+
+ /* compute the year */
+ y += 16;
+ s = hebrewDaysElapsed(y);
+ m = hebrewDaysElapsed(y + 1);
+ while(d >= m) { /* computed year was underestimated */
+ s = m;
+ y++;
+ m = hebrewDaysElapsed(y + 1);
+ }
+ d -= s;
+ s = m-s; /* size of current year */
+ y += 3744;
+
+ h.hd_flg = s % 10-4;
+
+ /* compute day and month */
+ if (d >= s-236) { /* last 8 months are regular */
+ d -= s-236;
+ m = d*2/59;
+ d -= (m*59 + 1)/2;
+ m += 4;
+ if (s > 365 && m <= 5) /* Adar of Meuberet */
+ m += 8;
+ } else {
+ /* first 4 months have 117-119 days */
+ s = 114 + s % 10;
+ m = d * 4 / s;
+ d -= (m * s + 3) / 4;
+ }
+
+ h.hd_day = d;
+ h.hd_mon = m;
+ h.hd_year = y;
+ return(&h);
+}
+
+static QString num2heb(int num, bool includeMillenium)
+{
+ const QChar decade[] = {0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6};
+ QString result;
+
+ if (num < 1 || num > 9999)
+ return QString::number(num);
+
+ if (num >= 1000) {
+ if (includeMillenium || num % 1000 == 0)
+ result += QChar(0x05D0 - 1 + num / 1000);
+ num %= 1000;
+ }
+ if (num >= 100) {
+ while (num >= 500) {
+ result += QChar(0x05EA);
+ num -= 400;
+ }
+ result += QChar(0x05E7 - 1 + num / 100);
+ num %= 100;
+ }
+ if (num >= 10) {
+ if (num == 15 || num == 16)
+ num -= 9;
+ result += decade[num / 10];
+ num %= 10;
+ }
+ if (num > 0)
+ result += QChar(0x05D0 - 1 + num);
+
+ if (result.length() == 1)
+ result += "'";
+ else
+ result.insert(result.length() - 1, '\"');
+
+ return result;
+}
+
+/* constants, in 1/18th of minute */
+static const int HOUR = 1080;
+static const int DAY = 24*HOUR;
+static const int WEEK = 7*DAY;
+#define M(h,p) ((h)*HOUR+p)
+#define MONTH (DAY+M(12,793))
+
+/**
+ * @internal
+ * no. of days in y years
+ */
+static int hebrewDaysElapsed(int y)
+{
+ int m, nm, dw, s, l;
+
+ l = y * 7 + 1; // no. of leap months
+ m = y*12+l/19; // total no. of months
+ l %= 19;
+ nm = m*MONTH+M(1+6,779); // molad new year 3744 (16BC) + 6 hours
+ s = m*28+nm/DAY-2;
+
+ nm %= WEEK;
+ dw = nm/DAY;
+ nm %= DAY;
+
+ // special cases of Molad Zaken
+ if (l < 12 && dw == 3 && nm >= M(9 + 6,204) ||
+ l < 7 && dw == 2 && nm>=M(15+6,589))
+ s++,dw++;
+ /* ADU */
+ if (dw == 1 || dw == 4 || dw == 6)
+ s++;
+ return s;
+}
+
+/**
+ * @internal
+ * true if long Cheshvan
+ */
+static int long_cheshvan(int year)
+{
+ QDate first, last;
+ class h_date *gd;
+
+ gd = hebrewToGregorian(year, 1, 1);
+ first.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
+
+ gd = hebrewToGregorian(year + 1, 1, 1);
+ last.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
+
+ return (first.daysTo(last) % 10 == 5);
+}
+
+/**
+ * @internal
+ * true if short Kislev
+ */
+static int short_kislev(int year)
+{
+ QDate first, last;
+ class h_date * gd;
+
+ gd = hebrewToGregorian(year, 1, 1);
+ first.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
+
+ gd = hebrewToGregorian(year + 1, 1, 1);
+ last.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
+
+ return (first.daysTo(last) % 10 == 3);
+}
+
+static bool is_leap_year(int year)
+{
+ return ((((7 * year) + 1) % 19) < 7);
+}
+
+// Ok
+KCalendarSystemHebrew::KCalendarSystemHebrew(const KLocale * locale)
+ : KCalendarSystem(locale)
+{
+}
+
+// Ok
+KCalendarSystemHebrew::~KCalendarSystemHebrew()
+{
+}
+
+// Ok
+static class h_date * toHebrew(const QDate & date)
+{
+ class h_date *sd;
+ sd = gregorianToHebrew(date.year(), date.month(), date.day());
+ ++sd->hd_mon;
+ ++sd->hd_day;
+ return sd;
+}
+
+// Ok
+int KCalendarSystemHebrew::year(const QDate& date) const
+{
+ class h_date *sd = toHebrew(date);
+ return sd->hd_year;
+}
+
+// Ok
+int KCalendarSystemHebrew::monthsInYear( const QDate & date ) const
+{
+ if ( is_leap_year( year(date) ) )
+ return 13;
+ else
+ return 12;
+}
+
+// Ok
+int KCalendarSystemHebrew::weeksInYear(int year) const
+{
+ QDate temp;
+ setYMD(temp, year, 1, 1); // don't pass an uninitialized QDate to
+ // monthsInYear in the next call
+ setYMD(temp, year, monthsInYear(temp), hndays(monthsInYear(temp), year) );
+
+ int nWeekNumber = weekNumber(temp);
+ if(nWeekNumber == 1) // last week belongs to next year
+ {
+ temp = temp.addDays(-7);
+ nWeekNumber = weekNumber(temp);
+ }
+
+ return nWeekNumber;
+}
+
+int KCalendarSystemHebrew::weekNumber(const QDate& date, int * yearNum) const
+{
+ QDate firstDayWeek1, lastDayOfYear;
+ int y = year(date);
+ int week;
+ int weekDay1, dayOfWeek1InYear;
+
+ // let's guess 1st day of 1st week
+ setYMD(firstDayWeek1, y, 1, 1);
+ weekDay1 = dayOfWeek(firstDayWeek1);
+
+ // iso 8601: week 1 is the first containing thursday and week starts on
+ // monday
+ if (weekDay1 > 4 /*Thursday*/)
+ firstDayWeek1 = addDays(firstDayWeek1 , 7 - weekDay1 + 1); // next monday
+
+ dayOfWeek1InYear = dayOfYear(firstDayWeek1);
+
+ if ( dayOfYear(date) < dayOfWeek1InYear ) // our date in prev year's week
+ {
+ if ( yearNum )
+ *yearNum = y - 1;
+ return weeksInYear(y - 1);
+ }
+
+ // let's check if its last week belongs to next year
+ setYMD(lastDayOfYear, y + 1, 1, 1);
+ lastDayOfYear = addDays(lastDayOfYear, -1);
+ if ( (dayOfYear(date) >= daysInYear(date) - dayOfWeek(lastDayOfYear) + 1)
+ // our date is in last week
+ && dayOfWeek(lastDayOfYear) < 4) // 1st week in next year has thursday
+ {
+ if ( yearNum )
+ *yearNum = y + 1;
+ week = 1;
+ }
+ else
+ {
+ if( weekDay1 < 5 ) // To calculate properly the number of weeks
+ // from day a to x let's make a day 1 of week
+ firstDayWeek1 = addDays( firstDayWeek1, -( weekDay1 - 1));
+
+ week = firstDayWeek1.daysTo(date) / 7 + 1;
+ }
+
+ return week;
+}
+
+// Ok
+QString KCalendarSystemHebrew::monthName(const QDate& date,
+ bool shortName) const
+{
+ return monthName(month(date), year(date), shortName);
+}
+
+// Ok
+QString KCalendarSystemHebrew::monthNamePossessive(const QDate& date,
+ bool shortName) const
+{
+ return monthNamePossessive(month(date), year(date), shortName);
+}
+
+// ### Fixme
+QString KCalendarSystemHebrew::monthName(int month, int year, bool /*shortName*/) const
+{
+ if ( month < 1 )
+ return QString::null;
+ if ( is_leap_year(year) )
+ {
+ if ( month > 13 )
+ return QString::null;
+ }
+ else if ( month > 12 )
+ return QString::null;
+
+ // We must map conversion algorithm month index to real index
+ if( month == 6 && is_leap_year(year) )
+ month = 13; /*Adar I*/
+ else if ( month == 7 && is_leap_year(year) )
+ month = 14; /*Adar II*/
+ else if ( month > 7 && is_leap_year(year) )
+ month--; //Because of Adar II
+
+ switch(month)
+ {
+ case 1:
+ return locale()->translate("Tishrey");
+ case 2:
+ return locale()->translate("Heshvan");
+ case 3:
+ return locale()->translate("Kislev");
+ case 4:
+ return locale()->translate("Tevet");
+ case 5:
+ return locale()->translate("Shvat");
+ case 6:
+ return locale()->translate("Adar");
+ case 7:
+ return locale()->translate("Nisan");
+ case 8:
+ return locale()->translate("Iyar");
+ case 9:
+ return locale()->translate("Sivan");
+ case 10:
+ return locale()->translate("Tamuz");
+ case 11:
+ return locale()->translate("Av");
+ case 12:
+ return locale()->translate("Elul");
+ case 13:
+ return locale()->translate("Adar I");
+ case 14:
+ return locale()->translate("Adar II");
+ default:
+ break;
+ }
+
+ return QString::null;
+}
+
+// ### Fixme
+QString KCalendarSystemHebrew::monthNamePossessive(int month, int year,
+ bool shortName) const
+{
+ return "of " + monthName(month, year, shortName);
+}
+
+bool KCalendarSystemHebrew::setYMD(QDate & date, int y, int m, int d) const
+{
+ if( y < minValidYear() || y > maxValidYear() )
+ return false;
+ if( m < 1 || m > (is_leap_year(y) ? 13 : 12) )
+ return false;
+ if( d < 1 || d > hndays(m,y) )
+ return false;
+
+ class h_date * gd = hebrewToGregorian( y, m, d );
+
+ return date.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
+}
+
+QString KCalendarSystemHebrew::weekDayName(int day, bool shortName) const
+{
+ return KCalendarSystem::weekDayName(day, shortName);
+}
+
+// Ok
+QString KCalendarSystemHebrew::weekDayName(const QDate& date,
+ bool shortName) const
+{
+ return weekDayName(dayOfWeek(date), shortName);
+}
+
+// Ok
+int KCalendarSystemHebrew::dayOfWeek(const QDate& date) const
+{
+ class h_date *sd = toHebrew(date);
+ if ( sd->hd_dw == 0 )
+ return 7;
+ else
+ return (sd->hd_dw);
+}
+
+// Ok
+int KCalendarSystemHebrew::dayOfYear(const QDate & date) const
+{
+ QDate first;
+ setYMD(first, year(date), 1, 1);
+
+ return first.daysTo(date) + 1;
+}
+
+int KCalendarSystemHebrew::daysInMonth(const QDate& date) const
+{
+ return hndays(month(date), year(date));
+}
+
+int KCalendarSystemHebrew::hndays(int mon, int year) const
+{
+ if ( mon == 6 && is_leap_year(year) )
+ mon = 13; /*Adar I*/
+ else if ( mon == 7 && is_leap_year(year) )
+ mon = 14; /*Adar II*/
+ else if ( mon > 7 && is_leap_year(year) )
+ mon--; //Because of Adar II
+
+ if( mon == 8 /*IYYAR*/ || mon == 10 /*TAMUZ*/ ||
+ mon == 12 /*ELUL*/ || mon == 4 /*TEVET*/ ||
+ mon == 14 /*ADAR 2*/||
+ ( mon == 6 /*ADAR*/ && !is_leap_year(year)) ||
+ (mon == 2 /*CHESHVAN*/ && !long_cheshvan(year)) ||
+ (mon == 3 /*KISLEV*/ && short_kislev(year)))
+ return 29;
+ else
+ return 30;
+}
+
+// Ok
+// Min valid year that may be converted to QDate
+int KCalendarSystemHebrew::minValidYear() const
+{
+ QDate date(1753, 1, 1);
+
+ return year(date);
+}
+
+// Ok
+// Max valid year that may be converted to QDate
+int KCalendarSystemHebrew::maxValidYear() const
+{
+ QDate date(8000, 1, 1);
+
+ return year(date);
+}
+
+// Ok
+int KCalendarSystemHebrew::day(const QDate& date) const
+{
+ class h_date *sd = toHebrew(date);
+
+ return sd->hd_day;
+}
+
+// Ok
+int KCalendarSystemHebrew::month(const QDate& date) const
+{
+ class h_date *sd = toHebrew(date);
+
+ int month = sd->hd_mon;
+ if ( is_leap_year( sd->hd_year ) )
+ {
+ if( month == 13 /*AdarI*/ )
+ month = 6;
+ else if( month == 14 /*AdarII*/ )
+ month = 7;
+ else if ( month > 6 && month < 13 )
+ ++month;
+ }
+
+ return month;
+}
+
+// Ok
+int KCalendarSystemHebrew::daysInYear(const QDate & date) const
+{
+ QDate first, last;
+ setYMD(first, year(date), 1, 1); // 1 Tishrey
+ setYMD(last, year(date) + 1, 1, 1); // 1 Tishrey the year later
+
+ return first.daysTo(last);
+}
+
+// Ok
+int KCalendarSystemHebrew::weekDayOfPray() const
+{
+ return 6; // saturday
+}
+
+// Ok
+QDate KCalendarSystemHebrew::addDays( const QDate & date, int ndays ) const
+{
+ return date.addDays( ndays );
+}
+
+// Ok
+QDate KCalendarSystemHebrew::addMonths( const QDate & date, int nmonths ) const
+{
+ QDate result = date;
+
+ while ( nmonths > 0 )
+ {
+ result = addDays(result, daysInMonth(result));
+ --nmonths;
+ }
+
+ while ( nmonths < 0 )
+ {
+ // get the number of days in the previous month to be consistent with
+ // addMonths where nmonths > 0
+ int nDaysInMonth = daysInMonth(addDays(result, -day(result)));
+ result = addDays(result, -nDaysInMonth);
+ ++nmonths;
+ }
+
+ return result;
+}
+
+// Ok
+QDate KCalendarSystemHebrew::addYears( const QDate & date, int nyears ) const
+{
+ QDate result = date;
+ int y = year(date) + nyears;
+
+ setYMD( result, y, month(date), day(date) );
+
+ return result;
+}
+
+// Ok
+QString KCalendarSystemHebrew::calendarName() const
+{
+ return QString::fromLatin1("hebrew");
+}
+
+// Ok
+bool KCalendarSystemHebrew::isLunar() const
+{
+ return false;
+}
+
+// Ok
+bool KCalendarSystemHebrew::isLunisolar() const
+{
+ return true;
+}
+
+// Ok
+bool KCalendarSystemHebrew::isSolar() const
+{
+ return false;
+}
+
+QString KCalendarSystemHebrew::dayString(const QDate & pDate, bool bShort) const
+{
+ QString sResult;
+
+ // Only use hebrew numbers if the hebrew setting is selected
+ if (locale()->language() == QString::fromLatin1("he"))
+ sResult = num2heb(day(pDate), false);
+ else
+ sResult = KCalendarSystem::dayString(pDate, bShort);
+
+ return sResult;
+}
+
+QString KCalendarSystemHebrew::yearString(const QDate & pDate, bool bShort) const
+{
+ QString sResult;
+
+ // Only use hebrew numbers if the hebrew setting is selected
+ if (locale()->language() == QString::fromLatin1("he"))
+ sResult = num2heb(year(pDate), !bShort);
+ else
+ sResult = KCalendarSystem::yearString(pDate, bShort);
+
+ return sResult;
+}
+
+static int heb2num(const QString& str, int & iLength) {
+ QChar c;
+ QString s = str;
+ int result = 0;
+ iLength = 0;
+ int decadeValues[14] = {10, 20, 20, 30, 40, 40, 50,
+ 50, 60, 70, 80, 80, 90, 90};
+
+ uint pos;
+ for (pos = 0 ; pos < s.length() ; pos++)
+ {
+ c = s[pos];
+ if (s.length() > pos && (s[pos + 1] == QChar('\'') ||
+ s[pos + 1] == QChar('\"')))
+ {
+ iLength++;
+ s.remove(pos + 1, 1);
+ }
+
+ if (c >= QChar(0x05D0) && c <= QChar(0x05D7))
+ {
+ if (s.length() > pos && s[pos + 1] >= QChar(0x05D0) &&
+ s[pos + 1] <= QChar(0x05EA))
+ result += (c.unicode() - 0x05D0 + 1) * 1000;
+ else
+ result += c.unicode() - 0x05D0 + 1;
+ }
+ else if (c == QChar(0x05D8))
+ {
+ if (s.length() > pos && s[pos + 1] >= QChar(0x05D0) &&
+ s[pos + 1] <= QChar(0x05EA) && s[pos + 1] != QChar(0x05D5) &&
+ s[pos + 1] != QChar(0x05D6))
+ result += 9000;
+ else
+ result += 9;
+ }
+ else if (c >= QChar(0x05D9) && c <= QChar(0x05E6))
+ {
+ if (s.length() > pos && s[pos + 1] >= QChar(0x05D9))
+ return -1;
+ else
+ result += decadeValues[c.unicode() - 0x05D9];
+ }
+ else if (c >= QChar(0x05E7) && c <= QChar(0x05EA))
+ {
+ result += (c.unicode() - 0x05E7 + 1) * 100;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ iLength += pos;
+
+ return result;
+}
+
+int KCalendarSystemHebrew::dayStringToInteger(const QString & sNum, int & iLength) const
+{
+ int iResult;
+ if (locale()->language() == "he")
+ iResult= heb2num(sNum, iLength);
+ else
+ iResult = KCalendarSystem::yearStringToInteger(sNum, iLength);
+
+ return iResult;
+}
+
+int KCalendarSystemHebrew::yearStringToInteger(const QString & sNum, int & iLength) const
+{
+ int iResult;
+ if (locale()->language() == "he")
+ iResult = heb2num(sNum, iLength);
+ else
+ iResult = KCalendarSystem::yearStringToInteger(sNum, iLength);
+
+ if (iResult < 1000)
+ iResult += 5000; // assume we're in the 6th millenium (y6k bug)
+
+ return iResult;
+}
+
diff --git a/kdecore/kcalendarsystemhebrew.h b/kdecore/kcalendarsystemhebrew.h
new file mode 100644
index 000000000..efa91698d
--- /dev/null
+++ b/kdecore/kcalendarsystemhebrew.h
@@ -0,0 +1,105 @@
+/*
+ Copyright (c) 2002-2003 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002-2003 Hans Petter Bieker <bieker@kde.org>
+ Calendar conversion routines based on Hdate v6, by Amos
+ Shapir 1978 (rev. 1985, 1992)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCALENDARSYSTEMHEBREW_H
+#define KCALENDARSYSTEMHEBREW_H
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+#include "kcalendarsystem.h"
+
+class KCalendarSystemHebrewPrivate;
+
+/**
+ * @internal
+ * This is the Hebrew calendar implementation.
+ *
+ * The Hebrew calendar is the traditional Islamic calendar used in the Midle
+ * East.
+ *
+ * @see KLocale,KCalendarSystem,KCalendarSystemFactory
+ *
+ * @author Hans Petter Bieker <bieker@kde.org>
+ * @since 3.2
+ */
+class KDECORE_EXPORT KCalendarSystemHebrew : public KCalendarSystem
+{
+public:
+ /** Constructor. Just like KCalendarSystem::KCalendarSystem(). */
+ KCalendarSystemHebrew(const KLocale * locale = 0);
+ virtual ~KCalendarSystemHebrew();
+
+ virtual int year (const QDate & date) const;
+ virtual int month (const QDate & date) const;
+ virtual int day (const QDate & date) const;
+ virtual int dayOfWeek (const QDate & date) const;
+ virtual int dayOfYear (const QDate & date) const;
+
+ virtual bool setYMD(QDate & date, int y, int m, int d) const;
+
+ virtual QDate addYears(const QDate & date, int nyears) const;
+ virtual QDate addMonths(const QDate & date, int nmonths) const;
+ virtual QDate addDays(const QDate & date, int ndays) const;
+
+ virtual int monthsInYear (const QDate & date) const;
+ virtual int daysInYear (const QDate & date) const;
+ virtual int daysInMonth (const QDate & date) const;
+ virtual int weeksInYear(int year) const;
+ virtual int weekNumber(const QDate& date, int * yearNum = 0) const;
+
+ virtual QString monthName (int month, int year, bool shortName = false) const;
+ virtual QString monthName (const QDate & date, bool shortName = false ) const;
+ virtual QString monthNamePossessive(int month, int year, bool shortName = false) const;
+ virtual QString monthNamePossessive(const QDate & date, bool shortName = false ) const;
+ virtual QString weekDayName (int weekDay, bool shortName = false) const;
+ virtual QString weekDayName (const QDate & date, bool shortName = false) const;
+
+ virtual QString dayString(const QDate & pDate, bool bShort) const;
+ virtual QString yearString(const QDate & pDate, bool bShort) const;
+ virtual int dayStringToInteger(const QString & sNum, int & iLength) const;
+ virtual int yearStringToInteger(const QString & sNum, int & iLength) const;
+
+ virtual int minValidYear () const;
+ virtual int maxValidYear () const;
+ virtual int weekDayOfPray () const;
+
+ virtual QString calendarName() const;
+
+ virtual bool isLunar() const;
+ virtual bool isLunisolar() const;
+ virtual bool isSolar() const;
+
+private:
+ /**
+ * Gets the number of days in a month for a given date
+ *
+ * @param year given year
+ * @param mon month number
+ * @return number of days in month
+ */
+ int hndays(int year, int mon) const;
+
+ KCalendarSystemHebrewPrivate * d;
+};
+
+#endif
diff --git a/kdecore/kcalendarsystemhijri.cpp b/kdecore/kcalendarsystemhijri.cpp
new file mode 100644
index 000000000..c594cf22b
--- /dev/null
+++ b/kdecore/kcalendarsystemhijri.cpp
@@ -0,0 +1,596 @@
+/*
+ Copyright (c) 2002-2003 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002-2003 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Derived hijri kde calendar class
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kcalendarsystemhijri.h"
+
+/*
+ The following C++ code is translated from the Lisp code
+ in ``Calendrical Calculations'' by Nachum Dershowitz and
+ Edward M. Reingold, Software---Practice & Experience,
+ vol. 20, no. 9 (September, 1990), pp. 899--928.
+
+ This code is in the public domain, but any use of it
+ should publically acknowledge its source.
+
+ Classes GregorianDate, IslamicDate
+ */
+
+static int lastDayOfGregorianMonth(int month, int year) {
+// Compute the last date of the month for the Gregorian calendar.
+
+ switch (month) {
+ case 2:
+ if ((((year % 4) == 0) && ((year % 100) != 0))
+ || ((year % 400) == 0))
+ return 29;
+ else
+ return 28;
+ case 4:
+ case 6:
+ case 9:
+ case 11: return 30;
+ default: return 31;
+ }
+}
+
+class GregorianDate {
+private:
+ int year; // 1...
+ int month; // 1 == January, ..., 12 == December
+ int day; // 1..lastDayOfGregorianMonth(month, year)
+
+public:
+ GregorianDate(int m, int d, int y) { month = m; day = d; year = y; }
+
+ GregorianDate(int d) { // Computes the Gregorian date from the absolute date.
+
+ // Search forward year by year from approximate year
+ year = d/366;
+ while (d >= GregorianDate(1,1,year+1))
+ year++;
+ // Search forward month by month from January
+ month = 1;
+ while (d > GregorianDate(month, lastDayOfGregorianMonth(month,year), year))
+ month++;
+ day = d - GregorianDate(month,1,year) + 1;
+ }
+
+ operator int() { // Computes the absolute date from the Gregorian date.
+ int N = day; // days this month
+ for (int m = month - 1; m > 0; m--) // days in prior months this year
+ N = N + lastDayOfGregorianMonth(m, year);
+ return
+ (N // days this year
+ + 365 * (year - 1) // days in previous years ignoring leap days
+ + (year - 1)/4 // Julian leap days before this year...
+ - (year - 1)/100 // ...minus prior century years...
+ + (year - 1)/400); // ...plus prior years divisible by 400
+ }
+
+ int getMonth() { return month; }
+ int getDay() { return day; }
+ int getYear() { return year; }
+
+};
+
+static int IslamicLeapYear(int year) {
+// True if year is an Islamic leap year
+
+ if ((((11 * year) + 14) % 30) < 11)
+ return 1;
+ else
+ return 0;
+}
+
+static const int IslamicEpoch = 227014; // Absolute date of start of
+ // Islamic calendar
+
+static int lastDayOfIslamicMonth(int month, int year) {
+// Last day in month during year on the Islamic calendar.
+
+ if (((month % 2) == 1) || ((month == 12) && IslamicLeapYear(year)))
+ return 30;
+ else
+ return 29;
+}
+
+class IslamicDate {
+private:
+ int year; // 1...
+ int month; // 1..13 (12 in a common year)
+ int day; // 1..lastDayOfIslamicMonth(month,year)
+
+public:
+ IslamicDate(int m, int d, int y) { month = m; day = d; year = y; }
+
+ IslamicDate(int d) { // Computes the Islamic date from the absolute date.
+ if (d <= IslamicEpoch) { // Date is pre-Islamic
+ month = 0;
+ day = 0;
+ year = 0;
+ }
+ else {
+ // Search forward year by year from approximate year
+ year = (d - IslamicEpoch) / 355;
+ while (d >= IslamicDate(1,1,year+1))
+ year++;
+ // Search forward month by month from Muharram
+ month = 1;
+ while (d > IslamicDate(month, lastDayOfIslamicMonth(month,year), year))
+ month++;
+ day = d - IslamicDate(month,1,year) + 1;
+ }
+ }
+
+ operator int() { // Computes the absolute date from the Islamic date.
+ return (day // days so far this month
+ + 29 * (month - 1) // days so far...
+ + month/2 // ...this year
+ + 354 * (year - 1) // non-leap days in prior years
+ + (3 + (11 * year)) / 30 // leap days in prior years
+ + IslamicEpoch); // days before start of calendar
+ }
+
+ int getMonth() { return month; }
+ int getDay() { return day; }
+ int getYear() { return year; }
+
+};
+
+static void gregorianToHijri(const QDate & date, int * pYear, int * pMonth,
+ int * pDay)
+{
+ GregorianDate gregorian(date.month(),date.day(),date.year());
+ int absolute = gregorian;
+
+ IslamicDate islamic(absolute);
+
+ if (pYear)
+ *pYear = islamic.getYear();
+ if (pMonth)
+ *pMonth = islamic.getMonth();
+ if (pDay)
+ *pDay = islamic.getDay();
+}
+
+KCalendarSystemHijri::KCalendarSystemHijri(const KLocale * locale)
+ : KCalendarSystem(locale)
+{
+}
+
+KCalendarSystemHijri::~KCalendarSystemHijri()
+{
+}
+
+int KCalendarSystemHijri::year(const QDate& date) const
+{
+ int y;
+ gregorianToHijri(date, &y, 0, 0);
+ return y;
+}
+
+int KCalendarSystemHijri::month(const QDate& date) const
+{
+ int m;
+ gregorianToHijri(date, 0, &m, 0);
+ return m;
+}
+
+int KCalendarSystemHijri::day(const QDate& date) const
+{
+ int d;
+ gregorianToHijri(date, 0, 0, &d);
+ return d;
+}
+
+int KCalendarSystemHijri::monthsInYear( const QDate & date ) const
+{
+ Q_UNUSED( date )
+
+ return 12;
+}
+
+int KCalendarSystemHijri::weeksInYear(int year) const
+{
+ QDate temp;
+ setYMD(temp, year, 12, lastDayOfIslamicMonth(12, year));
+
+ // If the last day of the year is in the first week, we have to check the
+ // week before
+ if ( weekNumber(temp) == 1 )
+ temp = addDays(temp, -7);
+
+ return weekNumber(temp);
+}
+
+int KCalendarSystemHijri::weekNumber(const QDate& date, int * yearNum) const
+{
+ QDate firstDayWeek1, lastDayOfYear;
+ int y = year(date);
+ int week;
+ int weekDay1, dayOfWeek1InYear;
+
+ // let's guess 1st day of 1st week
+ setYMD(firstDayWeek1, y, 1, 1);
+ weekDay1 = dayOfWeek(firstDayWeek1);
+
+ // iso 8601: week 1 is the first containing thursday and week starts on
+ // monday
+ if (weekDay1 > 4 )
+ firstDayWeek1 = addDays(firstDayWeek1 , 7 - weekDay1 + 1); // next monday
+
+ dayOfWeek1InYear = dayOfYear(firstDayWeek1);
+
+ if ( dayOfYear(date) < dayOfWeek1InYear ) // our date in prev year's week
+ {
+ if ( yearNum )
+ *yearNum = y - 1;
+ return weeksInYear(y - 1);
+ }
+
+ // let' check if its last week belongs to next year
+ setYMD(lastDayOfYear, y, 12, lastDayOfIslamicMonth(12, y));
+ if ( (dayOfYear(date) >= daysInYear(date) - dayOfWeek(lastDayOfYear) + 1)
+ // our date is in last week
+ && dayOfWeek(lastDayOfYear) < 4) // 1st week in next year has thursday
+ {
+ if ( yearNum )
+ *yearNum = y + 1;
+ week = 1;
+ }
+ else
+ {
+ if ( weekDay1 < 5 )
+ firstDayWeek1 = addDays(firstDayWeek1, - (weekDay1 - 1));
+
+ week = firstDayWeek1.daysTo(date) / 7 + 1;
+ }
+
+ return week;
+}
+
+QString KCalendarSystemHijri::monthName(const QDate& date,
+ bool shortName) const
+{
+ return monthName(month(date), year(date), shortName);
+}
+
+QString KCalendarSystemHijri::monthNamePossessive(const QDate& date,
+ bool shortName) const
+{
+ return monthNamePossessive(month(date), year(date), shortName);
+}
+
+QString KCalendarSystemHijri::monthName(int month, int year, bool shortName)
+ const {
+
+ Q_UNUSED(year);
+
+ if (shortName)
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("Muharram");
+ case 2:
+ return locale()->translate("Safar");
+ case 3:
+ return locale()->translate("R. Awal");
+ case 4:
+ return locale()->translate("R. Thaani");
+ case 5:
+ return locale()->translate("J. Awal");
+ case 6:
+ return locale()->translate("J. Thaani");
+ case 7:
+ return locale()->translate("Rajab");
+ case 8:
+ return locale()->translate("Sha`ban");
+ case 9:
+ return locale()->translate("Ramadan");
+ case 10:
+ return locale()->translate("Shawwal");
+ case 11:
+ return locale()->translate("Qi`dah");
+ case 12:
+ return locale()->translate("Hijjah");
+ }
+ else
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("Muharram");
+ case 2:
+ return locale()->translate("Safar");
+ case 3:
+ return locale()->translate("Rabi` al-Awal");
+ case 4:
+ return locale()->translate("Rabi` al-Thaani");
+ case 5:
+ return locale()->translate("Jumaada al-Awal");
+ case 6:
+ return locale()->translate("Jumaada al-Thaani");
+ case 7:
+ return locale()->translate("Rajab");
+ case 8:
+ return locale()->translate("Sha`ban");
+ case 9:
+ return locale()->translate("Ramadan");
+ case 10:
+ return locale()->translate("Shawwal");
+ case 11:
+ return locale()->translate("Thu al-Qi`dah");
+ case 12:
+ return locale()->translate("Thu al-Hijjah");
+ }
+
+ return QString::null;
+}
+
+QString KCalendarSystemHijri::monthNamePossessive(int month, int year,
+ bool shortName) const
+{
+ Q_UNUSED(year);
+
+ if (shortName)
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("of Muharram");
+ case 2:
+ return locale()->translate("of Safar");
+ case 3:
+ return locale()->translate("of R. Awal");
+ case 4:
+ return locale()->translate("of R. Thaani");
+ case 5:
+ return locale()->translate("of J. Awal");
+ case 6:
+ return locale()->translate("of J. Thaani");
+ case 7:
+ return locale()->translate("of Rajab");
+ case 8:
+ return locale()->translate("of Sha`ban");
+ case 9:
+ return locale()->translate("of Ramadan");
+ case 10:
+ return locale()->translate("of Shawwal");
+ case 11:
+ return locale()->translate("of Qi`dah");
+ case 12:
+ return locale()->translate("of Hijjah");
+ }
+ else
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("of Muharram");
+ case 2:
+ return locale()->translate("of Safar");
+ case 3:
+ return locale()->translate("of Rabi` al-Awal");
+ case 4:
+ return locale()->translate("of Rabi` al-Thaani");
+ case 5:
+ return locale()->translate("of Jumaada al-Awal");
+ case 6:
+ return locale()->translate("of Jumaada al-Thaani");
+ case 7:
+ return locale()->translate("of Rajab");
+ case 8:
+ return locale()->translate("of Sha`ban");
+ case 9:
+ return locale()->translate("of Ramadan");
+ case 10:
+ return locale()->translate("of Shawwal");
+ case 11:
+ return locale()->translate("of Thu al-Qi`dah");
+ case 12:
+ return locale()->translate("of Thu al-Hijjah");
+ }
+
+ return QString::null;
+}
+
+bool KCalendarSystemHijri::setYMD(QDate & date, int y, int m, int d) const
+{
+ // range checks
+ if ( y < minValidYear() || y > maxValidYear() )
+ return false;
+
+ if ( m < 1 || m > 12 )
+ return false;
+
+ if ( d < 1 || d > lastDayOfIslamicMonth(m, y) )
+ return false;
+
+ IslamicDate islamic (m, d, y);
+ int absolute = islamic;
+ GregorianDate gregorian(absolute);
+
+ return date.setYMD(gregorian.getYear(), gregorian.getMonth(),
+ gregorian.getDay());
+}
+
+QString KCalendarSystemHijri::weekDayName(int day, bool shortName) const
+{
+ if ( shortName )
+ switch (day)
+ {
+ case 1:
+ return locale()->translate("Ith");
+ case 2:
+ return locale()->translate("Thl");
+ case 3:
+ return locale()->translate("Arb");
+ case 4:
+ return locale()->translate("Kha");
+ case 5:
+ return locale()->translate("Jum");
+ case 6:
+ return locale()->translate("Sab");
+ case 7:
+ return locale()->translate("Ahd");
+ }
+ else
+ switch ( day )
+ {
+ case 1:
+ return locale()->translate("Yaum al-Ithnain");
+ case 2:
+ return locale()->translate("Yau al-Thulatha");
+ case 3:
+ return locale()->translate("Yaum al-Arbi'a");
+ case 4:
+ return locale()->translate("Yaum al-Khamees");
+ case 5:
+ return locale()->translate("Yaum al-Jumma");
+ case 6:
+ return locale()->translate("Yaum al-Sabt");
+ case 7:
+ return locale()->translate("Yaum al-Ahad");
+ }
+
+ return QString::null;
+}
+
+QString KCalendarSystemHijri::weekDayName(const QDate& date,
+ bool shortName) const
+{
+ return weekDayName(dayOfWeek(date), shortName);
+}
+
+int KCalendarSystemHijri::dayOfWeek(const QDate& date) const
+{
+ return date.dayOfWeek(); // same as gregorian
+}
+
+int KCalendarSystemHijri::dayOfYear(const QDate & date) const
+{
+ QDate first;
+ setYMD(first, year(date), 1, 1);
+
+ return first.daysTo(date) + 1;
+
+ return 100;
+}
+
+int KCalendarSystemHijri::daysInMonth(const QDate& date) const
+{
+ int y, m;
+ gregorianToHijri(date, &y, &m, 0);
+
+ return lastDayOfIslamicMonth(m, y);
+}
+
+// Min valid year that may be converted to QDate
+int KCalendarSystemHijri::minValidYear() const
+{
+ QDate date(1753, 1, 1);
+
+ return year(date);
+}
+
+// Max valid year that may be converted to QDate
+int KCalendarSystemHijri::maxValidYear() const
+{
+ QDate date(8000, 1, 1);
+
+ return year(date);
+}
+
+int KCalendarSystemHijri::daysInYear(const QDate & date) const
+{
+ QDate first, last;
+ setYMD(first, year(date), 1, 1);
+ setYMD(last, year(date) + 1, 1, 1);
+
+ return first.daysTo(last);
+}
+
+int KCalendarSystemHijri::weekDayOfPray() const
+{
+ return 5; // friday
+}
+
+QDate KCalendarSystemHijri::addDays( const QDate & date, int ndays ) const
+{
+ return date.addDays( ndays );
+}
+
+QDate KCalendarSystemHijri::addMonths( const QDate & date, int nmonths ) const
+{
+ QDate result = date;
+ int m = month(date);
+ int y = year(date);
+
+ if ( nmonths < 0 )
+ {
+ m += 12;
+ y -= 1;
+ }
+
+ --m; // this only works if we start counting at zero
+ m += nmonths;
+ y += m / 12;
+ m %= 12;
+ ++m;
+
+ setYMD( result, y, m, day(date) );
+
+ return result;
+}
+
+QDate KCalendarSystemHijri::addYears( const QDate & date, int nyears ) const
+{
+ QDate result = date;
+ int y = year(date) + nyears;
+
+ setYMD( result, y, month(date), day(date) );
+
+ return result;
+}
+
+QString KCalendarSystemHijri::calendarName() const
+{
+ return QString::fromLatin1("hijri");
+}
+
+bool KCalendarSystemHijri::isLunar() const
+{
+ return true;
+}
+
+bool KCalendarSystemHijri::isLunisolar() const
+{
+ return false;
+}
+
+bool KCalendarSystemHijri::isSolar() const
+{
+ return false;
+}
diff --git a/kdecore/kcalendarsystemhijri.h b/kdecore/kcalendarsystemhijri.h
new file mode 100644
index 000000000..d03efe528
--- /dev/null
+++ b/kdecore/kcalendarsystemhijri.h
@@ -0,0 +1,98 @@
+/*
+ Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
+ Copyright (c) 2002-2003 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCALENDARSYSTEMHIJRI_H
+#define KCALENDARSYSTEMHIJRI_H
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+#include "kcalendarsystem.h"
+
+class KCalendarSystemHijriPrivate;
+
+/**
+ * @internal
+ * This is the Hijri calendar implementation.
+ *
+ * The Hijri calendar is the traditional Islamic calendar used in the Midle
+ * East.
+ *
+ * @see KLocale,KCalendarSystem,KCalendarSystemFactory
+ *
+ * @author Carlos Moro <cfmoro@correo.uniovi.es>
+ * @since 3.2
+ */
+class KDECORE_EXPORT KCalendarSystemHijri : public KCalendarSystem
+{
+public:
+ /** Constructor. Just like KCalendarSystem::KCalendarSystem(). */
+ KCalendarSystemHijri(const KLocale * locale = 0);
+ virtual ~KCalendarSystemHijri();
+
+ virtual int year (const QDate & date) const;
+ virtual int month (const QDate & date) const;
+ virtual int day (const QDate & date) const;
+ virtual int dayOfWeek (const QDate & date) const;
+ virtual int dayOfYear (const QDate & date) const;
+
+ virtual bool setYMD(QDate & date, int y, int m, int d) const;
+
+ virtual QDate addYears(const QDate & date, int nyears) const;
+ virtual QDate addMonths(const QDate & date, int nmonths) const;
+ virtual QDate addDays(const QDate & date, int ndays) const;
+
+ virtual int monthsInYear (const QDate & date) const;
+ virtual int daysInYear (const QDate & date) const;
+ virtual int daysInMonth (const QDate & date) const;
+ virtual int weeksInYear(int year) const;
+ virtual int weekNumber(const QDate& date, int * yearNum = 0) const;
+
+ virtual QString monthName (int month, int year, bool shortName = false) const;
+ virtual QString monthName (const QDate & date, bool shortName = false ) const;
+ virtual QString monthNamePossessive(int month, int year, bool shortName = false) const;
+ virtual QString monthNamePossessive(const QDate & date, bool shortName = false ) const;
+ virtual QString weekDayName (int weekDay, bool shortName = false) const;
+ virtual QString weekDayName (const QDate & date, bool shortName = false) const;
+
+ virtual int minValidYear () const;
+ virtual int maxValidYear () const;
+ virtual int weekDayOfPray () const;
+
+ virtual QString calendarName() const;
+
+ virtual bool isLunar() const;
+ virtual bool isLunisolar() const;
+ virtual bool isSolar() const;
+
+ private:
+ /**
+ * Gets the number of days in a month for a given date
+ *
+ * @param month month number
+ * @param year given rear
+ * @return number of days in month
+ */
+ int hndays(int month, int year) const;
+
+ KCalendarSystemHijriPrivate * d;
+};
+
+#endif
diff --git a/kdecore/kcalendarsystemjalali.cpp b/kdecore/kcalendarsystemjalali.cpp
new file mode 100644
index 000000000..df8b5d0fa
--- /dev/null
+++ b/kdecore/kcalendarsystemjalali.cpp
@@ -0,0 +1,560 @@
+/*
+ Copyright (C) 2002-2003 Arash Bijanzadeh and FarsiKDE Project <www.farsikde.org>
+ Contact: Arash Bijanzadeh <a.bijanzadeh@linuxiran.org>
+
+ This program is part of FarsiKDE
+
+ FarsiKDE is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ FarsiKDE 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <math.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <stdio.h>
+
+#include "kcalendarsystemjalali.h"
+
+static const int gMonthDay[2][13]={
+ {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+};
+
+static const int jMonthDay[2][13] = {
+ {0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29},
+ {0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30},
+};
+
+typedef struct {
+ int day;
+ int mon;
+ int year;
+ } SDATE;
+// converting funcs from
+
+static int Ceil(float number)
+{
+ int ret;
+ if(number>0)
+ number += 0.5;
+ ret =(int) number;
+ return ret;
+}
+
+static long jalali_jdn(int year, int month, int day)
+{
+ const long PERSIAN_EPOCH = 1948321; /* The JDN of 1 Farvardin 1*/
+ int epbase;
+ long epyear;
+ long mdays;
+ long jdn;
+ epbase = year - 474;
+ epyear = 474 + (epbase % 2820);
+ if (month <= 7)
+ mdays = (month - 1) * 31;
+ else
+ mdays = (month - 1) * 30 + 6;
+ jdn = day + mdays ;
+ jdn += (((epyear * 682) - 110) / 2816) ;
+ jdn += (epyear - 1) * 365;
+ jdn += (epbase / 2820) * 1029983 ;
+ jdn += (PERSIAN_EPOCH - 1);
+ return jdn;
+}
+
+
+static SDATE jdn_jalali(long jdn)
+{
+ static SDATE ret;
+ int day, month, year;
+ int iYear, iMonth, iDay;
+ int depoch;
+ int cycle;
+ int cyear;
+ int ycycle;
+ int aux1, aux2;
+ int yday;
+ day = 1;
+ month = 1;
+ year = 475;
+ depoch = jdn - jalali_jdn(year,month, day);
+ cycle = (int) (depoch / 1029983);
+ cyear = depoch % 1029983;
+ if( cyear == 1029982)
+ ycycle = 2820;
+ else{
+ aux1 = cyear / 366;
+ aux2 = cyear % 366;
+ ycycle = (((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) + aux1 + 1;
+ }
+ iYear = ycycle + (2820 * cycle) + 474;
+ if (iYear <= 0)
+ iYear = iYear - 1;
+ year = iYear;
+ yday = (jdn - jalali_jdn(year, month, day)) + 1;
+ if(yday <= 186 )
+ iMonth = Ceil((yday-1) / 31);
+ else
+ iMonth = Ceil((yday - 7) / 30);
+ iMonth++;
+ month = iMonth;
+ iDay = (jdn - jalali_jdn(year, month, day)) + 1;
+ ret.day = iDay;
+ ret.mon = iMonth;
+ ret.year = iYear;
+ return ret;
+}
+
+
+
+static long civil_jdn(int year, int month, int day)
+{
+ long jdn = ((1461 * (year + 4800 + ((month - 14) / 12))) / 4)
+ + ((367 * (month - 2 - 12 * (((month - 14) / 12)))) / 12)
+ - ((3 * (((year + 4900 + ((month - 14) / 12)) / 100))) / 4)
+ + day - 32075;
+ return jdn;
+}
+
+static SDATE jdn_civil(long jdn)
+{
+ long l, n, i, j;
+ static SDATE ret;
+ int iday, imonth, iyear;
+ l = jdn + 68569;
+ n = ((4 * l) / 146097);
+ l = l - ((146097 * n + 3) / 4);
+ i = ((4000 * (l + 1)) / 1461001);
+ l = l - ((1461 * i) / 4) + 31;
+ j = ((80 * l) / 2447);
+ iday = l - ((2447 * j) / 80);
+ l = (j / 11);
+ imonth = j + 2 - 12 * l;
+ iyear = 100 * (n - 49) + i + l;
+ ret.day = iday;
+ ret.mon = imonth;
+ ret.year = iyear;
+ return (ret);
+}
+
+static SDATE *jalaliToGregorian(int y,int m,int d)
+{
+static SDATE sd;
+long jday = jalali_jdn(y,m,d);
+sd= jdn_civil(jday);
+return (&sd);
+}
+static SDATE *gregorianToJalali(int y,int m, int d)
+{
+ static SDATE sd;
+ long jdn = civil_jdn(y,m,d);//QDate::gregorianToJulian(y, m, d);
+ sd = jdn_jalali(jdn);
+ return(&sd);
+}
+static void gregorianToJalali(const QDate & date, int * pYear, int * pMonth,
+ int * pDay)
+{
+ SDATE *sd;
+ sd = gregorianToJalali(date.year(), date.month(), date.day());
+ if (pYear)
+ *pYear = sd->year;
+ if (pMonth)
+ *pMonth = sd->mon;
+ if (pDay)
+ *pDay = sd->day;
+
+}
+
+// End of converting functions
+
+static int isJalaliLeap(int year)
+{
+ int tmp;
+ tmp = year % 33;
+ if (tmp == 1 || tmp == 5||tmp==9||tmp==13||tmp==17||tmp==22||tmp==26||tmp==30)
+ return 1;
+else
+ return 0;
+}
+static int hndays(int m,int y)
+{
+ return jMonthDay[isJalaliLeap(y)][m];
+}
+
+
+KCalendarSystemJalali::KCalendarSystemJalali(const KLocale * locale)
+ : KCalendarSystem(locale)
+{
+}
+
+KCalendarSystemJalali::~KCalendarSystemJalali()
+{
+}
+
+int KCalendarSystemJalali::year(const QDate& date) const
+
+{
+ kdDebug(5400) << "Jalali year..." << endl;
+int y;
+ gregorianToJalali(date, &y, 0, 0);
+ return y;
+}
+
+int KCalendarSystemJalali::month (const QDate& date) const
+
+{
+ kdDebug(5400) << "Jalali month..." << endl;
+int m;
+ gregorianToJalali(date, 0 , &m, 0);
+ return m;
+}
+
+int KCalendarSystemJalali::day(const QDate& date) const
+
+{
+ kdDebug(5400) << "Jalali day..." << endl;
+int d;
+ gregorianToJalali(date, 0, 0, &d);
+ return d;
+}
+
+int KCalendarSystemJalali::dayOfWeek(const QDate& date) const
+{
+//same same I think?!
+ return date.dayOfWeek();
+
+}
+
+//NOT TESTED YET
+int KCalendarSystemJalali::dayOfYear(const QDate & date) const
+{
+ QDate first;
+ setYMD(first, year(date), 1, 1);
+
+ return first.daysTo(date) + 1;
+}
+
+//MAY BE BUGGY
+bool KCalendarSystemJalali::setYMD(QDate & date, int y, int m, int d) const
+{
+ // range checks
+ if ( y < minValidYear() || y > maxValidYear() )
+ return false;
+
+ if ( m < 1 || m > 12 )
+ return false;
+
+ if ( d < 1 || d > hndays(m, y) )
+ return false;
+
+ SDATE *gd =jalaliToGregorian( y, m, d);
+
+ return date.setYMD(gd->year, gd->mon, gd->day);
+}
+
+QDate KCalendarSystemJalali::addYears( const QDate & date, int nyears ) const
+{
+ QDate result = date;
+ int y = year(date) + nyears;
+ setYMD( result, y, month(date), day(date) );
+
+ return result;
+}
+
+QDate KCalendarSystemJalali::addMonths( const QDate & date, int nmonths ) const
+{
+ QDate result = date;
+ int m = month(date);
+ int y = year(date);
+
+ if ( nmonths < 0 )
+ {
+ m += 12;
+ y -= 1;
+ }
+
+ --m; // this only works if we start counting at zero
+ m += nmonths;
+ y += m / 12;
+ m %= 12;
+ ++m;
+
+ setYMD( result, y, m, day(date) );
+
+ return result;
+}
+
+QDate KCalendarSystemJalali::addDays( const QDate & date, int ndays ) const
+{
+ return date.addDays( ndays );
+}
+
+int KCalendarSystemJalali::monthsInYear( const QDate & date ) const
+{
+ Q_UNUSED( date )
+
+ return 12;
+}
+
+int KCalendarSystemJalali::daysInYear(const QDate & date) const
+{
+Q_UNUSED(date);
+int result;
+//SDATE *sd = gregorianToJalali(year(date),month(date),day(date));
+//if (isJalaliLeap(sd->year))
+ result=366;
+//else
+// result=365;
+return result;
+}
+
+int KCalendarSystemJalali::daysInMonth(const QDate & date) const
+{
+SDATE *sd = gregorianToJalali(date.year(),date.month(),date.day());
+return hndays(sd->mon,sd->year);
+}
+
+int KCalendarSystemJalali::weeksInYear(int year) const
+
+{
+ Q_UNUSED(year);
+// couldn't understand it!
+return 52;
+}
+
+int KCalendarSystemJalali::weekNumber(const QDate& date, int * yearNum) const
+{
+ QDate firstDayWeek1, lastDayOfYear;
+ int y = year(date);
+ int week;
+ int weekDay1, dayOfWeek1InYear;
+
+ // let's guess 1st day of 1st week
+ setYMD(firstDayWeek1, y, 1, 1);
+ weekDay1 = dayOfWeek(firstDayWeek1);
+
+ // iso 8601: week 1 is the first containing thursday and week starts on
+ // monday
+ if (weekDay1 > 4 /*Thursday*/)
+ firstDayWeek1 = addDays(firstDayWeek1 , 7 - weekDay1 + 1); // next monday
+
+ dayOfWeek1InYear = dayOfYear(firstDayWeek1);
+
+ if ( dayOfYear(date) < dayOfWeek1InYear ) // our date in prev year's week
+ {
+ if ( yearNum )
+ *yearNum = y - 1;
+ return weeksInYear(y - 1);
+ }
+ // let' check if its last week belongs to next year
+ setYMD(lastDayOfYear, y, 12, hndays(12, y));
+ if ( (dayOfYear(date) >= daysInYear(date) - dayOfWeek(lastDayOfYear) + 1)
+ // our date is in last week
+ && dayOfWeek(lastDayOfYear) < 4) // 1st week in next year has thursday
+ {
+ if ( yearNum )
+ *yearNum = y + 1;
+ week = 1;
+ }
+ else
+ week = firstDayWeek1.daysTo(date) / 7 + 1;
+
+ return week;
+}
+
+QString KCalendarSystemJalali::monthName(int month, int year, bool shortName)
+ const
+{
+ Q_UNUSED(year);
+
+ if (shortName)
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("Far");
+ case 2:
+ return locale()->translate("Ord");
+ case 3:
+ return locale()->translate("Kho");
+ case 4:
+ return locale()->translate("Tir");
+ case 5:
+ return locale()->translate("Mor");
+ case 6:
+ return locale()->translate("Sha");
+ case 7:
+ return locale()->translate("Meh");
+ case 8:
+ return locale()->translate("Aba");
+ case 9:
+ return locale()->translate("Aza");
+ case 10:
+ return locale()->translate("Dei");
+ case 11:
+ return locale()->translate("Bah");
+ case 12:
+ return locale()->translate("Esf");
+ }
+ else
+ switch ( month )
+ {
+ case 1:
+ return locale()->translate("Farvardin");
+ case 2:
+ return locale()->translate("Ordibehesht");
+ case 3:
+ return locale()->translate("Khordad");
+ case 4:
+ return locale()->translate("Tir");
+ case 5:
+ return locale()->translate("Mordad");
+ case 6:
+ return locale()->translate("Shahrivar");
+ case 7:
+ return locale()->translate("Mehr");
+ case 8:
+ return locale()->translate("Aban");
+ case 9:
+ return locale()->translate("Azar");
+ case 10:
+ return locale()->translate("Dei");
+ case 11:
+ return locale()->translate("Bahman");
+ case 12:
+ return locale()->translate("Esfand");
+ }
+
+ return QString::null;
+}
+
+QString KCalendarSystemJalali::monthName(const QDate& date, bool shortName)
+ const
+{
+ int mon;
+ gregorianToJalali(date,0,&mon,0);
+ //SDATE *sd = gregorianToJalali(date.year(),date.month(),date.day());
+ return (monthName(mon, 0, shortName));
+}
+
+QString KCalendarSystemJalali::monthNamePossessive(const QDate& date,
+ bool shortName ) const
+{
+ return monthName(date,shortName);
+}
+
+QString KCalendarSystemJalali::monthNamePossessive(int month, int year,
+ bool shortName ) const
+{
+ return monthName(month,year,shortName);
+}
+
+
+QString KCalendarSystemJalali::weekDayName(int day, bool shortName) const
+{
+ if ( shortName )
+ switch (day)
+ {
+ case 1:
+ return locale()->translate("2sh");
+ case 2:
+ return locale()->translate("3sh");
+ case 3:
+ return locale()->translate("4sh");
+ case 4:
+ return locale()->translate("5sh");
+ case 5:
+ return locale()->translate("Jom");
+ case 6:
+ return locale()->translate("shn");
+ case 7:
+ return locale()->translate("1sh");
+ }
+ else
+ switch ( day )
+ {
+ case 1:
+ return locale()->translate("Do shanbe");
+ case 2:
+ return locale()->translate("Se shanbe");
+ case 3:
+ return locale()->translate("Chahar shanbe");
+ case 4:
+ return locale()->translate("Panj shanbe");
+ case 5:
+ return locale()->translate("Jumee");
+ case 6:
+ return locale()->translate("Shanbe");
+ case 7:
+ return locale()->translate("Yek-shanbe");
+ }
+
+ return QString::null;
+}
+
+QString KCalendarSystemJalali::weekDayName(const QDate &date,bool shortName)
+ const
+{
+ return weekDayName(dayOfWeek(date), shortName);
+}
+
+// Min valid year that may be converted to QDate
+int KCalendarSystemJalali::minValidYear() const
+{
+ QDate date(1753, 1, 1);
+
+ return year(date);
+}
+
+// Max valid year that may be converted to QDate
+int KCalendarSystemJalali::maxValidYear() const
+{
+/*
+ QDate date(8000, 1, 1);
+
+ SDATE *sd = toJalali(date);
+
+ return sd->year;
+ */
+ return 10000;
+}
+int KCalendarSystemJalali::weekDayOfPray() const
+{
+ return 5; // friday
+}
+QString KCalendarSystemJalali::calendarName() const
+{
+ return QString::fromLatin1("jalali");
+}
+
+bool KCalendarSystemJalali::isLunar() const
+{
+ return false;
+}
+
+bool KCalendarSystemJalali::isLunisolar() const
+{
+ return false;
+}
+
+bool KCalendarSystemJalali::isSolar() const
+{
+ return true;
+}
diff --git a/kdecore/kcalendarsystemjalali.h b/kdecore/kcalendarsystemjalali.h
new file mode 100644
index 000000000..ae24c1446
--- /dev/null
+++ b/kdecore/kcalendarsystemjalali.h
@@ -0,0 +1,83 @@
+#ifndef KCALENDARSYSTEMJALALI_H
+#define KCALENDARSYSTEMJALALI_H
+
+
+/*
+ Copyright (C) 2002-2003 Arash Bijanzadeh and FarsiKDE Project <www.farsikde.org>
+ Contact: Arash Bijanzadeh <a.bijanzadeh@linuxiran.org>
+
+ This program is part of FarsiKDE
+
+ FarsiKDE is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ FarsiKDE 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+#include "kcalendarsystem.h"
+
+class KCalendarSystemJalaliPrivate;
+/**
+ Jalali calendar type implementation
+*/
+class KDECORE_EXPORT KCalendarSystemJalali : public KCalendarSystem
+{
+public:
+ /** Constructor. Just like KCalendarSystem::KCalendarSystem(). */
+ KCalendarSystemJalali(const KLocale * locale = 0);
+ virtual ~KCalendarSystemJalali();
+
+
+
+ virtual int year (const QDate & date) const;
+ virtual int month (const QDate & date) const;
+ virtual int day (const QDate & date) const;
+ virtual int dayOfWeek (const QDate & date) const;
+ virtual int dayOfYear (const QDate & date) const;
+
+ virtual bool setYMD(QDate & date, int y, int m, int d) const;
+
+ virtual QDate addYears(const QDate & date, int nyears) const;
+ virtual QDate addMonths(const QDate & date, int nmonths) const;
+ virtual QDate addDays(const QDate & date, int ndays) const;
+
+ virtual int monthsInYear (const QDate & date) const;
+
+ virtual int daysInYear (const QDate & date) const;
+ virtual int daysInMonth (const QDate & date) const;
+ virtual int weeksInYear(int year) const;
+ virtual int weekNumber(const QDate& date, int * yearNum = 0) const;
+
+ virtual QString monthName (const QDate & date, bool shortName = false ) const;
+ virtual QString monthNamePossessive(const QDate & date, bool shortName = false ) const;
+ virtual QString weekDayName (int weekDay, bool shortName = false) const;
+ virtual QString weekDayName (const QDate & date, bool shortName = false) const;
+ virtual QString monthNamePossessive(int month, int year, bool shortName = false) const;
+ virtual QString monthName(int month, int year, bool shortName = false) const;
+
+ virtual int minValidYear () const;
+ virtual int maxValidYear () const;
+ virtual int weekDayOfPray () const;
+
+ virtual QString calendarName() const;
+
+ virtual bool isLunar() const;
+ virtual bool isLunisolar() const;
+ virtual bool isSolar() const;
+
+};
+
+#endif
diff --git a/kdecore/kcatalogue.cpp b/kdecore/kcatalogue.cpp
new file mode 100644
index 000000000..d5e566db2
--- /dev/null
+++ b/kdecore/kcatalogue.cpp
@@ -0,0 +1,157 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2001 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <qfile.h>
+
+#include <kdebug.h>
+
+#include "kcatalogue.h"
+#include "kstandarddirs.h"
+
+char *k_nl_find_msg(struct kde_loaded_l10nfile *domain_file,
+ const char *msgid);
+void k_nl_unload_domain (struct loaded_domain *domain);
+
+#ifndef KDE_USE_FINAL // with --enable-final, we're getting this from libintl.cpp
+struct kde_loaded_l10nfile
+{
+ const char *filename;
+ int decided;
+
+ const void *data;
+
+ kde_loaded_l10nfile() : filename(0), decided(0), data(0) {}
+};
+#endif
+
+class KCataloguePrivate
+{
+public:
+ QString name;
+ QString language;
+ int pluralType;
+
+ kde_loaded_l10nfile domain;
+};
+
+KCatalogue::KCatalogue(const QString & name, const QString & language )
+ : d( new KCataloguePrivate )
+{
+ d->name = name;
+ d->language = language;
+ // at the moment we do not know more. To find out the plural type we first have to look into
+ // kdelibs.mo for the language. And for this we already need a catalog object. So this data
+ // has to be set after we have the first catalog objects.
+ d->pluralType = -1;
+
+ QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
+ .arg( d->language )
+ .arg( d->name );
+
+ setFileName( locate( "locale", path ) );
+
+}
+
+KCatalogue::KCatalogue(const KCatalogue & rhs)
+ : d( new KCataloguePrivate )
+{
+ *this = rhs;
+}
+
+KCatalogue & KCatalogue::operator=(const KCatalogue & rhs)
+{
+ d->name = rhs.d->name;
+ d->language = rhs.d->language;
+ d->pluralType = rhs.d->pluralType;
+ setFileName( rhs.fileName() );
+
+ return *this;
+}
+
+KCatalogue::~KCatalogue()
+{
+ doUnload();
+
+ delete d;
+}
+
+QString KCatalogue::name() const
+{
+ return d->name;
+}
+
+QString KCatalogue::language() const
+{
+ return d->language;
+}
+
+void KCatalogue::setPluralType( int pluralType)
+{
+ d->pluralType = pluralType;
+}
+
+int KCatalogue::pluralType() const
+{
+ return d->pluralType;
+}
+
+
+void KCatalogue::setFileName( const QString & fileName )
+{
+ // nothing to do if the file name is already the same
+ if ( this->fileName() == fileName ) return;
+
+ doUnload();
+
+ QCString newFileName = QFile::encodeName( fileName );
+
+ if ( !fileName.isEmpty() )
+ {
+ // set file name
+ char *filename = new char[ newFileName.length() + 1 ];
+ ::qstrcpy( filename, newFileName );
+ d->domain.filename = filename;
+ }
+}
+
+QString KCatalogue::fileName() const
+{
+ return QFile::decodeName( d->domain.filename );
+}
+
+const char * KCatalogue::translate(const char * msgid) const
+{
+ return ::k_nl_find_msg( &d->domain, msgid );
+}
+
+void KCatalogue::doUnload()
+{
+ // use gettext's unloader
+ if ( d->domain.data )
+ ::k_nl_unload_domain( (struct loaded_domain *)d->domain.data );
+ d->domain.data = 0;
+
+ // free name
+ delete [] const_cast<char *>(d->domain.filename);
+ d->domain.filename = 0;
+
+ d->domain.decided = 0;
+}
diff --git a/kdecore/kcatalogue.h b/kdecore/kcatalogue.h
new file mode 100644
index 000000000..38c067711
--- /dev/null
+++ b/kdecore/kcatalogue.h
@@ -0,0 +1,129 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2001 Hans Petter Bieker <bieker@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCATALOGUE_H
+#define KCATALOGUE_H
+
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+struct kde_loaded_l10nfile;
+
+class KCataloguePrivate;
+
+/**
+ * This class abstracts a gettext message catalog. It will take care of
+ * opening the file and reading the catalog.
+ *
+ * @see KLocale
+ */
+//REVISED: hausmann
+class KDECORE_EXPORT KCatalogue
+{
+public:
+ /**
+ * Constructor.
+ *
+ * @param name The name of the catalog
+ * @param language The language of this catalog
+ */
+ explicit KCatalogue(const QString & name = QString::null, const QString & language = QString::null);
+
+ /**
+ * Copy constructor.
+ */
+ KCatalogue(const KCatalogue & rhs);
+
+ /**
+ * Assignment operator.
+ */
+ KCatalogue & operator = ( const KCatalogue & rhs);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KCatalogue();
+
+ /**
+ * Returns the name of the catalog.
+ *
+ * @return The name of the catalog
+ */
+ QString name() const;
+
+ /**
+ * Returns the language of the catalog.
+ *
+ * @return The language of the catalog
+ */
+ QString language() const;
+
+ /**
+ * Returns the plural type for the catalog. This type is based on the language of the catalog
+ and is cached for performance.
+ *
+ * @return The plural type for the catalog
+ */
+ int pluralType() const;
+
+ /**
+ * Sets the plural type for the catalog. The caller has probably looked it up in a kdelibs.mo-catalog
+ * for the appropriate language
+ *
+ * @return The plural type for the catalog
+ */
+ void setPluralType( int pluralType );
+
+
+ /**
+ * Retrieves a translation of the specified message id.
+ *
+ * Do not pass 0 or "" strings as message ids.
+ *
+ * @param msgid The message id
+ *
+ * @return The translated message, in utf8 encoding, or 0 if not found
+ */
+ const char * translate( const char * msgid ) const;
+
+private:
+ /**
+ * @internal Changes the current file name.
+ *
+ * @param fileName The new file name
+ */
+
+ void setFileName( const QString & fileName );
+ /**
+ * @internal Retrieves the current file name.
+ *
+ * @return The current file name, if any.
+ */
+ QString fileName() const;
+
+ /**
+ * @internal Unloads the current file.
+ */
+ void doUnload();
+
+private:
+ KCataloguePrivate * d;
+};
+
+#endif
diff --git a/kdecore/kcharsets.cpp b/kdecore/kcharsets.cpp
new file mode 100644
index 000000000..1ac3fa94d
--- /dev/null
+++ b/kdecore/kcharsets.cpp
@@ -0,0 +1,664 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "kcharsets.h"
+
+#include "kqiodevicegzip_p.h"
+#include "kentities.c"
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+
+#include <qfontinfo.h>
+#include <qstrlist.h>
+#include <qfontdatabase.h>
+#include <kdebug.h>
+
+#include <qtextcodec.h>
+#include <qmap.h>
+#include <qcstring.h>
+#include <qdir.h>
+#include <qregexp.h>
+
+#include <assert.h>
+
+static const char * const language_names[] = {
+ I18N_NOOP( "Other" ),
+ I18N_NOOP( "Arabic" ),
+ I18N_NOOP( "Baltic" ),
+ I18N_NOOP( "Central European" ),
+ I18N_NOOP( "Chinese Simplified" ),
+ I18N_NOOP( "Chinese Traditional" ),
+ I18N_NOOP( "Cyrillic" ),
+ I18N_NOOP( "Greek" ),
+ I18N_NOOP( "Hebrew" ),
+ I18N_NOOP( "Japanese" ),
+ I18N_NOOP( "Korean" ),
+ I18N_NOOP( "Thai" ),
+ I18N_NOOP( "Turkish" ),
+ I18N_NOOP( "Western European" ),
+ I18N_NOOP( "Tamil" ),
+ I18N_NOOP( "Unicode" ),
+ I18N_NOOP( "Northern Saami" ),
+ I18N_NOOP( "Vietnamese" ),
+ I18N_NOOP( "South-Eastern Europe" )
+};
+
+// This list gives the charsets that can be used to display a file given in a certain encoding.
+// The list should be in order of preference
+static const char* const charsets_for_encoding[] = {
+ "koi8-r",
+ "koi8-u",
+ "iso 8859-1",
+ "iso 8859-2",
+ "iso 8859-3",
+ "iso 8859-4",
+ "iso 8859-5",
+ "iso 8859-6",
+ "iso 8859-7",
+ "iso 8859-8",
+ "iso 8859-8-i",
+ "iso 8859-9",
+ "iso 8859-11",
+ "iso 8859-13",
+ "iso 8859-14",
+ "iso 8859-15",
+ "iso 8859-16",
+ "utf8",
+ "utf16",
+ "iso-10646-ucs-2",
+ "cp 1250",
+ "cp 1251",
+ "cp 1252",
+ "cp 1253",
+ "cp 1254",
+ "cp 1255",
+ "cp 1256",
+ "cp 1257",
+ "cp 1258",
+ "ibm850",
+ "ibm852",
+ "ibm866",
+ "tis620",
+ "eucjp",
+ "sjis",
+ "jis7",
+ "big5",
+ "big5-hkscs",
+ "gbk",
+ "gb18030",
+ "gb2312",
+ "euckr",
+ "tscii",
+// "pt 154",
+ "winsami2",
+ "cp 874",
+ 0 }; // extra 0 for end
+
+// 0 other
+// 1 Arabic
+// 2 Baltic
+// 3 Central European
+// 4 Chinese Simplified
+// 5 Chinese Traditional
+// 6 Cyrillic
+// 7 Greek
+// 8 Hebrew
+// 9 Japanese
+// 10 Korean
+// 11 Thai
+// 12 Turkish
+// 13 Western European
+// 14 Tamil
+// 15 Unicode
+// 16 Northern Sami
+// 17 Vietnamese
+// 18 South-Eastern Europe
+// ### FIXME KDE4: the name of the encodings should mostly be uppercase
+static struct LanguageForEncoding
+ {
+ const char* index;
+ int data;
+ } const language_for_encoding[] = {
+ { "iso 8859-1", 13 },
+ { "iso 8859-15", 13 },
+ { "iso 8859-14", 13 },
+ { "cp 1252", 13 },
+ { "ibm850", 13 },
+ { "iso 8859-2", 3 },
+ { "iso 8859-3", 3 },
+ { "iso 8859-4", 2 },
+ { "iso 8859-13", 2 },
+ { "iso 8859-16", 18 },
+ { "cp 1250", 3 },
+ { "cp 1254", 12 },
+ { "cp 1257", 2 },
+ { "ibm852", 3 },
+ { "koi8-r", 6 },
+ { "iso 8859-5", 6 },
+ { "cp 1251", 6 },
+ { "koi8-u", 6 },
+// { "pt 154", 6 },
+ { "ibm866", 6 },
+ { "big5", 5 },
+ { "big5-hkscs", 5 },
+ { "gb18030", 4 },
+ { "gbk", 4 },
+ { "gb2312", 4 },
+ { "euckr", 10 },
+ { "sjis", 9 },
+ { "jis7", 9 },
+ { "eucjp", 9 },
+ { "iso 8859-7", 7 },
+ { "cp 1253", 7 },
+ { "iso 8859-6", 1 },
+ { "cp 1256", 1 },
+ { "iso 8859-8", 8 },
+ { "iso 8859-8-i", 8 },
+ { "cp 1255", 8 },
+ { "iso 8859-9", 12 },
+ { "tis620", 11 },
+ { "iso 8859-11", 11 },
+ { "cp 874", 11 },
+ { "cp 1258", 17 },
+ { "tscii", 14 },
+ { "utf8", 15 },
+ { "utf16", 15 },
+ { "utf7", 15 }, // ### FIXME: UTF-7 is not in Qt
+ { "ucs2", 15 },
+ { "iso-10646-ucs-2", 15 },
+ { "winsami2", 16},
+ { 0, 0 } };
+
+// defines some different names for codecs that are built into Qt.
+static struct Builtin
+ {
+ const char* index;
+ const char* data;
+ } const builtin[] = {
+ { "iso-ir-111", "koi8-r" },
+ { "koi8-ru", "koi8-u" }, // ### Qt 3.3 maps it to koi8-r
+ { "koi unified", "koi8-r" }, // ### FIXME: Qt 3.3 seems to map this to EUC-KR, so this mapping is too late :-(
+ // Using ISO-8859-1 for ASCII is an approximation at write
+ { "us-ascii", "iso 8859-1" },
+ { "usascii", "iso 8859-1" },
+ { "ascii", "iso 8859-1" },
+ { "x-utf-8", "utf-8" },
+ { "x-utf-7", "utf-7" }, // ### FIXME: UTF-7 is not in Qt
+ { "unicode-1-1-utf-7", "utf-7" }, // ### FIXME: UTF-7 is not in Qt
+ { "utf-16", "iso-10646-ucs-2" },
+ { "utf16", "iso-10646-ucs-2" },
+ { "ucs2", "iso-10646-ucs-2" },
+ { "iso10646-1", "iso-10646-ucs-2" },
+ { "gb18030.2000-1", "gb18030" },
+ { "gb18030.2000-0", "gb18030" },
+ { "gbk-0", "gbk" },
+ { "gb2312.1980-0", "gbk" },
+ { "gb_2312-80", "gbk" },/* this one is not official, but MS is using it :/ */
+ { "x-euc-kr", "euckr" },
+ { "jisx0201.1976-0", "eucjp" },
+ { "jisx0208.1983-0", "eucjp" },
+ { "jisx0208.1990-0", "eucjp" },
+ { "jisx0208.1997-0", "eucjp" },
+ { "jisx0212.1990-0", "eucjp" },
+ { "jisx0213.2000-1", "eucjp" },
+ { "jisx0213.2000-2", "eucjp" },
+ { "windows850", "ibm850" },
+ { "windows866", "ibm866" },
+ { "windows1251", "cp 1251" },
+ { "windows1252", "cp 1252" },
+ { "windows1253", "cp 1253" },
+ { "windows1254", "cp 1254" },
+ { "windows1255", "cp 1255" },
+ { "windows1256", "cp 1256" },
+ { "windows1257", "cp 1257" },
+ { "windows1258", "cp 1258" },
+ { "windows-850", "ibm850" },
+ { "windows-866", "ibm866" },
+ { "x-windows-850", "ibm850" },
+ { "x-windows-866", "ibm866" },
+ { "x-windows-1250", "cp 1250" },
+ { "x-windows-1251", "cp 1251" },
+ { "x-windows-1252", "cp 1252" },
+ { "x-windows-1253", "cp 1253" },
+ { "x-windows-1254", "cp 1254" },
+ { "x-windows-1255", "cp 1255" },
+ { "x-windows-1256", "cp 1256" },
+ { "x-windows-1257", "cp 1257" },
+ { "x-windows-1258", "cp 1258" },
+ { "cp819", "iso 8859-1" },
+ { "cp850", "ibm850" },
+ { "cp866", "ibm866" },
+ { "cp-819", "iso 8859-1" },
+ { "cp-850", "ibm850" },
+ { "cp-866", "ibm866" },
+ { "cp-1250", "cp 1250" },
+ { "cp-1251", "cp 1251" },
+ { "cp-1252", "cp 1252" },
+ { "cp-1253", "cp 1253" },
+ { "cp-1254", "cp 1254" },
+ { "cp-1255", "cp 1255" },
+ { "cp-1256", "cp 1256" },
+ { "cp-1257", "cp 1257" },
+ { "cp-1258", "cp 1258" },
+ { "cp-10000", "apple roman" },
+ { "x-cp-850", "ibm850" },
+ { "x-cp-866", "ibm866" },
+ { "x-cp-1250", "cp 1250" },
+ { "x-cp-1251", "cp 1251" },
+ { "x-cp-1252", "cp 1252" },
+ { "x-cp-1253", "cp 1253" },
+ { "x-cp-1254", "cp 1254" },
+ { "x-cp-1255", "cp 1255" },
+ { "x-cp-1256", "cp 1256" },
+ { "x-cp-1257", "cp 1257" },
+ { "x-cp-1258", "cp 1258" },
+ { "x-cp-10000", "apple roman" },
+ { "ibm819", "iso 8859-1" },
+ { "thai-tis620", "iso 8859-11" },
+ { "windows-874", "cp 874" },
+ { "windows874", "cp 874" },
+ { "x-windows-874", "cp 874" },
+ { "x-cp-874", "cp 874" },
+ { "ibm 874", "cp 874" },
+ { "ibm874", "cp 874" }, // Qt4 name
+ { "x-ibm874", "cp 874" },
+ { "ksc5601.1987-0", "euckr" },
+ { "x-winsami2", "winsami2" },
+ { "x-mac-roman", "apple roman" },
+ { "macintosh", "apple roman" },
+ { "mac", "apple roman" },
+ { "csiso2022jp", "jis7" }, // See bug #77243
+ { "big5-eten", "big5-hkscs" },
+ { "cp950", "big5-hkscs" },
+ { 0, 0 }};
+
+// some different names for the encodings defined in the charmaps files.
+// even though the charmap file names are all uppercase, the names are all lowercase here.
+static struct Aliases
+ {
+ const char* index;
+ const char* data;
+ } const aliases[] = {
+ { "cp852", "ibm852" },
+ { "cp-852", "ibm852" },
+ { "x-cp-852", "ibm852" },
+ { "windows852", "ibm852" },
+ { "windows-852", "ibm852" },
+ { "x-windows-852", "ibm852" },
+ { 0, 0 }};
+
+// some last resort hints in case the charmap file couldn't be found. This gives at least a partial conversion
+// and helps making things readable.
+// the name used as input here is already converted to the more canonical name as defined in the aliases array.
+static struct ConversionHints
+ {
+ const char* index;
+ const char* data;
+ } const conversion_hints[] = {
+ { "cp1250", "iso-8859-2" },
+ { "koi8-r", "iso-8859-5" },
+ { "koi8-u", "koi8-r" },
+ // KDE had always "CP 1251" as best fallback to PT 154. Now that Qt does not offer this encoding anymore, it is our fallback.
+ { "pt 154", "cp 1251" },
+ { "paratype-154", "cp 1251" },
+ { "pt-154", "cp 1251" },
+ { 0, 0 }};
+
+
+// search an array of items index/data, index is const char*, data is T, find first matching index
+// and return data, or return 0
+template< typename T, typename Data >
+static Data kcharsets_array_search( const T* start, const char* entry )
+{
+ for( const T* pos = start;
+ pos->index != 0;
+ ++pos )
+ if( qstrcmp( pos->index, entry ) == 0 )
+ return pos->data;
+ return 0;
+}
+
+
+class KCharsetsPrivate
+{
+public:
+ KCharsetsPrivate(KCharsets* _kc)
+ : codecForNameDict(43, false) // case insensitive
+ {
+ db = 0;
+ kc = _kc;
+ }
+ ~KCharsetsPrivate()
+ {
+ delete db;
+ }
+ QFontDatabase *db;
+ QAsciiDict<QTextCodec> codecForNameDict;
+ KCharsets* kc;
+};
+
+// --------------------------------------------------------------------------
+
+KCharsets::KCharsets()
+{
+ d = new KCharsetsPrivate(this);
+}
+
+KCharsets::~KCharsets()
+{
+ delete d;
+}
+
+QChar KCharsets::fromEntity(const QString &str)
+{
+ QChar res = QChar::null;
+
+ int pos = 0;
+ if(str[pos] == '&') pos++;
+
+ // Check for '&#000' or '&#x0000' sequence
+ if (str[pos] == '#' && str.length()-pos > 1) {
+ bool ok;
+ pos++;
+ if (str[pos] == 'x' || str[pos] == 'X') {
+ pos++;
+ // '&#x0000', hexadeciaml character reference
+ QString tmp(str.unicode()+pos, str.length()-pos);
+ res = tmp.toInt(&ok, 16);
+ } else {
+ // '&#0000', decimal character reference
+ QString tmp(str.unicode()+pos, str.length()-pos);
+ res = tmp.toInt(&ok, 10);
+ }
+ return res;
+ }
+
+ const entity *e = kde_findEntity(str.ascii(), str.length());
+
+ if(!e)
+ {
+ //kdDebug( 0 ) << "unknown entity " << str <<", len = " << str.length() << endl;
+ return QChar::null;
+ }
+ //kdDebug() << "got entity " << str << " = " << e->code << endl;
+
+ return QChar(e->code);
+}
+
+QChar KCharsets::fromEntity(const QString &str, int &len)
+{
+ // entities are never longer than 8 chars... we start from
+ // that length and work backwards...
+ len = 8;
+ while(len > 0)
+ {
+ QString tmp = str.left(len);
+ QChar res = fromEntity(tmp);
+ if( res != QChar::null ) return res;
+ len--;
+ }
+ return QChar::null;
+}
+
+
+QString KCharsets::toEntity(const QChar &ch)
+{
+ QString ent;
+ ent.sprintf("&#0x%x;", ch.unicode());
+ return ent;
+}
+
+QString KCharsets::resolveEntities( const QString &input )
+{
+ QString text = input;
+ const QChar *p = text.unicode();
+ const QChar *end = p + text.length();
+ const QChar *ampersand = 0;
+ bool scanForSemicolon = false;
+
+ for ( ; p < end; ++p ) {
+ const QChar ch = *p;
+
+ if ( ch == '&' ) {
+ ampersand = p;
+ scanForSemicolon = true;
+ continue;
+ }
+
+ if ( ch != ';' || scanForSemicolon == false )
+ continue;
+
+ assert( ampersand );
+
+ scanForSemicolon = false;
+
+ const QChar *entityBegin = ampersand + 1;
+
+ const uint entityLength = p - entityBegin;
+ if ( entityLength == 0 )
+ continue;
+
+ const QChar entityValue = KCharsets::fromEntity( QConstString( entityBegin, entityLength ).string() );
+ if ( entityValue.isNull() )
+ continue;
+
+ const uint ampersandPos = ampersand - text.unicode();
+
+ text[ (int)ampersandPos ] = entityValue;
+ text.remove( ampersandPos + 1, entityLength + 1 );
+ p = text.unicode() + ampersandPos;
+ end = text.unicode() + text.length();
+ ampersand = 0;
+ }
+
+ return text;
+}
+
+QStringList KCharsets::availableEncodingNames()
+{
+ QStringList available;
+ for ( const char* const* pos = charsets_for_encoding; *pos; ++pos ) {
+ //kdDebug(0) << *charsets << " available" << endl;
+ available.append( QString::fromLatin1( *pos ));
+ }
+ return available;
+}
+
+QString KCharsets::languageForEncoding( const QString &encoding )
+{
+ int lang = kcharsets_array_search< LanguageForEncoding, int >
+ ( language_for_encoding, encoding.latin1());
+ return i18n( language_names[lang] );
+}
+
+QString KCharsets::encodingForName( const QString &descriptiveName )
+{
+ const int left = descriptiveName.findRev( '(' );
+
+ if (left<0) // No parenthesis, so assume it is a normal encoding name
+ return descriptiveName.stripWhiteSpace();
+
+ QString name(descriptiveName.mid(left+1));
+
+ const int right = name.findRev( ')' );
+
+ if (right<0)
+ return name;
+
+ return name.left(right).stripWhiteSpace();
+}
+
+QStringList KCharsets::descriptiveEncodingNames()
+{
+ // As we are sorting, we can directly read the array language_for_encoding
+ QStringList encodings;
+ for ( const LanguageForEncoding* pos = language_for_encoding; pos->index; ++pos ) {
+ const QString name = QString::fromLatin1( pos->index );
+ const QString description = i18n( language_names[ pos->data ] );
+ encodings.append( i18n("Descriptive Encoding Name", "%1 ( %2 )"). arg ( description ). arg( name ) );
+ }
+ encodings.sort();
+ return encodings;
+}
+
+QTextCodec *KCharsets::codecForName(const QString &n) const
+{
+ bool b;
+ return codecForName( n, b );
+}
+
+QTextCodec *KCharsets::codecForName(const QString &n, bool &ok) const
+{
+ ok = true;
+
+ QTextCodec* codec = 0;
+ // dict lookup is case insensitive anyway
+ if((codec = d->codecForNameDict[n.isEmpty() ? "->locale<-" : n.latin1()]))
+ return codec; // cache hit, return
+
+ if (n.isEmpty()) {
+ codec = KGlobal::locale()->codecForEncoding();
+ d->codecForNameDict.replace("->locale<-", codec);
+ return codec;
+ }
+
+ QCString name = n.lower().latin1();
+ QCString key = name;
+ if (name.right(8) == "_charset")
+ name.truncate(name.length()-8);
+
+ if (name.isEmpty()) {
+ ok = false;
+ return QTextCodec::codecForName("iso8859-1");
+ }
+
+ codec = QTextCodec::codecForName(name);
+
+ if(codec) {
+ d->codecForNameDict.replace(key, codec);
+ return codec;
+ }
+
+ // these codecs are built into Qt, but the name given for the codec is different,
+ // so QTextCodec did not recognize it.
+ QCString cname = kcharsets_array_search< Builtin, const char* >( builtin, name.data());
+
+ if(!cname.isEmpty())
+ codec = QTextCodec::codecForName(cname);
+
+ if(codec)
+ {
+ d->codecForNameDict.replace(key, codec);
+ return codec;
+ }
+
+ QString dir;
+ {
+ KConfigGroupSaver cfgsav( KGlobal::config(), "i18n" );
+ dir = KGlobal::config()->readPathEntry("i18ndir", QString::fromLatin1("/usr/share/i18n/charmaps"));
+ }
+
+ // these are codecs not included in Qt. They can be build up if the corresponding charmap
+ // is available in the charmap directory.
+ cname = kcharsets_array_search< Aliases, const char* >( aliases, name.data());
+
+ if(cname.isEmpty())
+ cname = name;
+ cname = cname.upper();
+
+ const QString basicName = QString::fromLatin1(cname);
+ kdDebug() << k_funcinfo << endl << " Trying to find " << cname << " in " << dir << endl;
+
+ QString charMapFileName;
+ bool gzipped = false;
+ QDir qdir(dir);
+ if (!qdir.exists()) {
+ // The directory for the charmaps does not even exist... (That is common!)
+ }
+ else if (qdir.exists(basicName, false)) {
+ charMapFileName = basicName;
+ }
+ else if (qdir.exists(basicName+".gz", false)) {
+ charMapFileName = basicName + ".gz";
+ gzipped = true;
+ }
+ else {
+ // Check if we are asking a code page
+ // If yes, then check "CP99999" and "IBM99999"
+ // First we need to find the number of the codepage
+ QRegExp regexp("^(X-)?(CP|IBM)(-| )?(0-9)+");
+ if ( regexp.search(basicName) != -1) {
+ const QString num = regexp.cap(4);
+ if (num.isEmpty()) {
+ // No number, not a code page (or something went wrong)
+ }
+ else if (qdir.exists("IBM"+num)) {
+ charMapFileName = "IBM"+num;
+ }
+ else if (qdir.exists("IBM"+num+".gz")) {
+ charMapFileName = "IBM"+num+".gz";
+ gzipped = true;
+ }
+ else if (qdir.exists("CP"+num)) {
+ charMapFileName = "CP"+num;
+ }
+ else if (qdir.exists("CP"+num+".gz")) {
+ charMapFileName = "CP"+num+".gz";
+ gzipped = true;
+ }
+ }
+ }
+
+ if (gzipped && !charMapFileName.isEmpty()) {
+ KQIODeviceGZip gzip(dir + "/" + charMapFileName);
+ if (gzip.open(IO_ReadOnly)) {
+ kdDebug() << "Loading gzipped charset..." << endl;
+ codec = QTextCodec::loadCharmap(&gzip);
+ gzip.close();
+ }
+ else
+ kdWarning() << "Could not open gzipped charset!" << endl;
+ }
+ else if (!charMapFileName.isEmpty()) {
+ codec = QTextCodec::loadCharmapFile(dir + "/" + charMapFileName);
+ }
+
+ if(codec) {
+ d->codecForNameDict.replace(key, codec);
+ return codec;
+ }
+
+ // this also failed, the last resort is now to take some compatibility charmap
+
+ cname = kcharsets_array_search< ConversionHints, const char* >( conversion_hints, (const char*)name.data() );
+
+ if(!cname.isEmpty())
+ codec = QTextCodec::codecForName(cname);
+
+ if(codec) {
+ d->codecForNameDict.replace(key, codec);
+ return codec;
+ }
+
+ // could not assign a codec, let's return Latin1
+ ok = false;
+ return QTextCodec::codecForName("iso8859-1");
+}
diff --git a/kdecore/kcharsets.h b/kdecore/kcharsets.h
new file mode 100644
index 000000000..fe9bb3140
--- /dev/null
+++ b/kdecore/kcharsets.h
@@ -0,0 +1,142 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KCHARSETS_H
+#define KCHARSETS_H
+
+#include <qstring.h>
+#include <qfont.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include "kdelibs_export.h"
+
+class KGlobal;
+class KCharsetsPrivate;
+
+class QTextCodec;
+
+/**
+ * Charset font and encoder/decoder handling.
+ *
+ * This is needed, because Qt's font matching algorithm gives the font
+ * family a higher priority than the charset. For many applications
+ * this is not acceptable, since it can totally obscure the output,
+ * in languages which use non iso-8859-1 charsets.
+ *
+ * @author Lars Knoll <knoll@kde.org>
+ */
+class KDECORE_EXPORT KCharsets
+{
+ friend class KGlobal;
+
+protected:
+ /** Protected constructor. If you need the kcharsets object, use
+ KGlobal::charsets() instead.
+ */
+ KCharsets();
+
+public:
+
+ /**
+ * Destructor.
+ */
+ virtual ~KCharsets();
+
+ /**
+ * Provided for compatibility.
+ * @param name the name of the codec
+ * @return the QTextCodec. If the desired codec could not be found,
+ * it returns a default (Latin-1) codec
+ */
+ QTextCodec *codecForName(const QString &name) const;
+
+ /**
+ * Tries to find a QTextCodec to convert the given encoding from and to
+ * Unicode. If no codec could be found the latin1 codec will be returned an
+ * @p ok will be set to false.
+ * @return the QTextCodec. If the desired codec could not be found,
+ * it returns a default (Latin-1) codec
+ */
+ QTextCodec *codecForName(const QString &n, bool &ok) const;
+
+ /**
+ * Converts an entity to a character. The string must contain only the
+ * entity without the trailing ';'.
+ * @param str the entity
+ * @return QChar::null if the entity could not be decoded.
+ */
+ static QChar fromEntity(const QString &str);
+ /**
+ * Overloaded member function. Tries to find an entity in the
+ * QString str.
+ * @param str the string containing entified
+ * @param len is a return value, that gives the length of the decoded
+ * entity.
+ * @return a decoded entity if one could be found, QChar::null
+ * otherwise
+ */
+ static QChar fromEntity(const QString &str, int &len);
+
+ /**
+ * Converts a QChar to an entity. The returned string does already
+ * contain the leading '&' and the trailing ';'.
+ * @param ch the char to convert
+ * @return the entity
+ */
+ static QString toEntity(const QChar &ch);
+
+ /**
+ * Scans the given string for entities (like &amp;amp;) and resolves them
+ * using fromEntity.
+ * @param text the string containing the entities
+ * @return the clean string
+ * @since 3.1
+ */
+ static QString resolveEntities( const QString &text );
+
+ /**
+ * Lists all available encodings as names.
+ * @return the list of all encodings
+ */
+ QStringList availableEncodingNames();
+
+ /**
+ * Lists the available encoding names together with a more descriptive language.
+ * @return the list of descriptive encoding names
+ */
+ QStringList descriptiveEncodingNames();
+
+ /**
+ * Returns the language the encoding is used for.
+ * @param encoding the encoding for the language
+ * @return the language of the encoding
+ */
+ QString languageForEncoding( const QString &encoding );
+
+ /**
+ * Returns the encoding for a string obtained with descriptiveEncodingNames().
+ * @param descriptiveName the descriptive name for the encoding
+ * @return the name of the encoding
+ */
+ QString encodingForName( const QString &descriptiveName );
+
+private:
+ KCharsetsPrivate *d;
+};
+
+#endif
diff --git a/kdecore/kcheckaccelerators.cpp b/kdecore/kcheckaccelerators.cpp
new file mode 100644
index 000000000..98d8f2440
--- /dev/null
+++ b/kdecore/kcheckaccelerators.cpp
@@ -0,0 +1,216 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ Copyright (C) 1998, 1999, 2000 KDE Team
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+// $Id$
+
+#define INCLUDE_MENUITEM_DEF
+#include <qmenudata.h>
+
+#include "config.h"
+
+#include "kcheckaccelerators.h"
+#include "kaccelmanager.h"
+#include <qpopupmenu.h>
+#include <qapplication.h>
+#include <qdialog.h>
+#include <qlayout.h>
+#include <qtextview.h>
+#include <qobjectlist.h>
+#include <qmenubar.h>
+#include <qtabbar.h>
+#include <qpushbutton.h>
+#include <qmetaobject.h>
+#include <qcheckbox.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kshortcut.h>
+#include <klocale.h>
+
+/*
+
+ HOWTO:
+
+ This class allows translators (and application developers) to check for accelerator
+ conflicts in menu and widgets. Put the following in your kdeglobals (or the config
+ file for the application you're testing):
+
+ [Development]
+ CheckAccelerators=F12
+ AutoCheckAccelerators=false
+ AlwaysShowCheckAccelerators=false
+
+ The checking can be either manual or automatic. To perform manual check, press
+ the keyboard shortcut set to 'CheckAccelerators' (here F12). If automatic checking
+ is enabled by setting 'AutoCheckAccelerators' to true, check will be performed every
+ time the GUI changes. It's possible that in certain cases the check will be
+ done also when no visible changes in the GUI happen or the check won't be done
+ even if the GUI changed (in the latter case, use manual check ). Automatic
+ checks can be anytime disabled by the checkbox in the dialog presenting
+ the results of the check. If you set 'AlwaysShowCheckAccelerators' to true,
+ the dialog will be shown even if the automatic check didn't find any conflicts,
+ and all submenus will be shown, even those without conflicts.
+
+ The dialog first lists the name of the window, then all results for all menus
+ (if the window has a menubar) and then result for all controls in the active
+ window (if there are any checkboxes etc.). For every submenu and all controls
+ there are shown all conflicts grouped by accelerator, and a list of all used
+ accelerators.
+*/
+
+KCheckAccelerators::KCheckAccelerators( QObject* parent )
+ : QObject( parent, "kapp_accel_filter" ), key(0), block( false ), drklash(0)
+{
+ parent->installEventFilter( this );
+ KConfigGroupSaver saver( KGlobal::config(), "Development" );
+ QString sKey = KGlobal::config()->readEntry( "CheckAccelerators" ).stripWhiteSpace();
+ if( !sKey.isEmpty() ) {
+ KShortcut cuts( sKey );
+ if( cuts.count() > 0 )
+ key = int(cuts.seq(0).qt());
+ }
+ alwaysShow = KGlobal::config()->readBoolEntry( "AlwaysShowCheckAccelerators", false );
+ autoCheck = KGlobal::config()->readBoolEntry( "AutoCheckAccelerators", true );
+ connect( &autoCheckTimer, SIGNAL( timeout()), SLOT( autoCheckSlot()));
+}
+
+bool KCheckAccelerators::eventFilter( QObject * , QEvent * e)
+{
+ if ( block )
+ return false;
+
+ switch ( e->type() ) { // just simplify debuggin
+ case QEvent::Accel:
+ if ( key && (static_cast<QKeyEvent *>(e)->key() == key) ) {
+ block = true;
+ checkAccelerators( false );
+ block = false;
+ static_cast<QKeyEvent *>(e)->accept();
+ return true;
+ }
+ break;
+ case QEvent::ChildInserted:
+ case QEvent::ChildRemoved:
+ case QEvent::Resize:
+ case QEvent::LayoutHint:
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ if( autoCheck )
+ autoCheckTimer.start( 20, true ); // 20 ms
+ break;
+ case QEvent::Timer:
+ case QEvent::MouseMove:
+ case QEvent::Paint:
+ return false;
+ default:
+ // kdDebug(125) << "KCheckAccelerators::eventFilter " << e->type() << " " << autoCheck << endl;
+ break;
+ }
+ return false;
+}
+
+void KCheckAccelerators::autoCheckSlot()
+{
+ if( block )
+ {
+ autoCheckTimer.start( 20, true );
+ return;
+ }
+ block = true;
+ checkAccelerators( !alwaysShow );
+ block = false;
+}
+
+void KCheckAccelerators::createDialog(QWidget *actWin, bool automatic)
+{
+ if ( drklash )
+ return;
+
+ drklash = new QDialog( actWin, "kapp_accel_check_dlg", false, Qt::WDestructiveClose);
+ drklash->setCaption( i18n( "Dr. Klash' Accelerator Diagnosis" ));
+ drklash->resize( 500, 460 );
+ QVBoxLayout* layout = new QVBoxLayout( drklash, 11, 6 );
+ layout->setAutoAdd( true );
+ drklash_view = new QTextView( drklash );
+ QCheckBox* disableAutoCheck = NULL;
+ if( automatic ) {
+ disableAutoCheck = new QCheckBox( i18n( "&Disable automatic checking" ), drklash );
+ connect(disableAutoCheck, SIGNAL(toggled(bool)), SLOT(slotDisableCheck(bool)));
+ }
+ QPushButton* btnClose = new QPushButton( i18n( "&Close" ), drklash );
+ btnClose->setDefault( true );
+ connect( btnClose, SIGNAL( clicked() ), drklash, SLOT( close() ) );
+ if (disableAutoCheck)
+ disableAutoCheck->setFocus();
+ else
+ drklash_view->setFocus();
+}
+
+void KCheckAccelerators::slotDisableCheck(bool on)
+{
+ autoCheck = !on;
+ if (!on)
+ autoCheckSlot();
+}
+
+void KCheckAccelerators::checkAccelerators( bool automatic )
+{
+ QWidget* actWin = qApp->activeWindow();
+ if ( !actWin )
+ return;
+
+ KAcceleratorManager::manage(actWin);
+ QString a, c, r;
+ KAcceleratorManager::last_manage(a, c, r);
+
+ if (automatic) // for now we only show dialogs on F12 checks
+ return;
+
+ if (c.isEmpty() && r.isEmpty() && (automatic || a.isEmpty()))
+ return;
+
+ QString s;
+
+ if ( ! c.isEmpty() ) {
+ s += i18n("<h2>Accelerators changed</h2>");
+ s += "<table border><tr><th><b>Old Text</b></th><th><b>New Text</b></th></tr>"
+ + c + "</table>";
+ }
+
+ if ( ! r.isEmpty() ) {
+ s += i18n("<h2>Accelerators removed</h2>");
+ s += "<table border><tr><th><b>Old Text</b></th></tr>" + r + "</table>";
+ }
+
+ if ( ! a.isEmpty() ) {
+ s += i18n("<h2>Accelerators added (just for your info)</h2>");
+ s += "<table border><tr><th><b>New Text</b></th></tr>" + a + "</table>";
+ }
+
+ createDialog(actWin, automatic);
+ drklash_view->setText(s);
+ drklash->show();
+ drklash->raise();
+
+ // dlg will be destroyed before returning
+}
+
+#include "kcheckaccelerators.moc"
diff --git a/kdecore/kcheckaccelerators.h b/kdecore/kcheckaccelerators.h
new file mode 100644
index 000000000..a01d76051
--- /dev/null
+++ b/kdecore/kcheckaccelerators.h
@@ -0,0 +1,96 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ Copyright (C) 1998, 1999, 2000 KDE Team
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KCHECKACCELERATORS_H_
+#define KCHECKACCELERATORS_H_
+
+#include <qguardedptr.h>
+#include <qobject.h>
+#include <qkeysequence.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qtimer.h>
+
+class QMenuData;
+class QTextView;
+
+#include "kdelibs_export.h"
+
+/**
+ @internal
+ This class allows translators (and application developers) to check for accelerator
+ conflicts in menu and widgets. Put the following in your kdeglobals (or the config
+ file for the application you're testing):
+
+ \code
+ [Development]
+ CheckAccelerators=F12
+ AutoCheckAccelerators=false
+ AlwaysShowCheckAccelerators=false
+ \endcode
+
+ The checking can be either manual or automatic. To perform manual check, press
+ the keyboard shortcut set to 'CheckAccelerators' (here F12). If automatic checking
+ is enabled by setting 'AutoCheckAccelerators' to true, check will be performed every
+ time the GUI changes. It's possible that in certain cases the check will be
+ done also when no visible changes in the GUI happen or the check won't be done
+ even if the GUI changed (in the latter case, use manual check ). Automatic
+ checks can be anytime disabled by the checkbox in the dialog presenting
+ the results of the check. If you set 'AlwaysShowCheckAccelerators' to true,
+ the dialog will be shown even if the automatic check didn't find any conflicts,
+ and all submenus will be shown, even those without conflicts.
+
+ The dialog first lists the name of the window, then all results for all menus
+ (if the window has a menubar) and then result for all controls in the active
+ window (if there are any checkboxes etc.). For every submenu and all controls
+ there are shown all conflicts grouped by accelerator, and a list of all used
+ accelerators.
+*/
+class KDECORE_EXPORT KCheckAccelerators : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a KCheckAccelerators instance for the given object.
+ * @param parent the parent to check
+ */
+ KCheckAccelerators( QObject* parent );
+ /**
+ * Re-implemented to filter the parent's events.
+ */
+ bool eventFilter( QObject * , QEvent * e);
+
+private:
+ void checkAccelerators( bool automatic );
+ int key;
+ bool alwaysShow;
+ bool autoCheck;
+ bool block;
+ QTimer autoCheckTimer;
+ void createDialog(QWidget *parent, bool automatic);
+ QGuardedPtr<QDialog> drklash;
+ QTextView *drklash_view;
+
+private slots:
+ void autoCheckSlot();
+ void slotDisableCheck(bool);
+};
+
+#endif
diff --git a/kdecore/kckey.cpp b/kdecore/kckey.cpp
new file mode 100644
index 000000000..2a06a2c9c
--- /dev/null
+++ b/kdecore/kckey.cpp
@@ -0,0 +1,286 @@
+// This file has been automatically generated by "generate_keys.sh"
+// Distributed under the GNU Library General Public License
+
+#include <qnamespace.h>
+#include "kckey.h"
+
+const KKeys kde_KKEYS[NB_KEYS] = {
+ { "Escape", 0x1000 }, // translated
+ { "Tab", 0x1001 }, // translated
+ { "Backtab", 0x1002 }, // translated
+ { "Backspace", 0x1003 }, // translated
+ { "Return", 0x1004 }, // translated
+ { "Enter", 0x1005 }, // translated
+ { "Insert", 0x1006 }, // translated
+ { "Delete", 0x1007 }, // translated
+ { "Pause", 0x1008 }, // translated
+ { "Print", 0x1009 }, // translated
+ { "SysReq", 0x100a }, // translated
+ { "Clear", 0x100b },
+ { "Home", 0x1010 }, // translated
+ { "End", 0x1011 }, // translated
+ { "Left", 0x1012 }, // translated
+ { "Up", 0x1013 }, // translated
+ { "Right", 0x1014 }, // translated
+ { "Down", 0x1015 }, // translated
+ { "Prior", 0x1016 }, // translated
+ { "Next", 0x1017 }, // translated
+ { "Shift", 0x1020 }, // translated
+ { "Control", 0x1021 }, // translated
+ { "Meta", 0x1022 }, // translated
+ { "Alt", 0x1023 }, // translated
+ { "CapsLock", 0x1024 }, // translated
+ { "NumLock", 0x1025 }, // translated
+ { "ScrollLock", 0x1026 }, // translated
+ { "F1", 0x1030 },
+ { "F2", 0x1031 },
+ { "F3", 0x1032 },
+ { "F4", 0x1033 },
+ { "F5", 0x1034 },
+ { "F6", 0x1035 },
+ { "F7", 0x1036 },
+ { "F8", 0x1037 },
+ { "F9", 0x1038 },
+ { "F10", 0x1039 },
+ { "F11", 0x103a },
+ { "F12", 0x103b },
+ { "F13", 0x103c },
+ { "F14", 0x103d },
+ { "F15", 0x103e },
+ { "F16", 0x103f },
+ { "F17", 0x1040 },
+ { "F18", 0x1041 },
+ { "F19", 0x1042 },
+ { "F20", 0x1043 },
+ { "F21", 0x1044 },
+ { "F22", 0x1045 },
+ { "F23", 0x1046 },
+ { "F24", 0x1047 },
+ { "F25", 0x1048 },
+ { "F26", 0x1049 },
+ { "F27", 0x104a },
+ { "F28", 0x104b },
+ { "F29", 0x104c },
+ { "F30", 0x104d },
+ { "F31", 0x104e },
+ { "F32", 0x104f },
+ { "F33", 0x1050 },
+ { "F34", 0x1051 },
+ { "F35", 0x1052 },
+ { "Super_L", 0x1053 },
+ { "Super_R", 0x1054 },
+ { "Menu", 0x1055 }, // translated
+ { "Hyper_L", 0x1056 },
+ { "Hyper_R", 0x1057 },
+ { "Help", 0x1058 }, // translated
+ { "Direction_L", 0x1059 },
+ { "Direction_R", 0x1060 },
+ { "Space", 0x20 }, // translated
+ { "Any", Qt::Key_Space },
+ { "Exclam", 0x21 }, // translated
+ { "QuoteDbl", 0x22 },
+ { "NumberSign", 0x23 }, // translated
+ { "Dollar", 0x24 }, // translated
+ { "Percent", 0x25 }, // translated
+ { "Ampersand", 0x26 }, // translated
+ { "Apostrophe", 0x27 }, // translated
+ { "ParenLeft", 0x28 }, // translated
+ { "ParenRight", 0x29 }, // translated
+ { "Asterisk", 0x2a }, // translated
+ { "Plus", 0x2b }, // translated
+ { "Comma", 0x2c }, // translated
+ { "Minus", 0x2d }, // translated
+ { "Period", 0x2e }, // translated
+ { "Slash", 0x2f }, // translated
+ { "0", 0x30 },
+ { "1", 0x31 },
+ { "2", 0x32 },
+ { "3", 0x33 },
+ { "4", 0x34 },
+ { "5", 0x35 },
+ { "6", 0x36 },
+ { "7", 0x37 },
+ { "8", 0x38 },
+ { "9", 0x39 },
+ { "Colon", 0x3a }, // translated
+ { "Semicolon", 0x3b }, // translated
+ { "Less", 0x3c }, // translated
+ { "Equal", 0x3d }, // translated
+ { "Greater", 0x3e }, // translated
+ { "Question", 0x3f }, // translated
+ { "At", 0x40 },
+ { "A", 0x41 },
+ { "B", 0x42 },
+ { "C", 0x43 },
+ { "D", 0x44 },
+ { "E", 0x45 },
+ { "F", 0x46 },
+ { "G", 0x47 },
+ { "H", 0x48 },
+ { "I", 0x49 },
+ { "J", 0x4a },
+ { "K", 0x4b },
+ { "L", 0x4c },
+ { "M", 0x4d },
+ { "N", 0x4e },
+ { "O", 0x4f },
+ { "P", 0x50 },
+ { "Q", 0x51 },
+ { "R", 0x52 },
+ { "S", 0x53 },
+ { "T", 0x54 },
+ { "U", 0x55 },
+ { "V", 0x56 },
+ { "W", 0x57 },
+ { "X", 0x58 },
+ { "Y", 0x59 },
+ { "Z", 0x5a },
+ { "BracketLeft", 0x5b }, // translated
+ { "Backslash", 0x5c }, // translated
+ { "BracketRight", 0x5d }, // translated
+ { "AsciiCircum", 0x5e }, // translated
+ { "Underscore", 0x5f }, // translated
+ { "QuoteLeft", 0x60 }, // translated
+ { "BraceLeft", 0x7b }, // translated
+ { "Bar", 0x7c },
+ { "BraceRight", 0x7d }, // translated
+ { "AsciiTilde", 0x7e }, // translated
+ { "nobreakspace", 0x0a0 },
+ { "exclamdown", 0x0a1 },
+ { "cent", 0x0a2 },
+ { "sterling", 0x0a3 },
+ { "currency", 0x0a4 },
+ { "yen", 0x0a5 },
+ { "brokenbar", 0x0a6 },
+ { "section", 0x0a7 },
+ { "diaeresis", 0x0a8 },
+ { "copyright", 0x0a9 },
+ { "ordfeminine", 0x0aa },
+ { "guillemotleft", 0x0ab },
+ { "notsign", 0x0ac },
+ { "hyphen", 0x0ad },
+ { "registered", 0x0ae },
+ { "macron", 0x0af },
+ { "degree", 0x0b0 },
+ { "plusminus", 0x0b1 },
+ { "twosuperior", 0x0b2 },
+ { "threesuperior", 0x0b3 },
+ { "acute", 0x0b4 },
+ { "mu", 0x0b5 },
+ { "paragraph", 0x0b6 },
+ { "periodcentered", 0x0b7 },
+ { "cedilla", 0x0b8 },
+ { "onesuperior", 0x0b9 },
+ { "masculine", 0x0ba },
+ { "guillemotright", 0x0bb },
+ { "onequarter", 0x0bc },
+ { "onehalf", 0x0bd },
+ { "threequarters", 0x0be },
+ { "questiondown", 0x0bf },
+ { "Agrave", 0x0c0 },
+ { "Aacute", 0x0c1 },
+ { "Acircumflex", 0x0c2 },
+ { "Atilde", 0x0c3 },
+ { "Adiaeresis", 0x0c4 },
+ { "Aring", 0x0c5 },
+ { "AE", 0x0c6 },
+ { "Ccedilla", 0x0c7 },
+ { "Egrave", 0x0c8 },
+ { "Eacute", 0x0c9 },
+ { "Ecircumflex", 0x0ca },
+ { "Ediaeresis", 0x0cb },
+ { "Igrave", 0x0cc },
+ { "Iacute", 0x0cd },
+ { "Icircumflex", 0x0ce },
+ { "Idiaeresis", 0x0cf },
+ { "ETH", 0x0d0 },
+ { "Ntilde", 0x0d1 },
+ { "Ograve", 0x0d2 },
+ { "Oacute", 0x0d3 },
+ { "Ocircumflex", 0x0d4 },
+ { "Otilde", 0x0d5 },
+ { "Odiaeresis", 0x0d6 },
+ { "multiply", 0x0d7 },
+ { "Ooblique", 0x0d8 },
+ { "Ugrave", 0x0d9 },
+ { "Uacute", 0x0da },
+ { "Ucircumflex", 0x0db },
+ { "Udiaeresis", 0x0dc },
+ { "Yacute", 0x0dd },
+ { "THORN", 0x0de },
+ { "ssharp", 0x0df },
+ { "agrave", 0x0e0 },
+ { "aacute", 0x0e1 },
+ { "acircumflex", 0x0e2 },
+ { "atilde", 0x0e3 },
+ { "adiaeresis", 0x0e4 },
+ { "aring", 0x0e5 },
+ { "ae", 0x0e6 },
+ { "ccedilla", 0x0e7 },
+ { "egrave", 0x0e8 },
+ { "eacute", 0x0e9 },
+ { "ecircumflex", 0x0ea },
+ { "ediaeresis", 0x0eb },
+ { "igrave", 0x0ec },
+ { "iacute", 0x0ed },
+ { "icircumflex", 0x0ee },
+ { "idiaeresis", 0x0ef },
+ { "eth", 0x0f0 },
+ { "ntilde", 0x0f1 },
+ { "ograve", 0x0f2 },
+ { "oacute", 0x0f3 },
+ { "ocircumflex", 0x0f4 },
+ { "otilde", 0x0f5 },
+ { "odiaeresis", 0x0f6 },
+ { "division", 0x0f7 },
+ { "oslash", 0x0f8 },
+ { "ugrave", 0x0f9 },
+ { "uacute", 0x0fa },
+ { "ucircumflex", 0x0fb },
+ { "udiaeresis", 0x0fc },
+ { "yacute", 0x0fd },
+ { "thorn", 0x0fe },
+ { "ydiaeresis", 0x0ff },
+ { "Back ", 0x1061 },
+ { "Forward ", 0x1062 },
+ { "Stop ", 0x1063 },
+ { "Refresh ", 0x1064 },
+ { "VolumeDown", 0x1070 },
+ { "VolumeMute ", 0x1071 },
+ { "VolumeUp", 0x1072 },
+ { "BassBoost", 0x1073 },
+ { "BassUp", 0x1074 },
+ { "BassDown", 0x1075 },
+ { "TrebleUp", 0x1076 },
+ { "TrebleDown", 0x1077 },
+ { "MediaPlay ", 0x1080 },
+ { "MediaStop ", 0x1081 },
+ { "MediaPrev ", 0x1082 },
+ { "MediaNext ", 0x1083 },
+ { "MediaRecord", 0x1084 },
+ { "HomePage ", 0x1090 },
+ { "Favorites ", 0x1091 },
+ { "Search ", 0x1092 },
+ { "Standby", 0x1093 },
+ { "OpenUrl", 0x1094 },
+ { "LaunchMail ", 0x10a0 },
+ { "LaunchMedia", 0x10a1 },
+ { "Launch0 ", 0x10a2 },
+ { "Launch1 ", 0x10a3 },
+ { "Launch2 ", 0x10a4 },
+ { "Launch3 ", 0x10a5 },
+ { "Launch4 ", 0x10a6 },
+ { "Launch5 ", 0x10a7 },
+ { "Launch6 ", 0x10a8 },
+ { "Launch7 ", 0x10a9 },
+ { "Launch8 ", 0x10aa },
+ { "Launch9 ", 0x10ab },
+ { "LaunchA ", 0x10ac },
+ { "LaunchB ", 0x10ad },
+ { "LaunchC ", 0x10ae },
+ { "LaunchD ", 0x10af },
+ { "LaunchE ", 0x10b0 },
+ { "LaunchF ", 0x10b1 },
+ { "MediaLast", 0x1fff },
+ { "unknown", 0xffff }
+};
diff --git a/kdecore/kckey.h b/kdecore/kckey.h
new file mode 100644
index 000000000..887d42e0a
--- /dev/null
+++ b/kdecore/kckey.h
@@ -0,0 +1,17 @@
+// This file has been automatically generated by "generate_keys.sh"
+// Distributed under the GNU Library General Public License
+#ifndef KCKEY_H
+#define KCKEY_H
+
+typedef struct {
+ const char *name;
+ int code;
+} KKeys;
+
+#define MAX_KEY_LENGTH 15 // should be calculated (gawk ?)
+#define MAX_KEY_MODIFIER_LENGTH 21 // "SHIFT + CRTL + ALT + " :
+#define MAX_FCTN_LENGTH 50 // arbitrary limit
+#define NB_KEYS 278
+extern const KKeys kde_KKEYS[NB_KEYS];
+
+#endif
diff --git a/kdecore/kclipboard.cpp b/kdecore/kclipboard.cpp
new file mode 100644
index 000000000..3a266c171
--- /dev/null
+++ b/kdecore/kclipboard.cpp
@@ -0,0 +1,199 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+
+#include "kclipboard.h"
+
+/*
+ * This class provides an automatic synchronization of the X11 Clipboard and Selection
+ * buffers. There are two configuration options in the kdeglobals configuration file,
+ * in the [General] section:
+ * - SynchronizeClipboardAndSelection - whenever the Selection changes, Clipboard is
+ * set to the same value. This can be also enabled in Klipper.
+ * - ClipboardSetSelection - whenever the Clipboard changes, Selection is set
+ * to the same value. This setting is only for die-hard fans of the old broken
+ * KDE1/2 behavior, which can potentionally lead to unexpected problems,
+ * and this setting therefore can be enabled only in the configuration file.
+ *
+ * Whenever reporting any bug only remotely related to clipboard, first make
+ * sure you can reproduce it when both these two options are turned off,
+ * especially the second one.
+ */
+
+class KClipboardSynchronizer::MimeSource : public QMimeSource
+{
+public:
+ MimeSource( const QMimeSource * src )
+ : QMimeSource(),
+ m_formats( true ) // deep copies!
+ {
+ m_formats.setAutoDelete( true );
+ m_data.setAutoDelete( true );
+
+ if ( src )
+ {
+ QByteArray *byteArray;
+ const char *format;
+ int i = 0;
+ while ( (format = src->format( i++ )) )
+ {
+ byteArray = new QByteArray();
+ *byteArray = src->encodedData( format ).copy();
+ m_data.append( byteArray );
+ m_formats.append( format );
+ }
+ }
+ }
+
+ ~MimeSource() {}
+
+ virtual const char *format( int i ) const {
+ if ( i < (int) m_formats.count() )
+ return m_formats.at( i );
+ else
+ return 0L;
+ }
+ virtual bool provides( const char *mimeType ) const {
+ return ( m_formats.find( mimeType ) > -1 );
+ }
+ virtual QByteArray encodedData( const char *format ) const
+ {
+ int index = m_formats.find( format );
+ if ( index > -1 )
+ return *(m_data.at( index ));
+
+ return QByteArray();
+ }
+
+private:
+ mutable QStrList m_formats;
+ mutable QPtrList<QByteArray> m_data;
+};
+
+
+KClipboardSynchronizer * KClipboardSynchronizer::s_self = 0L;
+bool KClipboardSynchronizer::s_sync = false;
+bool KClipboardSynchronizer::s_reverse_sync = false;
+bool KClipboardSynchronizer::s_blocked = false;
+
+KClipboardSynchronizer * KClipboardSynchronizer::self()
+{
+ if ( !s_self )
+ s_self = new KClipboardSynchronizer( kapp, "KDE Clipboard" );
+
+ return s_self;
+}
+
+KClipboardSynchronizer::KClipboardSynchronizer( QObject *parent, const char *name )
+ : QObject( parent, name )
+{
+ s_self = this;
+
+ KConfigGroup config( KGlobal::config(), "General" );
+ s_sync = config.readBoolEntry( "SynchronizeClipboardAndSelection", s_sync);
+ s_reverse_sync = config.readBoolEntry( "ClipboardSetSelection",
+ s_reverse_sync );
+
+ setupSignals();
+}
+
+KClipboardSynchronizer::~KClipboardSynchronizer()
+{
+ if ( s_self == this )
+ s_self = 0L;
+}
+
+void KClipboardSynchronizer::setupSignals()
+{
+ QClipboard *clip = QApplication::clipboard();
+ disconnect( clip, NULL, this, NULL );
+ if( s_sync )
+ connect( clip, SIGNAL( selectionChanged() ),
+ SLOT( slotSelectionChanged() ));
+ if( s_reverse_sync )
+ connect( clip, SIGNAL( dataChanged() ),
+ SLOT( slotClipboardChanged() ));
+}
+
+void KClipboardSynchronizer::slotSelectionChanged()
+{
+ QClipboard *clip = QApplication::clipboard();
+
+// qDebug("*** sel changed: %i", s_blocked);
+ if ( s_blocked || !clip->ownsSelection() )
+ return;
+
+ setClipboard( new MimeSource( clip->data( QClipboard::Selection) ),
+ QClipboard::Clipboard );
+}
+
+void KClipboardSynchronizer::slotClipboardChanged()
+{
+ QClipboard *clip = QApplication::clipboard();
+
+// qDebug("*** clip changed : %i (implicit: %i, ownz: clip: %i, selection: %i)", s_blocked, s_implicitSelection, clip->ownsClipboard(), clip->ownsSelection());
+ if ( s_blocked || !clip->ownsClipboard() )
+ return;
+
+ setClipboard( new MimeSource( clip->data( QClipboard::Clipboard ) ),
+ QClipboard::Selection );
+}
+
+void KClipboardSynchronizer::setClipboard( QMimeSource *data, QClipboard::Mode mode )
+{
+// qDebug("---> setting clipboard: %p", data);
+
+ QClipboard *clip = QApplication::clipboard();
+
+ s_blocked = true;
+
+ if ( mode == QClipboard::Clipboard )
+ {
+ clip->setData( data, QClipboard::Clipboard );
+ }
+ else if ( mode == QClipboard::Selection )
+ {
+ clip->setData( data, QClipboard::Selection );
+ }
+
+ s_blocked = false;
+}
+
+void KClipboardSynchronizer::setSynchronizing( bool sync )
+{
+ s_sync = sync;
+ self()->setupSignals();
+}
+
+void KClipboardSynchronizer::setReverseSynchronizing( bool enable )
+{
+ s_reverse_sync = enable;
+ self()->setupSignals();
+}
+
+// private, called by KApplication
+void KClipboardSynchronizer::newConfiguration( int config )
+{
+ s_sync = (config & Synchronize);
+ self()->setupSignals();
+}
+
+#include "kclipboard.moc"
diff --git a/kdecore/kclipboard.h b/kdecore/kclipboard.h
new file mode 100644
index 000000000..bfd5cf8c4
--- /dev/null
+++ b/kdecore/kclipboard.h
@@ -0,0 +1,123 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCLIPBOARD_H
+#define KCLIPBOARD_H
+
+#include <qclipboard.h>
+#include <qmime.h>
+#include <qobject.h>
+#include <qstrlist.h>
+#include "kdelibs_export.h"
+
+/**
+ * This class is only for internal use.
+ *
+ * @short Allowing to automatically synchronize the X11 Clipboard and Selection buffers.
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @since 3.1
+ * @internal
+ */
+class KDECORE_EXPORT KClipboardSynchronizer : public QObject
+{
+ Q_OBJECT
+
+public:
+ /** Systray widget for manipulating the clipboard. */
+ friend class KlipperWidget;
+ friend class KApplication;
+
+ /**
+ * Returns the KClipboardSynchronizer singleton object.
+ * @return the KClipboardSynchronizer singleton object.
+ */
+ static KClipboardSynchronizer *self();
+
+ /**
+ * Configures KClipboardSynchronizer to synchronize the Selection to Clipboard whenever
+ * it changes.
+ *
+ * Default is false.
+ * @see isSynchronizing
+ */
+ static void setSynchronizing( bool sync );
+
+ /**
+ * Checks whether Clipboard and Selection will be synchronized upon changes.
+ * @returns whether Clipboard and Selection will be synchronized upon
+ * changes.
+ * @see setSynchronizing
+ */
+ static bool isSynchronizing()
+ {
+ return s_sync;
+ }
+
+ /**
+ * Configures KClipboardSynchronizer to copy the Clipboard buffer to the Selection
+ * buffer whenever the Clipboard changes.
+ *
+ *
+ * @param enable true to enable implicit selection, false otherwise.
+ * Default is true.
+ * @see selectionSetting
+ */
+ static void setReverseSynchronizing( bool enable );
+
+ /**
+ * Checks whether the Clipboard buffer will be copied to the Selection
+ * buffer upon changes.
+ * @returns whether the Clipboard buffer will be copied to the Selection
+ * buffer upon changes.
+ * @see setSelectionSetting
+ */
+ static bool isReverseSynchronizing()
+ {
+ return s_reverse_sync;
+ }
+
+
+protected:
+ ~KClipboardSynchronizer();
+
+private slots:
+ void slotSelectionChanged();
+ void slotClipboardChanged();
+
+private:
+ KClipboardSynchronizer( QObject *parent = 0, const char *name = 0L );
+ void setupSignals();
+
+ static void setClipboard( QMimeSource* data, QClipboard::Mode mode );
+
+ static KClipboardSynchronizer *s_self;
+ static bool s_sync;
+ static bool s_reverse_sync;
+ static bool s_blocked;
+
+ class MimeSource;
+
+private:
+ // needed by klipper
+ enum Configuration { Synchronize = 1 };
+ // called by KApplication upon kipc message, invoked by klipper
+ static void newConfiguration( int config );
+
+};
+
+#endif // KCLIPBOARD_H
diff --git a/kdecore/kcmdlineargs.cpp b/kdecore/kcmdlineargs.cpp
new file mode 100644
index 000000000..c99903009
--- /dev/null
+++ b/kdecore/kcmdlineargs.cpp
@@ -0,0 +1,1298 @@
+/*
+ Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qasciidict.h>
+#include <qstrlist.h>
+
+#include "kcmdlineargs.h"
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kstringhandler.h>
+#include <kstaticdeleter.h>
+
+#ifdef Q_WS_X11
+#define DISPLAY "DISPLAY"
+#elif defined(Q_WS_QWS)
+#define DISPLAY "QWS_DISPLAY"
+#endif
+
+#ifdef Q_WS_WIN
+#include <win32_utils.h>
+#endif
+
+template class QAsciiDict<QCString>;
+template class QPtrList<KCmdLineArgs>;
+
+class KCmdLineParsedOptions : public QAsciiDict<QCString>
+{
+public:
+ KCmdLineParsedOptions()
+ : QAsciiDict<QCString>( 7 ) { }
+
+ // WABA: Huh?
+ // The compiler doesn't find KCmdLineParsedOptions::write(s) by itself ???
+ // WABA: No, because there is another write function that hides the
+ // write function in the base class even though this function has a
+ // different signature. (obscure C++ feature)
+ QDataStream& save( QDataStream &s) const
+ { return QGDict::write(s); }
+
+ QDataStream& load( QDataStream &s)
+ { return QGDict::read(s); }
+
+protected:
+ virtual QDataStream& write( QDataStream &s, QPtrCollection::Item data) const
+ {
+ QCString *str = (QCString *) data;
+ s << (*str);
+ return s;
+ }
+
+ virtual QDataStream& read( QDataStream &s, QPtrCollection::Item &item)
+ {
+ QCString *str = new QCString;
+ s >> (*str);
+ item = (void *)str;
+ return s;
+ }
+
+};
+
+class KCmdLineParsedArgs : public QStrList
+{
+public:
+ KCmdLineParsedArgs()
+ : QStrList( true ) { }
+ QDataStream& save( QDataStream &s) const
+ { return QGList::write(s); }
+
+ QDataStream& load( QDataStream &s)
+ { return QGList::read(s); }
+};
+
+
+class KCmdLineArgsList: public QPtrList<KCmdLineArgs>
+{
+public:
+ KCmdLineArgsList() { }
+};
+
+KCmdLineArgsList *KCmdLineArgs::argsList = 0;
+int KCmdLineArgs::argc = 0;
+char **KCmdLineArgs::argv = 0;
+char *KCmdLineArgs::mCwd = 0;
+static KStaticDeleter <char> mCwdd;
+const KAboutData *KCmdLineArgs::about = 0;
+bool KCmdLineArgs::parsed = false;
+bool KCmdLineArgs::ignoreUnknown = false;
+
+//
+// Static functions
+//
+
+void
+KCmdLineArgs::init(int _argc, char **_argv, const char *_appname, const char* programName,
+ const char *_description, const char *_version, bool noKApp)
+{
+ init(_argc, _argv,
+ new KAboutData(_appname, programName, _version, _description),
+ noKApp);
+}
+
+void
+KCmdLineArgs::init(int _argc, char **_argv, const char *_appname,
+ const char *_description, const char *_version, bool noKApp)
+{
+ init(_argc, _argv,
+ new KAboutData(_appname, _appname, _version, _description),
+ noKApp);
+}
+
+void
+KCmdLineArgs::initIgnore(int _argc, char **_argv, const char *_appname )
+{
+ init(_argc, _argv,
+ new KAboutData(_appname, _appname, "unknown", "KDE Application", false));
+ ignoreUnknown = true;
+}
+
+void
+KCmdLineArgs::init(const KAboutData* ab)
+{
+ char **_argv = (char **) malloc(sizeof(char *));
+ _argv[0] = (char *) ab->appName();
+ init(1,_argv,ab, true);
+}
+
+
+void
+KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, bool noKApp)
+{
+ argc = _argc;
+ argv = _argv;
+
+ if (!argv)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Passing null-pointer to 'argv' is not allowed.\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+
+ // Strip path from argv[0]
+ if (argc) {
+ char *p = strrchr( argv[0], '/');
+ if (p)
+ argv[0] = p+1;
+ }
+
+ about = _about;
+ parsed = false;
+ mCwd = mCwdd.setObject(mCwd, new char [PATH_MAX+1], true);
+ (void) getcwd(mCwd, PATH_MAX);
+#ifdef Q_WS_WIN
+ win32_slashify(mCwd, PATH_MAX);
+#endif
+ if (!noKApp)
+ KApplication::addCmdLineOptions();
+}
+
+QString KCmdLineArgs::cwd()
+{
+ return QFile::decodeName(QCString(mCwd));
+}
+
+const char * KCmdLineArgs::appName()
+{
+ if (!argc) return 0;
+ return argv[0];
+}
+
+void
+KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions *options, const char *name,
+ const char *id, const char *afterId)
+{
+ if (!argsList)
+ argsList = new KCmdLineArgsList();
+
+ int pos = argsList->count();
+
+ if (pos && id && argsList->last() && !argsList->last()->name)
+ pos--;
+
+ KCmdLineArgs *args;
+ int i = 0;
+ for(args = argsList->first(); args; args = argsList->next(), i++)
+ {
+ if (!id && !args->id)
+ return; // Options already present.
+
+ if (id && args->id && (::qstrcmp(id, args->id) == 0))
+ return; // Options already present.
+
+ if (afterId && args->id && (::qstrcmp(afterId, args->id) == 0))
+ pos = i+1;
+ }
+
+ assert( parsed == false ); // You must add _ALL_ cmd line options
+ // before accessing the arguments!
+ args = new KCmdLineArgs(options, name, id);
+ argsList->insert(pos, args);
+}
+
+void
+KCmdLineArgs::saveAppArgs( QDataStream &ds)
+{
+ if (!parsed)
+ parseAllArgs();
+
+ // Remove Qt and KDE options.
+ removeArgs("qt");
+ removeArgs("kde");
+
+ QCString qCwd = mCwd;
+ ds << qCwd;
+
+ uint count = argsList ? argsList->count() : 0;
+ ds << count;
+
+ if (!count) return;
+
+ KCmdLineArgs *args;
+ for(args = argsList->first(); args; args = argsList->next())
+ {
+ ds << QCString(args->id);
+ args->save(ds);
+ }
+}
+
+void
+KCmdLineArgs::loadAppArgs( QDataStream &ds)
+{
+ parsed = true; // don't reparse argc/argv!
+
+ // Remove Qt and KDE options.
+ removeArgs("qt");
+ removeArgs("kde");
+
+ KCmdLineArgs *args;
+ if ( argsList ) {
+ for(args = argsList->first(); args; args = argsList->next())
+ {
+ args->clear();
+ }
+ }
+
+ if (ds.atEnd())
+ return;
+
+ QCString qCwd;
+ ds >> qCwd;
+ delete [] mCwd;
+
+ mCwd = mCwdd.setObject(mCwd, new char[qCwd.length()+1], true);
+ strncpy(mCwd, qCwd.data(), qCwd.length()+1);
+
+ uint count;
+ ds >> count;
+
+ while(count--)
+ {
+ QCString id;
+ ds >> id;
+ assert( argsList );
+ for(args = argsList->first(); args; args = argsList->next())
+ {
+ if (args->id == id)
+ {
+ args->load(ds);
+ break;
+ }
+ }
+ }
+ parsed = true;
+}
+
+KCmdLineArgs *KCmdLineArgs::parsedArgs(const char *id)
+{
+ KCmdLineArgs *args = argsList ? argsList->first() : 0;
+ while(args)
+ {
+ if ((id && ::qstrcmp(args->id, id) == 0) || (!id && !args->id))
+ {
+ if (!parsed)
+ parseAllArgs();
+ return args;
+ }
+ args = argsList->next();
+ }
+
+ return args;
+}
+
+void KCmdLineArgs::removeArgs(const char *id)
+{
+ KCmdLineArgs *args = argsList ? argsList->first() : 0;
+ while(args)
+ {
+ if (args->id && id && ::qstrcmp(args->id, id) == 0)
+ {
+ if (!parsed)
+ parseAllArgs();
+ break;
+ }
+ args = argsList->next();
+ }
+
+ if (args)
+ delete args;
+}
+
+/*
+ * @return:
+ * 0 - option not found.
+ * 1 - option found // -fork
+ * 2 - inverse option found ('no') // -nofork
+ * 3 - option + arg found // -fork now
+ *
+ * +4 - no more options follow // !fork
+ */
+static int
+findOption(const KCmdLineOptions *options, QCString &opt,
+ const char *&opt_name, const char *&def, bool &enabled)
+{
+ int result;
+ bool inverse;
+ int len = opt.length();
+ while(options && options->name)
+ {
+ result = 0;
+ inverse = false;
+ opt_name = options->name;
+ if ((opt_name[0] == ':') || (opt_name[0] == 0))
+ {
+ options++;
+ continue;
+ }
+
+ if (opt_name[0] == '!')
+ {
+ opt_name++;
+ result = 4;
+ }
+ if ((opt_name[0] == 'n') && (opt_name[1] == 'o'))
+ {
+ opt_name += 2;
+ inverse = true;
+ }
+ if (strncmp(opt.data(), opt_name, len) == 0)
+ {
+ opt_name += len;
+ if (!opt_name[0])
+ {
+ if (inverse)
+ return result+2;
+
+ if (!options->description)
+ {
+ options++;
+ if (!options->name)
+ return result+0;
+ QCString nextOption = options->name;
+ int p = nextOption.find(' ');
+ if (p > 0)
+ nextOption = nextOption.left(p);
+ if (nextOption[0] == '!')
+ nextOption = nextOption.mid(1);
+ if (strncmp(nextOption.data(), "no", 2) == 0)
+ {
+ nextOption = nextOption.mid(2);
+ enabled = !enabled;
+ }
+ result = findOption(options, nextOption, opt_name, def, enabled);
+ assert(result);
+ opt = nextOption;
+ return result;
+ }
+
+ return 1;
+ }
+ if (opt_name[0] == ' ')
+ {
+ opt_name++;
+ def = options->def;
+ return result+3;
+ }
+ }
+
+ options++;
+ }
+ return 0;
+}
+
+
+void
+KCmdLineArgs::findOption(const char *_opt, QCString opt, int &i, bool _enabled, bool &moreOptions)
+{
+ KCmdLineArgs *args = argsList->first();
+ const char *opt_name;
+ const char *def;
+ QCString argument;
+ int j = opt.find('=');
+ if (j != -1)
+ {
+ argument = opt.mid(j+1);
+ opt = opt.left(j);
+ }
+
+ bool enabled = true;
+ int result = 0;
+ while (args)
+ {
+ enabled = _enabled;
+ result = ::findOption(args->options, opt, opt_name, def, enabled);
+ if (result) break;
+ args = argsList->next();
+ }
+ if (!args && (_opt[0] == '-') && _opt[1] && (_opt[1] != '-'))
+ {
+ // Option not found check if it is a valid option
+ // in the style of -Pprinter1 or ps -aux
+ int p = 1;
+ while (true)
+ {
+ QCString singleCharOption = " ";
+ singleCharOption[0] = _opt[p];
+ args = argsList->first();
+ while (args)
+ {
+ enabled = _enabled;
+ result = ::findOption(args->options, singleCharOption, opt_name, def, enabled);
+ if (result) break;
+ args = argsList->next();
+ }
+ if (!args)
+ break; // Unknown argument
+
+ p++;
+ if (result == 1) // Single option
+ {
+ args->setOption(singleCharOption, enabled);
+ if (_opt[p])
+ continue; // Next option
+ else
+ return; // Finished
+ }
+ else if (result == 3) // This option takes an argument
+ {
+ if (argument.isEmpty())
+ {
+ argument = _opt+p;
+ }
+ args->setOption(singleCharOption, argument);
+ return;
+ }
+ break; // Unknown argument
+ }
+ args = 0;
+ result = 0;
+ }
+
+ if (!args || !result)
+ {
+ if (ignoreUnknown)
+ return;
+ enable_i18n();
+ usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt)));
+ }
+
+ if ((result & 4) != 0)
+ {
+ result &= ~4;
+ moreOptions = false;
+ }
+
+ if (result == 3) // This option takes an argument
+ {
+ if (!enabled)
+ {
+ if (ignoreUnknown)
+ return;
+ enable_i18n();
+ usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt)));
+ }
+ if (argument.isEmpty())
+ {
+ i++;
+ if (i >= argc)
+ {
+ enable_i18n();
+ usage( i18n("'%1' missing.").arg( opt_name));
+ }
+ argument = argv[i];
+ }
+ args->setOption(opt, argument);
+ }
+ else
+ {
+ args->setOption(opt, enabled);
+ }
+}
+
+void
+KCmdLineArgs::printQ(const QString &msg)
+{
+ QCString localMsg = msg.local8Bit();
+ fprintf(stdout, "%s", localMsg.data());
+}
+
+void
+KCmdLineArgs::parseAllArgs()
+{
+ bool allowArgs = false;
+ bool inOptions = true;
+ bool everythingAfterArgIsArgs = false;
+ KCmdLineArgs *appOptions = argsList->last();
+ if (!appOptions->id)
+ {
+ const KCmdLineOptions *option = appOptions->options;
+ while(option && option->name)
+ {
+ if (option->name[0] == '+')
+ allowArgs = true;
+ if ( option->name[0] == '!' && option->name[1] == '+' )
+ {
+ allowArgs = true;
+ everythingAfterArgIsArgs = true;
+ }
+ option++;
+ }
+ }
+ for(int i = 1; i < argc; i++)
+ {
+ if (!argv[i])
+ continue;
+
+ if ((argv[i][0] == '-') && argv[i][1] && inOptions)
+ {
+ bool enabled = true;
+ const char *option = &argv[i][1];
+ const char *orig = argv[i];
+ if (option[0] == '-')
+ {
+ option++;
+ argv[i]++;
+ if (!option[0])
+ {
+ inOptions = false;
+ continue;
+ }
+ }
+ if (::qstrcmp(option, "help") == 0)
+ {
+ usage(0);
+ }
+ else if (strncmp(option, "help-",5) == 0)
+ {
+ usage(option+5);
+ }
+ else if ( (::qstrcmp(option, "version") == 0) ||
+ (::qstrcmp(option, "v") == 0))
+ {
+ printQ( QString("Qt: %1\n").arg(qVersion()));
+ printQ( QString("KDE: %1\n").arg(KDE_VERSION_STRING));
+ printQ( QString("%1: %2\n").
+ arg(about->programName()).arg(about->version()));
+ exit(0);
+ } else if ( (::qstrcmp(option, "license") == 0) )
+ {
+ enable_i18n();
+ printQ( about->license() );
+ printQ( "\n" );
+ exit(0);
+ } else if ( ::qstrcmp( option, "author") == 0 ) {
+ enable_i18n();
+ if ( about ) {
+ const QValueList<KAboutPerson> authors = about->authors();
+ if ( !authors.isEmpty() ) {
+ QString authorlist;
+ for (QValueList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) {
+ QString email;
+ if ( !(*it).emailAddress().isEmpty() )
+ email = " <" + (*it).emailAddress() + ">";
+ authorlist += QString(" ") + (*it).name() + email + "\n";
+ }
+ printQ( i18n("the 2nd argument is a list of name+address, one on each line","%1 was written by\n%2").arg ( QString(about->programName()) ).arg( authorlist ) );
+ }
+ } else {
+ printQ( i18n("This application was written by somebody who wants to remain anonymous.") );
+ }
+ if (about)
+ {
+ if (!about->customAuthorTextEnabled ())
+ {
+ if (about->bugAddress().isEmpty() || about->bugAddress() == "submit@bugs.kde.org" )
+ printQ( i18n( "Please use http://bugs.kde.org to report bugs.\n" ) );
+ else {
+ if( about->authors().count() == 1 && about->authors().first().emailAddress() == about->bugAddress() )
+ printQ( i18n( "Please report bugs to %1.\n" ).arg( about->authors().first().emailAddress() ) );
+ else
+ printQ( i18n( "Please report bugs to %1.\n" ).arg(about->bugAddress()) );
+ }
+ }
+ else
+ {
+ printQ(about->customAuthorPlainText());
+ }
+ }
+ exit(0);
+ } else {
+ if ((option[0] == 'n') && (option[1] == 'o'))
+ {
+ option += 2;
+ enabled = false;
+ }
+ findOption(orig, option, i, enabled, inOptions);
+ }
+ }
+ else
+ {
+ // Check whether appOptions allows these arguments
+ if (!allowArgs)
+ {
+ if (ignoreUnknown)
+ continue;
+ enable_i18n();
+ usage( i18n("Unexpected argument '%1'.").arg(QString::fromLocal8Bit(argv[i])));
+ }
+ else
+ {
+ appOptions->addArgument(argv[i]);
+ if (everythingAfterArgIsArgs)
+ inOptions = false;
+ }
+ }
+ }
+ parsed = true;
+}
+
+/**
+ * For KApplication only:
+ *
+ * Return argc
+ */
+int *
+KCmdLineArgs::qt_argc()
+{
+ if (!argsList)
+ KApplication::addCmdLineOptions(); // Lazy bastards!
+
+ static int qt_argc = -1;
+ if( qt_argc != -1 )
+ return &qt_argc;
+
+ KCmdLineArgs *args = parsedArgs("qt");
+ assert(args); // No qt options have been added!
+ if (!argv)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+
+ assert(argc >= (args->count()+1));
+ qt_argc = args->count() +1;
+ return &qt_argc;
+}
+
+/**
+ * For KApplication only:
+ *
+ * Return argv
+ */
+char ***
+KCmdLineArgs::qt_argv()
+{
+ if (!argsList)
+ KApplication::addCmdLineOptions(); // Lazy bastards!
+
+ static char** qt_argv;
+ if( qt_argv != NULL )
+ return &qt_argv;
+
+ KCmdLineArgs *args = parsedArgs("qt");
+ assert(args); // No qt options have been added!
+ if (!argv)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+
+ qt_argv = new char*[ args->count() + 2 ];
+ qt_argv[ 0 ] = qstrdup( appName());
+ int i = 0;
+ for(; i < args->count(); i++)
+ {
+ qt_argv[i+1] = qstrdup((char *) args->arg(i));
+ }
+ qt_argv[i+1] = 0;
+
+ return &qt_argv;
+}
+
+void
+KCmdLineArgs::enable_i18n()
+{
+ // called twice or too late
+ if (KGlobal::_locale)
+ return;
+
+ if (!KGlobal::_instance) {
+ KInstance *instance = new KInstance(about);
+ (void) instance->config();
+ // Don't delete instance!
+ }
+}
+
+void
+KCmdLineArgs::usage(const QString &error)
+{
+ assert(KGlobal::_locale);
+ QCString localError = error.local8Bit();
+ if (localError[error.length()-1] == '\n')
+ localError = localError.left(error.length()-1);
+ fprintf(stderr, "%s: %s\n", argv[0], localError.data());
+
+ QString tmp = i18n("Use --help to get a list of available command line options.");
+ localError = tmp.local8Bit();
+ fprintf(stderr, "%s: %s\n", argv[0], localError.data());
+ exit(254);
+}
+
+void
+KCmdLineArgs::usage(const char *id)
+{
+ enable_i18n();
+ assert(argsList != 0); // It's an error to call usage(...) without
+ // having done addCmdLineOptions first!
+
+ QString optionFormatString = " %1 %2\n";
+ QString optionFormatStringDef = " %1 %2 [%3]\n";
+ QString optionHeaderString = i18n("\n%1:\n");
+ QString tmp;
+ QString usage;
+
+ KCmdLineArgs *args = argsList->last();
+
+ if (!(args->id) && (args->options) &&
+ (args->options->name) && (args->options->name[0] != '+'))
+ {
+ usage = i18n("[options] ")+usage;
+ }
+
+ while(args)
+ {
+ if (args->name)
+ {
+ usage = i18n("[%1-options]").arg(args->name)+" "+usage;
+ }
+ args = argsList->prev();
+ }
+
+ KCmdLineArgs *appOptions = argsList->last();
+ if (!appOptions->id)
+ {
+ const KCmdLineOptions *option = appOptions->options;
+ while(option && option->name)
+ {
+ if (option->name[0] == '+')
+ usage = usage + (option->name+1) + " ";
+ else if ( option->name[0] == '!' && option->name[1] == '+' )
+ usage = usage + (option->name+2) + " ";
+
+ option++;
+ }
+ }
+
+ printQ(i18n("Usage: %1 %2\n").arg(argv[0]).arg(usage));
+ printQ("\n"+about->shortDescription()+"\n");
+
+ printQ(optionHeaderString.arg(i18n("Generic options")));
+ printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options")));
+
+ args = argsList->first();
+ while(args)
+ {
+ if (args->name && args->id)
+ {
+ QString option = QString("--help-%1").arg(args->id);
+ QString desc = i18n("Show %1 specific options").arg(args->name);
+
+ printQ(optionFormatString.arg(option, -25).arg(desc));
+ }
+ args = argsList->next();
+ }
+
+ printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options")));
+ printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information")));
+ printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information")));
+ printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information")));
+ printQ(optionFormatString.arg("--", -25).arg(i18n("End of options")));
+
+ args = argsList->first(); // Sets current to 1st.
+
+ bool showAll = id && (::qstrcmp(id, "all") == 0);
+
+ if (!showAll)
+ {
+ while(args)
+ {
+ if (!id && !args->id) break;
+ if (id && (::qstrcmp(args->id, id) == 0)) break;
+ args = argsList->next();
+ }
+ }
+
+ while(args)
+ {
+ bool hasArgs = false;
+ bool hasOptions = false;
+ QString optionsHeader;
+ if (args->name)
+ optionsHeader = optionHeaderString.arg(i18n("%1 options").arg(QString::fromLatin1(args->name)));
+ else
+ optionsHeader = i18n("\nOptions:\n");
+
+ while (args)
+ {
+ const KCmdLineOptions *option = args->options;
+ QCString opt = "";
+//
+ while(option && option->name)
+ {
+ QString description;
+ QString descriptionRest;
+ QStringList dl;
+
+ // Option header
+ if (option->name[0] == ':')
+ {
+ if (option->description)
+ {
+ optionsHeader = "\n"+i18n(option->description);
+ if (!optionsHeader.endsWith("\n"))
+ optionsHeader.append("\n");
+ hasOptions = false;
+ }
+ option++;
+ continue;
+ }
+
+ // Free-form comment
+ if (option->name[0] == 0)
+ {
+ if (option->description)
+ {
+ QString tmp = "\n"+i18n(option->description);
+ if (!tmp.endsWith("\n"))
+ tmp.append("\n");
+ printQ(tmp);
+ }
+ option++;
+ continue;
+ }
+
+ // Options
+ if (option->description)
+ {
+ description = i18n(option->description);
+ dl = QStringList::split("\n", description, true);
+ description = dl.first();
+ dl.remove( dl.begin() );
+ }
+ QCString name = option->name;
+ if (name[0] == '!')
+ name = name.mid(1);
+
+ if (name[0] == '+')
+ {
+ if (!hasArgs)
+ {
+ printQ(i18n("\nArguments:\n"));
+ hasArgs = true;
+ }
+
+ name = name.mid(1);
+ if ((name[0] == '[') && (name[name.length()-1] == ']'))
+ name = name.mid(1, name.length()-2);
+ printQ(optionFormatString.arg(name, -25)
+ .arg(description));
+ }
+ else
+ {
+ if (!hasOptions)
+ {
+ printQ(optionsHeader);
+ hasOptions = true;
+ }
+
+ if ((name.length() == 1) || (name[1] == ' '))
+ name = "-"+name;
+ else
+ name = "--"+name;
+ if (!option->description)
+ {
+ opt = name + ", ";
+ }
+ else
+ {
+ opt = opt + name;
+ if (!option->def)
+ {
+ printQ(optionFormatString.arg(opt, -25)
+ .arg(description));
+ }
+ else
+ {
+ printQ(optionFormatStringDef.arg(opt, -25)
+ .arg(description).arg(option->def));
+ }
+ opt = "";
+ }
+ }
+ for(QStringList::Iterator it = dl.begin();
+ it != dl.end();
+ ++it)
+ {
+ printQ(optionFormatString.arg("", -25).arg(*it));
+ }
+
+ option++;
+ }
+ args = argsList->next();
+ if (!args || args->name || !args->id) break;
+ }
+ if (!showAll) break;
+ }
+
+ exit(254);
+}
+
+//
+// Member functions
+//
+
+/**
+ * Constructor.
+ *
+ * The given arguments are assumed to be constants.
+ */
+KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions *_options,
+ const char *_name, const char *_id)
+ : options(_options), name(_name), id(_id)
+{
+ parsedOptionList = 0;
+ parsedArgList = 0;
+ isQt = (::qstrcmp(id, "qt") == 0);
+}
+
+/**
+ * Destructor.
+ */
+KCmdLineArgs::~KCmdLineArgs()
+{
+ delete parsedOptionList;
+ delete parsedArgList;
+ if (argsList)
+ argsList->removeRef(this);
+}
+
+void
+KCmdLineArgs::clear()
+{
+ delete parsedArgList;
+ parsedArgList = 0;
+ delete parsedOptionList;
+ parsedOptionList = 0;
+}
+
+void
+KCmdLineArgs::reset()
+{
+ if ( argsList ) {
+ argsList->setAutoDelete( true );
+ argsList->clear();
+ delete argsList;
+ argsList = 0;
+ }
+ parsed = false;
+}
+
+void
+KCmdLineArgs::save( QDataStream &ds) const
+{
+ uint count = 0;
+ if (parsedOptionList)
+ parsedOptionList->save( ds );
+ else
+ ds << count;
+
+ if (parsedArgList)
+ parsedArgList->save( ds );
+ else
+ ds << count;
+}
+
+void
+KCmdLineArgs::load( QDataStream &ds)
+{
+ if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
+ if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
+
+ parsedOptionList->load( ds );
+ parsedArgList->load( ds );
+
+ if (parsedOptionList->count() == 0)
+ {
+ delete parsedOptionList;
+ parsedOptionList = 0;
+ }
+ if (parsedArgList->count() == 0)
+ {
+ delete parsedArgList;
+ parsedArgList = 0;
+ }
+}
+
+void
+KCmdLineArgs::setOption(const QCString &opt, bool enabled)
+{
+ if (isQt)
+ {
+ // Qt does it own parsing.
+ QCString arg = "-";
+ if( !enabled )
+ arg += "no";
+ arg += opt;
+ addArgument(arg);
+ }
+ if (!parsedOptionList) {
+ parsedOptionList = new KCmdLineParsedOptions;
+ parsedOptionList->setAutoDelete(true);
+ }
+
+ if (enabled)
+ parsedOptionList->replace( opt, new QCString("t") );
+ else
+ parsedOptionList->replace( opt, new QCString("f") );
+}
+
+void
+KCmdLineArgs::setOption(const QCString &opt, const char *value)
+{
+ if (isQt)
+ {
+ // Qt does it's own parsing.
+ QCString arg = "-";
+ arg += opt;
+ addArgument(arg);
+ addArgument(value);
+
+#ifdef Q_WS_X11
+ // Hack coming up!
+ if (arg == "-display")
+ {
+ setenv(DISPLAY, value, true);
+ }
+#endif
+ }
+ if (!parsedOptionList) {
+ parsedOptionList = new KCmdLineParsedOptions;
+ parsedOptionList->setAutoDelete(true);
+ }
+
+ parsedOptionList->insert( opt, new QCString(value) );
+}
+
+QCString
+KCmdLineArgs::getOption(const char *_opt) const
+{
+ QCString *value = 0;
+ if (parsedOptionList)
+ {
+ value = parsedOptionList->find(_opt);
+ }
+
+ if (value)
+ return (*value);
+
+ // Look up the default.
+ const char *opt_name;
+ const char *def;
+ bool dummy = true;
+ QCString opt = _opt;
+ int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
+
+ if (result != 3)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
+ _opt, _opt);
+ fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+ return QCString(def);
+}
+
+QCStringList
+KCmdLineArgs::getOptionList(const char *_opt) const
+{
+ QCStringList result;
+ if (!parsedOptionList)
+ return result;
+
+ while(true)
+ {
+ QCString *value = parsedOptionList->take(_opt);
+ if (!value)
+ break;
+ result.prepend(*value);
+ delete value;
+ }
+
+ // Reinsert items in dictionary
+ // WABA: This is rather silly, but I don't want to add restrictions
+ // to the API like "you can only call this function once".
+ // I can't access all items without taking them out of the list.
+ // So taking them out and then putting them back is the only way.
+ for(QCStringList::ConstIterator it=result.begin();
+ it != result.end();
+ ++it)
+ {
+ parsedOptionList->insert(_opt, new QCString(*it));
+ }
+ return result;
+}
+
+bool
+KCmdLineArgs::isSet(const char *_opt) const
+{
+ // Look up the default.
+ const char *opt_name;
+ const char *def;
+ bool dummy = true;
+ QCString opt = _opt;
+ int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
+
+ if (result == 0)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
+ _opt, _opt);
+ fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+
+ QCString *value = 0;
+ if (parsedOptionList)
+ {
+ value = parsedOptionList->find(opt);
+ }
+
+ if (value)
+ {
+ if (result == 3)
+ return true;
+ else
+ return ((*value)[0] == 't');
+ }
+
+ if (result == 3)
+ return false; // String option has 'false' as default.
+
+ // We return 'true' as default if the option was listed as '-nofork'
+ // We return 'false' as default if the option was listed as '-fork'
+ return (result == 2);
+}
+
+int
+KCmdLineArgs::count() const
+{
+ if (!parsedArgList)
+ return 0;
+ return parsedArgList->count();
+}
+
+const char *
+KCmdLineArgs::arg(int n) const
+{
+ if (!parsedArgList || (n >= (int) parsedArgList->count()))
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
+ fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
+ n);
+
+ assert( 0 );
+ exit(255);
+ }
+
+ return parsedArgList->at(n);
+}
+
+KURL
+KCmdLineArgs::url(int n) const
+{
+ return makeURL( arg(n) );
+}
+
+KURL KCmdLineArgs::makeURL(const char *_urlArg)
+{
+ const QString urlArg = QFile::decodeName(_urlArg);
+ QFileInfo fileInfo(urlArg);
+ if (!fileInfo.isRelative()) { // i.e. starts with '/', on unix
+ KURL result;
+ result.setPath(urlArg);
+ return result; // Absolute path.
+ }
+
+ if ( KURL::isRelativeURL(urlArg) || fileInfo.exists() ) {
+ KURL result;
+ result.setPath( cwd()+'/'+urlArg );
+ result.cleanPath();
+ return result; // Relative path
+ }
+
+ return KURL(urlArg); // Argument is a URL
+}
+
+void
+KCmdLineArgs::addArgument(const char *argument)
+{
+ if (!parsedArgList)
+ parsedArgList = new KCmdLineParsedArgs;
+
+ parsedArgList->append(argument);
+}
+
+static const KCmdLineOptions kde_tempfile_option[] =
+{
+ { "tempfile", I18N_NOOP("The files/URLs opened by the application will be deleted after use"), 0},
+ KCmdLineLastOption
+};
+
+void
+KCmdLineArgs::addTempFileOption()
+{
+ KCmdLineArgs::addCmdLineOptions( kde_tempfile_option, "KDE-tempfile", "kde-tempfile" );
+}
+
+bool KCmdLineArgs::isTempFileSet()
+{
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" );
+ if ( args )
+ return args->isSet( "tempfile" );
+ return false;
+}
diff --git a/kdecore/kcmdlineargs.h b/kdecore/kcmdlineargs.h
new file mode 100644
index 000000000..278ad976e
--- /dev/null
+++ b/kdecore/kcmdlineargs.h
@@ -0,0 +1,690 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KCMDLINEARGS_H_
+#define _KCMDLINEARGS_H_
+
+#include "kdelibs_export.h"
+#include <kurl.h>
+
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+
+typedef QValueList<QCString> QCStringList;
+
+/**
+ * @short Structure that holds command line options.
+ *
+ * This class is intended to be used with the KCmdLineArgs class, which
+ * provides convenient and powerful command line argument parsing and
+ * handling functionality.
+ *
+ * @see KCmdLineArgs for additional usage information
+ */
+struct KDECORE_EXPORT KCmdLineOptions
+{
+ /**
+ * The name of the argument as it should be called on the command line and
+ * appear in <i>myapp --help</i>.
+ *
+ * Note that if this option starts with "no" that you will need to test for
+ * the name without the "no" and the result will be the inverse of what is
+ * specified. i.e. if "nofoo" is the name of the option and
+ * <i>myapp --nofoo</i> is called:
+ *
+ * \code
+ * KCmdLineArgs::parsedArgs()->isSet("foo"); // false
+ * \endcode
+ */
+ const char *name;
+ /**
+ * The text description of the option as should appear in
+ * <i>myapp --help</i>. This value should be wrapped with I18N_NOOP().
+ */
+ const char *description;
+ /**
+ * The default value for the option, if it is not specified on the
+ * command line.
+ */
+ const char *def; // Default
+};
+
+#define KCmdLineLastOption { 0, 0, 0 }
+
+class KCmdLineArgsList;
+class KApplication;
+class KUniqueApplication;
+class KCmdLineParsedOptions;
+class KCmdLineParsedArgs;
+class KAboutData;
+class KCmdLineArgsPrivate;
+
+/**
+ * @short A class for command-line argument handling.
+ *
+ * KCmdLineArgs provides simple access to the command-line arguments
+ * for an application. It takes into account Qt-specific options,
+ * KDE-specific options and application specific options.
+ *
+ * This class is used in %main() via the static method
+ * init().
+ *
+ * A typical %KDE application using %KCmdLineArgs should look like this:
+ *
+ * \code
+ * int main(int argc, char *argv[])
+ * {
+ * // Initialize command line args
+ * KCmdLineArgs::init(argc, argv, appName, programName, description, version);
+ *
+ * // Tell which options are supported
+ * KCmdLineArgs::addCmdLineOptions( options );
+ *
+ * // Add options from other components
+ * KUniqueApplication::addCmdLineOptions();
+ *
+ * ....
+ *
+ * // Create application object without passing 'argc' and 'argv' again.
+ * KUniqueApplication app;
+ *
+ * ....
+ *
+ * // Handle our own options/arguments
+ * // A KApplication will usually do this in main but this is not
+ * // necessary.
+ * // A KUniqueApplication might want to handle it in newInstance().
+ *
+ * KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ *
+ * // A binary option (on / off)
+ * if (args->isSet("some-option"))
+ * ....
+ *
+ * // An option which takes an additional argument
+ * QCString anotherOptionArg = args->getOption("another-option");
+ *
+ * // Arguments (e.g. files to open)
+ * for(int i = 0; i < args->count(); i++) // Counting start at 0!
+ * {
+ * // don't forget to convert to Unicode!
+ * openFile( QFile::decodeName( args->arg(i)));
+ * // Or more convenient:
+ * // openURL( args->url(i));
+ *
+ * }
+ *
+ * args->clear(); // Free up some memory.
+ * ....
+ * }
+ * \endcode
+ *
+ * The options that an application supports are configured using the
+ * KCmdLineOptions class. An example is shown below:
+ *
+ * \code
+ * static const KCmdLineOptions options[] =
+ * {
+ * { "a", I18N_NOOP("A short binary option"), 0 },
+ * { "b \<file>", I18N_NOOP("A short option which takes an argument"), 0 },
+ * { "c \<speed>", I18N_NOOP("As above but with a default value"), "9600" },
+ * { "option1", I18N_NOOP("A long binary option, off by default"), 0 },
+ * { "nooption2", I18N_NOOP("A long binary option, on by default"), 0 },
+ * { ":", I18N_NOOP("Extra options:"), 0 },
+ * { "option3 \<file>", I18N_NOOP("A long option which takes an argument"), 0 },
+ * { "option4 \<speed>", I18N_NOOP("A long option which takes an argument, defaulting to 9600"), "9600" },
+ * { "d", 0, 0 },
+ * { "option5", I18N_NOOP("A long option which has a short option as alias"), 0 },
+ * { "e", 0, 0 },
+ * { "nooption6", I18N_NOOP("Another long option with an alias"), 0 },
+ * { "f", 0, 0 },
+ * { "option7 \<speed>", I18N_NOOP("'--option7 speed' is the same as '-f speed'"), 0 },
+ * { "!option8 \<cmd>", I18N_NOOP("All options following this one will be treated as arguments"), 0 },
+ * { "+file", I18N_NOOP("A required argument 'file'"), 0 },
+ * { "+[arg1]", I18N_NOOP("An optional argument 'arg1'"), 0 },
+ * { "!+command", I18N_NOOP("A required argument 'command', that can contain multiple words, even starting with '-'"), 0 },
+ * { "", I18N_NOOP("Additional help text not associated with any particular option") 0 },
+ * KCmdLineLastOption // End of options.
+ * };
+ * \endcode
+ *
+ * The I18N_NOOP macro is used to indicate that these strings should be
+ * marked for translation. The actual translation is done by KCmdLineArgs.
+ * You can't use i18n() here because we are setting up a static data
+ * structure and can't do translations at compile time.
+ *
+ * Note that a program should define the options before any arguments.
+ *
+ * When a long option has a short option as an alias, a program should
+ * only test for the long option.
+ *
+ * With the above options a command line could look like:
+ * \code
+ * myapp -a -c 4800 --display localhost:0.0 --nooption5 -d /tmp/file
+ * \endcode
+ *
+ * Long binary options can be in the form 'option' and 'nooption'.
+ * A command line may contain the same binary option multiple times,
+ * the last option determines the outcome:
+ * \code
+ * myapp --nooption4 --option4 --nooption4
+ * \endcode
+ * is the same as:
+ * \code
+ * myapp --nooption4
+ * \endcode
+ *
+ * If an option value is provided multiple times, normally only the last
+ * value is used:
+ * \code
+ * myapp -c 1200 -c 2400 -c 4800
+ * \endcode
+ * is usually the same as:
+ * \code
+ * myapp -c 4800
+ * \endcode
+ *
+ * However, an application can choose to use all values specified as well.
+ * As an example of this, consider that you may wish to specify a
+ * number of directories to use:
+ * \code
+ * myapp -I /usr/include -I /opt/kde/include -I /usr/X11/include
+ * \endcode
+ * When an application does this it should mention this in the description
+ * of the option. To access these options, use getOptionList()
+ *
+ * Tips for end-users:
+ *
+ * @li Single char options like "-a -b -c" may be combined into "-abc"
+ * @li The option "--foo bar" may also be written "--foo=bar"
+ * @li The option "-P lp1" may also be written "-P=lp1" or "-Plp1"
+ * @li The option "--foo bar" may also be written "-foo bar"
+ *
+ * @author Waldo Bastian
+ * @version 0.0.4
+ */
+class KDECORE_EXPORT KCmdLineArgs
+{
+ friend class KApplication;
+ friend class KUniqueApplication;
+ friend class QPtrList<KCmdLineArgs>;
+public:
+ // Static functions:
+
+ /**
+ * Initialize class.
+ *
+ * This function should be called as the very first thing in
+ * your application.
+ * @param _argc As passed to @p main(...).
+ * @param _argv As passed to @p main(...).
+ * @param _appname The untranslated name of your application. This should
+ * match with @p argv[0].
+ * @param programName A program name string to be used for display
+ * purposes. This string should be marked for
+ * translation. Example: I18N_NOOP("KEdit")
+ * @param _description A short description of what your application is about.
+ * @param _version A version.
+ * @param noKApp Set this true to not add commandline options for
+ * QApplication / KApplication
+ *
+ * @since 3.2
+ */
+ static void init(int _argc, char **_argv, const char *_appname,
+ const char* programName, const char *_description,
+ const char *_version, bool noKApp = false);
+ /**
+ * @deprecated
+ * You should convert any calls to this method to use the one
+ * above, by adding in the program name to be used for display
+ * purposes. Do not forget to mark it for translation using I18N_NOOP.
+ */
+ static void init(int _argc, char **_argv,
+ const char *_appname, const char *_description,
+ const char *_version, bool noKApp = false) KDE_DEPRECATED;
+
+ /**
+ * Initialize class.
+ *
+ * This function should be called as the very first thing in
+ * your application. It uses KAboutData to replace some of the
+ * arguments that would otherwise be required.
+ *
+ * @param _argc As passed to @p main(...).
+ * @param _argv As passed to @p main(...).
+ * @param about A KAboutData object describing your program.
+ * @param noKApp Set this true to not add commandline options for
+ * QApplication / KApplication
+ */
+ static void init(int _argc, char **_argv,
+ const KAboutData *about, bool noKApp = false);
+
+ /**
+ * Initialize Class
+ *
+ * This function should be called as the very first thing in your
+ * application. This method will rarely be used, since it doesn't
+ * provide any argument parsing. It does provide access to the
+ * KAboutData information.
+ * This method is exactly the same as calling
+ * init(0,0, const KAboutData *about, true).
+ *
+ * @param about the about data.
+ * \see KAboutData
+ */
+ static void init(const KAboutData *about);
+
+ /**
+ * Add options to your application.
+ *
+ * You must make sure that all possible options have been added before
+ * any class uses the command line arguments.
+ *
+ * The list of options should look like this:
+ *
+ * \code
+ * static KCmdLineOptions options[] =
+ * {
+ * { "option1 \<argument>", I18N_NOOP("Description 1"), "my_extra_arg" },
+ * { "o", 0, 0 },
+ * { "option2", I18N_NOOP("Description 2"), 0 },
+ * { "nooption3", I18N_NOOP("Description 3"), 0 },
+ * KCmdLineLastOption
+ * }
+ * \endcode
+ *
+ * @li "option1" is an option that requires an additional argument,
+ * but if one is not provided, it uses "my_extra_arg".
+ * @li "option2" is an option that can be turned on. The default is off.
+ * @li "option3" is an option that can be turned off. The default is on.
+ * @li "o" does not have a description. It is an alias for the option
+ * that follows. In this case "option2".
+ * @li "+file" specifies an argument. The '+' is removed. If your program
+ * doesn't specify that it can use arguments your program will abort
+ * when an argument is passed to it. Note that the reverse is not
+ * true. If required, you must check yourself the number of arguments
+ * specified by the user:
+ * \code
+ * KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ * if (args->count() == 0) KCmdLineArgs::usage(i18n("No file specified!"));
+ * \endcode
+ *
+ * In BNF:
+ * \code
+ * cmd = myapp [options] file
+ * options = (option)*
+ * option = --option1 \<argument> |
+ * (-o | --option2 | --nooption2) |
+ * ( --option3 | --nooption3 )
+ * \endcode
+ *
+ * Instead of "--option3" one may also use "-option3"
+ *
+ * Usage examples:
+ *
+ * @li "myapp --option1 test"
+ * @li "myapp" (same as "myapp --option1 my_extra_arg")
+ * @li "myapp --option2"
+ * @li "myapp --nooption2" (same as "myapp", since it is off by default)
+ * @li "myapp -o" (same as "myapp --option2")
+ * @li "myapp --nooption3"
+ * @li "myapp --option3 (same as "myapp", since it is on by default)
+ * @li "myapp --option2 --nooption2" (same as "myapp", because it
+ * option2 is off by default, and the last usage applies)
+ * @li "myapp /tmp/file"
+ *
+ * @param options A list of options that your code supplies.
+ * @param name the name of the option, can be 0.
+ * @param id A name with which these options can be identified, can be 0.
+ * @param afterId The options are inserted after this set of options, can be 0.
+ */
+ static void addCmdLineOptions( const KCmdLineOptions *options,
+ const char *name=0, const char *id = 0,
+ const char *afterId=0);
+
+ /**
+ * Access parsed arguments.
+ *
+ * This function returns all command line arguments that your code
+ * handles. If unknown command-line arguments are encountered the program
+ * is aborted and usage information is shown.
+ *
+ * @param id The name of the options you are interested in, can be 0.
+ */
+ static KCmdLineArgs *parsedArgs(const char *id=0);
+
+ /**
+ * Get the CWD (Current Working Directory) associated with the
+ * current command line arguments.
+ *
+ * Typically this is needed in KUniqueApplication::newInstance()
+ * since the CWD of the process may be different from the CWD
+ * where the user started a second instance.
+ * @return the current working directory
+ **/
+ static QString cwd();
+
+ /**
+ * Get the appname according to argv[0].
+ * @return the name of the application
+ **/
+ static const char *appName();
+
+ /**
+ * Print the usage help to stdout and exit.
+ *
+ * @param id if 0, print all options. If id is set, only print the
+ * option specified by id. The id is the value set by
+ * addCmdLineOptions().
+ **/
+ static void usage(const char *id = 0);
+
+ /**
+ * Print an error to stderr and the usage help to stdout and exit.
+ * @param error the error to print
+ **/
+ static void usage(const QString &error);
+
+ /**
+ * Enable i18n to be able to print a translated error message.
+ *
+ * N.B.: This function leaks memory, therefore you are expected to exit
+ * afterwards (e.g., by calling usage()).
+ **/
+ static void enable_i18n();
+
+ // Member functions:
+
+
+ /**
+ * Read out a string option.
+ *
+ * The option must have a corresponding KCmdLineOptions entry
+ * of the form:
+ * \code
+ * { "option \<argument>", I18N_NOOP("Description"), "default" }
+ * \endcode
+ * You cannot test for the presence of an alias - you must always
+ * test for the full option.
+ *
+ * @param option The name of the option without '-'.
+ *
+ * @return The value of the option. If the option was not
+ * present on the command line the default is returned.
+ * If the option was present more than the value of the
+ * last occurrence is used.
+ */
+ QCString getOption(const char *option) const;
+
+ /**
+ * Read out all occurrences of a string option.
+ *
+ * The option must have a corresponding KCmdLineOptions entry
+ * of the form:
+ * \code
+ * { "option \<argument>", I18N_NOOP("Description"), "default" }
+ * \endcode
+ * You cannot test for the presence of an alias - you must always
+ * test for the full option.
+ *
+ * @param option The name of the option, without '-' or '-no'.
+ *
+ * @return A list of all option values. If no option was present
+ * on the command line, an empty list is returned.
+ */
+ QCStringList getOptionList(const char *option) const;
+
+ /**
+ * Read out a boolean option or check for the presence of string option.
+ *
+ * @param option The name of the option without '-' or '-no'.
+ *
+ * @return The value of the option. It will be true if the option
+ * was specifically turned on in the command line, or if the option
+ * is turned on by default (in the KCmdLineOptions list) and was
+ * not specifically turned off in the command line. Equivalently,
+ * it will be false if the option was specifically turned off in
+ * the command line, or if the option is turned off by default (in
+ * the KCmdLineOptions list) and was not specifically turned on in
+ * the command line.
+ */
+ bool isSet(const char *option) const;
+
+ /**
+ * Read the number of arguments that aren't options (but,
+ * for example, filenames).
+ *
+ * @return The number of arguments that aren't options
+ */
+ int count() const;
+
+ /**
+ * Read out an argument.
+ *
+ * @param n The argument to read. 0 is the first argument.
+ * count()-1 is the last argument.
+ *
+ * @return A @p const @p char @p * pointer to the n'th argument.
+ */
+ const char *arg(int n) const;
+
+ /**
+ * Read out an argument representing a URL.
+ *
+ * The argument can be
+ * @li an absolute filename
+ * @li a relative filename
+ * @li a URL
+ *
+ * @param n The argument to read. 0 is the first argument.
+ * count()-1 is the last argument.
+ *
+ * @return a URL representing the n'th argument.
+ */
+ KURL url(int n) const;
+
+ /**
+ * Used by url().
+ * Made public for apps that don't use KCmdLineArgs
+ * @param urlArg the argument
+ * @return the url.
+ */
+ static KURL makeURL( const char * urlArg );
+
+ /**
+ * Made public for apps that don't use KCmdLineArgs
+ * To be done before makeURL, to set the current working
+ * directory in case makeURL needs it.
+ * @param cwd the new working directory
+ */
+ static void setCwd( char * cwd ) { mCwd = cwd; }
+
+ /**
+ * Clear all options and arguments.
+ */
+ void clear();
+
+ /**
+ * Reset all option definitions, i.e. cancel all addCmdLineOptions calls.
+ * Note that KApplication's options are removed too, you might want to
+ * call KApplication::addCmdLineOptions if you want them back.
+ *
+ * You usually don't want to call this method.
+ */
+ static void reset();
+
+ /**
+ * Load arguments from a stream.
+ */
+ static void loadAppArgs( QDataStream &);
+
+ /**
+ * Add standard option --tempfile
+ * @since 3.4
+ */
+ static void addTempFileOption();
+
+ // this avoids having to know the "id" used by addTempFileOption
+ // but this approach doesn't scale well, we can't have 50 standard options here...
+ /**
+ * @return true if --tempfile was set
+ * @since 3.4
+ */
+ static bool isTempFileSet();
+
+protected:
+ /**
+ * @internal
+ * Constructor.
+ */
+ KCmdLineArgs( const KCmdLineOptions *_options, const char *_name,
+ const char *_id);
+
+ /**
+ * @internal use only.
+ *
+ * Use clear() if you want to free up some memory.
+ *
+ * Destructor.
+ */
+ ~KCmdLineArgs();
+
+private:
+ /**
+ * @internal
+ *
+ * Checks what to do with a single option
+ */
+ static void findOption(const char *_opt, QCString opt, int &i, bool enabled, bool &moreOptions);
+
+ /**
+ * @internal
+ *
+ * Parse all arguments, verify correct syntax and put all arguments
+ * where they belong.
+ */
+ static void parseAllArgs();
+
+ /**
+ * @internal for KApplication only:
+ *
+ * Return argc
+ */
+ static int *qt_argc();
+
+ /**
+ * @internal for KApplication only:
+ *
+ * Return argv
+ */
+
+ static char ***qt_argv();
+
+ /**
+ * @internal
+ *
+ * Remove named options.
+ *
+ * @param id The name of the options to be removed.
+ */
+ static void removeArgs(const char *id);
+
+ /**
+ * @internal for KUniqueApplication only:
+ *
+ * Save all but the Qt and KDE arguments to a stream.
+ */
+ static void saveAppArgs( QDataStream &);
+
+ /**
+ * @internal
+ *
+ * Set a boolean option
+ */
+ void setOption(const QCString &option, bool enabled);
+
+ /**
+ * @internal
+ *
+ * Set a string option
+ */
+ void setOption(const QCString &option, const char *value);
+
+ /**
+ * @internal
+ *
+ * Add an argument
+ */
+ void addArgument(const char *argument);
+
+ /**
+ * @internal
+ *
+ * Save to a stream.
+ */
+ void save( QDataStream &) const;
+
+ /**
+ * @internal
+ *
+ * Restore from a stream.
+ */
+ void load( QDataStream &);
+
+ /**
+ * @internal for KApplication only
+ *
+ * Initialize class.
+ *
+ * This function should be called as the very first thing in
+ * your application.
+ * @param argc As passed to @p main(...).
+ * @param argv As passed to @p main(...).
+ * @param appname The untranslated name of your application. This should
+ * match with @p argv[0].
+ *
+ * This function makes KCmdLineArgs ignore all unknown options as well as
+ * all arguments.
+ */
+ static void initIgnore(int _argc, char **_argv, const char *_appname);
+
+ static void printQ(const QString &msg);
+
+ const KCmdLineOptions *options;
+ const char *name;
+ const char *id;
+ KCmdLineParsedOptions *parsedOptionList;
+ KCmdLineParsedArgs *parsedArgList;
+ bool isQt;
+
+ static KCmdLineArgsList *argsList; // All options.
+ static const KAboutData *about;
+
+ static int argc; // The original argc
+ static char **argv; // The original argv
+ static bool parsed; // Whether we have parsed the arguments since calling init
+ static bool ignoreUnknown; // Ignore unknown options and arguments
+ static char *mCwd; // Current working directory. Important for KUnqiueApp!
+ static bool parseArgs;
+
+ KCmdLineArgsPrivate *d;
+};
+
+#endif
+
diff --git a/kdecore/kcompletion.cpp b/kdecore/kcompletion.cpp
new file mode 100644
index 000000000..dfa8f351b
--- /dev/null
+++ b/kdecore/kcompletion.cpp
@@ -0,0 +1,892 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <knotifyclient.h>
+#include <kglobal.h>
+
+#include <qptrvector.h>
+
+#include "kcompletion.h"
+#include "kcompletion_private.h"
+
+
+class KCompletionPrivate
+{
+public:
+ // not a member to avoid #including kcompletion_private.h from kcompletion.h
+ // list used for nextMatch() and previousMatch()
+ KCompletionMatchesWrapper matches;
+};
+
+KCompletion::KCompletion()
+{
+ d = new KCompletionPrivate;
+
+ myCompletionMode = KGlobalSettings::completionMode();
+ myTreeRoot = new KCompTreeNode;
+ myBeep = true;
+ myIgnoreCase = false;
+ myHasMultipleMatches = false;
+ myRotationIndex = 0;
+ setOrder( Insertion );
+}
+
+KCompletion::~KCompletion()
+{
+ delete d;
+ delete myTreeRoot;
+}
+
+void KCompletion::setOrder( CompOrder order )
+{
+ myOrder = order;
+ d->matches.setSorting( order == Weighted );
+}
+
+void KCompletion::setIgnoreCase( bool ignoreCase )
+{
+ myIgnoreCase = ignoreCase;
+}
+
+void KCompletion::setItems( const QStringList& items )
+{
+ clear();
+ insertItems( items );
+}
+
+
+void KCompletion::insertItems( const QStringList& items )
+{
+ bool weighted = (myOrder == Weighted);
+ QStringList::ConstIterator it;
+ if ( weighted ) { // determine weight
+ for ( it = items.begin(); it != items.end(); ++it )
+ addWeightedItem( *it );
+ }
+ else {
+ for ( it = items.begin(); it != items.end(); ++it )
+ addItem( *it, 0 );
+ }
+}
+
+QStringList KCompletion::items() const
+{
+ KCompletionMatchesWrapper list; // unsorted
+ bool addWeight = (myOrder == Weighted);
+ extractStringsFromNode( myTreeRoot, QString::null, &list, addWeight );
+
+ return list.list();
+}
+
+bool KCompletion::isEmpty() const
+{
+ return (myTreeRoot->childrenCount() == 0);
+}
+
+void KCompletion::addItem( const QString& item )
+{
+ d->matches.clear();
+ myRotationIndex = 0;
+ myLastString = QString::null;
+
+ addItem( item, 0 );
+}
+
+void KCompletion::addItem( const QString& item, uint weight )
+{
+ if ( item.isEmpty() )
+ return;
+
+ KCompTreeNode *node = myTreeRoot;
+ uint len = item.length();
+
+ bool sorted = (myOrder == Sorted);
+ bool weighted = ((myOrder == Weighted) && weight > 1);
+
+ // knowing the weight of an item, we simply add this weight to all of its
+ // nodes.
+
+ for ( uint i = 0; i < len; i++ ) {
+ node = node->insert( item.at(i), sorted );
+ if ( weighted )
+ node->confirm( weight -1 ); // node->insert() sets weighting to 1
+ }
+
+ // add 0x0-item as delimiter with evtl. weight
+ node = node->insert( 0x0, true );
+ if ( weighted )
+ node->confirm( weight -1 );
+// qDebug("*** added: %s (%i)", item.latin1(), node->weight());
+}
+
+void KCompletion::addWeightedItem( const QString& item )
+{
+ if ( myOrder != Weighted ) {
+ addItem( item, 0 );
+ return;
+ }
+
+ uint len = item.length();
+ uint weight = 0;
+
+ // find out the weighting of this item (appended to the string as ":num")
+ int index = item.findRev(':');
+ if ( index > 0 ) {
+ bool ok;
+ weight = item.mid( index + 1 ).toUInt( &ok );
+ if ( !ok )
+ weight = 0;
+
+ len = index; // only insert until the ':'
+ }
+
+ addItem( item.left( len ), weight );
+ return;
+}
+
+
+void KCompletion::removeItem( const QString& item )
+{
+ d->matches.clear();
+ myRotationIndex = 0;
+ myLastString = QString::null;
+
+ myTreeRoot->remove( item );
+}
+
+
+void KCompletion::clear()
+{
+ d->matches.clear();
+ myRotationIndex = 0;
+ myLastString = QString::null;
+
+ delete myTreeRoot;
+ myTreeRoot = new KCompTreeNode;
+}
+
+
+QString KCompletion::makeCompletion( const QString& string )
+{
+ if ( myCompletionMode == KGlobalSettings::CompletionNone )
+ return QString::null;
+
+ //kdDebug(0) << "KCompletion: completing: " << string << endl;
+
+ d->matches.clear();
+ myRotationIndex = 0;
+ myHasMultipleMatches = false;
+ myLastMatch = myCurrentMatch;
+
+ // in Shell-completion-mode, emit all matches when we get the same
+ // complete-string twice
+ if ( myCompletionMode == KGlobalSettings::CompletionShell &&
+ string == myLastString ) {
+ // Don't use d->matches since calling postProcessMatches()
+ // on d->matches here would interfere with call to
+ // postProcessMatch() during rotation
+
+ findAllCompletions( string, &d->matches, myHasMultipleMatches );
+ QStringList l = d->matches.list();
+ postProcessMatches( &l );
+ emit matches( l );
+
+ if ( l.isEmpty() )
+ doBeep( NoMatch );
+
+ return QString::null;
+ }
+
+ QString completion;
+ // in case-insensitive popup mode, we search all completions at once
+ if ( myCompletionMode == KGlobalSettings::CompletionPopup ||
+ myCompletionMode == KGlobalSettings::CompletionPopupAuto ) {
+ findAllCompletions( string, &d->matches, myHasMultipleMatches );
+ if ( !d->matches.isEmpty() )
+ completion = d->matches.first();
+ }
+ else
+ completion = findCompletion( string );
+
+ if ( myHasMultipleMatches )
+ emit multipleMatches();
+
+ myLastString = string;
+ myCurrentMatch = completion;
+
+ postProcessMatch( &completion );
+
+ if ( !string.isEmpty() ) { // only emit match when string is not empty
+ //kdDebug(0) << "KCompletion: Match: " << completion << endl;
+ emit match( completion );
+ }
+
+ if ( completion.isNull() )
+ doBeep( NoMatch );
+
+ return completion;
+}
+
+
+QStringList KCompletion::substringCompletion( const QString& string ) const
+{
+ // get all items in the tree, possibly in sorted order
+ bool sorted = (myOrder == Weighted);
+ KCompletionMatchesWrapper allItems( sorted );
+ extractStringsFromNode( myTreeRoot, QString::null, &allItems, false );
+
+ QStringList list = allItems.list();
+
+ // subStringMatches is invoked manually, via a shortcut, so we should
+ // beep here, if necessary.
+ if ( list.isEmpty() ) {
+ doBeep( NoMatch );
+ return list;
+ }
+
+ if ( string.isEmpty() ) { // shortcut
+ postProcessMatches( &list );
+ return list;
+ }
+
+ QStringList matches;
+ QStringList::ConstIterator it = list.begin();
+
+ for( ; it != list.end(); ++it ) {
+ QString item = *it;
+ if ( item.find( string, 0, false ) != -1 ) { // always case insensitive
+ matches.append( item );
+ }
+ }
+
+ postProcessMatches( &matches );
+
+ if ( matches.isEmpty() )
+ doBeep( NoMatch );
+
+ return matches;
+}
+
+
+void KCompletion::setCompletionMode( KGlobalSettings::Completion mode )
+{
+ myCompletionMode = mode;
+}
+
+QStringList KCompletion::allMatches()
+{
+ // Don't use d->matches since calling postProcessMatches()
+ // on d->matches here would interfere with call to
+ // postProcessMatch() during rotation
+ KCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( myLastString, &matches, dummy );
+ QStringList l = matches.list();
+ postProcessMatches( &l );
+ return l;
+}
+
+KCompletionMatches KCompletion::allWeightedMatches()
+{
+ // Don't use d->matches since calling postProcessMatches()
+ // on d->matches here would interfere with call to
+ // postProcessMatch() during rotation
+ KCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( myLastString, &matches, dummy );
+ KCompletionMatches ret( matches );
+ postProcessMatches( &ret );
+ return ret;
+}
+
+QStringList KCompletion::allMatches( const QString &string )
+{
+ KCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( string, &matches, dummy );
+ QStringList l = matches.list();
+ postProcessMatches( &l );
+ return l;
+}
+
+KCompletionMatches KCompletion::allWeightedMatches( const QString &string )
+{
+ KCompletionMatchesWrapper matches( myOrder == Weighted );
+ bool dummy;
+ findAllCompletions( string, &matches, dummy );
+ KCompletionMatches ret( matches );
+ postProcessMatches( &ret );
+ return ret;
+}
+
+/////////////////////////////////////////////////////
+///////////////// tree operations ///////////////////
+
+
+QString KCompletion::nextMatch()
+{
+ QString completion;
+ myLastMatch = myCurrentMatch;
+
+ if ( d->matches.isEmpty() ) {
+ findAllCompletions( myLastString, &d->matches, myHasMultipleMatches );
+ completion = d->matches.first();
+ myCurrentMatch = completion;
+ myRotationIndex = 0;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+ }
+
+ QStringList matches = d->matches.list();
+ myLastMatch = matches[ myRotationIndex++ ];
+
+ if ( myRotationIndex == matches.count() -1 )
+ doBeep( Rotation ); // indicate last matching item -> rotating
+
+ else if ( myRotationIndex == matches.count() )
+ myRotationIndex = 0;
+
+ completion = matches[ myRotationIndex ];
+ myCurrentMatch = completion;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+}
+
+
+
+QString KCompletion::previousMatch()
+{
+ QString completion;
+ myLastMatch = myCurrentMatch;
+
+ if ( d->matches.isEmpty() ) {
+ findAllCompletions( myLastString, &d->matches, myHasMultipleMatches );
+ completion = d->matches.last();
+ myCurrentMatch = completion;
+ myRotationIndex = 0;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+ }
+
+ QStringList matches = d->matches.list();
+ myLastMatch = matches[ myRotationIndex ];
+ if ( myRotationIndex == 1 )
+ doBeep( Rotation ); // indicate first item -> rotating
+
+ else if ( myRotationIndex == 0 )
+ myRotationIndex = matches.count();
+
+ myRotationIndex--;
+
+ completion = matches[ myRotationIndex ];
+ myCurrentMatch = completion;
+ postProcessMatch( &completion );
+ emit match( completion );
+ return completion;
+}
+
+
+
+// tries to complete "string" from the tree-root
+QString KCompletion::findCompletion( const QString& string )
+{
+ QChar ch;
+ QString completion;
+ const KCompTreeNode *node = myTreeRoot;
+
+ // start at the tree-root and try to find the search-string
+ for( uint i = 0; i < string.length(); i++ ) {
+ ch = string.at( i );
+ node = node->find( ch );
+
+ if ( node )
+ completion += ch;
+ else
+ return QString::null; // no completion
+ }
+
+ // Now we have the last node of the to be completed string.
+ // Follow it as long as it has exactly one child (= longest possible
+ // completion)
+
+ while ( node->childrenCount() == 1 ) {
+ node = node->firstChild();
+ if ( !node->isNull() )
+ completion += *node;
+ }
+ // if multiple matches and auto-completion mode
+ // -> find the first complete match
+ if ( node && node->childrenCount() > 1 ) {
+ myHasMultipleMatches = true;
+
+ if ( myCompletionMode == KGlobalSettings::CompletionAuto ) {
+ myRotationIndex = 1;
+ if (myOrder != Weighted) {
+ while ( (node = node->firstChild()) ) {
+ if ( !node->isNull() )
+ completion += *node;
+ else
+ break;
+ }
+ }
+ else {
+ // don't just find the "first" match, but the one with the
+ // highest priority
+
+ const KCompTreeNode* temp_node = 0L;
+ while(1) {
+ int count = node->childrenCount();
+ temp_node = node->firstChild();
+ uint weight = temp_node->weight();
+ const KCompTreeNode* hit = temp_node;
+ for( int i = 1; i < count; i++ ) {
+ temp_node = node->childAt(i);
+ if( temp_node->weight() > weight ) {
+ hit = temp_node;
+ weight = hit->weight();
+ }
+ }
+ // 0x0 has the highest priority -> we have the best match
+ if ( hit->isNull() )
+ break;
+
+ node = hit;
+ completion += *node;
+ }
+ }
+ }
+
+ else
+ doBeep( PartialMatch ); // partial match -> beep
+ }
+
+ return completion;
+}
+
+
+void KCompletion::findAllCompletions(const QString& string,
+ KCompletionMatchesWrapper *matches,
+ bool& hasMultipleMatches) const
+{
+ //kdDebug(0) << "*** finding all completions for " << string << endl;
+
+ if ( string.isEmpty() )
+ return;
+
+ if ( myIgnoreCase ) { // case insensitive completion
+ extractStringsFromNodeCI( myTreeRoot, QString::null, string, matches );
+ hasMultipleMatches = (matches->count() > 1);
+ return;
+ }
+
+ QChar ch;
+ QString completion;
+ const KCompTreeNode *node = myTreeRoot;
+
+ // start at the tree-root and try to find the search-string
+ for( uint i = 0; i < string.length(); i++ ) {
+ ch = string.at( i );
+ node = node->find( ch );
+
+ if ( node )
+ completion += ch;
+ else
+ return; // no completion -> return empty list
+ }
+
+ // Now we have the last node of the to be completed string.
+ // Follow it as long as it has exactly one child (= longest possible
+ // completion)
+
+ while ( node->childrenCount() == 1 ) {
+ node = node->firstChild();
+ if ( !node->isNull() )
+ completion += *node;
+ // kdDebug() << completion << node->latin1();
+ }
+
+
+ // there is just one single match)
+ if ( node->childrenCount() == 0 )
+ matches->append( node->weight(), completion );
+
+ else {
+ // node has more than one child
+ // -> recursively find all remaining completions
+ hasMultipleMatches = true;
+ extractStringsFromNode( node, completion, matches );
+ }
+}
+
+
+void KCompletion::extractStringsFromNode( const KCompTreeNode *node,
+ const QString& beginning,
+ KCompletionMatchesWrapper *matches,
+ bool addWeight ) const
+{
+ if ( !node || !matches )
+ return;
+
+ // kDebug() << "Beginning: " << beginning << endl;
+ const KCompTreeChildren *list = node->children();
+ QString string;
+ QString w;
+
+ // loop thru all children
+ for ( KCompTreeNode *cur = list->begin(); cur ; cur = cur->next) {
+ string = beginning;
+ node = cur;
+ if ( !node->isNull() )
+ string += *node;
+
+ while ( node && node->childrenCount() == 1 ) {
+ node = node->firstChild();
+ if ( node->isNull() )
+ break;
+ string += *node;
+ }
+
+ if ( node && node->isNull() ) { // we found a leaf
+ if ( addWeight ) {
+ // add ":num" to the string to store the weighting
+ string += ':';
+ w.setNum( node->weight() );
+ string.append( w );
+ }
+ matches->append( node->weight(), string );
+ }
+
+ // recursively find all other strings.
+ if ( node && node->childrenCount() > 1 )
+ extractStringsFromNode( node, string, matches, addWeight );
+ }
+}
+
+void KCompletion::extractStringsFromNodeCI( const KCompTreeNode *node,
+ const QString& beginning,
+ const QString& restString,
+ KCompletionMatchesWrapper *matches ) const
+{
+ if ( restString.isEmpty() ) {
+ extractStringsFromNode( node, beginning, matches, false /*noweight*/ );
+ return;
+ }
+
+ QChar ch1 = restString.at(0);
+ QString newRest = restString.mid(1);
+ KCompTreeNode *child1, *child2;
+
+ child1 = node->find( ch1 ); // the correct match
+ if ( child1 )
+ extractStringsFromNodeCI( child1, beginning + *child1, newRest,
+ matches );
+
+ // append the case insensitive matches, if available
+ if ( ch1.isLetter() ) {
+ // find out if we have to lower or upper it. Is there a better way?
+ QChar ch2 = ch1.lower();
+ if ( ch1 == ch2 )
+ ch2 = ch1.upper();
+ if ( ch1 != ch2 ) {
+ child2 = node->find( ch2 );
+ if ( child2 )
+ extractStringsFromNodeCI( child2, beginning + *child2, newRest,
+ matches );
+ }
+ }
+}
+
+void KCompletion::doBeep( BeepMode mode ) const
+{
+ if ( !myBeep )
+ return;
+
+ QString text, event;
+
+ switch ( mode ) {
+ case Rotation:
+ event = QString::fromLatin1("Textcompletion: rotation");
+ text = i18n("You reached the end of the list\nof matching items.\n");
+ break;
+ case PartialMatch:
+ if ( myCompletionMode == KGlobalSettings::CompletionShell ||
+ myCompletionMode == KGlobalSettings::CompletionMan ) {
+ event = QString::fromLatin1("Textcompletion: partial match");
+ text = i18n("The completion is ambiguous, more than one\nmatch is available.\n");
+ }
+ break;
+ case NoMatch:
+ if ( myCompletionMode == KGlobalSettings::CompletionShell ) {
+ event = QString::fromLatin1("Textcompletion: no match");
+ text = i18n("There is no matching item available.\n");
+ }
+ break;
+ }
+
+ if ( !text.isEmpty() )
+ KNotifyClient::event( event, text );
+}
+
+
+/////////////////////////////////
+/////////
+
+
+// Implements the tree. Every node is a QChar and has a list of children, which
+// are Nodes as well.
+// QChar( 0x0 ) is used as the delimiter of a string; the last child of each
+// inserted string is 0x0.
+
+KCompTreeNode::~KCompTreeNode()
+{
+ // delete all children
+ KCompTreeNode *cur = myChildren.begin();
+ while (cur) {
+ KCompTreeNode * next = cur->next;
+ delete myChildren.remove(cur);
+ cur = next;
+ }
+}
+
+
+// Adds a child-node "ch" to this node. If such a node is already existant,
+// it will not be created. Returns the new/existing node.
+KCompTreeNode * KCompTreeNode::insert( const QChar& ch, bool sorted )
+{
+ KCompTreeNode *child = find( ch );
+ if ( !child ) {
+ child = new KCompTreeNode( ch );
+
+ // FIXME, first (slow) sorted insertion implementation
+ if ( sorted ) {
+ KCompTreeNode * prev = 0;
+ KCompTreeNode * cur = myChildren.begin();
+ while ( cur ) {
+ if ( ch > *cur ) {
+ prev = cur;
+ cur = cur->next;
+ } else
+ break;
+ }
+ if (prev)
+ myChildren.insert( prev, child );
+ else
+ myChildren.prepend(child);
+ }
+
+ else
+ myChildren.append( child );
+ }
+
+ // implicit weighting: the more often an item is inserted, the higher
+ // priority it gets.
+ child->confirm();
+
+ return child;
+}
+
+
+// Iteratively removes a string from the tree. The nicer recursive
+// version apparently was a little memory hungry (see #56757)
+void KCompTreeNode::remove( const QString& str )
+{
+ QString string = str;
+ string += QChar(0x0);
+
+ QPtrVector<KCompTreeNode> deletables( string.length() + 1 );
+
+ KCompTreeNode *child = 0L;
+ KCompTreeNode *parent = this;
+ deletables.insert( 0, parent );
+
+ uint i = 0;
+ for ( ; i < string.length(); i++ )
+ {
+ child = parent->find( string.at( i ) );
+ if ( child )
+ deletables.insert( i + 1, child );
+ else
+ break;
+
+ parent = child;
+ }
+
+ for ( ; i >= 1; i-- )
+ {
+ parent = deletables.at( i - 1 );
+ child = deletables.at( i );
+ if ( child->myChildren.count() == 0 )
+ delete parent->myChildren.remove( child );
+ }
+}
+
+QStringList KCompletionMatchesWrapper::list() const
+{
+ if ( sortedList && dirty ) {
+ sortedList->sort();
+ dirty = false;
+
+ stringList.clear();
+
+ // high weight == sorted last -> reverse the sorting here
+ QValueListConstIterator<KSortableItem<QString> > it;
+ for ( it = sortedList->begin(); it != sortedList->end(); ++it )
+ stringList.prepend( (*it).value() );
+ }
+
+ return stringList;
+}
+
+KCompletionMatches::KCompletionMatches( bool sort_P )
+ : _sorting( sort_P )
+{
+}
+
+KCompletionMatches::KCompletionMatches( const KCompletionMatchesWrapper& matches )
+ : _sorting( matches.sorting())
+{
+ if( matches.sortedList != 0L )
+ KCompletionMatchesList::operator=( *matches.sortedList );
+ else {
+ QStringList l = matches.list();
+ for( QStringList::ConstIterator it = l.begin();
+ it != l.end();
+ ++it )
+ prepend( KSortableItem<QString, int>( 1, *it ) );
+ }
+}
+
+KCompletionMatches::~KCompletionMatches()
+{
+}
+
+QStringList KCompletionMatches::list( bool sort_P ) const
+{
+ if( _sorting && sort_P )
+ const_cast< KCompletionMatches* >( this )->sort();
+ QStringList stringList;
+ // high weight == sorted last -> reverse the sorting here
+ for ( ConstIterator it = begin(); it != end(); ++it )
+ stringList.prepend( (*it).value() );
+ return stringList;
+}
+
+void KCompletionMatches::removeDuplicates()
+{
+ Iterator it1, it2;
+ for ( it1 = begin(); it1 != end(); ++it1 ) {
+ for ( (it2 = it1), ++it2; it2 != end();) {
+ if( (*it1).value() == (*it2).value()) {
+ // use the max height
+ (*it1).first = kMax( (*it1).index(), (*it2).index());
+ it2 = remove( it2 );
+ continue;
+ }
+ ++it2;
+ }
+ }
+}
+
+void KCompTreeNodeList::append(KCompTreeNode *item)
+{
+ m_count++;
+ if (!last) {
+ last = item;
+ last->next = 0;
+ first = item;
+ return;
+ }
+ last->next = item;
+ item->next = 0;
+ last = item;
+}
+
+void KCompTreeNodeList::prepend(KCompTreeNode *item)
+{
+ m_count++;
+ if (!last) {
+ last = item;
+ last->next = 0;
+ first = item;
+ return;
+ }
+ item->next = first;
+ first = item;
+}
+
+void KCompTreeNodeList::insert(KCompTreeNode *after, KCompTreeNode *item)
+{
+ if (!after) {
+ append(item);
+ return;
+ }
+
+ m_count++;
+
+ item->next = after->next;
+ after->next = item;
+
+ if (after == last)
+ last = item;
+}
+
+KCompTreeNode *KCompTreeNodeList::remove(KCompTreeNode *item)
+{
+ if (!first || !item)
+ return 0;
+ KCompTreeNode *cur = 0;
+
+ if (item == first)
+ first = first->next;
+ else {
+ cur = first;
+ while (cur && cur->next != item) cur = cur->next;
+ if (!cur)
+ return 0;
+ cur->next = item->next;
+ }
+ if (item == last)
+ last = cur;
+ m_count--;
+ return item;
+}
+
+KCompTreeNode *KCompTreeNodeList::at(uint index) const
+{
+ KCompTreeNode *cur = first;
+ while (index-- && cur) cur = cur->next;
+ return cur;
+}
+
+KZoneAllocator KCompTreeNode::alloc(8192);
+
+void KCompletion::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KCompletionBase::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kcompletion.moc"
diff --git a/kdecore/kcompletion.h b/kdecore/kcompletion.h
new file mode 100644
index 000000000..af4d5ee32
--- /dev/null
+++ b/kdecore/kcompletion.h
@@ -0,0 +1,1010 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCOMPLETION_H
+#define KCOMPLETION_H
+
+#include <qmap.h>
+#include <qptrlist.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qguardedptr.h>
+
+#include "kdelibs_export.h"
+#include <kglobalsettings.h>
+#include <ksortablevaluelist.h>
+#include <kshortcut.h>
+
+class KCompTreeNode;
+class KCompletionPrivate;
+class KCompletionBasePrivate;
+class KCompletionMatchesWrapper;
+class KCompletionMatches;
+class QPopupMenu;
+
+/**
+ * @short A generic class for completing QStrings
+ *
+ * This class offers easy use of "auto-completion", "manual-completion" or
+ * "shell completion" on QString objects. A common use is completing filenames
+ * or URLs (see KURLCompletion()).
+ * But it is not limited to URL-completion -- everything should be completable!
+ * The user should be able to complete email-addresses, telephone-numbers,
+ * commands, SQL queries, ...
+ * Every time your program knows what the user can type into an edit-field, you
+ * should offer completion. With KCompletion, this is very easy, and if you are
+ * using a line edit widget ( KLineEdit), it is even more easy.
+ * Basically, you tell a KCompletion object what strings should be completable
+ * and whenever completion should be invoked, you call makeCompletion().
+ * KLineEdit and (an editable) KComboBox even do this automatically for you.
+ *
+ * KCompletion offers the completed string via the signal match() and
+ * all matching strings (when the result is ambiguous) via the method
+ * allMatches().
+ *
+ * Notice: auto-completion, shell completion and manual completion work
+ * slightly differently:
+ *
+ * @li auto-completion always returns a complete item as match.
+ * When more than one matching items are available, it will deliver just
+ * the first (depending on sorting order) item. Iterating over all matches
+ * is possible via nextMatch() and previousMatch().
+ *
+ * @li popup-completion works in the same way, the only difference being that
+ * the completed items are not put into the edit-widget, but into a
+ * separate popup-box.
+ *
+ * @li manual completion works the same way as auto-completion, the
+ * subtle difference is, that it isn't invoked automatically while the user
+ * is typing, but only when the user presses a special key. The difference
+ * of manual and auto-completion is therefore only visible in UI classes,
+ * KCompletion needs to know whether to deliver partial matches
+ * (shell completion) or whole matches (auto/manual completion), therefore
+ * KGlobalSettings::CompletionMan and
+ * KGlobalSettings::CompletionAuto have the exact same effect in
+ * KCompletion.
+ *
+ * @li shell completion works like how shells complete filenames:
+ * when multiple matches are available, the longest possible string of all
+ * matches is returned (i.e. only a partial item).
+ * Iterating over all matching items (complete, not partial) is possible
+ * via nextMatch() and previousMatch().
+ *
+ * You don't have to worry much about that though, KCompletion handles
+ * that for you, according to the setting setCompletionMode().
+ * The default setting is globally configured by the user and read
+ * from KGlobalSettings::completionMode().
+ *
+ * A short example:
+ * \code
+ * KCompletion completion;
+ * completion.setOrder( KCompletion::Sorted );
+ * completion.addItem( "pfeiffer@kde.org" );
+ * completion.addItem( "coolo@kde.org" );
+ * completion.addItem( "carpdjih@sp.zrz.tu-berlin.de" );
+ * completion.addItem( "carp@cs.tu-berlin.de" );
+ *
+ * cout << completion.makeCompletion( "ca" ).latin1() << endl;
+ * \endcode
+ *
+ * In shell-completion-mode, this will be "carp"; in auto-completion-
+ * mode it will be "carp\@cs.tu-berlin.de", as that is alphabetically
+ * smaller.
+ * If setOrder was set to Insertion, "carpdjih\@sp.zrz.tu-berlin.de"
+ * would be completed in auto-completion-mode, as that was inserted before
+ * "carp\@cs.tu-berlin.de".
+ *
+ * You can dynamically update the completable items by removing and adding them
+ * whenever you want.
+ * For advanced usage, you could even use multiple KCompletion objects. E.g.
+ * imagine an editor like kwrite with multiple open files. You could store
+ * items of each file in a different KCompletion object, so that you know (and
+ * tell the user) where a completion comes from.
+ *
+ * Note: KCompletion does not work with strings that contain 0x0 characters
+ * (unicode nul), as this is used internally as a delimiter.
+ *
+ * You may inherit from KCompletion and override makeCompletion() in
+ * special cases (like reading directories/urls and then supplying the
+ * contents to KCompletion, as KURLCompletion does), but generally, this is
+ * not necessary.
+ *
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KDECORE_EXPORT KCompletion : public QObject
+{
+ Q_ENUMS( CompOrder )
+ Q_PROPERTY( CompOrder order READ order WRITE setOrder )
+ Q_PROPERTY( bool ignoreCase READ ignoreCase WRITE setIgnoreCase )
+ Q_PROPERTY( QStringList items READ items WRITE setItems )
+ Q_OBJECT
+
+public:
+ /**
+ * Constants that represent the order in which KCompletion performs
+ * completion-lookups.
+ */
+ enum CompOrder { Sorted, ///< Use alphabetically sorted order
+ Insertion, ///< Use order of insertion
+ Weighted ///< Use weighted order
+ };
+
+ /**
+ * Constructor, nothing special here :)
+ */
+ KCompletion();
+
+ // FIXME: copy constructor, assignment operator...
+
+ /**
+ * Destructor, nothing special here, either.
+ */
+ virtual ~KCompletion();
+
+ /**
+ * Attempts to find an item in the list of available completions,
+ * that begins with @p string. Will either return the first matching item
+ * (if there is more than one match) or QString::null, if no match was
+ * found.
+ *
+ * In the latter case, a sound will be issued, depending on
+ * isSoundsEnabled().
+ * If a match was found, it will also be emitted via the signal
+ * match().
+ *
+ * If this is called twice or more often with the same string while no
+ * items were added or removed in the meantime, all available completions
+ * will be emitted via the signal #matches().
+ * This happens only in shell-completion-mode.
+ *
+ * @param string the string to complete
+ * @return the matching item, or QString::null if there is no matching
+ * item.
+ * @see slotMakeCompletion
+ * @see substringCompletion
+ */
+ virtual QString makeCompletion( const QString& string );
+
+ /**
+ * Returns a list of all completion items that contain the given @p string.
+ * @param string the string to complete
+ * @return a list of items which all contain @p text as a substring,
+ * i.e. not necessarily at the beginning.
+ *
+ * @see makeCompletion
+ */
+ QStringList substringCompletion( const QString& string ) const;
+
+ /**
+ * Returns the next item from the matching-items-list.
+ * When reaching the beginning, the list is rotated so it will return the
+ * last match and a sound is issued (depending on isSoundsEnabled()).
+ * @return the next item from the matching-items-list.
+ * When there is no match, QString::null is returned and
+ * a sound is be issued.
+ * @see slotPreviousMatch
+ */
+ QString previousMatch();
+
+ /**
+ * Returns the next item from the matching-items-list.
+ * When reaching the last item, the list is rotated, so it will return
+ * the first match and a sound is issued (depending on
+ * isSoundsEnabled()).
+ * @return the next item from the matching-items-list. When there is no
+ * match, QString::null is returned and a sound is issued
+ * @see slotNextMatch
+ */
+ QString nextMatch();
+
+ /**
+ * Returns the last match. Might be useful if you need to check whether
+ * a completion is different from the last one.
+ * @return the last match. QString::null is returned when there is no
+ * last match.
+ */
+ virtual const QString& lastMatch() const { return myLastMatch; }
+
+ /**
+ * Returns a list of all items inserted into KCompletion. This is useful
+ * if you need to save the state of a KCompletion object and restore it
+ * later.
+ *
+ * Important note: when order() == Weighted, then every item in the
+ * stringlist has its weight appended, delimited by a colon. E.g. an item
+ * "www.kde.org" might look like "www.kde.org:4", where 4 is the weight.
+ *
+ * This is necessary so that you can save the items along with its
+ * weighting on disk and load them back with setItems(), restoring its
+ * weight as well. If you really don't want the appended weightings, call
+ * setOrder( KCompletion::Insertion )
+ * before calling items().
+ *
+ * @return a list of all items
+ * @see setItems
+ */
+ QStringList items() const;
+
+ /**
+ * Returns true when the completion object contains no entries.
+ */
+ bool isEmpty() const;
+
+ /**
+ * Sets the completion mode to Auto/Manual, Shell or None.
+ * If you don't set the mode explicitly, the global default value
+ * KGlobalSettings::completionMode() is used.
+ * KGlobalSettings::CompletionNone disables completion.
+ * @param mode the completion mode
+ * @see completionMode
+ * @see KGlobalSettings::completionMode
+ */
+ virtual void setCompletionMode( KGlobalSettings::Completion mode );
+
+ /**
+ * Return the current completion mode.
+ * May be different from KGlobalSettings::completionMode(), if you
+ * explicitly called setCompletionMode().
+ * @return the current completion mode
+ * @see setCompletionMode
+ */
+ KGlobalSettings::Completion completionMode() const {
+ return myCompletionMode;
+ }
+
+ /**
+ * KCompletion offers three different ways in which it offers its items:
+ * @li in the order of insertion
+ * @li sorted alphabetically
+ * @li weighted
+ *
+ * Choosing weighted makes KCompletion perform an implicit weighting based
+ * on how often an item is inserted. Imagine a web browser with a location
+ * bar, where the user enters URLs. The more often a URL is entered, the
+ * higher priority it gets.
+ *
+ * Note: Setting the order to sorted only affects new inserted items,
+ * already existing items will stay in the current order. So you probably
+ * want to call setOrder( Sorted ) before inserting items, when you want
+ * everything sorted.
+ *
+ * Default is insertion order.
+ * @param order the new order
+ * @see order
+ */
+ virtual void setOrder( CompOrder order );
+
+ /**
+ * Returns the completion order.
+ * @return the current completion order.
+ * @see setOrder
+ */
+ CompOrder order() const { return myOrder; }
+
+ /**
+ * Setting this to true makes KCompletion behave case insensitively.
+ * E.g. makeCompletion( "CA" ); might return "carp\@cs.tu-berlin.de".
+ * Default is false (case sensitive).
+ * @param ignoreCase true to ignore the case
+ * @see ignoreCase
+ */
+ virtual void setIgnoreCase( bool ignoreCase );
+
+ /**
+ * Return whether KCompletion acts case insensitively or not.
+ * Default is false (case sensitive).
+ * @return true if the case will be ignored
+ * @see setIgnoreCase
+ */
+ bool ignoreCase() const { return myIgnoreCase; }
+
+ /**
+ * Returns a list of all items matching the last completed string.
+ * Might take some time, when you have LOTS of items.
+ * @return a list of all matches for the last completed string.
+ * @see substringCompletion
+ */
+ QStringList allMatches();
+
+ /**
+ * Returns a list of all items matching @p string.
+ * @param string the string to match
+ * @return the list of all matches
+ */
+ QStringList allMatches( const QString& string );
+
+ /**
+ * Returns a list of all items matching the last completed string.
+ * Might take some time, when you have LOTS of items.
+ * The matches are returned as KCompletionMatches, which also
+ * keeps the weight of the matches, allowing
+ * you to modify some matches or merge them with matches
+ * from another call to allWeightedMatches(), and sort the matches
+ * after that in order to have the matches ordered correctly.
+ *
+ * @return a list of all completion matches
+ * @see substringCompletion
+ */
+ KCompletionMatches allWeightedMatches();
+
+ /**
+ * Returns a list of all items matching @p string.
+ * @param string the string to match
+ * @return a list of all matches
+ */
+ KCompletionMatches allWeightedMatches( const QString& string );
+
+ /**
+ * Enables/disables playing a sound when
+ * @li makeCompletion() can't find a match
+ * @li there is a partial completion (= multiple matches in
+ * Shell-completion mode)
+ * @li nextMatch() or previousMatch() hit the last possible
+ * match -> rotation
+ *
+ * For playing the sounds, KNotifyClient() is used.
+ *
+ * @param enable true to enable sounds
+ * @see isSoundsEnabled
+ */
+ virtual void setEnableSounds( bool enable ) { myBeep = enable; }
+
+ /**
+ * Tells you whether KCompletion will play sounds on certain occasions.
+ * Default is enabled.
+ * @return true if sounds are enabled
+ * @see enableSounds
+ * @see disableSounds
+ */
+ bool isSoundsEnabled() const { return myBeep; }
+
+ /**
+ * Returns true when more than one match is found.
+ * @return true if there are more than one match
+ * @see multipleMatches
+ */
+ bool hasMultipleMatches() const { return myHasMultipleMatches; }
+
+#ifndef KDE_NO_COMPAT
+ /**
+ * @deprecated
+ * @see setEnableSounds
+ */
+ void enableSounds() { myBeep = true; }
+
+ /**
+ * @deprecated
+ * @see setEnableSounds
+ */
+ void disableSounds() { myBeep = false; }
+#endif
+
+public slots:
+ /**
+ * Attempts to complete "string" and emits the completion via match().
+ * Same as makeCompletion() (just as a slot).
+ * @param string the string to complete
+ * @see makeCompletion
+ */
+ void slotMakeCompletion( const QString& string ) {
+ (void) makeCompletion( string );
+ }
+
+ /**
+ * Searches the previous matching item and emits it via match().
+ * Same as previousMatch() (just as a slot).
+ * @see previousMatch
+ */
+ void slotPreviousMatch() {
+ (void) previousMatch();
+ }
+
+ /**
+ * Searches the next matching item and emits it via match().
+ * Same as nextMatch() (just as a slot).
+ * @see nextMatch
+ */
+ void slotNextMatch() {
+ (void) nextMatch();
+ }
+
+ // FIXME ###: KDE4: unify the nomenclature. We have insertItems, addItem,
+ // setItems...
+ /**
+ * Inserts @p items into the list of possible completions.
+ * Does the same as setItems(), but does not call clear() before.
+ * @param items the items to insert
+ */
+ void insertItems( const QStringList& items );
+
+ /**
+ * Sets the list of items available for completion. Removes all previous
+ * items.
+ *
+ * Notice: when order() == Weighted, then the weighting is looked up for
+ * every item in the stringlist. Every item should have ":number" appended,
+ * where number is an unsigned integer, specifying the weighting.
+ *
+ * If you don't like this, call
+ * setOrder( KCompletion::Insertion )
+ * before calling setItems().
+ *
+ * @param list the list of items that are available for completion
+ * @see items
+ */
+ virtual void setItems( const QStringList& list);
+
+ /**
+ * Adds an item to the list of available completions.
+ * Resets the current item-state ( previousMatch() and nextMatch()
+ * won't work anymore).
+ * @param item the item to add
+ */
+ void addItem( const QString& item);
+
+ /**
+ * Adds an item to the list of available completions.
+ * Resets the current item-state ( previousMatch() and nextMatch()
+ * won't work anymore).
+ *
+ * Sets the weighting of the item to @p weight or adds it to the current
+ * weighting if the item is already available. The weight has to be greater
+ * than 1 to take effect (default weight is 1).
+ * @param item the item to add
+ * @param weight the weight of the item, default is 1
+ */
+ void addItem( const QString& item, uint weight );
+
+ /**
+ * Removes an item from the list of available completions.
+ * Resets the current item-state ( previousMatch() and nextMatch()
+ * won't work anymore).
+ * @param item the item to remove
+ */
+ void removeItem( const QString& item);
+
+ /**
+ * Removes all inserted items.
+ */
+ virtual void clear();
+
+
+signals:
+ /**
+ * The matching item. Will be emitted by makeCompletion(),
+ * previousMatch() or nextMatch(). May be QString::null if there
+ * is no matching item.
+ * @param item the match, or QString::null if there is none
+ */
+ void match( const QString& item);
+
+ /**
+ * All matching items. Will be emitted by makeCompletion() in shell-
+ * completion-mode, when the same string is passed to makeCompletion twice
+ * or more often.
+ * @param matchlist the list of matches
+ */
+ void matches( const QStringList& matchlist);
+
+ /**
+ * This signal is emitted, when calling makeCompletion() and more than
+ * one matching item is found.
+ * @see hasMultipleMatches
+ */
+ void multipleMatches();
+
+protected:
+ /**
+ * This method is called after a completion is found and before the
+ * matching string is emitted. You can override this method to modify the
+ * string that will be emitted.
+ * This is necessary e.g. in KURLCompletion(), where files with spaces
+ * in their names are shown escaped ("filename\ with\ spaces"), but stored
+ * unescaped inside KCompletion.
+ * Never delete that pointer!
+ *
+ * Default implementation does nothing.
+ * @param match the match to process
+ * @see postProcessMatches
+ */
+ virtual void postProcessMatch( QString *match ) const { Q_UNUSED(match) }
+
+ /**
+ * This method is called before a list of all available completions is
+ * emitted via #matches. You can override this method to modify the
+ * found items before match() or #matches are emitted.
+ * Never delete that pointer!
+ *
+ * Default implementation does nothing.
+ * @param matches the matches to process
+ * @see postProcessMatch
+ */
+ virtual void postProcessMatches( QStringList * matches ) const { Q_UNUSED(matches)}
+
+ /**
+ * This method is called before a list of all available completions is
+ * emitted via #matches. You can override this method to modify the
+ * found items before #match() or #matches() are emitted.
+ * Never delete that pointer!
+ *
+ * Default implementation does nothing.
+ * @param matches the matches to process
+ * @see postProcessMatch
+ */
+ virtual void postProcessMatches( KCompletionMatches * matches ) const {Q_UNUSED(matches)}
+
+private:
+ void addWeightedItem( const QString& );
+ QString findCompletion( const QString& string );
+ void findAllCompletions( const QString&,
+ KCompletionMatchesWrapper *matches,
+ bool& hasMultipleMatches ) const;
+
+ void extractStringsFromNode( const KCompTreeNode *,
+ const QString& beginning,
+ KCompletionMatchesWrapper *matches,
+ bool addWeight = false ) const;
+ void extractStringsFromNodeCI( const KCompTreeNode *,
+ const QString& beginning,
+ const QString& restString,
+ KCompletionMatchesWrapper *matches) const;
+
+ enum BeepMode { NoMatch, PartialMatch, Rotation };
+ void doBeep( BeepMode ) const;
+
+ KGlobalSettings::Completion myCompletionMode;
+
+ CompOrder myOrder;
+ QString myLastString;
+ QString myLastMatch;
+ QString myCurrentMatch;
+ KCompTreeNode * myTreeRoot;
+ QStringList myRotations;
+ bool myBeep;
+ bool myIgnoreCase;
+ bool myHasMultipleMatches;
+ uint myRotationIndex;
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KCompletionPrivate *d;
+};
+
+// some more helper stuff
+typedef KSortableValueList<QString> KCompletionMatchesList;
+class KCompletionMatchesPrivate;
+
+/**
+ * This structure is returned by KCompletion::allWeightedMatches .
+ * It also keeps the weight of the matches, allowing
+ * you to modify some matches or merge them with matches
+ * from another call to allWeightedMatches(), and sort the matches
+ * after that in order to have the matches ordered correctly
+ *
+ * Example (a simplified example of what Konqueror's completion does):
+ * \code
+ * KCompletionMatches matches = completion->allWeightedMatches( location );
+ * if( !location.startsWith( "www." ))
+ matches += completion->allWeightedmatches( "www." + location" );
+ * matches.removeDuplicates();
+ * QStringList list = matches.list();
+ * \endcode
+ *
+ * @short List for keeping matches returned from KCompletion
+ */
+class KDECORE_EXPORT KCompletionMatches : public KCompletionMatchesList
+{
+public:
+ KCompletionMatches( bool sort );
+ /**
+ * @internal
+ */
+ KCompletionMatches( const KCompletionMatchesWrapper& matches );
+ ~KCompletionMatches();
+ /**
+ * Removes duplicate matches. Needed only when you merged several matches
+ * results and there's a possibility of duplicates.
+ */
+ void removeDuplicates();
+ /**
+ * Returns the matches as a QStringList.
+ * @param sort if false, the matches won't be sorted before the conversion,
+ * use only if you're sure the sorting is not needed
+ * @return the list of matches
+ */
+ QStringList list( bool sort = true ) const;
+ /**
+ * If sorting() returns false, the matches aren't sorted by their weight,
+ * even if true is passed to list().
+ * @return true if the matches won't be sorted
+ */
+ bool sorting() const {
+ return _sorting;
+ }
+private:
+ bool _sorting;
+ KCompletionMatchesPrivate* d;
+};
+
+/**
+ * An abstract base class for adding a completion feature
+ * into widgets.
+ *
+ * This is a convenience class that provides the basic functions
+ * needed to add text completion support into widgets. All that
+ * is required is an implementation for the pure virtual function
+ * setCompletedText. Refer to KLineEdit or KComboBox
+ * to see how easily such support can be added using this as a base
+ * class.
+ *
+ * @short An abstract class for adding text completion support to widgets.
+ * @author Dawit Alemayehu <adawit@kde.org>
+ */
+class KDECORE_EXPORT KCompletionBase
+{
+public:
+ /**
+ * Constants that represent the items whose short-cut
+ * key-binding is programmable. The default key-bindings
+ * for these items are defined in KStdAccel.
+ */
+ enum KeyBindingType {
+ /**
+ * Text completion (by default Ctrl-E).
+ */
+ TextCompletion,
+ /**
+ * Switch to previous completion (by default Ctrl-Up).
+ */
+ PrevCompletionMatch,
+ /**
+ * Switch to next completion (by default Ctrl-Down).
+ */
+ NextCompletionMatch,
+ /**
+ * Substring completion (by default Ctrl-T).
+ */
+ SubstringCompletion
+ };
+
+
+ // Map for the key binding types mentioned above.
+ typedef QMap<KeyBindingType, KShortcut> KeyBindingMap;
+
+ /**
+ * Default constructor.
+ */
+ KCompletionBase();
+
+ /**
+ * Destructor.
+ */
+ virtual ~KCompletionBase();
+
+ /**
+ * Returns a pointer to the current completion object.
+ *
+ * If the completion object does not exist, it is automatically created and
+ * by default handles all the completion signals internally unless @p hsig
+ * is set to false. It is also automatically destroyed when the destructor
+ * is called. You can change this default behavior using the
+ * @ref setAutoDeleteCompletionObject and @ref setHandleSignals member
+ * functions.
+ *
+ * See also @ref compObj.
+ *
+ * @param hsig if true, handles completion signals internally.
+ * @return a pointer the completion object.
+ */
+ KCompletion* completionObject( bool hsig = true );
+
+ /**
+ * Sets up the completion object to be used.
+ *
+ * This method assigns the completion object and sets it up to automatically
+ * handle the completion and rotation signals internally. You should use
+ * this function if you want to share one completion object among your
+ * widgets or need to use a customized completion object.
+ *
+ * The object assigned through this method is not deleted when this object's
+ * destructor is invoked unless you explicitly call @ref setAutoDeleteCompletionObject
+ * after calling this method. Be sure to set the bool argument to false, if
+ * you want to handle the completion signals yourself.
+ *
+ * @param compObj a KCompletion() or a derived child object.
+ * @param hsig if true, handles completion signals internally.
+ */
+ virtual void setCompletionObject( KCompletion* compObj, bool hsig = true );
+
+ /**
+ * Enables this object to handle completion and rotation
+ * events internally.
+ *
+ * This function simply assigns a boolean value that
+ * indicates whether it should handle rotation and
+ * completion events or not. Note that this does not
+ * stop the object from emitting signals when these
+ * events occur.
+ *
+ * @param handle if true, handle completion & rotation internally.
+ */
+ virtual void setHandleSignals( bool handle );
+
+ /**
+ * Returns true if the completion object is deleted
+ * upon this widget's destruction.
+ *
+ * See setCompletionObject() and enableCompletion()
+ * for details.
+ *
+ * @return true if the completion object will be deleted
+ * automatically
+ */
+ bool isCompletionObjectAutoDeleted() const {
+ return m_delegate ? m_delegate->isCompletionObjectAutoDeleted() : m_bAutoDelCompObj;
+ }
+
+ /**
+ * Sets the completion object when this widget's destructor
+ * is called.
+ *
+ * If the argument is set to true, the completion object
+ * is deleted when this widget's destructor is called.
+ *
+ * @param autoDelete if true, delete completion object on destruction.
+ */
+ void setAutoDeleteCompletionObject( bool autoDelete ) {
+ if ( m_delegate )
+ m_delegate->setAutoDeleteCompletionObject( autoDelete );
+ else
+ m_bAutoDelCompObj = autoDelete;
+ }
+
+ /**
+ * Sets the widget's ability to emit text completion and
+ * rotation signals.
+ *
+ * Invoking this function with @p enable set to @p false will
+ * cause the completion & rotation signals not to be emitted.
+ * However, unlike setting the completion object to @p NULL
+ * using setCompletionObject, disabling the emition of
+ * the signals through this method does not affect the current
+ * completion object.
+ *
+ * There is no need to invoke this function by default. When a
+ * completion object is created through completionObject or
+ * setCompletionObject, these signals are set to emit
+ * automatically. Also note that disabling this signals will not
+ * necessarily interfere with the objects ability to handle these
+ * events internally. See setHandleSignals.
+ *
+ * @param enable if false, disables the emition of completion & rotation signals.
+ */
+ void setEnableSignals( bool enable ) {
+ if ( m_delegate )
+ m_delegate->setEnableSignals( enable );
+ else
+ m_bEmitSignals = enable;
+ }
+
+ /**
+ * Returns true if the object handles the signals.
+ *
+ * @return true if this signals are handled internally.
+ */
+ bool handleSignals() const { return m_delegate ? m_delegate->handleSignals() : m_bHandleSignals; }
+
+ /**
+ * Returns true if the object emits the signals.
+ *
+ * @return true if signals are emitted
+ */
+ bool emitSignals() const { return m_delegate ? m_delegate->emitSignals() : m_bEmitSignals; }
+
+ /**
+ * Sets the type of completion to be used.
+ *
+ * The completion modes supported are those defined in
+ * KGlobalSettings(). See below.
+ *
+ * @param mode Completion type:
+ * @li CompletionNone: Disables completion feature.
+ * @li CompletionAuto: Attempts to find a match &
+ * fills-in the remaining text.
+ * @li CompletionMan: Acts the same as the above
+ * except the action has to be
+ * manually triggered through
+ * pre-defined completion key.
+ * @li CompletionShell: Mimics the completion feature
+ * found in typical *nix shell
+ * environments.
+ * @li CompletionPopup: Shows all available completions at once,
+ * in a listbox popping up.
+ */
+ virtual void setCompletionMode( KGlobalSettings::Completion mode );
+
+ /**
+ * Returns the current completion mode.
+ *
+ * The return values are of type KGlobalSettings::Completion.
+ * See setCompletionMode() for details.
+ *
+ * @return the completion mode.
+ */
+ KGlobalSettings::Completion completionMode() const {
+ return m_delegate ? m_delegate->completionMode() : m_iCompletionMode;
+ }
+
+ /**
+ * Sets the key-binding to be used for manual text
+ * completion, text rotation in a history list as
+ * well as a completion list.
+ *
+ *
+ * When the keys set by this function are pressed, a
+ * signal defined by the inheriting widget will be activated.
+ * If the default value or 0 is specified by the second
+ * parameter, then the key-binding as defined in the global
+ * setting should be used. This method returns false value
+ * for @p key is negative or the supplied key-binding conflicts
+ * with the ones set for one of the other features.
+ *
+ * NOTE: To use a modifier key (Shift, Ctrl, Alt) as part of
+ * the key-binding simply simply @p sum up the values of the
+ * modifier and the actual key. For example, to use CTRL+E as
+ * a key binding for one of the items, you would simply supply
+ * @p "Qt::CtrlButton + Qt::Key_E" as the second argument to this
+ * function.
+ *
+ * @param item the feature whose key-binding needs to be set:
+ * @li TextCompletion the manual completion key-binding.
+ * @li PrevCompletionMatch the previous match key for multiple completion.
+ * @li NextCompletionMatch the next match key for for multiple completion.
+ * @li SubstringCompletion the key for substring completion
+ * @param key key-binding used to rotate down in a list.
+ * @return true if key-binding can successfully be set.
+ * @see getKeyBinding
+ */
+ bool setKeyBinding( KeyBindingType item , const KShortcut& key );
+
+ /**
+ * Returns the key-binding used for the specified item.
+ *
+ * This methods returns the key-binding used to activate
+ * the feature feature given by @p item. If the binding
+ * contains modifier key(s), the SUM of the modifier key
+ * and the actual key code are returned.
+ *
+ * @param item the item to check
+ * @return the key-binding used for the feature given by @p item.
+ * @see setKeyBinding
+ */
+ const KShortcut& getKeyBinding( KeyBindingType item ) const {
+ return m_delegate ? m_delegate->getKeyBinding( item ) : m_keyMap[ item ];
+ }
+
+ /**
+ * Sets this object to use global values for key-bindings.
+ *
+ * This method changes the values of the key bindings for
+ * rotation and completion features to the default values
+ * provided in KGlobalSettings.
+ *
+ * NOTE: By default inheriting widgets should uses the
+ * global key-bindings so that there will be no need to
+ * call this method.
+ */
+ void useGlobalKeyBindings();
+
+ /**
+ * A pure virtual function that must be implemented by
+ * all inheriting classes.
+ *
+ * This function is intended to allow external completion
+ * implementations to set completed text appropriately. It
+ * is mostly relevant when the completion mode is set to
+ * CompletionAuto and CompletionManual modes. See
+ * KCompletionBase::setCompletedText.
+ * Does nothing in CompletionPopup mode, as all available
+ * matches will be shown in the popup.
+ *
+ * @param text the completed text to be set in the widget.
+ */
+ virtual void setCompletedText( const QString& text ) = 0;
+
+ /**
+ * A pure virtual function that must be implemented by
+ * all inheriting classes.
+ * @param items the list of completed items
+ */
+ virtual void setCompletedItems( const QStringList& items ) = 0;
+
+ /**
+ * Returns a pointer to the completion object.
+ *
+ * This method is only different from completionObject()
+ * in that it does not create a new KCompletion object even if
+ * the internal pointer is @p NULL. Use this method to get the
+ * pointer to a completion object when inheriting so that you
+ * won't inadvertently create it!!
+ *
+ * @return the completion object or NULL if one does not exist.
+ */
+ KCompletion* compObj() const { return m_delegate ? m_delegate->compObj() : (KCompletion*) m_pCompObj; }
+
+protected:
+ /**
+ * Returns a key-binding map.
+ *
+ * This method is the same as getKeyBinding() except it
+ * returns the whole keymap containing the key-bindings.
+ *
+ * @return the key-binding used for the feature given by @p item.
+ */
+ KeyBindingMap getKeyBindings() const { return m_delegate ? m_delegate->getKeyBindings() : m_keyMap; }
+
+ /**
+ * Sets or removes the delegation object. If a delegation object is
+ * set, all function calls will be forwarded to the delegation object.
+ * @param delegate the delegation object, or 0 to remove it
+ */
+ void setDelegate( KCompletionBase *delegate );
+
+ /**
+ * Returns the delegation object.
+ * @return the delegation object, or 0 if there is none
+ * @see setDelegate()
+ */
+ KCompletionBase *delegate() const { return m_delegate; }
+
+private:
+ // This method simply sets the autodelete boolean for
+ // the completion object, the emit signals and handle
+ // signals internally flags to the provided values.
+ void setup( bool, bool, bool );
+
+ // Flag that determined whether the completion object
+ // should be deleted when this object is destroyed.
+ bool m_bAutoDelCompObj;
+ // Determines whether this widget handles completion signals
+ // internally or not
+ bool m_bHandleSignals;
+ // Determines whether this widget fires rotation signals
+ bool m_bEmitSignals;
+ // Stores the completion mode locally.
+ KGlobalSettings::Completion m_iCompletionMode;
+ // Pointer to Completion object.
+ QGuardedPtr<KCompletion> m_pCompObj;
+ // Keybindings
+ KeyBindingMap m_keyMap;
+ // we may act as a proxy to another KCompletionBase object
+ KCompletionBase *m_delegate;
+
+ // BCI
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KCompletionBasePrivate *d;
+};
+
+#endif // KCOMPLETION_H
diff --git a/kdecore/kcompletion_private.h b/kdecore/kcompletion_private.h
new file mode 100644
index 000000000..10d978806
--- /dev/null
+++ b/kdecore/kcompletion_private.h
@@ -0,0 +1,216 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef KCOMPLETION_PRIVATE_H
+#define KCOMPLETION_PRIVATE_H
+
+#include <qstring.h>
+#include <ksortablevaluelist.h>
+
+class KCompTreeNode;
+
+#include <kallocator.h>
+
+/**
+ * @internal
+ */
+class KDECORE_EXPORT KCompTreeNodeList
+{
+public:
+ KCompTreeNodeList() : first(0), last(0), m_count(0) {}
+ KCompTreeNode *begin() const { return first; }
+ KCompTreeNode *end() const { return last; }
+
+ KCompTreeNode *at(uint index) const;
+ void append(KCompTreeNode *item);
+ void prepend(KCompTreeNode *item);
+ void insert(KCompTreeNode *after, KCompTreeNode *item);
+ KCompTreeNode *remove(KCompTreeNode *item);
+ uint count() const { return m_count; }
+
+private:
+ KCompTreeNode *first, *last;
+ uint m_count;
+};
+
+typedef KCompTreeNodeList KCompTreeChildren;
+
+/**
+ * A helper class for KCompletion. Implements a tree of QChar.
+ *
+ * The tree looks like this (containing the items "kde", "kde-ui",
+ * "kde-core" and "pfeiffer". Every item is delimited with QChar( 0x0 )
+ *
+ * some_root_node
+ * / \
+ * k p
+ * | |
+ * d f
+ * | |
+ * e e
+ * /| |
+ * 0x0 - i
+ * / \ |
+ * u c f
+ * | | |
+ * i o f
+ * | | |
+ * 0x0 r e
+ * | |
+ * e r
+ * | |
+ * 0x0 0x0
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @internal
+ */
+class KDECORE_EXPORT KCompTreeNode : public QChar
+{
+public:
+ KCompTreeNode() : QChar(), myWeight(0) {}
+ KCompTreeNode( const QChar& ch, uint weight = 0 )
+ : QChar( ch ),
+ myWeight( weight ) {}
+ ~KCompTreeNode();
+
+ void * operator new( size_t s ) {
+ return alloc.allocate( s );
+ }
+ void operator delete( void * s ) {
+ alloc.deallocate( s );
+ }
+
+ // Returns a child of this node matching ch, if available.
+ // Otherwise, returns 0L
+ inline KCompTreeNode * find( const QChar& ch ) const {
+ KCompTreeNode * cur = myChildren.begin();
+ while (cur && (*cur != ch)) cur = cur->next;
+ return cur;
+ }
+ KCompTreeNode * insert( const QChar&, bool sorted );
+ void remove( const QString& );
+
+ inline int childrenCount() const { return myChildren.count(); }
+
+ // weighting
+ inline void confirm() { myWeight++; }
+ inline void confirm(uint w) { myWeight += w; }
+ inline void decline() { myWeight--; }
+ inline uint weight() const { return myWeight; }
+
+ inline const KCompTreeChildren * children() const {
+ return &myChildren;
+ }
+ inline const KCompTreeNode * childAt(int index) const {
+ return myChildren.at(index);
+ }
+ inline const KCompTreeNode * firstChild() const {
+ return myChildren.begin();
+ }
+ inline const KCompTreeNode * lastChild() const {
+ return myChildren.end();
+ }
+
+ /* We want to handle a list of KCompTreeNodes on our own, to not
+ need to use QValueList<>. And to make it even more fast we don't
+ use an accessor, but just a public member. */
+ KCompTreeNode *next;
+private:
+ uint myWeight;
+ KCompTreeNodeList myChildren;
+ static KZoneAllocator alloc;
+};
+
+
+
+// some more helper stuff
+typedef KSortableValueList<QString> KCompletionMatchesList;
+
+/**
+ * @internal
+ */
+class KDECORE_EXPORT KCompletionMatchesWrapper
+{
+public:
+ KCompletionMatchesWrapper( bool sort = false )
+ : sortedList( sort ? new KCompletionMatchesList : 0L ),
+ dirty( false )
+ {}
+ ~KCompletionMatchesWrapper() {
+ delete sortedList;
+ }
+
+ void setSorting( bool sort ) {
+ if ( sort && !sortedList )
+ sortedList = new KCompletionMatchesList;
+ else if ( !sort ) {
+ delete sortedList;
+ sortedList = 0L;
+ }
+ stringList.clear();
+ dirty = false;
+ }
+
+ bool sorting() const {
+ return sortedList != 0L;
+ }
+
+ void append( int i, const QString& string ) {
+ if ( sortedList )
+ sortedList->insert( i, string );
+ else
+ stringList.append( string );
+ dirty = true;
+ }
+
+ void clear() {
+ if ( sortedList )
+ sortedList->clear();
+ stringList.clear();
+ dirty = false;
+ }
+
+ uint count() const {
+ if ( sortedList )
+ return sortedList->count();
+ return stringList.count();
+ }
+
+ bool isEmpty() const {
+ return count() == 0;
+ }
+
+ QString first() const {
+ return list().first();
+ }
+
+ QString last() const {
+ return list().last();
+ }
+
+ QStringList list() const;
+
+ mutable QStringList stringList;
+ KCompletionMatchesList *sortedList;
+ mutable bool dirty;
+};
+
+
+#endif // KCOMPLETION_PRIVATE_H
diff --git a/kdecore/kcompletionbase.cpp b/kdecore/kcompletionbase.cpp
new file mode 100644
index 000000000..a9c70c7a1
--- /dev/null
+++ b/kdecore/kcompletionbase.cpp
@@ -0,0 +1,154 @@
+/* This file is part of the KDE libraries
+
+ Copyright (c) 2000 Dawit Alemayehu <adawit@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License (LGPL) as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qobject.h>
+
+#include <kcompletion.h>
+
+KCompletionBase::KCompletionBase()
+{
+ m_delegate = 0L;
+ // Assign the default completion type to use.
+ m_iCompletionMode = KGlobalSettings::completionMode();
+
+ // Initialize all key-bindings to 0 by default so that
+ // the event filter will use the global settings.
+ useGlobalKeyBindings();
+
+ // By default we initialize everything to false.
+ // All the variables would be setup properly when
+ // the appropriate member functions are called.
+ setup( false, false, false );
+}
+
+KCompletionBase::~KCompletionBase()
+{
+ if( m_bAutoDelCompObj && m_pCompObj )
+ {
+ delete m_pCompObj;
+ }
+}
+
+void KCompletionBase::setDelegate( KCompletionBase *delegate )
+{
+ m_delegate = delegate;
+
+ if ( m_delegate ) {
+ m_delegate->m_bAutoDelCompObj = m_bAutoDelCompObj;
+ m_delegate->m_bHandleSignals = m_bHandleSignals;
+ m_delegate->m_bEmitSignals = m_bEmitSignals;
+ m_delegate->m_iCompletionMode = m_iCompletionMode;
+ m_delegate->m_keyMap = m_keyMap;
+ }
+}
+
+KCompletion* KCompletionBase::completionObject( bool hsig )
+{
+ if ( m_delegate )
+ return m_delegate->completionObject( hsig );
+
+ if ( !m_pCompObj )
+ {
+ setCompletionObject( new KCompletion(), hsig );
+ m_bAutoDelCompObj = true;
+ }
+ return m_pCompObj;
+}
+
+void KCompletionBase::setCompletionObject( KCompletion* compObj, bool hsig )
+{
+ if ( m_delegate ) {
+ m_delegate->setCompletionObject( compObj, hsig );
+ return;
+ }
+
+ if ( m_bAutoDelCompObj && compObj != m_pCompObj )
+ delete m_pCompObj;
+
+ m_pCompObj = compObj;
+
+ // We emit rotation and completion signals
+ // if completion object is not NULL.
+ setup( false, hsig, !m_pCompObj.isNull() );
+}
+
+// BC: Inline this function and possibly rename it to setHandleEvents??? (DA)
+void KCompletionBase::setHandleSignals( bool handle )
+{
+ if ( m_delegate )
+ m_delegate->setHandleSignals( handle );
+ else
+ m_bHandleSignals = handle;
+}
+
+void KCompletionBase::setCompletionMode( KGlobalSettings::Completion mode )
+{
+ if ( m_delegate ) {
+ m_delegate->setCompletionMode( mode );
+ return;
+ }
+
+ m_iCompletionMode = mode;
+ // Always sync up KCompletion mode with ours as long as we
+ // are performing completions.
+ if( m_pCompObj && m_iCompletionMode != KGlobalSettings::CompletionNone )
+ m_pCompObj->setCompletionMode( m_iCompletionMode );
+}
+
+bool KCompletionBase::setKeyBinding( KeyBindingType item, const KShortcut& cut )
+{
+ if ( m_delegate )
+ return m_delegate->setKeyBinding( item, cut );
+
+
+ if( !cut.isNull() )
+ {
+ for( KeyBindingMap::Iterator it = m_keyMap.begin(); it != m_keyMap.end(); ++it )
+ if( it.data() == cut ) return false;
+ }
+ m_keyMap.replace( item, cut );
+ return true;
+}
+
+void KCompletionBase::useGlobalKeyBindings()
+{
+ if ( m_delegate ) {
+ m_delegate->useGlobalKeyBindings();
+ return;
+ }
+
+ m_keyMap.clear();
+ m_keyMap.insert( TextCompletion, 0 );
+ m_keyMap.insert( PrevCompletionMatch, 0 );
+ m_keyMap.insert( NextCompletionMatch, 0 );
+ m_keyMap.insert( SubstringCompletion, 0 );
+}
+
+void KCompletionBase::setup( bool autodel, bool hsig, bool esig )
+{
+ if ( m_delegate ) {
+ m_delegate->setup( autodel, hsig, esig );
+ return;
+ }
+
+ m_bAutoDelCompObj = autodel;
+ m_bHandleSignals = hsig;
+ m_bEmitSignals = esig;
+}
diff --git a/kdecore/kconfig.cpp b/kdecore/kconfig.cpp
new file mode 100644
index 000000000..4712415f4
--- /dev/null
+++ b/kdecore/kconfig.cpp
@@ -0,0 +1,367 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#include <config.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qfileinfo.h>
+
+#include <kapplication.h>
+#include "kconfigbackend.h"
+
+#include "kconfig.h"
+#include "kglobal.h"
+#include "kstandarddirs.h"
+#include "kstaticdeleter.h"
+#include <qtimer.h>
+
+KConfig::KConfig( const QString& fileName,
+ bool bReadOnly, bool bUseKderc, const char *resType )
+ : KConfigBase(), bGroupImmutable(false), bFileImmutable(false),
+ bForceGlobal(false)
+{
+ // set the object's read-only status.
+ setReadOnly(bReadOnly);
+
+ // for right now we will hardcode that we are using the INI
+ // back end driver. In the future this should be converted over to
+ // a object factory of some sorts.
+ KConfigINIBackEnd *aBackEnd = new KConfigINIBackEnd(this,
+ fileName,
+ resType,
+ bUseKderc);
+
+ // set the object's back end pointer to this new backend
+ backEnd = aBackEnd;
+
+ // read initial information off disk
+ reparseConfiguration();
+
+ // we let KStandardDirs add custom user config files. It will do
+ // this only once. So only the first call ever to this constructor
+ // will anything else than return here We have to reparse here as
+ // configuration files may appear after customized directories have
+ // been added. and the info they contain needs to be inserted into the
+ // config object.
+ // Since this makes only sense for config directories, addCustomized
+ // returns true only if new config directories appeared.
+ if (KGlobal::dirs()->addCustomized(this))
+ reparseConfiguration();
+}
+
+KConfig::KConfig(KConfigBackEnd *aBackEnd, bool bReadOnly)
+ : bGroupImmutable(false), bFileImmutable(false),
+ bForceGlobal(false)
+{
+ setReadOnly(bReadOnly);
+ backEnd = aBackEnd;
+ reparseConfiguration();
+}
+
+KConfig::~KConfig()
+{
+ sync();
+
+ delete backEnd;
+}
+
+void KConfig::rollback(bool bDeep)
+{
+ KConfigBase::rollback(bDeep);
+
+ if (!bDeep)
+ return; // object's bDeep flag is set in KConfigBase method
+
+ // clear any dirty flags that entries might have set
+ for (KEntryMapIterator aIt = aEntryMap.begin();
+ aIt != aEntryMap.end(); ++aIt)
+ (*aIt).bDirty = false;
+}
+
+QStringList KConfig::groupList() const
+{
+ QStringList retList;
+
+ KEntryMapConstIterator aIt = aEntryMap.begin();
+ KEntryMapConstIterator aEnd = aEntryMap.end();
+ for (; aIt != aEnd; ++aIt)
+ {
+ while(aIt.key().mKey.isEmpty())
+ {
+ QCString group = aIt.key().mGroup;
+ ++aIt;
+ while (true)
+ {
+ if (aIt == aEnd)
+ return retList; // done
+
+ if (aIt.key().mKey.isEmpty())
+ break; // Group is empty, next group
+
+ if (!aIt.key().bDefault && !(*aIt).bDeleted)
+ {
+ if (group != "$Version") // Special case!
+ retList.append(QString::fromUtf8(group));
+ break; // Group is non-empty, added, next group
+ }
+ ++aIt;
+ }
+ }
+ }
+
+ return retList;
+}
+
+QMap<QString, QString> KConfig::entryMap(const QString &pGroup) const
+{
+ QCString pGroup_utf = pGroup.utf8();
+ KEntryKey groupKey( pGroup_utf, 0 );
+ QMap<QString, QString> tmpMap;
+
+ KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
+ if (aIt == aEntryMap.end())
+ return tmpMap;
+ ++aIt; // advance past special group entry marker
+ for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
+ {
+ // Leave the default values out && leave deleted entries out
+ if (!aIt.key().bDefault && !(*aIt).bDeleted)
+ tmpMap.insert(QString::fromUtf8(aIt.key().mKey), QString::fromUtf8((*aIt).mValue.data(), (*aIt).mValue.length()));
+ }
+
+ return tmpMap;
+}
+
+void KConfig::reparseConfiguration()
+{
+ // Don't lose pending changes
+ if (!isReadOnly() && backEnd && bDirty)
+ backEnd->sync();
+
+ aEntryMap.clear();
+
+ // add the "default group" marker to the map
+ KEntryKey groupKey("<default>", 0);
+ aEntryMap.insert(groupKey, KEntry());
+
+ bFileImmutable = false;
+ parseConfigFiles();
+ bFileImmutable = bReadOnly;
+}
+
+KEntryMap KConfig::internalEntryMap(const QString &pGroup) const
+{
+ QCString pGroup_utf = pGroup.utf8();
+ KEntry aEntry;
+ KEntryMapConstIterator aIt;
+ KEntryKey aKey(pGroup_utf, 0);
+ KEntryMap tmpEntryMap;
+
+ aIt = aEntryMap.find(aKey);
+ if (aIt == aEntryMap.end()) {
+ // the special group key is not in the map,
+ // so it must be an invalid group. Return
+ // an empty map.
+ return tmpEntryMap;
+ }
+ // we now have a pointer to the nodes we want to copy.
+ for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
+ {
+ tmpEntryMap.insert(aIt.key(), *aIt);
+ }
+
+ return tmpEntryMap;
+}
+
+void KConfig::putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup)
+{
+ if (bFileImmutable && !_key.bDefault)
+ return;
+
+ // check to see if the special group key is present,
+ // and if not, put it in.
+ if (_checkGroup)
+ {
+ KEntryKey groupKey( _key.mGroup, 0);
+ KEntry &entry = aEntryMap[groupKey];
+ bGroupImmutable = entry.bImmutable;
+ }
+ if (bGroupImmutable && !_key.bDefault)
+ return;
+
+ // now either add or replace the data
+ KEntry &entry = aEntryMap[_key];
+ bool immutable = entry.bImmutable;
+ if (immutable && !_key.bDefault)
+ return;
+
+ entry = _data;
+ entry.bImmutable |= immutable;
+ entry.bGlobal |= bForceGlobal; // force to kdeglobals
+
+ if (_key.bDefault)
+ {
+ // We have added the data as default value,
+ // add it as normal value as well.
+ KEntryKey key(_key);
+ key.bDefault = false;
+ aEntryMap[key] = _data;
+ }
+}
+
+KEntry KConfig::lookupData(const KEntryKey &_key) const
+{
+ KEntryMapConstIterator aIt = aEntryMap.find(_key);
+ if (aIt != aEntryMap.end())
+ {
+ const KEntry &entry = *aIt;
+ if (entry.bDeleted)
+ return KEntry();
+ else
+ return entry;
+ }
+ else {
+ return KEntry();
+ }
+}
+
+bool KConfig::internalHasGroup(const QCString &group) const
+{
+ KEntryKey groupKey( group, 0);
+
+ KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
+ KEntryMapConstIterator aEnd = aEntryMap.end();
+
+ if (aIt == aEnd)
+ return false;
+ ++aIt;
+ for(; (aIt != aEnd); ++aIt)
+ {
+ if (aIt.key().mKey.isEmpty())
+ break;
+
+ if (!aIt.key().bDefault && !(*aIt).bDeleted)
+ return true;
+ }
+ return false;
+}
+
+void KConfig::setFileWriteMode(int mode)
+{
+ backEnd->setFileWriteMode(mode);
+}
+
+KLockFile::Ptr KConfig::lockFile(bool bGlobal)
+{
+ KConfigINIBackEnd *aBackEnd = dynamic_cast<KConfigINIBackEnd*>(backEnd);
+ if (!aBackEnd) return 0;
+ return aBackEnd->lockFile(bGlobal);
+}
+
+void KConfig::checkUpdate(const QString &id, const QString &updateFile)
+{
+ QString oldGroup = group();
+ setGroup("$Version");
+ QString cfg_id = updateFile+":"+id;
+ QStringList ids = readListEntry("update_info");
+ if (!ids.contains(cfg_id))
+ {
+ QStringList args;
+ args << "--check" << updateFile;
+ KApplication::kdeinitExecWait("kconf_update", args);
+ reparseConfiguration();
+ }
+ setGroup(oldGroup);
+}
+
+KConfig* KConfig::copyTo(const QString &file, KConfig *config) const
+{
+ if (!config)
+ config = new KConfig(QString::null, false, false);
+ config->backEnd->changeFileName(file, "config", false);
+ config->setReadOnly(false);
+ config->bFileImmutable = false;
+ config->backEnd->mConfigState = ReadWrite;
+
+ QStringList groups = groupList();
+ for(QStringList::ConstIterator it = groups.begin();
+ it != groups.end(); ++it)
+ {
+ QMap<QString, QString> map = entryMap(*it);
+ config->setGroup(*it);
+ for (QMap<QString,QString>::Iterator it2 = map.begin();
+ it2 != map.end(); ++it2)
+ {
+ config->writeEntry(it2.key(), it2.data());
+ }
+
+ }
+ return config;
+}
+
+void KConfig::virtual_hook( int id, void* data )
+{ KConfigBase::virtual_hook( id, data ); }
+
+static KStaticDeleter< QValueList<KSharedConfig*> > sd;
+QValueList<KSharedConfig*> *KSharedConfig::s_list = 0;
+
+KSharedConfig::Ptr KSharedConfig::openConfig(const QString& fileName, bool readOnly, bool useKDEGlobals )
+{
+ if (s_list)
+ {
+ for(QValueList<KSharedConfig*>::ConstIterator it = s_list->begin();
+ it != s_list->end(); ++it)
+ {
+ if ((*it)->backEnd->fileName() == fileName &&
+ (*it)->bReadOnly == readOnly &&
+ (*it)->backEnd->useKDEGlobals == useKDEGlobals )
+ return (*it);
+ }
+ }
+ return new KSharedConfig(fileName, readOnly, useKDEGlobals);
+}
+
+KSharedConfig::KSharedConfig( const QString& fileName, bool readonly, bool usekdeglobals)
+ : KConfig(fileName, readonly, usekdeglobals)
+{
+ if (!s_list)
+ {
+ sd.setObject(s_list, new QValueList<KSharedConfig*>);
+ }
+
+ s_list->append(this);
+}
+
+KSharedConfig::~KSharedConfig()
+{
+ if ( s_list )
+ s_list->remove(this);
+}
+
+#include "kconfig.moc"
diff --git a/kdecore/kconfig.h b/kdecore/kconfig.h
new file mode 100644
index 000000000..d8b4d7d54
--- /dev/null
+++ b/kdecore/kconfig.h
@@ -0,0 +1,296 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (C) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KCONFIG_H
+#define _KCONFIG_H
+
+class QTimer;
+
+#include <qvaluelist.h>
+
+#include "kconfigbase.h"
+#include "klockfile.h"
+
+class KConfigPrivate;
+
+/**
+* Access KDE Configuration entries.
+*
+* This class implements KDE's default configuration system.
+*
+* @author Kalle Dalheimer <kalle@kde.org>, Preston Brown <pbrown@kde.org>
+* @see KGlobal::config(), KConfigBase, KSimpleConfig
+* @short KDE Configuration Management class
+*/
+class KDECORE_EXPORT KConfig : public KConfigBase
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Constructs a KConfig object.
+ *
+ * @param fileName A file to parse in addition to the
+ * system-wide file(s). If it is not provided, only global
+ * KDE configuration data will be read (depending on the value of
+ * @p bUseKDEGlobals).
+ * @param bReadOnly Set the config object's read-only status. Note that the
+ * object will automatically become read-only if either the user does not have
+ * write permission to @p fileName or if no file was specified.
+ * @param bUseKDEGlobals Toggle reading the global KDE configuration file.
+ * @param resType the place to look in (config, data, etc) See KStandardDirs.
+ */
+ KConfig( const QString& fileName = QString::null,
+ bool bReadOnly = false, bool bUseKDEGlobals = true, const char *resType="config");
+
+ KConfig(KConfigBackEnd *backEnd, bool bReadOnly = false);
+
+ /**
+ * Destructs the KConfig object.
+ *
+ * Writes back any dirty configuration entries, and destroys
+ * dynamically created objects.
+ */
+ virtual ~KConfig();
+
+ /**
+ * Clears all entries out of the @p dirtyEntryMap, so the
+ * values will not be written to disk on a later call to
+ * sync().
+ *
+ * @param bDeep If true, the dirty map is actually emptied.
+ * otherwise, the config object's global dirty flag is set to
+ * false, but the dirty entries remain in the dirty entry
+ * map.
+ *
+ * @see KConfigBase::rollback
+ */
+ virtual void rollback(bool bDeep = true);
+
+
+ /**
+ * Returns a list of groups that are known.
+ * @return a list of of groups
+ */
+ virtual QStringList groupList() const;
+
+ /**
+ * Returns a map (tree) of entries for all entries in a particular
+ * group.
+ *
+ * Only the actual entry string is returned, none of the
+ * other internal data should be included.
+ *
+ * @param pGroup A group to get keys from.
+ * @return A map of entries in the group specified, indexed by key.
+ * The returned map may be empty if the group is not found.
+ */
+ virtual QMap<QString, QString> entryMap(const QString &pGroup) const;
+
+ /**
+ * Clears all internal data structures and then reread
+ * configuration information from disk.
+ */
+ virtual void reparseConfiguration();
+
+ /**
+ * Set the file mode for newly created files.
+ *
+ * @param mode the mode for new files as described in chmod(2)
+ * @see man:chmod(2) for a description of @p mode
+ */
+ void setFileWriteMode(int mode);
+
+ /**
+ * Forces all following write-operations being performed on kdeglobals,
+ * independent of the bGlobal flag in writeEntry().
+ * @param force true to force writing in kdeglobals
+ * @see forceGlobal
+ */
+ void setForceGlobal( bool force ) { bForceGlobal = force; }
+
+ /**
+ * Returns true if all entries are being written into kdeglobals.
+ * @return true if all entries are being written into kdeglobals
+ * @see setForceGlobal
+ */
+ bool forceGlobal() const { return bForceGlobal; }
+
+ /**
+ * Checks whether the config file contains the update @p id
+ * as contained in @p updateFile. If not, it runs kconf_update
+ * to update the config file.
+ *
+ * If you install config update files with critical fixes
+ * you may wish to use this method to verify that a critical
+ * update has indeed been performed to catch the case where
+ * a user restores an old config file from backup that has
+ * not been updated yet.
+ * @param id the update to check
+ * @param updateFile the file containing the update
+ * @since 3.1
+ */
+ void checkUpdate(const QString &id, const QString &updateFile);
+
+ /**
+ * Copies all entries from this config object to a new config
+ * object that will save itself to @p file.
+ *
+ * Actual saving to @p file happens when the returned object is
+ * destructed or when sync() is called upon it.
+ *
+ * @param file the new config object will save itself to.
+ * @param config optional config object to reuse
+ * @since 3.2
+ */
+ KConfig* copyTo(const QString &file, KConfig *config=0) const;
+
+ /**
+ * Returns a lock file object for the configuration file or 0 if
+ * the backend does not support locking.
+ * @param bGlobal if true, return the lock file for the global config file
+ *
+ * NOTE: KConfig::sync() requires a lock on both the normal and global
+ * config file. When calling KConfig::sync() while having a lock on the
+ * global config file, the normal config file MUST be locked AS WELL and the
+ * normal config file MUST be locked BEFORE the global config file!
+ * Otherwise there is a risk of deadlock.
+ * @since 3.3
+ */
+ KLockFile::Ptr lockFile( bool bGlobal=false );
+
+protected:
+
+ /**
+ * Returns true if the specified group is known.
+ *
+ * @param group The group to search for.
+ * @returns true if the group exists.
+ */
+ virtual bool internalHasGroup(const QCString &group) const;
+
+ /**
+ * @internal
+ * Returns a map (tree) of the entries in the specified group.
+ *
+ * Do not use this function, the implementation / return type are
+ * subject to change.
+ *
+ * @param pGroup the group to provide a KEntryMap for.
+ * @return The map of the entries in the group.
+ */
+ virtual KEntryMap internalEntryMap(const QString &pGroup) const;
+
+ /**
+ * @internal
+ * Returns a copy of the internal map used to hold all entries.
+ *
+ * Do not use this function, the implementation / return type are
+ * subject to change.
+ *
+ * @return The map of the entries in the group.
+ */
+ virtual KEntryMap internalEntryMap() const { return aEntryMap; }
+
+ /**
+ * Inserts a (key, value) pair into the internal storage mechanism of
+ * the configuration object.
+ *
+ * @param _key The key to insert. It contains information both on
+ * the group of the key and the key itself. If the key already
+ * exists, the old value will be replaced.
+ * @param _data the KEntry that is to be stored.
+ * @param _checkGroup When false, assume that the group already exists.
+ */
+ virtual void putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup=true);
+
+ /**
+ * Looks up an entry in the config object's internal structure.
+ *
+ * @param _key The key to look up It contains information both on
+ * the group of the key and the entry's key itself.
+ * @return the KEntry value (data) found for the key. KEntry.aValue
+ * will be the null string if nothing was located.
+ */
+ virtual KEntry lookupData(const KEntryKey &_key) const;
+
+ /**
+ * Contains all key,value entries, as well as some "special"
+ * keys which indicate the start of a group of entries.
+ *
+ * These special keys will have the .key portion of their KEntryKey
+ * set to QString::null.
+ */
+ KEntryMap aEntryMap;
+
+private:
+ /**
+ * @internal
+ * copy-construction and assignment are not allowed
+ */
+ KConfig( const KConfig& );
+ /**
+ * @internal
+ * copy-construction and assignment are not allowed
+ */
+ KConfig& operator= ( const KConfig& rConfig );
+
+private:
+ bool bGroupImmutable : 1; // Current group is immutable.
+ bool bFileImmutable : 1; // Current file is immutable.
+ bool bForceGlobal : 1; // Apply everything to kdeglobals.
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KConfigPrivate *d;
+};
+
+/**
+ * KConfig variant using shared memory
+ *
+ * KSharedConfig provides a reference counted, shared memory variant
+ * of KConfig.
+ */
+class KDECORE_EXPORT KSharedConfig : public KConfig, public KShared
+{
+ friend class QValueList<KSharedConfig*>;
+public:
+ typedef KSharedPtr<KSharedConfig> Ptr;
+
+public:
+ /**
+ * Returns a ref-counted pointer to a shared read-write config object.
+ * @param fileName the name of the file to use for the configuration
+ * @param readOnly set the config object's read-only status
+ * @param bUseKDEGlobals Toggle reading the global KDE configuration file.
+ */
+ static KSharedConfig::Ptr openConfig(const QString& fileName, bool readOnly = false,
+ bool bUseKDEGlobals = true);
+
+private:
+ KSharedConfig( const QString& fileName, bool readOnly, bool useKDEGlobals );
+ ~KSharedConfig();
+
+ static QValueList<KSharedConfig*> *s_list;
+};
+
+#endif
diff --git a/kdecore/kconfig_compiler/Makefile.am b/kdecore/kconfig_compiler/Makefile.am
new file mode 100644
index 000000000..cfecd8408
--- /dev/null
+++ b/kdecore/kconfig_compiler/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = example tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/kdecore -I$(top_srcdir) $(all_includes)
+
+bin_PROGRAMS = kconfig_compiler
+
+kconfig_compiler_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kconfig_compiler_LDADD = $(LIB_KDECORE)
+kconfig_compiler_SOURCES = kconfig_compiler.cpp
+
+TESTFILES = test1.kcfg test2.kcfg test3.kcfg test4.kcfg test_dpointer.kcfg
+
+check-local:
+ for i in $(TESTFILES); \
+ do xmllint --noout --schema $(srcdir)/kcfg.xsd $(srcdir)/tests/$$i; \
+ perl $(top_srcdir)/kdecore/kconfig_compiler/checkkcfg.pl \
+ $(top_srcdir)/kdecore/kconfig_compiler/tests/$$i; done
+
diff --git a/kdecore/kconfig_compiler/README.dox b/kdecore/kconfig_compiler/README.dox
new file mode 100644
index 000000000..36d9f988b
--- /dev/null
+++ b/kdecore/kconfig_compiler/README.dox
@@ -0,0 +1,255 @@
+/**
+\page kconfig_compiler The KDE Configuration Compiler
+
+kconfig_compiler generates C++ source code from an XML file containing
+information about configuration options (.kcfg) and a file that provides
+the code generation options (.kcfgc) The generated class is based on
+KConfigSkeleton and provides an API for the application to access its
+configuration data.
+
+<h2>XML description of the configuration options</h2>
+
+The structure of the .kcfg file is described by its DTD kcfg.dtd.
+
+The \<kcfgfile\> tag contains the name of the configuration file described.
+Omitting the name will make the generated class use the default configuration
+file ("<appname>rc").
+
+The \<include\> tags are optional and may contain C++ header files that
+are needed to compile the code needed to compute default values.
+
+The remaining entries in the XML file are grouped by the tag \<group\>
+which describes the corresponding group in the configuration file.
+
+The individual entries must have at least a name or a key. The name is used to
+create accessor and modifier functions. It's also used as the key in the config
+file. If \<key\> is given, but not \<name\>, the name is constructed by removing
+all spaces from \<key\>.
+
+An entry must also have a type. The list of allowable types is
+specified in the DTD and loosely follows the list of types supported
+by the QVariant with exception of the clearly binary types
+(e.g. Pixmap, Image...) which are not supported. Besides those basic
+type the following special types are supported:
+
+- Path This is a string that is specially treated as a file-path.
+ In particular paths in the home directory are prefixed with $HOME in
+ when being stored in the configuration file.
+
+- Enum This indicates an enumeration. The possible enum values should
+ be provided via the \<choices\> tag. Enum values are accessed as integers
+ by the application but stored as string in the configuration file. This
+ makes it possible to add more values at a later date without breaking
+ compatibility.
+
+- IntList This indicates a list of integers. This information is provided
+ to the application as QValueList<int>. Useful for storing QSplitter
+ geometries.
+
+An entry can optionally have a default value which is used as default when
+the value isn't specified in any config file. Default values are interpreted
+as literal constant values. If a default value needs to be computed
+or if it needs to be obtained from a function call, the \<default\> tag
+should contain the code="true" attribute. The contents of the \<default\>
+tag is then considered to be a C++ expression. Note that in this case you
+might have to add an \<include\> tag as described above so that the code
+which computes the default value can be compiled.
+
+Additional code for computing default values can be provided via
+the \<code\> tag. The contents of the \<code\> tag is inserted as-is. A
+typical use for this is to compute a common default value which can
+then be referenced by multiple entries that follow.
+
+<h2>Code generation options</h2>
+
+The options for generating the C++ sources are read from the file with the
+extension .kcfgc. To generate a class add the corresponding kcfgc file to the
+SOURCES line in the Makefile.am.
+
+The following options are read from the kcfgc file:
+
+<table>
+<tr>
+ <td><b><i>Name</i></b></td>
+ <td><b><i>Type</i></b></td>
+ <td><b><i>Default</i></b></td>
+ <td><b><i>Description</i></b></td>
+</tr>
+<tr>
+ <td><b>File</b></td>
+ <td>string</td>
+ <td>programname.kcfg</td>
+ <td>Name of kcfg file containing the options the class is generated for</td>
+</tr>
+<tr>
+ <td><b>NameSpace</b></td>
+ <td>string</td>
+ <td>-</td>
+ <td>Optional namespace for generated class</td>
+</tr>
+<tr>
+ <td><b>ClassName</b></td>
+ <td>string</td>
+ <td>-</td>
+ <td>Name of generated class (required)</td>
+</tr>
+<tr>
+ <td><b>Inherits</b></td>
+ <td>string</td>
+ <td>KConfigSkeleton</td>
+ <td>Class the generated class inherits from. This class must inherit
+ KConfigSkeleton.</td>
+</tr>
+<tr>
+ <td><b>Visibility</b></td>
+ <td>string</td>
+ <td>-</td>
+ <td>Inserts visibility directive (for example KDE_EXPORT) between "class" keyword and class
+ name in header file</td>
+</tr>
+<tr>
+ <td><b>Singleton</b></td>
+ <td>bool</td>
+ <td>false</td>
+ <td>Generated class is a singleton.</td>
+</tr>
+<tr>
+ <td><b>CustomAdditions</b></td>
+ <td>bool</td>
+ <td>-</td>
+ <td></td>
+</tr>
+<tr>
+ <td><b>MemberVariables</b></td>
+ <td>string: public|protected|private</td>
+ <td>private</td>
+ <td>C++ access modifier used for memeber variables holding the configuration
+ valuse</td>
+</tr>
+<tr>
+ <td><b>IncludeFiles</b></td>
+ <td>comma separated list of strings</td>
+ <td>-</td>
+ <td>Names of files to be included in the header of the generated class</td>
+</tr>
+<tr>
+ <td><b>Mutators</b></td>
+ <td>true, false or a comma seperated list of options</td>
+ <td>-</td>
+ <td>If true, mutator functions for all configuration options are generated.
+ If false, no mutator functions are generated. If a list is provided,
+ mutator functions are generated for the options that are listed.</td>
+</tr>
+<tr>
+ <td><b>ItemAccessors</b></td>
+ <td>bool</td>
+ <td>false</td>
+ <td>Generate accessor functions for the KConfigSkeletonItem objects
+ corresponding to the configuration options. If <b>SetUserTexts</b> is set,
+ <b>ItemAccessors</b> also has to be set.</td>
+</tr>
+<tr>
+ <td><b>SetUserTexts</b></td>
+ <td>bool</td>
+ <td>false</td>
+ <td>Set the label and whatthis texts of the items from the kcfg file.If
+ <b>SetUserTexts</b> is set, <b>ItemAccessors</b> also has to be set.</td>
+</tr>
+<tr>
+ <td><b>GlobalEnums</b></td>
+ <td>bool</td>
+ <td>false</td>
+ <td>If set to true all choices of Enum items will be created in the global
+ scope of the generated class. If set to false, each Enum item will get an own
+ namespace for its choices.</td>
+</tr>
+</table>
+
+
+<h2>Advanced options</h2>
+
+There are several possibilities to parameterize entries.
+
+- Parameterized entries
+
+An entry can be parameterized using a fixed range parameter specified with
+the \<parameter\> tag. Such parameter can either be an Enum or an int. An Enum
+parameter should specify the possible enumeration values with the \<choices\>
+tag. An int parameter should specify its maximum value. Its minimum value
+is always 0.
+
+A parameterized entry is expanded to a number of entries, one for each
+value in the parameter range. The name and key should contain a reference
+to the parameter in the form of $(parameter-name). When expanding the entries
+the $(parameter-name) part is replaced with the value of the parameter.
+In the case of an Enum parameter it is replaced with the name of the
+enumuration value. In the case of an int parameter it is replaced with
+the numeric value of the parameter.
+
+Parameterized entries all share the same default value unless different
+default values have been specified for specific parameter values.
+This can be done with the param= attribute of the \<default\>. When a
+param attribute is specified the default value only applies to that
+particular parameter value.
+
+Example 1:
+\verbatim
+ <entry name="Color$(ColorIndex)" type="Color" key="color_$(ColorIndex)">
+ <parameter name="ColorIndex" type="Int" max="3"/>
+ <default param="0">#ff0000</default>
+ <default param="1">#00ff00</default>
+ <default param="2">#0000ff</default>
+ <default param="3">#ffff00</default>
+ </entry>
+\endverbatim
+
+The above describes 4 color configuration entries with the following defaults:
+
+\verbatim
+color_0=#ff0000
+color_1=#00ff00
+color_2=#0000ff
+color_3=#ffff00
+\endverbatim
+
+The configuration options will be accessible to the application via
+a QColor color(int ColorIndex) and a
+void setColor(int ColorIndex, const QColor &v) function.
+
+Example 2:
+\verbatim
+ <entry name="Sound$(SoundEvent)" type="String" key="sound_$(SoundEvent)">
+ <parameter name="SoundEvent" type="Enum">
+ <values>
+ <value>Explosion</value>
+ <value>Crash</value>
+ <value>Missile</value>
+ </values>
+ </parameter>
+ <default param="Explosion">boom.wav</default>
+ <default param="Crash">crash.wav</default>
+ <default param="Missile">missile.wav</default>
+ </entry>
+\endverbatim
+
+The above describes 3 string configuration entries with the following defaults:
+
+sound_Explosion=boom.wav
+sound_Crash=crash.wav
+sound_Missile=missile.wav
+
+The configuration options will be accessible to the application via
+a QString sound(int SoundEvent) and a
+void setSound(int SoundEvent, const QString &v) function.
+
+- Parameterized groups
+
+...STILL TODO...
+
+
+
+
+
+If you have questions or comments please contact Cornelius Schumacher
+<schumacher@kde.org> or Waldo Bastian <bastian@kde.org>
+*/
diff --git a/kdecore/kconfig_compiler/TODO b/kdecore/kconfig_compiler/TODO
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/kdecore/kconfig_compiler/TODO
diff --git a/kdecore/kconfig_compiler/checkkcfg.pl b/kdecore/kconfig_compiler/checkkcfg.pl
new file mode 100755
index 000000000..2eddbeee6
--- /dev/null
+++ b/kdecore/kconfig_compiler/checkkcfg.pl
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+if ( @ARGV != 1 ) {
+ print STDERR "Missing arg: filename\n";
+ exit 1;
+}
+
+$file = $ARGV[0];
+
+$file =~ /^(.*)\.[^\.]*$/;
+$filebase = $1;
+
+$file_h = "$filebase.h";
+$file_cpp = "$filebase.cpp";
+
+$kcfgc = $file . "c";
+
+$cmd = "./kconfig_compiler $file $kcfgc";
+
+#print "CMD $cmd\n";
+
+if ( system( $cmd ) != 0 ) {
+ print STDERR "Unable to run kconfig_compiler\n";
+ exit 1;
+}
+
+checkfile( $file_h );
+checkfile( $file_cpp );
+
+exit 0;
+
+sub checkfile()
+{
+ my $file = shift;
+
+ $file =~ /\/([^\/]*)$/;
+ my $filename = $1;
+
+ print "Checking '$filename':\n";
+
+ my @ref;
+ if ( !open( REF, "$file.ref" ) ) {
+ print STDERR "Unable to open $file.ref\n";
+ exit 1;
+ }
+ while( <REF> ) {
+ push @ref, $_;
+ }
+ close REF;
+
+ if ( !open( READ, $filename ) ) {
+ print STDERR "Unable to open $filename\n";
+ exit 1;
+ }
+
+ $error = 0;
+ $i = 0;
+ $line = 1;
+ while( <READ> ) {
+ $out = $_;
+ $ref = @ref[$i++];
+
+ if ( $out ne $ref ) {
+ $error++;
+ print " Line $line: Expected : $ref";
+ print " Line $line: Compiler output : $out";
+ }
+
+ $line++;
+ }
+
+ close READ;
+
+ if ( $error > 0 ) {
+ print "\n FAILED: $error errors found.\n";
+ if ( $error > 5 ) {
+ system( "diff -u $file.ref $filename" );
+ }
+ exit 1;
+ } else {
+ print " OK\n";
+ }
+}
diff --git a/kdecore/kconfig_compiler/example/Makefile.am b/kdecore/kconfig_compiler/example/Makefile.am
new file mode 100644
index 000000000..730f7fcc3
--- /dev/null
+++ b/kdecore/kconfig_compiler/example/Makefile.am
@@ -0,0 +1,27 @@
+AM_CPPFLAGS = -I$(top_srcdir)/kdecore -I$(top_srcdir) $(all_includes)
+
+check_PROGRAMS = example # autoexample
+EXTRA_PROGRAMS = autoexample
+
+example_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+example_LDADD = $(LIB_KDECORE)
+example_SOURCES = example.cpp exampleprefs_base.cpp
+
+autoexample_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+autoexample_LDADD = $(LIB_KDECORE) $(LIB_KDEUI)
+autoexample_SOURCES = exampleprefs_base.cpp general_base.ui myoptions_base.ui \
+ autoexample.cpp
+
+example.o exampleprefs_base.o: exampleprefs_base.h
+# avoid running the below command in parallel
+exampleprefs_base.cpp: exampleprefs_base.h
+exampleprefs_base.cpp exampleprefs_base.h: $(srcdir)/example.kcfg ../kconfig_compiler $(srcdir)/exampleprefs_base.kcfgc
+ ../kconfig_compiler $(srcdir)/example.kcfg $(srcdir)/exampleprefs_base.kcfgc
+
+METASOURCES = AUTO
+
+CLEANFILES = exampleprefs_base.h exampleprefs_base.cpp
+
+## The example's messages should not go into kdelibs.pot
+messages: rc.cpp
+ true
diff --git a/kdecore/kconfig_compiler/example/autoexample.cpp b/kdecore/kconfig_compiler/example/autoexample.cpp
new file mode 100644
index 000000000..528c12457
--- /dev/null
+++ b/kdecore/kconfig_compiler/example/autoexample.cpp
@@ -0,0 +1,64 @@
+/*
+ This file is part of KDE.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "general_base.h"
+#include "myoptions_base.h"
+
+#include "exampleprefs_base.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kconfigdialog.h>
+
+#include <qlabel.h>
+
+int main( int argc, char **argv )
+{
+ KAboutData aboutData( "example", I18N_NOOP("autoconfig example"), "0.1" );
+ aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+
+ KApplication app;
+
+ ExamplePrefsBase configSkeleton( "dummy1", "dummy2" );
+ configSkeleton.readConfig();
+
+ KConfigDialog *dialog = new KConfigDialog( 0, "settings", &configSkeleton );
+
+ GeneralBase *general = new GeneralBase( 0 );
+ dialog->addPage( general, i18n("General"), "General", "" );
+
+ MyOptionsBase *myOptions = new MyOptionsBase( 0 );
+ dialog->addPage( myOptions, i18n("MyOptions"), "MyOptions", "" );
+
+ app.setMainWidget( dialog );
+
+ dialog->show();
+
+ return app.exec();
+}
diff --git a/kdecore/kconfig_compiler/example/example.cpp b/kdecore/kconfig_compiler/example/example.cpp
new file mode 100644
index 000000000..146d2460f
--- /dev/null
+++ b/kdecore/kconfig_compiler/example/example.cpp
@@ -0,0 +1,52 @@
+/*
+ This file is part of KDE.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "exampleprefs_base.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+
+int main( int argc, char **argv )
+{
+ KAboutData aboutData( "example", I18N_NOOP("cfgc example"), "0.1" );
+ aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+
+ KApplication app;
+
+ ExamplePrefsBase *prefs = new ExamplePrefsBase("Trans1", "Folder2");
+
+ prefs->readConfig();
+
+ prefs->setAnotherOption(17);
+
+ kdWarning() << "Another Option = " << prefs->anotherOption() << endl;
+ kdWarning() << "Another Option2 = " << prefs->anotherOption2() << endl;
+ kdWarning() << "MyPaths = " << prefs->myPaths() << endl;
+ kdWarning() << "MyPaths2 = " << prefs->myPaths2() << endl;
+}
diff --git a/kdecore/kconfig_compiler/example/example.kcfg b/kdecore/kconfig_compiler/example/example.kcfg
new file mode 100644
index 000000000..076bfb644
--- /dev/null
+++ b/kdecore/kconfig_compiler/example/example.kcfg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>qdir.h</include>
+ <kcfgfile name="examplerc">
+ <parameter name="transport" />
+ <parameter name="folder" />
+ </kcfgfile>
+ <group name="General-$(folder)">
+ <entry name="OneOption" type="Bool">
+ <label>One option</label>
+ <default>true</default>
+ </entry>
+ <entry name="AnotherOption" type="Int" key="Another Option">
+ <label>Another option</label>
+ <default>5</default>
+ </entry>
+ <entry name="ListOption" type="Enum">
+ <label>This is some funky option</label>
+ <whatsthis>And this is a longer description of this option. Just wondering, how will the translations of those be handled?</whatsthis>
+ <choices>
+ <choice name="One"/>
+ <choice name="Two"/>
+ <choice name="Three"/>
+ </choices>
+ <default>One</default>
+ </entry>
+ </group>
+ <group name="MyOptions">
+ <entry name="MyString" type="String">
+ <label>This is a string</label>
+ <default>Default String</default>
+ </entry>
+ <entry name="MyPath" type="Path">
+ <label>This is a path</label>
+ <default code="true">QDir::homeDirPath()+QString::fromLatin1(".hidden_file")</default>
+ </entry>
+ <entry name="MyPaths" type="PathList">
+ <label>This is a list of paths</label>
+ <default>/home,~</default>
+ </entry>
+ <entry name="MyPaths2" type="PathList">
+ <label>This is a list of paths (test2)</label>
+ <default code="true">QStringList(QDir::homeDirPath())</default>
+ </entry>
+ <entry name="AnotherOption2" type="Int" key="Another Option">
+ <label>Another option</label>
+ <default>10</default>
+ </entry>
+ <entry name="MyStringList" type="StringList">
+ <default>up,down</default>
+ </entry>
+ <entry name="MyStringListHidden" hidden="true" type="StringList">
+ <default>up,down</default>
+ </entry>
+ <entry name="MyNumber" type="Int64" key="List-$(transport)-$(folder)">
+ <label>List Number</label>
+ <default>1</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kdecore/kconfig_compiler/example/exampleprefs_base.kcfgc b/kdecore/kconfig_compiler/example/exampleprefs_base.kcfgc
new file mode 100644
index 000000000..957ed9123
--- /dev/null
+++ b/kdecore/kconfig_compiler/example/exampleprefs_base.kcfgc
@@ -0,0 +1,18 @@
+# Code generation options for kconfig_compiler
+ClassName=ExamplePrefsBase
+#
+# Singleton=false
+#
+# Inherits=KConfigSkeleton
+#
+# IncludeFiles=libkdepim/kpimprefs.h
+#
+# MemberVariables=public
+#
+### The following line includes the file exampleprefs_base_addon.h
+### It can be used to add extra functions and variables to the
+### class.
+# CustomAdditions=true
+#
+### Provide setFooBar(int) style functions
+Mutators=true
diff --git a/kdecore/kconfig_compiler/example/general_base.ui b/kdecore/kconfig_compiler/example/general_base.ui
new file mode 100644
index 000000000..9b41370c7
--- /dev/null
+++ b/kdecore/kconfig_compiler/example/general_base.ui
@@ -0,0 +1,46 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>GeneralBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>GeneralBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>486</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>AutoExampleDialog</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_OneOption</cstring>
+ </property>
+ <property name="text">
+ <string>OneOption</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_AnotherOption2</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>AnotherOption:</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kdecore/kconfig_compiler/example/myoptions_base.ui b/kdecore/kconfig_compiler/example/myoptions_base.ui
new file mode 100644
index 000000000..3c0c2e6cb
--- /dev/null
+++ b/kdecore/kconfig_compiler/example/myoptions_base.ui
@@ -0,0 +1,35 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>MyOptionsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>MyOptionsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>486</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>MyString:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_MyString</cstring>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kdecore/kconfig_compiler/kcfg.xsd b/kdecore/kconfig_compiler/kcfg.xsd
new file mode 100644
index 000000000..97f716d62
--- /dev/null
+++ b/kdecore/kconfig_compiler/kcfg.xsd
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- kcfg XSD v1.0 -->
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:kcfg="http://www.kde.org/standards/kcfg/1.0"
+ targetNamespace="http://www.kde.org/standards/kcfg/1.0"
+ version="1.0"
+ elementFormDefault="qualified" >
+
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Copyright (c) 2003 Cornelius Schumacher &lt;schumacher@kde.org&gt;
+ Copyright (c) 2003 Waldo Bastian &lt;bastian@kde.org&gt;
+ Copyright (c) 2003 Zack Rusin &lt;zack@kde.org&gt;
+ Copyright (c) 2004 Frans Englich &lt;frans.englich@telia.com&gt;
+
+ Permission to use, copy, modify and distribute this DTD
+ and its accompanying documentation for any purpose and without fee
+ is hereby granted in perpetuity, provided that the above copyright
+ notice and this paragraph appear in all copies. The copyright
+ holders make no representation about the suitability of the DTD for
+ any purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:annotation>
+ <xsd:documentation>
+
+ A Schema for KDE's KConfigXT XML format. It is similar to the DTD
+ found at:
+
+ http://www.kde.org/standards/kcfg/1.0/kcfg.dtd
+
+ Documents valid against the Schema version are backwards compatible
+ to the DTD. Validating against the Schema instead of the DTD is
+ recommended, since the former provides better validation.
+
+ A document instance of this Schema should have a declaration
+ looking like this:
+
+ <![CDATA[
+
+ <?xml version="1.0" encoding="UTF-8" ?>
+ <kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <!-- the content -->
+ </kcfg>
+
+ ]]>
+
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:element name="kcfg">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="include" minOccurs="0" maxOccurs="unbounded" type="xsd:string"/>
+ <xsd:element name="kcfgfile" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="parameter" type="kcfg:parameter" minOccurs="0" maxOccurs="unbounded" />
+ <!-- FIXME: Are really unbounded occurances of parameter allowed? -->
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="optional"/>
+ <xsd:attribute name="arg" type="xsd:boolean" use="optional"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="group" maxOccurs="unbounded" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="entry" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="parameter" minOccurs="0" type="kcfg:parameter"/>
+ <xsd:element name="label" minOccurs="0" type="xsd:string"/>
+ <xsd:element name="whatsthis" minOccurs="0" type="xsd:string"/>
+ <xsd:element name="choices" minOccurs="0">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="choice" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:all>
+ <xsd:element minOccurs="0" name="label" type="xsd:string"/>
+ <xsd:element minOccurs="0" name="whatsthis" type="xsd:string"/>
+ </xsd:all>
+ <xsd:attribute name="name" use="required" type="xsd:string"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="code" minOccurs="0" type="kcfg:code"/>
+
+ <xsd:element name="default" maxOccurs="unbounded" minOccurs="0" >
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute use="optional" name="code" type="xsd:boolean"/>
+ <xsd:attribute use="optional" name="param" type="xsd:string"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="min" minOccurs="0" >
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="code" type="xsd:boolean"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="max" minOccurs="0">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="code" type="xsd:boolean"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ </xsd:choice>
+ <xsd:attribute name="name" use="optional" type="xsd:string"/>
+ <xsd:attribute name="key" use="optional" type="xsd:string"/>
+ <xsd:attribute name="hidden" use="optional" type="xsd:boolean"/>
+ <xsd:attribute name="type" type="kcfg:datatype"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:simpleType name="datatype">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="String"/>
+ <xsd:enumeration value="StringList"/>
+ <xsd:enumeration value="Font"/>
+ <xsd:enumeration value="Rect"/>
+ <xsd:enumeration value="Size"/>
+ <xsd:enumeration value="Color"/>
+ <xsd:enumeration value="Point"/>
+ <xsd:enumeration value="Int"/>
+ <xsd:enumeration value="UInt"/>
+ <xsd:enumeration value="Bool"/>
+ <xsd:enumeration value="Double"/>
+ <xsd:enumeration value="DateTime"/>
+ <xsd:enumeration value="Int64"/>
+ <xsd:enumeration value="UInt64"/>
+ <xsd:enumeration value="IntList"/>
+ <xsd:enumeration value="Enum"/>
+ <xsd:enumeration value="Path"/>
+ <xsd:enumeration value="PathList"/>
+ <xsd:enumeration value="Password"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="parameter">
+ <xsd:sequence>
+ <xsd:element minOccurs="0" name="values">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" maxOccurs="unbounded" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string"/>
+ <xsd:attribute name="type" use="optional" type="kcfg:datatype" />
+ <xsd:attribute name="max" use="optional" type="xsd:positiveInteger"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="code">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string"/>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+</xsd:schema>
+
diff --git a/kdecore/kconfig_compiler/kconfig_compiler.cpp b/kdecore/kconfig_compiler/kconfig_compiler.cpp
new file mode 100644
index 000000000..9c245e319
--- /dev/null
+++ b/kdecore/kconfig_compiler/kconfig_compiler.cpp
@@ -0,0 +1,1700 @@
+// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
+/*
+ This file is part of KDE.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qdom.h>
+#include <qregexp.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+
+#include <iostream>
+
+static const KCmdLineOptions options[] =
+{
+ { "d", 0, 0 },
+ { "directory <dir>", I18N_NOOP("Directory to generate files in"), "." },
+ { "+file.kcfg", I18N_NOOP("Input kcfg XML file"), 0 },
+ { "+file.kcfgc", I18N_NOOP("Code generation options file"), 0 },
+ KCmdLineLastOption
+};
+
+
+bool globalEnums;
+bool itemAccessors;
+bool dpointer;
+QStringList allNames;
+QRegExp *validNameRegexp;
+QString This;
+QString Const;
+
+class CfgEntry
+{
+ public:
+ struct Choice
+ {
+ QString name;
+ QString label;
+ QString whatsThis;
+ };
+
+ CfgEntry( const QString &group, const QString &type, const QString &key,
+ const QString &name, const QString &label,
+ const QString &whatsThis, const QString &code,
+ const QString &defaultValue, const QValueList<Choice> &choices,
+ bool hidden )
+ : mGroup( group ), mType( type ), mKey( key ), mName( name ),
+ mLabel( label ), mWhatsThis( whatsThis ), mCode( code ),
+ mDefaultValue( defaultValue ),
+ mChoices( choices ), mHidden( hidden )
+ {
+ }
+
+ void setGroup( const QString &group ) { mGroup = group; }
+ QString group() const { return mGroup; }
+
+ void setType( const QString &type ) { mType = type; }
+ QString type() const { return mType; }
+
+ void setKey( const QString &key ) { mKey = key; }
+ QString key() const { return mKey; }
+
+ void setName( const QString &name ) { mName = name; }
+ QString name() const { return mName; }
+
+ void setLabel( const QString &label ) { mLabel = label; }
+ QString label() const { return mLabel; }
+
+ void setWhatsThis( const QString &whatsThis ) { mWhatsThis = whatsThis; }
+ QString whatsThis() const { return mWhatsThis; }
+
+ void setDefaultValue( const QString &d ) { mDefaultValue = d; }
+ QString defaultValue() const { return mDefaultValue; }
+
+ void setCode( const QString &d ) { mCode = d; }
+ QString code() const { return mCode; }
+
+ void setMinValue( const QString &d ) { mMin = d; }
+ QString minValue() const { return mMin; }
+
+ void setMaxValue( const QString &d ) { mMax = d; }
+ QString maxValue() const { return mMax; }
+
+ void setParam( const QString &d ) { mParam = d; }
+ QString param() const { return mParam; }
+
+ void setParamName( const QString &d ) { mParamName = d; }
+ QString paramName() const { return mParamName; }
+
+ void setParamType( const QString &d ) { mParamType = d; }
+ QString paramType() const { return mParamType; }
+
+ void setChoices( const QValueList<Choice> &d ) { mChoices = d; }
+ QValueList<Choice> choices() const { return mChoices; }
+
+ void setParamValues( const QStringList &d ) { mParamValues = d; }
+ QStringList paramValues() const { return mParamValues; }
+
+ void setParamDefaultValues( const QStringList &d ) { mParamDefaultValues = d; }
+ QString paramDefaultValue(int i) const { return mParamDefaultValues[i]; }
+
+ void setParamMax( int d ) { mParamMax = d; }
+ int paramMax() const { return mParamMax; }
+
+ bool hidden() const { return mHidden; }
+
+ void dump() const
+ {
+ kdDebug() << "<entry>" << endl;
+ kdDebug() << " group: " << mGroup << endl;
+ kdDebug() << " type: " << mType << endl;
+ kdDebug() << " key: " << mKey << endl;
+ kdDebug() << " name: " << mName << endl;
+ kdDebug() << " label: " << mLabel << endl;
+// whatsthis
+ kdDebug() << " code: " << mCode << endl;
+// kdDebug() << " values: " << mValues.join(":") << endl;
+
+ if (!param().isEmpty())
+ {
+ kdDebug() << " param name: "<< mParamName << endl;
+ kdDebug() << " param type: "<< mParamType << endl;
+ kdDebug() << " paramvalues: " << mParamValues.join(":") << endl;
+ }
+ kdDebug() << " default: " << mDefaultValue << endl;
+ kdDebug() << " hidden: " << mHidden << endl;
+ kdDebug() << " min: " << mMin << endl;
+ kdDebug() << " max: " << mMax << endl;
+ kdDebug() << "</entry>" << endl;
+ }
+
+ private:
+ QString mGroup;
+ QString mType;
+ QString mKey;
+ QString mName;
+ QString mLabel;
+ QString mWhatsThis;
+ QString mCode;
+ QString mDefaultValue;
+ QString mParam;
+ QString mParamName;
+ QString mParamType;
+ QValueList<Choice> mChoices;
+ QStringList mParamValues;
+ QStringList mParamDefaultValues;
+ int mParamMax;
+ bool mHidden;
+ QString mMin;
+ QString mMax;
+};
+
+class Param {
+public:
+ QString name;
+ QString type;
+};
+
+// returns the name of an member variable
+// use itemPath to know the full path
+// like using d-> in case of dpointer
+static QString varName(const QString &n)
+{
+ QString result;
+ if ( !dpointer ) {
+ result = "m"+n;
+ result[1] = result[1].upper();
+ }
+ else {
+ result = n;
+ result[0] = result[0].lower();
+ }
+ return result;
+}
+
+static QString varPath(const QString &n)
+{
+ QString result;
+ if ( dpointer ) {
+ result = "d->"+varName(n);
+ }
+ else {
+ result = varName(n);
+ }
+ return result;
+}
+
+static QString enumName(const QString &n)
+{
+ QString result = "Enum"+n;
+ result[4] = result[4].upper();
+ return result;
+}
+
+static QString setFunction(const QString &n, const QString &className = QString::null)
+{
+ QString result = "set"+n;
+ result[3] = result[3].upper();
+
+ if ( !className.isEmpty() )
+ result = className + "::" + result;
+ return result;
+}
+
+
+static QString getFunction(const QString &n, const QString &className = QString::null)
+{
+ QString result = n;
+ result[0] = result[0].lower();
+
+ if ( !className.isEmpty() )
+ result = className + "::" + result;
+ return result;
+}
+
+
+static void addQuotes( QString &s )
+{
+ if ( s.left( 1 ) != "\"" ) s.prepend( "\"" );
+ if ( s.right( 1 ) != "\"" ) s.append( "\"" );
+}
+
+static QString quoteString( const QString &s )
+{
+ QString r = s;
+ r.replace( "\\", "\\\\" );
+ r.replace( "\"", "\\\"" );
+ r.replace( "\r", "" );
+ r.replace( "\n", "\\n\"\n\"" );
+ return "\"" + r + "\"";
+}
+
+static QString literalString( const QString &s )
+{
+ bool isAscii = true;
+ for(int i = s.length(); i--;)
+ if (s[i].unicode() > 127) isAscii = false;
+
+ if (isAscii)
+ return "QString::fromLatin1( " + quoteString(s) + " )";
+ else
+ return "QString::fromUtf8( " + quoteString(s) + " )";
+}
+
+static QString dumpNode(const QDomNode &node)
+{
+ QString msg;
+ QTextStream s(&msg, IO_WriteOnly );
+ node.save(s, 0);
+
+ msg = msg.simplifyWhiteSpace();
+ if (msg.length() > 40)
+ return msg.left(37)+"...";
+ return msg;
+}
+
+static QString filenameOnly(QString path)
+{
+ int i = path.findRev('/');
+ if (i >= 0)
+ return path.mid(i+1);
+ return path;
+}
+
+static void preProcessDefault( QString &defaultValue, const QString &name,
+ const QString &type,
+ const QValueList<CfgEntry::Choice> &choices,
+ QString &code )
+{
+ if ( type == "String" && !defaultValue.isEmpty() ) {
+ defaultValue = literalString(defaultValue);
+
+ } else if ( type == "Path" && !defaultValue.isEmpty() ) {
+ defaultValue = literalString( defaultValue );
+
+ } else if ( (type == "StringList" || type == "PathList") && !defaultValue.isEmpty() ) {
+ QTextStream cpp( &code, IO_WriteOnly | IO_Append );
+ if (!code.isEmpty())
+ cpp << endl;
+
+ cpp << " QStringList default" << name << ";" << endl;
+ QStringList defaults = QStringList::split( ",", defaultValue );
+ QStringList::ConstIterator it;
+ for( it = defaults.begin(); it != defaults.end(); ++it ) {
+ cpp << " default" << name << ".append( QString::fromUtf8( \"" << *it << "\" ) );"
+ << endl;
+ }
+ defaultValue = "default" + name;
+
+ } else if ( type == "Color" && !defaultValue.isEmpty() ) {
+ QRegExp colorRe("\\d+,\\s*\\d+,\\s*\\d+");
+ if (colorRe.exactMatch(defaultValue))
+ {
+ defaultValue = "QColor( " + defaultValue + " )";
+ }
+ else
+ {
+ defaultValue = "QColor( \"" + defaultValue + "\" )";
+ }
+
+ } else if ( type == "Enum" ) {
+ if ( !globalEnums ) {
+ QValueList<CfgEntry::Choice>::ConstIterator it;
+ for( it = choices.begin(); it != choices.end(); ++it ) {
+ if ( (*it).name == defaultValue ) {
+ defaultValue.prepend( enumName(name) + "::");
+ break;
+ }
+ }
+ }
+
+ } else if ( type == "IntList" ) {
+ QTextStream cpp( &code, IO_WriteOnly | IO_Append );
+ if (!code.isEmpty())
+ cpp << endl;
+
+ cpp << " QValueList<int> default" << name << ";" << endl;
+ QStringList defaults = QStringList::split( ",", defaultValue );
+ QStringList::ConstIterator it;
+ for( it = defaults.begin(); it != defaults.end(); ++it ) {
+ cpp << " default" << name << ".append( " << *it << " );"
+ << endl;
+ }
+ defaultValue = "default" + name;
+ }
+}
+
+
+CfgEntry *parseEntry( const QString &group, const QDomElement &element )
+{
+ bool defaultCode = false;
+ QString type = element.attribute( "type" );
+ QString name = element.attribute( "name" );
+ QString key = element.attribute( "key" );
+ QString hidden = element.attribute( "hidden" );
+ QString label;
+ QString whatsThis;
+ QString defaultValue;
+ QString code;
+ QString param;
+ QString paramName;
+ QString paramType;
+ QValueList<CfgEntry::Choice> choices;
+ QStringList paramValues;
+ QStringList paramDefaultValues;
+ QString minValue;
+ QString maxValue;
+ int paramMax = 0;
+
+ QDomNode n;
+ for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+ QString tag = e.tagName();
+ if ( tag == "label" ) label = e.text();
+ else if ( tag == "whatsthis" ) whatsThis = e.text();
+ else if ( tag == "min" ) minValue = e.text();
+ else if ( tag == "max" ) maxValue = e.text();
+ else if ( tag == "code" ) code = e.text();
+ else if ( tag == "parameter" )
+ {
+ param = e.attribute( "name" );
+ paramType = e.attribute( "type" );
+ if ( param.isEmpty() ) {
+ kdError() << "Parameter must have a name: " << dumpNode(e) << endl;
+ return 0;
+ }
+ if ( paramType.isEmpty() ) {
+ kdError() << "Parameter must have a type: " << dumpNode(e) << endl;
+ return 0;
+ }
+ if ((paramType == "Int") || (paramType == "UInt"))
+ {
+ bool ok;
+ paramMax = e.attribute("max").toInt(&ok);
+ if (!ok)
+ {
+ kdError() << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl;
+ return 0;
+ }
+ }
+ else if (paramType == "Enum")
+ {
+ QDomNode n2;
+ for ( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
+ QDomElement e2 = n2.toElement();
+ if (e2.tagName() == "values")
+ {
+ QDomNode n3;
+ for ( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
+ QDomElement e3 = n3.toElement();
+ if (e3.tagName() == "value")
+ {
+ paramValues.append( e3.text() );
+ }
+ }
+ break;
+ }
+ }
+ if (paramValues.isEmpty())
+ {
+ kdError() << "No values specified for parameter '" << param << "'." << endl;
+ return 0;
+ }
+ paramMax = paramValues.count()-1;
+ }
+ else
+ {
+ kdError() << "Parameter '" << param << "' has type " << paramType << " but must be of type int, uint or Enum." << endl;
+ return 0;
+ }
+ }
+ else if ( tag == "default" )
+ {
+ if (e.attribute("param").isEmpty())
+ {
+ defaultValue = e.text();
+ if (e.attribute( "code" ) == "true")
+ defaultCode = true;
+ }
+ }
+ else if ( tag == "choices" ) {
+ QDomNode n2;
+ for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
+ QDomElement e2 = n2.toElement();
+ if ( e2.tagName() == "choice" ) {
+ QDomNode n3;
+ CfgEntry::Choice choice;
+ choice.name = e2.attribute( "name" );
+ if ( choice.name.isEmpty() ) {
+ kdError() << "Tag <choice> requires attribute 'name'." << endl;
+ }
+ for( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
+ QDomElement e3 = n3.toElement();
+ if ( e3.tagName() == "label" ) choice.label = e3.text();
+ if ( e3.tagName() == "whatsthis" ) choice.whatsThis = e3.text();
+ }
+ choices.append( choice );
+ }
+ }
+ }
+ }
+
+ bool nameIsEmpty = name.isEmpty();
+ if ( nameIsEmpty && key.isEmpty() ) {
+ kdError() << "Entry must have a name or a key: " << dumpNode(element) << endl;
+ return 0;
+ }
+
+ if ( key.isEmpty() ) {
+ key = name;
+ }
+
+ if ( nameIsEmpty ) {
+ name = key;
+ name.replace( " ", QString::null );
+ } else if ( name.contains( ' ' ) ) {
+ kdWarning()<<"Entry '"<<name<<"' contains spaces! <name> elements can't contain speces!"<<endl;
+ name.remove( ' ' );
+ }
+
+ if (name.contains("$("))
+ {
+ if (param.isEmpty())
+ {
+ kdError() << "Name may not be parameterized: " << name << endl;
+ return 0;
+ }
+ }
+ else
+ {
+ if (!param.isEmpty())
+ {
+ kdError() << "Name must contain '$(" << param << ")': " << name << endl;
+ return 0;
+ }
+ }
+
+ if ( label.isEmpty() ) {
+ label = key;
+ }
+
+ if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad
+
+ if (!param.isEmpty())
+ {
+ // Adjust name
+ paramName = name;
+ name.replace("$("+param+")", QString::null);
+ // Lookup defaults for indexed entries
+ for(int i = 0; i <= paramMax; i++)
+ {
+ paramDefaultValues.append(QString::null);
+ }
+
+ QDomNode n;
+ for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+ QString tag = e.tagName();
+ if ( tag == "default" )
+ {
+ QString index = e.attribute("param");
+ if (index.isEmpty())
+ continue;
+
+ bool ok;
+ int i = index.toInt(&ok);
+ if (!ok)
+ {
+ i = paramValues.findIndex(index);
+ if (i == -1)
+ {
+ kdError() << "Index '" << index << "' for default value is unknown." << endl;
+ return 0;
+ }
+ }
+
+ if ((i < 0) || (i > paramMax))
+ {
+ kdError() << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl;
+ return 0;
+ }
+
+ QString tmpDefaultValue = e.text();
+
+ if (e.attribute( "code" ) != "true")
+ preProcessDefault(tmpDefaultValue, name, type, choices, code);
+
+ paramDefaultValues[i] = tmpDefaultValue;
+ }
+ }
+ }
+
+ if (!validNameRegexp->exactMatch(name))
+ {
+ if (nameIsEmpty)
+ kdError() << "The key '" << key << "' can not be used as name for the entry because "
+ "it is not a valid name. You need to specify a valid name for this entry." << endl;
+ else
+ kdError() << "The name '" << name << "' is not a valid name for an entry." << endl;
+ return 0;
+ }
+
+ if (allNames.contains(name))
+ {
+ if (nameIsEmpty)
+ kdError() << "The key '" << key << "' can not be used as name for the entry because "
+ "it does not result in a unique name. You need to specify a unique name for this entry." << endl;
+ else
+ kdError() << "The name '" << name << "' is not unique." << endl;
+ return 0;
+ }
+ allNames.append(name);
+
+ if (!defaultCode)
+ {
+ preProcessDefault(defaultValue, name, type, choices, code);
+ }
+
+ CfgEntry *result = new CfgEntry( group, type, key, name, label, whatsThis,
+ code, defaultValue, choices,
+ hidden == "true" );
+ if (!param.isEmpty())
+ {
+ result->setParam(param);
+ result->setParamName(paramName);
+ result->setParamType(paramType);
+ result->setParamValues(paramValues);
+ result->setParamDefaultValues(paramDefaultValues);
+ result->setParamMax(paramMax);
+ }
+ result->setMinValue(minValue);
+ result->setMaxValue(maxValue);
+
+ return result;
+}
+
+/**
+ Return parameter declaration for given type.
+*/
+QString param( const QString &type )
+{
+ if ( type == "String" ) return "const QString &";
+ else if ( type == "StringList" ) return "const QStringList &";
+ else if ( type == "Font" ) return "const QFont &";
+ else if ( type == "Rect" ) return "const QRect &";
+ else if ( type == "Size" ) return "const QSize &";
+ else if ( type == "Color" ) return "const QColor &";
+ else if ( type == "Point" ) return "const QPoint &";
+ else if ( type == "Int" ) return "int";
+ else if ( type == "UInt" ) return "uint";
+ else if ( type == "Bool" ) return "bool";
+ else if ( type == "Double" ) return "double";
+ else if ( type == "DateTime" ) return "const QDateTime &";
+ else if ( type == "Int64" ) return "Q_INT64";
+ else if ( type == "UInt64" ) return "Q_UINT64";
+ else if ( type == "IntList" ) return "const QValueList<int> &";
+ else if ( type == "Enum" ) return "int";
+ else if ( type == "Path" ) return "const QString &";
+ else if ( type == "PathList" ) return "const QStringList &";
+ else if ( type == "Password" ) return "const QString &";
+ else {
+ kdError() <<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
+ return "QString"; //For now, but an assert would be better
+ }
+}
+
+/**
+ Actual C++ storage type for given type.
+*/
+QString cppType( const QString &type )
+{
+ if ( type == "String" ) return "QString";
+ else if ( type == "StringList" ) return "QStringList";
+ else if ( type == "Font" ) return "QFont";
+ else if ( type == "Rect" ) return "QRect";
+ else if ( type == "Size" ) return "QSize";
+ else if ( type == "Color" ) return "QColor";
+ else if ( type == "Point" ) return "QPoint";
+ else if ( type == "Int" ) return "int";
+ else if ( type == "UInt" ) return "uint";
+ else if ( type == "Bool" ) return "bool";
+ else if ( type == "Double" ) return "double";
+ else if ( type == "DateTime" ) return "QDateTime";
+ else if ( type == "Int64" ) return "Q_INT64";
+ else if ( type == "UInt64" ) return "Q_UINT64";
+ else if ( type == "IntList" ) return "QValueList<int>";
+ else if ( type == "Enum" ) return "int";
+ else if ( type == "Path" ) return "QString";
+ else if ( type == "PathList" ) return "QStringList";
+ else if ( type == "Password" ) return "QString";
+ else {
+ kdError()<<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
+ return "QString"; //For now, but an assert would be better
+ }
+}
+
+QString defaultValue( const QString &type )
+{
+ if ( type == "String" ) return "\"\""; // Use empty string, not null string!
+ else if ( type == "StringList" ) return "QStringList()";
+ else if ( type == "Font" ) return "KGlobalSettings::generalFont()";
+ else if ( type == "Rect" ) return "QRect()";
+ else if ( type == "Size" ) return "QSize()";
+ else if ( type == "Color" ) return "QColor(128, 128, 128)";
+ else if ( type == "Point" ) return "QPoint()";
+ else if ( type == "Int" ) return "0";
+ else if ( type == "UInt" ) return "0";
+ else if ( type == "Bool" ) return "false";
+ else if ( type == "Double" ) return "0.0";
+ else if ( type == "DateTime" ) return "QDateTime()";
+ else if ( type == "Int64" ) return "0";
+ else if ( type == "UInt64" ) return "0";
+ else if ( type == "IntList" ) return "QValueList<int>()";
+ else if ( type == "Enum" ) return "0";
+ else if ( type == "Path" ) return "\"\""; // Use empty string, not null string!
+ else if ( type == "PathList" ) return "QStringList()";
+ else if ( type == "Password" ) return "\"\""; // Use empty string, not null string!
+ else {
+ kdWarning()<<"Error, kconfig_compiler doesn't support the \""<< type <<"\" type!"<<endl;
+ return "QString"; //For now, but an assert would be better
+ }
+}
+
+QString itemType( const QString &type )
+{
+ QString t;
+
+ t = type;
+ t.replace( 0, 1, t.left( 1 ).upper() );
+
+ return t;
+}
+
+static QString itemDeclaration(const CfgEntry *e)
+{
+ if (itemAccessors)
+ return QString::null;
+
+ QString fCap = e->name();
+ fCap[0] = fCap[0].upper();
+ return " KConfigSkeleton::Item"+itemType( e->type() ) +
+ " *item" + fCap +
+ ( (!e->param().isEmpty())?(QString("[%1]").arg(e->paramMax()+1)) : QString::null) +
+ ";\n";
+}
+
+// returns the name of an item variable
+// use itemPath to know the full path
+// like using d-> in case of dpointer
+static QString itemVar(const CfgEntry *e)
+{
+ QString result;
+ if (itemAccessors)
+ {
+ if ( !dpointer )
+ {
+ result = "m" + e->name() + "Item";
+ result[1] = result[1].upper();
+ }
+ else
+ {
+ result = e->name() + "Item";
+ result[0] = result[0].lower();
+ }
+ }
+ else
+ {
+ result = "item" + e->name();
+ result[4] = result[4].upper();
+ }
+ return result;
+}
+
+static QString itemPath(const CfgEntry *e)
+{
+ QString result;
+ if ( dpointer ) {
+ result = "d->"+itemVar(e);
+ }
+ else {
+ result = itemVar(e);
+ }
+ return result;
+}
+
+QString newItem( const QString &type, const QString &name, const QString &key,
+ const QString &defaultValue, const QString &param = QString::null)
+{
+ QString t = "new KConfigSkeleton::Item" + itemType( type ) +
+ "( currentGroup(), " + key + ", " + varPath( name ) + param;
+ if ( type == "Enum" ) t += ", values" + name;
+ if ( !defaultValue.isEmpty() ) {
+ t += ", ";
+ if ( type == "String" ) t += defaultValue;
+ else t+= defaultValue;
+ }
+ t += " );";
+
+ return t;
+}
+
+QString paramString(const QString &s, const CfgEntry *e, int i)
+{
+ QString result = s;
+ QString needle = "$("+e->param()+")";
+ if (result.contains(needle))
+ {
+ QString tmp;
+ if (e->paramType() == "Enum")
+ {
+ tmp = e->paramValues()[i];
+ }
+ else
+ {
+ tmp = QString::number(i);
+ }
+
+ result.replace(needle, tmp);
+ }
+ return result;
+}
+
+QString paramString(const QString &group, const QValueList<Param> &parameters)
+{
+ QString paramString = group;
+ QString arguments;
+ int i = 1;
+ for (QValueList<Param>::ConstIterator it = parameters.begin();
+ it != parameters.end(); ++it)
+ {
+ if (paramString.contains("$("+(*it).name+")"))
+ {
+ QString tmp;
+ tmp.sprintf("%%%d", i++);
+ paramString.replace("$("+(*it).name+")", tmp);
+ arguments += ".arg( mParam"+(*it).name+" )";
+ }
+ }
+ if (arguments.isEmpty())
+ return "QString::fromLatin1( \""+group+"\" )";
+
+ return "QString::fromLatin1( \""+paramString+"\" )"+arguments;
+}
+
+/* int i is the value of the parameter */
+QString userTextsFunctions( CfgEntry *e, QString itemVarStr=QString::null, QString i=QString::null )
+{
+ QString txt;
+ if (itemVarStr.isNull()) itemVarStr=itemPath(e);
+ if ( !e->label().isEmpty() ) {
+ txt += " " + itemVarStr + "->setLabel( i18n(";
+ if ( !e->param().isEmpty() )
+ txt += quoteString(e->label().replace("$("+e->param()+")", i));
+ else
+ txt+= quoteString(e->label());
+ txt+= ") );\n";
+ }
+ if ( !e->whatsThis().isEmpty() ) {
+ txt += " " + itemVarStr + "->setWhatsThis( i18n(";
+ if ( !e->param().isEmpty() )
+ txt += quoteString(e->whatsThis().replace("$("+e->param()+")", i));
+ else
+ txt+= quoteString(e->whatsThis());
+ txt+=") );\n";
+ }
+ return txt;
+}
+
+// returns the member accesor implementation
+// which should go in the h file if inline
+// or the cpp file if not inline
+QString memberAccessorBody( CfgEntry *e )
+{
+ QString result;
+ QTextStream out(&result, IO_WriteOnly);
+ QString n = e->name();
+ QString t = e->type();
+
+ out << "return " << This << varPath(n);
+ if (!e->param().isEmpty()) out << "[i]";
+ out << ";" << endl;
+
+ return result;
+}
+
+// returns the member mutator implementation
+// which should go in the h file if inline
+// or the cpp file if not inline
+QString memberMutatorBody( CfgEntry *e )
+{
+ QString result;
+ QTextStream out(&result, IO_WriteOnly);
+ QString n = e->name();
+ QString t = e->type();
+
+ if (!e->minValue().isEmpty())
+ {
+ out << "if (v < " << e->minValue() << ")" << endl;
+ out << "{" << endl;
+ out << " kdDebug() << \"" << setFunction(n);
+ out << ": value \" << v << \" is less than the minimum value of ";
+ out << e->minValue()<< "\" << endl;" << endl;
+ out << " v = " << e->minValue() << ";" << endl;
+ out << "}" << endl;
+ }
+
+ if (!e->maxValue().isEmpty())
+ {
+ out << endl << "if (v > " << e->maxValue() << ")" << endl;
+ out << "{" << endl;
+ out << " kdDebug() << \"" << setFunction(n);
+ out << ": value \" << v << \" is greater than the maximum value of ";
+ out << e->maxValue()<< "\" << endl;" << endl;
+ out << " v = " << e->maxValue() << ";" << endl;
+ out << "}" << endl << endl;
+ }
+
+ out << "if (!" << This << "isImmutable( QString::fromLatin1( \"";
+ if (!e->param().isEmpty())
+ {
+ out << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( ";
+ if ( e->paramType() == "Enum" ) {
+ out << "QString::fromLatin1( ";
+
+ if (globalEnums)
+ out << enumName(e->param()) << "ToString[i]";
+ else
+ out << enumName(e->param()) << "::enumToString[i]";
+
+ out << " )";
+ }
+ else
+ {
+ out << "i";
+ }
+ out << " )";
+ }
+ else
+ {
+ out << n << "\" )";
+ }
+ out << " ))" << endl;
+ out << " " << This << varPath(n);
+ if (!e->param().isEmpty())
+ out << "[i]";
+ out << " = v;" << endl;
+
+ return result;
+}
+
+// returns the item accesor implementation
+// which should go in the h file if inline
+// or the cpp file if not inline
+QString itemAccessorBody( CfgEntry *e )
+{
+ QString result;
+ QTextStream out(&result, IO_WriteOnly);
+
+ out << "return " << itemPath(e);
+ if (!e->param().isEmpty()) out << "[i]";
+ out << ";" << endl;
+
+ return result;
+}
+
+//indents text adding X spaces per line
+QString indent(QString text, int spaces)
+{
+ QString result;
+ QTextStream out(&result, IO_WriteOnly);
+ QTextStream in(&text, IO_ReadOnly);
+ QString currLine;
+ while ( !in.atEnd() )
+ {
+ currLine = in.readLine();
+ if (!currLine.isEmpty())
+ for (int i=0; i < spaces; i++)
+ out << " ";
+ out << currLine << endl;
+ }
+ return result;
+}
+
+
+int main( int argc, char **argv )
+{
+ KAboutData aboutData( "kconfig_compiler", I18N_NOOP("KDE .kcfg compiler"), "0.3",
+ I18N_NOOP("KConfig Compiler") , KAboutData::License_LGPL );
+ aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
+ aboutData.addAuthor( "Waldo Bastian", 0, "bastian@kde.org" );
+ aboutData.addAuthor( "Zack Rusin", 0, "zack@kde.org" );
+ aboutData.addCredit( "Reinhold Kainhofer", "Fix for parametrized entries",
+ "reinhold@kainhofer.com", "http://reinhold.kainhofer.com" );
+ aboutData.addCredit( "Duncan Mac-Vicar P.", "dpointer support",
+ "duncan@kde.org", "http://www.mac-vicar.com/~duncan" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KInstance app( &aboutData );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if ( args->count() < 2 ) {
+ kdError() << "Too few arguments." << endl;
+ return 1;
+ }
+ if ( args->count() > 2 ) {
+ kdError() << "Too many arguments." << endl;
+ return 1;
+ }
+
+ validNameRegexp = new QRegExp("[a-zA-Z_][a-zA-Z0-9_]*");
+
+ QString baseDir = QFile::decodeName(args->getOption("directory"));
+ if (!baseDir.endsWith("/"))
+ baseDir.append("/");
+
+ QString inputFilename = args->url( 0 ).path();
+ QString codegenFilename = args->url( 1 ).path();
+
+ if (!codegenFilename.endsWith(".kcfgc"))
+ {
+ kdError() << "Codegen options file must have extension .kcfgc" << endl;
+ return 1;
+ }
+ QString baseName = args->url( 1 ).fileName();
+ baseName = baseName.left(baseName.length() - 6);
+
+ KSimpleConfig codegenConfig( codegenFilename, true );
+
+ QString nameSpace = codegenConfig.readEntry("NameSpace");
+ QString className = codegenConfig.readEntry("ClassName");
+ QString inherits = codegenConfig.readEntry("Inherits");
+ QString visibility = codegenConfig.readEntry("Visibility");
+ if (!visibility.isEmpty()) visibility+=" ";
+ bool singleton = codegenConfig.readBoolEntry("Singleton", false);
+ bool staticAccessors = singleton;
+ //bool useDPointer = codegenConfig.readBoolEntry("DPointer", false);
+ bool customAddons = codegenConfig.readBoolEntry("CustomAdditions");
+ QString memberVariables = codegenConfig.readEntry("MemberVariables");
+ QStringList headerIncludes = codegenConfig.readListEntry("IncludeFiles");
+ QStringList mutators = codegenConfig.readListEntry("Mutators");
+ bool allMutators = false;
+ if ((mutators.count() == 1) && (mutators[0].lower() == "true"))
+ allMutators = true;
+ itemAccessors = codegenConfig.readBoolEntry( "ItemAccessors", false );
+ bool setUserTexts = codegenConfig.readBoolEntry( "SetUserTexts", false );
+
+ globalEnums = codegenConfig.readBoolEntry( "GlobalEnums", false );
+
+ dpointer = (memberVariables == "dpointer");
+
+ QFile input( inputFilename );
+
+ QDomDocument doc;
+ QString errorMsg;
+ int errorRow;
+ int errorCol;
+ if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
+ kdError() << "Unable to load document." << endl;
+ kdError() << "Parse error in " << args->url( 0 ).fileName() << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
+ return 1;
+ }
+
+ QDomElement cfgElement = doc.documentElement();
+
+ if ( cfgElement.isNull() ) {
+ kdError() << "No document in kcfg file" << endl;
+ return 1;
+ }
+
+ QString cfgFileName;
+ bool cfgFileNameArg = false;
+ QValueList<Param> parameters;
+ QStringList includes;
+
+ QPtrList<CfgEntry> entries;
+ entries.setAutoDelete( true );
+
+ QDomNode n;
+ for ( n = cfgElement.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+
+ QString tag = e.tagName();
+
+ if ( tag == "include" ) {
+ QString includeFile = e.text();
+ if (!includeFile.isEmpty())
+ includes.append(includeFile);
+
+ } else if ( tag == "kcfgfile" ) {
+ cfgFileName = e.attribute( "name" );
+ cfgFileNameArg = e.attribute( "arg" ).lower() == "true";
+ QDomNode n2;
+ for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
+ QDomElement e2 = n2.toElement();
+ if ( e2.tagName() == "parameter" ) {
+ Param p;
+ p.name = e2.attribute( "name" );
+ p.type = e2.attribute( "type" );
+ if (p.type.isEmpty())
+ p.type = "String";
+ parameters.append( p );
+ }
+ }
+
+ } else if ( tag == "group" ) {
+ QString group = e.attribute( "name" );
+ if ( group.isEmpty() ) {
+ kdError() << "Group without name" << endl;
+ return 1;
+ }
+ QDomNode n2;
+ for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
+ QDomElement e2 = n2.toElement();
+ if ( e2.tagName() != "entry" ) continue;
+ CfgEntry *entry = parseEntry( group, e2 );
+ if ( entry ) entries.append( entry );
+ else {
+ kdError() << "Can't parse entry." << endl;
+ return 1;
+ }
+ }
+ }
+ }
+
+ if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
+
+ if ( className.isEmpty() ) {
+ kdError() << "Class name missing" << endl;
+ return 1;
+ }
+
+ if ( singleton && !parameters.isEmpty() ) {
+ kdError() << "Singleton class can not have parameters" << endl;
+ return 1;
+ }
+
+ if ( !cfgFileName.isEmpty() && cfgFileNameArg)
+ {
+ kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl;
+ return 1;
+ }
+
+ if ( entries.isEmpty() ) {
+ kdWarning() << "No entries." << endl;
+ }
+
+#if 0
+ CfgEntry *cfg;
+ for( cfg = entries.first(); cfg; cfg = entries.next() ) {
+ cfg->dump();
+ }
+#endif
+
+ QString headerFileName = baseName + ".h";
+ QString implementationFileName = baseName + ".cpp";
+ QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values
+
+ QFile header( baseDir + headerFileName );
+ if ( !header.open( IO_WriteOnly ) ) {
+ kdError() << "Can't open '" << headerFileName << "' for writing." << endl;
+ return 1;
+ }
+
+ QTextStream h( &header );
+
+ h << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
+ h << "// All changes you do to this file will be lost." << endl;
+
+ h << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
+ << className.upper() << "_H" << endl;
+ h << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
+ << className.upper() << "_H" << endl << endl;
+
+ // Includes
+ QStringList::ConstIterator it;
+ for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) {
+ h << "#include <" << *it << ">" << endl;
+ }
+
+ if ( headerIncludes.count() > 0 ) h << endl;
+
+ if ( !singleton && cfgFileNameArg && parameters.isEmpty() )
+ h << "#include <kglobal.h>" << endl;
+
+ h << "#include <kconfigskeleton.h>" << endl;
+ h << "#include <kdebug.h>" << endl << endl;
+
+ // Includes
+ for( it = includes.begin(); it != includes.end(); ++it ) {
+ h << "#include <" << *it << ">" << endl;
+ }
+
+
+ if ( !nameSpace.isEmpty() )
+ h << "namespace " << nameSpace << " {" << endl << endl;
+
+ // Private class declaration
+ if ( dpointer )
+ h << "class " << className << "Private;" << endl << endl;
+
+ // Class declaration header
+ h << "class " << visibility << className << " : public " << inherits << endl;
+ h << "{" << endl;
+ h << " public:" << endl;
+
+ // enums
+ CfgEntry *e;
+ for( e = entries.first(); e; e = entries.next() ) {
+ QValueList<CfgEntry::Choice> choices = e->choices();
+ if ( !choices.isEmpty() ) {
+ QStringList values;
+ QValueList<CfgEntry::Choice>::ConstIterator itChoice;
+ for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) {
+ values.append( (*itChoice).name );
+ }
+ if ( globalEnums ) {
+ h << " enum { " << values.join( ", " ) << " };" << endl;
+ } else {
+ h << " class " << enumName(e->name()) << endl;
+ h << " {" << endl;
+ h << " public:" << endl;
+ h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl;
+ h << " };" << endl;
+ }
+ }
+ QStringList values = e->paramValues();
+ if ( !values.isEmpty() ) {
+ if ( globalEnums ) {
+ h << " enum { " << values.join( ", " ) << " };" << endl;
+ h << " static const char* const " << enumName(e->param()) << "ToString[];" << endl;
+ cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "ToString[] = " +
+ "{ \"" + values.join( "\", \"" ) + "\" };\n";
+ } else {
+ h << " class " << enumName(e->param()) << endl;
+ h << " {" << endl;
+ h << " public:" << endl;
+ h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl;
+ h << " static const char* const enumToString[];" << endl;
+ h << " };" << endl;
+ cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "::enumToString[] = " +
+ "{ \"" + values.join( "\", \"" ) + "\" };\n";
+ }
+ }
+ }
+
+ h << endl;
+
+ // Constructor or singleton accessor
+ if ( !singleton ) {
+ h << " " << className << "(";
+ if (cfgFileNameArg)
+ h << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " = KGlobal::sharedConfig()" : ", ");
+ for (QValueList<Param>::ConstIterator it = parameters.begin();
+ it != parameters.end(); ++it)
+ {
+ if (it != parameters.begin())
+ h << ",";
+ h << " " << param((*it).type) << " " << (*it).name;
+ }
+ h << " );" << endl;
+ } else {
+ h << " static " << className << " *self();" << endl;
+ if (cfgFileNameArg)
+ h << " static void instance(const char * cfgfilename);" << endl;
+ }
+
+ // Destructor
+ h << " ~" << className << "();" << endl << endl;
+
+ // global variables
+ if (staticAccessors)
+ This = "self()->";
+ else
+ Const = " const";
+
+ for( e = entries.first(); e; e = entries.next() ) {
+ QString n = e->name();
+ QString t = e->type();
+
+ // Manipulator
+ if (allMutators || mutators.contains(n))
+ {
+ h << " /**" << endl;
+ h << " Set " << e->label() << endl;
+ h << " */" << endl;
+ if (staticAccessors)
+ h << " static" << endl;
+ h << " void " << setFunction(n) << "( ";
+ if (!e->param().isEmpty())
+ h << cppType(e->paramType()) << " i, ";
+ h << param( t ) << " v )";
+ // function body inline only if not using dpointer
+ // for BC mode
+ if ( !dpointer )
+ {
+ h << endl << " {" << endl;
+ h << indent(memberMutatorBody(e), 6 );
+ h << " }" << endl;
+ }
+ else
+ {
+ h << ";" << endl;
+ }
+ }
+ h << endl;
+ // Accessor
+ h << " /**" << endl;
+ h << " Get " << e->label() << endl;
+ h << " */" << endl;
+ if (staticAccessors)
+ h << " static" << endl;
+ h << " " << cppType(t) << " " << getFunction(n) << "(";
+ if (!e->param().isEmpty())
+ h << " " << cppType(e->paramType()) <<" i ";
+ h << ")" << Const;
+ // function body inline only if not using dpointer
+ // for BC mode
+ if ( !dpointer )
+ {
+ h << endl << " {" << endl;
+ h << indent(memberAccessorBody(e), 6 );
+ h << " }" << endl;
+ }
+ else
+ {
+ h << ";" << endl;
+ }
+
+ // Item accessor
+ if ( itemAccessors ) {
+ h << endl;
+ h << " /**" << endl;
+ h << " Get Item object corresponding to " << n << "()"
+ << endl;
+ h << " */" << endl;
+ h << " Item" << itemType( e->type() ) << " *"
+ << getFunction( n ) << "Item(";
+ if (!e->param().isEmpty()) {
+ h << " " << cppType(e->paramType()) << " i ";
+ }
+ h << ")";
+ if (! dpointer )
+ {
+ h << endl << " {" << endl;
+ h << indent( itemAccessorBody(e), 6);
+ h << " }" << endl;
+ }
+ else
+ {
+ h << ";" << endl;
+ }
+ }
+
+ h << endl;
+ }
+
+ // Static writeConfig method for singleton
+ if ( singleton ) {
+ h << " static" << endl;
+ h << " void writeConfig()" << endl;
+ h << " {" << endl;
+ h << " static_cast<KConfigSkeleton*>(self())->writeConfig();" << endl;
+ h << " }" << endl;
+ }
+
+ h << " protected:" << endl;
+
+ // Private constructor for singleton
+ if ( singleton ) {
+ h << " " << className << "(";
+ if ( cfgFileNameArg )
+ h << "const char *arg";
+ h << ");" << endl;
+ h << " static " << className << " *mSelf;" << endl << endl;
+ }
+
+ // Member variables
+ if ( !memberVariables.isEmpty() && memberVariables != "private" && memberVariables != "dpointer") {
+ h << " " << memberVariables << ":" << endl;
+ }
+
+ // Class Parameters
+ for (QValueList<Param>::ConstIterator it = parameters.begin();
+ it != parameters.end(); ++it)
+ {
+ h << " " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl;
+ }
+
+ if ( memberVariables != "dpointer" )
+ {
+ QString group;
+ for( e = entries.first(); e; e = entries.next() ) {
+ if ( e->group() != group ) {
+ group = e->group();
+ h << endl;
+ h << " // " << group << endl;
+ }
+ h << " " << cppType(e->type()) << " " << varName(e->name());
+ if (!e->param().isEmpty())
+ {
+ h << QString("[%1]").arg(e->paramMax()+1);
+ }
+ h << ";" << endl;
+ }
+
+ h << endl << " private:" << endl;
+ if ( itemAccessors ) {
+ for( e = entries.first(); e; e = entries.next() ) {
+ h << " Item" << itemType( e->type() ) << " *" << itemVar( e );
+ if (!e->param().isEmpty() ) h << QString("[%1]").arg( e->paramMax()+1 );
+ h << ";" << endl;
+ }
+ }
+
+ }
+ else
+ {
+ // use a private class for both member variables and items
+ h << " private:" << endl;
+ h << " " + className + "Private *d;" << endl;
+ }
+
+ if (customAddons)
+ {
+ h << " // Include custom additions" << endl;
+ h << " #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
+ }
+
+ h << "};" << endl << endl;
+
+ if ( !nameSpace.isEmpty() ) h << "}" << endl << endl;
+
+ h << "#endif" << endl << endl;
+
+
+ header.close();
+
+ QFile implementation( baseDir + implementationFileName );
+ if ( !implementation.open( IO_WriteOnly ) ) {
+ kdError() << "Can't open '" << implementationFileName << "' for writing."
+ << endl;
+ return 1;
+ }
+
+ QTextStream cpp( &implementation );
+
+
+ cpp << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
+ cpp << "// All changes you do to this file will be lost." << endl << endl;
+
+ cpp << "#include \"" << headerFileName << "\"" << endl << endl;
+
+ if ( setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
+
+ // Header required by singleton implementation
+ if ( singleton )
+ cpp << "#include <kstaticdeleter.h>" << endl << endl;
+ if ( singleton && cfgFileNameArg )
+ cpp << "#include <kdebug.h>" << endl << endl;
+
+ if ( !nameSpace.isEmpty() )
+ cpp << "using namespace " << nameSpace << ";" << endl << endl;
+
+ QString group;
+
+ // private class implementation
+ if ( dpointer )
+ {
+ cpp << "class " << className << "Private" << endl;
+ cpp << "{" << endl;
+ cpp << " public:" << endl;
+ for( e = entries.first(); e; e = entries.next() ) {
+ if ( e->group() != group ) {
+ group = e->group();
+ cpp << endl;
+ cpp << " // " << group << endl;
+ }
+ cpp << " " << cppType(e->type()) << " " << varName(e->name());
+ if (!e->param().isEmpty())
+ {
+ cpp << QString("[%1]").arg(e->paramMax()+1);
+ }
+ cpp << ";" << endl;
+ }
+ cpp << endl << " // items" << endl;
+ for( e = entries.first(); e; e = entries.next() ) {
+ cpp << " KConfigSkeleton::Item" << itemType( e->type() ) << " *" << itemVar( e );
+ if (!e->param().isEmpty() ) cpp << QString("[%1]").arg( e->paramMax()+1 );
+ cpp << ";" << endl;
+ }
+
+ cpp << "};" << endl << endl;
+ }
+
+ // Singleton implementation
+ if ( singleton ) {
+ cpp << className << " *" << className << "::mSelf = 0;" << endl;
+ cpp << "static KStaticDeleter<" << className << "> static" << className << "Deleter;" << endl << endl;
+
+ cpp << className << " *" << className << "::self()" << endl;
+ cpp << "{" << endl;
+ if ( cfgFileNameArg ) {
+ cpp << " if (!mSelf)" << endl;
+ cpp << " kdFatal() << \"you need to call " << className << "::instance before using\" << endl;" << endl;
+ } else {
+ cpp << " if ( !mSelf ) {" << endl;
+ cpp << " static" << className << "Deleter.setObject( mSelf, new " << className << "() );" << endl;
+ cpp << " mSelf->readConfig();" << endl;
+ cpp << " }" << endl << endl;
+ }
+ cpp << " return mSelf;" << endl;
+ cpp << "}" << endl << endl;
+
+ if ( cfgFileNameArg ) {
+ cpp << "void " << className << "::instance(const char *cfgfilename)" << endl;
+ cpp << "{" << endl;
+ cpp << " if (mSelf) {" << endl;
+ cpp << " kdError() << \"" << className << "::instance called after the first use - ignoring\" << endl;" << endl;
+ cpp << " return;" << endl;
+ cpp << " }" << endl;
+ cpp << " static" << className << "Deleter.setObject( mSelf, new " << className << "(cfgfilename) );" << endl;
+ cpp << " mSelf->readConfig();" << endl;
+ cpp << "}" << endl << endl;
+ }
+ }
+
+ if ( !cppPreamble.isEmpty() )
+ cpp << cppPreamble << endl;
+
+ // Constructor
+ cpp << className << "::" << className << "( ";
+ if ( cfgFileNameArg ) {
+ if ( !singleton )
+ cpp << " KSharedConfig::Ptr config";
+ else
+ cpp << " const char *config";
+ cpp << (parameters.isEmpty() ? " " : ", ");
+ }
+
+ for (QValueList<Param>::ConstIterator it = parameters.begin();
+ it != parameters.end(); ++it)
+ {
+ if (it != parameters.begin())
+ cpp << ",";
+ cpp << " " << param((*it).type) << " " << (*it).name;
+ }
+ cpp << " )" << endl;
+
+ cpp << " : " << inherits << "(";
+ if ( !cfgFileName.isEmpty() ) cpp << " QString::fromLatin1( \"" << cfgFileName << "\" ";
+ if ( cfgFileNameArg ) cpp << " config ";
+ if ( !cfgFileName.isEmpty() ) cpp << ") ";
+ cpp << ")" << endl;
+
+ // Store parameters
+ for (QValueList<Param>::ConstIterator it = parameters.begin();
+ it != parameters.end(); ++it)
+ {
+ cpp << " , mParam" << (*it).name << "(" << (*it).name << ")" << endl;
+ }
+
+ cpp << "{" << endl;
+
+ if (dpointer)
+ cpp << " d = new " + className + "Private;" << endl;
+ // Needed in case the singleton class is used as baseclass for
+ // another singleton.
+ if ( singleton )
+ cpp << " mSelf = this;" << endl;
+
+ group = QString::null;
+ for( e = entries.first(); e; e = entries.next() ) {
+ if ( e->group() != group ) {
+ if ( !group.isEmpty() ) cpp << endl;
+ group = e->group();
+ cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
+ }
+
+ QString key = paramString(e->key(), parameters);
+ if ( !e->code().isEmpty())
+ {
+ cpp << e->code() << endl;
+ }
+ if ( e->type() == "Enum" ) {
+ cpp << " QValueList<KConfigSkeleton::ItemEnum::Choice> values"
+ << e->name() << ";" << endl;
+ QValueList<CfgEntry::Choice> choices = e->choices();
+ QValueList<CfgEntry::Choice>::ConstIterator it;
+ for( it = choices.begin(); it != choices.end(); ++it ) {
+ cpp << " {" << endl;
+ cpp << " KConfigSkeleton::ItemEnum::Choice choice;" << endl;
+ cpp << " choice.name = QString::fromLatin1( \"" << (*it).name << "\" );" << endl;
+ if ( setUserTexts ) {
+ if ( !(*it).label.isEmpty() )
+ cpp << " choice.label = i18n(" << quoteString((*it).label) << ");" << endl;
+ if ( !(*it).whatsThis.isEmpty() )
+ cpp << " choice.whatsThis = i18n(" << quoteString((*it).whatsThis) << ");" << endl;
+ }
+ cpp << " values" << e->name() << ".append( choice );" << endl;
+ cpp << " }" << endl;
+ }
+ }
+
+ if (!dpointer)
+ cpp << itemDeclaration(e);
+
+ if (e->param().isEmpty())
+ {
+ // Normal case
+ cpp << " " << itemPath(e) << " = "
+ << newItem( e->type(), e->name(), key, e->defaultValue() ) << endl;
+
+ if ( !e->minValue().isEmpty() )
+ cpp << " " << itemPath(e) << "->setMinValue(" << e->minValue() << ");" << endl;
+ if ( !e->maxValue().isEmpty() )
+ cpp << " " << itemPath(e) << "->setMaxValue(" << e->maxValue() << ");" << endl;
+
+ if ( setUserTexts )
+ cpp << userTextsFunctions( e );
+
+ cpp << " addItem( " << itemPath(e);
+ QString quotedName = e->name();
+ addQuotes( quotedName );
+ if ( quotedName != key ) cpp << ", QString::fromLatin1( \"" << e->name() << "\" )";
+ cpp << " );" << endl;
+ }
+ else
+ {
+ // Indexed
+ for(int i = 0; i <= e->paramMax(); i++)
+ {
+ QString defaultStr;
+ QString itemVarStr(itemPath(e)+QString("[%1]").arg(i));
+
+ if ( !e->paramDefaultValue(i).isEmpty() )
+ defaultStr = e->paramDefaultValue(i);
+ else if ( !e->defaultValue().isEmpty() )
+ defaultStr = paramString(e->defaultValue(), e, i);
+ else
+ defaultStr = defaultValue( e->type() );
+
+ cpp << " " << itemVarStr << " = "
+ << newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, QString("[%1]").arg(i) )
+ << endl;
+
+ if ( setUserTexts )
+ cpp << userTextsFunctions( e, itemVarStr, e->paramName() );
+
+ // Make mutators for enum parameters work by adding them with $(..) replaced by the
+ // param name. The check for isImmutable in the set* functions doesn't have the param
+ // name available, just the corresponding enum value (int), so we need to store the
+ // param names in a separate static list!.
+ cpp << " addItem( " << itemVarStr << ", QString::fromLatin1( \"";
+ if ( e->paramType()=="Enum" )
+ cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(e->paramValues()[i] );
+ else
+ cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(i);
+ cpp << "\" ) );" << endl;
+ }
+ }
+ }
+
+ cpp << "}" << endl << endl;
+
+ if (dpointer)
+ {
+ // setters and getters go in Cpp if in dpointer mode
+ for( e = entries.first(); e; e = entries.next() )
+ {
+ QString n = e->name();
+ QString t = e->type();
+
+ // Manipulator
+ if (allMutators || mutators.contains(n))
+ {
+ cpp << "void " << setFunction(n, className) << "( ";
+ if (!e->param().isEmpty())
+ cpp << cppType(e->paramType()) << " i, ";
+ cpp << param( t ) << " v )" << endl;
+ // function body inline only if not using dpointer
+ // for BC mode
+ cpp << "{" << endl;
+ cpp << indent(memberMutatorBody(e), 6);
+ cpp << "}" << endl << endl;
+ }
+
+ // Accessor
+ cpp << cppType(t) << " " << getFunction(n, className) << "(";
+ if (!e->param().isEmpty())
+ cpp << " " << cppType(e->paramType()) <<" i ";
+ cpp << ")" << Const << endl;
+ // function body inline only if not using dpointer
+ // for BC mode
+ cpp << "{" << endl;
+ cpp << indent(memberAccessorBody(e), 2);
+ cpp << "}" << endl << endl;
+
+ // Item accessor
+ if ( itemAccessors )
+ {
+ cpp << endl;
+ cpp << "KConfigSkeleton::Item" << itemType( e->type() ) << " *"
+ << getFunction( n, className ) << "Item(";
+ if (!e->param().isEmpty()) {
+ cpp << " " << cppType(e->paramType()) << " i ";
+ }
+ cpp << ")" << endl;
+ cpp << "{" << endl;
+ cpp << indent(itemAccessorBody(e), 2);
+ cpp << "}" << endl;
+ }
+
+ cpp << endl;
+ }
+ }
+
+ // Destructor
+ cpp << className << "::~" << className << "()" << endl;
+ cpp << "{" << endl;
+ if ( singleton ) {
+ if ( dpointer )
+ cpp << " delete d;" << endl;
+ cpp << " if ( mSelf == this )" << endl;
+ cpp << " static" << className << "Deleter.setObject( mSelf, 0, false );" << endl;
+ }
+ cpp << "}" << endl << endl;
+
+ implementation.close();
+}
diff --git a/kdecore/kconfig_compiler/tests/Makefile.am b/kdecore/kconfig_compiler/tests/Makefile.am
new file mode 100644
index 000000000..cb538783c
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/Makefile.am
@@ -0,0 +1,134 @@
+AM_CPPFLAGS = -I$(top_srcdir)/kdecore -I$(top_srcdir)/kunittest $(all_includes) -DQT_NO_CAST_ASCII -DSRCDIR=\"$(srcdir)\"
+
+check_PROGRAMS = test1 test2 test3 test4 test5 test6 test7 test8 test9 test_dpointer
+
+CLEANFILES = test1.cpp test1.h \
+ test2.cpp test2.h \
+ test3.cpp test3.h \
+ test4.cpp test4.h \
+ test5.cpp test5.h \
+ test6.cpp test6.h \
+ test7.cpp test7.h \
+ test8a.cpp test8a.h test8b.cpp test8b.h \
+ test9.cpp test9.h \
+ test_dpointer.cpp test_dpointer.h \
+ md5sums
+
+test1_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test1_LDADD = $(LIB_KDECORE)
+test1_SOURCES = test1main.cpp test1.cpp
+
+test2_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test2_LDADD = $(LIB_KDECORE)
+test2_SOURCES = test2main.cpp test2.cpp
+
+test3_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test3_LDADD = $(LIB_KDECORE)
+test3_SOURCES = test3main.cpp test3.cpp
+
+test4_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test4_LDADD = $(LIB_KDECORE)
+test4_SOURCES = test4main.cpp test4.cpp
+
+test5_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test5_LDADD = $(LIB_KDECORE)
+test5_SOURCES = test5main.cpp test5.cpp
+
+test6_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test6_LDADD = $(LIB_KDECORE)
+test6_SOURCES = test6main.cpp test6.cpp
+
+test7_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test7_LDADD = $(LIB_KDECORE)
+test7_SOURCES = test7main.cpp test7.cpp
+
+test8_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test8_LDADD = $(LIB_KDECORE)
+test8_SOURCES = test8main.cpp test8a.cpp test8b.cpp
+
+test9_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test9_LDADD = $(LIB_KDECORE)
+test9_SOURCES = test9main.cpp test9.cpp
+
+test_dpointer_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+test_dpointer_LDADD = $(LIB_KDECORE)
+test_dpointer_SOURCES = test_dpointer_main.cpp test_dpointer.cpp
+
+check_LTLIBRARIES = kunittest_kconfigcompiler_test.la
+
+kunittest_kconfigcompiler_test_la_SOURCES = kconfigcompiler_test.cpp
+kunittest_kconfigcompiler_test_la_LIBADD = \
+ $(top_builddir)/kunittest/libkunittest.la
+kunittest_kconfigcompiler_test_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) \
+ $(all_libraries)
+
+
+test1main.o test1.o: test1.h
+# avoid running the below command in parallel
+test1.cpp: test1.h
+test1.cpp test1.h: $(srcdir)/test1.kcfg ../kconfig_compiler $(srcdir)/test1.kcfgc
+ ../kconfig_compiler $(srcdir)/test1.kcfg $(srcdir)/test1.kcfgc
+
+test2main.o test2.o: test2.h
+# avoid running the below command in parallel
+test2.cpp: test2.h
+test2.cpp test2.h: $(srcdir)/test2.kcfg ../kconfig_compiler $(srcdir)/test2.kcfgc
+ ../kconfig_compiler $(srcdir)/test2.kcfg $(srcdir)/test2.kcfgc
+
+test3main.o test3.o: test3.h
+# avoid running the below command in parallel
+test3.cpp: test3.h
+test3.cpp test3.h: $(srcdir)/test3.kcfg ../kconfig_compiler $(srcdir)/test3.kcfgc
+ ../kconfig_compiler $(srcdir)/test3.kcfg $(srcdir)/test3.kcfgc
+
+test4main.o test4.o: test4.h
+# avoid running the below command in parallel
+test4.cpp: test4.h
+test4.cpp test4.h: $(srcdir)/test4.kcfg ../kconfig_compiler $(srcdir)/test4.kcfgc
+ ../kconfig_compiler $(srcdir)/test4.kcfg $(srcdir)/test4.kcfgc
+
+test5main.o test5.o: test5.h
+# avoid running the below command in parallel
+test5.cpp: test5.h
+test5.cpp test5.h: $(srcdir)/test5.kcfg ../kconfig_compiler $(srcdir)/test5.kcfgc
+ ../kconfig_compiler $(srcdir)/test5.kcfg $(srcdir)/test5.kcfgc
+
+test6main.o test6.o: test6.h
+# avoid running the below command in parallel
+test6.cpp: test6.h
+test6.cpp test6.h: $(srcdir)/test6.kcfg ../kconfig_compiler $(srcdir)/test6.kcfgc
+ ../kconfig_compiler $(srcdir)/test6.kcfg $(srcdir)/test6.kcfgc
+
+test7main.o test7.o: test7.h
+# avoid running the below command in parallel
+test7.cpp: test7.h
+test7.cpp test7.h: $(srcdir)/test7.kcfg ../kconfig_compiler $(srcdir)/test7.kcfgc
+ ../kconfig_compiler $(srcdir)/test7.kcfg $(srcdir)/test7.kcfgc
+
+test8main.o test8a.o test8b.o: test8a.h test8b.h
+# avoid running the below command in parallel
+test8a.cpp: test8a.h
+test8a.cpp test8a.h: $(srcdir)/test8a.kcfg ../kconfig_compiler $(srcdir)/test8a.kcfgc
+ ../kconfig_compiler $(srcdir)/test8a.kcfg $(srcdir)/test8a.kcfgc
+test8b.cpp: test8b.h
+test8b.cpp test8b.h: $(srcdir)/test8b.kcfg ../kconfig_compiler $(srcdir)/test8b.kcfgc
+ ../kconfig_compiler $(srcdir)/test8b.kcfg $(srcdir)/test8b.kcfgc
+
+test9main.o test9.o: test9.h
+# avoid running the below command in parallel
+test9.cpp: test9.h
+test9.cpp test9.h: $(srcdir)/test9.kcfg ../kconfig_compiler $(srcdir)/test9.kcfgc
+ ../kconfig_compiler $(srcdir)/test9.kcfg $(srcdir)/test9.kcfgc
+
+test_dpointer_main.o test_dpointer.o: test_dpointer.h
+# avoid running the below command in parallel
+test_dpointer.cpp: test_dpointer.h
+test_dpointer.cpp test_dpointer.h: $(srcdir)/test_dpointer.kcfg ../kconfig_compiler $(srcdir)/test_dpointer.kcfgc
+ ../kconfig_compiler $(srcdir)/test_dpointer.kcfg $(srcdir)/test_dpointer.kcfgc
+
+md5sums:
+ $(MD5SUM) $(srcdir)/test*.ref | sed -e "s,$(srcdir)/,,; s,\.ref$$,," > md5sums
+
+md5check: test1.cpp test2.cpp test3.cpp test4.cpp test5.cpp test6.cpp test7.cpp test8a.cpp test8b.cpp test9.cpp md5sums
+ $(MD5SUM) -c md5sums
+
diff --git a/kdecore/kconfig_compiler/tests/kconfigcompiler_test.cpp b/kdecore/kconfig_compiler/tests/kconfigcompiler_test.cpp
new file mode 100644
index 000000000..31f3f5ee9
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/kconfigcompiler_test.cpp
@@ -0,0 +1,96 @@
+/*
+ Tests for KConfig Compiler
+
+ Copyright (c) 2005 by Duncan Mac-Vicar <duncan@kde.org>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <qfile.h>
+#include <qstring.h>
+#include <kdebug.h>
+#include <kunittest/module.h>
+#include "kconfigcompiler_test.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_kconfigcompiler_test, "KConfigXT")
+KUNITTEST_MODULE_REGISTER_TESTER( KConfigCompiler_Test )
+
+typedef const char * CompilerTestSet[];
+
+static CompilerTestSet testCases =
+{
+ "test1.cpp", "test1.h",
+ "test2.cpp", "test2.h",
+ "test3.cpp", "test3.h",
+ "test4.cpp", "test4.h",
+ "test5.cpp", "test5.h",
+ "test6.cpp", "test6.h",
+ "test7.cpp", "test7.h",
+ "test8a.cpp", "test8a.h",
+ "test8b.cpp", "test8b.h",
+ "test9.h", "test9.cpp",
+ "test_dpointer.cpp", "test_dpointer.h",
+ NULL
+};
+
+static CompilerTestSet willFailCases =
+{
+ // where is that QDir comming from?
+ //"test9.cpp", NULL
+ NULL
+};
+
+
+void KConfigCompiler_Test::allTests()
+{
+ testExpectedOutput();
+}
+
+void KConfigCompiler_Test::testExpectedOutput()
+{
+ uint i = 0;
+ // Known to pass test cases
+ while (testCases[ i ])
+ {
+ performCompare(QString::fromLatin1(testCases[ i ]));
+ ++i;
+ }
+
+ // broken test cases
+ i= 0;
+ while (willFailCases[ i ])
+ {
+ performCompare(QString::fromLatin1(willFailCases[ i ]), true);
+ ++i;
+ }
+}
+
+void KConfigCompiler_Test::performCompare(const QString &fileName, bool fail)
+{
+ QFile file(fileName);
+ QFile fileRef(QString::fromLatin1(SRCDIR) + QString::fromLatin1("/") + fileName + QString::fromLatin1(".ref"));
+
+ if ( file.open(IO_ReadOnly) && fileRef.open(IO_ReadOnly) )
+ {
+ QString content = file.readAll();
+ QString contentRef = fileRef.readAll();
+
+ if (!fail)
+ CHECK( content, contentRef);
+ else
+ XFAIL( content, contentRef);
+ }
+ else
+ {
+ SKIP("Can't open file for comparision");
+ }
+}
diff --git a/kdecore/kconfig_compiler/tests/kconfigcompiler_test.h b/kdecore/kconfig_compiler/tests/kconfigcompiler_test.h
new file mode 100644
index 000000000..8ccea83fa
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/kconfigcompiler_test.h
@@ -0,0 +1,35 @@
+/*
+ Tests for KConfig Compiler
+
+ Copyright (c) 2005 by Duncan Mac-Vicar <duncan@kde.org>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KCONFIGCOMPILER_TEST_H
+#define KCONFIGCOMPILER_TEST_H
+
+#include <kunittest/tester.h>
+
+class QString;
+
+// change to SlotTester when it works
+class KConfigCompiler_Test : public KUnitTest::Tester
+{
+public:
+ void allTests();
+public slots:
+ void testExpectedOutput();
+private:
+ void performCompare(const QString &fileName, bool fail=false);
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/myprefs.h b/kdecore/kconfig_compiler/tests/myprefs.h
new file mode 100644
index 000000000..263c409d2
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/myprefs.h
@@ -0,0 +1,7 @@
+#include <kconfigskeleton.h>
+
+class MyPrefs : public KConfigSkeleton
+{
+ public:
+ MyPrefs( const QString &a ) : KConfigSkeleton( a ) {}
+};
diff --git a/kdecore/kconfig_compiler/tests/test1.cpp.ref b/kdecore/kconfig_compiler/tests/test1.cpp.ref
new file mode 100644
index 000000000..e4c9f86d8
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test1.cpp.ref
@@ -0,0 +1,72 @@
+// This file is generated by kconfig_compiler from test1.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test1.h"
+
+Test1::Test1( const QString & transport, const QString & folder )
+ : KConfigSkeleton( QString::fromLatin1( "examplerc" ) )
+ , mParamtransport(transport)
+ , mParamfolder(folder)
+{
+ setCurrentGroup( QString::fromLatin1( "General-%1" ).arg( mParamfolder ) );
+
+ KConfigSkeleton::ItemBool *itemOneOption;
+ itemOneOption = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "OneOption" ), mOneOption, true );
+ addItem( itemOneOption, QString::fromLatin1( "OneOption" ) );
+ KConfigSkeleton::ItemInt *itemAnotherOption;
+ itemAnotherOption = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Another Option" ), mAnotherOption, 5 );
+ addItem( itemAnotherOption, QString::fromLatin1( "AnotherOption" ) );
+ QValueList<KConfigSkeleton::ItemEnum::Choice> valuesListOption;
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "One" );
+ valuesListOption.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "Two" );
+ valuesListOption.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "Three" );
+ valuesListOption.append( choice );
+ }
+ KConfigSkeleton::ItemEnum *itemListOption;
+ itemListOption = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "ListOption" ), mListOption, valuesListOption, EnumListOption::One );
+ addItem( itemListOption, QString::fromLatin1( "ListOption" ) );
+
+ setCurrentGroup( QString::fromLatin1( "MyOptions" ) );
+
+ KConfigSkeleton::ItemString *itemMyString;
+ itemMyString = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "MyString" ), mMyString, QString::fromLatin1( "Default String" ) );
+ addItem( itemMyString, QString::fromLatin1( "MyString" ) );
+ KConfigSkeleton::ItemPath *itemMyPath;
+ itemMyPath = new KConfigSkeleton::ItemPath( currentGroup(), QString::fromLatin1( "MyPath" ), mMyPath, QDir::homeDirPath()+QString::fromLatin1(".hidden_file") );
+ addItem( itemMyPath, QString::fromLatin1( "MyPath" ) );
+ KConfigSkeleton::ItemInt *itemAnotherOption2;
+ itemAnotherOption2 = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Another Option" ), mAnotherOption2, 10 );
+ addItem( itemAnotherOption2, QString::fromLatin1( "AnotherOption2" ) );
+ QStringList defaultMyStringList;
+ defaultMyStringList.append( QString::fromUtf8( "up" ) );
+ defaultMyStringList.append( QString::fromUtf8( "down" ) );
+
+ KConfigSkeleton::ItemStringList *itemMyStringList;
+ itemMyStringList = new KConfigSkeleton::ItemStringList( currentGroup(), QString::fromLatin1( "MyStringList" ), mMyStringList, defaultMyStringList );
+ addItem( itemMyStringList, QString::fromLatin1( "MyStringList" ) );
+ QStringList defaultMyStringListHidden;
+ defaultMyStringListHidden.append( QString::fromUtf8( "up" ) );
+ defaultMyStringListHidden.append( QString::fromUtf8( "down" ) );
+
+ KConfigSkeleton::ItemStringList *itemMyStringListHidden;
+ itemMyStringListHidden = new KConfigSkeleton::ItemStringList( currentGroup(), QString::fromLatin1( "MyStringListHidden" ), mMyStringListHidden, defaultMyStringListHidden );
+ addItem( itemMyStringListHidden, QString::fromLatin1( "MyStringListHidden" ) );
+ KConfigSkeleton::ItemInt *itemMyNumber;
+ itemMyNumber = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "List-%1-%2" ).arg( mParamtransport ).arg( mParamfolder ), mMyNumber, 1 );
+ addItem( itemMyNumber, QString::fromLatin1( "MyNumber" ) );
+}
+
+Test1::~Test1()
+{
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test1.h.ref b/kdecore/kconfig_compiler/tests/test1.h.ref
new file mode 100644
index 000000000..e08ccee8a
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test1.h.ref
@@ -0,0 +1,196 @@
+// This file is generated by kconfig_compiler from test1.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST1_H
+#define TEST1_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+#include <qdir.h>
+class Test1 : public KConfigSkeleton
+{
+ public:
+ class EnumListOption
+ {
+ public:
+ enum type { One, Two, Three, COUNT };
+ };
+
+ Test1( const QString & transport, const QString & folder );
+ ~Test1();
+
+ /**
+ Set One option
+ */
+ void setOneOption( bool v )
+ {
+ if (!isImmutable( QString::fromLatin1( "OneOption" ) ))
+ mOneOption = v;
+ }
+
+ /**
+ Get One option
+ */
+ bool oneOption() const
+ {
+ return mOneOption;
+ }
+
+ /**
+ Set Another option
+ */
+ void setAnotherOption( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "AnotherOption" ) ))
+ mAnotherOption = v;
+ }
+
+ /**
+ Get Another option
+ */
+ int anotherOption() const
+ {
+ return mAnotherOption;
+ }
+
+ /**
+ Set This is some funky option
+ */
+ void setListOption( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "ListOption" ) ))
+ mListOption = v;
+ }
+
+ /**
+ Get This is some funky option
+ */
+ int listOption() const
+ {
+ return mListOption;
+ }
+
+ /**
+ Set This is a string
+ */
+ void setMyString( const QString & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyString" ) ))
+ mMyString = v;
+ }
+
+ /**
+ Get This is a string
+ */
+ QString myString() const
+ {
+ return mMyString;
+ }
+
+ /**
+ Set This is a path
+ */
+ void setMyPath( const QString & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyPath" ) ))
+ mMyPath = v;
+ }
+
+ /**
+ Get This is a path
+ */
+ QString myPath() const
+ {
+ return mMyPath;
+ }
+
+ /**
+ Set Another option
+ */
+ void setAnotherOption2( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "AnotherOption2" ) ))
+ mAnotherOption2 = v;
+ }
+
+ /**
+ Get Another option
+ */
+ int anotherOption2() const
+ {
+ return mAnotherOption2;
+ }
+
+ /**
+ Set MyStringList
+ */
+ void setMyStringList( const QStringList & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyStringList" ) ))
+ mMyStringList = v;
+ }
+
+ /**
+ Get MyStringList
+ */
+ QStringList myStringList() const
+ {
+ return mMyStringList;
+ }
+
+ /**
+ Set MyStringListHidden
+ */
+ void setMyStringListHidden( const QStringList & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyStringListHidden" ) ))
+ mMyStringListHidden = v;
+ }
+
+ /**
+ Get MyStringListHidden
+ */
+ QStringList myStringListHidden() const
+ {
+ return mMyStringListHidden;
+ }
+
+ /**
+ Set List Number
+ */
+ void setMyNumber( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyNumber" ) ))
+ mMyNumber = v;
+ }
+
+ /**
+ Get List Number
+ */
+ int myNumber() const
+ {
+ return mMyNumber;
+ }
+
+ protected:
+ QString mParamtransport;
+ QString mParamfolder;
+
+ // General-$(folder)
+ bool mOneOption;
+ int mAnotherOption;
+ int mListOption;
+
+ // MyOptions
+ QString mMyString;
+ QString mMyPath;
+ int mAnotherOption2;
+ QStringList mMyStringList;
+ QStringList mMyStringListHidden;
+ int mMyNumber;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test1.kcfg b/kdecore/kconfig_compiler/tests/test1.kcfg
new file mode 100644
index 000000000..ce42aebfb
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test1.kcfg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>qdir.h</include>
+ <kcfgfile name="examplerc">
+ <parameter name="transport" />
+ <parameter name="folder" />
+ </kcfgfile>
+ <group name="General-$(folder)">
+ <entry name="OneOption" type="Bool">
+ <label>One option</label>
+ <default>true</default>
+ </entry>
+ <entry name="AnotherOption" type="Int" key="Another Option">
+ <label>Another option</label>
+ <default>5</default>
+ </entry>
+ <entry name="ListOption" type="Enum">
+ <label>This is some funky option</label>
+ <whatsthis>And this is a longer description of this option. Just wondering, how will the translations of those be handled?</whatsthis>
+ <choices>
+ <choice name="One"/>
+ <choice name="Two"/>
+ <choice name="Three"/>
+ </choices>
+ <default>One</default>
+ </entry>
+ </group>
+ <group name="MyOptions">
+ <entry name="MyString" type="String">
+ <label>This is a string</label>
+ <default>Default String</default>
+ </entry>
+ <entry name="MyPath" type="Path">
+ <label>This is a path</label>
+ <default code="true">QDir::homeDirPath()+QString::fromLatin1(".hidden_file")</default>
+ </entry>
+ <entry name="AnotherOption2" type="Int" key="Another Option">
+ <label>Another option</label>
+ <default>10</default>
+ </entry>
+ <entry name="MyStringList" type="StringList">
+ <default>up,down</default>
+ </entry>
+ <entry name="MyStringListHidden" hidden="true" type="StringList">
+ <default>up,down</default>
+ </entry>
+ <entry name="MyNumber" type="Int" key="List-$(transport)-$(folder)">
+ <label>List Number</label>
+ <default>1</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test1.kcfgc b/kdecore/kconfig_compiler/tests/test1.kcfgc
new file mode 100644
index 000000000..6e0edd366
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test1.kcfgc
@@ -0,0 +1,18 @@
+# Code generation options for kconfig_compiler
+ClassName=Test1
+#
+# Singleton=false
+#
+# Inherits=KConfigSkeleton
+#
+# IncludeFiles=libkdepim/kpimprefs.h
+#
+# MemberVariables=public
+#
+### The following line includes the file exampleprefs_base_addon.h
+### It can be used to add extra functions and variables to the
+### class.
+# CustomAdditions=true
+#
+### Provide setFooBar(int) style functions
+Mutators=true
diff --git a/kdecore/kconfig_compiler/tests/test1main.cpp b/kdecore/kconfig_compiler/tests/test1main.cpp
new file mode 100644
index 000000000..f55f54195
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test1main.cpp
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+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.
+*/
+#include "test1.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test1 *t = new Test1( QString::null, QString::null );
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test2.cpp.ref b/kdecore/kconfig_compiler/tests/test2.cpp.ref
new file mode 100644
index 000000000..d2197856e
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test2.cpp.ref
@@ -0,0 +1,98 @@
+// This file is generated by kconfig_compiler from test2.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test2.h"
+
+#include <klocale.h>
+
+Test2::Test2( )
+ : MyPrefs( QString::fromLatin1( "korganizerrc" ) )
+{
+ setCurrentGroup( QString::fromLatin1( "General" ) );
+
+ mAutoSaveItem = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "Auto Save" ), mAutoSave, false );
+ mAutoSaveItem->setLabel( i18n("Enable automatic saving of calendar") );
+ mAutoSaveItem->setWhatsThis( i18n("WhatsThis text for AutoSave option") );
+ addItem( mAutoSaveItem, QString::fromLatin1( "AutoSave" ) );
+ mAutoSaveIntervalItem = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Auto Save Interval" ), mAutoSaveInterval, 10 );
+ mAutoSaveIntervalItem->setLabel( i18n("Auto Save Interval") );
+ addItem( mAutoSaveIntervalItem, QString::fromLatin1( "AutoSaveInterval" ) );
+ mConfirmItem = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "Confirm Deletes" ), mConfirm, true );
+ mConfirmItem->setLabel( i18n("Confirm deletes") );
+ addItem( mConfirmItem, QString::fromLatin1( "Confirm" ) );
+ mArchiveFileItem = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "Archive File" ), mArchiveFile );
+ mArchiveFileItem->setLabel( i18n("Archive File") );
+ addItem( mArchiveFileItem, QString::fromLatin1( "ArchiveFile" ) );
+ QValueList<KConfigSkeleton::ItemEnum::Choice> valuesDestination;
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "standardDestination" );
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "askDestination" );
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "argl1" );
+ choice.label = i18n("Argl1 Label");
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "argl2" );
+ choice.whatsThis = i18n("Argl2 Whatsthis");
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "argl3" );
+ choice.label = i18n("Argl3 Label");
+ choice.whatsThis = i18n("Argl3 Whatsthis");
+ valuesDestination.append( choice );
+ }
+ mDestinationItem = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "Destination" ), mDestination, valuesDestination, standardDestination );
+ mDestinationItem->setLabel( i18n("New Events/Todos Should") );
+ addItem( mDestinationItem, QString::fromLatin1( "Destination" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Views" ) );
+
+ mHourSizeItem = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Hour Size" ), mHourSize, 10 );
+ mHourSizeItem->setLabel( i18n("Hour Size") );
+ addItem( mHourSizeItem, QString::fromLatin1( "HourSize" ) );
+ mSelectionStartsEditorItem = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "SelectionStartsEditor" ), mSelectionStartsEditor, false );
+ mSelectionStartsEditorItem->setLabel( i18n("Time range selection in agenda view starts event editor") );
+ addItem( mSelectionStartsEditorItem, QString::fromLatin1( "SelectionStartsEditor" ) );
+
+ setCurrentGroup( QString::fromLatin1( "KOrganizer Plugins" ) );
+
+ QStringList defaultSelectedPlugins;
+ defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) );
+ defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) );
+
+ mSelectedPluginsItem = new KConfigSkeleton::ItemStringList( currentGroup(), QString::fromLatin1( "SelectedPlugins" ), mSelectedPlugins, defaultSelectedPlugins );
+ mSelectedPluginsItem->setLabel( i18n("SelectedPlugins") );
+ addItem( mSelectedPluginsItem, QString::fromLatin1( "SelectedPlugins" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Colors" ) );
+
+ mHighlightColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "Highlight Color" ), mHighlightColor, QColor( 100, 100, 255 ) );
+ mHighlightColorItem->setLabel( i18n("Highlight color") );
+ addItem( mHighlightColorItem, QString::fromLatin1( "HighlightColor" ) );
+ mAgendaBgColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "Agenda Background Color" ), mAgendaBgColor, QColor( 255, 255, 255 ) );
+ mAgendaBgColorItem->setLabel( i18n("Agenda view background color") );
+ addItem( mAgendaBgColorItem, QString::fromLatin1( "AgendaBgColor" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Fonts" ) );
+
+ mTimeBarFontItem = new KConfigSkeleton::ItemFont( currentGroup(), QString::fromLatin1( "TimeBar Font" ), mTimeBarFont );
+ mTimeBarFontItem->setLabel( i18n("Time bar") );
+ addItem( mTimeBarFontItem, QString::fromLatin1( "TimeBarFont" ) );
+}
+
+Test2::~Test2()
+{
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test2.h.ref b/kdecore/kconfig_compiler/tests/test2.h.ref
new file mode 100644
index 000000000..4e8b5ec1f
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test2.h.ref
@@ -0,0 +1,333 @@
+// This file is generated by kconfig_compiler from test2.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST2_H
+#define TEST2_H
+
+#include <myprefs.h>
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class Test2 : public MyPrefs
+{
+ public:
+ enum { standardDestination, askDestination, argl1, argl2, argl3 };
+
+ Test2( );
+ ~Test2();
+
+ /**
+ Set Enable automatic saving of calendar
+ */
+ void setAutoSave( bool v )
+ {
+ if (!isImmutable( QString::fromLatin1( "AutoSave" ) ))
+ mAutoSave = v;
+ }
+
+ /**
+ Get Enable automatic saving of calendar
+ */
+ bool autoSave() const
+ {
+ return mAutoSave;
+ }
+
+ /**
+ Get Item object corresponding to AutoSave()
+ */
+ ItemBool *autoSaveItem()
+ {
+ return mAutoSaveItem;
+ }
+
+ /**
+ Set Auto Save Interval
+ */
+ void setAutoSaveInterval( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "AutoSaveInterval" ) ))
+ mAutoSaveInterval = v;
+ }
+
+ /**
+ Get Auto Save Interval
+ */
+ int autoSaveInterval() const
+ {
+ return mAutoSaveInterval;
+ }
+
+ /**
+ Get Item object corresponding to AutoSaveInterval()
+ */
+ ItemInt *autoSaveIntervalItem()
+ {
+ return mAutoSaveIntervalItem;
+ }
+
+ /**
+ Set Confirm deletes
+ */
+ void setConfirm( bool v )
+ {
+ if (!isImmutable( QString::fromLatin1( "Confirm" ) ))
+ mConfirm = v;
+ }
+
+ /**
+ Get Confirm deletes
+ */
+ bool confirm() const
+ {
+ return mConfirm;
+ }
+
+ /**
+ Get Item object corresponding to Confirm()
+ */
+ ItemBool *confirmItem()
+ {
+ return mConfirmItem;
+ }
+
+ /**
+ Set Archive File
+ */
+ void setArchiveFile( const QString & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "ArchiveFile" ) ))
+ mArchiveFile = v;
+ }
+
+ /**
+ Get Archive File
+ */
+ QString archiveFile() const
+ {
+ return mArchiveFile;
+ }
+
+ /**
+ Get Item object corresponding to ArchiveFile()
+ */
+ ItemString *archiveFileItem()
+ {
+ return mArchiveFileItem;
+ }
+
+ /**
+ Set New Events/Todos Should
+ */
+ void setDestination( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "Destination" ) ))
+ mDestination = v;
+ }
+
+ /**
+ Get New Events/Todos Should
+ */
+ int destination() const
+ {
+ return mDestination;
+ }
+
+ /**
+ Get Item object corresponding to Destination()
+ */
+ ItemEnum *destinationItem()
+ {
+ return mDestinationItem;
+ }
+
+ /**
+ Set Hour Size
+ */
+ void setHourSize( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "HourSize" ) ))
+ mHourSize = v;
+ }
+
+ /**
+ Get Hour Size
+ */
+ int hourSize() const
+ {
+ return mHourSize;
+ }
+
+ /**
+ Get Item object corresponding to HourSize()
+ */
+ ItemInt *hourSizeItem()
+ {
+ return mHourSizeItem;
+ }
+
+ /**
+ Set Time range selection in agenda view starts event editor
+ */
+ void setSelectionStartsEditor( bool v )
+ {
+ if (!isImmutable( QString::fromLatin1( "SelectionStartsEditor" ) ))
+ mSelectionStartsEditor = v;
+ }
+
+ /**
+ Get Time range selection in agenda view starts event editor
+ */
+ bool selectionStartsEditor() const
+ {
+ return mSelectionStartsEditor;
+ }
+
+ /**
+ Get Item object corresponding to SelectionStartsEditor()
+ */
+ ItemBool *selectionStartsEditorItem()
+ {
+ return mSelectionStartsEditorItem;
+ }
+
+ /**
+ Set SelectedPlugins
+ */
+ void setSelectedPlugins( const QStringList & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "SelectedPlugins" ) ))
+ mSelectedPlugins = v;
+ }
+
+ /**
+ Get SelectedPlugins
+ */
+ QStringList selectedPlugins() const
+ {
+ return mSelectedPlugins;
+ }
+
+ /**
+ Get Item object corresponding to SelectedPlugins()
+ */
+ ItemStringList *selectedPluginsItem()
+ {
+ return mSelectedPluginsItem;
+ }
+
+ /**
+ Set Highlight color
+ */
+ void setHighlightColor( const QColor & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "HighlightColor" ) ))
+ mHighlightColor = v;
+ }
+
+ /**
+ Get Highlight color
+ */
+ QColor highlightColor() const
+ {
+ return mHighlightColor;
+ }
+
+ /**
+ Get Item object corresponding to HighlightColor()
+ */
+ ItemColor *highlightColorItem()
+ {
+ return mHighlightColorItem;
+ }
+
+ /**
+ Set Agenda view background color
+ */
+ void setAgendaBgColor( const QColor & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "AgendaBgColor" ) ))
+ mAgendaBgColor = v;
+ }
+
+ /**
+ Get Agenda view background color
+ */
+ QColor agendaBgColor() const
+ {
+ return mAgendaBgColor;
+ }
+
+ /**
+ Get Item object corresponding to AgendaBgColor()
+ */
+ ItemColor *agendaBgColorItem()
+ {
+ return mAgendaBgColorItem;
+ }
+
+ /**
+ Set Time bar
+ */
+ void setTimeBarFont( const QFont & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "TimeBarFont" ) ))
+ mTimeBarFont = v;
+ }
+
+ /**
+ Get Time bar
+ */
+ QFont timeBarFont() const
+ {
+ return mTimeBarFont;
+ }
+
+ /**
+ Get Item object corresponding to TimeBarFont()
+ */
+ ItemFont *timeBarFontItem()
+ {
+ return mTimeBarFontItem;
+ }
+
+ protected:
+ public:
+
+ // General
+ bool mAutoSave;
+ int mAutoSaveInterval;
+ bool mConfirm;
+ QString mArchiveFile;
+ int mDestination;
+
+ // Views
+ int mHourSize;
+ bool mSelectionStartsEditor;
+
+ // KOrganizer Plugins
+ QStringList mSelectedPlugins;
+
+ // Colors
+ QColor mHighlightColor;
+ QColor mAgendaBgColor;
+
+ // Fonts
+ QFont mTimeBarFont;
+
+ private:
+ ItemBool *mAutoSaveItem;
+ ItemInt *mAutoSaveIntervalItem;
+ ItemBool *mConfirmItem;
+ ItemString *mArchiveFileItem;
+ ItemEnum *mDestinationItem;
+ ItemInt *mHourSizeItem;
+ ItemBool *mSelectionStartsEditorItem;
+ ItemStringList *mSelectedPluginsItem;
+ ItemColor *mHighlightColorItem;
+ ItemColor *mAgendaBgColorItem;
+ ItemFont *mTimeBarFontItem;
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test2.kcfg b/kdecore/kconfig_compiler/tests/test2.kcfg
new file mode 100644
index 000000000..3b19e270e
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test2.kcfg
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="korganizerrc"/>
+
+ <group name="General">
+ <entry type="Bool" key="Auto Save">
+ <label>Enable automatic saving of calendar</label>
+ <whatsthis>WhatsThis text for AutoSave option</whatsthis>
+ <default>false</default>
+ </entry>
+ <entry type="Int" key="Auto Save Interval">
+ <default>10</default>
+ </entry>
+ <entry type="Bool" key="Confirm Deletes" name="Confirm">
+ <label>Confirm deletes</label>
+ <default>true</default>
+ </entry>
+ <entry type="String" key="Archive File">
+ </entry>
+ <entry type="Enum" key="Destination" name="Destination">
+ <label>New Events/Todos Should</label>
+ <choices>
+ <choice name="standardDestination">
+ </choice>
+ <choice name="askDestination">
+ </choice>
+ <choice name="argl1">
+ <label>Argl1 Label</label>
+ </choice>
+ <choice name="argl2">
+ <whatsthis>Argl2 Whatsthis</whatsthis>
+ </choice>
+ <choice name="argl3">
+ <label>Argl3 Label</label>
+ <whatsthis>Argl3 Whatsthis</whatsthis>
+ </choice>
+ </choices>
+ <default>standardDestination</default>
+ </entry>
+ </group>
+
+ <group name="Views">
+ <entry type="Int" key="Hour Size">
+ <default>10</default>
+ </entry>
+ <entry type="Bool" name="SelectionStartsEditor">
+ <label>Time range selection in agenda view starts event editor</label>
+ <default>false</default>
+ </entry>
+ </group>
+
+ <group name="KOrganizer Plugins">
+ <entry type="StringList" name="SelectedPlugins">
+ <default>holidays,webexport</default>
+ </entry>
+ </group>
+
+ <group name="Colors">
+ <entry type="Color" key="Highlight Color">
+ <label>Highlight color</label>
+ <default>100, 100, 255</default>
+ </entry>
+ <entry type="Color" key="Agenda Background Color" name="AgendaBgColor">
+ <label>Agenda view background color</label>
+ <default>255, 255, 255</default>
+ </entry>
+ </group>
+
+ <group name="Fonts">
+ <entry type="Font" key="TimeBar Font">
+ <label>Time bar</label>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test2.kcfgc b/kdecore/kconfig_compiler/tests/test2.kcfgc
new file mode 100644
index 000000000..56620d2f4
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test2.kcfgc
@@ -0,0 +1,11 @@
+# Code generation options for kconfig_compiler
+File=test2.kcfg
+ClassName=Test2
+Singleton=false
+Mutators=true
+Inherits=MyPrefs
+IncludeFiles=myprefs.h
+MemberVariables=public
+GlobalEnums=true
+ItemAccessors=true
+SetUserTexts=true
diff --git a/kdecore/kconfig_compiler/tests/test2main.cpp b/kdecore/kconfig_compiler/tests/test2main.cpp
new file mode 100644
index 000000000..904c57270
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test2main.cpp
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+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.
+*/
+#include "test2.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test2 *t = new Test2();
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test3.cpp.ref b/kdecore/kconfig_compiler/tests/test3.cpp.ref
new file mode 100644
index 000000000..a9435f2cf
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test3.cpp.ref
@@ -0,0 +1,29 @@
+// This file is generated by kconfig_compiler from test3.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test3.h"
+
+using namespace TestNameSpace;
+
+Test3::Test3( )
+ : KConfigSkeleton( QString::fromLatin1( "test3rc" ) )
+{
+ setCurrentGroup( QString::fromLatin1( "General" ) );
+
+ mAutoSaveItem = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "Auto Save" ), mAutoSave, false );
+ addItem( mAutoSaveItem, QString::fromLatin1( "AutoSave" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Blah" ) );
+
+ mBlubbItem = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Blubb" ), mBlubb, 10 );
+ addItem( mBlubbItem, QString::fromLatin1( "Blubb" ) );
+ mBlahBlahItem = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "BlahBlah" ), mBlahBlah, QString::fromLatin1( "a string" ) );
+ addItem( mBlahBlahItem, QString::fromLatin1( "BlahBlah" ) );
+ mMyPasswordItem = new KConfigSkeleton::ItemPassword( currentGroup(), QString::fromLatin1( "MyPassword" ), mMyPassword );
+ addItem( mMyPasswordItem, QString::fromLatin1( "MyPassword" ) );
+}
+
+Test3::~Test3()
+{
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test3.h.ref b/kdecore/kconfig_compiler/tests/test3.h.ref
new file mode 100644
index 000000000..4742a0ec1
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test3.h.ref
@@ -0,0 +1,138 @@
+// This file is generated by kconfig_compiler from test3.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TESTNAMESPACE_TEST3_H
+#define TESTNAMESPACE_TEST3_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+namespace TestNameSpace {
+
+class Test3 : public KConfigSkeleton
+{
+ public:
+
+ Test3( );
+ ~Test3();
+
+ /**
+ Set Enable automatic saving of calendar
+ */
+ void setAutoSave( bool v )
+ {
+ if (!isImmutable( QString::fromLatin1( "AutoSave" ) ))
+ mAutoSave = v;
+ }
+
+ /**
+ Get Enable automatic saving of calendar
+ */
+ bool autoSave() const
+ {
+ return mAutoSave;
+ }
+
+ /**
+ Get Item object corresponding to AutoSave()
+ */
+ ItemBool *autoSaveItem()
+ {
+ return mAutoSaveItem;
+ }
+
+ /**
+ Set Blubb
+ */
+ void setBlubb( int v )
+ {
+ if (!isImmutable( QString::fromLatin1( "Blubb" ) ))
+ mBlubb = v;
+ }
+
+ /**
+ Get Blubb
+ */
+ int blubb() const
+ {
+ return mBlubb;
+ }
+
+ /**
+ Get Item object corresponding to Blubb()
+ */
+ ItemInt *blubbItem()
+ {
+ return mBlubbItem;
+ }
+
+ /**
+ Set BlahBlah
+ */
+ void setBlahBlah( const QString & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "BlahBlah" ) ))
+ mBlahBlah = v;
+ }
+
+ /**
+ Get BlahBlah
+ */
+ QString blahBlah() const
+ {
+ return mBlahBlah;
+ }
+
+ /**
+ Get Item object corresponding to BlahBlah()
+ */
+ ItemString *blahBlahItem()
+ {
+ return mBlahBlahItem;
+ }
+
+ /**
+ Set MyPassword
+ */
+ void setMyPassword( const QString & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyPassword" ) ))
+ mMyPassword = v;
+ }
+
+ /**
+ Get MyPassword
+ */
+ QString myPassword() const
+ {
+ return mMyPassword;
+ }
+
+ /**
+ Get Item object corresponding to MyPassword()
+ */
+ ItemPassword *myPasswordItem()
+ {
+ return mMyPasswordItem;
+ }
+
+ protected:
+
+ // General
+ bool mAutoSave;
+
+ // Blah
+ int mBlubb;
+ QString mBlahBlah;
+ QString mMyPassword;
+
+ private:
+ ItemBool *mAutoSaveItem;
+ ItemInt *mBlubbItem;
+ ItemString *mBlahBlahItem;
+ ItemPassword *mMyPasswordItem;
+};
+
+}
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test3.kcfg b/kdecore/kconfig_compiler/tests/test3.kcfg
new file mode 100644
index 000000000..77916da40
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test3.kcfg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="test3rc"/>
+
+ <group name="General">
+ <entry type="Bool" key="Auto Save">
+ <label>Enable automatic saving of calendar</label>
+ <whatsthis>WhatsThis text for AutoSave option</whatsthis>
+ <default>false</default>
+ </entry>
+ </group>
+
+ <group name="Blah">
+ <entry type="Int" name="Blubb">
+ <default>10</default>
+ </entry>
+ <entry type="String" name="BlahBlah">
+ <default>a string</default>
+ </entry>
+ <entry type="Password" name="MyPassword"/>
+ </group>
+
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test3.kcfgc b/kdecore/kconfig_compiler/tests/test3.kcfgc
new file mode 100644
index 000000000..ca2c22057
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test3.kcfgc
@@ -0,0 +1,12 @@
+# Code generation options for kconfig_compiler
+File=test3.kcfg
+NameSpace=TestNameSpace
+ClassName=Test3
+#Singleton=false
+Mutators=true
+#Inherits=MyPrefs
+#IncludeFiles=myprefs.h
+#MemberVariables=public
+GlobalEnums=true
+ItemAccessors=true
+#SetUserTexts=true
diff --git a/kdecore/kconfig_compiler/tests/test3main.cpp b/kdecore/kconfig_compiler/tests/test3main.cpp
new file mode 100644
index 000000000..9789d697d
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test3main.cpp
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+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.
+*/
+#include "test3.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ TestNameSpace::Test3 *t = new TestNameSpace::Test3();
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test4.cpp.ref b/kdecore/kconfig_compiler/tests/test4.cpp.ref
new file mode 100644
index 000000000..d50c98b26
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test4.cpp.ref
@@ -0,0 +1,82 @@
+// This file is generated by kconfig_compiler from test4.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test4.h"
+
+#include <kstaticdeleter.h>
+
+Test4 *Test4::mSelf = 0;
+static KStaticDeleter<Test4> staticTest4Deleter;
+
+Test4 *Test4::self()
+{
+ if ( !mSelf ) {
+ staticTest4Deleter.setObject( mSelf, new Test4() );
+ mSelf->readConfig();
+ }
+
+ return mSelf;
+}
+
+const char* const Test4::EnumButton::enumToString[] = { "right", "mid", "left" };
+
+Test4::Test4( )
+ : KConfigSkeleton( QString::fromLatin1( "test4rc" ) )
+{
+ mSelf = this;
+ setCurrentGroup( QString::fromLatin1( "Foo" ) );
+
+QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black };
+ KConfigSkeleton::ItemColor *itemColor[4];
+ itemColor[0] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #0" ), mColor[0], defaultColor[0] );
+ addItem( itemColor[0], QString::fromLatin1( "Color0" ) );
+ itemColor[1] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #1" ), mColor[1], defaultColor[1] );
+ addItem( itemColor[1], QString::fromLatin1( "Color1" ) );
+ itemColor[2] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #2" ), mColor[2], defaultColor[2] );
+ addItem( itemColor[2], QString::fromLatin1( "Color2" ) );
+ itemColor[3] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #3" ), mColor[3], defaultColor[3] );
+ addItem( itemColor[3], QString::fromLatin1( "Color3" ) );
+ QValueList<KConfigSkeleton::ItemEnum::Choice> valuesMouseAction;
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "Encrypt" );
+ valuesMouseAction.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "Decrypt" );
+ valuesMouseAction.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "CrashNBurn" );
+ valuesMouseAction.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "PumpNDump" );
+ valuesMouseAction.append( choice );
+ }
+ KConfigSkeleton::ItemEnum *itemMouseAction[3];
+ itemMouseAction[0] = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "right_mouse_action" ), mMouseAction[0], valuesMouseAction, EnumMouseAction::Decrypt );
+ addItem( itemMouseAction[0], QString::fromLatin1( "MouseActionright" ) );
+ itemMouseAction[1] = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "mid_mouse_action" ), mMouseAction[1], valuesMouseAction, EnumMouseAction::Encrypt );
+ addItem( itemMouseAction[1], QString::fromLatin1( "MouseActionmid" ) );
+ itemMouseAction[2] = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "left_mouse_action" ), mMouseAction[2], valuesMouseAction, EnumMouseAction::PumpNDump );
+ addItem( itemMouseAction[2], QString::fromLatin1( "MouseActionleft" ) );
+ KConfigSkeleton::ItemString *itemFooBar;
+ itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "foo bar" ), mFooBar );
+ addItem( itemFooBar, QString::fromLatin1( "FooBar" ) );
+ KConfigSkeleton::ItemInt *itemAge;
+ itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Age" ), mAge, 35 );
+ itemAge->setMinValue(8);
+ itemAge->setMaxValue(88);
+ addItem( itemAge, QString::fromLatin1( "Age" ) );
+}
+
+Test4::~Test4()
+{
+ if ( mSelf == this )
+ staticTest4Deleter.setObject( mSelf, 0, false );
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test4.h.ref b/kdecore/kconfig_compiler/tests/test4.h.ref
new file mode 100644
index 000000000..b7ae85287
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test4.h.ref
@@ -0,0 +1,135 @@
+// This file is generated by kconfig_compiler from test4.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST4_H
+#define TEST4_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class Test4 : public KConfigSkeleton
+{
+ public:
+ class EnumMouseAction
+ {
+ public:
+ enum type { Encrypt, Decrypt, CrashNBurn, PumpNDump, COUNT };
+ };
+ class EnumButton
+ {
+ public:
+ enum type { right, mid, left, COUNT };
+ static const char* const enumToString[];
+ };
+
+ static Test4 *self();
+ ~Test4();
+
+ /**
+ Set Block colors.
+ */
+ static
+ void setColor( int i, const QColor & v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "Color%1" ).arg( i ) ))
+ self()->mColor[i] = v;
+ }
+
+ /**
+ Get Block colors.
+ */
+ static
+ QColor color( int i )
+ {
+ return self()->mColor[i];
+ }
+
+ /**
+ Set Mouse actions.
+ */
+ static
+ void setMouseAction( int i, int v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "MouseAction%1" ).arg( QString::fromLatin1( EnumButton::enumToString[i] ) ) ))
+ self()->mMouseAction[i] = v;
+ }
+
+ /**
+ Get Mouse actions.
+ */
+ static
+ int mouseAction( int i )
+ {
+ return self()->mMouseAction[i];
+ }
+
+ /**
+ Set foo bar
+ */
+ static
+ void setFooBar( const QString & v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "FooBar" ) ))
+ self()->mFooBar = v;
+ }
+
+ /**
+ Get foo bar
+ */
+ static
+ QString fooBar()
+ {
+ return self()->mFooBar;
+ }
+
+ /**
+ Set Age
+ */
+ static
+ void setAge( int v )
+ {
+ if (v < 8)
+ {
+ kdDebug() << "setAge: value " << v << " is less than the minimum value of 8" << endl;
+ v = 8;
+ }
+
+ if (v > 88)
+ {
+ kdDebug() << "setAge: value " << v << " is greater than the maximum value of 88" << endl;
+ v = 88;
+ }
+
+ if (!self()->isImmutable( QString::fromLatin1( "Age" ) ))
+ self()->mAge = v;
+ }
+
+ /**
+ Get Age
+ */
+ static
+ int age()
+ {
+ return self()->mAge;
+ }
+
+ static
+ void writeConfig()
+ {
+ static_cast<KConfigSkeleton*>(self())->writeConfig();
+ }
+ protected:
+ Test4();
+ static Test4 *mSelf;
+
+
+ // Foo
+ QColor mColor[4];
+ int mMouseAction[3];
+ QString mFooBar;
+ int mAge;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test4.kcfg b/kdecore/kconfig_compiler/tests/test4.kcfg
new file mode 100644
index 000000000..d8ef2bfae
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test4.kcfg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="test4rc"/>
+
+ <group name="Foo">
+ <entry name="Color$(Number)" type="Color" key="color #$(Number)">
+ <parameter name="Number" type="Int" max="3"/>
+ <label>Block colors.</label>
+ <code>QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black };</code>
+ <default code="true">defaultColor[$(Number)]</default>
+ </entry>
+ <entry name="MouseAction$(Button)" type="Enum" key="$(Button)_mouse_action">
+ <parameter name="Button" type="Enum">
+ <values>
+ <value>right</value>
+ <value>mid</value>
+ <value>left</value>
+ </values>
+ </parameter>
+ <label>Mouse actions.</label>
+ <choices>
+ <choice name="Encrypt"/>
+ <choice name="Decrypt"/>
+ <choice name="CrashNBurn"/>
+ <choice name="PumpNDump"/>
+ </choices>
+ <default param="right">Decrypt</default>
+ <default param="mid">Encrypt</default>
+ <default param="left">PumpNDump</default>
+ </entry>
+ <entry name="FooBar" key="foo bar" type="String"/>
+ <entry name="Age" type="Int">
+ <default>35</default>
+ <min>8</min>
+ <max>88</max>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test4.kcfgc b/kdecore/kconfig_compiler/tests/test4.kcfgc
new file mode 100644
index 000000000..754706dff
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test4.kcfgc
@@ -0,0 +1,11 @@
+# Code generation options for kconfig_compiler
+File=test4.kcfg
+ClassName=Test4
+Singleton=true
+Mutators=true
+#Inherits=MyPrefs
+#IncludeFiles=myprefs.h
+#MemberVariables=public
+GlobalEnums=false
+ItemAccessors=false
+#SetUserTexts=true
diff --git a/kdecore/kconfig_compiler/tests/test4main.cpp b/kdecore/kconfig_compiler/tests/test4main.cpp
new file mode 100644
index 000000000..8b38b3dbd
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test4main.cpp
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2003,2004 Waldo Bastian <bastian@kde.org>
+
+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.
+*/
+
+#include "test4.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test4 *t = Test4::self();
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test5.cpp.ref b/kdecore/kconfig_compiler/tests/test5.cpp.ref
new file mode 100644
index 000000000..e6dc13f85
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test5.cpp.ref
@@ -0,0 +1,82 @@
+// This file is generated by kconfig_compiler from test5.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test5.h"
+
+#include <kstaticdeleter.h>
+
+Test5 *Test5::mSelf = 0;
+static KStaticDeleter<Test5> staticTest5Deleter;
+
+Test5 *Test5::self()
+{
+ if ( !mSelf ) {
+ staticTest5Deleter.setObject( mSelf, new Test5() );
+ mSelf->readConfig();
+ }
+
+ return mSelf;
+}
+
+const char* const Test5::EnumButtonToString[] = { "right", "mid", "left" };
+
+Test5::Test5( )
+ : KConfigSkeleton( QString::fromLatin1( "test4rc" ) )
+{
+ mSelf = this;
+ setCurrentGroup( QString::fromLatin1( "Foo" ) );
+
+QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black };
+ KConfigSkeleton::ItemColor *itemColor[4];
+ itemColor[0] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #0" ), mColor[0], defaultColor[0] );
+ addItem( itemColor[0], QString::fromLatin1( "Color0" ) );
+ itemColor[1] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #1" ), mColor[1], defaultColor[1] );
+ addItem( itemColor[1], QString::fromLatin1( "Color1" ) );
+ itemColor[2] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #2" ), mColor[2], defaultColor[2] );
+ addItem( itemColor[2], QString::fromLatin1( "Color2" ) );
+ itemColor[3] = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #3" ), mColor[3], defaultColor[3] );
+ addItem( itemColor[3], QString::fromLatin1( "Color3" ) );
+ QValueList<KConfigSkeleton::ItemEnum::Choice> valuesMouseAction;
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "Encrypt" );
+ valuesMouseAction.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "Decrypt" );
+ valuesMouseAction.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "CrashNBurn" );
+ valuesMouseAction.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "PumpNDump" );
+ valuesMouseAction.append( choice );
+ }
+ KConfigSkeleton::ItemEnum *itemMouseAction[3];
+ itemMouseAction[0] = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "right_mouse_action" ), mMouseAction[0], valuesMouseAction, Decrypt );
+ addItem( itemMouseAction[0], QString::fromLatin1( "MouseActionright" ) );
+ itemMouseAction[1] = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "mid_mouse_action" ), mMouseAction[1], valuesMouseAction, Encrypt );
+ addItem( itemMouseAction[1], QString::fromLatin1( "MouseActionmid" ) );
+ itemMouseAction[2] = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "left_mouse_action" ), mMouseAction[2], valuesMouseAction, PumpNDump );
+ addItem( itemMouseAction[2], QString::fromLatin1( "MouseActionleft" ) );
+ KConfigSkeleton::ItemString *itemFooBar;
+ itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "foo bar" ), mFooBar );
+ addItem( itemFooBar, QString::fromLatin1( "FooBar" ) );
+ KConfigSkeleton::ItemInt *itemAge;
+ itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Age" ), mAge, 35 );
+ itemAge->setMinValue(8);
+ itemAge->setMaxValue(88);
+ addItem( itemAge, QString::fromLatin1( "Age" ) );
+}
+
+Test5::~Test5()
+{
+ if ( mSelf == this )
+ staticTest5Deleter.setObject( mSelf, 0, false );
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test5.h.ref b/kdecore/kconfig_compiler/tests/test5.h.ref
new file mode 100644
index 000000000..1a61d3913
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test5.h.ref
@@ -0,0 +1,127 @@
+// This file is generated by kconfig_compiler from test5.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST5_H
+#define TEST5_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class Test5 : public KConfigSkeleton
+{
+ public:
+ enum { Encrypt, Decrypt, CrashNBurn, PumpNDump };
+ enum { right, mid, left };
+ static const char* const EnumButtonToString[];
+
+ static Test5 *self();
+ ~Test5();
+
+ /**
+ Set Block colors.
+ */
+ static
+ void setColor( int i, const QColor & v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "Color%1" ).arg( i ) ))
+ self()->mColor[i] = v;
+ }
+
+ /**
+ Get Block colors.
+ */
+ static
+ QColor color( int i )
+ {
+ return self()->mColor[i];
+ }
+
+ /**
+ Set Mouse actions.
+ */
+ static
+ void setMouseAction( int i, int v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "MouseAction%1" ).arg( QString::fromLatin1( EnumButtonToString[i] ) ) ))
+ self()->mMouseAction[i] = v;
+ }
+
+ /**
+ Get Mouse actions.
+ */
+ static
+ int mouseAction( int i )
+ {
+ return self()->mMouseAction[i];
+ }
+
+ /**
+ Set foo bar
+ */
+ static
+ void setFooBar( const QString & v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "FooBar" ) ))
+ self()->mFooBar = v;
+ }
+
+ /**
+ Get foo bar
+ */
+ static
+ QString fooBar()
+ {
+ return self()->mFooBar;
+ }
+
+ /**
+ Set Age
+ */
+ static
+ void setAge( int v )
+ {
+ if (v < 8)
+ {
+ kdDebug() << "setAge: value " << v << " is less than the minimum value of 8" << endl;
+ v = 8;
+ }
+
+ if (v > 88)
+ {
+ kdDebug() << "setAge: value " << v << " is greater than the maximum value of 88" << endl;
+ v = 88;
+ }
+
+ if (!self()->isImmutable( QString::fromLatin1( "Age" ) ))
+ self()->mAge = v;
+ }
+
+ /**
+ Get Age
+ */
+ static
+ int age()
+ {
+ return self()->mAge;
+ }
+
+ static
+ void writeConfig()
+ {
+ static_cast<KConfigSkeleton*>(self())->writeConfig();
+ }
+ protected:
+ Test5();
+ static Test5 *mSelf;
+
+
+ // Foo
+ QColor mColor[4];
+ int mMouseAction[3];
+ QString mFooBar;
+ int mAge;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test5.kcfg b/kdecore/kconfig_compiler/tests/test5.kcfg
new file mode 100644
index 000000000..d8ef2bfae
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test5.kcfg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="test4rc"/>
+
+ <group name="Foo">
+ <entry name="Color$(Number)" type="Color" key="color #$(Number)">
+ <parameter name="Number" type="Int" max="3"/>
+ <label>Block colors.</label>
+ <code>QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black };</code>
+ <default code="true">defaultColor[$(Number)]</default>
+ </entry>
+ <entry name="MouseAction$(Button)" type="Enum" key="$(Button)_mouse_action">
+ <parameter name="Button" type="Enum">
+ <values>
+ <value>right</value>
+ <value>mid</value>
+ <value>left</value>
+ </values>
+ </parameter>
+ <label>Mouse actions.</label>
+ <choices>
+ <choice name="Encrypt"/>
+ <choice name="Decrypt"/>
+ <choice name="CrashNBurn"/>
+ <choice name="PumpNDump"/>
+ </choices>
+ <default param="right">Decrypt</default>
+ <default param="mid">Encrypt</default>
+ <default param="left">PumpNDump</default>
+ </entry>
+ <entry name="FooBar" key="foo bar" type="String"/>
+ <entry name="Age" type="Int">
+ <default>35</default>
+ <min>8</min>
+ <max>88</max>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test5.kcfgc b/kdecore/kconfig_compiler/tests/test5.kcfgc
new file mode 100644
index 000000000..663005e5e
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test5.kcfgc
@@ -0,0 +1,11 @@
+# Code generation options for kconfig_compiler
+File=test5.kcfg
+ClassName=Test5
+Singleton=true
+Mutators=true
+#Inherits=MyPrefs
+#IncludeFiles=myprefs.h
+#MemberVariables=public
+GlobalEnums=true
+ItemAccessors=false
+#SetUserTexts=true
diff --git a/kdecore/kconfig_compiler/tests/test5main.cpp b/kdecore/kconfig_compiler/tests/test5main.cpp
new file mode 100644
index 000000000..57ad5189d
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test5main.cpp
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2004 Waldo Bastian <bastian@kde.org>
+
+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.
+*/
+
+#include "test5.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test5 *t = Test5::self();
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test6.cpp.ref b/kdecore/kconfig_compiler/tests/test6.cpp.ref
new file mode 100644
index 000000000..21fea85f6
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test6.cpp.ref
@@ -0,0 +1,31 @@
+// This file is generated by kconfig_compiler from test6.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test6.h"
+
+Test6::Test6( const QString & Number )
+ : KConfigSkeleton( QString::fromLatin1( "test4rc" ) )
+ , mParamNumber(Number)
+{
+ setCurrentGroup( QString::fromLatin1( "Foo" ) );
+
+ KConfigSkeleton::ItemColor *itemColor;
+ itemColor = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #%1" ).arg( mParamNumber ), mColor, QColor( "red" ) );
+ addItem( itemColor, QString::fromLatin1( "Color" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Bar%1" ).arg( mParamNumber ) );
+
+ KConfigSkeleton::ItemString *itemFooBar;
+ itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "foo bar" ), mFooBar );
+ addItem( itemFooBar, QString::fromLatin1( "FooBar" ) );
+ KConfigSkeleton::ItemInt *itemAge;
+ itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Age" ), mAge, 35 );
+ itemAge->setMinValue(8);
+ itemAge->setMaxValue(88);
+ addItem( itemAge, QString::fromLatin1( "Age" ) );
+}
+
+Test6::~Test6()
+{
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test6.h.ref b/kdecore/kconfig_compiler/tests/test6.h.ref
new file mode 100644
index 000000000..75fcfd04f
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test6.h.ref
@@ -0,0 +1,93 @@
+// This file is generated by kconfig_compiler from test6.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST6_H
+#define TEST6_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class Test6 : public KConfigSkeleton
+{
+ public:
+
+ Test6( const QString & Number );
+ ~Test6();
+
+ /**
+ Set Block colors.
+ */
+ void setColor( const QColor & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "Color" ) ))
+ mColor = v;
+ }
+
+ /**
+ Get Block colors.
+ */
+ QColor color() const
+ {
+ return mColor;
+ }
+
+ /**
+ Set foo bar
+ */
+ void setFooBar( const QString & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "FooBar" ) ))
+ mFooBar = v;
+ }
+
+ /**
+ Get foo bar
+ */
+ QString fooBar() const
+ {
+ return mFooBar;
+ }
+
+ /**
+ Set Age
+ */
+ void setAge( int v )
+ {
+ if (v < 8)
+ {
+ kdDebug() << "setAge: value " << v << " is less than the minimum value of 8" << endl;
+ v = 8;
+ }
+
+ if (v > 88)
+ {
+ kdDebug() << "setAge: value " << v << " is greater than the maximum value of 88" << endl;
+ v = 88;
+ }
+
+ if (!isImmutable( QString::fromLatin1( "Age" ) ))
+ mAge = v;
+ }
+
+ /**
+ Get Age
+ */
+ int age() const
+ {
+ return mAge;
+ }
+
+ protected:
+ QString mParamNumber;
+
+ // Foo
+ QColor mColor;
+
+ // Bar$(Number)
+ QString mFooBar;
+ int mAge;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test6.kcfg b/kdecore/kconfig_compiler/tests/test6.kcfg
new file mode 100644
index 000000000..e59fa88f3
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test6.kcfg
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="test4rc">
+ <parameter name="Number" type="String"/>
+ </kcfgfile>
+
+ <group name="Foo">
+ <entry name="Color" type="Color" key="color #$(Number)">
+ <label>Block colors.</label>
+ <default>red</default>
+ </entry>
+ </group>
+ <group name="Bar$(Number)">
+ <entry name="FooBar" key="foo bar" type="String"/>
+ <entry name="Age" type="Int">
+ <default>35</default>
+ <min>8</min>
+ <max>88</max>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test6.kcfgc b/kdecore/kconfig_compiler/tests/test6.kcfgc
new file mode 100644
index 000000000..b69dc152d
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test6.kcfgc
@@ -0,0 +1,11 @@
+# Code generation options for kconfig_compiler
+File=test6.kcfg
+ClassName=Test6
+Singleton=false
+Mutators=true
+#Inherits=MyPrefs
+#IncludeFiles=myprefs.h
+#MemberVariables=public
+GlobalEnums=true
+ItemAccessors=false
+#SetUserTexts=true
diff --git a/kdecore/kconfig_compiler/tests/test6main.cpp b/kdecore/kconfig_compiler/tests/test6main.cpp
new file mode 100644
index 000000000..a891c097a
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test6main.cpp
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2004 Waldo Bastian <bastian@kde.org>
+
+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.
+*/
+
+#include "test6.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test6 *t = new Test6(QString::null);
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test7.cpp.ref b/kdecore/kconfig_compiler/tests/test7.cpp.ref
new file mode 100644
index 000000000..8292e31d1
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test7.cpp.ref
@@ -0,0 +1,31 @@
+// This file is generated by kconfig_compiler from test7.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test7.h"
+
+Test7::Test7( int Number )
+ : KConfigSkeleton( QString::fromLatin1( "test7rc" ) )
+ , mParamNumber(Number)
+{
+ setCurrentGroup( QString::fromLatin1( "Foo" ) );
+
+ KConfigSkeleton::ItemColor *itemColor;
+ itemColor = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "color #%1" ).arg( mParamNumber ), mColor, QColor( "red" ) );
+ addItem( itemColor, QString::fromLatin1( "Color" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Bar%1" ).arg( mParamNumber ) );
+
+ KConfigSkeleton::ItemString *itemFooBar;
+ itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "foo bar" ), mFooBar );
+ addItem( itemFooBar, QString::fromLatin1( "FooBar" ) );
+ KConfigSkeleton::ItemInt *itemAge;
+ itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Age" ), mAge, 35 );
+ itemAge->setMinValue(8);
+ itemAge->setMaxValue(88);
+ addItem( itemAge, QString::fromLatin1( "Age" ) );
+}
+
+Test7::~Test7()
+{
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test7.h.ref b/kdecore/kconfig_compiler/tests/test7.h.ref
new file mode 100644
index 000000000..e8983907d
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test7.h.ref
@@ -0,0 +1,93 @@
+// This file is generated by kconfig_compiler from test7.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST7_H
+#define TEST7_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class Test7 : public KConfigSkeleton
+{
+ public:
+
+ Test7( int Number );
+ ~Test7();
+
+ /**
+ Set Block colors.
+ */
+ void setColor( const QColor & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "Color" ) ))
+ mColor = v;
+ }
+
+ /**
+ Get Block colors.
+ */
+ QColor color() const
+ {
+ return mColor;
+ }
+
+ /**
+ Set foo bar
+ */
+ void setFooBar( const QString & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "FooBar" ) ))
+ mFooBar = v;
+ }
+
+ /**
+ Get foo bar
+ */
+ QString fooBar() const
+ {
+ return mFooBar;
+ }
+
+ /**
+ Set Age
+ */
+ void setAge( int v )
+ {
+ if (v < 8)
+ {
+ kdDebug() << "setAge: value " << v << " is less than the minimum value of 8" << endl;
+ v = 8;
+ }
+
+ if (v > 88)
+ {
+ kdDebug() << "setAge: value " << v << " is greater than the maximum value of 88" << endl;
+ v = 88;
+ }
+
+ if (!isImmutable( QString::fromLatin1( "Age" ) ))
+ mAge = v;
+ }
+
+ /**
+ Get Age
+ */
+ int age() const
+ {
+ return mAge;
+ }
+
+ protected:
+ int mParamNumber;
+
+ // Foo
+ QColor mColor;
+
+ // Bar$(Number)
+ QString mFooBar;
+ int mAge;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test7.kcfg b/kdecore/kconfig_compiler/tests/test7.kcfg
new file mode 100644
index 000000000..0a7fd3272
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test7.kcfg
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="test7rc">
+ <parameter name="Number" type="Int"/>
+ </kcfgfile>
+
+ <group name="Foo">
+ <entry name="Color" type="Color" key="color #$(Number)">
+ <label>Block colors.</label>
+ <default>red</default>
+ </entry>
+ </group>
+ <group name="Bar$(Number)">
+ <entry name="FooBar" key="foo bar" type="String"/>
+ <entry name="Age" type="Int">
+ <default>35</default>
+ <min>8</min>
+ <max>88</max>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test7.kcfgc b/kdecore/kconfig_compiler/tests/test7.kcfgc
new file mode 100644
index 000000000..9a6c40954
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test7.kcfgc
@@ -0,0 +1,11 @@
+# Code generation options for kconfig_compiler
+File=test7.kcfg
+ClassName=Test7
+Singleton=false
+Mutators=true
+#Inherits=MyPrefs
+#IncludeFiles=myprefs.h
+#MemberVariables=public
+GlobalEnums=true
+ItemAccessors=false
+#SetUserTexts=true
diff --git a/kdecore/kconfig_compiler/tests/test7main.cpp b/kdecore/kconfig_compiler/tests/test7main.cpp
new file mode 100644
index 000000000..9c1ad1931
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test7main.cpp
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2004 Waldo Bastian <bastian@kde.org>
+
+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.
+*/
+
+#include "test7.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test7 *t = new Test7(42);
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test8a.cpp.ref b/kdecore/kconfig_compiler/tests/test8a.cpp.ref
new file mode 100644
index 000000000..868b63438
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8a.cpp.ref
@@ -0,0 +1,22 @@
+// This file is generated by kconfig_compiler from test8a.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test8a.h"
+
+Test8a::Test8a( KSharedConfig::Ptr config )
+ : KConfigSkeleton( config )
+{
+ setCurrentGroup( QString::fromLatin1( "Group" ) );
+
+ KConfigSkeleton::ItemFont *itemFont;
+ itemFont = new KConfigSkeleton::ItemFont( currentGroup(), QString::fromLatin1( "Font" ), mFont, KGlobalSettings::generalFont() );
+ addItem( itemFont, QString::fromLatin1( "Font" ) );
+ KConfigSkeleton::ItemFont *itemTitleFont;
+ itemTitleFont = new KConfigSkeleton::ItemFont( currentGroup(), QString::fromLatin1( "TitleFont" ), mTitleFont, KGlobalSettings::windowTitleFont() );
+ addItem( itemTitleFont, QString::fromLatin1( "TitleFont" ) );
+}
+
+Test8a::~Test8a()
+{
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test8a.h.ref b/kdecore/kconfig_compiler/tests/test8a.h.ref
new file mode 100644
index 000000000..6d4f2a00d
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8a.h.ref
@@ -0,0 +1,61 @@
+// This file is generated by kconfig_compiler from test8a.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST8A_H
+#define TEST8A_H
+
+#include <kglobal.h>
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class Test8a : public KConfigSkeleton
+{
+ public:
+
+ Test8a( KSharedConfig::Ptr config = KGlobal::sharedConfig() );
+ ~Test8a();
+
+ /**
+ Set Font
+ */
+ void setFont( const QFont & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "Font" ) ))
+ mFont = v;
+ }
+
+ /**
+ Get Font
+ */
+ QFont font() const
+ {
+ return mFont;
+ }
+
+ /**
+ Set TitleFont
+ */
+ void setTitleFont( const QFont & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "TitleFont" ) ))
+ mTitleFont = v;
+ }
+
+ /**
+ Get TitleFont
+ */
+ QFont titleFont() const
+ {
+ return mTitleFont;
+ }
+
+ protected:
+
+ // Group
+ QFont mFont;
+ QFont mTitleFont;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test8a.kcfg b/kdecore/kconfig_compiler/tests/test8a.kcfg
new file mode 100644
index 000000000..5ee87199f
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8a.kcfg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile arg="true"/>
+
+ <group name="Group">
+ <entry name="Font" type="Font">
+ <default code="true">KGlobalSettings::generalFont()</default>
+ </entry>
+
+ <entry name="TitleFont" type="Font">
+ <default code="true">KGlobalSettings::windowTitleFont()</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test8a.kcfgc b/kdecore/kconfig_compiler/tests/test8a.kcfgc
new file mode 100644
index 000000000..5f63c31c2
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8a.kcfgc
@@ -0,0 +1,3 @@
+File=test8a.kcfg
+ClassName=Test8a
+Mutators=true
diff --git a/kdecore/kconfig_compiler/tests/test8b.cpp.ref b/kdecore/kconfig_compiler/tests/test8b.cpp.ref
new file mode 100644
index 000000000..101f2ab6a
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8b.cpp.ref
@@ -0,0 +1,46 @@
+// This file is generated by kconfig_compiler from test8b.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test8b.h"
+
+#include <kstaticdeleter.h>
+
+Test8b *Test8b::mSelf = 0;
+static KStaticDeleter<Test8b> staticTest8bDeleter;
+
+Test8b *Test8b::self()
+{
+ if ( !mSelf ) {
+ staticTest8bDeleter.setObject( mSelf, new Test8b() );
+ mSelf->readConfig();
+ }
+
+ return mSelf;
+}
+
+Test8b::Test8b( )
+ : Test8a()
+{
+ mSelf = this;
+ setCurrentGroup( QString::fromLatin1( "Group8b1" ) );
+
+ KConfigSkeleton::ItemUInt *itemSomething;
+ itemSomething = new KConfigSkeleton::ItemUInt( currentGroup(), QString::fromLatin1( "Something" ), mSomething, 60 );
+ addItem( itemSomething, QString::fromLatin1( "Something" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Group8b2" ) );
+
+ KConfigSkeleton::ItemBool *itemFooBoo;
+ itemFooBoo = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "FooBoo" ), mFooBoo, false );
+ addItem( itemFooBoo, QString::fromLatin1( "FooBoo" ) );
+ KConfigSkeleton::ItemUInt *itemPort;
+ itemPort = new KConfigSkeleton::ItemUInt( currentGroup(), QString::fromLatin1( "Port" ), mPort, 1000 );
+ addItem( itemPort, QString::fromLatin1( "Port" ) );
+}
+
+Test8b::~Test8b()
+{
+ if ( mSelf == this )
+ staticTest8bDeleter.setObject( mSelf, 0, false );
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test8b.h.ref b/kdecore/kconfig_compiler/tests/test8b.h.ref
new file mode 100644
index 000000000..0ee51e3f8
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8b.h.ref
@@ -0,0 +1,96 @@
+// This file is generated by kconfig_compiler from test8b.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST8B_H
+#define TEST8B_H
+
+#include <test8a.h>
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class Test8b : public Test8a
+{
+ public:
+
+ static Test8b *self();
+ ~Test8b();
+
+ /**
+ Set Something
+ */
+ static
+ void setSomething( uint v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "Something" ) ))
+ self()->mSomething = v;
+ }
+
+ /**
+ Get Something
+ */
+ static
+ uint something()
+ {
+ return self()->mSomething;
+ }
+
+ /**
+ Set FooBoo
+ */
+ static
+ void setFooBoo( bool v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "FooBoo" ) ))
+ self()->mFooBoo = v;
+ }
+
+ /**
+ Get FooBoo
+ */
+ static
+ bool fooBoo()
+ {
+ return self()->mFooBoo;
+ }
+
+ /**
+ Set Port
+ */
+ static
+ void setPort( uint v )
+ {
+ if (!self()->isImmutable( QString::fromLatin1( "Port" ) ))
+ self()->mPort = v;
+ }
+
+ /**
+ Get Port
+ */
+ static
+ uint port()
+ {
+ return self()->mPort;
+ }
+
+ static
+ void writeConfig()
+ {
+ static_cast<KConfigSkeleton*>(self())->writeConfig();
+ }
+ protected:
+ Test8b();
+ static Test8b *mSelf;
+
+
+ // Group8b1
+ uint mSomething;
+
+ // Group8b2
+ bool mFooBoo;
+ uint mPort;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test8b.kcfg b/kdecore/kconfig_compiler/tests/test8b.kcfg
new file mode 100644
index 000000000..3e203a155
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8b.kcfg
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <group name="Group8b1">
+ <entry name="Something" type="UInt">
+ <default>60</default>
+ </entry>
+ </group>
+
+ <group name="Group8b2">
+ <entry name="FooBoo" type="Bool">
+ <default>false</default>
+ </entry>
+
+ <entry name="Port" type="UInt">
+ <default>1000</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test8b.kcfgc b/kdecore/kconfig_compiler/tests/test8b.kcfgc
new file mode 100644
index 000000000..7be055203
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8b.kcfgc
@@ -0,0 +1,6 @@
+File=test8b.kcfg
+ClassName=Test8b
+Mutators=true
+Singleton=true
+IncludeFiles=test8a.h
+Inherits=Test8a
diff --git a/kdecore/kconfig_compiler/tests/test8main.cpp b/kdecore/kconfig_compiler/tests/test8main.cpp
new file mode 100644
index 000000000..912631f7a
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test8main.cpp
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2005 Michael Brade <brade@kde.org>
+
+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.
+*/
+
+#include "test8a.h"
+#include "test8b.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test8a *config1 = new Test8a( KSharedConfig::openConfig( QString::null ) );
+ Test8a *config2 = new Test8a();
+ Test8b::self();
+ delete config1;
+ delete config2;
+}
diff --git a/kdecore/kconfig_compiler/tests/test9.cpp.ref b/kdecore/kconfig_compiler/tests/test9.cpp.ref
new file mode 100644
index 000000000..309c1ddbe
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test9.cpp.ref
@@ -0,0 +1,35 @@
+// This file is generated by kconfig_compiler from test9.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test9.h"
+
+Test9::Test9( const QString & transport, const QString & folder )
+ : KConfigSkeleton( QString::fromLatin1( "examplerc" ) )
+ , mParamtransport(transport)
+ , mParamfolder(folder)
+{
+ setCurrentGroup( QString::fromLatin1( "MyOptionsXX" ) );
+
+ QStringList defaultMyStringList;
+ defaultMyStringList.append( QString::fromUtf8( "up" ) );
+ defaultMyStringList.append( QString::fromUtf8( "down" ) );
+
+ KConfigSkeleton::ItemStringList *itemMyStringList;
+ itemMyStringList = new KConfigSkeleton::ItemStringList( currentGroup(), QString::fromLatin1( "MyStringList" ), mMyStringList, defaultMyStringList );
+ addItem( itemMyStringList, QString::fromLatin1( "MyStringList" ) );
+ QStringList defaultMyPathList;
+ defaultMyPathList.append( QString::fromUtf8( "/home" ) );
+ defaultMyPathList.append( QString::fromUtf8( "~" ) );
+
+ KConfigSkeleton::ItemPathList *itemMyPathList;
+ itemMyPathList = new KConfigSkeleton::ItemPathList( currentGroup(), QString::fromLatin1( "MyPathList" ), mMyPathList, defaultMyPathList );
+ addItem( itemMyPathList, QString::fromLatin1( "MyPathList" ) );
+ KConfigSkeleton::ItemPathList *itemMyPathsList2;
+ itemMyPathsList2 = new KConfigSkeleton::ItemPathList( currentGroup(), QString::fromLatin1( "MyPathsList2" ), mMyPathsList2, QStringList(QString::fromLatin1("/usr/bin")) += QDir::homeDirPath() );
+ addItem( itemMyPathsList2, QString::fromLatin1( "MyPathsList2" ) );
+}
+
+Test9::~Test9()
+{
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test9.h.ref b/kdecore/kconfig_compiler/tests/test9.h.ref
new file mode 100644
index 000000000..4f3e241fc
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test9.h.ref
@@ -0,0 +1,82 @@
+// This file is generated by kconfig_compiler from test9.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TEST9_H
+#define TEST9_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+#include <qdir.h>
+class Test9 : public KConfigSkeleton
+{
+ public:
+
+ Test9( const QString & transport, const QString & folder );
+ ~Test9();
+
+ /**
+ Set MyStringList
+ */
+ void setMyStringList( const QStringList & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyStringList" ) ))
+ mMyStringList = v;
+ }
+
+ /**
+ Get MyStringList
+ */
+ QStringList myStringList() const
+ {
+ return mMyStringList;
+ }
+
+ /**
+ Set This is a list of paths
+ */
+ void setMyPathList( const QStringList & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyPathList" ) ))
+ mMyPathList = v;
+ }
+
+ /**
+ Get This is a list of paths
+ */
+ QStringList myPathList() const
+ {
+ return mMyPathList;
+ }
+
+ /**
+ Set This is an additional test for PathList
+ */
+ void setMyPathsList2( const QStringList & v )
+ {
+ if (!isImmutable( QString::fromLatin1( "MyPathsList2" ) ))
+ mMyPathsList2 = v;
+ }
+
+ /**
+ Get This is an additional test for PathList
+ */
+ QStringList myPathsList2() const
+ {
+ return mMyPathsList2;
+ }
+
+ protected:
+ public:
+ QString mParamtransport;
+ QString mParamfolder;
+
+ // MyOptionsXX
+ QStringList mMyStringList;
+ QStringList mMyPathList;
+ QStringList mMyPathsList2;
+
+ private:
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test9.kcfg b/kdecore/kconfig_compiler/tests/test9.kcfg
new file mode 100644
index 000000000..b7495e2b6
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test9.kcfg
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>qdir.h</include>
+ <kcfgfile name="examplerc">
+ <parameter name="transport" />
+ <parameter name="folder" />
+ </kcfgfile>
+ <group name="MyOptionsXX">
+ <entry name="MyStringList" type="StringList">
+ <default>up,down</default>
+ </entry>
+ <entry name="MyPathList" type="PathList">
+ <label>This is a list of paths</label>
+ <default>/home,~</default>
+ </entry>
+ <entry name="MyPathsList2" type="PathList">
+ <label>This is an additional test for PathList</label>
+ <default code="true">QStringList(QString::fromLatin1("/usr/bin")) += QDir::homeDirPath()</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test9.kcfgc b/kdecore/kconfig_compiler/tests/test9.kcfgc
new file mode 100644
index 000000000..d44233380
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test9.kcfgc
@@ -0,0 +1,18 @@
+# Code generation options for kconfig_compiler
+ClassName=Test9
+#
+# Singleton=false
+#
+# Inherits=KConfigSkeleton
+#
+# IncludeFiles=libkdepim/kpimprefs.h
+#
+MemberVariables=public
+#
+### The following line includes the file exampleprefs_base_addon.h
+### It can be used to add extra functions and variables to the
+### class.
+# CustomAdditions=true
+#
+### Provide setFooBar(int) style functions
+Mutators=true
diff --git a/kdecore/kconfig_compiler/tests/test9main.cpp b/kdecore/kconfig_compiler/tests/test9main.cpp
new file mode 100644
index 000000000..3802cd339
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test9main.cpp
@@ -0,0 +1,43 @@
+/*
+Copyright (c) 2005 Helge Deller <deller@kde.org>
+
+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.
+*/
+#include "test9.h"
+#include "kinstance.h"
+#include <kdebug.h>
+#include <qdir.h>
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ Test9 *t = new Test9( QString::null, QString::null );
+
+ QStringList myPathsList2 = t->myPathsList2();
+ kdWarning() << myPathsList2 << endl;
+
+ // add another path
+ QStringList newlist = QDir::homeDirPath() + QString::fromLatin1("/.kde");
+ myPathsList2 = myPathsList2 + newlist;
+ kdWarning() << myPathsList2 << endl;
+
+ t->setMyPathsList2(myPathsList2);
+ kdWarning() << t->myPathsList2() << endl;
+
+ delete t;
+}
diff --git a/kdecore/kconfig_compiler/tests/test_dpointer.cpp.ref b/kdecore/kconfig_compiler/tests/test_dpointer.cpp.ref
new file mode 100644
index 000000000..e36c50dd0
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test_dpointer.cpp.ref
@@ -0,0 +1,344 @@
+// This file is generated by kconfig_compiler from test_dpointer.kcfg.
+// All changes you do to this file will be lost.
+
+#include "test_dpointer.h"
+
+#include <klocale.h>
+
+#include <kstaticdeleter.h>
+
+class TestDPointerPrivate
+{
+ public:
+
+ // General
+ bool autoSave;
+ int autoSaveInterval;
+ bool confirm;
+ QString archiveFile;
+ int destination;
+
+ // Views
+ int hourSize;
+ bool selectionStartsEditor;
+
+ // KOrganizer Plugins
+ QStringList selectedPlugins;
+
+ // Colors
+ QColor highlightColor;
+ QColor agendaBgColor;
+
+ // Fonts
+ QFont timeBarFont;
+
+ // items
+ KConfigSkeleton::ItemBool *autoSaveItem;
+ KConfigSkeleton::ItemInt *autoSaveIntervalItem;
+ KConfigSkeleton::ItemBool *confirmItem;
+ KConfigSkeleton::ItemString *archiveFileItem;
+ KConfigSkeleton::ItemEnum *destinationItem;
+ KConfigSkeleton::ItemInt *hourSizeItem;
+ KConfigSkeleton::ItemBool *selectionStartsEditorItem;
+ KConfigSkeleton::ItemStringList *selectedPluginsItem;
+ KConfigSkeleton::ItemColor *highlightColorItem;
+ KConfigSkeleton::ItemColor *agendaBgColorItem;
+ KConfigSkeleton::ItemFont *timeBarFontItem;
+};
+
+TestDPointer *TestDPointer::mSelf = 0;
+static KStaticDeleter<TestDPointer> staticTestDPointerDeleter;
+
+TestDPointer *TestDPointer::self()
+{
+ if ( !mSelf ) {
+ staticTestDPointerDeleter.setObject( mSelf, new TestDPointer() );
+ mSelf->readConfig();
+ }
+
+ return mSelf;
+}
+
+TestDPointer::TestDPointer( )
+ : KConfigSkeleton( QString::fromLatin1( "korganizerrc" ) )
+{
+ d = new TestDPointerPrivate;
+ mSelf = this;
+ setCurrentGroup( QString::fromLatin1( "General" ) );
+
+ d->autoSaveItem = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "Auto Save" ), d->autoSave, false );
+ d->autoSaveItem->setLabel( i18n("Enable automatic saving of calendar") );
+ d->autoSaveItem->setWhatsThis( i18n("WhatsThis text for AutoSave option") );
+ addItem( d->autoSaveItem, QString::fromLatin1( "AutoSave" ) );
+ d->autoSaveIntervalItem = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Auto Save Interval" ), d->autoSaveInterval, 10 );
+ d->autoSaveIntervalItem->setLabel( i18n("Auto Save Interval") );
+ addItem( d->autoSaveIntervalItem, QString::fromLatin1( "AutoSaveInterval" ) );
+ d->confirmItem = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "Confirm Deletes" ), d->confirm, true );
+ d->confirmItem->setLabel( i18n("Confirm deletes") );
+ addItem( d->confirmItem, QString::fromLatin1( "Confirm" ) );
+ d->archiveFileItem = new KConfigSkeleton::ItemString( currentGroup(), QString::fromLatin1( "Archive File" ), d->archiveFile );
+ d->archiveFileItem->setLabel( i18n("Archive File") );
+ addItem( d->archiveFileItem, QString::fromLatin1( "ArchiveFile" ) );
+ QValueList<KConfigSkeleton::ItemEnum::Choice> valuesDestination;
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "standardDestination" );
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "askDestination" );
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "argl1" );
+ choice.label = i18n("Argl1 Label");
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "argl2" );
+ choice.whatsThis = i18n("Argl2 Whatsthis");
+ valuesDestination.append( choice );
+ }
+ {
+ KConfigSkeleton::ItemEnum::Choice choice;
+ choice.name = QString::fromLatin1( "argl3" );
+ choice.label = i18n("Argl3 Label");
+ choice.whatsThis = i18n("Argl3 Whatsthis");
+ valuesDestination.append( choice );
+ }
+ d->destinationItem = new KConfigSkeleton::ItemEnum( currentGroup(), QString::fromLatin1( "Destination" ), d->destination, valuesDestination, EnumDestination::standardDestination );
+ d->destinationItem->setLabel( i18n("New Events/Todos Should") );
+ addItem( d->destinationItem, QString::fromLatin1( "Destination" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Views" ) );
+
+ d->hourSizeItem = new KConfigSkeleton::ItemInt( currentGroup(), QString::fromLatin1( "Hour Size" ), d->hourSize, 10 );
+ d->hourSizeItem->setLabel( i18n("Hour Size") );
+ addItem( d->hourSizeItem, QString::fromLatin1( "HourSize" ) );
+ d->selectionStartsEditorItem = new KConfigSkeleton::ItemBool( currentGroup(), QString::fromLatin1( "SelectionStartsEditor" ), d->selectionStartsEditor, false );
+ d->selectionStartsEditorItem->setLabel( i18n("Time range selection in agenda view starts event editor") );
+ addItem( d->selectionStartsEditorItem, QString::fromLatin1( "SelectionStartsEditor" ) );
+
+ setCurrentGroup( QString::fromLatin1( "KOrganizer Plugins" ) );
+
+ QStringList defaultSelectedPlugins;
+ defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) );
+ defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) );
+
+ d->selectedPluginsItem = new KConfigSkeleton::ItemStringList( currentGroup(), QString::fromLatin1( "SelectedPlugins" ), d->selectedPlugins, defaultSelectedPlugins );
+ d->selectedPluginsItem->setLabel( i18n("SelectedPlugins") );
+ addItem( d->selectedPluginsItem, QString::fromLatin1( "SelectedPlugins" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Colors" ) );
+
+ d->highlightColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "Highlight Color" ), d->highlightColor, QColor( 100, 100, 255 ) );
+ d->highlightColorItem->setLabel( i18n("Highlight color") );
+ addItem( d->highlightColorItem, QString::fromLatin1( "HighlightColor" ) );
+ d->agendaBgColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QString::fromLatin1( "Agenda Background Color" ), d->agendaBgColor, QColor( 255, 255, 255 ) );
+ d->agendaBgColorItem->setLabel( i18n("Agenda view background color") );
+ addItem( d->agendaBgColorItem, QString::fromLatin1( "AgendaBgColor" ) );
+
+ setCurrentGroup( QString::fromLatin1( "Fonts" ) );
+
+ d->timeBarFontItem = new KConfigSkeleton::ItemFont( currentGroup(), QString::fromLatin1( "TimeBar Font" ), d->timeBarFont );
+ d->timeBarFontItem->setLabel( i18n("Time bar") );
+ addItem( d->timeBarFontItem, QString::fromLatin1( "TimeBarFont" ) );
+}
+
+void TestDPointer::setAutoSave( bool v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "AutoSave" ) ))
+ self()->d->autoSave = v;
+}
+
+bool TestDPointer::autoSave()
+{
+ return self()->d->autoSave;
+}
+
+
+KConfigSkeleton::ItemBool *TestDPointer::autoSaveItem()
+{
+ return d->autoSaveItem;
+}
+
+void TestDPointer::setAutoSaveInterval( int v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "AutoSaveInterval" ) ))
+ self()->d->autoSaveInterval = v;
+}
+
+int TestDPointer::autoSaveInterval()
+{
+ return self()->d->autoSaveInterval;
+}
+
+
+KConfigSkeleton::ItemInt *TestDPointer::autoSaveIntervalItem()
+{
+ return d->autoSaveIntervalItem;
+}
+
+void TestDPointer::setConfirm( bool v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "Confirm" ) ))
+ self()->d->confirm = v;
+}
+
+bool TestDPointer::confirm()
+{
+ return self()->d->confirm;
+}
+
+
+KConfigSkeleton::ItemBool *TestDPointer::confirmItem()
+{
+ return d->confirmItem;
+}
+
+void TestDPointer::setArchiveFile( const QString & v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "ArchiveFile" ) ))
+ self()->d->archiveFile = v;
+}
+
+QString TestDPointer::archiveFile()
+{
+ return self()->d->archiveFile;
+}
+
+
+KConfigSkeleton::ItemString *TestDPointer::archiveFileItem()
+{
+ return d->archiveFileItem;
+}
+
+void TestDPointer::setDestination( int v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "Destination" ) ))
+ self()->d->destination = v;
+}
+
+int TestDPointer::destination()
+{
+ return self()->d->destination;
+}
+
+
+KConfigSkeleton::ItemEnum *TestDPointer::destinationItem()
+{
+ return d->destinationItem;
+}
+
+void TestDPointer::setHourSize( int v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "HourSize" ) ))
+ self()->d->hourSize = v;
+}
+
+int TestDPointer::hourSize()
+{
+ return self()->d->hourSize;
+}
+
+
+KConfigSkeleton::ItemInt *TestDPointer::hourSizeItem()
+{
+ return d->hourSizeItem;
+}
+
+void TestDPointer::setSelectionStartsEditor( bool v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "SelectionStartsEditor" ) ))
+ self()->d->selectionStartsEditor = v;
+}
+
+bool TestDPointer::selectionStartsEditor()
+{
+ return self()->d->selectionStartsEditor;
+}
+
+
+KConfigSkeleton::ItemBool *TestDPointer::selectionStartsEditorItem()
+{
+ return d->selectionStartsEditorItem;
+}
+
+void TestDPointer::setSelectedPlugins( const QStringList & v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "SelectedPlugins" ) ))
+ self()->d->selectedPlugins = v;
+}
+
+QStringList TestDPointer::selectedPlugins()
+{
+ return self()->d->selectedPlugins;
+}
+
+
+KConfigSkeleton::ItemStringList *TestDPointer::selectedPluginsItem()
+{
+ return d->selectedPluginsItem;
+}
+
+void TestDPointer::setHighlightColor( const QColor & v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "HighlightColor" ) ))
+ self()->d->highlightColor = v;
+}
+
+QColor TestDPointer::highlightColor()
+{
+ return self()->d->highlightColor;
+}
+
+
+KConfigSkeleton::ItemColor *TestDPointer::highlightColorItem()
+{
+ return d->highlightColorItem;
+}
+
+void TestDPointer::setAgendaBgColor( const QColor & v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "AgendaBgColor" ) ))
+ self()->d->agendaBgColor = v;
+}
+
+QColor TestDPointer::agendaBgColor()
+{
+ return self()->d->agendaBgColor;
+}
+
+
+KConfigSkeleton::ItemColor *TestDPointer::agendaBgColorItem()
+{
+ return d->agendaBgColorItem;
+}
+
+void TestDPointer::setTimeBarFont( const QFont & v )
+{
+ if (!self()->isImmutable( QString::fromLatin1( "TimeBarFont" ) ))
+ self()->d->timeBarFont = v;
+}
+
+QFont TestDPointer::timeBarFont()
+{
+ return self()->d->timeBarFont;
+}
+
+
+KConfigSkeleton::ItemFont *TestDPointer::timeBarFontItem()
+{
+ return d->timeBarFontItem;
+}
+
+TestDPointer::~TestDPointer()
+{
+ delete d;
+ if ( mSelf == this )
+ staticTestDPointerDeleter.setObject( mSelf, 0, false );
+}
+
diff --git a/kdecore/kconfig_compiler/tests/test_dpointer.h.ref b/kdecore/kconfig_compiler/tests/test_dpointer.h.ref
new file mode 100644
index 000000000..a8568fc9b
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test_dpointer.h.ref
@@ -0,0 +1,224 @@
+// This file is generated by kconfig_compiler from test_dpointer.kcfg.
+// All changes you do to this file will be lost.
+#ifndef TESTDPOINTER_H
+#define TESTDPOINTER_H
+
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+
+class TestDPointerPrivate;
+
+class TestDPointer : public KConfigSkeleton
+{
+ public:
+ class EnumDestination
+ {
+ public:
+ enum type { standardDestination, askDestination, argl1, argl2, argl3, COUNT };
+ };
+
+ static TestDPointer *self();
+ ~TestDPointer();
+
+ /**
+ Set Enable automatic saving of calendar
+ */
+ static
+ void setAutoSave( bool v );
+
+ /**
+ Get Enable automatic saving of calendar
+ */
+ static
+ bool autoSave();
+
+ /**
+ Get Item object corresponding to AutoSave()
+ */
+ ItemBool *autoSaveItem();
+
+ /**
+ Set Auto Save Interval
+ */
+ static
+ void setAutoSaveInterval( int v );
+
+ /**
+ Get Auto Save Interval
+ */
+ static
+ int autoSaveInterval();
+
+ /**
+ Get Item object corresponding to AutoSaveInterval()
+ */
+ ItemInt *autoSaveIntervalItem();
+
+ /**
+ Set Confirm deletes
+ */
+ static
+ void setConfirm( bool v );
+
+ /**
+ Get Confirm deletes
+ */
+ static
+ bool confirm();
+
+ /**
+ Get Item object corresponding to Confirm()
+ */
+ ItemBool *confirmItem();
+
+ /**
+ Set Archive File
+ */
+ static
+ void setArchiveFile( const QString & v );
+
+ /**
+ Get Archive File
+ */
+ static
+ QString archiveFile();
+
+ /**
+ Get Item object corresponding to ArchiveFile()
+ */
+ ItemString *archiveFileItem();
+
+ /**
+ Set New Events/Todos Should
+ */
+ static
+ void setDestination( int v );
+
+ /**
+ Get New Events/Todos Should
+ */
+ static
+ int destination();
+
+ /**
+ Get Item object corresponding to Destination()
+ */
+ ItemEnum *destinationItem();
+
+ /**
+ Set Hour Size
+ */
+ static
+ void setHourSize( int v );
+
+ /**
+ Get Hour Size
+ */
+ static
+ int hourSize();
+
+ /**
+ Get Item object corresponding to HourSize()
+ */
+ ItemInt *hourSizeItem();
+
+ /**
+ Set Time range selection in agenda view starts event editor
+ */
+ static
+ void setSelectionStartsEditor( bool v );
+
+ /**
+ Get Time range selection in agenda view starts event editor
+ */
+ static
+ bool selectionStartsEditor();
+
+ /**
+ Get Item object corresponding to SelectionStartsEditor()
+ */
+ ItemBool *selectionStartsEditorItem();
+
+ /**
+ Set SelectedPlugins
+ */
+ static
+ void setSelectedPlugins( const QStringList & v );
+
+ /**
+ Get SelectedPlugins
+ */
+ static
+ QStringList selectedPlugins();
+
+ /**
+ Get Item object corresponding to SelectedPlugins()
+ */
+ ItemStringList *selectedPluginsItem();
+
+ /**
+ Set Highlight color
+ */
+ static
+ void setHighlightColor( const QColor & v );
+
+ /**
+ Get Highlight color
+ */
+ static
+ QColor highlightColor();
+
+ /**
+ Get Item object corresponding to HighlightColor()
+ */
+ ItemColor *highlightColorItem();
+
+ /**
+ Set Agenda view background color
+ */
+ static
+ void setAgendaBgColor( const QColor & v );
+
+ /**
+ Get Agenda view background color
+ */
+ static
+ QColor agendaBgColor();
+
+ /**
+ Get Item object corresponding to AgendaBgColor()
+ */
+ ItemColor *agendaBgColorItem();
+
+ /**
+ Set Time bar
+ */
+ static
+ void setTimeBarFont( const QFont & v );
+
+ /**
+ Get Time bar
+ */
+ static
+ QFont timeBarFont();
+
+ /**
+ Get Item object corresponding to TimeBarFont()
+ */
+ ItemFont *timeBarFontItem();
+
+ static
+ void writeConfig()
+ {
+ static_cast<KConfigSkeleton*>(self())->writeConfig();
+ }
+ protected:
+ TestDPointer();
+ static TestDPointer *mSelf;
+
+ private:
+ TestDPointerPrivate *d;
+};
+
+#endif
+
diff --git a/kdecore/kconfig_compiler/tests/test_dpointer.kcfg b/kdecore/kconfig_compiler/tests/test_dpointer.kcfg
new file mode 100644
index 000000000..3b19e270e
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test_dpointer.kcfg
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="korganizerrc"/>
+
+ <group name="General">
+ <entry type="Bool" key="Auto Save">
+ <label>Enable automatic saving of calendar</label>
+ <whatsthis>WhatsThis text for AutoSave option</whatsthis>
+ <default>false</default>
+ </entry>
+ <entry type="Int" key="Auto Save Interval">
+ <default>10</default>
+ </entry>
+ <entry type="Bool" key="Confirm Deletes" name="Confirm">
+ <label>Confirm deletes</label>
+ <default>true</default>
+ </entry>
+ <entry type="String" key="Archive File">
+ </entry>
+ <entry type="Enum" key="Destination" name="Destination">
+ <label>New Events/Todos Should</label>
+ <choices>
+ <choice name="standardDestination">
+ </choice>
+ <choice name="askDestination">
+ </choice>
+ <choice name="argl1">
+ <label>Argl1 Label</label>
+ </choice>
+ <choice name="argl2">
+ <whatsthis>Argl2 Whatsthis</whatsthis>
+ </choice>
+ <choice name="argl3">
+ <label>Argl3 Label</label>
+ <whatsthis>Argl3 Whatsthis</whatsthis>
+ </choice>
+ </choices>
+ <default>standardDestination</default>
+ </entry>
+ </group>
+
+ <group name="Views">
+ <entry type="Int" key="Hour Size">
+ <default>10</default>
+ </entry>
+ <entry type="Bool" name="SelectionStartsEditor">
+ <label>Time range selection in agenda view starts event editor</label>
+ <default>false</default>
+ </entry>
+ </group>
+
+ <group name="KOrganizer Plugins">
+ <entry type="StringList" name="SelectedPlugins">
+ <default>holidays,webexport</default>
+ </entry>
+ </group>
+
+ <group name="Colors">
+ <entry type="Color" key="Highlight Color">
+ <label>Highlight color</label>
+ <default>100, 100, 255</default>
+ </entry>
+ <entry type="Color" key="Agenda Background Color" name="AgendaBgColor">
+ <label>Agenda view background color</label>
+ <default>255, 255, 255</default>
+ </entry>
+ </group>
+
+ <group name="Fonts">
+ <entry type="Font" key="TimeBar Font">
+ <label>Time bar</label>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdecore/kconfig_compiler/tests/test_dpointer.kcfgc b/kdecore/kconfig_compiler/tests/test_dpointer.kcfgc
new file mode 100644
index 000000000..48baa376e
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test_dpointer.kcfgc
@@ -0,0 +1,11 @@
+# Code generation options for kconfig_compiler
+File=test_dpointer.kcfg
+ClassName=TestDPointer
+Singleton=true
+Mutators=true
+#Inherits=MyPrefs
+#IncludeFiles=myprefs.h
+MemberVariables=dpointer
+#GlobalEnums=true
+ItemAccessors=true
+SetUserTexts=true
diff --git a/kdecore/kconfig_compiler/tests/test_dpointer_main.cpp b/kdecore/kconfig_compiler/tests/test_dpointer_main.cpp
new file mode 100644
index 000000000..a6c23c8fe
--- /dev/null
+++ b/kdecore/kconfig_compiler/tests/test_dpointer_main.cpp
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2005 Duncan Mac-Vicar P. <duncan@kde.org>
+
+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.
+*/
+
+#include "test_dpointer.h"
+#include "kinstance.h"
+
+int main( int, char*[] )
+{
+ KInstance i("test");
+ TestDPointer *t = TestDPointer::self();
+ delete t;
+}
diff --git a/kdecore/kconfigbackend.cpp b/kdecore/kconfigbackend.cpp
new file mode 100644
index 000000000..37bafdced
--- /dev/null
+++ b/kdecore/kconfigbackend.cpp
@@ -0,0 +1,1135 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <unistd.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qtextcodec.h>
+#include <qtextstream.h>
+
+#include "kconfigbackend.h"
+#include "kconfigbase.h"
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <ksavefile.h>
+#include <kurl.h>
+#include <kde_file.h>
+
+extern bool checkAccess(const QString& pathname, int mode);
+/* translate escaped escape sequences to their actual values. */
+static QCString printableToString(const char *str, int l)
+{
+ // Strip leading white-space.
+ while((l>0) &&
+ ((*str == ' ') || (*str == '\t') || (*str == '\r')))
+ {
+ str++; l--;
+ }
+
+ // Strip trailing white-space.
+ while((l>0) &&
+ ((str[l-1] == ' ') || (str[l-1] == '\t') || (str[l-1] == '\r')))
+ {
+ l--;
+ }
+
+ QCString result(l + 1);
+ char *r = result.data();
+
+ for(int i = 0; i < l;i++, str++)
+ {
+ if (*str == '\\')
+ {
+ i++, str++;
+ if (i >= l) // End of line. (Line ends with single slash)
+ {
+ *r++ = '\\';
+ break;
+ }
+ switch(*str)
+ {
+ case 's':
+ *r++ = ' ';
+ break;
+ case 't':
+ *r++ = '\t';
+ break;
+ case 'n':
+ *r++ = '\n';
+ break;
+ case 'r':
+ *r++ = '\r';
+ break;
+ case '\\':
+ *r++ = '\\';
+ break;
+ default:
+ *r++ = '\\';
+ *r++ = *str;
+ }
+ }
+ else
+ {
+ *r++ = *str;
+ }
+ }
+ result.truncate(r-result.data());
+ return result;
+}
+
+static QCString stringToPrintable(const QCString& str){
+ QCString result(str.length()*2); // Maximum 2x as long as source string
+ register char *r = result.data();
+ register char *s = str.data();
+
+ if (!s) return QCString("");
+
+ // Escape leading space
+ if (*s == ' ')
+ {
+ *r++ = '\\'; *r++ = 's';
+ s++;
+ }
+
+ if (*s)
+ {
+ while(*s)
+ {
+ if (*s == '\n')
+ {
+ *r++ = '\\'; *r++ = 'n';
+ }
+ else if (*s == '\t')
+ {
+ *r++ = '\\'; *r++ = 't';
+ }
+ else if (*s == '\r')
+ {
+ *r++ = '\\'; *r++ = 'r';
+ }
+ else if (*s == '\\')
+ {
+ *r++ = '\\'; *r++ = '\\';
+ }
+ else
+ {
+ *r++ = *s;
+ }
+ s++;
+ }
+ // Escape trailing space
+ if (*(r-1) == ' ')
+ {
+ *(r-1) = '\\'; *r++ = 's';
+ }
+ }
+
+ result.truncate(r - result.data());
+ return result;
+}
+
+static QCString decodeGroup(const char*s, int l)
+{
+ QCString result(l);
+ register char *r = result.data();
+
+ l--; // Correct for trailing \0
+ while(l)
+ {
+ if ((*s == '[') && (l > 1))
+ {
+ if ((*(s+1) == '['))
+ {
+ l--;
+ s++;
+ }
+ }
+ if ((*s == ']') && (l > 1))
+ {
+ if ((*(s+1) == ']'))
+ {
+ l--;
+ s++;
+ }
+ }
+ *r++ = *s++;
+ l--;
+ }
+ result.truncate(r - result.data());
+ return result;
+}
+
+static QCString encodeGroup(const QCString &str)
+{
+ int l = str.length();
+ QCString result(l*2+1);
+ register char *r = result.data();
+ register char *s = str.data();
+ while(l)
+ {
+ if ((*s == '[') || (*s == ']'))
+ *r++ = *s;
+ *r++ = *s++;
+ l--;
+ }
+ result.truncate(r - result.data());
+ return result;
+}
+
+static QCString encodeKey(const char* key)
+{
+ QCString newKey(key);
+
+ newKey.replace('[', "%5b");
+ newKey.replace(']', "%5d");
+
+ return newKey;
+}
+
+static QCString decodeKey(const char* key)
+{
+ QCString newKey(key);
+
+ newKey.replace("%5b", "[");
+ newKey.replace("%5d", "]");
+
+ return newKey;
+}
+
+class KConfigBackEnd::KConfigBackEndPrivate
+{
+public:
+ QDateTime localLastModified;
+ uint localLastSize;
+ KLockFile::Ptr localLockFile;
+ KLockFile::Ptr globalLockFile;
+};
+
+void KConfigBackEnd::changeFileName(const QString &_fileName,
+ const char * _resType,
+ bool _useKDEGlobals)
+{
+ mfileName = _fileName;
+ resType = _resType;
+ useKDEGlobals = _useKDEGlobals;
+ if (mfileName.isEmpty())
+ mLocalFileName = QString::null;
+ else if (!QDir::isRelativePath(mfileName))
+ mLocalFileName = mfileName;
+ else
+ mLocalFileName = KGlobal::dirs()->saveLocation(resType) + mfileName;
+
+ if (useKDEGlobals)
+ mGlobalFileName = KGlobal::dirs()->saveLocation("config") +
+ QString::fromLatin1("kdeglobals");
+ else
+ mGlobalFileName = QString::null;
+
+ d->localLastModified = QDateTime();
+ d->localLastSize = 0;
+ d->localLockFile = 0;
+ d->globalLockFile = 0;
+}
+
+KLockFile::Ptr KConfigBackEnd::lockFile(bool bGlobal)
+{
+ if (bGlobal)
+ {
+ if (d->globalLockFile)
+ return d->globalLockFile;
+
+ if (!mGlobalFileName.isEmpty())
+ {
+ d->globalLockFile = new KLockFile(mGlobalFileName+".lock");
+ return d->globalLockFile;
+ }
+ }
+ else
+ {
+ if (d->localLockFile)
+ return d->localLockFile;
+
+ if (!mLocalFileName.isEmpty())
+ {
+ d->localLockFile = new KLockFile(mLocalFileName+".lock");
+ return d->localLockFile;
+ }
+ }
+ return 0;
+}
+
+KConfigBackEnd::KConfigBackEnd(KConfigBase *_config,
+ const QString &_fileName,
+ const char * _resType,
+ bool _useKDEGlobals)
+ : pConfig(_config), bFileImmutable(false), mConfigState(KConfigBase::NoAccess), mFileMode(-1)
+{
+ d = new KConfigBackEndPrivate;
+ changeFileName(_fileName, _resType, _useKDEGlobals);
+}
+
+KConfigBackEnd::~KConfigBackEnd()
+{
+ delete d;
+}
+
+void KConfigBackEnd::setFileWriteMode(int mode)
+{
+ mFileMode = mode;
+}
+
+bool KConfigINIBackEnd::parseConfigFiles()
+{
+ // Check if we can write to the local file.
+ mConfigState = KConfigBase::ReadOnly;
+ if (!mLocalFileName.isEmpty() && !pConfig->isReadOnly())
+ {
+ if (checkAccess(mLocalFileName, W_OK))
+ {
+ mConfigState = KConfigBase::ReadWrite;
+ }
+ else
+ {
+ // Create the containing dir, maybe it wasn't there
+ KURL path;
+ path.setPath(mLocalFileName);
+ QString dir=path.directory();
+ KStandardDirs::makeDir(dir);
+
+ if (checkAccess(mLocalFileName, W_OK))
+ {
+ mConfigState = KConfigBase::ReadWrite;
+ }
+ }
+ QFileInfo info(mLocalFileName);
+ d->localLastModified = info.lastModified();
+ d->localLastSize = info.size();
+ }
+
+ // Parse all desired files from the least to the most specific.
+ bFileImmutable = false;
+
+ // Parse the general config files
+ if (useKDEGlobals) {
+ QStringList kdercs = KGlobal::dirs()->
+ findAllResources("config", QString::fromLatin1("kdeglobals"));
+
+#ifdef Q_WS_WIN
+ QString etc_kderc = QFile::decodeName( QCString(getenv("WINDIR")) + "\\kderc" );
+#else
+ QString etc_kderc = QString::fromLatin1("/etc/kderc");
+#endif
+
+ if (checkAccess(etc_kderc, R_OK))
+ kdercs += etc_kderc;
+
+ kdercs += KGlobal::dirs()->
+ findAllResources("config", QString::fromLatin1("system.kdeglobals"));
+
+ QStringList::ConstIterator it;
+
+ for (it = kdercs.fromLast(); it != kdercs.end(); --it) {
+
+ QFile aConfigFile( *it );
+ if (!aConfigFile.open( IO_ReadOnly ))
+ continue;
+ parseSingleConfigFile( aConfigFile, 0L, true, (*it != mGlobalFileName) );
+ aConfigFile.close();
+ if (bFileImmutable)
+ break;
+ }
+ }
+
+ bool bReadFile = !mfileName.isEmpty();
+ while(bReadFile) {
+ bReadFile = false;
+ QString bootLanguage;
+ if (useKDEGlobals && localeString.isEmpty() && !KGlobal::_locale) {
+ // Boot strap language
+ bootLanguage = KLocale::_initLanguage(pConfig);
+ setLocaleString(bootLanguage.utf8());
+ }
+
+ bFileImmutable = false;
+ QStringList list;
+ if ( !QDir::isRelativePath(mfileName) )
+ list << mfileName;
+ else
+ list = KGlobal::dirs()->findAllResources(resType, mfileName);
+
+ QStringList::ConstIterator it;
+
+ for (it = list.fromLast(); it != list.end(); --it) {
+
+ QFile aConfigFile( *it );
+ // we can already be sure that this file exists
+ bool bIsLocal = (*it == mLocalFileName);
+ if (aConfigFile.open( IO_ReadOnly )) {
+ parseSingleConfigFile( aConfigFile, 0L, false, !bIsLocal );
+ aConfigFile.close();
+ if (bFileImmutable)
+ break;
+ }
+ }
+ if (KGlobal::dirs()->isRestrictedResource(resType, mfileName))
+ bFileImmutable = true;
+ QString currentLanguage;
+ if (!bootLanguage.isEmpty())
+ {
+ currentLanguage = KLocale::_initLanguage(pConfig);
+ // If the file changed the language, we need to read the file again
+ // with the new language setting.
+ if (bootLanguage != currentLanguage)
+ {
+ bReadFile = true;
+ setLocaleString(currentLanguage.utf8());
+ }
+ }
+ }
+ if (bFileImmutable)
+ mConfigState = KConfigBase::ReadOnly;
+
+ return true;
+}
+
+#ifdef HAVE_MMAP
+#ifdef SIGBUS
+static sigjmp_buf mmap_jmpbuf;
+struct sigaction mmap_old_sigact;
+
+extern "C" {
+ static void mmap_sigbus_handler(int)
+ {
+ siglongjmp (mmap_jmpbuf, 1);
+ }
+}
+#endif
+#endif
+
+extern bool kde_kiosk_exception;
+
+void KConfigINIBackEnd::parseSingleConfigFile(QFile &rFile,
+ KEntryMap *pWriteBackMap,
+ bool bGlobal, bool bDefault)
+{
+ const char *s; // May get clobbered by sigsetjump, but we don't use them afterwards.
+ const char *eof; // May get clobbered by sigsetjump, but we don't use them afterwards.
+ QByteArray data;
+
+ if (!rFile.isOpen()) // come back, if you have real work for us ;->
+ return;
+
+ //using kdDebug() here leads to an infinite loop
+ //remove this for the release, aleXXX
+ //qWarning("Parsing %s, global = %s default = %s",
+ // rFile.name().latin1(), bGlobal ? "true" : "false", bDefault ? "true" : "false");
+
+ QCString aCurrentGroup("<default>");
+
+ unsigned int ll = localeString.length();
+
+#ifdef HAVE_MMAP
+ static volatile const char *map;
+ map = ( const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
+ rFile.handle(), 0);
+
+ if ( map != MAP_FAILED )
+ {
+ s = (const char*) map;
+ eof = s + rFile.size();
+
+#ifdef SIGBUS
+ struct sigaction act;
+ act.sa_handler = mmap_sigbus_handler;
+ sigemptyset( &act.sa_mask );
+#ifdef SA_ONESHOT
+ act.sa_flags = SA_ONESHOT;
+#else
+ act.sa_flags = SA_RESETHAND;
+#endif
+ sigaction( SIGBUS, &act, &mmap_old_sigact );
+
+ if (sigsetjmp (mmap_jmpbuf, 1))
+ {
+qWarning("SIGBUS while reading %s", rFile.name().latin1());
+ munmap(( char* )map, rFile.size());
+ sigaction (SIGBUS, &mmap_old_sigact, 0);
+ return;
+ }
+#endif
+ }
+ else
+#endif
+ {
+ rFile.at(0);
+ data = rFile.readAll();
+ s = data.data();
+ eof = s + data.size();
+ }
+
+ bool fileOptionImmutable = false;
+ bool groupOptionImmutable = false;
+ bool groupSkip = false;
+
+ int line = 0;
+ for(; s < eof; s++)
+ {
+ line++;
+
+ while((s < eof) && isspace(*s) && (*s != '\n'))
+ s++; //skip leading whitespace, shouldn't happen too often
+
+ //skip empty lines, lines starting with #
+ if ((s < eof) && ((*s == '\n') || (*s == '#')))
+ {
+ sktoeol: //skip till end-of-line
+ while ((s < eof) && (*s != '\n'))
+ s++;
+ continue; // Empty or comment or no keyword
+ }
+ const char *startLine = s;
+
+ if (*s == '[') //group
+ {
+ // In a group [[ and ]] have a special meaning
+ while ((s < eof) && (*s != '\n'))
+ {
+ if (*s == ']')
+ {
+ if ((s+1 < eof) && (*(s+1) == ']'))
+ s++; // Skip "]]"
+ else
+ break;
+ }
+
+ s++; // Search till end of group
+ }
+ const char *e = s;
+ while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
+ if ((e >= eof) || (*e != ']'))
+ {
+ fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
+ continue;
+ }
+ // group found; get the group name by taking everything in
+ // between the brackets
+ if ((e-startLine == 3) &&
+ (startLine[1] == '$') &&
+ (startLine[2] == 'i'))
+ {
+ if (!kde_kiosk_exception)
+ fileOptionImmutable = true;
+ continue;
+ }
+
+ aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
+ //cout<<"found group ["<<aCurrentGroup<<"]"<<endl;
+
+ // Backwards compatibility
+ if (aCurrentGroup == "KDE Desktop Entry")
+ aCurrentGroup = "Desktop Entry";
+
+ groupOptionImmutable = fileOptionImmutable;
+
+ e++;
+ if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$')) // Option follows
+ {
+ if ((*e == 'i') && !kde_kiosk_exception)
+ {
+ groupOptionImmutable = true;
+ }
+ }
+
+ KEntryKey groupKey(aCurrentGroup, 0);
+ KEntry entry = pConfig->lookupData(groupKey);
+ groupSkip = entry.bImmutable;
+
+ if (groupSkip && !bDefault)
+ continue;
+
+ entry.bImmutable |= groupOptionImmutable;
+ pConfig->putData(groupKey, entry, false);
+
+ if (pWriteBackMap)
+ {
+ // add the special group key indicator
+ (*pWriteBackMap)[groupKey] = entry;
+ }
+
+ continue;
+ }
+ if (groupSkip && !bDefault)
+ goto sktoeol; // Skip entry
+
+ bool optionImmutable = groupOptionImmutable;
+ bool optionDeleted = false;
+ bool optionExpand = false;
+ const char *endOfKey = 0, *locale = 0, *elocale = 0;
+ for (; (s < eof) && (*s != '\n'); s++)
+ {
+ if (*s == '=') //find the equal sign
+ {
+ if (!endOfKey)
+ endOfKey = s;
+ goto haveeq;
+ }
+ if (*s == '[') //find the locale or options.
+ {
+ const char *option;
+ const char *eoption;
+ endOfKey = s;
+ option = ++s;
+ for (;; s++)
+ {
+ if ((s >= eof) || (*s == '\n') || (*s == '=')) {
+ fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
+ goto sktoeol;
+ }
+ if (*s == ']')
+ break;
+ }
+ eoption = s;
+ if (*option != '$')
+ {
+ // Locale
+ if (locale) {
+ fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
+ goto sktoeol;
+ }
+ locale = option;
+ elocale = eoption;
+ }
+ else
+ {
+ // Option
+ while (option < eoption)
+ {
+ option++;
+ if ((*option == 'i') && !kde_kiosk_exception)
+ optionImmutable = true;
+ else if (*option == 'e')
+ optionExpand = true;
+ else if (*option == 'd')
+ {
+ optionDeleted = true;
+ goto haveeq;
+ }
+ else if (*option == ']')
+ break;
+ }
+ }
+ }
+ }
+ fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
+ continue;
+
+ haveeq:
+ for (endOfKey--; ; endOfKey--)
+ {
+ if (endOfKey < startLine)
+ {
+ fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
+ goto sktoeol;
+ }
+ if (!isspace(*endOfKey))
+ break;
+ }
+
+ const char *st = ++s;
+ while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
+
+ if (locale) {
+ unsigned int cl = static_cast<unsigned int>(elocale - locale);
+ if ((ll != cl) || memcmp(locale, localeString.data(), ll))
+ {
+ // backward compatibility. C == en_US
+ if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
+ //cout<<"mismatched locale '"<<QCString(locale, elocale-locale +1)<<"'"<<endl;
+ // We can ignore this one
+ if (!pWriteBackMap)
+ continue; // We just ignore it
+ // We just store it as is to be able to write it back later.
+ endOfKey = elocale;
+ locale = 0;
+ }
+ }
+ }
+
+ // insert the key/value line
+ QCString key(startLine, endOfKey - startLine + 2);
+ QCString val = printableToString(st, s - st);
+ //qDebug("found key '%s' with value '%s'", key.data(), val.data());
+
+ KEntryKey aEntryKey(aCurrentGroup, decodeKey(key));
+ aEntryKey.bLocal = (locale != 0);
+ aEntryKey.bDefault = bDefault;
+
+ KEntry aEntry;
+ aEntry.mValue = val;
+ aEntry.bGlobal = bGlobal;
+ aEntry.bImmutable = optionImmutable;
+ aEntry.bDeleted = optionDeleted;
+ aEntry.bExpand = optionExpand;
+ aEntry.bNLS = (locale != 0);
+
+ if (pWriteBackMap) {
+ // don't insert into the config object but into the temporary
+ // scratchpad map
+ pWriteBackMap->insert(aEntryKey, aEntry);
+ } else {
+ // directly insert value into config object
+ // no need to specify localization; if the key we just
+ // retrieved was localized already, no need to localize it again.
+ pConfig->putData(aEntryKey, aEntry, false);
+ }
+ }
+ if (fileOptionImmutable)
+ bFileImmutable = true;
+
+#ifdef HAVE_MMAP
+ if (map)
+ {
+ munmap(( char* )map, rFile.size());
+#ifdef SIGBUS
+ sigaction (SIGBUS, &mmap_old_sigact, 0);
+#endif
+ }
+#endif
+}
+
+
+void KConfigINIBackEnd::sync(bool bMerge)
+{
+ // write-sync is only necessary if there are dirty entries
+ if (!pConfig->isDirty())
+ return;
+
+ bool bEntriesLeft = true;
+
+ // find out the file to write to (most specific writable file)
+ // try local app-specific file first
+
+ if (!mfileName.isEmpty()) {
+ // Create the containing dir if needed
+ if ((resType!="config") && !QDir::isRelativePath(mLocalFileName))
+ {
+ KURL path;
+ path.setPath(mLocalFileName);
+ QString dir=path.directory();
+ KStandardDirs::makeDir(dir);
+ }
+
+ // Can we allow the write? We can, if the program
+ // doesn't run SUID. But if it runs SUID, we must
+ // check if the user would be allowed to write if
+ // it wasn't SUID.
+ if (checkAccess(mLocalFileName, W_OK)) {
+ // File is writable
+ KLockFile::Ptr lf;
+
+ bool mergeLocalFile = bMerge;
+ // Check if the file has been updated since.
+ if (mergeLocalFile)
+ {
+ lf = lockFile(false); // Lock file for local file
+ if (lf && lf->isLocked())
+ lf = 0; // Already locked, we don't need to lock/unlock again
+
+ if (lf)
+ {
+ lf->lock( KLockFile::LockForce );
+ // But what if the locking failed? Ignore it for now...
+ }
+
+ QFileInfo info(mLocalFileName);
+ if ((d->localLastSize == info.size()) &&
+ (d->localLastModified == info.lastModified()))
+ {
+ // Not changed, don't merge.
+ mergeLocalFile = false;
+ }
+ else
+ {
+ // Changed...
+ d->localLastModified = QDateTime();
+ d->localLastSize = 0;
+ }
+ }
+
+ bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
+
+ // Only if we didn't have to merge anything can we use our in-memory state
+ // the next time around. Otherwise the config-file may contain entries
+ // that are different from our in-memory state which means we will have to
+ // do a merge from then on.
+ // We do not automatically update the in-memory state with the on-disk
+ // state when writing the config to disk. We only do so when
+ // KCOnfig::reparseConfiguration() is called.
+ // For KDE 4.0 we may wish to reconsider that.
+ if (!mergeLocalFile)
+ {
+ QFileInfo info(mLocalFileName);
+ d->localLastModified = info.lastModified();
+ d->localLastSize = info.size();
+ }
+ if (lf) lf->unlock();
+ }
+ }
+
+ // only write out entries to the kdeglobals file if there are any
+ // entries marked global (indicated by bEntriesLeft) and
+ // the useKDEGlobals flag is set.
+ if (bEntriesLeft && useKDEGlobals) {
+
+ // can we allow the write? (see above)
+ if (checkAccess ( mGlobalFileName, W_OK )) {
+ KLockFile::Ptr lf = lockFile(true); // Lock file for global file
+ if (lf && lf->isLocked())
+ lf = 0; // Already locked, we don't need to lock/unlock again
+
+ if (lf)
+ {
+ lf->lock( KLockFile::LockForce );
+ // But what if the locking failed? Ignore it for now...
+ }
+ writeConfigFile( mGlobalFileName, true, bMerge ); // Always merge
+ if (lf) lf->unlock();
+ }
+ }
+
+}
+
+static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const QCString &localeString)
+{
+ // now write out all other groups.
+ QCString currentGroup;
+ for (KEntryMapConstIterator aIt = entryMap.begin();
+ aIt != entryMap.end(); ++aIt)
+ {
+ const KEntryKey &key = aIt.key();
+
+ // Either proces the default group or all others
+ if ((key.mGroup != "<default>") == defaultGroup)
+ continue; // Skip
+
+ // Skip default values and group headers.
+ if ((key.bDefault) || key.mKey.isEmpty())
+ continue; // Skip
+
+ const KEntry &currentEntry = *aIt;
+
+ KEntryMapConstIterator aTestIt = aIt;
+ ++aTestIt;
+ bool hasDefault = (aTestIt != entryMap.end());
+ if (hasDefault)
+ {
+ const KEntryKey &defaultKey = aTestIt.key();
+ if ((!defaultKey.bDefault) ||
+ (defaultKey.mKey != key.mKey) ||
+ (defaultKey.mGroup != key.mGroup) ||
+ (defaultKey.bLocal != key.bLocal))
+ hasDefault = false;
+ }
+
+
+ if (hasDefault)
+ {
+ // Entry had a default value
+ if ((currentEntry.mValue == (*aTestIt).mValue) &&
+ (currentEntry.bDeleted == (*aTestIt).bDeleted))
+ continue; // Same as default, don't write.
+ }
+ else
+ {
+ // Entry had no default value.
+ if (currentEntry.bDeleted)
+ continue; // Don't write deleted entries if there is no default.
+ }
+
+ if (!defaultGroup && (currentGroup != key.mGroup)) {
+ if (!firstEntry)
+ fprintf(pStream, "\n");
+ currentGroup = key.mGroup;
+ fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
+ }
+
+ firstEntry = false;
+ // it is data for a group
+ fputs(encodeKey(key.mKey.data()), pStream); // Key
+
+ if ( currentEntry.bNLS )
+ {
+ fputc('[', pStream);
+ fputs(localeString.data(), pStream);
+ fputc(']', pStream);
+ }
+
+ if (currentEntry.bDeleted)
+ {
+ fputs("[$d]\n", pStream); // Deleted
+ }
+ else
+ {
+ if (currentEntry.bImmutable || currentEntry.bExpand)
+ {
+ fputc('[', pStream);
+ fputc('$', pStream);
+ if (currentEntry.bImmutable)
+ fputc('i', pStream);
+ if (currentEntry.bExpand)
+ fputc('e', pStream);
+
+ fputc(']', pStream);
+ }
+ fputc('=', pStream);
+ fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
+ fputc('\n', pStream);
+ }
+ } // for loop
+}
+
+bool KConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
+ QFile *mergeFile)
+{
+ bool bEntriesLeft = false;
+ bFileImmutable = false;
+
+ // Read entries from disk
+ if (mergeFile && mergeFile->open(IO_ReadOnly))
+ {
+ // fill the temporary structure with entries from the file
+ parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
+
+ if (bFileImmutable) // File has become immutable on disk
+ return bEntriesLeft;
+ }
+
+ KEntryMap aMap = pConfig->internalEntryMap();
+
+ // augment this structure with the dirty entries from the config object
+ for (KEntryMapIterator aIt = aMap.begin();
+ aIt != aMap.end(); ++aIt)
+ {
+ const KEntry &currentEntry = *aIt;
+ if(aIt.key().bDefault)
+ {
+ aTempMap.replace(aIt.key(), currentEntry);
+ continue;
+ }
+
+ if (mergeFile && !currentEntry.bDirty)
+ continue;
+
+ // only write back entries that have the same
+ // "globality" as the file
+ if (currentEntry.bGlobal != bGlobal)
+ {
+ // wrong "globality" - might have to be saved later
+ bEntriesLeft = true;
+ continue;
+ }
+
+ // put this entry from the config object into the
+ // temporary map, possibly replacing an existing entry
+ KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
+ if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
+ continue; // Bail out if the on-disk entry is immutable
+
+ aTempMap.insert(aIt.key(), currentEntry, true);
+ } // loop
+
+ return bEntriesLeft;
+}
+
+/* antlarr: KDE 4.0: make the first parameter "const QString &" */
+bool KConfigINIBackEnd::writeConfigFile(QString filename, bool bGlobal,
+ bool bMerge)
+{
+ // is the config object read-only?
+ if (pConfig->isReadOnly())
+ return true; // pretend we wrote it
+
+ KEntryMap aTempMap;
+ QFile *mergeFile = (bMerge ? new QFile(filename) : 0);
+ bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
+ delete mergeFile;
+ if (bFileImmutable)
+ return true; // pretend we wrote it
+
+ // OK now the temporary map should be full of ALL entries.
+ // write it out to disk.
+
+ // Check if file exists:
+ int fileMode = -1;
+ bool createNew = true;
+
+ KDE_struct_stat buf;
+ if (KDE_stat(QFile::encodeName(filename), &buf) == 0)
+ {
+ if (buf.st_uid == getuid())
+ {
+ // Preserve file mode if file exists and is owned by user.
+ fileMode = buf.st_mode & 0777;
+ }
+ else
+ {
+ // File is not owned by user:
+ // Don't create new file but write to existing file instead.
+ createNew = false;
+ }
+ }
+
+ KSaveFile *pConfigFile = 0;
+ FILE *pStream = 0;
+
+ if (createNew)
+ {
+ pConfigFile = new KSaveFile( filename, 0600 );
+
+ if (pConfigFile->status() != 0)
+ {
+ delete pConfigFile;
+ return bEntriesLeft;
+ }
+
+ if (!bGlobal && (fileMode == -1))
+ fileMode = mFileMode;
+
+ if (fileMode != -1)
+ {
+ fchmod(pConfigFile->handle(), fileMode);
+ }
+
+ pStream = pConfigFile->fstream();
+ }
+ else
+ {
+ // Open existing file.
+ // We use open() to ensure that we call without O_CREAT.
+ int fd = KDE_open( QFile::encodeName(filename), O_WRONLY | O_TRUNC );
+ if (fd < 0)
+ {
+ return bEntriesLeft;
+ }
+ pStream = KDE_fdopen( fd, "w");
+ if (!pStream)
+ {
+ close(fd);
+ return bEntriesLeft;
+ }
+ }
+
+ writeEntries(pStream, aTempMap);
+
+ if (pConfigFile)
+ {
+ bool bEmptyFile = (ftell(pStream) == 0);
+ if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
+ {
+ // File is empty and doesn't have special permissions: delete it.
+ ::unlink(QFile::encodeName(filename));
+ pConfigFile->abort();
+ }
+ else
+ {
+ // Normal case: Close the file
+ pConfigFile->close();
+ }
+ delete pConfigFile;
+ }
+ else
+ {
+ fclose(pStream);
+ }
+
+ return bEntriesLeft;
+}
+
+void KConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
+{
+ bool firstEntry = true;
+
+ // Write default group
+ ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
+
+ // Write all other groups
+ ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
+}
+
+void KConfigBackEnd::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KConfigINIBackEnd::virtual_hook( int id, void* data )
+{ KConfigBackEnd::virtual_hook( id, data ); }
+
+bool KConfigBackEnd::checkConfigFilesWritable(bool warnUser)
+{
+ // WARNING: Do NOT use the event loop as it may not exist at this time.
+ bool allWritable = true;
+ QString errorMsg;
+ if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
+ {
+ errorMsg = i18n("Will not save configuration.\n");
+ allWritable = false;
+ errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
+ }
+ // We do not have an immutability flag for kdeglobals. However, making kdeglobals mutable while making
+ // the local config file immutable is senseless.
+ if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
+ {
+ if ( errorMsg.isEmpty() )
+ errorMsg = i18n("Will not save configuration.\n");
+ errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
+ allWritable = false;
+ }
+
+ if (warnUser && !allWritable)
+ {
+ // Note: We don't ask the user if we should not ask this question again because we can't save the answer.
+ errorMsg += i18n("Please contact your system administrator.");
+ QString cmdToExec = KStandardDirs::findExe(QString("kdialog"));
+ KApplication *app = kapp;
+ if (!cmdToExec.isEmpty() && app)
+ {
+ KProcess lprocess;
+ lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << errorMsg.local8Bit();
+ lprocess.start( KProcess::Block );
+ }
+ }
+ return allWritable;
+}
diff --git a/kdecore/kconfigbackend.h b/kdecore/kconfigbackend.h
new file mode 100644
index 000000000..49e0e3e49
--- /dev/null
+++ b/kdecore/kconfigbackend.h
@@ -0,0 +1,293 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Portions copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KCONFIGBACKEND_H
+#define _KCONFIGBACKEND_H
+
+#include "kconfigdata.h"
+#include <kconfigbase.h>
+#include <klockfile.h>
+#include "kdelibs_export.h"
+
+class QFile;
+class KConfigBackEndPrivate;
+
+/**
+ * Abstract base class for KDE configuration file loading/saving.
+ *
+ * This class forms the base for all classes that implement some
+ * manner of loading/saving to configuration files. It is an
+ * abstract base class, meaning that you cannot directly instantiate
+ * objects of this class. As of right now, the only back end available
+ * is one to read/write to INI-style files, but in the future, other
+ * formats may be available, such as XML or a database.
+ *
+ * @author Preston Brown <pbrown@kde.org>,
+ * Matthias Kalle Dalheimer <kalle@kde.org>
+ * @short KDE Configuration file loading/saving abstract base class
+ */
+class KDECORE_EXPORT KConfigBackEnd
+{
+ friend class KConfig;
+ friend class KSharedConfig;
+public:
+ /**
+ * Constructs a configuration back end.
+ *
+ * @param _config Specifies the configuration object which values
+ * will be passed to as they are read, or from where values
+ * to be written to will be obtained from.
+ * @param _fileName The name of the file in which config
+ * data is stored. All registered configuration directories
+ * will be looked in in order of decreasing relevance.
+ * @param _resType the resource type of the fileName specified, _if_
+ * it is not an absolute path (otherwise this parameter is ignored).
+ * @param _useKDEGlobals If true, the user's system-wide kdeglobals file
+ * will be imported into the config object. If false, only
+ * the filename specified will be dealt with.
+ */
+ KConfigBackEnd(KConfigBase *_config, const QString &_fileName,
+ const char * _resType, bool _useKDEGlobals);
+
+ /**
+ * Destructs the configuration backend.
+ */
+ virtual ~KConfigBackEnd();
+
+ /**
+ * Parses all configuration files for a configuration object. This
+ * method must be reimplemented by the derived classes.
+ *
+ * @returns Whether or not parsing was successful.
+ */
+ virtual bool parseConfigFiles() = 0;
+
+ /**
+ * Writes configuration data to file(s). This method must be
+ * reimplemented by the derived classes.
+ *
+ * @param bMerge Specifies whether the old config file already
+ * on disk should be merged in with the data in memory. If true,
+ * data is read off the disk and merged. If false, the on-disk
+ * file is removed and only in-memory data is written out.
+ */
+ virtual void sync(bool bMerge = true) = 0;
+
+ /**
+ * Changes the filenames associated with this back end. You should
+ * probably reparse your config info after doing this.
+ *
+ * @param _fileName the new filename to use
+ * @param _resType the resource type of the fileName specified, _if_
+ * it is not an absolute path (otherwise this parameter is ignored).
+ * @param _useKDEGlobals specifies whether or not to also parse the
+ * global KDE configuration files.
+ */
+ void changeFileName(const QString &_fileName, const char * _resType,
+ bool _useKDEGlobals);
+
+ /**
+ * Returns the state of the app-config object.
+ *
+ * @see KConfig::getConfigState
+ */
+ virtual KConfigBase::ConfigState getConfigState() const
+ { return mConfigState; }
+
+ /**
+ * Returns the filename as passed to the constructor.
+ * @return the filename as passed to the constructor.
+ */
+ QString fileName() const { return mfileName; }
+
+ /**
+ * Returns the resource type as passed to the constructor.
+ * @return the resource type as passed to the constructor.
+ */
+ const char * resource() const { return resType; }
+
+ /**
+ * Set the locale string that defines the current language.
+ * @param _localeString the identifier of the language
+ * @see KLocale
+ */
+ void setLocaleString(const QCString &_localeString) { localeString = _localeString; }
+
+ /**
+ * Set the file mode for newly created files.
+ * @param mode the filemode (as in chmod)
+ */
+ void setFileWriteMode(int mode);
+
+ /**
+ * Check whether the config files are writable.
+ * @param warnUser Warn the user if the configuration files are not writable.
+ * @return Indicates that all of the configuration files used are writable.
+ * @since 3.2
+ */
+ bool checkConfigFilesWritable(bool warnUser);
+
+ /**
+ * Returns a lock file object for the configuration file
+ * @param bGlobal If true, returns a lock file object for kdeglobals
+ * @since 3.3
+ */
+ KLockFile::Ptr lockFile( bool bGlobal = false );
+
+#ifdef KDE_NO_COMPAT
+private:
+#endif
+ /**
+ * @deprecated Use fileName() instead
+ */
+ KDE_DEPRECATED QString filename() const { return mfileName; }
+
+protected:
+ KConfigBase *pConfig;
+
+ QString mfileName;
+ QCString resType;
+ bool useKDEGlobals : 1;
+ bool bFileImmutable : 1;
+ QCString localeString;
+ QString mLocalFileName;
+ QString mGlobalFileName;
+ KConfigBase::ConfigState mConfigState;
+ int mFileMode;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+protected:
+ class KConfigBackEndPrivate;
+ KConfigBackEndPrivate *d;
+};
+
+
+/**
+ * Class for KDE INI-style configuration file loading/saving.
+ *
+ * @author Preston Brown <pbrown@kde.org>,
+ * Matthias Kalle Dalheimer <kalle@kde.org>
+ */
+class KDECORE_EXPORT KConfigINIBackEnd : public KConfigBackEnd
+{
+
+public:
+ /**
+ * Constructs an ini-style configuration back end.
+ *
+ * @param _config Specifies the configuration object which values
+ * will be passed to as they are read, or from where values
+ * to be written to will be obtained from.
+ * @param _fileName The name of the file in which config
+ * data is stored. All registered configuration directories
+ * will be looked in in order of decreasing relevance.
+ * @param _resType the resource type of the fileName specified, _if_
+ * it is not an absolute path (otherwise this parameter is ignored).
+ * @param _useKDEGlobals If true, the user's system-wide kdeglobals file
+ * will be imported into the config object. If false, only
+ * the filename specified will be dealt with.
+ */
+ KConfigINIBackEnd(KConfigBase *_config, const QString &_fileName,
+ const char * _resType, bool _useKDEGlobals = true)
+ : KConfigBackEnd(_config, _fileName, _resType, _useKDEGlobals) {}
+
+ /**
+ * Destructs the configuration backend.
+ */
+ virtual ~KConfigINIBackEnd() {}
+
+ /**
+ * Parses all INI-style configuration files for a config object.
+ *
+ * @returns Whether or not parsing was successful.
+ */
+ bool parseConfigFiles();
+
+ /**
+ * Writes configuration data to file(s).
+ * @param bMerge Specifies whether the old config file already
+ * on disk should be merged in with the data in memory. If true,
+ * data is read off the disk and merged. If false, the on-disk
+ * file is removed and only in-memory data is written out.
+ */
+ virtual void sync(bool bMerge = true);
+
+protected:
+ /**
+ * Parses one configuration file.
+ *
+ * @param rFile The configuration file to parse
+ * @param pWriteBackMap If specified, points to a KEntryMap where
+ * the data read from the file should be stored, instead of
+ * inserting them directly into the configuration object.
+ * Use this area as a "scratchpad" when you need to know what is
+ * on disk but don't want to effect the configuration object.
+ * @param bGlobal Specifies whether entries should be marked as
+ * belonging to the global KDE configuration file rather
+ * than the application-specific KDE configuration file(s).
+ * @param bDefault Specifies whether entries should be marked as
+ * being default values.
+ */
+ void parseSingleConfigFile(QFile& rFile, KEntryMap *pWriteBackMap = 0L,
+ bool bGlobal = false, bool bDefault = false);
+
+ /**
+ * Writes configuration file back.
+ *
+ * @param filename The name of the file to write.
+ * @param bGlobal Specifies whether to write only entries which
+ * are marked as belonging to the global KDE config file.
+ * If this is false, it skips those entries.
+ * @param bMerge Specifies whether the old config file already
+ * on disk should be merged in with the data in memory. If true,
+ * data is read off the disk and merged. If false, the on-disk
+ * file is removed and only in-memory data is written out.
+ * @return Whether some entries are left to be written to other
+ * files.
+ */
+ bool writeConfigFile(QString filename, bool bGlobal = false, bool bMerge = true);
+
+ /** Get the entry map.
+ *
+ * @param map the entries will be stored in this object.
+ * @param bGlobal Specifies whether to get only entries which
+ * are marked as belonging to the global KDE config file.
+ * If this is false, it skips those entries.
+ * @param mergeFile if not null, the dirty entries for this file will
+ * be merged.
+ *
+ * @return Whether there will be some entries left for writing to other
+ * files.
+ */
+ bool getEntryMap(KEntryMap &map, bool bGlobal, QFile *mergeFile);
+
+ /** Write the entries in @e aTempMap to the file stream.*/
+ void writeEntries(FILE *pStream, const KEntryMap &aTempMap);
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KConfigINIBackEndPrivate;
+ KConfigINIBackEndPrivate *not_d;
+};
+
+#endif
diff --git a/kdecore/kconfigbase.cpp b/kdecore/kconfigbase.cpp
new file mode 100644
index 000000000..05156e969
--- /dev/null
+++ b/kdecore/kconfigbase.cpp
@@ -0,0 +1,1869 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qtextstream.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kcharsets.h>
+
+#include "kconfigbase.h"
+#include "kconfigbackend.h"
+#include "kdebug.h"
+#include "kstandarddirs.h"
+#include "kstringhandler.h"
+
+class KConfigBase::KConfigBasePrivate
+{
+public:
+ KConfigBasePrivate() : readDefaults(false) { };
+
+public:
+ bool readDefaults;
+};
+
+KConfigBase::KConfigBase()
+ : backEnd(0L), bDirty(false), bLocaleInitialized(false),
+ bReadOnly(false), bExpand(false), d(0)
+{
+ setGroup(QString::null);
+}
+
+KConfigBase::~KConfigBase()
+{
+ delete d;
+}
+
+void KConfigBase::setLocale()
+{
+ bLocaleInitialized = true;
+
+ if (KGlobal::locale())
+ aLocaleString = KGlobal::locale()->language().utf8();
+ else
+ aLocaleString = KLocale::defaultLanguage().utf8();
+ if (backEnd)
+ backEnd->setLocaleString(aLocaleString);
+}
+
+QString KConfigBase::locale() const
+{
+ return QString::fromUtf8(aLocaleString);
+}
+
+void KConfigBase::setGroup( const QString& group )
+{
+ if ( group.isEmpty() )
+ mGroup = "<default>";
+ else
+ mGroup = group.utf8();
+}
+
+void KConfigBase::setGroup( const char *pGroup )
+{
+ setGroup(QCString(pGroup));
+}
+
+void KConfigBase::setGroup( const QCString &group )
+{
+ if ( group.isEmpty() )
+ mGroup = "<default>";
+ else
+ mGroup = group;
+}
+
+QString KConfigBase::group() const {
+ return QString::fromUtf8(mGroup);
+}
+
+void KConfigBase::setDesktopGroup()
+{
+ mGroup = "Desktop Entry";
+}
+
+bool KConfigBase::hasKey(const QString &key) const
+{
+ return hasKey(key.utf8().data());
+}
+
+bool KConfigBase::hasKey(const char *pKey) const
+{
+ KEntryKey aEntryKey(mGroup, 0);
+ aEntryKey.c_key = pKey;
+ aEntryKey.bDefault = readDefaults();
+
+ if (!locale().isNull()) {
+ // try the localized key first
+ aEntryKey.bLocal = true;
+ KEntry entry = lookupData(aEntryKey);
+ if (!entry.mValue.isNull())
+ return true;
+ aEntryKey.bLocal = false;
+ }
+
+ // try the non-localized version
+ KEntry entry = lookupData(aEntryKey);
+ return !entry.mValue.isNull();
+}
+
+bool KConfigBase::hasGroup(const QString &group) const
+{
+ return internalHasGroup( group.utf8());
+}
+
+bool KConfigBase::hasGroup(const char *_pGroup) const
+{
+ return internalHasGroup( QCString(_pGroup));
+}
+
+bool KConfigBase::hasGroup(const QCString &_pGroup) const
+{
+ return internalHasGroup( _pGroup);
+}
+
+bool KConfigBase::isImmutable() const
+{
+ return (getConfigState() != ReadWrite);
+}
+
+bool KConfigBase::groupIsImmutable(const QString &group) const
+{
+ if (getConfigState() != ReadWrite)
+ return true;
+
+ KEntryKey groupKey(group.utf8(), 0);
+ KEntry entry = lookupData(groupKey);
+ return entry.bImmutable;
+}
+
+bool KConfigBase::entryIsImmutable(const QString &key) const
+{
+ if (getConfigState() != ReadWrite)
+ return true;
+
+ KEntryKey entryKey(mGroup, 0);
+ KEntry aEntryData = lookupData(entryKey); // Group
+ if (aEntryData.bImmutable)
+ return true;
+
+ QCString utf8_key = key.utf8();
+ entryKey.c_key = utf8_key.data();
+ aEntryData = lookupData(entryKey); // Normal entry
+ if (aEntryData.bImmutable)
+ return true;
+
+ entryKey.bLocal = true;
+ aEntryData = lookupData(entryKey); // Localized entry
+ return aEntryData.bImmutable;
+}
+
+
+QString KConfigBase::readEntryUntranslated( const QString& pKey,
+ const QString& aDefault ) const
+{
+ return KConfigBase::readEntryUntranslated(pKey.utf8().data(), aDefault);
+}
+
+
+QString KConfigBase::readEntryUntranslated( const char *pKey,
+ const QString& aDefault ) const
+{
+ QCString result = readEntryUtf8(pKey);
+ if (result.isNull())
+ return aDefault;
+ return QString::fromUtf8(result);
+}
+
+
+QString KConfigBase::readEntry( const QString& pKey,
+ const QString& aDefault ) const
+{
+ return KConfigBase::readEntry(pKey.utf8().data(), aDefault);
+}
+
+QString KConfigBase::readEntry( const char *pKey,
+ const QString& aDefault ) const
+{
+ // we need to access _locale instead of the method locale()
+ // because calling locale() will create a locale object if it
+ // doesn't exist, which requires KConfig, which will create a infinite
+ // loop, and nobody likes those.
+ if (!bLocaleInitialized && KGlobal::_locale) {
+ // get around const'ness.
+ KConfigBase *that = const_cast<KConfigBase *>(this);
+ that->setLocale();
+ }
+
+ QString aValue;
+
+ bool expand = false;
+ // construct a localized version of the key
+ // try the localized key first
+ KEntry aEntryData;
+ KEntryKey entryKey(mGroup, 0);
+ entryKey.c_key = pKey;
+ entryKey.bDefault = readDefaults();
+ entryKey.bLocal = true;
+ aEntryData = lookupData(entryKey);
+ if (!aEntryData.mValue.isNull()) {
+ // for GNOME .desktop
+ aValue = KStringHandler::from8Bit( aEntryData.mValue.data() );
+ expand = aEntryData.bExpand;
+ } else {
+ entryKey.bLocal = false;
+ aEntryData = lookupData(entryKey);
+ if (!aEntryData.mValue.isNull()) {
+ aValue = QString::fromUtf8(aEntryData.mValue.data());
+ if (aValue.isNull())
+ {
+ static const QString &emptyString = KGlobal::staticQString("");
+ aValue = emptyString;
+ }
+ expand = aEntryData.bExpand;
+ } else {
+ aValue = aDefault;
+ }
+ }
+
+ // only do dollar expansion if so desired
+ if( expand || bExpand )
+ {
+ // check for environment variables and make necessary translations
+ int nDollarPos = aValue.find( '$' );
+
+ while( nDollarPos != -1 && nDollarPos+1 < static_cast<int>(aValue.length())) {
+ // there is at least one $
+ if( (aValue)[nDollarPos+1] == '(' ) {
+ uint nEndPos = nDollarPos+1;
+ // the next character is no $
+ while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!=')') )
+ nEndPos++;
+ nEndPos++;
+ QString cmd = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
+
+ QString result;
+ FILE *fs = popen(QFile::encodeName(cmd).data(), "r");
+ if (fs)
+ {
+ {
+ QTextStream ts(fs, IO_ReadOnly);
+ result = ts.read().stripWhiteSpace();
+ }
+ pclose(fs);
+ }
+ aValue.replace( nDollarPos, nEndPos-nDollarPos, result );
+ } else if( (aValue)[nDollarPos+1] != '$' ) {
+ uint nEndPos = nDollarPos+1;
+ // the next character is no $
+ QString aVarName;
+ if (aValue[nEndPos]=='{')
+ {
+ while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!='}') )
+ nEndPos++;
+ nEndPos++;
+ aVarName = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
+ }
+ else
+ {
+ while ( nEndPos <= aValue.length() && (aValue[nEndPos].isNumber()
+ || aValue[nEndPos].isLetter() || aValue[nEndPos]=='_' ) )
+ nEndPos++;
+ aVarName = aValue.mid( nDollarPos+1, nEndPos-nDollarPos-1 );
+ }
+ const char* pEnv = 0;
+ if (!aVarName.isEmpty())
+ pEnv = getenv( aVarName.ascii() );
+ if( pEnv ) {
+ // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
+ // A environment variables may contain values in 8bit
+ // locale cpecified encoding or in UTF8 encoding.
+ aValue.replace( nDollarPos, nEndPos-nDollarPos, KStringHandler::from8Bit( pEnv ) );
+ } else
+ aValue.remove( nDollarPos, nEndPos-nDollarPos );
+ } else {
+ // remove one of the dollar signs
+ aValue.remove( nDollarPos, 1 );
+ nDollarPos++;
+ }
+ nDollarPos = aValue.find( '$', nDollarPos );
+ }
+ }
+
+ return aValue;
+}
+
+QCString KConfigBase::readEntryUtf8( const char *pKey) const
+{
+ // We don't try the localized key
+ KEntryKey entryKey(mGroup, 0);
+ entryKey.bDefault = readDefaults();
+ entryKey.c_key = pKey;
+ KEntry aEntryData = lookupData(entryKey);
+ if (aEntryData.bExpand)
+ {
+ // We need to do fancy, take the slow route.
+ return readEntry(pKey, QString::null).utf8();
+ }
+ return aEntryData.mValue;
+}
+
+QVariant KConfigBase::readPropertyEntry( const QString& pKey,
+ QVariant::Type type ) const
+{
+ return readPropertyEntry(pKey.utf8().data(), type);
+}
+
+QVariant KConfigBase::readPropertyEntry( const char *pKey,
+ QVariant::Type type ) const
+{
+ QVariant va;
+ if ( !hasKey( pKey ) ) return va;
+ (void)va.cast(type);
+ return readPropertyEntry(pKey, va);
+}
+
+QVariant KConfigBase::readPropertyEntry( const QString& pKey,
+ const QVariant &aDefault ) const
+{
+ return readPropertyEntry(pKey.utf8().data(), aDefault);
+}
+
+QVariant KConfigBase::readPropertyEntry( const char *pKey,
+ const QVariant &aDefault ) const
+{
+ if ( !hasKey( pKey ) ) return aDefault;
+
+ QVariant tmp = aDefault;
+
+ switch( aDefault.type() )
+ {
+ case QVariant::Invalid:
+ return QVariant();
+ case QVariant::String:
+ return QVariant( readEntry( pKey, aDefault.toString() ) );
+ case QVariant::StringList:
+ return QVariant( readListEntry( pKey ) );
+ case QVariant::List: {
+ QStringList strList = readListEntry( pKey );
+ QStringList::ConstIterator it = strList.begin();
+ QStringList::ConstIterator end = strList.end();
+ QValueList<QVariant> list;
+
+ for (; it != end; ++it ) {
+ tmp = *it;
+ list.append( tmp );
+ }
+ return QVariant( list );
+ }
+ case QVariant::Font:
+ return QVariant( readFontEntry( pKey, &tmp.asFont() ) );
+ case QVariant::Point:
+ return QVariant( readPointEntry( pKey, &tmp.asPoint() ) );
+ case QVariant::Rect:
+ return QVariant( readRectEntry( pKey, &tmp.asRect() ) );
+ case QVariant::Size:
+ return QVariant( readSizeEntry( pKey, &tmp.asSize() ) );
+ case QVariant::Color:
+ return QVariant( readColorEntry( pKey, &tmp.asColor() ) );
+ case QVariant::Int:
+ return QVariant( readNumEntry( pKey, aDefault.toInt() ) );
+ case QVariant::UInt:
+ return QVariant( readUnsignedNumEntry( pKey, aDefault.toUInt() ) );
+ case QVariant::LongLong:
+ return QVariant( readNum64Entry( pKey, aDefault.toLongLong() ) );
+ case QVariant::ULongLong:
+ return QVariant( readUnsignedNum64Entry( pKey, aDefault.toULongLong() ) );
+ case QVariant::Bool:
+ return QVariant( readBoolEntry( pKey, aDefault.toBool() ), 0 );
+ case QVariant::Double:
+ return QVariant( readDoubleNumEntry( pKey, aDefault.toDouble() ) );
+ case QVariant::DateTime:
+ return QVariant( readDateTimeEntry( pKey, &tmp.asDateTime() ) );
+ case QVariant::Date:
+ return QVariant(readDateTimeEntry( pKey, &tmp.asDateTime() ).date());
+
+ case QVariant::Pixmap:
+ case QVariant::Image:
+ case QVariant::Brush:
+ case QVariant::Palette:
+ case QVariant::ColorGroup:
+ case QVariant::Map:
+ case QVariant::IconSet:
+ case QVariant::CString:
+ case QVariant::PointArray:
+ case QVariant::Region:
+ case QVariant::Bitmap:
+ case QVariant::Cursor:
+ case QVariant::SizePolicy:
+ case QVariant::Time:
+ case QVariant::ByteArray:
+ case QVariant::BitArray:
+ case QVariant::KeySequence:
+ case QVariant::Pen:
+ break;
+ }
+
+ Q_ASSERT( 0 );
+ return QVariant();
+}
+
+int KConfigBase::readListEntry( const QString& pKey,
+ QStrList &list, char sep ) const
+{
+ return readListEntry(pKey.utf8().data(), list, sep);
+}
+
+int KConfigBase::readListEntry( const char *pKey,
+ QStrList &list, char sep ) const
+{
+ if( !hasKey( pKey ) )
+ return 0;
+
+ QCString str_list = readEntryUtf8( pKey );
+ if (str_list.isEmpty())
+ return 0;
+
+ list.clear();
+ QCString value = "";
+ int len = str_list.length();
+
+ for (int i = 0; i < len; i++) {
+ if (str_list[i] != sep && str_list[i] != '\\') {
+ value += str_list[i];
+ continue;
+ }
+ if (str_list[i] == '\\') {
+ i++;
+ if ( i < len )
+ value += str_list[i];
+ continue;
+ }
+ // if we fell through to here, we are at a separator. Append
+ // contents of value to the list
+ // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
+ // A QStrList may contain values in 8bit locale cpecified
+ // encoding
+ list.append( value );
+ value.truncate(0);
+ }
+
+ if ( str_list[len-1] != sep || ( len > 1 && str_list[len-2] == '\\' ) )
+ list.append( value );
+ return list.count();
+}
+
+QStringList KConfigBase::readListEntry( const QString& pKey, char sep ) const
+{
+ return readListEntry(pKey.utf8().data(), sep);
+}
+
+QStringList KConfigBase::readListEntry( const char *pKey, char sep ) const
+{
+ static const QString& emptyString = KGlobal::staticQString("");
+
+ QStringList list;
+ if( !hasKey( pKey ) )
+ return list;
+ QString str_list = readEntry( pKey );
+ if( str_list.isEmpty() )
+ return list;
+ QString value(emptyString);
+ int len = str_list.length();
+ // obviously too big, but faster than letting each += resize the string.
+ value.reserve( len );
+ for( int i = 0; i < len; i++ )
+ {
+ if( str_list[i] != sep && str_list[i] != '\\' )
+ {
+ value += str_list[i];
+ continue;
+ }
+ if( str_list[i] == '\\' )
+ {
+ i++;
+ if ( i < len )
+ value += str_list[i];
+ continue;
+ }
+ QString finalvalue( value );
+ finalvalue.squeeze();
+ list.append( finalvalue );
+ value.truncate( 0 );
+ }
+ if ( str_list[len-1] != sep || ( len > 1 && str_list[len-2] == '\\' ) )
+ {
+ value.squeeze();
+ list.append( value );
+ }
+ return list;
+}
+
+QStringList KConfigBase::readListEntry( const char* pKey, const QStringList& aDefault,
+ char sep ) const
+{
+ if ( !hasKey( pKey ) )
+ return aDefault;
+ else
+ return readListEntry( pKey, sep );
+}
+
+QValueList<int> KConfigBase::readIntListEntry( const QString& pKey ) const
+{
+ return readIntListEntry(pKey.utf8().data());
+}
+
+QValueList<int> KConfigBase::readIntListEntry( const char *pKey ) const
+{
+ QStringList strlist = readListEntry(pKey);
+ QValueList<int> list;
+ QStringList::ConstIterator end(strlist.end());
+ for (QStringList::ConstIterator it = strlist.begin(); it != end; ++it)
+ // I do not check if the toInt failed because I consider the number of items
+ // more important than their value
+ list << (*it).toInt();
+
+ return list;
+}
+
+QString KConfigBase::readPathEntry( const QString& pKey, const QString& pDefault ) const
+{
+ return readPathEntry(pKey.utf8().data(), pDefault);
+}
+
+QString KConfigBase::readPathEntry( const char *pKey, const QString& pDefault ) const
+{
+ const bool bExpandSave = bExpand;
+ bExpand = true;
+ QString aValue = readEntry( pKey, pDefault );
+ bExpand = bExpandSave;
+ return aValue;
+}
+
+QStringList KConfigBase::readPathListEntry( const QString& pKey, char sep ) const
+{
+ return readPathListEntry(pKey.utf8().data(), sep);
+}
+
+QStringList KConfigBase::readPathListEntry( const char *pKey, char sep ) const
+{
+ const bool bExpandSave = bExpand;
+ bExpand = true;
+ QStringList aValue = readListEntry( pKey, sep );
+ bExpand = bExpandSave;
+ return aValue;
+}
+
+int KConfigBase::readNumEntry( const QString& pKey, int nDefault) const
+{
+ return readNumEntry(pKey.utf8().data(), nDefault);
+}
+
+int KConfigBase::readNumEntry( const char *pKey, int nDefault) const
+{
+ QCString aValue = readEntryUtf8( pKey );
+ if( aValue.isNull() )
+ return nDefault;
+ else if( aValue == "true" || aValue == "on" || aValue == "yes" )
+ return 1;
+ else
+ {
+ bool ok;
+ int rc = aValue.toInt( &ok );
+ return( ok ? rc : nDefault );
+ }
+}
+
+
+unsigned int KConfigBase::readUnsignedNumEntry( const QString& pKey, unsigned int nDefault) const
+{
+ return readUnsignedNumEntry(pKey.utf8().data(), nDefault);
+}
+
+unsigned int KConfigBase::readUnsignedNumEntry( const char *pKey, unsigned int nDefault) const
+{
+ QCString aValue = readEntryUtf8( pKey );
+ if( aValue.isNull() )
+ return nDefault;
+ else
+ {
+ bool ok;
+ unsigned int rc = aValue.toUInt( &ok );
+ return( ok ? rc : nDefault );
+ }
+}
+
+
+long KConfigBase::readLongNumEntry( const QString& pKey, long nDefault) const
+{
+ return readLongNumEntry(pKey.utf8().data(), nDefault);
+}
+
+long KConfigBase::readLongNumEntry( const char *pKey, long nDefault) const
+{
+ QCString aValue = readEntryUtf8( pKey );
+ if( aValue.isNull() )
+ return nDefault;
+ else
+ {
+ bool ok;
+ long rc = aValue.toLong( &ok );
+ return( ok ? rc : nDefault );
+ }
+}
+
+
+unsigned long KConfigBase::readUnsignedLongNumEntry( const QString& pKey, unsigned long nDefault) const
+{
+ return readUnsignedLongNumEntry(pKey.utf8().data(), nDefault);
+}
+
+unsigned long KConfigBase::readUnsignedLongNumEntry( const char *pKey, unsigned long nDefault) const
+{
+ QCString aValue = readEntryUtf8( pKey );
+ if( aValue.isNull() )
+ return nDefault;
+ else
+ {
+ bool ok;
+ unsigned long rc = aValue.toULong( &ok );
+ return( ok ? rc : nDefault );
+ }
+}
+
+Q_INT64 KConfigBase::readNum64Entry( const QString& pKey, Q_INT64 nDefault) const
+{
+ return readNum64Entry(pKey.utf8().data(), nDefault);
+}
+
+Q_INT64 KConfigBase::readNum64Entry( const char *pKey, Q_INT64 nDefault) const
+{
+ // Note that QCString::toLongLong() is missing, we muse use a QString instead.
+ QString aValue = readEntry( pKey );
+ if( aValue.isNull() )
+ return nDefault;
+ else
+ {
+ bool ok;
+ Q_INT64 rc = aValue.toLongLong( &ok );
+ return( ok ? rc : nDefault );
+ }
+}
+
+
+Q_UINT64 KConfigBase::readUnsignedNum64Entry( const QString& pKey, Q_UINT64 nDefault) const
+{
+ return readUnsignedNum64Entry(pKey.utf8().data(), nDefault);
+}
+
+Q_UINT64 KConfigBase::readUnsignedNum64Entry( const char *pKey, Q_UINT64 nDefault) const
+{
+ // Note that QCString::toULongLong() is missing, we muse use a QString instead.
+ QString aValue = readEntry( pKey );
+ if( aValue.isNull() )
+ return nDefault;
+ else
+ {
+ bool ok;
+ Q_UINT64 rc = aValue.toULongLong( &ok );
+ return( ok ? rc : nDefault );
+ }
+}
+
+double KConfigBase::readDoubleNumEntry( const QString& pKey, double nDefault) const
+{
+ return readDoubleNumEntry(pKey.utf8().data(), nDefault);
+}
+
+double KConfigBase::readDoubleNumEntry( const char *pKey, double nDefault) const
+{
+ QCString aValue = readEntryUtf8( pKey );
+ if( aValue.isNull() )
+ return nDefault;
+ else
+ {
+ bool ok;
+ double rc = aValue.toDouble( &ok );
+ return( ok ? rc : nDefault );
+ }
+}
+
+
+bool KConfigBase::readBoolEntry( const QString& pKey, bool bDefault ) const
+{
+ return readBoolEntry(pKey.utf8().data(), bDefault);
+}
+
+bool KConfigBase::readBoolEntry( const char *pKey, bool bDefault ) const
+{
+ QCString aValue = readEntryUtf8( pKey );
+
+ if( aValue.isNull() )
+ return bDefault;
+ else
+ {
+ if( aValue == "true" || aValue == "on" || aValue == "yes" || aValue == "1" )
+ return true;
+ else
+ {
+ bool bOK;
+ int val = aValue.toInt( &bOK );
+ if( bOK && val != 0 )
+ return true;
+ else
+ return false;
+ }
+ }
+}
+
+QFont KConfigBase::readFontEntry( const QString& pKey, const QFont* pDefault ) const
+{
+ return readFontEntry(pKey.utf8().data(), pDefault);
+}
+
+QFont KConfigBase::readFontEntry( const char *pKey, const QFont* pDefault ) const
+{
+ QFont aRetFont;
+
+ QString aValue = readEntry( pKey );
+ if( !aValue.isNull() ) {
+ if ( aValue.contains( ',' ) > 5 ) {
+ // KDE3 and upwards entry
+ if ( !aRetFont.fromString( aValue ) && pDefault )
+ aRetFont = *pDefault;
+ }
+ else {
+ // backward compatibility with older font formats
+ // ### remove KDE 3.1 ?
+ // find first part (font family)
+ int nIndex = aValue.find( ',' );
+ if( nIndex == -1 ){
+ if( pDefault )
+ aRetFont = *pDefault;
+ return aRetFont;
+ }
+ aRetFont.setFamily( aValue.left( nIndex ) );
+
+ // find second part (point size)
+ int nOldIndex = nIndex;
+ nIndex = aValue.find( ',', nOldIndex+1 );
+ if( nIndex == -1 ){
+ if( pDefault )
+ aRetFont = *pDefault;
+ return aRetFont;
+ }
+
+ aRetFont.setPointSize( aValue.mid( nOldIndex+1,
+ nIndex-nOldIndex-1 ).toInt() );
+
+ // find third part (style hint)
+ nOldIndex = nIndex;
+ nIndex = aValue.find( ',', nOldIndex+1 );
+
+ if( nIndex == -1 ){
+ if( pDefault )
+ aRetFont = *pDefault;
+ return aRetFont;
+ }
+
+ aRetFont.setStyleHint( (QFont::StyleHint)aValue.mid( nOldIndex+1, nIndex-nOldIndex-1 ).toUInt() );
+
+ // find fourth part (char set)
+ nOldIndex = nIndex;
+ nIndex = aValue.find( ',', nOldIndex+1 );
+
+ if( nIndex == -1 ){
+ if( pDefault )
+ aRetFont = *pDefault;
+ return aRetFont;
+ }
+
+ QString chStr=aValue.mid( nOldIndex+1,
+ nIndex-nOldIndex-1 );
+ // find fifth part (weight)
+ nOldIndex = nIndex;
+ nIndex = aValue.find( ',', nOldIndex+1 );
+
+ if( nIndex == -1 ){
+ if( pDefault )
+ aRetFont = *pDefault;
+ return aRetFont;
+ }
+
+ aRetFont.setWeight( aValue.mid( nOldIndex+1,
+ nIndex-nOldIndex-1 ).toUInt() );
+
+ // find sixth part (font bits)
+ uint nFontBits = aValue.right( aValue.length()-nIndex-1 ).toUInt();
+
+ aRetFont.setItalic( nFontBits & 0x01 );
+ aRetFont.setUnderline( nFontBits & 0x02 );
+ aRetFont.setStrikeOut( nFontBits & 0x04 );
+ aRetFont.setFixedPitch( nFontBits & 0x08 );
+ aRetFont.setRawMode( nFontBits & 0x20 );
+ }
+ }
+ else
+ {
+ if( pDefault )
+ aRetFont = *pDefault;
+ }
+
+ return aRetFont;
+}
+
+
+QRect KConfigBase::readRectEntry( const QString& pKey, const QRect* pDefault ) const
+{
+ return readRectEntry(pKey.utf8().data(), pDefault);
+}
+
+QRect KConfigBase::readRectEntry( const char *pKey, const QRect* pDefault ) const
+{
+ QCString aValue = readEntryUtf8(pKey);
+
+ if (!aValue.isEmpty())
+ {
+ int left, top, width, height;
+
+ if (sscanf(aValue.data(), "%d,%d,%d,%d", &left, &top, &width, &height) == 4)
+ {
+ return QRect(left, top, width, height);
+ }
+ }
+ if (pDefault)
+ return *pDefault;
+ return QRect();
+}
+
+
+QPoint KConfigBase::readPointEntry( const QString& pKey,
+ const QPoint* pDefault ) const
+{
+ return readPointEntry(pKey.utf8().data(), pDefault);
+}
+
+QPoint KConfigBase::readPointEntry( const char *pKey,
+ const QPoint* pDefault ) const
+{
+ QCString aValue = readEntryUtf8(pKey);
+
+ if (!aValue.isEmpty())
+ {
+ int x,y;
+
+ if (sscanf(aValue.data(), "%d,%d", &x, &y) == 2)
+ {
+ return QPoint(x,y);
+ }
+ }
+ if (pDefault)
+ return *pDefault;
+ return QPoint();
+}
+
+QSize KConfigBase::readSizeEntry( const QString& pKey,
+ const QSize* pDefault ) const
+{
+ return readSizeEntry(pKey.utf8().data(), pDefault);
+}
+
+QSize KConfigBase::readSizeEntry( const char *pKey,
+ const QSize* pDefault ) const
+{
+ QCString aValue = readEntryUtf8(pKey);
+
+ if (!aValue.isEmpty())
+ {
+ int width,height;
+
+ if (sscanf(aValue.data(), "%d,%d", &width, &height) == 2)
+ {
+ return QSize(width, height);
+ }
+ }
+ if (pDefault)
+ return *pDefault;
+ return QSize();
+}
+
+
+QColor KConfigBase::readColorEntry( const QString& pKey,
+ const QColor* pDefault ) const
+{
+ return readColorEntry(pKey.utf8().data(), pDefault);
+}
+
+QColor KConfigBase::readColorEntry( const char *pKey,
+ const QColor* pDefault ) const
+{
+ QColor aRetColor;
+ int nRed = 0, nGreen = 0, nBlue = 0;
+
+ QString aValue = readEntry( pKey );
+ if( !aValue.isEmpty() )
+ {
+ if ( aValue.at(0) == '#' )
+ {
+ aRetColor.setNamedColor(aValue);
+ }
+ else
+ {
+
+ bool bOK;
+
+ // find first part (red)
+ int nIndex = aValue.find( ',' );
+
+ if( nIndex == -1 ){
+ // return a sensible default -- Bernd
+ if( pDefault )
+ aRetColor = *pDefault;
+ return aRetColor;
+ }
+
+ nRed = aValue.left( nIndex ).toInt( &bOK );
+
+ // find second part (green)
+ int nOldIndex = nIndex;
+ nIndex = aValue.find( ',', nOldIndex+1 );
+
+ if( nIndex == -1 ){
+ // return a sensible default -- Bernd
+ if( pDefault )
+ aRetColor = *pDefault;
+ return aRetColor;
+ }
+ nGreen = aValue.mid( nOldIndex+1,
+ nIndex-nOldIndex-1 ).toInt( &bOK );
+
+ // find third part (blue)
+ nBlue = aValue.right( aValue.length()-nIndex-1 ).toInt( &bOK );
+
+ aRetColor.setRgb( nRed, nGreen, nBlue );
+ }
+ }
+ else {
+
+ if( pDefault )
+ aRetColor = *pDefault;
+ }
+
+ return aRetColor;
+}
+
+
+QDateTime KConfigBase::readDateTimeEntry( const QString& pKey,
+ const QDateTime* pDefault ) const
+{
+ return readDateTimeEntry(pKey.utf8().data(), pDefault);
+}
+
+// ### currentDateTime() as fallback ? (Harri)
+QDateTime KConfigBase::readDateTimeEntry( const char *pKey,
+ const QDateTime* pDefault ) const
+{
+ if( !hasKey( pKey ) )
+ {
+ if( pDefault )
+ return *pDefault;
+ else
+ return QDateTime::currentDateTime();
+ }
+
+ QStrList list;
+ int count = readListEntry( pKey, list, ',' );
+ if( count == 6 ) {
+ QDate date( atoi( list.at( 0 ) ), atoi( list.at( 1 ) ),
+ atoi( list.at( 2 ) ) );
+ QTime time( atoi( list.at( 3 ) ), atoi( list.at( 4 ) ),
+ atoi( list.at( 5 ) ) );
+
+ return QDateTime( date, time );
+ }
+
+ return QDateTime::currentDateTime();
+}
+
+void KConfigBase::writeEntry( const QString& pKey, const QString& value,
+ bool bPersistent,
+ bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), value, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QString& value,
+ bool bPersistent,
+ bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey, value, bPersistent, bGlobal, bNLS, false);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QString& value,
+ bool bPersistent,
+ bool bGlobal,
+ bool bNLS,
+ bool bExpand )
+{
+ // the KConfig object is dirty now
+ // set this before any IO takes place so that if any derivative
+ // classes do caching, they won't try and flush the cache out
+ // from under us before we read. A race condition is still
+ // possible but minimized.
+ if( bPersistent )
+ setDirty(true);
+
+ if (!bLocaleInitialized && KGlobal::locale())
+ setLocale();
+
+ KEntryKey entryKey(mGroup, pKey);
+ entryKey.bLocal = bNLS;
+
+ KEntry aEntryData;
+ aEntryData.mValue = value.utf8(); // set new value
+ aEntryData.bGlobal = bGlobal;
+ aEntryData.bNLS = bNLS;
+ aEntryData.bExpand = bExpand;
+
+ if (bPersistent)
+ aEntryData.bDirty = true;
+
+ // rewrite the new value
+ putData(entryKey, aEntryData, true);
+}
+
+void KConfigBase::writePathEntry( const QString& pKey, const QString & path,
+ bool bPersistent, bool bGlobal,
+ bool bNLS)
+{
+ writePathEntry(pKey.utf8().data(), path, bPersistent, bGlobal, bNLS);
+}
+
+
+static bool cleanHomeDirPath( QString &path, const QString &homeDir )
+{
+#ifdef Q_WS_WIN //safer
+ if (!QDir::convertSeparators(path).startsWith(QDir::convertSeparators(homeDir)))
+ return false;
+#else
+ if (!path.startsWith(homeDir))
+ return false;
+#endif
+
+ unsigned int len = homeDir.length();
+ // replace by "$HOME" if possible
+ if (len && (path.length() == len || path[len] == '/')) {
+ path.replace(0, len, QString::fromLatin1("$HOME"));
+ return true;
+ } else
+ return false;
+}
+
+static QString translatePath( QString path )
+{
+ if (path.isEmpty())
+ return path;
+
+ // only "our" $HOME should be interpreted
+ path.replace('$', "$$");
+
+ bool startsWithFile = path.startsWith("file:", false);
+
+ // return original path, if it refers to another type of URL (e.g. http:/), or
+ // if the path is already relative to another directory
+ if (!startsWithFile && path[0] != '/' ||
+ startsWithFile && path[5] != '/')
+ return path;
+
+ if (startsWithFile)
+ path.remove(0,5); // strip leading "file:/" off the string
+
+ // keep only one single '/' at the beginning - needed for cleanHomeDirPath()
+ while (path[0] == '/' && path[1] == '/')
+ path.remove(0,1);
+
+ // we can not use KGlobal::dirs()->relativeLocation("home", path) here,
+ // since it would not recognize paths without a trailing '/'.
+ // All of the 3 following functions to return the user's home directory
+ // can return different paths. We have to test all them.
+ QString homeDir0 = QFile::decodeName(getenv("HOME"));
+ QString homeDir1 = QDir::homeDirPath();
+ QString homeDir2 = QDir(homeDir1).canonicalPath();
+ if (cleanHomeDirPath(path, homeDir0) ||
+ cleanHomeDirPath(path, homeDir1) ||
+ cleanHomeDirPath(path, homeDir2) ) {
+ // kdDebug() << "Path was replaced\n";
+ }
+
+ if (startsWithFile)
+ path.prepend( "file://" );
+
+ return path;
+}
+
+void KConfigBase::writePathEntry( const char *pKey, const QString & path,
+ bool bPersistent, bool bGlobal,
+ bool bNLS)
+{
+ writeEntry(pKey, translatePath(path), bPersistent, bGlobal, bNLS, true);
+}
+
+void KConfigBase::writePathEntry ( const QString& pKey, const QStringList &list,
+ char sep , bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ writePathEntry(pKey.utf8().data(), list, sep, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writePathEntry ( const char *pKey, const QStringList &list,
+ char sep , bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ if( list.isEmpty() )
+ {
+ writeEntry( pKey, QString::fromLatin1(""), bPersistent );
+ return;
+ }
+ QStringList new_list;
+ QStringList::ConstIterator it = list.begin();
+ for( ; it != list.end(); ++it )
+ {
+ QString value = *it;
+ new_list.append( translatePath(value) );
+ }
+ writeEntry( pKey, new_list, sep, bPersistent, bGlobal, bNLS, true );
+}
+
+void KConfigBase::deleteEntry( const QString& pKey,
+ bool bNLS,
+ bool bGlobal)
+{
+ deleteEntry(pKey.utf8().data(), bNLS, bGlobal);
+}
+
+void KConfigBase::deleteEntry( const char *pKey,
+ bool bNLS,
+ bool bGlobal)
+{
+ // the KConfig object is dirty now
+ // set this before any IO takes place so that if any derivative
+ // classes do caching, they won't try and flush the cache out
+ // from under us before we read. A race condition is still
+ // possible but minimized.
+ setDirty(true);
+
+ if (!bLocaleInitialized && KGlobal::locale())
+ setLocale();
+
+ KEntryKey entryKey(mGroup, pKey);
+ KEntry aEntryData;
+
+ aEntryData.bGlobal = bGlobal;
+ aEntryData.bNLS = bNLS;
+ aEntryData.bDirty = true;
+ aEntryData.bDeleted = true;
+
+ // rewrite the new value
+ putData(entryKey, aEntryData, true);
+}
+
+bool KConfigBase::deleteGroup( const QString& group, bool bDeep, bool bGlobal )
+{
+ KEntryMap aEntryMap = internalEntryMap(group);
+
+ if (!bDeep) {
+ // Check if it empty
+ return aEntryMap.isEmpty();
+ }
+
+ bool dirty = false;
+ bool checkGroup = true;
+ // we want to remove all entries in the group
+ KEntryMapIterator aIt;
+ for (aIt = aEntryMap.begin(); aIt != aEntryMap.end(); ++aIt)
+ {
+ if (!aIt.key().mKey.isEmpty() && !aIt.key().bDefault && !(*aIt).bDeleted)
+ {
+ (*aIt).bDeleted = true;
+ (*aIt).bDirty = true;
+ (*aIt).bGlobal = bGlobal;
+ (*aIt).mValue = 0;
+ putData(aIt.key(), *aIt, checkGroup);
+ checkGroup = false;
+ dirty = true;
+ }
+ }
+ if (dirty)
+ setDirty(true);
+ return true;
+}
+
+void KConfigBase::writeEntry ( const QString& pKey, const QVariant &prop,
+ bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), prop, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry ( const char *pKey, const QVariant &prop,
+ bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ switch( prop.type() )
+ {
+ case QVariant::Invalid:
+ writeEntry( pKey, "", bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::String:
+ writeEntry( pKey, prop.toString(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::StringList:
+ writeEntry( pKey, prop.toStringList(), ',', bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::List: {
+ QValueList<QVariant> list = prop.toList();
+ QValueList<QVariant>::ConstIterator it = list.begin();
+ QValueList<QVariant>::ConstIterator end = list.end();
+ QStringList strList;
+
+ for (; it != end; ++it )
+ strList.append( (*it).toString() );
+
+ writeEntry( pKey, strList, ',', bPersistent, bGlobal, bNLS );
+
+ return;
+ }
+ case QVariant::Font:
+ writeEntry( pKey, prop.toFont(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::Point:
+ writeEntry( pKey, prop.toPoint(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::Rect:
+ writeEntry( pKey, prop.toRect(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::Size:
+ writeEntry( pKey, prop.toSize(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::Color:
+ writeEntry( pKey, prop.toColor(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::Int:
+ writeEntry( pKey, prop.toInt(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::UInt:
+ writeEntry( pKey, prop.toUInt(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::LongLong:
+ writeEntry( pKey, prop.toLongLong(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::ULongLong:
+ writeEntry( pKey, prop.toULongLong(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::Bool:
+ writeEntry( pKey, prop.toBool(), bPersistent, bGlobal, bNLS );
+ return;
+ case QVariant::Double:
+ writeEntry( pKey, prop.toDouble(), bPersistent, bGlobal, 'g', 6, bNLS );
+ return;
+ case QVariant::DateTime:
+ writeEntry( pKey, prop.toDateTime(), bPersistent, bGlobal, bNLS);
+ return;
+ case QVariant::Date:
+ writeEntry( pKey, QDateTime(prop.toDate()), bPersistent, bGlobal, bNLS);
+ return;
+
+ case QVariant::Pixmap:
+ case QVariant::Image:
+ case QVariant::Brush:
+ case QVariant::Palette:
+ case QVariant::ColorGroup:
+ case QVariant::Map:
+ case QVariant::IconSet:
+ case QVariant::CString:
+ case QVariant::PointArray:
+ case QVariant::Region:
+ case QVariant::Bitmap:
+ case QVariant::Cursor:
+ case QVariant::SizePolicy:
+ case QVariant::Time:
+ case QVariant::ByteArray:
+ case QVariant::BitArray:
+ case QVariant::KeySequence:
+ case QVariant::Pen:
+ break;
+ }
+
+ Q_ASSERT( 0 );
+}
+
+void KConfigBase::writeEntry ( const QString& pKey, const QStrList &list,
+ char sep , bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), list, sep, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry ( const char *pKey, const QStrList &list,
+ char sep , bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ if( list.isEmpty() )
+ {
+ writeEntry( pKey, QString::fromLatin1(""), bPersistent );
+ return;
+ }
+ QString str_list;
+ QStrListIterator it( list );
+ for( ; it.current(); ++it )
+ {
+ uint i;
+ QString value;
+ // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
+ // A QStrList may contain values in 8bit locale cpecified
+ // encoding or in UTF8 encoding.
+ value = KStringHandler::from8Bit(it.current());
+ uint strLengh(value.length());
+ for( i = 0; i < strLengh; i++ )
+ {
+ if( value[i] == sep || value[i] == '\\' )
+ str_list += '\\';
+ str_list += value[i];
+ }
+ str_list += sep;
+ }
+ if( str_list.at(str_list.length() - 1) == sep )
+ str_list.truncate( str_list.length() -1 );
+ writeEntry( pKey, str_list, bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry ( const QString& pKey, const QStringList &list,
+ char sep , bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), list, sep, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry ( const char *pKey, const QStringList &list,
+ char sep , bool bPersistent,
+ bool bGlobal, bool bNLS )
+{
+ writeEntry(pKey, list, sep, bPersistent, bGlobal, bNLS, false);
+}
+
+void KConfigBase::writeEntry ( const char *pKey, const QStringList &list,
+ char sep, bool bPersistent,
+ bool bGlobal, bool bNLS, bool bExpand )
+{
+ if( list.isEmpty() )
+ {
+ writeEntry( pKey, QString::fromLatin1(""), bPersistent );
+ return;
+ }
+ QString str_list;
+ str_list.reserve( 4096 );
+ QStringList::ConstIterator it = list.begin();
+ for( ; it != list.end(); ++it )
+ {
+ QString value = *it;
+ uint i;
+ uint strLength(value.length());
+ for( i = 0; i < strLength; i++ )
+ {
+ if( value[i] == sep || value[i] == '\\' )
+ str_list += '\\';
+ str_list += value[i];
+ }
+ str_list += sep;
+ }
+ if( str_list.at(str_list.length() - 1) == sep )
+ str_list.truncate( str_list.length() -1 );
+ writeEntry( pKey, str_list, bPersistent, bGlobal, bNLS, bExpand );
+}
+
+void KConfigBase::writeEntry ( const QString& pKey, const QValueList<int> &list,
+ bool bPersistent, bool bGlobal, bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), list, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry ( const char *pKey, const QValueList<int> &list,
+ bool bPersistent, bool bGlobal, bool bNLS )
+{
+ QStringList strlist;
+ QValueList<int>::ConstIterator end = list.end();
+ for (QValueList<int>::ConstIterator it = list.begin(); it != end; it++)
+ strlist << QString::number(*it);
+ writeEntry(pKey, strlist, ',', bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const QString& pKey, int nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const char *pKey, int nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, unsigned int nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const char *pKey, unsigned int nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, long nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const char *pKey, long nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, unsigned long nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const char *pKey, unsigned long nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const QString& pKey, Q_INT64 nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const char *pKey, Q_INT64 nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, Q_UINT64 nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const char *pKey, Q_UINT64 nValue,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue), bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const QString& pKey, double nValue,
+ bool bPersistent, bool bGlobal,
+ char format, int precision,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue, format, precision),
+ bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const char *pKey, double nValue,
+ bool bPersistent, bool bGlobal,
+ char format, int precision,
+ bool bNLS )
+{
+ writeEntry( pKey, QString::number(nValue, format, precision),
+ bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, bool bValue,
+ bool bPersistent,
+ bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), bValue, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, bool bValue,
+ bool bPersistent,
+ bool bGlobal,
+ bool bNLS )
+{
+ QString aValue;
+
+ if( bValue )
+ aValue = "true";
+ else
+ aValue = "false";
+
+ writeEntry( pKey, aValue, bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, const QFont& rFont,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), rFont, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QFont& rFont,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey, rFont.toString(), bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, const QRect& rRect,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), rRect, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QRect& rRect,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ QStrList list;
+ QCString tempstr;
+ list.insert( 0, tempstr.setNum( rRect.left() ) );
+ list.insert( 1, tempstr.setNum( rRect.top() ) );
+ list.insert( 2, tempstr.setNum( rRect.width() ) );
+ list.insert( 3, tempstr.setNum( rRect.height() ) );
+
+ writeEntry( pKey, list, ',', bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, const QPoint& rPoint,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), rPoint, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QPoint& rPoint,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ QStrList list;
+ QCString tempstr;
+ list.insert( 0, tempstr.setNum( rPoint.x() ) );
+ list.insert( 1, tempstr.setNum( rPoint.y() ) );
+
+ writeEntry( pKey, list, ',', bPersistent, bGlobal, bNLS );
+}
+
+
+void KConfigBase::writeEntry( const QString& pKey, const QSize& rSize,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), rSize, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QSize& rSize,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ QStrList list;
+ QCString tempstr;
+ list.insert( 0, tempstr.setNum( rSize.width() ) );
+ list.insert( 1, tempstr.setNum( rSize.height() ) );
+
+ writeEntry( pKey, list, ',', bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const QString& pKey, const QColor& rColor,
+ bool bPersistent,
+ bool bGlobal,
+ bool bNLS )
+{
+ writeEntry( pKey.utf8().data(), rColor, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QColor& rColor,
+ bool bPersistent,
+ bool bGlobal,
+ bool bNLS )
+{
+ QString aValue;
+ if (rColor.isValid())
+ aValue.sprintf( "%d,%d,%d", rColor.red(), rColor.green(), rColor.blue() );
+ else
+ aValue = "invalid";
+
+ writeEntry( pKey, aValue, bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::writeEntry( const QString& pKey, const QDateTime& rDateTime,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ writeEntry(pKey.utf8().data(), rDateTime, bPersistent, bGlobal, bNLS);
+}
+
+void KConfigBase::writeEntry( const char *pKey, const QDateTime& rDateTime,
+ bool bPersistent, bool bGlobal,
+ bool bNLS )
+{
+ QStrList list;
+ QCString tempstr;
+
+ QTime time = rDateTime.time();
+ QDate date = rDateTime.date();
+
+ list.insert( 0, tempstr.setNum( date.year() ) );
+ list.insert( 1, tempstr.setNum( date.month() ) );
+ list.insert( 2, tempstr.setNum( date.day() ) );
+
+ list.insert( 3, tempstr.setNum( time.hour() ) );
+ list.insert( 4, tempstr.setNum( time.minute() ) );
+ list.insert( 5, tempstr.setNum( time.second() ) );
+
+ writeEntry( pKey, list, ',', bPersistent, bGlobal, bNLS );
+}
+
+void KConfigBase::parseConfigFiles()
+{
+ if (!bLocaleInitialized && KGlobal::_locale) {
+ setLocale();
+ }
+ if (backEnd)
+ {
+ backEnd->parseConfigFiles();
+ bReadOnly = (backEnd->getConfigState() == ReadOnly);
+ }
+}
+
+void KConfigBase::sync()
+{
+ if (isReadOnly())
+ return;
+
+ if (backEnd)
+ backEnd->sync();
+ if (bDirty)
+ rollback();
+}
+
+KConfigBase::ConfigState KConfigBase::getConfigState() const {
+ if (backEnd)
+ return backEnd->getConfigState();
+ return ReadOnly;
+}
+
+void KConfigBase::rollback( bool /*bDeep = true*/ )
+{
+ bDirty = false;
+}
+
+
+void KConfigBase::setReadDefaults(bool b)
+{
+ if (!d)
+ {
+ if (!b) return;
+ d = new KConfigBasePrivate();
+ }
+
+ d->readDefaults = b;
+}
+
+bool KConfigBase::readDefaults() const
+{
+ return (d && d->readDefaults);
+}
+
+void KConfigBase::revertToDefault(const QString &key)
+{
+ setDirty(true);
+
+ KEntryKey aEntryKey(mGroup, key.utf8());
+ aEntryKey.bDefault = true;
+
+ if (!locale().isNull()) {
+ // try the localized key first
+ aEntryKey.bLocal = true;
+ KEntry entry = lookupData(aEntryKey);
+ if (entry.mValue.isNull())
+ entry.bDeleted = true;
+
+ entry.bDirty = true;
+ putData(aEntryKey, entry, true); // Revert
+ aEntryKey.bLocal = false;
+ }
+
+ // try the non-localized version
+ KEntry entry = lookupData(aEntryKey);
+ if (entry.mValue.isNull())
+ entry.bDeleted = true;
+ entry.bDirty = true;
+ putData(aEntryKey, entry, true); // Revert
+}
+
+bool KConfigBase::hasDefault(const QString &key) const
+{
+ KEntryKey aEntryKey(mGroup, key.utf8());
+ aEntryKey.bDefault = true;
+
+ if (!locale().isNull()) {
+ // try the localized key first
+ aEntryKey.bLocal = true;
+ KEntry entry = lookupData(aEntryKey);
+ if (!entry.mValue.isNull())
+ return true;
+
+ aEntryKey.bLocal = false;
+ }
+
+ // try the non-localized version
+ KEntry entry = lookupData(aEntryKey);
+ if (!entry.mValue.isNull())
+ return true;
+
+ return false;
+}
+
+
+
+KConfigGroup::KConfigGroup(KConfigBase *master, const QString &group)
+{
+ mMaster = master;
+ backEnd = mMaster->backEnd; // Needed for getConfigState()
+ bLocaleInitialized = true;
+ bReadOnly = mMaster->bReadOnly;
+ bExpand = false;
+ bDirty = false; // Not used
+ mGroup = group.utf8();
+ aLocaleString = mMaster->aLocaleString;
+ setReadDefaults(mMaster->readDefaults());
+}
+
+KConfigGroup::KConfigGroup(KConfigBase *master, const QCString &group)
+{
+ mMaster = master;
+ backEnd = mMaster->backEnd; // Needed for getConfigState()
+ bLocaleInitialized = true;
+ bReadOnly = mMaster->bReadOnly;
+ bExpand = false;
+ bDirty = false; // Not used
+ mGroup = group;
+ aLocaleString = mMaster->aLocaleString;
+ setReadDefaults(mMaster->readDefaults());
+}
+
+KConfigGroup::KConfigGroup(KConfigBase *master, const char * group)
+{
+ mMaster = master;
+ backEnd = mMaster->backEnd; // Needed for getConfigState()
+ bLocaleInitialized = true;
+ bReadOnly = mMaster->bReadOnly;
+ bExpand = false;
+ bDirty = false; // Not used
+ mGroup = group;
+ aLocaleString = mMaster->aLocaleString;
+ setReadDefaults(mMaster->readDefaults());
+}
+
+void KConfigGroup::deleteGroup(bool bGlobal)
+{
+ mMaster->deleteGroup(KConfigBase::group(), true, bGlobal);
+}
+
+bool KConfigGroup::groupIsImmutable() const
+{
+ return mMaster->groupIsImmutable(KConfigBase::group());
+}
+
+void KConfigGroup::setDirty(bool _bDirty)
+{
+ mMaster->setDirty(_bDirty);
+}
+
+void KConfigGroup::putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup)
+{
+ mMaster->putData(_key, _data, _checkGroup);
+}
+
+KEntry KConfigGroup::lookupData(const KEntryKey &_key) const
+{
+ return mMaster->lookupData(_key);
+}
+
+void KConfigGroup::sync()
+{
+ mMaster->sync();
+}
+
+void KConfigBase::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KConfigGroup::virtual_hook( int id, void* data )
+{ KConfigBase::virtual_hook( id, data ); }
+
+bool KConfigBase::checkConfigFilesWritable(bool warnUser)
+{
+ if (backEnd)
+ return backEnd->checkConfigFilesWritable(warnUser);
+ else
+ return false;
+}
+
+#include "kconfigbase.moc"
diff --git a/kdecore/kconfigbase.h b/kdecore/kconfigbase.h
new file mode 100644
index 000000000..a393b4d87
--- /dev/null
+++ b/kdecore/kconfigbase.h
@@ -0,0 +1,2178 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+ Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KCONFIGBASE_H
+#define _KCONFIGBASE_H
+
+#include <qobject.h>
+#include <qcolor.h>
+#include <qfont.h>
+#include <qdatetime.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qvariant.h>
+#include <qmap.h>
+
+#include "kconfigdata.h"
+#include "kdelibs_export.h"
+
+class KConfigBackEnd;
+class KConfigBasePrivate;
+class KConfigGroup;
+
+/**
+ * @short KDE Configuration Management abstract base class
+ *
+ * This class forms the base for all %KDE configuration. It is an
+ * abstract base class, meaning that you cannot directly instantiate
+ * objects of this class. Either use KConfig (for usual %KDE
+ * configuration) or KSimpleConfig (for special needs as in ksamba), or
+ * even KSharedConfig (stores values in shared memory).
+ *
+ * All configuration entries are key, value pairs. Each entry also
+ * belongs to a specific group of related entries. All configuration
+ * entries that do not explicitly specify which group they are in are
+ * in a special group called the default group.
+ *
+ * If there is a $ character in an entry, KConfigBase tries to expand
+ * environment variable and uses its value instead of its name. You
+ * can avoid this feature by having two consecutive $ characters in
+ * your config file which get expanded to one.
+ *
+ * \note the '=' char is not allowed in keys and the ']' char is not allowed in
+ * a group name.
+ *
+ * @author Kalle Dalheimer <kalle@kde.org>, Preston Brown <pbrown@kde.org>
+ * @see KGlobal#config()
+ * @see KConfig
+ * @see KSimpleConfig
+ * @see KSharedConfig
+ */
+class KDECORE_EXPORT KConfigBase : public QObject
+{
+ Q_OBJECT
+
+ friend class KConfigBackEnd;
+ friend class KConfigINIBackEnd;
+ friend class KConfigGroup;
+
+public:
+ /**
+ * Construct a KConfigBase object.
+ */
+ KConfigBase();
+
+ /**
+ * Destructs the KConfigBase object.
+ */
+ virtual ~KConfigBase();
+
+ /**
+ * Specifies the group in which keys will be read and written.
+ *
+ * Subsequent
+ * calls to readEntry() and writeEntry() will be applied only in the
+ * activated group.
+ *
+ * Switch back to the default group by passing a null string.
+ * @param group The name of the new group.
+ */
+ void setGroup( const QString& group );
+
+ /**
+ * Sets the group to the "Desktop Entry" group used for
+ * desktop configuration files for applications, mime types, etc.
+ */
+ void setDesktopGroup();
+
+ /**
+ * Returns the name of the group in which we are
+ * searching for keys and from which we are retrieving entries.
+ *
+ * @return The current group.
+ */
+ QString group() const;
+
+ /**
+ * Returns true if the specified group is known about.
+ *
+ * @param group The group to search for.
+ * @return true if the group exists.
+ */
+ bool hasGroup(const QString &group) const;
+
+ /**
+ * Returns a list of groups that are known about.
+ *
+ * @return The list of groups.
+ **/
+ virtual QStringList groupList() const = 0;
+
+ /**
+ * Returns a the current locale.
+ *
+ * @return A string representing the current locale.
+ */
+ QString locale() const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ * If you want to read a path, please use readPathEntry().
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found.
+ * @return The value for this key. Can be QString::null if aDefault is null.
+ */
+ QString readEntry(const QString& pKey,
+ const QString& aDefault = QString::null ) const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found.
+ * @return The value for this key. Can be QString::null if aDefault is null.
+ */
+ QString readEntry(const char *pKey,
+ const QString& aDefault = QString::null ) const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ * The value is treated as if it is of the given type.
+ *
+ * Note that only the following QVariant types are allowed : String,
+ * StringList, List, Font, Point, Rect, Size, Color, Int, UInt, Bool,
+ * Double, DateTime and Date.
+ * @deprecated
+ *
+ * @param pKey The key to search for.
+ * @return An invalid QVariant if the key was not found or if the
+ * read value cannot be converted to the given QVariant::Type.
+ */
+ QVariant readPropertyEntry( const QString& pKey, QVariant::Type ) const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ * The value is treated as if it is of the given type.
+ *
+ * Note that only the following QVariant types are allowed : String,
+ * StringList, List, Font, Point, Rect, Size, Color, Int, UInt, Bool,
+ * Double, DateTime and Date.
+ *
+ * @deprecated
+ *
+ * @param pKey The key to search for.
+ * @return An invalid QVariant if the key was not found or if the
+ * read value cannot be converted to the given QVariant::Type.
+ */
+ QVariant readPropertyEntry( const char *pKey, QVariant::Type ) const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ * The value is treated as if it is of the type of the given default value.
+ *
+ * Note that only the following QVariant types are allowed : String,
+ * StringList, List, Font, Point, Rect, Size, Color, Int, UInt, Bool,
+ * Double, DateTime and Date.
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found or
+ * if the read value cannot be converted to the QVariant::Type.
+ * @return The value for the key or the default value if the key was not
+ * found.
+ */
+ QVariant readPropertyEntry( const QString& pKey,
+ const QVariant &aDefault) const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ * The value is treated as if it is of the type of the given default value.
+ *
+ * Note that only the following QVariant types are allowed : String,
+ * StringList, List, Font, Point, Rect, Size, Color, Int, UInt, Bool,
+ * Double, DateTime and Date.
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found or
+ * if the read value cannot be converted to the QVariant::Type.
+ * @return The value for the key or the default value if the key was not
+ * found.
+ */
+ QVariant readPropertyEntry( const char *pKey,
+ const QVariant &aDefault) const;
+
+ /**
+ * Reads a list of strings.
+ *
+ * @deprecated
+ *
+ * @param pKey The key to search for
+ * @param list In this object, the read list will be returned.
+ * @param sep The list separator (default ",")
+ * @return The number of entries in the list.
+ */
+ int readListEntry( const QString& pKey, QStrList &list, char sep = ',' ) const;
+
+ /**
+ * Reads a list of strings.
+ *
+ * @deprecated
+ *
+ * @param pKey The key to search for
+ * @param list In this object, the read list will be returned.
+ * @param sep The list separator (default ",")
+ * @return The number of entries in the list.
+ */
+ int readListEntry( const char *pKey, QStrList &list, char sep = ',' ) const;
+
+ /**
+ * Reads a list of strings.
+ *
+ * @param pKey The key to search for.
+ * @param sep The list separator (default is ",").
+ * @return The list. Empty if the entry does not exist.
+ */
+ QStringList readListEntry( const QString& pKey, char sep = ',' ) const;
+
+ /**
+ * Reads a list of strings.
+ *
+ * @param pKey The key to search for.
+ * @param sep The list separator (default is ",").
+ * @return The list. Empty if the entry does not exist.
+ */
+ QStringList readListEntry( const char *pKey, char sep = ',' ) const;
+
+ /**
+ * Reads a list of strings, but returns a default if the key
+ * did not exist.
+ * @param pKey The key to search for.
+ * @param aDefault The default value to use if the key does not exist.
+ * @param sep The list separator (default is ",").
+ * @return The list. Contains @p aDefault if the Key does not exist.
+ * @since 3.3
+ */
+ QStringList readListEntry( const char* pKey, const QStringList& aDefault,
+ char sep = ',' ) const;
+
+ /**
+ * Reads a list of Integers.
+ *
+ * @param pKey The key to search for.
+ * @return The list. Empty if the entry does not exist.
+ */
+ QValueList<int> readIntListEntry( const QString& pKey ) const;
+
+ /**
+ * Reads a list of Integers.
+ *
+ * @param pKey The key to search for.
+ * @return The list. Empty if the entry does not exist.
+ */
+ QValueList<int> readIntListEntry( const char *pKey ) const;
+
+ /**
+ * Reads a path.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a path. This means, dollar expansion is activated
+ * for this value, so that e.g. $HOME gets expanded.
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found.
+ * @return The value for this key. Can be QString::null if aDefault is null.
+ */
+ QString readPathEntry( const QString& pKey, const QString & aDefault = QString::null ) const;
+
+ /**
+ * Reads a path.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a path. This means, dollar expansion is activated
+ * for this value, so that e.g. $HOME gets expanded.
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found.
+ * @return The value for this key. Can be QString::null if aDefault is null.
+ */
+ QString readPathEntry( const char *pKey, const QString & aDefault = QString::null ) const;
+
+ /**
+ * Reads a list of string paths.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a list of paths. This means, dollar expansion is activated
+ * for this value, so that e.g. $HOME gets expanded.
+ *
+ * @param pKey The key to search for.
+ * @param sep The list separator (default is ",").
+ * @return The list. Empty if the entry does not exist.
+ * @since 3.1.3
+ */
+ QStringList readPathListEntry( const QString& pKey, char sep = ',' ) const;
+
+ /**
+ * Reads a list of string paths.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a list of paths. This means, dollar expansion is activated
+ * for this value, so that e.g. $HOME gets expanded.
+ *
+ * @param pKey The key to search for.
+ * @param sep The list separator (default is ",").
+ * @return The list. Empty if the entry does not exist.
+ * @since 3.1.3
+ */
+ QStringList readPathListEntry( const char *pKey, char sep = ',' ) const;
+
+
+ /**
+ * Reads a numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ int readNumEntry( const QString& pKey, int nDefault = 0 ) const;
+
+ /**
+ * Reads a numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ int readNumEntry( const char *pKey, int nDefault = 0 ) const;
+
+ /**
+ * Reads an unsigned numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ unsigned int readUnsignedNumEntry( const QString& pKey, unsigned int nDefault = 0 ) const;
+
+ /**
+ * Reads an unsigned numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ unsigned int readUnsignedNumEntry( const char *pKey, unsigned int nDefault = 0 ) const;
+
+
+ /**
+ * Reads a numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ long readLongNumEntry( const QString& pKey, long nDefault = 0 ) const;
+
+ /**
+ * Reads a numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ long readLongNumEntry( const char *pKey, long nDefault = 0 ) const;
+
+ /**
+ * Read an unsigned numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ unsigned long readUnsignedLongNumEntry( const QString& pKey, unsigned long nDefault = 0 ) const;
+
+ /**
+ * Read an unsigned numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ unsigned long readUnsignedLongNumEntry( const char *pKey, unsigned long nDefault = 0 ) const;
+
+ /**
+ * Reads a 64-bit numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ Q_INT64 readNum64Entry( const QString& pKey, Q_INT64 nDefault = 0 ) const;
+
+ /**
+ * Reads a 64-bit numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ Q_INT64 readNum64Entry( const char *pKey, Q_INT64 nDefault = 0 ) const;
+
+ /**
+ * Read an 64-bit unsigned numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ Q_UINT64 readUnsignedNum64Entry( const QString& pKey, Q_UINT64 nDefault = 0 ) const;
+
+ /**
+ * Read an 64-bit unsigned numerical value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ Q_UINT64 readUnsignedNum64Entry( const char *pKey, Q_UINT64 nDefault = 0 ) const;
+
+ /**
+ * Reads a floating point value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ double readDoubleNumEntry( const QString& pKey, double nDefault = 0.0 ) const;
+
+ /**
+ * Reads a floating point value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it numerically.
+ *
+ * @param pKey The key to search for.
+ * @param nDefault A default value returned if the key was not found or if
+ * the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ double readDoubleNumEntry( const char *pKey, double nDefault = 0.0 ) const;
+
+ /**
+ * Reads a QFont value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a font object.
+ *
+ * @param pKey The key to search for.
+ * @param pDefault A default value (null QFont by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QFont readFontEntry( const QString& pKey, const QFont* pDefault = 0L ) const;
+
+ /**
+ * Reads a QFont value.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a font object.
+ *
+ * @param pKey The key to search for.
+ * @param pDefault A default value (null QFont by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QFont readFontEntry( const char *pKey, const QFont* pDefault = 0L ) const;
+
+ /**
+ * Reads a boolean entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a boolean value. Currently "on", "yes", "1" and
+ * "true" are accepted as true, everything else if false.
+ *
+ * @param pKey The key to search for
+ * @param bDefault A default value returned if the key was not found.
+ * @return The value for this key.
+ */
+ bool readBoolEntry( const QString& pKey, bool bDefault = false ) const;
+
+ /**
+ * Reads a boolean entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a boolean value. Currently "on", "yes", "1" and
+ * "true" are accepted as true, everything else if false.
+ *
+ * @param pKey The key to search for
+ * @param bDefault A default value returned if the key was not found.
+ * @return The value for this key.
+ */
+ bool readBoolEntry( const char *pKey, bool bDefault = false ) const;
+
+ /**
+ * Reads a QRect entry.
+ *
+ * Read the value of an entry specified by pKey in the current group
+ * and interpret it as a QRect object.
+ *
+ * @param pKey The key to search for
+ * @param pDefault A default value (null QRect by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QRect readRectEntry( const QString& pKey, const QRect* pDefault = 0L ) const;
+
+ /**
+ * Reads a QRect entry.
+ *
+ * Read the value of an entry specified by pKey in the current group
+ * and interpret it as a QRect object.
+ *
+ * @param pKey The key to search for
+ * @param pDefault A default value (null QRect by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QRect readRectEntry( const char *pKey, const QRect* pDefault = 0L ) const;
+
+ /**
+ * Reads a QPoint entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a QPoint object.
+ *
+ * @param pKey The key to search for
+ * @param pDefault A default value (null QPoint by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QPoint readPointEntry( const QString& pKey, const QPoint* pDefault = 0L ) const;
+
+ /**
+ * Reads a QPoint entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a QPoint object.
+ *
+ * @param pKey The key to search for
+ * @param pDefault A default value (null QPoint by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QPoint readPointEntry( const char *pKey, const QPoint* pDefault = 0L ) const;
+
+ /**
+ * Reads a QSize entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a QSize object.
+ *
+ * @param pKey The key to search for
+ * @param pDefault A default value (null QSize by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QSize readSizeEntry( const QString& pKey, const QSize* pDefault = 0L ) const;
+
+ /**
+ * Reads a QSize entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a QSize object.
+ *
+ * @param pKey The key to search for
+ * @param pDefault A default value (null QSize by default) returned if the
+ * key was not found or if the read value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QSize readSizeEntry( const char *pKey, const QSize* pDefault = 0L ) const;
+
+
+ /**
+ * Reads a QColor entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a color.
+ *
+ * @param pKey The key to search for.
+ * @param pDefault A default value (null QColor by default) returned if the
+ * key was not found or if the value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QColor readColorEntry( const QString& pKey, const QColor* pDefault = 0L ) const;
+
+ /**
+ * Reads a QColor entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a color.
+ *
+ * @param pKey The key to search for.
+ * @param pDefault A default value (null QColor by default) returned if the
+ * key was not found or if the value cannot be interpreted.
+ * @return The value for this key.
+ */
+ QColor readColorEntry( const char *pKey, const QColor* pDefault = 0L ) const;
+
+ /**
+ * Reads a QDateTime entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a date and time.
+ *
+ * @param pKey The key to search for.
+ * @param pDefault A default value ( currentDateTime() by default)
+ * returned if the key was not found or if the read value cannot be
+ * interpreted.
+ * @return The value for this key.
+ */
+ QDateTime readDateTimeEntry( const QString& pKey, const QDateTime* pDefault = 0L ) const;
+
+ /**
+ * Reads a QDateTime entry.
+ *
+ * Read the value of an entry specified by @p pKey in the current group
+ * and interpret it as a date and time.
+ *
+ * @param pKey The key to search for.
+ * @param pDefault A default value ( currentDateTime() by default)
+ * returned if the key was not found or if the read value cannot be
+ * interpreted.
+ * @return The value for this key.
+ */
+ QDateTime readDateTimeEntry( const char *pKey, const QDateTime* pDefault = 0L ) const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ * The untranslated entry is returned, you normally do not need this.
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found.
+ * @return The value for this key.
+ */
+ QString readEntryUntranslated( const QString& pKey,
+ const QString& aDefault = QString::null ) const;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group.
+ * The untranslated entry is returned, you normally do not need this.
+ *
+ * @param pKey The key to search for.
+ * @param aDefault A default value returned if the key was not found.
+ * @return The value for this key.
+ */
+ QString readEntryUntranslated( const char *pKey,
+ const QString& aDefault = QString::null ) const;
+
+ /**
+ * Writes a key/value pair.
+ *
+ * This is stored in the most specific config file when destroying the
+ * config object or when calling sync().
+ *
+ * If you want to write a path, please use writePathEntry().
+ *
+ * @param pKey The key to write.
+ * @param pValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will
+ * not be written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const QString& pValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a key/value pair.
+ *
+ * This is stored in the most specific config file when destroying the
+ * config object or when calling sync().
+ *
+ * @param pKey The key to write.
+ * @param pValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will
+ * not be written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const QString& pValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * writeEntry() Overridden to accept a property.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The property to write
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const QString& pKey, const QVariant& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * writeEntry() Overridden to accept a property.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The property to write
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const char *pKey, const QVariant& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * writeEntry() overridden to accept a list of strings.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param sep The list separator (default is ",").
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const QString& pKey, const QStrList &rValue,
+ char sep = ',', bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+ /**
+ * writeEntry() overridden to accept a list of strings.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param sep The list separator (default is ",").
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const char *pKey, const QStrList &rValue,
+ char sep = ',', bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+
+ /**
+ * writeEntry() overridden to accept a list of strings.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param sep The list separator (default is ",").
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const QString& pKey, const QStringList &rValue,
+ char sep = ',', bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+ /**
+ * writeEntry() overridden to accept a list of strings.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param sep The list separator (default is ",").
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const char *pKey, const QStringList &rValue,
+ char sep = ',', bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+
+
+ /**
+ * writeEntry() overridden to accept a list of Integers.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const QString& pKey, const QValueList<int>& rValue,
+ bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+ /**
+ * writeEntry() overridden to accept a list of Integers.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writeEntry()
+ */
+ void writeEntry( const char *pKey, const QValueList<int>& rValue,
+ bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+
+ /**
+ * Write a (key/value) pair.
+ *
+ * This is stored to the most specific config file when destroying the
+ * config object or when calling sync().
+ *
+ * @param pKey The key to write.
+ * @param pValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will
+ * not be written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const char *pValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false )
+ { writeEntry(pKey, QString::fromLatin1(pValue), bPersistent, bGlobal, bNLS); }
+ /**
+ * Write a (key/value) pair.
+ *
+ * This is stored to the most specific config file when destroying the
+ * config object or when calling sync().
+ *
+ * @param pKey The key to write.
+ * @param pValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will
+ * not be written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const char *pValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false )
+ { writeEntry(pKey, QString::fromLatin1(pValue), bPersistent, bGlobal, bNLS); }
+
+ /**
+ * Write a (key/value) pair.
+ * Same as above, but writes a numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, int nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Write a (key/value) pair.
+ * Same as above, but writes a numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, int nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes an unsigned numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, unsigned int nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes an unsigned numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, unsigned int nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but write a long numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, long nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but write a long numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, long nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes an unsigned long numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, unsigned long nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes an unsigned long numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, unsigned long nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but write a 64-bit numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, Q_INT64 nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but write a long numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, Q_INT64 nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes an unsigned 64-bit numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, Q_UINT64 nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes an unsigned 64-bit numerical value.
+ *
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, Q_UINT64 nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a floating-point value.
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param format @p format determines the format to which the value
+ * is converted. Default is 'g'.
+ * @param precision @p precision sets the precision with which the
+ * value is converted. Default is 6 as in QString.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, double nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ char format = 'g', int precision = 6,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a floating-point value.
+ * @param pKey The key to write.
+ * @param nValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param format @p format determines the format to which the value
+ * is converted. Default is 'g'.
+ * @param precision @p precision sets the precision with which the
+ * value is converted. Default is 6 as in QString.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, double nValue,
+ bool bPersistent = true, bool bGlobal = false,
+ char format = 'g', int precision = 6,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a boolean value.
+ *
+ * @param pKey The key to write.
+ * @param bValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, bool bValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a boolean value.
+ *
+ * @param pKey The key to write.
+ * @param bValue The value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, bool bValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a font value.
+ *
+ * @param pKey The key to write.
+ * @param rFont The font value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const QFont& rFont,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a font value.
+ *
+ * @param pKey The key to write.
+ * @param rFont The font value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const QFont& rFont,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but write a color entry.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rColor The color value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const QColor& rColor,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but write a color entry.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rColor The color value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const QColor& rColor,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a date and time entry.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * @em not returned here!
+ *
+ * @param pKey The key to write.
+ * @param rDateTime The date and time value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const QDateTime& rDateTime,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a date and time entry.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * @em not returned here!
+ *
+ * @param pKey The key to write.
+ * @param rDateTime The date and time value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const QDateTime& rDateTime,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a rectangle.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rValue The rectangle value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const QRect& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a rectangle.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rValue The rectangle value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const QRect& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a point.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rValue The point value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const QPoint& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a point.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rValue The point value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const QPoint& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a size.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rValue The size value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const QString& pKey, const QSize& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a (key/value) pair.
+ * Same as above, but writes a size.
+ *
+ * Note: Unlike the other writeEntry() functions, the old value is
+ * _not_ returned here!
+ *
+ * @param pKey The key to write.
+ * @param rValue The size value to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writeEntry( const char *pKey, const QSize& rValue,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * Writes a file path.
+ *
+ * It is checked whether the path is located under $HOME. If so the
+ * path is written out with the user's home-directory replaced with
+ * $HOME. The path should be read back with readPathEntry()
+ *
+ * @param pKey The key to write.
+ * @param path The path to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writePathEntry( const QString& pKey, const QString & path,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+ /**
+ * Writes a file path.
+ *
+ * It is checked whether the path is located under $HOME. If so the
+ * path is written out with the user's home-directory replaced with
+ * $HOME. The path should be read back with readPathEntry()
+ *
+ * @param pKey The key to write.
+ * @param path The path to write.
+ * @param bPersistent If @p bPersistent is false, the entry's dirty
+ * flag will not be set and thus the entry will not be written to
+ * disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ */
+ void writePathEntry( const char *pKey, const QString & path,
+ bool bPersistent = true, bool bGlobal = false,
+ bool bNLS = false );
+
+ /**
+ * writePathEntry() overridden to accept a list of paths (strings).
+ *
+ * It is checked whether the paths are located under $HOME. If so each of
+ * the paths are written out with the user's home-directory replaced with
+ * $HOME. The paths should be read back with readPathListEntry()
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param sep The list separator (default is ",").
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writePathEntry()
+ * @see readPathListEntry()
+ * @since 3.1.3
+ */
+ void writePathEntry( const QString& pKey, const QStringList &rValue,
+ char sep = ',', bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+ /**
+ * writePathEntry() overridden to accept a list of paths (strings).
+ *
+ * It is checked whether the paths are located under $HOME. If so each of
+ * the paths are written out with the user's home-directory replaced with
+ * $HOME. The paths should be read back with readPathListEntry()
+ *
+ * @param pKey The key to write
+ * @param rValue The list to write
+ * @param sep The list separator (default is ",").
+ * @param bPersistent If @p bPersistent is false, the entry's dirty flag
+ * will not be set and thus the entry will not be
+ * written to disk at deletion time.
+ * @param bGlobal If @p bGlobal is true, the pair is not saved to the
+ * application specific config file, but to the
+ * global KDE config file.
+ * @param bNLS If @p bNLS is true, the locale tag is added to the key
+ * when writing it back.
+ *
+ * @see writePathEntry()
+ * @see readPathListEntry()
+ * @since 3.1.3
+ */
+ void writePathEntry( const char *pKey, const QStringList &rValue,
+ char sep = ',', bool bPersistent = true, bool bGlobal = false, bool bNLS = false );
+
+
+ /**
+ * Deletes the entry specified by @p pKey in the current group.
+ *
+ * @param pKey The key to delete.
+ * @param bGlobal If @p bGlobal is true, the pair is not removed from the
+ * application specific config file, but to the global KDE config file.
+ * @param bNLS If @p bNLS is true, the key with the locale tag is removed.
+ */
+ void deleteEntry( const QString& pKey,
+ bool bNLS = false, bool bGlobal = false);
+ /**
+ * Deletes the entry specified by @p pKey in the current group.
+ *
+ * @param pKey The key to delete.
+ * @param bGlobal If @p bGlobal is true, the pair is not removed from the
+ * application specific config file, but from the global KDE config file.
+ * @param bNLS If @p bNLS is true, the key with the locale tag is removed.
+ */
+ void deleteEntry( const char *pKey,
+ bool bNLS = false, bool bGlobal = false);
+
+ /**
+ * Deletes a configuration entry group
+ *
+ * If the group is not empty and bDeep is false, nothing gets
+ * deleted and false is returned.
+ * If this group is the current group and it is deleted, the
+ * current group is undefined and should be set with setGroup()
+ * before the next operation on the configuration object.
+ *
+ * @param group The name of the group
+ * @param bDeep Specify whether non-empty groups should be completely
+ * deleted (including their entries).
+ * @param bGlobal If @p bGlobal is true, the group is not removed from the
+ * application specific config file, but from the global KDE config file.
+ * @return If the group is not empty and bDeep is false,
+ * deleteGroup returns false.
+ */
+ bool deleteGroup( const QString& group, bool bDeep = true, bool bGlobal = false );
+
+
+ /**
+ * Turns on or off "dollar expansion" (see KConfigBase introduction)
+ * when reading config entries.
+ * Dollar sign expansion is initially OFF.
+ *
+ * @param _bExpand Tf true, dollar expansion is turned on.
+ */
+ void setDollarExpansion( bool _bExpand = true ) { bExpand = _bExpand; }
+
+ /**
+ * Returns whether dollar expansion is on or off. It is initially OFF.
+ *
+ * @return true if dollar expansion is on.
+ */
+ bool isDollarExpansion() const { return bExpand; }
+
+ /**
+ * Mark the config object as "clean," i.e. don't write dirty entries
+ * at destruction time. If @p bDeep is false, only the global dirty
+ * flag of the KConfig object gets cleared. If you then call
+ * writeEntry() again, the global dirty flag is set again and all
+ * dirty entries will be written at a subsequent sync() call.
+ *
+ * Classes that derive from KConfigBase should override this
+ * method and implement storage-specific behavior, as well as
+ * calling the KConfigBase::rollback() explicitly in the initializer.
+ *
+ * @param bDeep If true, the dirty flags of all entries are cleared,
+ * as well as the global dirty flag.
+ */
+ virtual void rollback( bool bDeep = true );
+
+ /**
+ * Flushes all changes that currently reside only in memory
+ * back to disk / permanent storage. Dirty configuration entries are
+ * written to the most specific file available.
+ *
+ * Asks the back end to flush out all pending writes, and then calls
+ * rollback(). No changes are made if the object has @p readOnly
+ * status.
+ *
+ * You should call this from your destructor in derivative classes.
+ *
+ * @see rollback(), #isReadOnly()
+ */
+ virtual void sync();
+
+ /**
+ * Checks whether the config file has any dirty (modified) entries.
+ * @return true if the config file has any dirty (modified) entries.
+ */
+ bool isDirty() const { return bDirty; }
+
+ /**
+ * Sets the config object's read-only status.
+ *
+ * @param _ro If true, the config object will not write out any
+ * changes to disk even if it is destroyed or sync() is called.
+ *
+ */
+ virtual void setReadOnly(bool _ro) { bReadOnly = _ro; }
+
+ /**
+ * Returns the read-only status of the config object.
+ *
+ * @return The read-only status.
+ */
+ bool isReadOnly() const { return bReadOnly; }
+
+ /**
+ * Checks whether the key has an entry in the currently active group.
+ * Use this to determine whether a key is not specified for the current
+ * group (hasKey() returns false). Keys with null data are considered
+ * nonexistent.
+ *
+ * @param key The key to search for.
+ * @return If true, the key is available.
+ */
+ bool hasKey( const QString& key ) const;
+
+ /**
+ * Returns a map (tree) of entries for all entries in a particular
+ * group. Only the actual entry string is returned, none of the
+ * other internal data should be included.
+ *
+ * @param group A group to get keys from.
+ * @return A map of entries in the group specified, indexed by key.
+ * The returned map may be empty if the group is not found.
+ * @see QMap
+ */
+ virtual QMap<QString, QString> entryMap(const QString &group) const = 0;
+
+ /**
+ * Reparses all configuration files. This is useful for programs
+ * that use stand alone graphical configuration tools. The base
+ * method implemented here only clears the group list and then
+ * appends the default group.
+ *
+ * Derivative classes should clear any internal data structures and
+ * then simply call parseConfigFiles() when implementing this
+ * method.
+ *
+ * @see parseConfigFiles()
+ */
+ virtual void reparseConfiguration() = 0;
+
+ /**
+ * Checks whether this configuration file can be modified.
+ * @return whether changes may be made to this configuration file.
+ */
+ bool isImmutable() const;
+
+ /**
+ * Checks whether it is possible to change the given group.
+ * @param group the group to check
+ * @return whether changes may be made to @p group in this configuration
+ * file.
+ */
+ bool groupIsImmutable(const QString &group) const;
+
+ /**
+ * Checks whether it is possible to change the given entry.
+ * @param key the key to check
+ * @return whether the entry @p key may be changed in the current group
+ * in this configuration file.
+ */
+ bool entryIsImmutable(const QString &key) const;
+
+ /**
+ * Possible return values for getConfigState().
+ *
+ * @see getConfigState()
+ */
+ enum ConfigState { NoAccess, ReadOnly, ReadWrite };
+
+ /**
+ * Returns the state of the app-config object.
+ *
+ * Possible return values
+ * are NoAccess (the application-specific config file could not be
+ * opened neither read-write nor read-only), ReadOnly (the
+ * application-specific config file is opened read-only, but not
+ * read-write) and ReadWrite (the application-specific config
+ * file is opened read-write).
+ *
+ * @see ConfigState()
+ * @return the state of the app-config object
+ */
+ ConfigState getConfigState() const;
+
+ /**
+ * Check whether the config files are writable.
+ * @param warnUser Warn the user if the configuration files are not writable.
+ * @return Indicates that all of the configuration files used are writable.
+ * @since 3.2
+ */
+ bool checkConfigFilesWritable(bool warnUser);
+
+ /**
+ * When set, all readEntry and readXXXEntry calls return the system
+ * wide (default) values instead of the user's preference.
+ * This is off by default.
+ * @since 3.2
+ */
+ void setReadDefaults(bool b);
+
+ /**
+ * @returns true if all readEntry and readXXXEntry calls return the system
+ * wide (default) values instead of the user's preference.
+ * @since 3.2
+ */
+ bool readDefaults() const;
+
+ /**
+ * Reverts the entry with key @p key in the current group in the
+ * application specific config file to either the system wide (default)
+ * value or the value specified in the global KDE config file.
+ *
+ * To revert entries in the global KDE config file, the global KDE config
+ * file should be opened explicitly in a separate config object.
+ *
+ * @param key The key of the entry to revert.
+ * @since 3.2
+ */
+ void revertToDefault(const QString &key);
+
+ /**
+ * Returns whether a default is specified for an entry in either the
+ * system wide configuration file or the global KDE config file.
+ *
+ * If an application computes a default value at runtime for
+ * a certain entry, e.g. like:
+ * \code
+ * QColor computedDefault = kapp->palette().color(QPalette::Active, QColorGroup::Text)
+ * QColor color = config->readEntry(key, computedDefault);
+ * \encode
+ *
+ * Then it may wish to make the following check before
+ * writing back changes:
+ * \code
+ * if ( (value == computedDefault) && !config->hasDefault(key) )
+ * config->revertToDefault(key)
+ * else
+ * config->writeEntry(key, value)
+ * \endcode
+ *
+ * This ensures that as long as the entry is not modified to differ from
+ * the computed default, the application will keep using the computed default
+ * and will follow changes the computed default makes over time.
+ * @param key The key of the entry to check.
+ * @since 3.2
+ */
+ bool hasDefault(const QString &key) const;
+
+protected:
+ /**
+ * Reads the locale and put in the configuration data struct.
+ * Note that this should be done in the constructor, but this is not
+ * possible due to some mutual dependencies in KApplication::init()
+ */
+ void setLocale();
+
+ /**
+ * Sets the global dirty flag of the config object
+ *
+ * @param _bDirty How to mark the object's dirty status
+ */
+ virtual void setDirty(bool _bDirty = true) { bDirty = _bDirty; }
+
+ /**
+ * Parses all configuration files for a configuration object.
+ *
+ * The actual parsing is done by the associated KConfigBackEnd.
+ */
+ virtual void parseConfigFiles();
+
+ /**
+ * Returns a map (tree) of the entries in the specified group.
+ * This may or may not return all entries that belong to the
+ * config object. The only guarantee that you are given is that
+ * any entries that are dirty (i.e. modified and not yet written back
+ * to the disk) will be contained in the map. Some derivative
+ * classes may choose to return everything.
+ *
+ * Do not use this function, the implementation / return type are
+ * subject to change.
+ *
+ * @param pGroup The group to provide a KEntryMap for.
+ * @return The map of the entries in the group.
+ * @internal
+ */
+ virtual KEntryMap internalEntryMap( const QString& pGroup ) const = 0;
+
+ /**
+ * Returns a map (tree) of the entries in the tree.
+ *
+ * Do not use this function, the implementation / return type are
+ * subject to change.
+ *
+ * @return A map of the entries in the tree.
+ *
+ * @internal
+ *
+ */
+ virtual KEntryMap internalEntryMap() const = 0;
+
+ /**
+ * Inserts a (key/value) pair into the internal storage mechanism of
+ * the configuration object. Classes that derive from KConfigBase
+ * will need to implement this method in a storage-specific manner.
+ *
+ * Do not use this function, the implementation / return type are
+ * subject to change.
+ *
+ * @param _key The key to insert. It contains information both on
+ * the group of the key and the key itself. If the key already
+ * exists, the old value will be replaced.
+ * @param _data the KEntry that is to be stored.
+ * @param _checkGroup When false, assume that the group already exists.
+ * @internal
+ */
+ virtual void putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup = true) = 0;
+
+ /**
+ * Looks up an entry in the config object's internal structure.
+ * Classes that derive from KConfigBase will need to implement this
+ * method in a storage-specific manner.
+ *
+ * Do not use this function, the implementation and return type are
+ * subject to change.
+ *
+ * @param _key The key to look up It contains information both on
+ * the group of the key and the entry's key itself.
+ * @return The KEntry value (data) found for the key. @p KEntry.aValue
+ * will be the null string if nothing was located.
+ * @internal
+ */
+ virtual KEntry lookupData(const KEntryKey &_key) const = 0;
+
+ virtual bool internalHasGroup(const QCString &group) const = 0;
+
+ /**
+ * A back end for loading/saving to disk in a particular format.
+ */
+ KConfigBackEnd *backEnd;
+public:
+ /**
+ * Overloaded public methods:
+ */
+ void setGroup( const QCString &pGroup );
+ void setGroup( const char *pGroup );
+ bool hasGroup(const QCString &_pGroup) const;
+ bool hasGroup(const char *_pGroup) const;
+ bool hasKey( const char *pKey ) const;
+
+protected:
+ QCString readEntryUtf8( const char *pKey) const;
+
+ /**
+ * The currently selected group. */
+ QCString mGroup;
+
+ /**
+ * The locale to retrieve keys under if possible, i.e en_US or fr. */
+ QCString aLocaleString;
+
+ /**
+ * Indicates whether there are any dirty entries in the config object
+ * that need to be written back to disk. */
+ bool bDirty;
+
+ bool bLocaleInitialized;
+ bool bReadOnly; // currently only used by KSimpleConfig
+ mutable bool bExpand; // whether dollar expansion is used
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KConfigBasePrivate;
+ KConfigBasePrivate *d;
+
+ void writeEntry( const char *pKey, const QString &rValue,
+ bool bPersistent, bool bGlobal, bool bNLS, bool bExpand );
+ void writeEntry( const char *pKey, const QStringList &rValue,
+ char sep, bool bPersistent, bool bGlobal, bool bNLS, bool bExpand );
+
+};
+
+class KConfigGroupSaverPrivate;
+
+/**
+ * Helper class to facilitate working with KConfig / KSimpleConfig
+ * groups.
+ *
+ * Careful programmers always set the group of a
+ * KConfig KSimpleConfig object to the group they want to read from
+ * and set it back to the old one of afterwards. This is usually
+ * written as:
+ * \code
+ *
+ * QString oldgroup config->group();
+ * config->setGroup( "TheGroupThatIWant" );
+ * ...
+ * config->writeEntry( "Blah", "Blubb" );
+ *
+ * config->setGroup( oldgroup );
+ * \endcode
+ *
+ * In order to facilitate this task, you can use
+ * KConfigGroupSaver. Simply construct such an object ON THE STACK
+ * when you want to switch to a new group. Then, when the object goes
+ * out of scope, the group will automatically be restored. If you
+ * want to use several different groups within a function or method,
+ * you can still use KConfigGroupSaver: Simply enclose all work with
+ * one group (including the creation of the KConfigGroupSaver object)
+ * in one block.
+ *
+ * @deprecated This class is deprecated and will be removed in KDE 4.
+ * KConfigGroup provides similar functionality in a more object oriented
+ * way.
+ *
+ * @author Matthias Kalle Dalheimer <kalle@kde.org>
+ * @see KConfigBase, KConfig, KSimpleConfig, KConfigGroup
+ * @short Helper class for easier use of KConfig/KSimpleConfig groups
+ */
+
+class KDECORE_EXPORT KConfigGroupSaver // KDE4 remove
+{
+public:
+ /**
+ * Constructor. You pass a pointer to the KConfigBase-derived
+ * object you want to work with and a string indicating the _new_
+ * group.
+ *
+ * @param config The KConfigBase-derived object this
+ * KConfigGroupSaver works on.
+ * @param group The new group that the config object should switch to.
+ */
+ KConfigGroupSaver( KConfigBase* config, QString group )
+ /* KDE 4 : make the second parameter const QString & */
+ : _config(config), _oldgroup(config->group())
+ { _config->setGroup( group ); }
+
+ KConfigGroupSaver( KConfigBase* config, const char *group )
+ : _config(config), _oldgroup(config->group())
+ { _config->setGroup( group ); }
+
+ KConfigGroupSaver( KConfigBase* config, const QCString &group )
+ : _config(config), _oldgroup(config->group())
+ { _config->setGroup( group ); }
+
+ ~KConfigGroupSaver() { _config->setGroup( _oldgroup ); }
+
+ KConfigBase* config() { return _config; };
+
+private:
+ KConfigBase* _config;
+ QString _oldgroup;
+
+ KConfigGroupSaver(const KConfigGroupSaver&);
+ KConfigGroupSaver& operator=(const KConfigGroupSaver&);
+
+ KConfigGroupSaverPrivate *d;
+};
+
+class KConfigGroupPrivate;
+
+/**
+ * A KConfigBase derived class for one specific group in a KConfig object.
+ */
+class KDECORE_EXPORT KConfigGroup: public KConfigBase
+{
+public:
+ /**
+ * Construct a config group corresponding to @p group in @p master.
+ * @p group is the group name encoded in UTF-8.
+ */
+ KConfigGroup(KConfigBase *master, const QCString &group);
+ /**
+ * This is an overloaded constructor provided for convenience.
+ * It behaves essentially like the above function.
+ *
+ * Construct a config group corresponding to @p group in @p master
+ */
+ KConfigGroup(KConfigBase *master, const QString &group);
+ /**
+ * This is an overloaded constructor provided for convenience.
+ * It behaves essentially like the above function.
+ *
+ * Construct a config group corresponding to @p group in @p master
+ * @p group is the group name encoded in UTF-8.
+ */
+ KConfigGroup(KConfigBase *master, const char * group);
+
+ /**
+ * Delete all entries in the entire group
+ * @param bGlobal If @p bGlobal is true, the entries are not removed
+ * from the application specific config file, but from the global
+ * KDE config file.
+ */
+ void deleteGroup(bool bGlobal = false);
+
+ /**
+ * Checks whether it is possible to change this group.
+ * @return whether changes may be made to this group in this configuration
+ * file.
+ * @since 3.4
+ */
+ bool groupIsImmutable() const;
+
+ // The following functions are reimplemented:
+ virtual void setDirty(bool _bDirty);
+ virtual void putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup = true);
+ virtual KEntry lookupData(const KEntryKey &_key) const;
+ virtual void sync();
+
+private:
+ // Hide the following members:
+ void setGroup() { }
+ void setDesktopGroup() { }
+ void group() { }
+ void hasGroup() { }
+ void setReadOnly(bool) { }
+ void isDirty() { }
+
+ // The following members are not used.
+ virtual QStringList groupList() const { return QStringList(); }
+ virtual void rollback(bool) { }
+ virtual void reparseConfiguration() { }
+ virtual QMap<QString, QString> entryMap(const QString &) const
+ { return QMap<QString,QString>(); }
+ virtual KEntryMap internalEntryMap( const QString&) const
+ { return KEntryMap(); }
+ virtual KEntryMap internalEntryMap() const
+ { return KEntryMap(); }
+ virtual bool internalHasGroup(const QCString &) const
+ { return false; }
+
+ void getConfigState() { }
+
+ KConfigBase *mMaster;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KConfigGroupPrivate* d;
+};
+
+#endif
diff --git a/kdecore/kconfigdata.h b/kdecore/kconfigdata.h
new file mode 100644
index 000000000..281e8ecd6
--- /dev/null
+++ b/kdecore/kconfigdata.h
@@ -0,0 +1,146 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999-2000 Preston Brown <pbrown@kde.org>
+ Copyright (C) 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KCONFIGDATA_H
+#define _KCONFIGDATA_H
+
+#include <qmap.h> // generic red-black tree class
+#include "kdelibs_export.h"
+
+/**
+ * map/dict/list config node entry.
+ * @internal
+ */
+struct KDECORE_EXPORT KEntry
+{
+ KEntry()
+ : mValue(0), bDirty(false), bNLS(false),
+ bGlobal(false), bImmutable(false), bDeleted(false), bExpand(false) {}
+ QCString mValue;
+ /**
+ * Must the entry be written back to disk?
+ */
+ bool bDirty :1;
+ /**
+ * Entry should be written with locale tag
+ */
+ bool bNLS :1;
+ /**
+ * Entry should be written to the global config file
+ */
+ bool bGlobal:1;
+ /**
+ * Entry can not be modified.
+ */
+ bool bImmutable:1;
+ /**
+ * Entry has been deleted.
+ */
+ bool bDeleted:1;
+ /**
+ * Whether to apply dollar expansion or not.
+ */
+ bool bExpand:1;
+};
+
+/**
+ * key structure holding both the actual key and the the group
+ * to which it belongs.
+ * @internal
+ */
+struct KDECORE_EXPORT KEntryKey
+{
+ KEntryKey(const QCString& _group = 0,
+ const QCString& _key = 0)
+ : mGroup(_group), mKey(_key), bLocal(false), bDefault(false),
+ c_key(_key.data()) {}
+ /**
+ * The "group" to which this EntryKey belongs
+ */
+ QCString mGroup;
+ /**
+ * The _actual_ key of the entry in question
+ */
+ QCString mKey;
+ /**
+ * Entry is localised or not
+ */
+ bool bLocal :1;
+ /**
+ * Entry indicates if this is a default value.
+ */
+ bool bDefault:1;
+
+ const char *c_key;
+};
+
+/**
+ * compares two KEntryKeys (needed for QMap).
+ * @internal
+ */
+inline bool operator <(const KEntryKey &k1, const KEntryKey &k2)
+{
+ //saves one strcmp on each call
+ int result=qstrcmp(k1.mGroup.data(),k2.mGroup.data());
+ if (result!=0)
+ return (result<0);
+
+ if (!k1.c_key && k2.c_key)
+ return true;
+
+ result = 0;
+ if (k1.c_key && k2.c_key)
+ result = strcmp(k1.c_key, k2.c_key);
+ if (result != 0)
+ return result < 0;
+ if (!k1.bLocal && k2.bLocal)
+ return true;
+ if (k1.bLocal && !k2.bLocal)
+ return false;
+ return (!k1.bDefault && k2.bDefault);
+}
+
+/**
+ * \relates KEntry
+ * type specifying a map of entries (key,value pairs).
+ * The keys are actually a key in a particular config file group together
+ * with the group name.
+ * @internal
+ */
+typedef QMap<KEntryKey, KEntry> KEntryMap;
+
+/**
+ * \relates KEntry
+ * type for iterating over keys in a KEntryMap in sorted order.
+ * @internal
+ */
+typedef QMap<KEntryKey, KEntry>::Iterator KEntryMapIterator;
+
+/**
+ * \relates KEntry
+ * type for iterating over keys in a KEntryMap in sorted order.
+ * It is const, thus you cannot change the entries in the iterator,
+ * only examine them.
+ * @internal
+ */
+typedef QMap<KEntryKey, KEntry>::ConstIterator KEntryMapConstIterator;
+
+#endif
diff --git a/kdecore/kconfigdialogmanager.cpp b/kdecore/kconfigdialogmanager.cpp
new file mode 100644
index 000000000..b9a310b1e
--- /dev/null
+++ b/kdecore/kconfigdialogmanager.cpp
@@ -0,0 +1,399 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net)
+ * Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kconfigdialogmanager.h"
+
+#include <qbuttongroup.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qmetaobject.h>
+#include <qobjectlist.h>
+#include <qsqlpropertymap.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+
+#include <kapplication.h>
+#include <kconfigskeleton.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <assert.h>
+
+class KConfigDialogManager::Private {
+
+public:
+ Private() : insideGroupBox(false) { }
+
+public:
+ QDict<QWidget> knownWidget;
+ QDict<QWidget> buddyWidget;
+ bool insideGroupBox;
+};
+
+KConfigDialogManager::KConfigDialogManager(QWidget *parent, KConfigSkeleton *conf, const char *name)
+ : QObject(parent, name), m_conf(conf), m_dialog(parent)
+{
+ d = new Private();
+
+ kapp->installKDEPropertyMap();
+ propertyMap = QSqlPropertyMap::defaultMap();
+
+ init(true);
+}
+
+KConfigDialogManager::~KConfigDialogManager()
+{
+ delete d;
+}
+
+void KConfigDialogManager::init(bool trackChanges)
+{
+ if(trackChanges)
+ {
+ // QT
+ changedMap.insert("QButton", SIGNAL(stateChanged(int)));
+ changedMap.insert("QCheckBox", SIGNAL(stateChanged(int)));
+ changedMap.insert("QPushButton", SIGNAL(stateChanged(int)));
+ changedMap.insert("QRadioButton", SIGNAL(stateChanged(int)));
+ // We can only store one thing, so you can't have
+ // a ButtonGroup that is checkable.
+ changedMap.insert("QButtonGroup", SIGNAL(clicked(int)));
+ changedMap.insert("QGroupBox", SIGNAL(toggled(bool)));
+ changedMap.insert("QComboBox", SIGNAL(activated (int)));
+ //qsqlproperty map doesn't store the text, but the value!
+ //changedMap.insert("QComboBox", SIGNAL(textChanged(const QString &)));
+ changedMap.insert("QDateEdit", SIGNAL(valueChanged(const QDate &)));
+ changedMap.insert("QDateTimeEdit", SIGNAL(valueChanged(const QDateTime &)));
+ changedMap.insert("QDial", SIGNAL(valueChanged (int)));
+ changedMap.insert("QLineEdit", SIGNAL(textChanged(const QString &)));
+ changedMap.insert("QSlider", SIGNAL(valueChanged(int)));
+ changedMap.insert("QSpinBox", SIGNAL(valueChanged(int)));
+ changedMap.insert("QTimeEdit", SIGNAL(valueChanged(const QTime &)));
+ changedMap.insert("QTextEdit", SIGNAL(textChanged()));
+ changedMap.insert("QTextBrowser", SIGNAL(sourceChanged(const QString &)));
+ changedMap.insert("QMultiLineEdit", SIGNAL(textChanged()));
+ changedMap.insert("QListBox", SIGNAL(selectionChanged()));
+ changedMap.insert("QTabWidget", SIGNAL(currentChanged(QWidget *)));
+
+ // KDE
+ changedMap.insert( "KComboBox", SIGNAL(activated (int)));
+ changedMap.insert( "KFontCombo", SIGNAL(activated (int)));
+ changedMap.insert( "KFontRequester", SIGNAL(fontSelected(const QFont &)));
+ changedMap.insert( "KFontChooser", SIGNAL(fontSelected(const QFont &)));
+ changedMap.insert( "KHistoryCombo", SIGNAL(activated (int)));
+
+ changedMap.insert( "KColorButton", SIGNAL(changed(const QColor &)));
+ changedMap.insert( "KDatePicker", SIGNAL(dateSelected (QDate)));
+ changedMap.insert( "KDateWidget", SIGNAL(changed (QDate)));
+ changedMap.insert( "KDateTimeWidget", SIGNAL(valueChanged (const QDateTime &)));
+ changedMap.insert( "KEditListBox", SIGNAL(changed()));
+ changedMap.insert( "KListBox", SIGNAL(selectionChanged()));
+ changedMap.insert( "KLineEdit", SIGNAL(textChanged(const QString &)));
+ changedMap.insert( "KPasswordEdit", SIGNAL(textChanged(const QString &)));
+ changedMap.insert( "KRestrictedLine", SIGNAL(textChanged(const QString &)));
+ changedMap.insert( "KTextBrowser", SIGNAL(sourceChanged(const QString &)));
+ changedMap.insert( "KTextEdit", SIGNAL(textChanged()));
+ changedMap.insert( "KURLRequester", SIGNAL(textChanged (const QString& )));
+ changedMap.insert( "KIntNumInput", SIGNAL(valueChanged (int)));
+ changedMap.insert( "KIntSpinBox", SIGNAL(valueChanged (int)));
+ changedMap.insert( "KDoubleNumInput", SIGNAL(valueChanged (double)));
+ }
+
+ // Go through all of the children of the widgets and find all known widgets
+ (void) parseChildren(m_dialog, trackChanges);
+}
+
+void KConfigDialogManager::addWidget(QWidget *widget)
+{
+ (void) parseChildren(widget, true);
+}
+
+void KConfigDialogManager::setupWidget(QWidget *widget, KConfigSkeletonItem *item)
+{
+ QVariant minValue = item->minValue();
+ if (minValue.isValid())
+ {
+ if (widget->metaObject()->findProperty("minValue", true) != -1)
+ widget->setProperty("minValue", minValue);
+ }
+ QVariant maxValue = item->maxValue();
+ if (maxValue.isValid())
+ {
+ if (widget->metaObject()->findProperty("maxValue", true) != -1)
+ widget->setProperty("maxValue", maxValue);
+ }
+ if (QWhatsThis::textFor( widget ).isEmpty())
+ {
+ QString whatsThis = item->whatsThis();
+ if ( !whatsThis.isEmpty() )
+ {
+ QWhatsThis::add( widget, whatsThis );
+ }
+ }
+}
+
+bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChanges)
+{
+ bool valueChanged = false;
+ const QObjectList *listOfChildren = widget->children();
+ if(!listOfChildren)
+ return valueChanged;
+
+ QObject *object;
+ for( QPtrListIterator<QObject> it( *listOfChildren );
+ (object = it.current()); ++it )
+ {
+ if(!object->isWidgetType())
+ continue; // Skip non-widgets
+
+ QWidget *childWidget = (QWidget *)object;
+
+ const char *widgetName = childWidget->name(0);
+ bool bParseChildren = true;
+ bool bSaveInsideGroupBox = d->insideGroupBox;
+
+ if (widgetName && (strncmp(widgetName, "kcfg_", 5) == 0))
+ {
+ // This is one of our widgets!
+ QString configId = widgetName+5;
+ KConfigSkeletonItem *item = m_conf->findItem(configId);
+ if (item)
+ {
+ d->knownWidget.insert(configId, childWidget);
+
+ setupWidget(childWidget, item);
+
+ QMap<QString, QCString>::const_iterator changedIt = changedMap.find(childWidget->className());
+
+ if (changedIt == changedMap.end())
+ {
+ // If the class name of the widget wasn't in the monitored widgets map, then look for
+ // it again using the super class name. This fixes a problem with using QtRuby/Korundum
+ // widgets with KConfigXT where 'Qt::Widget' wasn't being seen a the real deal, even
+ // though it was a 'QWidget'.
+ changedIt = changedMap.find(childWidget->metaObject()->superClassName());
+ }
+
+ if (changedIt == changedMap.end())
+ {
+ kdWarning(178) << "Don't know how to monitor widget '" << childWidget->className() << "' for changes!" << endl;
+ }
+ else
+ {
+ connect(childWidget, *changedIt,
+ this, SIGNAL(widgetModified()));
+
+ QGroupBox *gb = dynamic_cast<QGroupBox *>(childWidget);
+ if (!gb)
+ bParseChildren = false;
+ else
+ d->insideGroupBox = true;
+
+ QComboBox *cb = dynamic_cast<QComboBox *>(childWidget);
+ if (cb && cb->editable())
+ connect(cb, SIGNAL(textChanged(const QString &)),
+ this, SIGNAL(widgetModified()));
+ }
+ }
+ else
+ {
+ kdWarning(178) << "A widget named '" << widgetName << "' was found but there is no setting named '" << configId << "'" << endl;
+ assert(false);
+ }
+ }
+ else if (childWidget->inherits("QLabel"))
+ {
+ QLabel *label = static_cast<QLabel *>(childWidget);
+ QWidget *buddy = label->buddy();
+ if (!buddy)
+ continue;
+ const char *buddyName = buddy->name(0);
+ if (buddyName && (strncmp(buddyName, "kcfg_", 5) == 0))
+ {
+ // This is one of our widgets!
+ QString configId = buddyName+5;
+ d->buddyWidget.insert(configId, childWidget);
+ }
+ }
+#ifndef NDEBUG
+ else if (widgetName)
+ {
+ QMap<QString, QCString>::const_iterator changedIt = changedMap.find(childWidget->className());
+ if (changedIt != changedMap.end())
+ {
+ if ((!d->insideGroupBox || !childWidget->inherits("QRadioButton")) &&
+ !childWidget->inherits("QGroupBox"))
+ kdDebug(178) << "Widget '" << widgetName << "' (" << childWidget->className() << ") remains unmanaged." << endl;
+ }
+ }
+#endif
+
+ if(bParseChildren)
+ {
+ // this widget is not known as something we can store.
+ // Maybe we can store one of its children.
+ valueChanged |= parseChildren(childWidget, trackChanges);
+ }
+ d->insideGroupBox = bSaveInsideGroupBox;
+ }
+ return valueChanged;
+}
+
+void KConfigDialogManager::updateWidgets()
+{
+ bool changed = false;
+ bool bSignalsBlocked = signalsBlocked();
+ blockSignals(true);
+
+ QWidget *widget;
+ for( QDictIterator<QWidget> it( d->knownWidget );
+ (widget = it.current()); ++it )
+ {
+ KConfigSkeletonItem *item = m_conf->findItem(it.currentKey());
+ if (!item)
+ {
+ kdWarning(178) << "The setting '" << it.currentKey() << "' has disappeared!" << endl;
+ continue;
+ }
+
+ QVariant p = item->property();
+ if (p != property(widget))
+ {
+ setProperty(widget, p);
+// kdDebug(178) << "The setting '" << it.currentKey() << "' [" << widget->className() << "] has changed" << endl;
+ changed = true;
+ }
+ if (item->isImmutable())
+ {
+ widget->setEnabled(false);
+ QWidget *buddy = d->buddyWidget.find(it.currentKey());
+ if (buddy)
+ buddy->setEnabled(false);
+ }
+ }
+ blockSignals(bSignalsBlocked);
+
+ if (changed)
+ QTimer::singleShot(0, this, SIGNAL(widgetModified()));
+}
+
+void KConfigDialogManager::updateWidgetsDefault()
+{
+ bool bUseDefaults = m_conf->useDefaults(true);
+ updateWidgets();
+ m_conf->useDefaults(bUseDefaults);
+}
+
+void KConfigDialogManager::updateSettings()
+{
+ bool changed = false;
+
+ QWidget *widget;
+ for( QDictIterator<QWidget> it( d->knownWidget );
+ (widget = it.current()); ++it )
+ {
+ KConfigSkeletonItem *item = m_conf->findItem(it.currentKey());
+ if (!item)
+ {
+ kdWarning(178) << "The setting '" << it.currentKey() << "' has disappeared!" << endl;
+ continue;
+ }
+
+ QVariant p = property(widget);
+ if (p != item->property())
+ {
+ item->setProperty(p);
+ changed = true;
+ }
+ }
+ if (changed)
+ {
+ m_conf->writeConfig();
+ emit settingsChanged();
+ }
+}
+
+void KConfigDialogManager::setProperty(QWidget *w, const QVariant &v)
+{
+ QButtonGroup *bg = dynamic_cast<QButtonGroup *>(w);
+ if (bg)
+ {
+ bg->setButton(v.toInt());
+ return;
+ }
+
+ QComboBox *cb = dynamic_cast<QComboBox *>(w);
+ if (cb && cb->editable())
+ {
+ cb->setCurrentText(v.toString());
+ return;
+ }
+
+ propertyMap->setProperty(w, v);
+}
+
+QVariant KConfigDialogManager::property(QWidget *w)
+{
+ QButtonGroup *bg = dynamic_cast<QButtonGroup *>(w);
+ if (bg)
+ return QVariant(bg->selectedId());
+
+ QComboBox *cb = dynamic_cast<QComboBox *>(w);
+ if (cb && cb->editable())
+ return QVariant(cb->currentText());
+
+ return propertyMap->property(w);
+}
+
+bool KConfigDialogManager::hasChanged()
+{
+
+ QWidget *widget;
+ for( QDictIterator<QWidget> it( d->knownWidget );
+ (widget = it.current()); ++it )
+ {
+ KConfigSkeletonItem *item = m_conf->findItem(it.currentKey());
+ if (!item)
+ {
+ kdWarning(178) << "The setting '" << it.currentKey() << "' has disappeared!" << endl;
+ continue;
+ }
+
+ QVariant p = property(widget);
+ if (p != item->property())
+ {
+// kdDebug(178) << "Widget for '" << it.currentKey() << "' has changed." << endl;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool KConfigDialogManager::isDefault()
+{
+ bool bUseDefaults = m_conf->useDefaults(true);
+ bool result = !hasChanged();
+ m_conf->useDefaults(bUseDefaults);
+ return result;
+}
+
+#include "kconfigdialogmanager.moc"
+
diff --git a/kdecore/kconfigdialogmanager.h b/kdecore/kconfigdialogmanager.h
new file mode 100644
index 000000000..f7d3f0c40
--- /dev/null
+++ b/kdecore/kconfigdialogmanager.h
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net)
+ * Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KCONFIGDIALOGMANAGER_H
+#define KCONFIGDIALOGMANAGER_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+#include "kdelibs_export.h"
+
+class KConfigSkeleton;
+class KConfigSkeletonItem;
+class QWidget;
+class QSqlPropertyMap;
+
+/**
+ * @short Provides a means of automatically retrieving,
+ * saving and resetting KConfigSkeleton based settings in a dialog.
+ *
+ * The KConfigDialogManager class provides a means of automatically
+ * retrieving, saving and resetting basic settings.
+ * It also can emit signals when settings have been changed
+ * (settings were saved) or modified (the user changes a checkbox
+ * from on to off).
+ *
+ * The names of the widgets to be managed have to correspond to the names of the
+ * configuration entries in the KConfigSkeleton object plus an additional
+ * "kcfg_" prefix. For example a widget named "kcfg_MyOption" would be
+ * associated to the configuration entry "MyOption".
+ *
+ * KConfigDialogManager uses the QSqlPropertyMap class to determine if it can do
+ * anything to a widget. Note that KConfigDialogManager doesn't require a
+ * database, it simply uses the functionality that is built into the
+ * QSqlPropertyMap class. New widgets can be added to the map using
+ * QSqlPropertyMap::installDefaultMap(). Note that you can't just add any
+ * class. The class must have a matching Q_PROPERTY(...) macro defined.
+ *
+ * For example (note that KColorButton is already added and it doesn't need to
+ * manually added):
+ *
+ * kcolorbutton.h defines the following property:
+ * \code
+ * Q_PROPERTY( QColor color READ color WRITE setColor )
+ * \endcode
+ *
+ * To add KColorButton the following code would be inserted in the main.
+ *
+ * \code
+ * kapp->installKDEPropertyMap();
+ * QSqlPropertyMap *map = QSqlPropertyMap::defaultMap();
+ * map->insert("KColorButton", "color");
+ * \endcode
+ *
+ * If you add a new widget to the QSqlPropertyMap and wish to be notified when
+ * it is modified you should add its signal using addWidgetChangedSignal().
+
+ * @since 3.2
+ * @author Benjamin C Meyer <ben+kdelibs at meyerhome dot net>
+ * @author Waldo Bastian <bastian@kde.org>
+ */
+class KDECORE_EXPORT KConfigDialogManager : public QObject {
+
+Q_OBJECT
+
+signals:
+ /**
+ * One or more of the settings have been saved (such as when the user
+ * clicks on the Apply button). This is only emitted by updateSettings()
+ * whenever one or more setting were changed and consequently saved.
+ */
+ void settingsChanged();
+
+ /**
+ * TODO: Verify
+ * One or more of the settings have been changed.
+ * @param widget - The widget group (pass in via addWidget()) that
+ * contains the one or more modified setting.
+ * @see settingsChanged()
+ */
+ void settingsChanged( QWidget *widget );
+
+ /**
+ * If retrieveSettings() was told to track changes then if
+ * any known setting was changed this signal will be emitted. Note
+ * that a settings can be modified several times and might go back to the
+ * original saved state. hasChanged() will tell you if anything has
+ * actually changed from the saved values.
+ */
+ void widgetModified();
+
+
+public:
+
+ /**
+ * Constructor.
+ * @param parent Dialog widget to manage
+ * @param conf Object that contains settings
+ * @param name - Object name.
+ */
+ KConfigDialogManager(QWidget *parent, KConfigSkeleton *conf, const char *name=0);
+
+ /**
+ * Destructor.
+ */
+ ~KConfigDialogManager();
+
+ /**
+ * Add additional widgets to manage
+ * @param widget Additional widget to manage, inlcuding all its children
+ */
+ void addWidget(QWidget *widget);
+
+ /**
+ * Returns whether the current state of the known widgets are
+ * different from the state in the config object.
+ */
+ bool hasChanged();
+
+ /**
+ * Returns whether the current state of the known widgets are
+ * the same as the default state in the config object.
+ */
+ bool isDefault();
+
+public slots:
+ /**
+ * Traverse the specified widgets, saving the settings of all known
+ * widgets in the settings object.
+ *
+ * Example use: User clicks Ok or Apply button in a configure dialog.
+ */
+ void updateSettings();
+
+ /**
+ * Traverse the specified widgets, sets the state of all known
+ * widgets according to the state in the settings object.
+ *
+ * Example use: Initialisation of dialog.
+ * Example use: User clicks Reset button in a configure dialog.
+ */
+ void updateWidgets();
+
+ /**
+ * Traverse the specified widgets, sets the state of all known
+ * widgets according to the default state in the settings object.
+ *
+ * Example use: User clicks Defaults button in a configure dialog.
+ */
+ void updateWidgetsDefault();
+
+protected:
+
+ /**
+ * @param trackChanges - If any changes by the widgets should be tracked
+ * set true. This causes the emitting the modified() signal when
+ * something changes.
+ * TODO: @return bool - True if any setting was changed from the default.
+ */
+ void init(bool trackChanges);
+
+ /**
+ * Recursive function that finds all known children.
+ * Goes through the children of widget and if any are known and not being
+ * ignored, stores them in currentGroup. Also checks if the widget
+ * should be disabled because it is set immutable.
+ * @param widget - Parent of the children to look at.
+ * @param trackChanges - If true then tracks any changes to the children of
+ * widget that are known.
+ * @return bool - If a widget was set to something other then its default.
+ */
+ bool parseChildren(const QWidget *widget, bool trackChanges);
+
+ /**
+ * Set a property
+ */
+ void setProperty(QWidget *w, const QVariant &v);
+
+ /**
+ * Retrieve a property
+ */
+ QVariant property(QWidget *w);
+
+ /**
+ * Setup secondary widget properties
+ */
+ void setupWidget(QWidget *widget, KConfigSkeletonItem *item);
+
+protected:
+ /**
+ * KConfigSkeleton object used to store settings
+ */
+ KConfigSkeleton *m_conf;
+
+ /**
+ * Dialog being managed
+ */
+ QWidget *m_dialog;
+
+ /**
+ * Pointer to the property map for easy access.
+ */
+ QSqlPropertyMap *propertyMap;
+
+ /**
+ * Map of the classes and the signals that they emit when changed.
+ */
+ QMap<QString, QCString> changedMap;
+
+private:
+ class Private;
+ /**
+ * KConfigDialogManager Private class.
+ */
+ Private *d;
+
+};
+
+#endif // KCONFIGDIALOGMANAGER_H
+
diff --git a/kdecore/kconfigskeleton.cpp b/kdecore/kconfigskeleton.cpp
new file mode 100644
index 000000000..819696a15
--- /dev/null
+++ b/kdecore/kconfigskeleton.cpp
@@ -0,0 +1,1207 @@
+/*
+ This file is part of KOrganizer.
+ Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcolor.h>
+#include <qvariant.h>
+
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kdebug.h>
+
+#include "kstringhandler.h"
+
+#include "kconfigskeleton.h"
+
+void KConfigSkeletonItem::readImmutability( KConfig *config )
+{
+ mIsImmutable = config->entryIsImmutable( mKey );
+}
+
+
+KConfigSkeleton::ItemString::ItemString( const QString &group, const QString &key,
+ QString &reference,
+ const QString &defaultValue,
+ Type type )
+ : KConfigSkeletonGenericItem<QString>( group, key, reference, defaultValue ),
+ mType( type )
+{
+}
+
+void KConfigSkeleton::ItemString::writeConfig( KConfig *config )
+{
+ if ( mReference != mLoadedValue ) // WABA: Is this test needed?
+ {
+ config->setGroup( mGroup );
+ if ((mDefault == mReference) && !config->hasDefault( mKey))
+ config->revertToDefault( mKey );
+ else if ( mType == Path )
+ config->writePathEntry( mKey, mReference );
+ else if ( mType == Password )
+ config->writeEntry( mKey, KStringHandler::obscure( mReference ) );
+ else
+ config->writeEntry( mKey, mReference );
+ }
+}
+
+
+void KConfigSkeleton::ItemString::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+
+ if ( mType == Path )
+ {
+ mReference = config->readPathEntry( mKey, mDefault );
+ }
+ else if ( mType == Password )
+ {
+ QString value = config->readEntry( mKey,
+ KStringHandler::obscure( mDefault ) );
+ mReference = KStringHandler::obscure( value );
+ }
+ else
+ {
+ mReference = config->readEntry( mKey, mDefault );
+ }
+
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemString::setProperty(const QVariant & p)
+{
+ mReference = p.toString();
+}
+
+QVariant KConfigSkeleton::ItemString::property() const
+{
+ return QVariant(mReference);
+}
+
+KConfigSkeleton::ItemPassword::ItemPassword( const QString &group, const QString &key,
+ QString &reference,
+ const QString &defaultValue)
+ : ItemString( group, key, reference, defaultValue, Password )
+{
+}
+
+KConfigSkeleton::ItemPath::ItemPath( const QString &group, const QString &key,
+ QString &reference,
+ const QString &defaultValue)
+ : ItemString( group, key, reference, defaultValue, Path )
+{
+}
+
+KConfigSkeleton::ItemProperty::ItemProperty( const QString &group,
+ const QString &key,
+ QVariant &reference,
+ QVariant defaultValue )
+ : KConfigSkeletonGenericItem<QVariant>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemProperty::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readPropertyEntry( mKey, mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemProperty::setProperty(const QVariant & p)
+{
+ mReference = p;
+}
+
+QVariant KConfigSkeleton::ItemProperty::property() const
+{
+ return mReference;
+}
+
+KConfigSkeleton::ItemBool::ItemBool( const QString &group, const QString &key,
+ bool &reference, bool defaultValue )
+ : KConfigSkeletonGenericItem<bool>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemBool::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readBoolEntry( mKey, mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemBool::setProperty(const QVariant & p)
+{
+ mReference = p.toBool();
+}
+
+QVariant KConfigSkeleton::ItemBool::property() const
+{
+ return QVariant( mReference, 42 /* dummy */ );
+}
+
+
+KConfigSkeleton::ItemInt::ItemInt( const QString &group, const QString &key,
+ int &reference, int defaultValue )
+ : KConfigSkeletonGenericItem<int>( group, key, reference, defaultValue )
+ ,mHasMin(false), mHasMax(false)
+{
+}
+
+void KConfigSkeleton::ItemInt::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readNumEntry( mKey, mDefault );
+ if (mHasMin)
+ mReference = QMAX(mReference, mMin);
+ if (mHasMax)
+ mReference = QMIN(mReference, mMax);
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemInt::setProperty(const QVariant & p)
+{
+ mReference = p.toInt();
+}
+
+QVariant KConfigSkeleton::ItemInt::property() const
+{
+ return QVariant(mReference);
+}
+
+QVariant KConfigSkeleton::ItemInt::minValue() const
+{
+ if (mHasMin)
+ return QVariant(mMin);
+ return QVariant();
+}
+
+QVariant KConfigSkeleton::ItemInt::maxValue() const
+{
+ if (mHasMax)
+ return QVariant(mMax);
+ return QVariant();
+}
+
+void KConfigSkeleton::ItemInt::setMinValue(int v)
+{
+ mHasMin = true;
+ mMin = v;
+}
+
+void KConfigSkeleton::ItemInt::setMaxValue(int v)
+{
+ mHasMax = true;
+ mMax = v;
+}
+
+
+KConfigSkeleton::ItemInt64::ItemInt64( const QString &group, const QString &key,
+ Q_INT64 &reference, Q_INT64 defaultValue )
+ : KConfigSkeletonGenericItem<Q_INT64>( group, key, reference, defaultValue )
+ ,mHasMin(false), mHasMax(false)
+{
+}
+
+void KConfigSkeleton::ItemInt64::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readNum64Entry( mKey, mDefault );
+ if (mHasMin)
+ mReference = QMAX(mReference, mMin);
+ if (mHasMax)
+ mReference = QMIN(mReference, mMax);
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemInt64::setProperty(const QVariant & p)
+{
+ mReference = p.toLongLong();
+}
+
+QVariant KConfigSkeleton::ItemInt64::property() const
+{
+ return QVariant(mReference);
+}
+
+QVariant KConfigSkeleton::ItemInt64::minValue() const
+{
+ if (mHasMin)
+ return QVariant(mMin);
+ return QVariant();
+}
+
+QVariant KConfigSkeleton::ItemInt64::maxValue() const
+{
+ if (mHasMax)
+ return QVariant(mMax);
+ return QVariant();
+}
+
+void KConfigSkeleton::ItemInt64::setMinValue(Q_INT64 v)
+{
+ mHasMin = true;
+ mMin = v;
+}
+
+void KConfigSkeleton::ItemInt64::setMaxValue(Q_INT64 v)
+{
+ mHasMax = true;
+ mMax = v;
+}
+
+KConfigSkeleton::ItemEnum::ItemEnum( const QString &group, const QString &key,
+ int &reference,
+ const QValueList<Choice> &choices,
+ int defaultValue )
+ : ItemInt( group, key, reference, defaultValue ), mChoices( choices )
+{
+}
+
+void KConfigSkeleton::ItemEnum::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ if (!config->hasKey(mKey))
+ {
+ mReference = mDefault;
+ }
+ else
+ {
+ int i = 0;
+ mReference = -1;
+ QString tmp = config->readEntry( mKey ).lower();
+ for(QValueList<Choice>::ConstIterator it = mChoices.begin();
+ it != mChoices.end(); ++it, ++i)
+ {
+ if ((*it).name.lower() == tmp)
+ {
+ mReference = i;
+ break;
+ }
+ }
+ if (mReference == -1)
+ mReference = config->readNumEntry( mKey, mDefault );
+ }
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemEnum::writeConfig( KConfig *config )
+{
+ if ( mReference != mLoadedValue ) // WABA: Is this test needed?
+ {
+ config->setGroup( mGroup );
+ if ((mDefault == mReference) && !config->hasDefault( mKey))
+ config->revertToDefault( mKey );
+ else if ((mReference >= 0) && (mReference < (int) mChoices.count()))
+ config->writeEntry( mKey, mChoices[mReference].name );
+ else
+ config->writeEntry( mKey, mReference );
+ }
+}
+
+QValueList<KConfigSkeleton::ItemEnum::Choice> KConfigSkeleton::ItemEnum::choices() const
+{
+ return mChoices;
+}
+
+
+KConfigSkeleton::ItemUInt::ItemUInt( const QString &group, const QString &key,
+ unsigned int &reference,
+ unsigned int defaultValue )
+ : KConfigSkeletonGenericItem<unsigned int>( group, key, reference, defaultValue )
+ ,mHasMin(false), mHasMax(false)
+{
+}
+
+void KConfigSkeleton::ItemUInt::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readUnsignedNumEntry( mKey, mDefault );
+ if (mHasMin)
+ mReference = QMAX(mReference, mMin);
+ if (mHasMax)
+ mReference = QMIN(mReference, mMax);
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemUInt::setProperty(const QVariant & p)
+{
+ mReference = p.toUInt();
+}
+
+QVariant KConfigSkeleton::ItemUInt::property() const
+{
+ return QVariant(mReference);
+}
+
+QVariant KConfigSkeleton::ItemUInt::minValue() const
+{
+ if (mHasMin)
+ return QVariant(mMin);
+ return QVariant();
+}
+
+QVariant KConfigSkeleton::ItemUInt::maxValue() const
+{
+ if (mHasMax)
+ return QVariant(mMax);
+ return QVariant();
+}
+
+void KConfigSkeleton::ItemUInt::setMinValue(unsigned int v)
+{
+ mHasMin = true;
+ mMin = v;
+}
+
+void KConfigSkeleton::ItemUInt::setMaxValue(unsigned int v)
+{
+ mHasMax = true;
+ mMax = v;
+}
+
+
+KConfigSkeleton::ItemUInt64::ItemUInt64( const QString &group, const QString &key,
+ Q_UINT64 &reference, Q_UINT64 defaultValue )
+ : KConfigSkeletonGenericItem<Q_UINT64>( group, key, reference, defaultValue )
+ ,mHasMin(false), mHasMax(false)
+{
+}
+
+void KConfigSkeleton::ItemUInt64::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readUnsignedNum64Entry( mKey, mDefault );
+ if (mHasMin)
+ mReference = QMAX(mReference, mMin);
+ if (mHasMax)
+ mReference = QMIN(mReference, mMax);
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemUInt64::setProperty(const QVariant & p)
+{
+ mReference = p.toULongLong();
+}
+
+QVariant KConfigSkeleton::ItemUInt64::property() const
+{
+ return QVariant(mReference);
+}
+
+QVariant KConfigSkeleton::ItemUInt64::minValue() const
+{
+ if (mHasMin)
+ return QVariant(mMin);
+ return QVariant();
+}
+
+QVariant KConfigSkeleton::ItemUInt64::maxValue() const
+{
+ if (mHasMax)
+ return QVariant(mMax);
+ return QVariant();
+}
+
+void KConfigSkeleton::ItemUInt64::setMinValue(Q_UINT64 v)
+{
+ mHasMin = true;
+ mMin = v;
+}
+
+void KConfigSkeleton::ItemUInt64::setMaxValue(Q_UINT64 v)
+{
+ mHasMax = true;
+ mMax = v;
+}
+
+KConfigSkeleton::ItemLong::ItemLong( const QString &group, const QString &key,
+ long &reference, long defaultValue )
+ : KConfigSkeletonGenericItem<long>( group, key, reference, defaultValue )
+ ,mHasMin(false), mHasMax(false)
+{
+}
+
+void KConfigSkeleton::ItemLong::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readLongNumEntry( mKey, mDefault );
+ if (mHasMin)
+ mReference = QMAX(mReference, mMin);
+ if (mHasMax)
+ mReference = QMIN(mReference, mMax);
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemLong::setProperty(const QVariant & p)
+{
+ mReference = p.toLongLong();
+}
+
+QVariant KConfigSkeleton::ItemLong::property() const
+{
+ return QVariant((Q_LLONG) mReference);
+}
+
+QVariant KConfigSkeleton::ItemLong::minValue() const
+{
+ if (mHasMin)
+ return QVariant((Q_LLONG) mMin);
+ return QVariant();
+}
+
+QVariant KConfigSkeleton::ItemLong::maxValue() const
+{
+ if (mHasMax)
+ return QVariant((Q_LLONG) mMax);
+ return QVariant();
+}
+
+void KConfigSkeleton::ItemLong::setMinValue(long v)
+{
+ mHasMin = true;
+ mMin = v;
+}
+
+void KConfigSkeleton::ItemLong::setMaxValue(long v)
+{
+ mHasMax = true;
+ mMax = v;
+}
+
+
+KConfigSkeleton::ItemULong::ItemULong( const QString &group, const QString &key,
+ unsigned long &reference,
+ unsigned long defaultValue )
+ : KConfigSkeletonGenericItem<unsigned long>( group, key, reference, defaultValue )
+ ,mHasMin(false), mHasMax(false)
+{
+}
+
+void KConfigSkeleton::ItemULong::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readUnsignedLongNumEntry( mKey, mDefault );
+ if (mHasMin)
+ mReference = QMAX(mReference, mMin);
+ if (mHasMax)
+ mReference = QMIN(mReference, mMax);
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemULong::setProperty(const QVariant & p)
+{
+ mReference = p.toULongLong();
+}
+
+QVariant KConfigSkeleton::ItemULong::property() const
+{
+ return QVariant((Q_ULLONG) mReference);
+}
+
+QVariant KConfigSkeleton::ItemULong::minValue() const
+{
+ if (mHasMin)
+ return QVariant((Q_ULLONG) mMin);
+ return QVariant();
+}
+
+QVariant KConfigSkeleton::ItemULong::maxValue() const
+{
+ if (mHasMax)
+ return QVariant((Q_ULLONG) mMax);
+ return QVariant();
+}
+
+void KConfigSkeleton::ItemULong::setMinValue(unsigned long v)
+{
+ mHasMin = true;
+ mMin = v;
+}
+
+void KConfigSkeleton::ItemULong::setMaxValue(unsigned long v)
+{
+ mHasMax = true;
+ mMax = v;
+}
+
+
+KConfigSkeleton::ItemDouble::ItemDouble( const QString &group, const QString &key,
+ double &reference, double defaultValue )
+ : KConfigSkeletonGenericItem<double>( group, key, reference, defaultValue )
+ ,mHasMin(false), mHasMax(false)
+{
+}
+
+void KConfigSkeleton::ItemDouble::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readDoubleNumEntry( mKey, mDefault );
+ if (mHasMin)
+ mReference = QMAX(mReference, mMin);
+ if (mHasMax)
+ mReference = QMIN(mReference, mMax);
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemDouble::setProperty(const QVariant & p)
+{
+ mReference = p.toDouble();
+}
+
+QVariant KConfigSkeleton::ItemDouble::property() const
+{
+ return QVariant(mReference);
+}
+
+QVariant KConfigSkeleton::ItemDouble::minValue() const
+{
+ if (mHasMin)
+ return QVariant(mMin);
+ return QVariant();
+}
+
+QVariant KConfigSkeleton::ItemDouble::maxValue() const
+{
+ if (mHasMax)
+ return QVariant(mMax);
+ return QVariant();
+}
+
+void KConfigSkeleton::ItemDouble::setMinValue(double v)
+{
+ mHasMin = true;
+ mMin = v;
+}
+
+void KConfigSkeleton::ItemDouble::setMaxValue(double v)
+{
+ mHasMax = true;
+ mMax = v;
+}
+
+
+KConfigSkeleton::ItemColor::ItemColor( const QString &group, const QString &key,
+ QColor &reference,
+ const QColor &defaultValue )
+ : KConfigSkeletonGenericItem<QColor>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemColor::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readColorEntry( mKey, &mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemColor::setProperty(const QVariant & p)
+{
+ mReference = p.toColor();
+}
+
+QVariant KConfigSkeleton::ItemColor::property() const
+{
+ return QVariant(mReference);
+}
+
+
+KConfigSkeleton::ItemFont::ItemFont( const QString &group, const QString &key,
+ QFont &reference,
+ const QFont &defaultValue )
+ : KConfigSkeletonGenericItem<QFont>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemFont::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readFontEntry( mKey, &mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemFont::setProperty(const QVariant & p)
+{
+ mReference = p.toFont();
+}
+
+QVariant KConfigSkeleton::ItemFont::property() const
+{
+ return QVariant(mReference);
+}
+
+
+KConfigSkeleton::ItemRect::ItemRect( const QString &group, const QString &key,
+ QRect &reference,
+ const QRect &defaultValue )
+ : KConfigSkeletonGenericItem<QRect>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemRect::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readRectEntry( mKey, &mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemRect::setProperty(const QVariant & p)
+{
+ mReference = p.toRect();
+}
+
+QVariant KConfigSkeleton::ItemRect::property() const
+{
+ return QVariant(mReference);
+}
+
+
+KConfigSkeleton::ItemPoint::ItemPoint( const QString &group, const QString &key,
+ QPoint &reference,
+ const QPoint &defaultValue )
+ : KConfigSkeletonGenericItem<QPoint>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemPoint::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readPointEntry( mKey, &mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemPoint::setProperty(const QVariant & p)
+{
+ mReference = p.toPoint();
+}
+
+QVariant KConfigSkeleton::ItemPoint::property() const
+{
+ return QVariant(mReference);
+}
+
+
+KConfigSkeleton::ItemSize::ItemSize( const QString &group, const QString &key,
+ QSize &reference,
+ const QSize &defaultValue )
+ : KConfigSkeletonGenericItem<QSize>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemSize::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readSizeEntry( mKey, &mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemSize::setProperty(const QVariant & p)
+{
+ mReference = p.toSize();
+}
+
+QVariant KConfigSkeleton::ItemSize::property() const
+{
+ return QVariant(mReference);
+}
+
+
+KConfigSkeleton::ItemDateTime::ItemDateTime( const QString &group, const QString &key,
+ QDateTime &reference,
+ const QDateTime &defaultValue )
+ : KConfigSkeletonGenericItem<QDateTime>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemDateTime::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ mReference = config->readDateTimeEntry( mKey, &mDefault );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemDateTime::setProperty(const QVariant & p)
+{
+ mReference = p.toDateTime();
+}
+
+QVariant KConfigSkeleton::ItemDateTime::property() const
+{
+ return QVariant(mReference);
+}
+
+
+KConfigSkeleton::ItemStringList::ItemStringList( const QString &group, const QString &key,
+ QStringList &reference,
+ const QStringList &defaultValue )
+ : KConfigSkeletonGenericItem<QStringList>( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemStringList::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ if ( !config->hasKey( mKey ) )
+ mReference = mDefault;
+ else
+ mReference = config->readListEntry( mKey );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemStringList::setProperty(const QVariant & p)
+{
+ mReference = p.toStringList();
+}
+
+QVariant KConfigSkeleton::ItemStringList::property() const
+{
+ return QVariant(mReference);
+}
+
+
+KConfigSkeleton::ItemPathList::ItemPathList( const QString &group, const QString &key,
+ QStringList &reference,
+ const QStringList &defaultValue )
+ : ItemStringList( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemPathList::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ if ( !config->hasKey( mKey ) )
+ mReference = mDefault;
+ else
+ mReference = config->readPathListEntry( mKey );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemPathList::writeConfig( KConfig *config )
+{
+ if ( mReference != mLoadedValue ) // WABA: Is this test needed?
+ {
+ config->setGroup( mGroup );
+ if ((mDefault == mReference) && !config->hasDefault( mKey))
+ config->revertToDefault( mKey );
+ else {
+ QStringList sl = mReference;
+ config->writePathEntry( mKey, sl );
+ }
+ }
+}
+
+
+KConfigSkeleton::ItemIntList::ItemIntList( const QString &group, const QString &key,
+ QValueList<int> &reference,
+ const QValueList<int> &defaultValue )
+ : KConfigSkeletonGenericItem<QValueList<int> >( group, key, reference, defaultValue )
+{
+}
+
+void KConfigSkeleton::ItemIntList::readConfig( KConfig *config )
+{
+ config->setGroup( mGroup );
+ if ( !config->hasKey( mKey ) )
+ mReference = mDefault;
+ else
+ mReference = config->readIntListEntry( mKey );
+ mLoadedValue = mReference;
+
+ readImmutability( config );
+}
+
+void KConfigSkeleton::ItemIntList::setProperty(const QVariant &)
+{
+ // TODO: Not yet supported
+}
+
+QVariant KConfigSkeleton::ItemIntList::property() const
+{
+ // TODO: Not yet supported
+ return QVariant();
+}
+
+
+KConfigSkeleton::KConfigSkeleton( const QString &configname )
+ : mCurrentGroup( "No Group" ), mUseDefaults(false)
+{
+ kdDebug(177) << "Creating KConfigSkeleton (" << (void *)this << ")" << endl;
+
+ if ( !configname.isEmpty() )
+ {
+ mConfig = KSharedConfig::openConfig( configname );
+ }
+ else
+ {
+ mConfig = KGlobal::sharedConfig();
+ }
+}
+
+KConfigSkeleton::KConfigSkeleton(KSharedConfig::Ptr config)
+ : mCurrentGroup( "No Group" ), mUseDefaults(false)
+{
+ kdDebug(177) << "Creating KConfigSkeleton (" << (void *)this << ")" << endl;
+ mConfig = config;
+}
+
+
+KConfigSkeleton::~KConfigSkeleton()
+{
+ KConfigSkeletonItem::List::ConstIterator it;
+ for( it = mItems.begin(); it != mItems.end(); ++it )
+ {
+ delete *it;
+ }
+}
+
+void KConfigSkeleton::setCurrentGroup( const QString &group )
+{
+ mCurrentGroup = group;
+}
+
+KConfig *KConfigSkeleton::config() const
+{
+ return mConfig;
+}
+
+bool KConfigSkeleton::useDefaults(bool b)
+{
+ if (b == mUseDefaults)
+ return mUseDefaults;
+
+ mUseDefaults = b;
+ KConfigSkeletonItem::List::ConstIterator it;
+ for( it = mItems.begin(); it != mItems.end(); ++it )
+ {
+ (*it)->swapDefault();
+ }
+
+ usrUseDefaults(b);
+ return !mUseDefaults;
+}
+
+void KConfigSkeleton::setDefaults()
+{
+ KConfigSkeletonItem::List::ConstIterator it;
+ for( it = mItems.begin(); it != mItems.end(); ++it ) {
+ (*it)->setDefault();
+ }
+
+ usrSetDefaults();
+}
+
+void KConfigSkeleton::readConfig()
+{
+ kdDebug(177) << "KConfigSkeleton::readConfig()" << endl;
+
+ QString origGroup = mConfig->group();
+
+ mConfig->reparseConfiguration();
+ KConfigSkeletonItem::List::ConstIterator it;
+ for( it = mItems.begin(); it != mItems.end(); ++it )
+ {
+ (*it)->readConfig( mConfig );
+ }
+
+ usrReadConfig();
+
+ mConfig->setGroup(origGroup);
+}
+
+void KConfigSkeleton::writeConfig()
+{
+ kdDebug(177) << "KConfigSkeleton::writeConfig()" << endl;
+
+ QString origGroup = mConfig->group();
+
+ KConfigSkeletonItem::List::ConstIterator it;
+ for( it = mItems.begin(); it != mItems.end(); ++it )
+ {
+ (*it)->writeConfig( mConfig );
+ }
+
+ usrWriteConfig();
+
+ mConfig->sync();
+
+ readConfig();
+
+ mConfig->setGroup(origGroup);
+}
+
+void KConfigSkeleton::addItem( KConfigSkeletonItem *item, const QString &name )
+{
+ item->setName( name.isEmpty() ? item->key() : name );
+ mItems.append( item );
+ mItemDict.insert( item->name(), item );
+ item->readDefault( mConfig );
+ item->readConfig( mConfig );
+}
+
+KConfigSkeleton::ItemString *KConfigSkeleton::addItemString( const QString &name, QString &reference,
+ const QString &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemString *item;
+ item = new KConfigSkeleton::ItemString( mCurrentGroup, key.isEmpty() ? name : key,
+ reference, defaultValue,
+ KConfigSkeleton::ItemString::Normal );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemPassword *KConfigSkeleton::addItemPassword( const QString &name, QString &reference,
+ const QString &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemPassword *item;
+ item = new KConfigSkeleton::ItemPassword( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemPath *KConfigSkeleton::addItemPath( const QString &name, QString &reference,
+ const QString &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemPath *item;
+ item = new KConfigSkeleton::ItemPath( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemProperty *KConfigSkeleton::addItemProperty( const QString &name, QVariant &reference,
+ const QVariant &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemProperty *item;
+ item = new KConfigSkeleton::ItemProperty( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemBool *KConfigSkeleton::addItemBool( const QString &name, bool &reference,
+ bool defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemBool *item;
+ item = new KConfigSkeleton::ItemBool( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemInt *KConfigSkeleton::addItemInt( const QString &name, int &reference,
+ int defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemInt *item;
+ item = new KConfigSkeleton::ItemInt( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemUInt *KConfigSkeleton::addItemUInt( const QString &name, unsigned int &reference,
+ unsigned int defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemUInt *item;
+ item = new KConfigSkeleton::ItemUInt( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemInt64 *KConfigSkeleton::addItemInt64( const QString &name, Q_INT64 &reference,
+ Q_INT64 defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemInt64 *item;
+ item = new KConfigSkeleton::ItemInt64( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemUInt64 *KConfigSkeleton::addItemUInt64( const QString &name, Q_UINT64 &reference,
+ Q_UINT64 defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemUInt64 *item;
+ item = new KConfigSkeleton::ItemUInt64( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemLong *KConfigSkeleton::addItemLong( const QString &name, long &reference,
+ long defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemLong *item;
+ item = new KConfigSkeleton::ItemLong( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemULong *KConfigSkeleton::addItemULong( const QString &name, unsigned long &reference,
+ unsigned long defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemULong *item;
+ item = new KConfigSkeleton::ItemULong( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemDouble *KConfigSkeleton::addItemDouble( const QString &name, double &reference,
+ double defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemDouble *item;
+ item = new KConfigSkeleton::ItemDouble( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemColor *KConfigSkeleton::addItemColor( const QString &name, QColor &reference,
+ const QColor &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemColor *item;
+ item = new KConfigSkeleton::ItemColor( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemFont *KConfigSkeleton::addItemFont( const QString &name, QFont &reference,
+ const QFont &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemFont *item;
+ item = new KConfigSkeleton::ItemFont( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemRect *KConfigSkeleton::addItemRect( const QString &name, QRect &reference,
+ const QRect &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemRect *item;
+ item = new KConfigSkeleton::ItemRect( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemPoint *KConfigSkeleton::addItemPoint( const QString &name, QPoint &reference,
+ const QPoint &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemPoint *item;
+ item = new KConfigSkeleton::ItemPoint( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemSize *KConfigSkeleton::addItemSize( const QString &name, QSize &reference,
+ const QSize &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemSize *item;
+ item = new KConfigSkeleton::ItemSize( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemDateTime *KConfigSkeleton::addItemDateTime( const QString &name, QDateTime &reference,
+ const QDateTime &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemDateTime *item;
+ item = new KConfigSkeleton::ItemDateTime( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemStringList *KConfigSkeleton::addItemStringList( const QString &name, QStringList &reference,
+ const QStringList &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemStringList *item;
+ item = new KConfigSkeleton::ItemStringList( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+KConfigSkeleton::ItemIntList *KConfigSkeleton::addItemIntList( const QString &name, QValueList<int> &reference,
+ const QValueList<int> &defaultValue, const QString &key )
+{
+ KConfigSkeleton::ItemIntList *item;
+ item = new KConfigSkeleton::ItemIntList( mCurrentGroup, key.isNull() ? name : key,
+ reference, defaultValue );
+ addItem( item, name );
+ return item;
+}
+
+bool KConfigSkeleton::isImmutable(const QString &name)
+{
+ KConfigSkeletonItem *item = findItem(name);
+ return !item || item->isImmutable();
+}
+
+KConfigSkeletonItem *KConfigSkeleton::findItem(const QString &name)
+{
+ return mItemDict.find(name);
+}
diff --git a/kdecore/kconfigskeleton.h b/kdecore/kconfigskeleton.h
new file mode 100644
index 000000000..44fdfc7fa
--- /dev/null
+++ b/kdecore/kconfigskeleton.h
@@ -0,0 +1,1230 @@
+/*
+ * This file is part of KDE.
+ *
+ * Copyright (c) 2001,2002,2003 Cornelius Schumacher <schumacher@kde.org>
+ * Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KCONFIGSKELETON_H
+#define _KCONFIGSKELETON_H
+
+#include <qcolor.h>
+#include <qdatetime.h>
+#include <qfont.h>
+#include <qpoint.h>
+#include <qptrlist.h>
+#include <qdict.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qstringlist.h>
+#include <qvariant.h>
+#include <kconfig.h>
+#include <kglobalsettings.h>
+
+ /**
+ * @short Class for storing a preferences setting
+ * @author Cornelius Schumacher
+ * @see KConfigSkeleton
+ *
+ * This class represents one preferences setting as used by @ref KConfigSkeleton.
+ * Subclasses of KConfigSkeletonItem implement storage functions for a certain type of
+ * setting. Normally you don't have to use this class directly. Use the special
+ * addItem() functions of KConfigSkeleton instead. If you subclass this class you will
+ * have to register instances with the function KConfigSkeleton::addItem().
+ */
+ class KDECORE_EXPORT KConfigSkeletonItem
+ {
+ public:
+ typedef QValueList < KConfigSkeletonItem * >List;
+ typedef QDict < KConfigSkeletonItem > Dict;
+ typedef QDictIterator < KConfigSkeletonItem > DictIterator;
+
+ /**
+ * Constructor.
+ *
+ * @param group Config file group.
+ * @param key Config file key.
+ */
+ KConfigSkeletonItem(const QString & group, const QString & key)
+ :mGroup(group),mKey(key), mIsImmutable(true)
+ {
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~KConfigSkeletonItem()
+ {
+ }
+
+ /**
+ * Set config file group.
+ */
+ void setGroup( const QString &group )
+ {
+ mGroup = group;
+ }
+
+ /**
+ * Return config file group.
+ */
+ QString group() const
+ {
+ return mGroup;
+ }
+
+ /**
+ * Set config file key.
+ */
+ void setKey( const QString &key )
+ {
+ mKey = key;
+ }
+
+ /**
+ * Return config file key.
+ */
+ QString key() const
+ {
+ return mKey;
+ }
+
+ /**
+ * Set internal name of entry.
+ */
+ void setName(const QString &name)
+ {
+ mName = name;
+ }
+
+ /**
+ * Return internal name of entry.
+ */
+ QString name() const
+ {
+ return mName;
+ }
+
+ /**
+ Set label providing a translated one-line description of the item.
+ */
+ void setLabel( const QString &l )
+ {
+ mLabel = l;
+ }
+
+ /**
+ Return label of item. See setLabel().
+ */
+ QString label() const
+ {
+ return mLabel;
+ }
+
+ /**
+ Set WhatsThis description og item.
+ */
+ void setWhatsThis( const QString &w )
+ {
+ mWhatsThis = w;
+ }
+
+ /**
+ Return WhatsThis description of item. See setWhatsThis().
+ */
+ QString whatsThis() const
+ {
+ return mWhatsThis;
+ }
+
+ /**
+ * This function is called by @ref KConfigSkeleton to read the value for this setting
+ * from a config file.
+ * value.
+ */
+ virtual void readConfig(KConfig *) = 0;
+
+ /**
+ * This function is called by @ref KConfigSkeleton to write the value of this setting
+ * to a config file.
+ */
+ virtual void writeConfig(KConfig *) = 0;
+
+ /**
+ * Read global default value.
+ */
+ virtual void readDefault(KConfig *) = 0;
+
+ /**
+ * Set item to @p p
+ */
+ virtual void setProperty(const QVariant &p) = 0;
+
+ /**
+ * Return item as property
+ */
+ virtual QVariant property() const = 0;
+
+ /**
+ * Return minimum value of item or invalid if not specified
+ */
+ virtual QVariant minValue() const { return QVariant(); }
+
+ /**
+ * Return maximum value of item or invalid if not specified
+ */
+ virtual QVariant maxValue() const { return QVariant(); }
+
+ /**
+ Sets the current value to the default value.
+ */
+ virtual void setDefault() = 0;
+
+ /**
+ * Exchanges the current value with the default value
+ * Used by KConfigSkeleton::useDefaults(bool);
+ */
+ virtual void swapDefault() = 0;
+
+ /**
+ * Return if the entry can be modified.
+ */
+ bool isImmutable() const
+ {
+ return mIsImmutable;
+ }
+
+ protected:
+ /**
+ * sets mIsImmutable to true if mKey in config is immutable
+ * @param config KConfig to check if mKey is immutable in
+ */
+ void readImmutability(KConfig *config);
+
+ QString mGroup;
+ QString mKey;
+ QString mName;
+
+ private:
+ bool mIsImmutable;
+
+ QString mLabel;
+ QString mWhatsThis;
+ };
+
+
+template < typename T > class KConfigSkeletonGenericItem:public KConfigSkeletonItem
+ {
+ public:
+ KConfigSkeletonGenericItem(const QString & group, const QString & key, T & reference,
+ T defaultValue)
+ : KConfigSkeletonItem(group, key), mReference(reference),
+ mDefault(defaultValue), mLoadedValue(defaultValue)
+ {
+ }
+
+ /**
+ * Set value of this KConfigSkeletonItem.
+ */
+ void setValue(const T & v)
+ {
+ mReference = v;
+ }
+
+ /**
+ * Return value of this KConfigSkeletonItem.
+ */
+ T & value()
+ {
+ return mReference;
+ }
+
+ /**
+ * Return const value of this KConfigSkeletonItem.
+ */
+ const T & value() const
+ {
+ return mReference;
+ }
+
+ /**
+ Set default value for this item.
+ */
+ virtual void setDefaultValue( const T &v )
+ {
+ mDefault = v;
+ }
+
+ virtual void setDefault()
+ {
+ mReference = mDefault;
+ }
+
+ virtual void writeConfig(KConfig * config)
+ {
+ if ( mReference != mLoadedValue ) // Is this needed?
+ {
+ config->setGroup(mGroup);
+ if ((mDefault == mReference) && !config->hasDefault( mKey))
+ config->revertToDefault( mKey );
+ else
+ config->writeEntry(mKey, mReference);
+ }
+ }
+
+ void readDefault(KConfig * config)
+ {
+ config->setReadDefaults(true);
+ readConfig(config);
+ config->setReadDefaults(false);
+ mDefault = mReference;
+ }
+
+ void swapDefault()
+ {
+ T tmp = mReference;
+ mReference = mDefault;
+ mDefault = tmp;
+ }
+
+ protected:
+ T & mReference;
+ T mDefault;
+ T mLoadedValue;
+ };
+
+ /**
+ * @short Class for handling preferences settings for an application.
+ * @author Cornelius Schumacher
+ * @see KConfigSkeletonItem
+ *
+ * This class provides an interface to preferences settings. Preferences items
+ * can be registered by the addItem() function corresponding to the data type of
+ * the seetting. KConfigSkeleton then handles reading and writing of config files and
+ * setting of default values.
+ *
+ * Normally you will subclass KConfigSkeleton, add data members for the preferences
+ * settings and register the members in the constructor of the subclass.
+ *
+ * Example:
+ * \code
+ * class MyPrefs : public KConfigSkeleton
+ * {
+ * public:
+ * MyPrefs()
+ * {
+ * setCurrentGroup("MyGroup");
+ * addItemBool("MySetting1",mMyBool,false);
+ * addItemColor("MySetting2",mMyColor,QColor(1,2,3));
+ *
+ * setCurrentGroup("MyOtherGroup");
+ * addItemFont("MySetting3",mMyFont,QFont("helvetica",12));
+ * }
+ *
+ * bool mMyBool;
+ * QColor mMyColor;
+ * QFont mMyFont;
+ * }
+ * \endcode
+ *
+ * It might be convenient in many cases to make this subclass of KConfigSkeleton a
+ * singleton for global access from all over the application without passing
+ * references to the KConfigSkeleton object around.
+ *
+ * You can write the data to the configuration file by calling @ref writeConfig()
+ * and read the data from the configuration file by calling @ref readConfig().
+ *
+ * If you have items, which are not covered by the existing addItem() functions
+ * you can add customized code for reading, writing and default setting by
+ * implementing the functions @ref usrUseDefaults(), @ref usrReadConfig() and
+ * @ref usrWriteConfig().
+ *
+ * Internally preferences settings are stored in instances of subclasses of
+ * @ref KConfigSkeletonItem. You can also add KConfigSkeletonItem subclasses
+ * for your own types and call the generic @ref addItem() to register them.
+ *
+ * In many cases you don't have to write the specific KConfigSkeleton
+ * subclasses yourself, but you can use \ref kconfig_compiler to automatically
+ * generate the C++ code from an XML description of the configuration options.
+ */
+class KDECORE_EXPORT KConfigSkeleton
+{
+public:
+
+ /**
+ * Class for handling a string preferences item.
+ */
+ class KDECORE_EXPORT ItemString:public KConfigSkeletonGenericItem < QString >
+ {
+ public:
+ enum Type { Normal, Password, Path };
+
+ ItemString(const QString & group, const QString & key,
+ QString & reference,
+ const QString & defaultValue = QString::fromLatin1(""), // NOT QString::null !!
+ Type type = Normal);
+
+ void writeConfig(KConfig * config);
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+
+ private:
+ Type mType;
+ };
+
+ /**
+ * Class for handling a password preferences item.
+ */
+ class KDECORE_EXPORT ItemPassword:public ItemString
+ {
+ public:
+ ItemPassword(const QString & group, const QString & key,
+ QString & reference,
+ const QString & defaultValue = QString::fromLatin1("")); // NOT QString::null !!
+ };
+
+ /**
+ * Class for handling a path preferences item.
+ */
+ class KDECORE_EXPORT ItemPath:public ItemString
+ {
+ public:
+ ItemPath(const QString & group, const QString & key,
+ QString & reference,
+ const QString & defaultValue = QString::null);
+ };
+
+
+ /**
+ * Class for handling a QVariant preferences item.
+ */
+ class KDECORE_EXPORT ItemProperty:public KConfigSkeletonGenericItem < QVariant >
+ {
+ public:
+ ItemProperty(const QString & group, const QString & key,
+ QVariant & reference, QVariant defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a bool preferences item.
+ */
+ class KDECORE_EXPORT ItemBool:public KConfigSkeletonGenericItem < bool >
+ {
+ public:
+ ItemBool(const QString & group, const QString & key, bool & reference,
+ bool defaultValue = true);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling an integer preferences item.
+ */
+ class KDECORE_EXPORT ItemInt:public KConfigSkeletonGenericItem < int >
+ {
+ public:
+ ItemInt(const QString & group, const QString & key, int &reference,
+ int defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ QVariant minValue() const;
+ QVariant maxValue() const;
+
+ void setMinValue(int);
+ void setMaxValue(int);
+
+ private:
+ bool mHasMin : 1;
+ bool mHasMax : 1;
+ int mMin;
+ int mMax;
+ };
+
+ /**
+ * Class for handling an 64-bit integer preferences item.
+ */
+ class KDECORE_EXPORT ItemInt64:public KConfigSkeletonGenericItem < Q_INT64 >
+ {
+ public:
+ ItemInt64(const QString & group, const QString & key, Q_INT64 &reference,
+ Q_INT64 defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+
+ QVariant minValue() const;
+ QVariant maxValue() const;
+
+ void setMinValue(Q_INT64);
+ void setMaxValue(Q_INT64);
+
+ private:
+ bool mHasMin : 1;
+ bool mHasMax : 1;
+ Q_INT64 mMin;
+ Q_INT64 mMax;
+ };
+
+ /**
+ * Class for handling enums.
+ */
+ class KDECORE_EXPORT ItemEnum:public ItemInt
+ {
+ public:
+ struct Choice
+ {
+ QString name;
+ QString label;
+ QString whatsThis;
+ };
+
+ ItemEnum(const QString & group, const QString & key, int &reference,
+ const QValueList<Choice> &choices, int defaultValue = 0);
+
+ QValueList<Choice> choices() const;
+
+ void readConfig(KConfig * config);
+ void writeConfig(KConfig * config);
+
+ private:
+ QValueList<Choice> mChoices;
+ };
+
+
+ /**
+ * Class for handling an unsingend integer preferences item.
+ */
+ class KDECORE_EXPORT ItemUInt:public KConfigSkeletonGenericItem < unsigned int >
+ {
+ public:
+ ItemUInt(const QString & group, const QString & key,
+ unsigned int &reference, unsigned int defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ QVariant minValue() const;
+ QVariant maxValue() const;
+
+ void setMinValue(unsigned int);
+ void setMaxValue(unsigned int);
+
+ private:
+ bool mHasMin : 1;
+ bool mHasMax : 1;
+ unsigned int mMin;
+ unsigned int mMax;
+ };
+
+
+ /**
+ * Class for hanlding a long integer preferences item.
+ */
+ class KDECORE_EXPORT ItemLong:public KConfigSkeletonGenericItem < long >
+ {
+ public:
+ ItemLong(const QString & group, const QString & key, long &reference,
+ long defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ QVariant minValue() const;
+ QVariant maxValue() const;
+
+ void setMinValue(long);
+ void setMaxValue(long);
+
+ private:
+ bool mHasMin : 1;
+ bool mHasMax : 1;
+ long mMin;
+ long mMax;
+ };
+
+
+ /**
+ * Class for handling an unsigned long integer preferences item.
+ */
+ class KDECORE_EXPORT ItemULong:public KConfigSkeletonGenericItem < unsigned long >
+ {
+ public:
+ ItemULong(const QString & group, const QString & key,
+ unsigned long &reference, unsigned long defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ QVariant minValue() const;
+ QVariant maxValue() const;
+
+ void setMinValue(unsigned long);
+ void setMaxValue(unsigned long);
+
+ private:
+ bool mHasMin : 1;
+ bool mHasMax : 1;
+ unsigned long mMin;
+ unsigned long mMax;
+ };
+
+ /**
+ * Class for handling unsigned 64-bit integer preferences item.
+ */
+ class KDECORE_EXPORT ItemUInt64:public KConfigSkeletonGenericItem < Q_UINT64 >
+ {
+ public:
+ ItemUInt64(const QString & group, const QString & key, Q_UINT64 &reference,
+ Q_UINT64 defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+
+ QVariant minValue() const;
+ QVariant maxValue() const;
+
+ void setMinValue(Q_UINT64);
+ void setMaxValue(Q_UINT64);
+
+ private:
+ bool mHasMin : 1;
+ bool mHasMax : 1;
+ Q_UINT64 mMin;
+ Q_UINT64 mMax;
+ };
+
+ /**
+ * Class for handling a floating point preference item.
+ */
+ class KDECORE_EXPORT ItemDouble:public KConfigSkeletonGenericItem < double >
+ {
+ public:
+ ItemDouble(const QString & group, const QString & key,
+ double &reference, double defaultValue = 0);
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ QVariant minValue() const;
+ QVariant maxValue() const;
+
+ void setMinValue(double);
+ void setMaxValue(double);
+
+ private:
+ bool mHasMin : 1;
+ bool mHasMax : 1;
+ double mMin;
+ double mMax;
+ };
+
+
+ /**
+ * Class for handling a color preferences item.
+ */
+ class KDECORE_EXPORT ItemColor:public KConfigSkeletonGenericItem < QColor >
+ {
+ public:
+ ItemColor(const QString & group, const QString & key,
+ QColor & reference,
+ const QColor & defaultValue = QColor(128, 128, 128));
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a font preferences item.
+ */
+ class KDECORE_EXPORT ItemFont:public KConfigSkeletonGenericItem < QFont >
+ {
+ public:
+ ItemFont(const QString & group, const QString & key, QFont & reference,
+ const QFont & defaultValue = KGlobalSettings::generalFont());
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a QRect preferences item.
+ */
+ class KDECORE_EXPORT ItemRect:public KConfigSkeletonGenericItem < QRect >
+ {
+ public:
+ ItemRect(const QString & group, const QString & key, QRect & reference,
+ const QRect & defaultValue = QRect());
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a QPoint preferences item.
+ */
+ class KDECORE_EXPORT ItemPoint:public KConfigSkeletonGenericItem < QPoint >
+ {
+ public:
+ ItemPoint(const QString & group, const QString & key, QPoint & reference,
+ const QPoint & defaultValue = QPoint());
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a QSize preferences item.
+ */
+ class KDECORE_EXPORT ItemSize:public KConfigSkeletonGenericItem < QSize >
+ {
+ public:
+ ItemSize(const QString & group, const QString & key, QSize & reference,
+ const QSize & defaultValue = QSize());
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a QDateTime preferences item.
+ */
+ class KDECORE_EXPORT ItemDateTime:public KConfigSkeletonGenericItem < QDateTime >
+ {
+ public:
+ ItemDateTime(const QString & group, const QString & key,
+ QDateTime & reference,
+ const QDateTime & defaultValue = QDateTime());
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a string list preferences item.
+ */
+ class KDECORE_EXPORT ItemStringList:public KConfigSkeletonGenericItem < QStringList >
+ {
+ public:
+ ItemStringList(const QString & group, const QString & key,
+ QStringList & reference,
+ const QStringList & defaultValue = QStringList());
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+ /**
+ * Class for handling a path list preferences item.
+ */
+ class KDECORE_EXPORT ItemPathList:public ItemStringList
+ {
+ public:
+ ItemPathList(const QString & group, const QString & key,
+ QStringList & reference,
+ const QStringList & defaultValue = QStringList());
+
+ void readConfig(KConfig * config);
+ void writeConfig(KConfig * config);
+ };
+
+
+ /**
+ * Class for handling an integer list preferences item.
+ */
+ class KDECORE_EXPORT ItemIntList:public KConfigSkeletonGenericItem < QValueList < int > >
+ {
+ public:
+ ItemIntList(const QString & group, const QString & key,
+ QValueList < int >&reference,
+ const QValueList < int >&defaultValue = QValueList < int >());
+
+ void readConfig(KConfig * config);
+ void setProperty(const QVariant & p);
+ QVariant property() const;
+ };
+
+
+public:
+ /**
+ * Constructor.
+ *
+ * @param configname name of config file. If no name is given, the default
+ * config file as returned by kapp()->config() is used.
+ */
+ KConfigSkeleton(const QString & configname = QString::null);
+
+ /**
+ * Constructor.
+ *
+ * @param config configuration object to use.
+ */
+ KConfigSkeleton(KSharedConfig::Ptr config);
+
+ /**
+ * Destructor
+ */
+ virtual ~ KConfigSkeleton();
+
+ /**
+ Set all registered items to their default values.
+ */
+ void setDefaults();
+
+ /**
+ * Read preferences from config file. All registered items are set to the
+ * values read from disk.
+ */
+ void readConfig();
+
+ /**
+ * Write preferences to config file. The values of all registered items are
+ * written to disk.
+ */
+ void writeConfig();
+
+ /**
+ * Set the config file group for subsequent addItem() calls. It is valid
+ * until setCurrentGroup() is called with a new argument. Call this before
+ * you add any items. The default value is "No Group".
+ */
+ void setCurrentGroup(const QString & group);
+
+ /**
+ * Returns the current group used for addItem() calls.
+ */
+ QString currentGroup() // ### KDE 4.0: make const
+ {
+ return mCurrentGroup;
+ }
+
+ /**
+ * Register a custom @ref KConfigSkeletonItem with a given name. If the name
+ * parameter is null, take the name from KConfigSkeletonItem::key().
+ * Note that all names must be unique but that multiple entries can have
+ * the same key if they reside in different groups.
+ */
+ void addItem(KConfigSkeletonItem *, const QString & name = QString::null );
+
+ /**
+ * Register an item of type QString.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemString *addItemString(const QString & name, QString & reference,
+ const QString & defaultValue = QString::fromLatin1(""), // NOT QString::null !!
+ const QString & key = QString::null);
+
+ /**
+ * Register a password item of type QString. The string value is written
+ * encrypted to the config file. Note that the current encryption scheme
+ * is very weak.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemPassword *addItemPassword(const QString & name, QString & reference,
+ const QString & defaultValue = QString::fromLatin1(""),
+ const QString & key = QString::null);
+
+ /**
+ * Register a path item of type QString. The string value is interpreted
+ * as a path. This means, dollar expension is activated for this value, so
+ * that e.g. $HOME gets expanded.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemPath *addItemPath(const QString & name, QString & reference,
+ const QString & defaultValue = QString::fromLatin1(""),
+ const QString & key = QString::null);
+
+ /**
+ * Register a property item of type QVariant. Note that only the following
+ * QVariant types are allowed: String, StringList, Font, Point, Rect, Size,
+ * Color, Int, UInt, Bool, Double, DateTime and Date.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemProperty *addItemProperty(const QString & name, QVariant & reference,
+ const QVariant & defaultValue = QVariant(),
+ const QString & key = QString::null);
+ /**
+ * Register an item of type bool.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemBool *addItemBool(const QString & name, bool & reference,
+ bool defaultValue = false,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type int.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemInt *addItemInt(const QString & name, int &reference, int defaultValue = 0,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type unsigned int.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemUInt *addItemUInt(const QString & name, unsigned int &reference,
+ unsigned int defaultValue = 0,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type long.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemLong *addItemLong(const QString & name, long &reference,
+ long defaultValue = 0,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type unsigned long.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemULong *addItemULong(const QString & name, unsigned long &reference,
+ unsigned long defaultValue = 0,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type Q_INT64.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemInt64 *addItemInt64(const QString & name, Q_INT64 &reference,
+ Q_INT64 defaultValue = 0,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type Q_UINT64
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemUInt64 *addItemUInt64(const QString & name, Q_UINT64 &reference,
+ Q_UINT64 defaultValue = 0,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type double.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemDouble *addItemDouble(const QString & name, double &reference,
+ double defaultValue = 0.0,
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QColor.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemColor *addItemColor(const QString & name, QColor & reference,
+ const QColor & defaultValue = QColor(128, 128, 128),
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QFont.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemFont *addItemFont(const QString & name, QFont & reference,
+ const QFont & defaultValue =
+ KGlobalSettings::generalFont(),
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QRect.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemRect *addItemRect(const QString & name, QRect & reference,
+ const QRect & defaultValue = QRect(),
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QPoint.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemPoint *addItemPoint(const QString & name, QPoint & reference,
+ const QPoint & defaultValue = QPoint(),
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QSize.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemSize *addItemSize(const QString & name, QSize & reference,
+ const QSize & defaultValue = QSize(),
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QDateTime.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemDateTime *addItemDateTime(const QString & name, QDateTime & reference,
+ const QDateTime & defaultValue = QDateTime(),
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QStringList.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemStringList *addItemStringList(const QString & name, QStringList & reference,
+ const QStringList & defaultValue = QStringList(),
+ const QString & key = QString::null);
+
+ /**
+ * Register an item of type QValueList<int>.
+ *
+ * @param name Name used to indentify this setting. Names must be unique.
+ * @param reference Pointer to the variable, which is set by readConfig()
+ * calls and read by writeConfig() calls.
+ * @param defaultValue Default value, which is used when the config file
+ * does not yet contain the key of this item.
+ * @param key Key used in config file. If key is null, name is used as key.
+ * @return The created item
+ */
+ ItemIntList *addItemIntList(const QString & name, QValueList < int >&reference,
+ const QValueList < int >&defaultValue =
+ QValueList < int >(),
+ const QString & key = QString::null);
+
+ /**
+ * Return the @ref KConfig object used for reading and writing the settings.
+ */
+ KConfig *config() const;
+
+ /**
+ * Return list of items managed by this KConfigSkeleton object.
+ */
+ KConfigSkeletonItem::List items() const
+ {
+ return mItems;
+ }
+
+ /**
+ * Return whether a certain item is immutable
+ */
+ bool isImmutable(const QString & name);
+
+ /**
+ * Lookup item by name
+ */
+ KConfigSkeletonItem * findItem(const QString & name);
+
+ /**
+ * Indicate whether this object should reflect the actual
+ * values or the default values.
+ * @param b If true this object reflects the default values.
+ * @return The state prior to this call
+ */
+ bool useDefaults(bool b);
+
+protected:
+ /**
+ * Implemented by subclasses that use special defaults.
+ * It should replace the default values with the actual
+ * values and vice versa.
+ */
+ virtual void usrUseDefaults(bool)
+ {
+ }
+
+ virtual void usrSetDefaults()
+ {
+ }
+
+ /**
+ * Implemented by subclasses that read special config values.
+ */
+ virtual void usrReadConfig()
+ {
+ }
+
+ /**
+ * Implemented by subclasses that write special config values.
+ */
+ virtual void usrWriteConfig()
+ {
+ }
+
+private:
+ QString mCurrentGroup;
+
+ KSharedConfig::Ptr mConfig; // pointer to KConfig object
+
+ KConfigSkeletonItem::List mItems;
+ KConfigSkeletonItem::Dict mItemDict;
+
+ bool mUseDefaults;
+
+ class Private;
+ Private *d;
+
+};
+
+#endif
diff --git a/kdecore/kcrash.cpp b/kdecore/kcrash.cpp
new file mode 100644
index 000000000..61ba5f796
--- /dev/null
+++ b/kdecore/kcrash.cpp
@@ -0,0 +1,522 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
+ * Tom Braun <braunt@fh-konstanz.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file is used to catch signals which would normally
+ * crash the application (like segmentation fault, floating
+ * point exception and such).
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include "kcrash.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <qwindowdefs.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+
+#include <../kinit/klauncher_cmds.h>
+
+#if defined Q_WS_X11
+#include <X11/Xlib.h>
+#endif
+
+KCrash::HandlerType KCrash::_emergencySaveFunction = 0;
+KCrash::HandlerType KCrash::_crashHandler = 0;
+const char *KCrash::appName = 0;
+const char *KCrash::appPath = 0;
+bool KCrash::safer = false;
+
+// This function sets the function which should be called when the
+// application crashes and the
+// application is asked to try to save its data.
+void
+KCrash::setEmergencySaveFunction (HandlerType saveFunction)
+{
+ _emergencySaveFunction = saveFunction;
+
+ /*
+ * We need at least the default crash handler for
+ * emergencySaveFunction to be called
+ */
+ if (_emergencySaveFunction && !_crashHandler)
+ _crashHandler = defaultCrashHandler;
+}
+
+
+// This function sets the function which should be responsible for
+// the application crash handling.
+void
+KCrash::setCrashHandler (HandlerType handler)
+{
+#ifdef Q_OS_UNIX
+ if (!handler)
+ handler = SIG_DFL;
+
+ sigset_t mask;
+ sigemptyset(&mask);
+
+#ifdef SIGSEGV
+ signal (SIGSEGV, handler);
+ sigaddset(&mask, SIGSEGV);
+#endif
+#ifdef SIGFPE
+ signal (SIGFPE, handler);
+ sigaddset(&mask, SIGFPE);
+#endif
+#ifdef SIGILL
+ signal (SIGILL, handler);
+ sigaddset(&mask, SIGILL);
+#endif
+#ifdef SIGABRT
+ signal (SIGABRT, handler);
+ sigaddset(&mask, SIGABRT);
+#endif
+
+ sigprocmask(SIG_UNBLOCK, &mask, 0);
+#endif //Q_OS_UNIX
+
+ _crashHandler = handler;
+}
+
+void
+KCrash::defaultCrashHandler (int sig)
+{
+#ifdef Q_OS_UNIX
+ // WABA: Do NOT use kdDebug() in this function because it is much too risky!
+ // Handle possible recursions
+ static int crashRecursionCounter = 0;
+ crashRecursionCounter++; // Nothing before this, please !
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(3); // Kill me... (in case we deadlock in malloc)
+
+ if (crashRecursionCounter < 2) {
+ if (_emergencySaveFunction) {
+ _emergencySaveFunction (sig);
+ }
+ crashRecursionCounter++; //
+ }
+
+ // Close all remaining file descriptors except for stdin/stdout/stderr
+ struct rlimit rlp;
+ getrlimit(RLIMIT_NOFILE, &rlp);
+ for (int i = 3; i < (int)rlp.rlim_cur; i++)
+ close(i);
+
+
+ // this code is leaking, but this should not hurt cause we will do a
+ // exec() afterwards. exec() is supposed to clean up.
+ if (crashRecursionCounter < 3)
+ {
+ if (appName)
+ {
+#ifndef NDEBUG
+ fprintf(stderr, "KCrash: crashing... crashRecursionCounter = %d\n", crashRecursionCounter);
+ fprintf(stderr, "KCrash: Application Name = %s path = %s pid = %d\n", appName ? appName : "<unknown>" , appPath ? appPath : "<unknown>", getpid());
+#else
+ fprintf(stderr, "KCrash: Application '%s' crashing...\n", appName ? appName : "<unknown>");
+#endif
+
+ const char * argv[24]; // don't forget to update this
+ int i = 0;
+
+ // argument 0 has to be drkonqi
+ argv[i++] = "drkonqi";
+
+#if defined Q_WS_X11
+ // start up on the correct display
+ argv[i++] = "-display";
+ if ( qt_xdisplay() )
+ argv[i++] = XDisplayString(qt_xdisplay());
+ else
+ argv[i++] = getenv("DISPLAY");
+#elif defined(Q_WS_QWS)
+ // start up on the correct display
+ argv[i++] = "-display";
+ argv[i++] = getenv("QWS_DISPLAY");
+#endif
+
+ // we have already tested this
+ argv[i++] = "--appname";
+ argv[i++] = appName;
+ if (KApplication::loadedByKdeinit)
+ argv[i++] = "--kdeinit";
+
+ // only add apppath if it's not NULL
+ if (appPath) {
+ argv[i++] = "--apppath";
+ argv[i++] = appPath;
+ }
+
+ // signal number -- will never be NULL
+ char sigtxt[ 10 ];
+ sprintf( sigtxt, "%d", sig );
+ argv[i++] = "--signal";
+ argv[i++] = sigtxt;
+
+ char pidtxt[ 10 ];
+ sprintf( pidtxt, "%d", getpid());
+ argv[i++] = "--pid";
+ argv[i++] = pidtxt;
+
+ const KInstance *instance = KGlobal::_instance;
+ const KAboutData *about = instance ? instance->aboutData() : 0;
+ if (about) {
+ if (about->internalVersion()) {
+ argv[i++] = "--appversion";
+ argv[i++] = about->internalVersion();
+ }
+
+ if (about->internalProgramName()) {
+ argv[i++] = "--programname";
+ argv[i++] = about->internalProgramName();
+ }
+
+ if (about->internalBugAddress()) {
+ argv[i++] = "--bugaddress";
+ argv[i++] = about->internalBugAddress();
+ }
+ }
+
+ if ( kapp && !kapp->startupId().isNull()) {
+ argv[i++] = "--startupid";
+ argv[i++] = kapp->startupId().data();
+ }
+
+ if ( safer )
+ argv[i++] = "--safer";
+
+ // NULL terminated list
+ argv[i] = NULL;
+
+ startDrKonqi( argv, i );
+ _exit(253);
+
+ }
+ else {
+ fprintf(stderr, "Unknown appname\n");
+ }
+ }
+
+ if (crashRecursionCounter < 4)
+ {
+ fprintf(stderr, "Unable to start Dr. Konqi\n");
+ }
+#endif //Q_OS_UNIX
+
+ _exit(255);
+}
+
+#ifdef Q_OS_UNIX
+
+// Since we can't fork() in the crashhandler, we cannot execute any external code
+// (there can be functions registered to be performed before fork(), for example
+// handling of malloc locking, which doesn't work when malloc crashes because of heap corruption).
+
+static int write_socket(int sock, char *buffer, int len);
+static int read_socket(int sock, char *buffer, int len);
+static int openSocket();
+
+void KCrash::startDrKonqi( const char* argv[], int argc )
+{
+ int socket = openSocket();
+ if( socket < -1 )
+ {
+ startDirectly( argv, argc );
+ return;
+ }
+ klauncher_header header;
+ header.cmd = LAUNCHER_EXEC_NEW;
+ const int BUFSIZE = 8192; // make sure this is big enough
+ char buffer[ BUFSIZE + 10 ];
+ int pos = 0;
+ long argcl = argc;
+ memcpy( buffer + pos, &argcl, sizeof( argcl ));
+ pos += sizeof( argcl );
+ for( int i = 0;
+ i < argc;
+ ++i )
+ {
+ int len = strlen( argv[ i ] ) + 1; // include terminating \0
+ if( pos + len > BUFSIZE )
+ {
+ fprintf( stderr, "BUFSIZE in KCrash not big enough!\n" );
+ startDirectly( argv, argc );
+ return;
+ }
+ memcpy( buffer + pos, argv[ i ], len );
+ pos += len;
+ }
+ long env = 0;
+ memcpy( buffer + pos, &env, sizeof( env ));
+ pos += sizeof( env );
+ long avoid_loops = 0;
+ memcpy( buffer + pos, &avoid_loops, sizeof( avoid_loops ));
+ pos += sizeof( avoid_loops );
+ header.arg_length = pos;
+ write_socket(socket, (char *) &header, sizeof(header));
+ write_socket(socket, buffer, pos);
+ if( read_socket( socket, (char *) &header, sizeof(header)) < 0
+ || header.cmd != LAUNCHER_OK )
+ {
+ startDirectly( argv, argc );
+ return;
+ }
+ long pid;
+ read_socket(socket, buffer, header.arg_length);
+ pid = *((long *) buffer);
+
+ alarm(0); // Seems we made it....
+
+ for(;;)
+ {
+ if( kill( pid, 0 ) < 0 )
+ _exit(253);
+ sleep(1);
+ // the debugger should stop this process anyway
+ }
+}
+
+// If we can't reach kdeinit we can still at least try to fork()
+void KCrash::startDirectly( const char* argv[], int )
+{
+ fprintf( stderr, "KCrash cannot reach kdeinit, launching directly.\n" );
+ pid_t pid = fork();
+ if (pid <= 0)
+ {
+ if(!geteuid() && setgid(getgid()) < 0)
+ _exit(253);
+ if(!geteuid() && setuid(getuid()) < 0)
+ _exit(253);
+ execvp("drkonqi", const_cast< char** >( argv ));
+ _exit(errno);
+ }
+ else
+ {
+ alarm(0); // Seems we made it....
+ // wait for child to exit
+ waitpid(pid, NULL, 0);
+ _exit(253);
+ }
+}
+
+// From now on this code is copy&pasted from kinit/wrapper.c :
+
+extern char **environ;
+
+static char *getDisplay()
+{
+ const char *display;
+ char *result;
+ char *screen;
+ char *colon;
+ char *i;
+/*
+ don't test for a value from qglobal.h but instead distinguish
+ Qt/X11 from Qt/Embedded by the fact that Qt/E apps have -DQWS
+ on the commandline (which in qglobal.h however triggers Q_WS_QWS,
+ but we don't want to include that here) (Simon)
+#ifdef Q_WS_X11
+ */
+#if !defined(QWS)
+ display = getenv("DISPLAY");
+#else
+ display = getenv("QWS_DISPLAY");
+#endif
+ if (!display || !*display)
+ {
+ display = ":0";
+ }
+ result = (char*)malloc(strlen(display)+1);
+ if (result == NULL)
+ return NULL;
+
+ strcpy(result, display);
+ screen = strrchr(result, '.');
+ colon = strrchr(result, ':');
+ if (screen && (screen > colon))
+ *screen = '\0';
+ while((i = strchr(result, ':')))
+ *i = '_';
+ return result;
+}
+
+/*
+ * Write 'len' bytes from 'buffer' into 'sock'.
+ * returns 0 on success, -1 on failure.
+ */
+static int write_socket(int sock, char *buffer, int len)
+{
+ ssize_t result;
+ int bytes_left = len;
+ while ( bytes_left > 0)
+ {
+ result = write(sock, buffer, bytes_left);
+ if (result > 0)
+ {
+ buffer += result;
+ bytes_left -= result;
+ }
+ else if (result == 0)
+ return -1;
+ else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Read 'len' bytes from 'sock' into 'buffer'.
+ * returns 0 on success, -1 on failure.
+ */
+static int read_socket(int sock, char *buffer, int len)
+{
+ ssize_t result;
+ int bytes_left = len;
+ while ( bytes_left > 0)
+ {
+ result = read(sock, buffer, bytes_left);
+ if (result > 0)
+ {
+ buffer += result;
+ bytes_left -= result;
+ }
+ else if (result == 0)
+ return -1;
+ else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
+ return -1;
+ }
+ return 0;
+}
+
+static int openSocket()
+{
+ kde_socklen_t socklen;
+ int s;
+ struct sockaddr_un server;
+#define MAX_SOCK_FILE 255
+ char sock_file[MAX_SOCK_FILE + 1];
+ const char *home_dir = getenv("HOME");
+ const char *kde_home = getenv("KDEHOME");
+ char *display;
+
+ sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
+
+ if (!kde_home || !kde_home[0])
+ {
+ kde_home = "~/.kde/";
+ }
+
+ if (kde_home[0] == '~')
+ {
+ if (!home_dir || !home_dir[0])
+ {
+ fprintf(stderr, "Warning: $HOME not set!\n");
+ return -1;
+ }
+ if (strlen(home_dir) > (MAX_SOCK_FILE-100))
+ {
+ fprintf(stderr, "Warning: Home directory path too long!\n");
+ return -1;
+ }
+ kde_home++;
+ strncpy(sock_file, home_dir, MAX_SOCK_FILE);
+ }
+ strncat(sock_file, kde_home, MAX_SOCK_FILE - strlen(sock_file));
+
+ /** Strip trailing '/' **/
+ if ( sock_file[strlen(sock_file)-1] == '/')
+ sock_file[strlen(sock_file)-1] = 0;
+
+ strncat(sock_file, "/socket-", MAX_SOCK_FILE - strlen(sock_file));
+ if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
+ {
+ perror("Warning: Could not determine hostname: ");
+ return -1;
+ }
+ sock_file[sizeof(sock_file)-1] = '\0';
+
+ /* append $DISPLAY */
+ display = getDisplay();
+ if (display == NULL)
+ {
+ fprintf(stderr, "Error: Could not determine display.\n");
+ return -1;
+ }
+
+ if (strlen(sock_file)+strlen(display)+strlen("/kdeinit_")+2 > MAX_SOCK_FILE)
+ {
+ fprintf(stderr, "Warning: Socket name will be too long.\n");
+ free(display);
+ return -1;
+ }
+ strcat(sock_file, "/kdeinit_");
+ strcat(sock_file, display);
+ free(display);
+
+ if (strlen(sock_file) >= sizeof(server.sun_path))
+ {
+ fprintf(stderr, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
+ return -1;
+ }
+
+ /*
+ * create the socket stream
+ */
+ s = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (s < 0)
+ {
+ perror("Warning: socket() failed: ");
+ return -1;
+ }
+
+ server.sun_family = AF_UNIX;
+ strcpy(server.sun_path, sock_file);
+ socklen = sizeof(server);
+ if(connect(s, (struct sockaddr *)&server, socklen) == -1)
+ {
+ perror("Warning: connect() failed: ");
+ close(s);
+ return -1;
+ }
+ return s;
+}
+
+#endif // Q_OS_UNIX
diff --git a/kdecore/kcrash.h b/kdecore/kcrash.h
new file mode 100644
index 000000000..a2fe969ea
--- /dev/null
+++ b/kdecore/kcrash.h
@@ -0,0 +1,127 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
+ * Tom Braun <braunt@fh-konstanz.de>
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KCRASH_H
+#define __KCRASH_H
+
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+/**
+ * This class handles segmentation-faults.
+ * By default it displays a message-box saying the application crashed.
+ * This default can be overridden by setting a custom crash handler with
+ * setCrashHandler().
+ * If a function is specified with setEmergencySaveFunction() it will
+ * be called by the default crash handler, giving the application a chance
+ * to save its data.
+ */
+class KDECORE_EXPORT KCrash
+{
+ private: // ;o)
+ static const char *appName;
+ static const char *appPath;
+ static bool safer;
+
+ public:
+ /**
+ * The default crash handler.
+ * @param signal the signal number
+ */
+ static void defaultCrashHandler (int signal);
+
+ /**
+ * This function type is a pointer to a crash handler function.
+ * The function's argument is the number of the signal.
+ */
+ typedef void (*HandlerType)(int);
+
+ /**
+ * Install a function to be called in case a SIGSEGV is caught.
+ * @param handler HandlerType handler can be one of
+ * @li null in which case signal-catching is disabled
+ * (by calling signal(SIGSEGV, SIG_DFL))
+ * @li if handler is omitted the default crash handler is installed.
+ * @li an user defined function in the form:
+ * static (if in a class) void myCrashHandler(int);
+ * @param handler the crash handler
+ */
+
+ static void setCrashHandler (HandlerType handler = defaultCrashHandler);
+
+ /**
+ * Returns the installed crash handler.
+ * @return the crash handler
+ */
+ static HandlerType crashHandler() { return _crashHandler; }
+
+ /**
+ * Installs a function which should try to save the applications data.
+ * It is the crash handler´s responsibility to call this function.
+ * Therefore, if no crash handler is set, the default crash handler
+ * is installed to ensure the save function is called.
+ * @param saveFunction the handler to install
+ */
+ static void setEmergencySaveFunction (HandlerType saveFunction = (HandlerType)0);
+ /**
+ * Return the currently set emergency save function.
+ * @return the emergency save function
+ */
+ static HandlerType emergencySaveFunction() { return _emergencySaveFunction; }
+
+ /**
+ * Set whether to start drkonqi without arbitrary disk access
+ */
+ static void setSafer( bool on ) { safer = on; }
+
+ /**
+ * Sets the application @p path which should be passed to
+ * Dr. Konqi, our nice crash display application.
+ * @param path the application path.
+ */
+ static void setApplicationPath (QString path) { appPath = qstrdup(path.local8Bit().data()); }
+ /* KDE 4: Make it const QString & */
+
+ /**
+ * Sets the application name @p name which should be passed to
+ * Dr. Konqi, our nice crash display application.
+ * @param name the name of the application, as shown in Dr. Konqi
+ */
+ static void setApplicationName (QString name) { appName = qstrdup(name.local8Bit().data()); }
+ /* KDE 4: Make it const QString & */
+
+ protected:
+ /**
+ * Pointer to the crash handler.
+ */
+ static HandlerType _crashHandler;
+ /**
+ * Pointer to the emergency save function.
+ */
+ static HandlerType _emergencySaveFunction;
+
+ private:
+ static void startDrKonqi( const char* argv[], int argc );
+ static void startDirectly( const char* argv[], int argc );
+};
+
+#endif
+
diff --git a/kdecore/kdcoppropertyproxy.cpp b/kdecore/kdcoppropertyproxy.cpp
new file mode 100644
index 000000000..e9c024fa0
--- /dev/null
+++ b/kdecore/kdcoppropertyproxy.cpp
@@ -0,0 +1,335 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kdcoppropertyproxy.h"
+
+#include <qstrlist.h>
+#include <qmetaobject.h>
+#include <qvariant.h>
+#include <qcursor.h>
+#include <qbitmap.h>
+#include <qregion.h>
+#include <qpointarray.h>
+#include <qiconset.h>
+#include <qfont.h>
+#include <qimage.h>
+#include <qbrush.h>
+#include <qpalette.h>
+
+#include <ctype.h>
+#include <assert.h>
+
+class KDCOPPropertyProxyPrivate
+{
+public:
+ KDCOPPropertyProxyPrivate()
+ {
+ }
+ ~KDCOPPropertyProxyPrivate()
+ {
+ }
+
+ QObject *m_object;
+};
+
+KDCOPPropertyProxy::KDCOPPropertyProxy( QObject *object )
+{
+ d = new KDCOPPropertyProxyPrivate;
+ d->m_object = object;
+}
+
+KDCOPPropertyProxy::~KDCOPPropertyProxy()
+{
+ delete d;
+}
+
+bool KDCOPPropertyProxy::isPropertyRequest( const QCString &fun )
+{
+ return isPropertyRequest( fun, d->m_object );
+}
+
+bool KDCOPPropertyProxy::processPropertyRequest( const QCString &fun, const QByteArray &data,
+ QCString &replyType, QByteArray &replyData )
+{
+ return processPropertyRequest( fun, data, replyType, replyData, d->m_object );
+}
+
+QValueList<QCString> KDCOPPropertyProxy::functions()
+{
+ return functions( d->m_object );
+}
+
+bool KDCOPPropertyProxy::isPropertyRequest( const QCString &fun, QObject *object )
+{
+ if ( fun == "property(QCString)" ||
+ fun == "setProperty(QCString,QVariant)" ||
+ fun == "propertyNames(bool)" )
+ return true;
+
+ bool set;
+ QCString propName, arg;
+ return decodePropertyRequestInternal( fun, object, set, propName, arg );
+}
+
+QValueList<QCString> KDCOPPropertyProxy::functions( QObject *object )
+{
+ QValueList<QCString> res;
+ res << "QVariant property(QCString property)";
+ res << "bool setProperty(QCString name,QVariant property)";
+ res << "QValueList<QCString> propertyNames(bool super)";
+
+ QMetaObject *metaObj = object->metaObject();
+ QStrList properties = metaObj->propertyNames( true );
+ QStrListIterator it( properties );
+ for (; it.current(); ++it )
+ {
+ const QMetaProperty *metaProp = metaObj->property( metaObj->findProperty( it.current(), true ), true );
+
+ assert( metaProp );
+
+ QCString name = it.current();
+ name.prepend( " " );
+ name.prepend( metaProp->type() );
+ name.append( "()" );
+ res << name;
+
+ if ( metaProp->writable() )
+ {
+ QCString setName = it.current();
+ setName[ 0 ] = toupper( setName[ 0 ] );
+ setName = "void set" + setName + "(" + metaProp->type() + " " + it.current() + ")";
+ res << setName;
+ }
+ }
+
+ return res;
+}
+
+bool KDCOPPropertyProxy::processPropertyRequest( const QCString &fun, const QByteArray &data,
+ QCString &replyType, QByteArray &replyData,
+ QObject *object )
+{
+ if ( fun == "property(QCString)" )
+ {
+ QCString propName;
+ QDataStream stream( data, IO_ReadOnly );
+ stream >> propName;
+
+ replyType = "QVariant";
+ QDataStream reply( replyData, IO_WriteOnly );
+ reply << object->property( propName );
+ return true;
+ }
+
+ if ( fun == "setProperty(QCString,QVariant)" )
+ {
+ QCString propName;
+ QVariant propValue;
+ QDataStream stream( data, IO_ReadOnly );
+ stream >> propName >> propValue;
+
+ replyType = "bool";
+ QDataStream reply( replyData, IO_WriteOnly );
+ reply << (Q_INT8)object->setProperty( propName, propValue );
+ return true;
+ }
+
+ if ( fun == "propertyNames(bool)" )
+ {
+ Q_INT8 b;
+ QDataStream stream( data, IO_ReadOnly );
+ stream >> b;
+
+ QValueList<QCString> res;
+ QStrList props = object->metaObject()->propertyNames( static_cast<bool>( b ) );
+ QStrListIterator it( props );
+ for (; it.current(); ++it )
+ res.append( it.current() );
+
+ replyType = "QValueList<QCString>";
+ QDataStream reply( replyData, IO_WriteOnly );
+ reply << res;
+ return true;
+ }
+
+ bool set;
+ QCString propName, arg;
+
+ bool res = decodePropertyRequestInternal( fun, object, set, propName, arg );
+ if ( !res )
+ return false;
+
+ if ( set )
+ {
+ QVariant prop;
+ QDataStream stream( data, IO_ReadOnly );
+
+ QVariant::Type type = QVariant::nameToType( arg );
+ if ( type == QVariant::Invalid )
+ return false;
+
+#define DEMARSHAL( type, val ) \
+ case QVariant::type: \
+ { \
+ val v; \
+ stream >> v; \
+ prop = QVariant( v ); \
+ } \
+ break;
+
+ typedef QValueList<QVariant> ListType;
+ typedef QMap<QString,QVariant> MapType;
+
+ switch ( type )
+ {
+ DEMARSHAL( Cursor, QCursor )
+ DEMARSHAL( Bitmap, QBitmap )
+ DEMARSHAL( PointArray, QPointArray )
+ DEMARSHAL( Region, QRegion )
+ DEMARSHAL( List, ListType )
+ DEMARSHAL( Map, MapType )
+ DEMARSHAL( String, QString )
+ DEMARSHAL( CString, QCString )
+ DEMARSHAL( StringList, QStringList )
+ DEMARSHAL( Font, QFont )
+ DEMARSHAL( Pixmap, QPixmap )
+ DEMARSHAL( Image, QImage )
+ DEMARSHAL( Brush, QBrush )
+ DEMARSHAL( Point, QPoint )
+ DEMARSHAL( Rect, QRect )
+ DEMARSHAL( Size, QSize )
+ DEMARSHAL( Color, QColor )
+ DEMARSHAL( Palette, QPalette )
+ DEMARSHAL( ColorGroup, QColorGroup )
+ case QVariant::IconSet:
+ {
+ QPixmap val;
+ stream >> val;
+ prop = QVariant( QIconSet( val ) );
+ }
+ break;
+ DEMARSHAL( Int, int )
+ DEMARSHAL( UInt, uint )
+ case QVariant::Bool:
+ {
+ Q_INT8 v;
+ stream >> v;
+ prop = QVariant( static_cast<bool>( v ), 1 );
+ }
+ break;
+ DEMARSHAL( Double, double )
+ default:
+ return false;
+ }
+
+ replyType = "void";
+ return object->setProperty( propName, prop );
+ }
+ else
+ {
+ QVariant prop = object->property( propName );
+
+ if ( prop.type() == QVariant::Invalid )
+ return false;
+
+ replyType = prop.typeName();
+ QDataStream reply( replyData, IO_WriteOnly );
+
+#define MARSHAL( type ) \
+ case QVariant::type: \
+ reply << prop.to##type(); \
+ break;
+
+ switch ( prop.type() )
+ {
+ MARSHAL( Cursor )
+ MARSHAL( Bitmap )
+ MARSHAL( PointArray )
+ MARSHAL( Region )
+ MARSHAL( List )
+ MARSHAL( Map )
+ MARSHAL( String )
+ MARSHAL( CString )
+ MARSHAL( StringList )
+ MARSHAL( Font )
+ MARSHAL( Pixmap )
+ MARSHAL( Image )
+ MARSHAL( Brush )
+ MARSHAL( Point )
+ MARSHAL( Rect )
+ MARSHAL( Size )
+ MARSHAL( Color )
+ MARSHAL( Palette )
+ MARSHAL( ColorGroup )
+ case QVariant::IconSet:
+ reply << prop.toIconSet().pixmap();
+ break;
+ MARSHAL( Int )
+ MARSHAL( UInt )
+ case QVariant::Bool:
+ reply << (Q_INT8)prop.toBool();
+ break;
+ MARSHAL( Double )
+ default:
+ return false;
+ }
+
+#undef MARSHAL
+#undef DEMARSHAL
+
+ return true;
+ }
+
+ return false;
+}
+
+bool KDCOPPropertyProxy::decodePropertyRequestInternal( const QCString &fun, QObject *object, bool &set,
+ QCString &propName, QCString &arg )
+{
+ if ( fun.length() < 3 )
+ return false;
+
+ set = false;
+
+ propName = fun;
+
+ if ( propName.left( 3 ) == "set" )
+ {
+ propName.detach();
+ set = true;
+ propName = propName.mid( 3 );
+ int p1 = propName.find( '(' );
+
+ uint len = propName.length();
+
+ if ( propName[ len - 1 ] != ')' )
+ return false;
+
+ arg = propName.mid( p1+1, len - p1 - 2 );
+ propName.truncate( p1 );
+ propName[ 0 ] = tolower( propName[ 0 ] );
+ }
+ else
+ propName.truncate( propName.length() - 2 );
+
+ if ( !object->metaObject()->propertyNames( true ).contains( propName ) )
+ return false;
+
+ return true;
+}
diff --git a/kdecore/kdcoppropertyproxy.h b/kdecore/kdcoppropertyproxy.h
new file mode 100644
index 000000000..97b5f6f73
--- /dev/null
+++ b/kdecore/kdcoppropertyproxy.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __kdcoppropertyproxy_h__
+#define __kdcoppropertyproxy_h__
+
+#include <qobject.h>
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include "kdelibs_export.h"
+
+class KDCOPPropertyProxyPrivate;
+/**
+ * The KDCOPPropertyProxy class provides an easy way to publish Qt properties of a
+ * QObject through DCOP.
+ *
+ * The class provides DCOP equivalents for the Qt property methods setProperty() ,
+ * property() and propertyNames() and also provides automatic set/get methods for
+ * the properties of a QObject. That means for example if your object provides a
+ * QString property called foo , then KDCOPPropertyProxy translates DCOP calls
+ * "setFoo( QString )" and "QString foo()" automatically into the corresponding
+ * setProperty/property calls.
+ */
+class KDECORE_EXPORT KDCOPPropertyProxy
+{
+public:
+ /**
+ * Convenience constructor. Use it if you want to use this class as object, in contrary
+ * to using the static methods of this class and providing a QObject argument for each
+ * call.
+ */
+ KDCOPPropertyProxy( QObject *object );
+ /**
+ * Destructor.
+ */
+ ~KDCOPPropertyProxy();
+
+ /**
+ * Convenience method, when using this class as object. See documentation of the constructor and
+ * static isPropertyRequest method.
+ */
+ bool isPropertyRequest( const QCString &fun );
+
+ /**
+ * Convenience method, when using this class as object. See documentation of the constructor and
+ * static processPropertyRequest method.
+ */
+ bool processPropertyRequest( const QCString &fun, const QByteArray &data, QCString &replyType,
+ QByteArray &replyData );
+
+ /**
+ * Convenience method, when using this class as object. See documentation of the constructor and
+ * static functions method.
+ */
+ QValueList<QCString> functions();
+
+ /**
+ * Returns a semicolon-separated list of functions understood by the PropertyProxy for the given
+ * QObject argument.
+ *
+ * Returns "property(QCString);setProperty(QCString,QVariant);propertyNames();" plus set/get
+ * methods for the properties of the given object argument.
+ *
+ * @see DCOPObject::functions()
+ */
+ static QValueList<QCString> functions( QObject *object );
+
+ /**
+ * Returns true if the method request in the fun argument matches the signature of the three standard
+ * property methods or set/get methods for the properties of the object argument.
+ *
+ * Use this method in your own DCOPObject dispatcher to check if the DCOP request is a property
+ * request which can be handled by this class.
+ */
+ static bool isPropertyRequest( const QCString &fun, QObject *object );
+
+ /**
+ * Processes the given DCOP method request by translating the request into a setProperty/property call
+ * on the given QObject argument.
+ */
+ static bool processPropertyRequest( const QCString &fun, const QByteArray &data, QCString &replyType,
+ QByteArray &replyData, QObject *object );
+
+private:
+ static bool decodePropertyRequestInternal( const QCString &fun, QObject *object, bool &set,
+ QCString &propName, QCString &arg );
+
+ KDCOPPropertyProxyPrivate *d;
+};
+
+#endif
diff --git a/kdecore/kde-config.cpp.in b/kdecore/kde-config.cpp.in
new file mode 100644
index 000000000..2a9b66bdf
--- /dev/null
+++ b/kdecore/kde-config.cpp.in
@@ -0,0 +1,270 @@
+// -*- c++ -*-
+
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kinstance.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <stdio.h>
+#include <kaboutdata.h>
+#include <config.h>
+#include <kapplication.h>
+
+static const char *description = I18N_NOOP("A little program to output installation paths");
+
+static KCmdLineOptions options[] =
+{
+ { "expandvars", I18N_NOOP("expand ${prefix} and ${exec_prefix} in output"), 0 },
+ { "prefix", I18N_NOOP("Compiled in prefix for KDE libraries"), 0 },
+ { "exec-prefix", I18N_NOOP("Compiled in exec_prefix for KDE libraries"), 0 },
+ { "libsuffix", I18N_NOOP("Compiled in library path suffix"), 0 },
+ { "localprefix", I18N_NOOP("Prefix in $HOME used to write files"), 0},
+ { "version", I18N_NOOP("Compiled in version string for KDE libraries"), 0 },
+ { "types", I18N_NOOP("Available KDE resource types"), 0 },
+ { "path type", I18N_NOOP("Search path for resource type"), 0 },
+ { "userpath type", I18N_NOOP("User path: desktop|autostart|trash|document"), 0 },
+ { "install type", I18N_NOOP("Prefix to install resource files to"), 0},
+ { 0,0,0 }
+};
+
+bool _expandvars = false;
+
+QString expandvars(const char *_input)
+{
+ QString result = QString::fromLatin1(_input);
+ if (!_expandvars)
+ return result;
+
+ bool changed = false;
+ int index = result.find("${prefix}");
+ if (index >= 0) {
+ result = result.replace(index, 9, "@prefix@");
+ changed = true;
+ }
+ index = result.find("$(prefix)");
+ if (index >= 0) {
+ result = result.replace(index, 9, "@prefix@");
+ changed = true;
+ }
+ index = result.find("${datadir}");
+ if (index >= 0) {
+ result = result.replace(index, 10, "@datadir@");
+ changed = true;
+ }
+ index = result.find("$(datadir)");
+ if (index >= 0) {
+ result = result.replace(index, 10, "@datadir@");
+ changed = true;
+ }
+ index = result.find("${exec_prefix}");
+ if (index >= 0) {
+ result = result.replace(index, 14, "@exec_prefix@");
+ changed = true;
+ }
+ index = result.find("$(exec_prefix)");
+ if (index >= 0) {
+ result = result.replace(index, 14, "@exec_prefix@");
+ changed = true;
+ }
+ index = result.find("${libdir}");
+ if (index >= 0) {
+ result = result.replace(index, 9, "@libdir@");
+ changed = true;
+ }
+ index = result.find("$(libdir)");
+ if (index >= 0) {
+ result = result.replace(index, 9, "@libdir@");
+ changed = true;
+ }
+ index = result.find("${includedir}");
+ if (index >= 0) {
+ result = result.replace(index, 20, "@includedir@");
+ changed = true;
+ }
+ index = result.find("$(includedir)");
+ if (index >= 0) {
+ result = result.replace(index, 20, "@includedir@");
+ changed = true;
+ }
+ index = result.find("${sysconfdir}");
+ if (index >= 0) {
+ result = result.replace(index, 13, "@sysconfdir@");
+ changed = true;
+ }
+ index = result.find("$(sysconfdir)");
+ if (index >= 0) {
+ result = result.replace(index, 13, "@sysconfdir@");
+ changed = true;
+ }
+ if (changed)
+ return expandvars(result.latin1());
+ else
+ return result;
+}
+
+void printResult(const QString &s)
+{
+ if (s.isEmpty())
+ printf("\n");
+ else
+ printf("%s\n", s.local8Bit().data());
+}
+
+int main(int argc, char **argv)
+{
+ KLocale::setMainCatalogue("kdelibs");
+ KAboutData about("kde-config", "kde-config", "1.0", description, KAboutData::License_GPL, "(C) 2000 Stephan Kulow");
+ KCmdLineArgs::init( argc, argv, &about);
+
+ KCmdLineArgs::addCmdLineOptions( options ); // Add my own options.
+
+ KInstance a("kde-config");
+ (void)KGlobal::dirs(); // trigger the creation
+ (void)KGlobal::config();
+
+ // Get application specific arguments
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ _expandvars = args->isSet("expandvars");
+
+ if (args->isSet("prefix"))
+ {
+ printResult(expandvars("@prefix@"));
+ return 0;
+ }
+
+ if (args->isSet("exec-prefix"))
+ {
+ printResult(expandvars("@exec_prefix@"));
+ return 0;
+ }
+
+ if (args->isSet("libsuffix"))
+ {
+ QString tmp(KDELIBSUFF);
+ tmp.remove('"');
+ printResult(expandvars(tmp.local8Bit()));
+ return 0;
+ }
+
+ if (args->isSet("localprefix"))
+ {
+ printResult(KGlobal::dirs()->localkdedir());
+ return 0;
+ }
+
+ if (args->isSet("version"))
+ {
+ printf("%s\n", KDE_VERSION_STRING);
+ return 0;
+ }
+
+ if (args->isSet("types"))
+ {
+ QStringList types = KGlobal::dirs()->allTypes();
+ types.sort();
+ const char *helptexts[] = {
+ "apps", I18N_NOOP("Applications menu (.desktop files)"),
+ "cgi", I18N_NOOP("CGIs to run from kdehelp"),
+ "config", I18N_NOOP("Configuration files"),
+ "data", I18N_NOOP("Where applications store data"),
+ "exe", I18N_NOOP("Executables in $prefix/bin"),
+ "html", I18N_NOOP("HTML documentation"),
+ "icon", I18N_NOOP("Icons"),
+ "kcfg", I18N_NOOP("Configuration description files"),
+ "lib", I18N_NOOP("Libraries"),
+ "include", I18N_NOOP("Includes/Headers"),
+ "locale", I18N_NOOP("Translation files for KLocale"),
+ "mime", I18N_NOOP("Mime types"),
+ "module", I18N_NOOP("Loadable modules"),
+ "qtplugins", I18N_NOOP("Qt plugins"),
+ "services", I18N_NOOP("Services"),
+ "servicetypes", I18N_NOOP("Service types"),
+ "sound", I18N_NOOP("Application sounds"),
+ "templates", I18N_NOOP("Templates"),
+ "wallpaper", I18N_NOOP("Wallpapers"),
+ "xdgdata-apps", I18N_NOOP("XDG Application menu (.desktop files)"),
+ "xdgdata-dirs", I18N_NOOP("XDG Menu descriptions (.directory files)"),
+ "xdgconf-menu", I18N_NOOP("XDG Menu layout (.menu files)"),
+ "tmp", I18N_NOOP("Temporary files (specific for both current host and current user)"),
+ "socket", I18N_NOOP("UNIX Sockets (specific for both current host and current user)"),
+ 0, 0
+ };
+ for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it)
+ {
+ int index = 0;
+ while (helptexts[index] && *it != helptexts[index]) {
+ index += 2;
+ }
+ if (helptexts[index]) {
+ printf("%s - %s\n", helptexts[index], i18n(helptexts[index+1]).local8Bit().data());
+ } else {
+ printf("%s", i18n("%1 - unknown type\n").arg(*it).local8Bit().data());
+ }
+ }
+ return 0;
+ }
+
+ QString type = args->getOption("path");
+ if (!type.isEmpty())
+ {
+ printResult(KGlobal::dirs()->resourceDirs(type.latin1()).join(":"));
+ return 0;
+ }
+
+ type = args->getOption("userpath");
+ if (!type.isEmpty())
+ {
+ if ( type == "desktop" )
+ printResult(KGlobalSettings::desktopPath());
+ else if ( type == "autostart" )
+ printResult(KGlobalSettings::autostartPath());
+ else if ( type == "trash" )
+ printResult(KGlobalSettings::trashPath());
+ else if ( type == "document" )
+ printResult(KGlobalSettings::documentPath());
+ else
+ fprintf(stderr, "%s", i18n("%1 - unknown type of userpath\n").arg(type).local8Bit().data() );
+ return 0;
+ }
+
+ type = args->getOption("install");
+ if (!type.isEmpty())
+ {
+ const char *installprefixes[] = {
+ "apps", "@kde_appsdir@",
+ "config", "@kde_confdir@",
+ "kcfg", "@kde_kcfgdir@",
+ "data", "@kde_datadir@",
+ "exe", "@kde_bindir@",
+ "html", "@kde_htmldir@",
+ "icon", "@kde_icondir@",
+ "lib", "@libdir@",
+ "module", "@kde_moduledir@",
+ "qtplugins", "@kde_moduledir@/plugins",
+ "locale", "@kde_locale@",
+ "mime", "@kde_mimedir@",
+ "services", "@kde_servicesdir@",
+ "servicetypes", "@kde_servicetypesdir@",
+ "sound", "@kde_sounddir@",
+ "templates", "@kde_templatesdir@",
+ "wallpaper", "@kde_wallpaperdir@",
+ "xdgconf-menu", "@xdg_menudir@",
+ "xdgdata-apps", "@xdg_appsdir@",
+ "xdgdata-dirs", "@xdg_directorydir@",
+ "include", "@includedir@",
+ 0, 0
+ };
+ int index = 0;
+ while (installprefixes[index] && type != installprefixes[index]) {
+ index += 2;
+ }
+ if (installprefixes[index]) {
+ printResult(expandvars(installprefixes[index+1]));
+ } else {
+ printResult("NONE"); // no i18n here as for scripts
+ }
+ }
+ return 0;
+}
diff --git a/kdecore/kde_dmalloc.h b/kdecore/kde_dmalloc.h
new file mode 100644
index 000000000..4609349ae
--- /dev/null
+++ b/kdecore/kde_dmalloc.h
@@ -0,0 +1,28 @@
+/* This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ * These operators are used in conjunction with the dmalloc memory
+ * debugging library.
+ */
+#if !defined(KDE_DMALLOC_H) && defined(WITH_DMALLOC)
+#define KDE_DMALLOC_H
+
+#warning dmalloc support has been removed from KDE. use valgrind :)
+
+#endif
+
diff --git a/kdecore/kde_file.h b/kdecore/kde_file.h
new file mode 100644
index 000000000..b402aab29
--- /dev/null
+++ b/kdecore/kde_file.h
@@ -0,0 +1,125 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2001 Waldo Bastian <bastian@kde.org>
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDE_FILE_H_
+#define _KDE_FILE_H_
+
+/**
+ * \file kde_file.h
+ * \brief This file provides portable defines for file support.
+ *
+ * Use the KDE_xxx defines instead of the normal C
+ * functions and structures.
+ * \since 3.3
+ */
+
+#include <unistd.h>
+#ifdef _WIN32
+#include <kde_file_win.h>
+#endif
+
+#if (defined _LFS64_LARGEFILE) && (defined _LARGEFILE64_SOURCE)
+/*
+ * This section provides portable defines for large file support.
+ * To use this you must compile your code with _LARGEFILE64_SOURCE
+ * defined and use the KDE_xxx defines instead of the normal
+ * C functions and structures.
+ *
+ * Please note that not every platform supports 64 bit file structures,
+ * in that case the normal 32 bit functions will be used.
+ *
+ * @see http://www.suse.de/~aj/linux_lfs.html
+ * @see http://ftp.sas.com/standards/large.file/xopen/x_open.05Mar96.html
+ *
+ * KDE makes use of the "Transitional Extensions" since we can not ensure
+ * that all modules and libraries used by KDE will be compiled with
+ * 64-bit support.
+ * (A.3.2.3 Mixed API and Compile Environments within a Single Process)
+ */
+#define KDE_stat ::stat64
+#define KDE_lstat ::lstat64
+#define KDE_fstat ::fstat64
+#define KDE_open ::open64
+#define KDE_lseek ::lseek64
+#define KDE_fseek ::fseek64
+#define KDE_ftell ::ftell64
+#define KDE_fgetpos ::fgetpos64
+#define KDE_fsetpos ::fsetpos64
+#define KDE_readdir ::readdir64
+#define KDE_sendfile ::sendfile64
+#define KDE_struct_stat struct stat64
+#define KDE_struct_dirent struct dirent64
+#define KDE_rename ::rename
+#define KDE_mkdir ::mkdir
+/* TODO: define for win32 */
+
+#else /* !_LFS64_LARGEFILE */
+
+/*
+ * This section defines portable defines for standard file support.
+ */
+#ifdef _WIN32
+#define KDE_stat kdewin32_stat
+#define KDE_lstat kdewin32_lstat
+#define KDE_open kdewin32_open
+#define KDE_rename kdewin32_rename
+#define KDE_mkdir kdewin32_mkdir
+#else /* unix */
+#define KDE_stat ::stat
+#define KDE_lstat ::lstat
+#define KDE_open ::open
+#define KDE_rename ::rename
+#define KDE_mkdir ::mkdir
+#endif
+
+#define KDE_fstat ::fstat
+#define KDE_lseek ::lseek
+#define KDE_fseek ::fseek
+#define KDE_ftell ::ftell
+#define KDE_fgetpos ::fgetpos
+#define KDE_fsetpos ::fsetpos
+#define KDE_readdir ::readdir
+#define KDE_sendfile ::sendfile
+#define KDE_struct_stat struct stat
+#define KDE_struct_dirent struct dirent
+#endif
+
+
+#ifdef _LFS64_STDIO
+#define KDE_fopen ::fopen64
+#define KDE_freopen ::freopen64
+/* TODO: define for win32 */
+#else
+#ifdef _WIN32
+#define KDE_fopen kdewin32_fopen
+#define KDE_freopen kdewin32_freopen
+#else /* unix */
+#define KDE_fopen ::fopen
+#endif
+#endif
+
+/* functions without 64-bit version but wrapped for compatibility reasons */
+#ifdef _WIN32
+#define KDE_fdopen kdewin32_fdopen
+#else /* unix */
+#define KDE_fdopen ::fdopen
+#endif
+
+#endif /* _KDE_FILE_H_ */
diff --git a/kdecore/kdebug.areas b/kdecore/kdebug.areas
new file mode 100644
index 000000000..d1dc1ffa1
--- /dev/null
+++ b/kdecore/kdebug.areas
@@ -0,0 +1,599 @@
+#Debug areas for kdebug()
+# If you plan to add some areas, look at http://lists.kde.org/?l=kde-devel&m=106607933724723&w=2 first.
+# Applications of the kdenonbeta module (or similar) should not define any own area but use area 0.
+# When you add KDebug areas, email kde-devel@kde.org with the appropriate descriptions.
+#
+#Format : number<tab>description
+
+125 kdecore (KAccel)
+126 kdecore (KURL)
+127 kio (KProtocolInfo)
+128 kdecore (KRegExp)
+129 kdecore (KAction)
+130 kio (KPasswdServer)
+131 kdecore (KAcceleratorManager)
+150 kdecore (KLibLoader)
+160 kdecore (KNotifyClient)
+170 kdecore (KNetwork socket)
+171 kdecore (KSocks)
+172 kdecore (KStartupInfo)
+173 kdecore (KLocale)
+174 kdecore (KProcIO)
+175 kdecore (KProcess)
+176 kdecore (KWin)
+177 kdecore (KConfigSkeleton)
+178 kdecore (KConfigDialogManager)
+179 kdecore (KNetwork resolver)
+180 kdecore (kdelibs)
+200 kdeui (KMainWindow)
+220 kdeui (KToolBar)
+230 kdeui (KCommand)
+240 kdeui (kdelibs)
+250 kfile (kdelibs)
+264 kdecore (KIconLoader)
+265 kdecore (KIconEffect)
+270 kdeui (KRootPixmap)
+280 kdeui (KSharedPixmap)
+281 kdeui (KCModule)
+282 kdeui (KDockWidget)
+290 kdeui (KPixmapIO)
+291 kdeui (KAboutDialog)
+292 kdeui (KComboBox)
+293 kdeui (KLineEdit)
+294 kdeui (KEdit)
+295 kdeui (KMenuBar)
+296 kdeui (KPopupMenu)
+298 kdeui (KDatePicker)
+399 kimgio
+400 artskde
+500 kdeprint
+700 kutils (KSettings::Dialog)
+701 kutils (KSettings::Dispatcher)
+702 kutils (KPluginSelector)
+703 kutils (KPluginInfo)
+704 kutils (KSettings::ComponentsDialog)
+710 kutils (KCMultiDialog)
+711 kutils (KCModuleProxy)
+712 kutils (KCModuleInfo)
+713 kutils (KCModuleContainer)
+750 kspell (kdelibs)
+760 kmdi
+780 kcmshell (kdelibs)
+790 kimproxy (kdelibs)
+800 kabapi (kdelibs)
+900 kdesu (kdelibs)
+912 ksmartcard (kdelibs)
+
+
+1000 kparts
+1001 kparts (mainwindow)
+1002 kparts (factory)
+
+# kdebase
+1201 konqtree
+1202 konqueror
+1203 libkonq
+1204 kdesktop
+1205 kdesud
+1206 kdesu
+1207 kdesktop (Minicli)
+1208 kcontrol
+1210 kicker
+1211 konsole
+1212 kwin
+1213 kappfinder
+1214 kdesktop (icons)
+1215 ksysguard
+1216 kwin (client errors)
+1217 khotkeys
+1218 ksmserver
+1219 media kioslave
+1220 remote kioslave
+
+1400 khelpcenter (kdebase)
+1401 kcmhelpcenter
+1402 khc_indexbuilder
+
+1420 kikbd
+1421 ki18b_keys (kcmodule)
+
+1430 nspluginviewer (Qt/Xt)
+1431 nspluginviewer (plugin)
+1432 nspluginviewer (part)
+1433 nspluginscan
+
+# kdeutils
+1501 khexedit (kdeutils)
+1511 kdessh (kdeutils)
+1512 kdepasswd (kdeutils)
+1601 ark (kdeutils)
+1901 kfind
+1902 kfind (KfindWindow::updateResults)
+1903 kfind (KfindTabDialog::createQuery)
+2000 kfind
+2001 kregexpeditor
+2002 kfloppy
+2003 ksim
+2100 kgpg
+2200 kdf
+2300 kwallet
+
+# 2500-2999 Reserved for private use
+
+# kdeadmin
+3000 ksysv
+3100 ksysv (model)
+
+# kdegraphics
+4300 kdvi (kdegraphics)
+4400 kpaint (kdegraphics)
+4500 kghostview (kdegraphics)
+4600 kview
+4610 kviewviewer
+4620 kviewcanvas
+4630 kview_plugin
+4640 kiconedit
+
+# kdenetwork
+5001 kget
+5002 kppp
+5003 knode
+5004 kdict
+5005 knewsticker
+5006 kmail
+5007 kpf
+5008 ksirc
+5009 filesharing
+5050 libkmime
+5051 libkmime (Codecs)
+5052 libkmime (Plugin Loader)
+5100 libkdenetwork
+5150 libkleopatra
+
+
+# kdepim
+5200 kitchensync
+5201 kitchensync (Konnector)
+5202 kitchensync (OpieKonnector)
+5203 kitchensync (PhoneKonnector)
+5204 kitchensync (AgendaKonnector)
+5205 kitchensync (CasioKonnector)
+5210 kitchensync (KitchenSyncApp)
+5220 kitchensync (ManipulatorParts)
+5221 kitchensync (overviewpart)
+5222 kitchensync (organizerpart)
+5223 kitchensync (fileviewpart)
+5224 kitchensync Desktop
+5225 kitchensync (QtopiaKonnector)
+5226 kitchensync Categories
+5227 kitchensync Todo
+5228 kitchensync AddressBook
+5229 kitchensync Datebook
+5230 kitchensync SyncEntry
+5231 kitchensync SyncUI
+5250 kitchensync (Syncing Algorithm)
+5300 libkdepim
+5310 kprefs
+5400 calendarsystem
+5500 knotes
+5510 kpilot
+5511 kpilotdaemon
+5512 kpilotconduit
+5600 kontact (core)
+5601 kontact (interfaces)
+5602 kontact (plugins)
+5650 kresources
+5700 kabc
+5710 kabc/vcard
+5720 kaddressbook
+5800 libkcal
+5850 korganizer
+5855 korganizer (verbose)
+5890 korgac
+5891 korgac (check)
+5900 kalarmd
+5901 kalarmd (check)
+5950 kalarm
+5960 kandy
+5970 karm
+
+# libkhtml
+6000 khtml
+6005 khtml (encoding)
+6010 khtml (dom)
+6020 khtml (xml)
+6030 khtml (html)
+6031 khtml (frames & objects)
+6035 khtml (parser)
+6036 khtml (tokenizer)
+6040 khtml (render)
+6041 khtml (bidi)
+6045 khtml (rendering tree)
+6050 khtml (part)
+6060 khtml (cache)
+6061 khtml (cache-expiredates)
+6070 khtml (jscript)
+6080 khtml (css)
+6090 khtml (memory)
+6100 kjas
+6200 khtml (caret)
+6201 khtml (caret table)
+6210 khtml (editor)
+
+# libkio
+7000 kio
+7001 kio (KDirWatch)
+7002 kio (Slave)
+7003 kio (KDirLister)
+7004 kio (KDirListerCache)
+7005 kio (Filter)
+7006 kio (Scheduler)
+7007 kio (KIOJob)
+7009 kio (KMimeType)
+7010 kio (KRun)
+7011 kio (KSycoca)
+7012 kio (KService*)
+7013 kio (KPing)
+7014 kio (KTrader)
+7015 kio (KAutoMount)
+7016 kio (KLauncher)
+7017 kio (KIOConnection)
+7018 kio (KMimeMagic)
+7019 kio (kioslave)
+7020 kded
+7021 kbuildsycoca
+7022 kurifilter
+7023 kurifilter (plugins)
+7024 kio (UIServer)
+7025 kpac
+7026 kio (KShred)
+7027 kio (TCPSlaveBase)
+7028 kio (Observer)
+7029 kssl
+7030 kio (KEMailSettings)
+7031 KImageIO
+7032 kio (KURLCompletion)
+7033 KFileMetaInfo
+7034 KFileMetainfo (plugins)
+7040 KZip
+7041 KTar
+7042 KAr
+7043 kio (bookmarks)
+
+# 71xx are for kioslaves
+7101 kio_file
+7102 kio_ftp
+7103 kio_http
+7104 kcookiejar
+7105 kio_pop3
+7106 kio_smb
+7107 kio_man
+7108 kio_info
+7109 kio_tar
+7110 kio_gzip
+7111 kio_sql
+7112 kio_smtp
+7113 kio_http_debug
+7114 kio_nntp
+7115 kio_thumbnail
+7116 kio_imap
+7117 kio_audiocd
+7118 kio_bzip2
+7119 kio_help
+7120 kio_sftp
+7121 kio_nfs
+7122 kio_sieve
+7123 kio_kamera
+7124 kio_cgi
+7125 kio_ldap
+7126 kio_devices
+7127 kio_fish
+7128 kio_svn
+
+# kdesdk
+8100 kompare
+8101 kompare (libs)
+8102 kompare (shell)
+8103 kompare (part)
+8104 kompare (list view)
+8105 kompare (nav view)
+8106 kompare (connect widget)
+8107 kbabel
+8108 kbabel (search)
+8109 catalogmanager
+8050 cervisia
+8051 cervisia (cvsservice)
+
+# kdevelop
+9000 kdevelop (core)
+9001 kdevelop (grep view)
+9002 kdevelop (doc tree view)
+9003 kdevelop (class view)
+9004 kdevelop (output views)
+9005 kdevelop (class store)
+9006 kdevelop (cvs interface)
+9007 kdevelop (cpp support)
+9008 kdevelop (gcc options)
+9009 kdevelop (astyle)
+9010 kdevelop (appwizard)
+9011 kdevelop (python scripting)
+9012 kdevelop (debugger)
+9013 kdevelop (java support)
+9014 kdevelop (python support)
+9015 kdevelop (script project)
+9016 kdevelop (perl support)
+9017 kdevelop (file view)
+9018 kdevelop (php support)
+9019 kdevelop (fortran support)
+9020 kdevelop (auto project)
+9021 kdevelop (pgi options)
+9022 kdevelop (ctags)
+9023 kdevelop (regexptest)
+9024 kdevelop (trollproject)
+9025 kdevelop (customproject)
+9026 kdevelop (doxygen)
+9027 kdevelop (cvs)
+9028 kdevelop (abbrev)
+9029 kdevelop (filter)
+9030 kdevelop (texttools)
+9031 kdevelop (history)
+9032 qeditor
+9033 kdevelop (diff frontend)
+9034 kdevelop (filecreate part)
+9035 kdevelop (konsole part)
+9036 kdevelop (subversion part)
+
+# toys and games
+10000 amor
+10500 KBackgammon
+11000 libkdegames
+11001 libkdegames (KGame)
+11002 libkdegames (Highscores)
+11111 kpat
+12000 KPoker
+12001 KPoker (Server)
+12002 kvoctrain (application)
+12003 kvoctrain (core library)
+12004 kweather
+12005 kallers
+12006 kweatherservice
+12007 kolf
+12008 kbounce
+12009 kblackbox
+12010 kwin4
+12011 kenolaba
+12012 kasteroids
+
+
+# Kate/Kant/KWrite
+13000 Kate
+13001 Kate (App)
+13002 Kate (View Manager)
+13010 Kate (XML/Syntax)
+13020 Kate (Document)
+13025 Kate (Commands)
+13030 Kate (View)
+13033 Kate (Renderer)
+13035 Kate (Code Completion)
+13040 Kate (Plugins)
+13050 Kate (Scripting)
+13051 Kate (KJS Scripts)
+
+# Kopete
+14000 kopete
+14010 libkopete
+14100 kopete (gadu)
+14101 kopete (gadu - raw protocol)
+14110 kopete (icq)
+14111 kopete (icq - raw protocol)
+14120 kopete (irc)
+14121 kopete (irc - raw protocol)
+14130 kopete (jabber)
+14131 kopete (jabber - raw protocol)
+14140 kopete (msn)
+14141 kopete (msn - raw protocol)
+14150 kopete (oscar)
+14151 kopete (oscar - raw protocol)
+14152 kopete (oscar/aim)
+14153 kopete (oscar/icq)
+14160 kopete (sms)
+14161 kopete (sms - raw protocol)
+14170 kopete (winpopup)
+14171 kopete (winpopup - raw protocol)
+14180 kopete (yahoo)
+14181 kopete (yahoo - raw protocol)
+14190 kopete (groupwise)
+14191 kopete (libgroupwise)
+14192 kopete (libgroupwise - raw)
+14200 kopete (meanwhile)
+14300 kopete (autoaway)
+14301 kopete (connectionstatus)
+14302 kopete (contactnotes)
+14303 kopete (cryptography)
+14304 kopete (importer)
+14305 kopete (motionautoaway)
+14306 kopete (msginfo)
+14307 kopete (nowlistening)
+14308 kopete (translator)
+14309 kopete (webpresence)
+14310 kopete (history)
+14311 kopete (skype)
+14312 kopete (smpppdcs)
+
+# KDB
+20000 KDB (core)
+20001 KDB (ui)
+20010 KDB (DBEngine)
+20011 KDB (Connection)
+20012 KDB (plugin)
+
+#kfilereplace
+23000 KFileReplace (kfilereplacepart)
+
+#klinkstatus
+23100 KLinkStatus
+
+# Quanta
+24000 Quanta
+24001 Quanta (parser)
+24002 Quanta (debugger)
+
+# kafka
+25000 Kafka (kafkapp)
+25001 Kafka (kafkaeditpart)
+25002 Kafka (kafkapluginloader)
+25003 Kafka (kafkaplugins)
+25004 Kafka (kafkaobjectmgr)
+25005 Kafka (kafkadom)
+
+# KSVG
+26000 KSVG
+26001 KSVG - Parser
+26002 KSVG - Rendering
+26003 KSVG - KPart
+26004 KSVG - Ecma
+26005 KSVG - Canvas
+
+26500 KDOM XInclude
+26550 KDOM XPointer
+26560 KDOM XPath
+26600 KDOM Catalog
+26650 KDOM kxmllint
+
+# XSLT on top of KDOM
+27000 KXSLT
+
+# libkscan / kooka
+28000 Kooka
+29000 libkscan
+
+# 30001-40000 are for KOffice
+30001 koffice (lib koml)
+30002 koffice (lib store)
+30003 koffice (lib kofficecore)
+30004 koffice (lib kofficeui)
+30005 koffice (lib kopainter)
+30006 koffice (lib kospell)
+30007 koffice (lib koproperty)
+30500 koffice (filter manager)
+30501 csvfilter
+30502 asciifilter
+30503 htmlfilter
+30504 wmffilter
+30505 msodfilter
+30506 abiwordfilter
+30507 docbookfilter
+30508 export-filter-lib
+30509 mswritefilter
+30510 ole-lib
+30511 ole-excel
+30512 ole-powerpoint
+30513 winword-filter
+30514 svgfilter
+30515 rtffilter
+30516 pdffilter
+30517 applix-filter
+30518 openoffice-filter
+30519 import-export-openoffice-filter-lib
+30520 kword-1.3-filter
+30521 gnumeric-filter
+30522 latex-filter
+30523 quattro-pro-filter
+# 30524
+30525 palmdoc-filter
+31000 koffice
+32001 kword
+32002 kword (formatting)
+32003 kword (UI)
+32004 kword (tables)
+32500 kotext
+33001 kpresenter
+34000 kpresenter
+34001 klyx
+35000 klyx
+35001 kchart
+36000 kchart
+36001 kspread
+36002 kspread (cell)
+37000 kspread
+37001 graphite
+38000 karbon
+39001 kformula
+40000 kformula
+41000 krita (tiles)
+41001 krita (core)
+41002 krita (registry)
+41003 krita (tools)
+41004 krita (color management system)
+41005 krita (filters)
+41006 krita (plugins)
+41007 krita (user interface)
+41008 krita (file handling)
+41009 krita (math)
+41010 krita (render)
+41011 krita (scripting)
+42000 kplato
+43000 kivio
+44000 KexiDB
+44001 KexiDB (driver impl)
+44010 Kexi (general)
+44020 Kexi (core)
+44021 Kexi (plugins)
+
+# kdeextragear
+50001 kfortune
+
+# KIPI - KDE Imaging Plugin Interface
+51000 KIPI (general)
+51001 KIPI (loading)
+
+# kdemultimedia
+60001 kreatecd
+60002 kaudiocreator
+60005 krec
+60010 libkcddb
+65432 juk
+66666 noatun
+67000 kscd
+67100 kmix
+67200 kmid
+
+# kdebindings
+70001 dcoppython
+80001 kjsembed
+
+# kdeaddons
+90000 vimpart
+90010 noatun-plugins (dub)
+90020 noatun-plugins (lyrics)
+90100 konq-plugins (fsview)
+90110 konq-plugins (webarchiver)
+90120 konq-plugins (validators)
+90130 konq-plugins (uachanger)
+90140 konq-plugins (sidebar - newsticker)
+90150 konq-plugins (minitools)
+90160 konq-plugins (kuick)
+90170 konq-plugins (kimgalleryplugin)
+90180 konq-plugins (domtreeviewer)
+90190 konq-plugins (dirfilter)
+90200 kicker-applets (mediacontrol)
+90210 konq-plugins (rellinks)
+
+
+# kdenonbeta
+100000 reaktivate (KPart)
+100001 reaktivate (proxy)
+100100 geheimnis
+100101 geheimnis (backends)
+
+100200 kfs
+
+# rosegarden
+
+200000 rosegarden
+200001 rosegarden (notation)
+200002 rosegarden (matrix)
+200003 rosegarden (sequencer)
+200004 rosegarden (sequence manager)
+
+
diff --git a/kdecore/kdebug.cpp b/kdecore/kdebug.cpp
new file mode 100644
index 000000000..575f00e37
--- /dev/null
+++ b/kdecore/kdebug.cpp
@@ -0,0 +1,595 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ 2002 Holger Freyther (freyther@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kdebug.h"
+
+#ifdef NDEBUG
+#undef kdDebug
+#undef kdBacktrace
+#endif
+
+#include "kdebugdcopiface.h"
+
+#include "kapplication.h"
+#include "kglobal.h"
+#include "kinstance.h"
+#include "kstandarddirs.h"
+
+#include <qmessagebox.h>
+#include <klocale.h>
+#include <qfile.h>
+#include <qintdict.h>
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qpoint.h>
+#include <qrect.h>
+#include <qregion.h>
+#include <qstringlist.h>
+#include <qpen.h>
+#include <qbrush.h>
+#include <qsize.h>
+
+#include <kurl.h>
+
+#include <stdlib.h> // abort
+#include <unistd.h> // getpid
+#include <stdarg.h> // vararg stuff
+#include <ctype.h> // isprint
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <kconfig.h>
+#include "kstaticdeleter.h"
+#include <config.h>
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+class KDebugEntry;
+
+class KDebugEntry
+{
+public:
+ KDebugEntry (int n, const QCString& d) {number=n; descr=d;}
+ unsigned int number;
+ QCString descr;
+};
+
+static QIntDict<KDebugEntry> *KDebugCache;
+
+static KStaticDeleter< QIntDict<KDebugEntry> > kdd;
+
+static QCString getDescrFromNum(unsigned int _num)
+{
+ if (!KDebugCache) {
+ kdd.setObject(KDebugCache, new QIntDict<KDebugEntry>( 601 ));
+ // Do not call this deleter from ~KApplication
+ KGlobal::unregisterStaticDeleter(&kdd);
+ KDebugCache->setAutoDelete(true);
+ }
+
+ KDebugEntry *ent = KDebugCache->find( _num );
+ if ( ent )
+ return ent->descr;
+
+ if ( !KDebugCache->isEmpty() ) // areas already loaded
+ return QCString();
+
+ QString filename(locate("config","kdebug.areas"));
+ if (filename.isEmpty())
+ return QCString();
+
+ QFile file(filename);
+ if (!file.open(IO_ReadOnly)) {
+ qWarning("Couldn't open %s", filename.local8Bit().data());
+ file.close();
+ return QCString();
+ }
+
+ uint lineNumber=0;
+ QCString line(1024);
+ int len;
+
+ while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
+ int i=0;
+ ++lineNumber;
+
+ while (line[i] && line[i] <= ' ')
+ i++;
+
+ unsigned char ch=line[i];
+
+ if ( !ch || ch =='#' || ch =='\n')
+ continue; // We have an eof, a comment or an empty line
+
+ if (ch < '0' && ch > '9') {
+ qWarning("Syntax error: no number (line %u)",lineNumber);
+ continue;
+ }
+
+ const int numStart=i;
+ do {
+ ch=line[++i];
+ } while ( ch >= '0' && ch <= '9');
+
+ const Q_ULONG number =line.mid(numStart,i).toULong();
+
+ while (line[i] && line[i] <= ' ')
+ i++;
+
+ KDebugCache->insert(number, new KDebugEntry(number, line.mid(i, len-i-1)));
+ }
+ file.close();
+
+ ent = KDebugCache->find( _num );
+ if ( ent )
+ return ent->descr;
+
+ return QCString();
+}
+
+enum DebugLevels {
+ KDEBUG_INFO= 0,
+ KDEBUG_WARN= 1,
+ KDEBUG_ERROR= 2,
+ KDEBUG_FATAL= 3
+};
+
+
+struct kDebugPrivate {
+ kDebugPrivate() :
+ oldarea(0), config(0) { }
+
+ ~kDebugPrivate() { delete config; }
+
+ QCString aAreaName;
+ unsigned int oldarea;
+ KConfig *config;
+};
+
+static kDebugPrivate *kDebug_data = 0;
+static KStaticDeleter<kDebugPrivate> pcd;
+static KStaticDeleter<KDebugDCOPIface> dcopsd;
+static KDebugDCOPIface* kDebugDCOPIface = 0;
+
+static void kDebugBackend( unsigned short nLevel, unsigned int nArea, const char *data)
+{
+ if ( !kDebug_data )
+ {
+ pcd.setObject(kDebug_data, new kDebugPrivate());
+ // Do not call this deleter from ~KApplication
+ KGlobal::unregisterStaticDeleter(&pcd);
+
+ // create the dcop interface if it has not been created yet
+ if (!kDebugDCOPIface)
+ {
+ kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface, new KDebugDCOPIface);
+ }
+ }
+
+ if (!kDebug_data->config && KGlobal::_instance )
+ {
+ kDebug_data->config = new KConfig("kdebugrc", false, false);
+ kDebug_data->config->setGroup("0");
+
+ //AB: this is necessary here, otherwise all output with area 0 won't be
+ //prefixed with anything, unless something with area != 0 is called before
+ if ( KGlobal::_instance )
+ kDebug_data->aAreaName = KGlobal::instance()->instanceName();
+ }
+
+ if (kDebug_data->config && kDebug_data->oldarea != nArea) {
+ kDebug_data->config->setGroup( QString::number(static_cast<int>(nArea)) );
+ kDebug_data->oldarea = nArea;
+ if ( nArea > 0 && KGlobal::_instance )
+ kDebug_data->aAreaName = getDescrFromNum(nArea);
+ if ((nArea == 0) || kDebug_data->aAreaName.isEmpty())
+ if ( KGlobal::_instance )
+ kDebug_data->aAreaName = KGlobal::instance()->instanceName();
+ }
+
+ int nPriority = 0;
+ QString aCaption;
+
+ /* Determine output */
+
+ QString key;
+ switch( nLevel )
+ {
+ case KDEBUG_INFO:
+ key = "InfoOutput";
+ aCaption = "Info";
+ nPriority = LOG_INFO;
+ break;
+ case KDEBUG_WARN:
+ key = "WarnOutput";
+ aCaption = "Warning";
+ nPriority = LOG_WARNING;
+ break;
+ case KDEBUG_FATAL:
+ key = "FatalOutput";
+ aCaption = "Fatal Error";
+ nPriority = LOG_CRIT;
+ break;
+ case KDEBUG_ERROR:
+ default:
+ /* Programmer error, use "Error" as default */
+ key = "ErrorOutput";
+ aCaption = "Error";
+ nPriority = LOG_ERR;
+ break;
+ }
+
+ short nOutput = kDebug_data->config ? kDebug_data->config->readNumEntry(key, 2) : 2;
+
+ // If the application doesn't have a QApplication object it can't use
+ // a messagebox.
+ if (!kapp && (nOutput == 1))
+ nOutput = 2;
+ else if ( nOutput == 4 && nLevel != KDEBUG_FATAL )
+ return;
+
+ const int BUFSIZE = 4096;
+ char buf[BUFSIZE];
+ if ( !kDebug_data->aAreaName.isEmpty() ) {
+ strlcpy( buf, kDebug_data->aAreaName.data(), BUFSIZE );
+ strlcat( buf, ": ", BUFSIZE );
+ strlcat( buf, data, BUFSIZE );
+ }
+ else
+ strlcpy( buf, data, BUFSIZE );
+
+
+ // Output
+ switch( nOutput )
+ {
+ case 0: // File
+ {
+ const char* aKey;
+ switch( nLevel )
+ {
+ case KDEBUG_INFO:
+ aKey = "InfoFilename";
+ break;
+ case KDEBUG_WARN:
+ aKey = "WarnFilename";
+ break;
+ case KDEBUG_FATAL:
+ aKey = "FatalFilename";
+ break;
+ case KDEBUG_ERROR:
+ default:
+ aKey = "ErrorFilename";
+ break;
+ }
+ QFile aOutputFile( kDebug_data->config->readPathEntry(aKey, "kdebug.dbg") );
+ aOutputFile.open( IO_WriteOnly | IO_Append | IO_Raw );
+ aOutputFile.writeBlock( buf, strlen( buf ) );
+ aOutputFile.close();
+ break;
+ }
+ case 1: // Message Box
+ {
+ // Since we are in kdecore here, we cannot use KMsgBox and use
+ // QMessageBox instead
+ if ( !kDebug_data->aAreaName.isEmpty() )
+ aCaption += QString("(%1)").arg( kDebug_data->aAreaName );
+ QMessageBox::warning( 0L, aCaption, data, i18n("&OK") );
+ break;
+ }
+ case 2: // Shell
+ {
+ write( 2, buf, strlen( buf ) ); //fputs( buf, stderr );
+ break;
+ }
+ case 3: // syslog
+ {
+ syslog( nPriority, "%s", buf);
+ break;
+ }
+ }
+
+ // check if we should abort
+ if( ( nLevel == KDEBUG_FATAL )
+ && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) )
+ abort();
+}
+
+kdbgstream &perror( kdbgstream &s) { return s << QString::fromLocal8Bit(strerror(errno)); }
+kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); }
+kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); }
+
+kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); }
+kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); }
+kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); }
+kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); }
+kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); }
+kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); }
+
+kdbgstream::kdbgstream(kdbgstream &str)
+ : output(str.output), area(str.area), level(str.level), print(str.print)
+{
+ str.output.truncate(0);
+}
+
+void kdbgstream::flush() {
+ if (output.isEmpty() || !print)
+ return;
+ kDebugBackend( level, area, output.local8Bit().data() );
+ output = QString::null;
+}
+
+kdbgstream &kdbgstream::form(const char *format, ...)
+{
+ char buf[4096];
+ va_list arguments;
+ va_start( arguments, format );
+ vsnprintf( buf, sizeof(buf), format, arguments );
+ va_end(arguments);
+ *this << buf;
+ return *this;
+}
+
+kdbgstream::~kdbgstream() {
+ if (!output.isEmpty()) {
+ fprintf(stderr, "ASSERT: debug output not ended with \\n\n");
+ fprintf(stderr, "%s", kdBacktrace().latin1());
+ *this << "\n";
+ }
+}
+
+kdbgstream& kdbgstream::operator << (char ch)
+{
+ if (!print) return *this;
+ if (!isprint(ch))
+ output += "\\x" + QString::number( static_cast<uint>( ch ), 16 ).rightJustify(2, '0');
+ else {
+ output += ch;
+ if (ch == '\n') flush();
+ }
+ return *this;
+}
+
+kdbgstream& kdbgstream::operator << (QChar ch)
+{
+ if (!print) return *this;
+ if (!ch.isPrint())
+ output += "\\x" + QString::number( ch.unicode(), 16 ).rightJustify(2, '0');
+ else {
+ output += ch;
+ if (ch == '\n') flush();
+ }
+ return *this;
+}
+
+kdbgstream& kdbgstream::operator << (QWidget* widget)
+{
+ return *this << const_cast< const QWidget* >( widget );
+}
+
+kdbgstream& kdbgstream::operator << (const QWidget* widget)
+{
+ QString string, temp;
+ // -----
+ if(widget==0)
+ {
+ string=(QString)"[Null pointer]";
+ } else {
+ temp.setNum((ulong)widget, 16);
+ string=(QString)"["+widget->className()+" pointer "
+ + "(0x" + temp + ")";
+ if(widget->name(0)==0)
+ {
+ string += " to unnamed widget, ";
+ } else {
+ string += (QString)" to widget " + widget->name() + ", ";
+ }
+ string += "geometry="
+ + QString().setNum(widget->width())
+ + "x"+QString().setNum(widget->height())
+ + "+"+QString().setNum(widget->x())
+ + "+"+QString().setNum(widget->y())
+ + "]";
+ }
+ if (!print)
+ {
+ return *this;
+ }
+ output += string;
+ if (output.at(output.length() -1 ) == '\n')
+ {
+ flush();
+ }
+ return *this;
+}
+/*
+ * either use 'output' directly and do the flush if needed
+ * or use the QString operator which calls the char* operator
+ *
+ */
+kdbgstream& kdbgstream::operator<<( const QDateTime& time) {
+ *this << time.toString();
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QDate& date) {
+ *this << date.toString();
+
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QTime& time ) {
+ *this << time.toString();
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QPoint& p ) {
+ *this << "(" << p.x() << ", " << p.y() << ")";
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QSize& s ) {
+ *this << "[" << s.width() << "x" << s.height() << "]";
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QRect& r ) {
+ *this << "[" << r.x() << "," << r.y() << " - " << r.width() << "x" << r.height() << "]";
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QRegion& reg ) {
+ *this<< "[ ";
+
+ QMemArray<QRect>rs=reg.rects();
+ for (uint i=0;i<rs.size();++i)
+ *this << QString("[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() ) ;
+
+ *this <<"]";
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const KURL& u ) {
+ *this << u.prettyURL();
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QStringList& l ) {
+ *this << "(";
+ *this << l.join(",");
+ *this << ")";
+
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QColor& c ) {
+ if ( c.isValid() )
+ *this <<c.name();
+ else
+ *this << "(invalid/default)";
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QPen& p ) {
+ static const char* const s_penStyles[] = {
+ "NoPen", "SolidLine", "DashLine", "DotLine", "DashDotLine",
+ "DashDotDotLine" };
+ static const char* const s_capStyles[] = {
+ "FlatCap", "SquareCap", "RoundCap" };
+ *this << "[ style:";
+ *this << s_penStyles[ p.style() ];
+ *this << " width:";
+ *this << p.width();
+ *this << " color:";
+ if ( p.color().isValid() )
+ *this << p.color().name();
+ else
+ *this <<"(invalid/default)";
+ if ( p.width() > 0 ) // cap style doesn't matter, otherwise
+ {
+ *this << " capstyle:";
+ *this << s_capStyles[ p.capStyle() >> 4 ];
+ // join style omitted
+ }
+ *this <<" ]";
+ return *this;
+}
+kdbgstream& kdbgstream::operator<<( const QBrush& b) {
+ static const char* const s_brushStyles[] = {
+ "NoBrush", "SolidPattern", "Dense1Pattern", "Dense2Pattern", "Dense3Pattern",
+ "Dense4Pattern", "Dense5Pattern", "Dense6Pattern", "Dense7Pattern",
+ "HorPattern", "VerPattern", "CrossPattern", "BDiagPattern", "FDiagPattern",
+ "DiagCrossPattern" };
+
+ *this <<"[ style: ";
+ *this <<s_brushStyles[ b.style() ];
+ *this <<" color: ";
+ // can't use operator<<(str, b.color()) because that terminates a kdbgstream (flushes)
+ if ( b.color().isValid() )
+ *this <<b.color().name() ;
+ else
+ *this <<"(invalid/default)";
+ if ( b.pixmap() )
+ *this <<" has a pixmap";
+ *this <<" ]";
+ return *this;
+}
+
+kdbgstream& kdbgstream::operator<<( const QVariant& v) {
+ *this << "[variant: ";
+ *this << v.typeName();
+ // For now we just attempt a conversion to string.
+ // Feel free to switch(v.type()) and improve the output.
+ *this << " toString=";
+ *this << v.toString();
+ *this << "]";
+ return *this;
+}
+
+kdbgstream& kdbgstream::operator<<( const QByteArray& data) {
+ if (!print) return *this;
+ output += '[';
+ unsigned int i = 0;
+ unsigned int sz = QMIN( data.size(), 64 );
+ for ( ; i < sz ; ++i ) {
+ output += QString::number( (unsigned char) data[i], 16 ).rightJustify(2, '0');
+ if ( i < sz )
+ output += ' ';
+ }
+ if ( sz < data.size() )
+ output += "...";
+ output += ']';
+ return *this;
+}
+
+QString kdBacktrace(int levels)
+{
+ QString s;
+#ifdef HAVE_BACKTRACE
+ void* trace[256];
+ int n = backtrace(trace, 256);
+ if (!n)
+ return s;
+ char** strings = backtrace_symbols (trace, n);
+
+ if ( levels != -1 )
+ n = QMIN( n, levels );
+ s = "[\n";
+
+ for (int i = 0; i < n; ++i)
+ s += QString::number(i) +
+ QString::fromLatin1(": ") +
+ QString::fromLatin1(strings[i]) + QString::fromLatin1("\n");
+ s += "]\n";
+ if (strings)
+ free (strings);
+#endif
+ return s;
+}
+
+QString kdBacktrace()
+{
+ return kdBacktrace(-1 /*all*/);
+}
+
+void kdClearDebugConfig()
+{
+ if (kDebug_data) {
+ delete kDebug_data->config;
+ kDebug_data->config = 0;
+ }
+}
+
+
+// Needed for --enable-final
+#ifdef NDEBUG
+#define kdDebug kndDebug
+#endif
diff --git a/kdecore/kdebug.h b/kdecore/kdebug.h
new file mode 100644
index 000000000..cf954454d
--- /dev/null
+++ b/kdecore/kdebug.h
@@ -0,0 +1,665 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ 2000-2002 Stephan Kulow (coolo@kde.org)
+ 2002 Holger Freyther (freyther@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDEBUG_H_
+#define _KDEBUG_H_
+
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+class QWidget;
+class QDateTime;
+class QDate;
+class QTime;
+class QPoint;
+class QSize;
+class QRect;
+class QRegion;
+class KURL;
+class QStringList;
+class QColor;
+class QPen;
+class QBrush;
+class QVariant;
+template <class T>
+class QValueList;
+
+class kdbgstream;
+class kndbgstream;
+
+/**
+ * \addtogroup kdebug Debug message generators
+ * @{
+ * KDE debug message streams let you and the user control just how many debug
+ * messages you see.
+ */
+
+typedef kdbgstream & (*KDBGFUNC)(kdbgstream &); // manipulator function
+typedef kndbgstream & (*KNDBGFUNC)(kndbgstream &); // manipulator function
+
+#ifdef __GNUC__
+#define k_funcinfo "[" << __PRETTY_FUNCTION__ << "] "
+#else
+#define k_funcinfo "[" << __FILE__ << ":" << __LINE__ << "] "
+#endif
+
+#define k_lineinfo "[" << __FILE__ << ":" << __LINE__ << "] "
+
+class kdbgstreamprivate;
+/**
+ * kdbgstream is a text stream that allows you to print debug messages.
+ * Using the overloaded "<<" operator you can send messages. Usually
+ * you do not create the kdbgstream yourself, but use kdDebug()
+ * kdWarning(), kdError() or kdFatal to obtain one.
+ *
+ * Example:
+ * \code
+ * int i = 5;
+ * kdDebug() << "The value of i is " << i << endl;
+ * \endcode
+ * @see kndbgstream
+ */
+class KDECORE_EXPORT kdbgstream {
+ public:
+ /**
+ * @internal
+ */
+ kdbgstream(unsigned int _area, unsigned int _level, bool _print = true) :
+ area(_area), level(_level), print(_print) { }
+ kdbgstream(const char * initialString, unsigned int _area, unsigned int _level, bool _print = true) :
+ output(QString::fromLatin1(initialString)), area(_area), level(_level), print(_print) { }
+ /// Copy constructor
+ kdbgstream(kdbgstream &str);
+ kdbgstream(const kdbgstream &str) :
+ output(str.output), area(str.area), level(str.level), print(str.print) {}
+ ~kdbgstream();
+ /**
+ * Prints the given value.
+ * @param i the boolean to print (as "true" or "false")
+ * @return this stream
+ */
+ kdbgstream &operator<<(bool i) {
+ if (!print) return *this;
+ output += QString::fromLatin1(i ? "true" : "false");
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param i the short to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(short i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param i the unsigned short to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(unsigned short i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param ch the char to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(char ch);
+ /**
+ * Prints the given value.
+ * @param ch the unsigned char to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(unsigned char ch) {
+ return operator<<( static_cast<char>( ch ) );
+ }
+ /**
+ * Prints the given value.
+ * @param i the int to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(int i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param i the unsigned int to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(unsigned int i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param i the long to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(long i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param i the unsigned long to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(unsigned long i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param i the long long to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(Q_LLONG i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param i the unsigned long long to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(Q_ULLONG i) {
+ if (!print) return *this;
+ QString tmp; tmp.setNum(i); output += tmp;
+ return *this;
+ }
+
+ /**
+ * Flushes the output.
+ */
+ void flush(); //AB: maybe this should be virtual! would save some trouble for some 3rd party projects
+
+ /**
+ * Prints the given value.
+ * @param ch the char to print
+ * @return this stream
+ * @since 3.3
+ */
+ kdbgstream &operator<<(QChar ch);
+ /**
+ * Prints the given value.
+ * @param string the string to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(const QString& string) {
+ if (!print) return *this;
+ output += string;
+ if (output.at(output.length() -1 ) == '\n')
+ flush();
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param string the string to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(const char *string) {
+ if (!print) return *this;
+ output += QString::fromUtf8(string);
+ if (output.at(output.length() - 1) == '\n')
+ flush();
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param string the string to print
+ * @return this stream
+ */
+ kdbgstream &operator<<(const QCString& string) {
+ *this << string.data();
+ return *this;
+ }
+ /**
+ * Prints the given value.
+ * @param p a pointer to print (in number form)
+ * @return this stream
+ */
+ kdbgstream& operator<<(const void * p) {
+ form("%p", p);
+ return *this;
+ }
+ /**
+ * Invokes the given function.
+ * @param f the function to invoke
+ * @return the return value of @p f
+ */
+ kdbgstream& operator<<(KDBGFUNC f) {
+ if (!print) return *this;
+ return (*f)(*this);
+ }
+ /**
+ * Prints the given value.
+ * @param d the double to print
+ * @return this stream
+ */
+ kdbgstream& operator<<(double d) {
+ QString tmp; tmp.setNum(d); output += tmp;
+ return *this;
+ }
+ /**
+ * Prints the string @p format which can contain
+ * printf-style formatted values.
+ * @param format the printf-style format
+ * @return this stream
+ */
+ kdbgstream &form(const char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ( ( format ( printf, 2, 3 ) ) )
+#endif
+ ;
+
+ /** Operator to print out basic information about a QWidget.
+ * Output of class names only works if the class is moc'ified.
+ * @param widget the widget to print
+ * @return this stream
+ */
+ kdbgstream& operator << (const QWidget* widget);
+ kdbgstream& operator << (QWidget* widget); // KDE4 merge
+
+ /**
+ * Prints the given value.
+ * @param dateTime the datetime to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QDateTime& dateTime );
+
+ /**
+ * Prints the given value.
+ * @param date the date to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QDate& date );
+
+ /**
+ * Prints the given value.
+ * @param time the time to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QTime& time );
+
+ /**
+ * Prints the given value.
+ * @param point the point to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QPoint& point );
+
+ /**
+ * Prints the given value.
+ * @param size the QSize to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QSize& size );
+
+ /**
+ * Prints the given value.
+ * @param rect the QRect to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QRect& rect);
+
+ /**
+ * Prints the given value.
+ * @param region the QRegion to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QRegion& region);
+
+ /**
+ * Prints the given value.
+ * @param url the url to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const KURL& url );
+
+ /**
+ * Prints the given value.
+ * @param list the stringlist to print
+ * @return this stream
+ */
+ // ### KDE4: Remove in favor of template operator for QValueList<T> below
+ kdbgstream& operator << ( const QStringList& list);
+
+ /**
+ * Prints the given value.
+ * @param color the color to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QColor& color);
+
+ /**
+ * Prints the given value.
+ * @param pen the pen to print
+ * @return this stream
+ * @since 3.2
+ */
+ kdbgstream& operator << ( const QPen& pen );
+
+ /**
+ * Prints the given value.
+ * @param brush the brush to print
+ * @return this stream
+ */
+ kdbgstream& operator << ( const QBrush& brush );
+
+ /**
+ * Prints the given value.
+ * @param variant the variant to print
+ * @return this stream
+ * @since 3.3
+ */
+ kdbgstream& operator << ( const QVariant& variant );
+
+ /**
+ * Prints the given value.
+ * @param data the byte array to print
+ * @return this stream
+ * @since 3.3
+ */
+ kdbgstream& operator << ( const QByteArray& data );
+
+ /**
+ * Prints the given value
+ * @param list the list to print
+ * @return this stream
+ * @since 3.3
+ */
+ template <class T>
+ kdbgstream& operator << ( const QValueList<T> &list );
+
+ private:
+ QString output;
+ unsigned int area, level;
+ bool print;
+ kdbgstreamprivate* d;
+};
+
+template <class T>
+kdbgstream &kdbgstream::operator<<( const QValueList<T> &list )
+{
+ *this << "(";
+ typename QValueList<T>::ConstIterator it = list.begin();
+ if ( !list.isEmpty() ) {
+ *this << *it++;
+ }
+ for ( ; it != list.end(); ++it ) {
+ *this << "," << *it;
+ }
+ *this << ")";
+ return *this;
+}
+
+/**
+ * \relates KGlobal
+ * Prints an "\n".
+ * @param s the debug stream to write to
+ * @return the debug stream (@p s)
+ */
+inline kdbgstream &endl( kdbgstream &s) { s << "\n"; return s; }
+
+/**
+ * \relates KGlobal
+ * Flushes the stream.
+ * @param s the debug stream to write to
+ * @return the debug stream (@p s)
+ */
+inline kdbgstream &flush( kdbgstream &s) { s.flush(); return s; }
+
+KDECORE_EXPORT kdbgstream &perror( kdbgstream &s);
+
+/**
+ * \relates KGlobal
+ * kndbgstream is a dummy variant of kdbgstream. All functions do
+ * nothing.
+ * @see kndDebug()
+ */
+class KDECORE_EXPORT kndbgstream {
+ public:
+ /// Default constructor.
+ kndbgstream() {}
+ ~kndbgstream() {}
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(short int ) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(unsigned short int ) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(char ) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(unsigned char ) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(int ) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(unsigned int ) { return *this; }
+ /**
+ * Does nothing.
+ */
+ void flush() {}
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(QChar) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(const QString& ) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(const QCString& ) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &operator<<(const char *) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(const void *) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(void *) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(double) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(long) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(unsigned long) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(Q_LLONG) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(Q_ULLONG) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator<<(KNDBGFUNC) { return *this; }
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream& operator << (const QWidget*) { return *this; }
+ kndbgstream& operator << (QWidget*) { return *this; } // KDE4 merge
+ /**
+ * Does nothing.
+ * @return this stream
+ */
+ kndbgstream &form(const char *, ...) { return *this; }
+
+ kndbgstream& operator<<( const QDateTime& ) { return *this; }
+ kndbgstream& operator<<( const QDate& ) { return *this; }
+ kndbgstream& operator<<( const QTime& ) { return *this; }
+ kndbgstream& operator<<( const QPoint & ) { return *this; }
+ kndbgstream& operator<<( const QSize & ) { return *this; }
+ kndbgstream& operator<<( const QRect & ) { return *this; }
+ kndbgstream& operator<<( const QRegion & ) { return *this; }
+ kndbgstream& operator<<( const KURL & ) { return *this; }
+ kndbgstream& operator<<( const QStringList & ) { return *this; }
+ kndbgstream& operator<<( const QColor & ) { return *this; }
+ kndbgstream& operator<<( const QPen & ) { return *this; }
+ kndbgstream& operator<<( const QBrush & ) { return *this; }
+ kndbgstream& operator<<( const QVariant & ) { return *this; }
+ kndbgstream& operator<<( const QByteArray & ) { return *this; }
+
+ template <class T>
+ kndbgstream& operator<<( const QValueList<T> & ) { return *this; }
+};
+
+/**
+ * Does nothing.
+ * @param s a stream
+ * @return the given @p s
+ */
+inline kndbgstream &endl( kndbgstream & s) { return s; }
+/**
+ * Does nothing.
+ * @param s a stream
+ * @return the given @p s
+ */
+inline kndbgstream &flush( kndbgstream & s) { return s; }
+inline kndbgstream &perror( kndbgstream & s) { return s; }
+
+/**
+ * \relates KGlobal
+ * Returns a debug stream. You can use it to print debug
+ * information.
+ * @param area an id to identify the output, 0 for default
+ * @see kndDebug()
+ */
+KDECORE_EXPORT kdbgstream kdDebug(int area = 0);
+KDECORE_EXPORT kdbgstream kdDebug(bool cond, int area = 0);
+/**
+ * \relates KGlobal
+ * Returns a backtrace.
+ * @return a backtrace
+ */
+KDECORE_EXPORT QString kdBacktrace();
+/**
+ * \relates KGlobal
+ * Returns a backtrace.
+ * @param levels the number of levels of the backtrace
+ * @return a backtrace
+ * @since 3.1
+ */
+KDECORE_EXPORT QString kdBacktrace(int levels);
+/**
+ * Returns a dummy debug stream. The stream does not print anything.
+ * @param area an id to identify the output, 0 for default
+ * @see kdDebug()
+ */
+inline kndbgstream kndDebug(int area = 0) { Q_UNUSED(area); return kndbgstream(); }
+inline kndbgstream kndDebug(bool , int = 0) { return kndbgstream(); }
+inline QString kndBacktrace() { return QString::null; }
+inline QString kndBacktrace(int) { return QString::null; }
+
+/**
+ * \relates KGlobal
+ * Returns a warning stream. You can use it to print warning
+ * information.
+ * @param area an id to identify the output, 0 for default
+ */
+KDECORE_EXPORT kdbgstream kdWarning(int area = 0);
+KDECORE_EXPORT kdbgstream kdWarning(bool cond, int area = 0);
+/**
+ * \relates KGlobal
+ * Returns an error stream. You can use it to print error
+ * information.
+ * @param area an id to identify the output, 0 for default
+ */
+KDECORE_EXPORT kdbgstream kdError(int area = 0);
+KDECORE_EXPORT kdbgstream kdError(bool cond, int area = 0);
+/**
+ * \relates KGlobal
+ * Returns a fatal error stream. You can use it to print fatal error
+ * information.
+ * @param area an id to identify the output, 0 for default
+ */
+KDECORE_EXPORT kdbgstream kdFatal(int area = 0);
+KDECORE_EXPORT kdbgstream kdFatal(bool cond, int area = 0);
+
+/**
+ * \relates KGlobal
+ * Deletes the kdebugrc cache and therefore forces KDebug to reread the
+ * config file
+ */
+KDECORE_EXPORT void kdClearDebugConfig();
+
+/** @} */
+
+#ifdef NDEBUG
+#define kdDebug kndDebug
+#define kdBacktrace kndBacktrace
+#endif
+
+#endif
+
diff --git a/kdecore/kdebugclasses.h b/kdecore/kdebugclasses.h
new file mode 100644
index 000000000..00c0b07ce
--- /dev/null
+++ b/kdecore/kdebugclasses.h
@@ -0,0 +1,33 @@
+
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ 2000-2002 Stephan Kulow (coolo@kde.org)
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDEBUG_CLASSES_H_
+#define _KDEBUG_CLASSES_H_
+
+#if defined(__GNUC__)
+#warning include kdebug.h instead, except if KDE 3.1 compatibility is needed
+#endif
+
+#include <kdebug.h>
+
+#endif
+
diff --git a/kdecore/kdebugdcopiface.cpp b/kdecore/kdebugdcopiface.cpp
new file mode 100644
index 000000000..427384479
--- /dev/null
+++ b/kdecore/kdebugdcopiface.cpp
@@ -0,0 +1,40 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Andreas Beckermann (b_mann@gmx.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kdebugdcopiface.h"
+#include "kdebug.h"
+
+KDebugDCOPIface::KDebugDCOPIface() : DCOPObject("KDebug")
+{
+}
+
+KDebugDCOPIface::~KDebugDCOPIface()
+{
+}
+
+void KDebugDCOPIface::notifyKDebugConfigChanged()
+{
+ kdClearDebugConfig();
+}
+
+void KDebugDCOPIface::printBacktrace()
+{
+ kdDebug() << kdBacktrace() << endl;
+}
+
diff --git a/kdecore/kdebugdcopiface.h b/kdecore/kdebugdcopiface.h
new file mode 100644
index 000000000..44e4bcf71
--- /dev/null
+++ b/kdecore/kdebugdcopiface.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Andreas Beckermann (b_mann@gmx.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDEBUGDCOPIFACE_H_
+#define _KDEBUGDCOPIFACE_H_
+
+#include <dcopobject.h>
+#include <dcopref.h>
+#include "kdelibs_export.h"
+
+/**
+ * @short DCOP interface to KDebug.
+ **/
+class KDECORE_EXPORT KDebugDCOPIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+ KDebugDCOPIface();
+ ~KDebugDCOPIface();
+
+k_dcop:
+ /**
+ * The kdebugrc has been changed and should be reparsed now.
+ * This will simply call kdClearDebugConfig
+ **/
+ void notifyKDebugConfigChanged();
+
+ /**
+ * Print out a kdBacktrace. Useful when trying to understand why
+ * a dialog is popping up, without having to launch gdb
+ */
+ void printBacktrace();
+};
+
+#endif
+
diff --git a/kdecore/kdebugrc b/kdecore/kdebugrc
new file mode 100644
index 000000000..dc8deb29d
--- /dev/null
+++ b/kdecore/kdebugrc
@@ -0,0 +1,142 @@
+# This files includes the default behavior for some specific debug areas
+# This allows to leave the kdDebug* calls in the code, but still have them
+# disabled for most users.
+#
+# This file will be installed as $KDEDIR/share/config/kdebugrc
+#
+# There are four levels of output: Info, Warn, Error and Fatal
+# corresponding to kdDebug(), kdWarn(), kdError(), kdFatal()
+#
+# For every of them you can define a target by *Output=n
+# using the following numbers:
+#
+# 0 = file
+# 1 = message box
+# 2 = shell (stderr)
+# 3 = syslog
+# 4 = off
+#
+# For file output you can give a filename by *Filename=<file>
+# otherwise kdebug.dbg in the current directory is used.
+#
+# ekzample:
+#
+# For the debug area 100 you want output of debug messages
+# to a file /var/log/dbg.log and error messages as message boxes.
+# Additionally the program should abort on fatal errors.
+#
+# [100]
+# InfoOutput=0
+# InfoFilename=/var/log/dbg.log
+# ErrorOutput=1
+# AbortFatal=1
+#
+
+# KAccel debug info off
+[125]
+InfoOutput=4
+
+# KCheckAccel debug info off
+[131]
+InfoOutput=4
+
+# KAction debug info off
+[129]
+InfoOutput=4
+
+# KStartupInfo debug info off
+[172]
+InfoOutput=4
+
+# KLocale debug info off
+[173]
+InfoOutput=4
+
+# KMainWindow debug info off
+[200]
+InfoOutput=4
+
+# KFile debug info off
+[250]
+InfoOutput=4
+
+# KIconloader debug info off
+[264]
+InfoOutput=4
+
+# KSpell debug info off
+[750]
+InfoOutput=4
+
+# KPart's mainwindow info off
+[1001]
+InfoOutput=4
+
+# KPart's factory info off
+[1002]
+InfoOutput=4
+
+# KDesktop icons
+[1214]
+InfoOutput=4
+
+# KHotKeys
+[1217]
+InfoOutput=4
+
+# KMail
+[5006]
+InfoOutput=2
+
+# KitchenSync (Syncing Algorithm)
+[5250]
+InfoOutput=4
+
+# calendarsystem debug info off
+[5400]
+InfoOutput=4
+
+# kabc/vcard
+[5710]
+InfoOutput=4
+
+# korganizer (verbose)
+[5855]
+InfoOutput=4
+
+# korgac (check)
+[5891]
+InfoOutput=4
+
+# kalarmd check
+[5901]
+InfoOutput=4
+
+# kio_http_debug debug info off
+[7113]
+InfoOutput=4
+
+# kbzip2filter's debug info off
+[7118]
+InfoOutput=4
+
+# kio_nntp debug info off
+[7114]
+InfoOutput=4
+
+# KRun debug info off
+[7010]
+InfoOutput=4
+
+# KMimeMagic debug info off
+[7018]
+InfoOutput=4
+
+# KGame debug info off
+[11001]
+InfoOutput=4
+
+# KOStore debug info off
+[30002]
+InfoOutput=4
+
diff --git a/kdecore/kdelibs_export.h b/kdecore/kdelibs_export.h
new file mode 100644
index 000000000..8f9afad71
--- /dev/null
+++ b/kdecore/kdelibs_export.h
@@ -0,0 +1,85 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDELIBS_EXPORT_H
+#define _KDELIBS_EXPORT_H
+
+/* needed for KDE_EXPORT macros */
+#include <kdemacros.h>
+
+/* needed, because e.g. Q_OS_UNIX is so frequently used */
+#include <qglobal.h>
+
+#ifdef Q_WS_WIN
+#include <kdelibs_export_win.h>
+
+#else /* Q_OS_UNIX */
+
+/* export statements for unix */
+#define KDECORE_EXPORT KDE_EXPORT
+#define KDEUI_EXPORT KDE_EXPORT
+#define KDEFX_EXPORT KDE_EXPORT
+#define KDEPRINT_EXPORT KDE_EXPORT
+#define KDNSSD_EXPORT KDE_EXPORT
+#define KIO_EXPORT KDE_EXPORT
+#define DCOP_EXPORT KDE_EXPORT
+#define KPARTS_EXPORT KDE_EXPORT
+#define KTEXTEDITOR_EXPORT KDE_EXPORT
+#define KABC_EXPORT KDE_EXPORT
+#define KDESU_EXPORT KDE_EXPORT
+#define KVCARD_EXPORT KDE_EXPORT
+#define KRESOURCES_EXPORT KDE_EXPORT
+#define KSTYLE_EXPORT KDE_EXPORT
+#define KHTML_EXPORT KDE_EXPORT
+#define KMDI_EXPORT KDE_EXPORT
+#define KUTILS_EXPORT KDE_EXPORT
+#define KATEPARTINTERFACES_EXPORT KDE_EXPORT
+#define KATEPART_EXPORT KDE_EXPORT
+#define KMID_EXPORT KDE_EXPORT
+#define KIMPROXY_EXPORT KDE_EXPORT
+#define KDE_ARTS_EXPORT KDE_EXPORT
+#define KUNITTEST_EXPORT KDE_EXPORT
+
+#define KPATH_SEPARATOR ':'
+
+#ifndef O_BINARY
+#define O_BINARY 0 /* for open() */
+#endif
+
+#endif
+
+#endif /*_KDELIBS_EXPORT_H*/
+
+/* workaround for kdecore: stupid moc's grammar doesn't accept two macros
+ between 'class' keyword and <classname>: */
+#ifdef KDE_DEPRECATED
+# ifndef KDECORE_EXPORT_DEPRECATED
+# define KDECORE_EXPORT_DEPRECATED KDE_DEPRECATED KDECORE_EXPORT
+# endif
+# ifndef KIO_EXPORT_DEPRECATED
+# define KIO_EXPORT_DEPRECATED KDE_DEPRECATED KIO_EXPORT
+# endif
+# ifndef KDEUI_EXPORT_DEPRECATED
+# define KDEUI_EXPORT_DEPRECATED KDE_DEPRECATED KDEUI_EXPORT
+# endif
+# ifndef KABC_EXPORT_DEPRECATED
+# define KABC_EXPORT_DEPRECATED KDE_DEPRECATED KABC_EXPORT
+# endif
+#endif
+/* (let's add KDE****_EXPORT_DEPRECATED for other libraries if it's needed) */
diff --git a/kdecore/kdemacros.h.in b/kdecore/kdemacros.h.in
new file mode 100644
index 000000000..00f49bbd7
--- /dev/null
+++ b/kdecore/kdemacros.h.in
@@ -0,0 +1,220 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2002-2003 KDE Team
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDE_MACROS_H_
+#define _KDE_MACROS_H_
+
+/* Set by configure */
+#undef __KDE_HAVE_GCC_VISIBILITY
+
+/**
+ * The KDE_NO_EXPORT macro marks the symbol of the given variable
+ * to be hidden. A hidden symbol is stripped during the linking step,
+ * so it can't be used from outside the resulting library, which is similar
+ * to static. However, static limits the visibility to the current
+ * compilation unit. hidden symbols can still be used in multiple compilation
+ * units.
+ *
+ * \code
+ * int KDE_NO_EXPORT foo;
+ * int KDE_EXPORT bar;
+ * \end
+ */
+
+#ifdef __KDE_HAVE_GCC_VISIBILITY
+#define KDE_NO_EXPORT __attribute__ ((visibility("hidden")))
+#define KDE_EXPORT __attribute__ ((visibility("default")))
+#elif defined(Q_WS_WIN)
+#define KDE_NO_EXPORT
+#define KDE_EXPORT __declspec(dllexport)
+#else
+#define KDE_NO_EXPORT
+#define KDE_EXPORT
+#endif
+
+/**
+ * KDE_Q_EXPORT_PLUGIN is a workaround for Qt not being able to
+ * cope with symbol visibility.
+ */
+#define KDE_Q_EXPORT_PLUGIN(PLUGIN) \
+ Q_EXTERN_C KDE_EXPORT const char* qt_ucm_query_verification_data(); \
+ Q_EXTERN_C KDE_EXPORT QUnknownInterface* ucm_instantiate(); \
+ Q_EXPORT_PLUGIN(PLUGIN)
+
+/**
+ * The KDE_PACKED can be used to hint the compiler that a particular
+ * structure or class should not contain unnecessary paddings.
+ */
+
+#ifdef __GNUC__
+#define KDE_PACKED __attribute__((__packed__))
+#else
+#define KDE_PACKED
+#endif
+
+/**
+ * The KDE_DEPRECATED macro can be used to trigger compile-time warnings
+ * with newer compilers when deprecated functions are used.
+ *
+ * For non-inline functions, the macro gets inserted at the very end of the
+ * function declaration, right before the semicolon:
+ *
+ * \code
+ * DeprecatedConstructor() KDE_DEPRECATED;
+ * void deprecatedFunctionA() KDE_DEPRECATED;
+ * int deprecatedFunctionB() const KDE_DEPRECATED;
+ * \endcode
+ *
+ * Functions which are implemented inline are handled differently: for them,
+ * the KDE_DEPRECATED macro is inserted at the front, right before the return
+ * type, but after "static" or "virtual":
+ *
+ * \code
+ * KDE_DEPRECATED void deprecatedInlineFunctionA() { .. }
+ * virtual KDE_DEPRECATED int deprecatedInlineFunctionB() { .. }
+ * static KDE_DEPRECATED bool deprecatedInlineFunctionC() { .. }
+ * \end
+ *
+ * You can also mark whole structs or classes as deprecated, by inserting the
+ * KDE_DEPRECATED macro after the struct/class keyword, but before the
+ * name of the struct/class:
+ *
+ * \code
+ * class KDE_DEPRECATED DeprecatedClass { };
+ * struct KDE_DEPRECATED DeprecatedStruct { };
+ * \endcode
+ *
+ * \note
+ * It does not make much sense to use the KDE_DEPRECATED keyword for a Qt signal;
+ * this is because usually get called by the class which they belong to,
+ * and one'd assume that a class author doesn't use deprecated methods of his
+ * own class. The only exception to this are signals which are connected to
+ * other signals; they get invoked from moc-generated code. In any case,
+ * printing a warning message in either case is not useful.
+ * For slots, it can make sense (since slots can be invoked directly) but be
+ * aware that if the slots get triggered by a signal, the will get called from
+ * moc code as well and thus the warnings are useless.
+ *
+ * \par
+ * Also note that it is not possible to use KDE_DEPRECATED for classes which
+ * use the k_dcop keyword (to indicate a DCOP interface declaration); this is
+ * because the dcopidl program would choke on the unexpected declaration
+ * syntax.
+ */
+
+#ifndef KDE_DEPRECATED
+#if __GNUC__ - 0 > 3 || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 >= 2)
+ /* gcc >= 3.2 */
+# define KDE_DEPRECATED __attribute__ ((deprecated))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+ /* msvc >= 7 */
+# define KDE_DEPRECATED __declspec(deprecated)
+#else
+# define KDE_DEPRECATED
+#endif
+#endif
+
+/**
+ * The KDE_ISLIKELY macro tags a boolean expression as likely to evaluate to
+ * 'true'. When used in an if ( ) statement, it gives a hint to the compiler
+ * that the following codeblock is likely to get executed. Providing this
+ * information helps the compiler to optimize the code for better performance.
+ * Using the macro has an insignificant code size or runtime memory footprint impact.
+ * The code semantics is not affected.
+ *
+ * \note
+ * Providing wrong information ( like marking a condition that almost never
+ * passes as 'likely' ) will cause a significant runtime slowdown. Therefore only
+ * use it for cases where you can be sure about the odds of the expression to pass
+ * in all cases ( independent from e.g. user configuration ).
+ *
+ * \par
+ * The KDE_ISUNLIKELY macro tags an expression as unlikely evaluating to 'true'.
+ *
+ * \note
+ * Do NOT use ( !KDE_ISLIKELY(foo) ) as an replacement for KDE_ISUNLIKELY !
+ *
+ * \code
+ * if ( KDE_ISUNLIKELY( testsomething() ) )
+ * abort(); // assume its unlikely that the application aborts
+ * \endcode
+ */
+#if __GNUC__ - 0 >= 3
+# define KDE_ISLIKELY( x ) __builtin_expect(!!(x),1)
+# define KDE_ISUNLIKELY( x ) __builtin_expect(!!(x),0)
+#else
+# define KDE_ISLIKELY( x ) ( x )
+# define KDE_ISUNLIKELY( x ) ( x )
+#endif
+
+/**
+ * This macro, and it's friends going up to 10 reserve a fixed number of virtual
+ * functions in a class. Because adding virtual functions to a class changes the
+ * size of the vtable, adding virtual functions to a class breaks binary
+ * compatibility. However, by using this macro, and decrementing it as new
+ * virtual methods are added, binary compatibility can still be preserved.
+ *
+ * \note The added functions must be added to the header at the same location
+ * as the macro; changing the order of virtual functions in a header is also
+ * binary incompatible as it breaks the layout of the vtable.
+ */
+
+#define RESERVE_VIRTUAL_1 \
+ virtual void reservedVirtual1() {}
+#define RESERVE_VIRTUAL_2 \
+ virtual void reservedVirtual2() {} \
+ RESERVE_VIRTUAL_1
+#define RESERVE_VIRTUAL_3 \
+ virtual void reservedVirtual3() {} \
+ RESERVE_VIRTUAL_2
+#define RESERVE_VIRTUAL_4 \
+ virtual void reservedVirtual4() {} \
+ RESERVE_VIRTUAL_3
+#define RESERVE_VIRTUAL_5 \
+ virtual void reservedVirtual5() {} \
+ RESERVE_VIRTUAL_4
+#define RESERVE_VIRTUAL_6 \
+ virtual void reservedVirtual6() {} \
+ RESERVE_VIRTUAL_5
+#define RESERVE_VIRTUAL_7 \
+ virtual void reservedVirtual7() {} \
+ RESERVE_VIRTUAL_6
+#define RESERVE_VIRTUAL_8 \
+ virtual void reservedVirtual8() {} \
+ RESERVE_VIRTUAL_7
+#define RESERVE_VIRTUAL_9 \
+ virtual void reservedVirtual9() {} \
+ RESERVE_VIRTUAL_8
+#define RESERVE_VIRTUAL_10 \
+ virtual void reservedVirtual10() {} \
+ RESERVE_VIRTUAL_9
+
+/**
+ * The KDE_WEAK_SYMBOL macro can be used to tell the compiler that
+ * a particular function should be a weak symbol (that e.g. may be overriden
+ * in another library, -Bdirect will not bind this symbol directly)
+ */
+
+#ifdef __GNUC__
+#define KDE_WEAK_SYMBOL __attribute__((__weak__))
+#else
+#define KDE_WEAK_SYMBOL
+#endif
+
+#endif /* _KDE_MACROS_H_ */
diff --git a/kdecore/kdesktopfile.cpp b/kdecore/kdesktopfile.cpp
new file mode 100644
index 000000000..0168803ea
--- /dev/null
+++ b/kdecore/kdesktopfile.cpp
@@ -0,0 +1,346 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Pietro Iglio <iglio@kde.org>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include "kurl.h"
+#include "kconfigbackend.h"
+#include "kapplication.h"
+#include "kstandarddirs.h"
+#include "kmountpoint.h"
+
+#include "kdesktopfile.h"
+#include "kdesktopfile.moc"
+
+KDesktopFile::KDesktopFile(const QString &fileName, bool bReadOnly,
+ const char * resType)
+ : KConfig(QString::fromLatin1(""), bReadOnly, false)
+{
+ // KConfigBackEnd will try to locate the filename that is provided
+ // based on the resource type specified, _only_ if the filename
+ // is not an absolute path.
+ backEnd->changeFileName(fileName, resType, false);
+ setReadOnly(bReadOnly);
+ reparseConfiguration();
+ setDesktopGroup();
+}
+
+KDesktopFile::~KDesktopFile()
+{
+ // no need to do anything
+}
+
+QString KDesktopFile::locateLocal(const QString &path)
+{
+ QString local;
+ if (path.endsWith(".directory"))
+ {
+ local = path;
+ if (!QDir::isRelativePath(local))
+ {
+ // Relative wrt apps?
+ local = KGlobal::dirs()->relativeLocation("apps", path);
+ }
+
+ if (QDir::isRelativePath(local))
+ {
+ local = ::locateLocal("apps", local); // Relative to apps
+ }
+ else
+ {
+ // XDG Desktop menu items come with absolute paths, we need to
+ // extract their relative path and then build a local path.
+ local = KGlobal::dirs()->relativeLocation("xdgdata-dirs", local);
+ if (!QDir::isRelativePath(local))
+ {
+ // Hm, that didn't work...
+ // What now? Use filename only and hope for the best.
+ local = path.mid(path.findRev('/')+1);
+ }
+ local = ::locateLocal("xdgdata-dirs", local);
+ }
+ }
+ else
+ {
+ if (QDir::isRelativePath(path))
+ {
+ local = ::locateLocal("apps", path); // Relative to apps
+ }
+ else
+ {
+ // XDG Desktop menu items come with absolute paths, we need to
+ // extract their relative path and then build a local path.
+ local = KGlobal::dirs()->relativeLocation("xdgdata-apps", path);
+ if (!QDir::isRelativePath(local))
+ {
+ // What now? Use filename only and hope for the best.
+ local = path.mid(path.findRev('/')+1);
+ }
+ local = ::locateLocal("xdgdata-apps", local);
+ }
+ }
+ return local;
+}
+
+bool KDesktopFile::isDesktopFile(const QString& path)
+{
+ int len = path.length();
+
+ if(len > 8 && path.right(8) == QString::fromLatin1(".desktop"))
+ return true;
+ else if(len > 7 && path.right(7) == QString::fromLatin1(".kdelnk"))
+ return true;
+ else
+ return false;
+}
+
+bool KDesktopFile::isAuthorizedDesktopFile(const QString& path)
+{
+ if (!kapp || kapp->authorize("run_desktop_files"))
+ return true;
+
+ if (path.isEmpty())
+ return false; // Empty paths are not ok.
+
+ if (QDir::isRelativePath(path))
+ return true; // Relative paths are ok.
+
+ KStandardDirs *dirs = KGlobal::dirs();
+ if (QDir::isRelativePath( dirs->relativeLocation("apps", path) ))
+ return true;
+ if (QDir::isRelativePath( dirs->relativeLocation("xdgdata-apps", path) ))
+ return true;
+ if (QDir::isRelativePath( dirs->relativeLocation("services", path) ))
+ return true;
+ if (dirs->relativeLocation("data", path).startsWith("kdesktop/Desktop"))
+ return true;
+
+ kdWarning() << "Access to '" << path << "' denied because of 'run_desktop_files' restriction." << endl;
+ return false;
+}
+
+QString KDesktopFile::readType() const
+{
+ return readEntry("Type");
+}
+
+QString KDesktopFile::readIcon() const
+{
+ return readEntry("Icon");
+}
+
+QString KDesktopFile::readName() const
+{
+ return readEntry("Name");
+}
+
+QString KDesktopFile::readComment() const
+{
+ return readEntry("Comment");
+}
+
+QString KDesktopFile::readGenericName() const
+{
+ return readEntry("GenericName");
+}
+
+QString KDesktopFile::readPath() const
+{
+ return readPathEntry("Path");
+}
+
+QString KDesktopFile::readDevice() const
+{
+ return readEntry("Dev");
+}
+
+QString KDesktopFile::readURL() const
+{
+ if (hasDeviceType()) {
+ QString device = readDevice();
+ KMountPoint::List mountPoints = KMountPoint::possibleMountPoints();
+
+ for(KMountPoint::List::ConstIterator it = mountPoints.begin();
+ it != mountPoints.end(); ++it)
+ {
+ KMountPoint *mp = *it;
+ if (mp->mountedFrom() == device)
+ {
+ KURL u;
+ u.setPath( mp->mountPoint() );
+ return u.url();
+ }
+ }
+ return QString::null;
+ } else {
+ QString url = readPathEntry("URL");
+ if ( !url.isEmpty() && !QDir::isRelativePath(url) )
+ {
+ // Handle absolute paths as such (i.e. we need to escape them)
+ KURL u;
+ u.setPath( url );
+ return u.url();
+ }
+ return url;
+ }
+}
+
+QStringList KDesktopFile::readActions() const
+{
+ return readListEntry("Actions", ';');
+}
+
+void KDesktopFile::setActionGroup(const QString &group)
+{
+ setGroup(QString::fromLatin1("Desktop Action ") + group);
+}
+
+bool KDesktopFile::hasActionGroup(const QString &group) const
+{
+ return hasGroup(QString::fromLatin1("Desktop Action ") + group);
+}
+
+bool KDesktopFile::hasLinkType() const
+{
+ return readEntry("Type") == QString::fromLatin1("Link");
+}
+
+bool KDesktopFile::hasApplicationType() const
+{
+ return readEntry("Type") == QString::fromLatin1("Application");
+}
+
+bool KDesktopFile::hasMimeTypeType() const
+{
+ return readEntry("Type") == QString::fromLatin1("MimeType");
+}
+
+bool KDesktopFile::hasDeviceType() const
+{
+ return readEntry("Type") == QString::fromLatin1("FSDev") ||
+ readEntry("Type") == QString::fromLatin1("FSDevice");
+}
+
+bool KDesktopFile::tryExec() const
+{
+ // Test for TryExec and "X-KDE-AuthorizeAction"
+ QString te = readPathEntry("TryExec");
+
+ if (!te.isEmpty()) {
+ if (!QDir::isRelativePath(te)) {
+ if (::access(QFile::encodeName(te), X_OK))
+ return false;
+ } else {
+ // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
+ // Environment PATH may contain filenames in 8bit locale cpecified
+ // encoding (Like a filenames).
+ QStringList dirs = QStringList::split(':', QFile::decodeName(::getenv("PATH")));
+ QStringList::Iterator it(dirs.begin());
+ bool match = false;
+ for (; it != dirs.end(); ++it) {
+ QString fName = *it + "/" + te;
+ if (::access(QFile::encodeName(fName), X_OK) == 0)
+ {
+ match = true;
+ break;
+ }
+ }
+ // didn't match at all
+ if (!match)
+ return false;
+ }
+ }
+ QStringList list = readListEntry("X-KDE-AuthorizeAction");
+ if (kapp && !list.isEmpty())
+ {
+ for(QStringList::ConstIterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ if (!kapp->authorize((*it).stripWhiteSpace()))
+ return false;
+ }
+ }
+
+ // See also KService::username()
+ bool su = readBoolEntry("X-KDE-SubstituteUID");
+ if (su)
+ {
+ QString user = readEntry("X-KDE-Username");
+ if (user.isEmpty())
+ user = ::getenv("ADMIN_ACCOUNT");
+ if (user.isEmpty())
+ user = "root";
+ if (!kapp->authorize("user/"+user))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @return the filename as passed to the constructor.
+ */
+QString
+KDesktopFile::fileName() const { return backEnd->fileName(); }
+
+/**
+ * @return the resource type as passed to the constructor.
+ */
+QString
+KDesktopFile::resource() const { return backEnd->resource(); }
+
+QStringList
+KDesktopFile::sortOrder() const
+{
+ return readListEntry("SortOrder");
+}
+
+void KDesktopFile::virtual_hook( int id, void* data )
+{ KConfig::virtual_hook( id, data ); }
+
+QString KDesktopFile::readDocPath() const
+{
+ // Depreciated, remove in KDE4 or 5?
+ // See: http://www.freedesktop.org/Standards/desktop-entry-spec
+ if(hasKey( "DocPath" ))
+ return readPathEntry( "DocPath" );
+
+ return readPathEntry( "X-DocPath" );
+}
+
+KDesktopFile* KDesktopFile::copyTo(const QString &file) const
+{
+ KDesktopFile *config = new KDesktopFile(QString::null, false);
+ KConfig::copyTo(file, config);
+ config->setDesktopGroup();
+ return config;
+}
+
+
diff --git a/kdecore/kdesktopfile.h b/kdecore/kdesktopfile.h
new file mode 100644
index 000000000..ff0f66407
--- /dev/null
+++ b/kdecore/kdesktopfile.h
@@ -0,0 +1,251 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Pietro Iglio <iglio@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KDESKTOPFILE_H
+#define _KDESKTOPFILE_H
+
+#include "kconfig.h"
+#include "kdelibs_export.h"
+
+class KDesktopFilePrivate;
+
+/**
+ * KDE Desktop File Management.
+ *
+ * @author Pietro Iglio <iglio@kde.org>
+ * @see KConfigBase KConfig
+ * @short KDE Desktop File Management class
+ */
+class KDECORE_EXPORT KDesktopFile : public KConfig
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KDesktopFile object and make it either read-write
+ * or read-only.
+ *
+ * @param fileName The name or path of the desktop file. If it
+ * is not absolute, it will be located
+ * using the resource type @p resType.
+ * @param readOnly Whether the object should be read-only.
+ * @param resType Allows you to change what sort of resource
+ * to search for if @p fileName is not absolute. For
+ * instance, you might want to specify "config".
+ */
+ KDesktopFile( const QString &fileName, bool readOnly = false,
+ const char * resType = "apps");
+
+ /**
+ * Destructs the KDesktopFile object.
+ *
+ * Writes back any dirty configuration entries.
+ */
+ virtual ~KDesktopFile();
+
+ /**
+ * Checks whether this is really a desktop file.
+ *
+ * The check is performed looking at the file extension (the file is not
+ * opened).
+ * Currently, valid extensions are ".kdelnk" and ".desktop".
+ * @param path the path of the file to check
+ * @return true if the file appears to be a desktop file.
+ */
+ static bool isDesktopFile(const QString& path);
+
+ /**
+ * Checks whether the user is authorized to run this desktop file.
+ * By default users are authorized to run all desktop files but
+ * the KIOSK framework can be used to activate certain restrictions.
+ * See README.kiosk for more information.
+ * @param path the file to check
+ * @return true if the user is authorized to run the file
+ * @since 3.1
+ */
+ static bool isAuthorizedDesktopFile(const QString& path);
+
+ /**
+ * Returns the location where changes for the .desktop file @p path
+ * should be written to.
+ * @since 3.2
+ */
+ static QString locateLocal(const QString &path);
+
+ /**
+ * Returns the value of the "Type=" entry.
+ * @return the type or QString::null if not specified
+ */
+ QString readType() const;
+
+ /**
+ * Returns the value of the "Icon=" entry.
+ * @return the icon or QString::null if not specified
+ */
+ QString readIcon() const;
+
+ /**
+ * Returns the value of the "Name=" entry.
+ * @return the name or QString::null if not specified
+ */
+ QString readName() const;
+
+ /**
+ * Returns the value of the "Comment=" entry.
+ * @return the comment or QString::null if not specified
+ */
+ QString readComment() const;
+
+ /**
+ * Returns the value of the "GenericName=" entry.
+ * @return the generic name or QString::null if not specified
+ */
+ QString readGenericName() const;
+
+ /**
+ * Returns the value of the "Path=" entry.
+ * @return the path or QString::null if not specified
+ */
+ QString readPath() const;
+
+ /**
+ * Returns the value of the "Dev=" entry.
+ * @return the device or QString::null if not specified
+ */
+ QString readDevice() const;
+
+ /**
+ * Returns the value of the "URL=" entry.
+ * @return the URL or QString::null if not specified
+ */
+ QString readURL() const;
+
+ /**
+ * Returns a list of the "Actions=" entries.
+ * @return the list of actions
+ */
+ QStringList readActions() const;
+
+ /**
+ * Sets the desktop action group.
+ * @param group the new action group
+ */
+ void setActionGroup(const QString &group);
+
+ /**
+ * Returns true if the action group exists, false otherwise
+ * @param group the action group to test
+ * @return true if the action group exists
+ */
+ bool hasActionGroup(const QString &group) const;
+
+ /**
+ * Checks whether there is a "Type=Link" entry.
+ *
+ * The link points to the "URL=" entry.
+ * @return true if there is a "Type=Link" entry
+ */
+ bool hasLinkType() const;
+
+ /**
+ * Checks whether there is an entry "Type=Application".
+ * @return true if there is a "Type=Application" entry
+ */
+ bool hasApplicationType() const;
+
+ /**
+ * Checks whether there is an entry "Type=MimeType".
+ * @return true if there is a "Type=MimeType" entry
+ */
+ bool hasMimeTypeType() const; // funny name :)
+
+ /**
+ * Checks whether there is an entry "Type=FSDev".
+ * @return true if there is a "Type=FSDev" entry
+ */
+ bool hasDeviceType() const;
+
+ /**
+ * Checks whether the TryExec field contains a binary
+ * which is found on the local system.
+ * @return true if TryExec contains an existing binary
+ */
+ bool tryExec() const;
+
+ /**
+ * Returns the file name.
+ * @return The filename as passed to the constructor.
+ */
+ QString fileName() const;
+
+ /**
+ * Returns the resource.
+ * @return The resource type as passed to the constructor.
+ */
+ QString resource() const;
+
+ /**
+ * Returns the value of the "X-DocPath=" Or "DocPath=" entry.
+ * X-DocPath should be used and DocPath is depreciated and will
+ * one day be not supported.
+ * @return The value of the "X-DocPath=" Or "DocPath=" entry.
+ * @since 3.1
+ */
+ QString readDocPath() const;
+
+ /**
+ * Returns the entry of the "SortOrder=" entry.
+ * @return the value of the "SortOrder=" entry.
+ */
+ QStringList sortOrder() const;
+
+ /**
+ * Copies all entries from this config object to a new
+ * KDesktopFile object that will save itself to @p file.
+ *
+ * Actual saving to @p file happens when the returned object is
+ * destructed or when sync() is called upon it.
+ *
+ * @param file the new KDesktopFile object it will save itself to.
+ * @since 3.2
+ */
+ KDesktopFile* copyTo(const QString &file) const;
+
+#ifdef KDE_NO_COMPAT
+private:
+#endif
+ /**
+ * @deprecated Use fileName() instead.
+ */
+ KDE_DEPRECATED QString filename() const { return fileName(); };
+
+private:
+
+ // copy-construction and assignment are not allowed
+ KDesktopFile( const KDesktopFile& );
+ KDesktopFile& operator= ( const KDesktopFile& );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KDesktopFilePrivate *d;
+};
+
+
+#endif
+
diff --git a/kdecore/kdeversion.cpp b/kdecore/kdeversion.cpp
new file mode 100644
index 000000000..807618244
--- /dev/null
+++ b/kdecore/kdeversion.cpp
@@ -0,0 +1,46 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2002 KDE Team
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kdeversion.h"
+
+unsigned int KDE::version()
+{
+ return KDE_VERSION;
+}
+
+unsigned int KDE::versionMajor()
+{
+ return KDE_VERSION_MAJOR;
+}
+
+unsigned int KDE::versionMinor()
+{
+ return KDE_VERSION_MINOR;
+}
+
+unsigned int KDE::versionRelease()
+{
+ return KDE_VERSION_RELEASE;
+}
+
+const char *KDE::versionString()
+{
+ return KDE_VERSION_STRING;
+}
+
diff --git a/kdecore/kdeversion.h b/kdecore/kdeversion.h
new file mode 100644
index 000000000..dbe094633
--- /dev/null
+++ b/kdecore/kdeversion.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2002-2005 KDE Team
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDE_VERSION_H_
+#define _KDE_VERSION_H_
+
+#include "kdelibs_export.h"
+
+#define KDE_VERSION_STRING "3.5.10"
+#define KDE_VERSION_MAJOR 3
+#define KDE_VERSION_MINOR 5
+#define KDE_VERSION_RELEASE 10
+#define KDE_MAKE_VERSION( a,b,c ) (((a) << 16) | ((b) << 8) | (c))
+
+#define KDE_VERSION \
+ KDE_MAKE_VERSION(KDE_VERSION_MAJOR,KDE_VERSION_MINOR,KDE_VERSION_RELEASE)
+
+#define KDE_IS_VERSION(a,b,c) ( KDE_VERSION >= KDE_MAKE_VERSION(a,b,c) )
+
+/**
+ * Namespace for general KDE functions.
+ */
+namespace KDE
+{
+ /**
+ * Returns the encoded number of KDE's version, see the KDE_VERSION macro.
+ * In contrary to that macro this function returns the number of the actully
+ * installed KDE version, not the number of the KDE version that was
+ * installed when the program was compiled.
+ * @return the version number, encoded in a single uint
+ * @since 3.2
+ */
+ KDECORE_EXPORT unsigned int version();
+ /**
+ * Returns the major number of KDE's version, e.g.
+ * 3 for KDE 3.1.2.
+ * @return the major version number
+ * @since 3.1
+ */
+ KDECORE_EXPORT unsigned int versionMajor();
+ /**
+ * Returns the minor number of KDE's version, e.g.
+ * 1 for KDE 3.1.2.
+ * @return the minor version number
+ * @since 3.1
+ */
+ KDECORE_EXPORT unsigned int versionMinor();
+ /**
+ * Returns the release of KDE's version, e.g.
+ * 2 for KDE 3.1.2.
+ * @return the release number
+ * @since 3.1
+ */
+ KDECORE_EXPORT unsigned int versionRelease();
+ /**
+ * Returns the KDE version as string, e.g. "3.1.2".
+ * @return the KDE version. You can keep the string forever
+ * @since 3.1
+ */
+ KDECORE_EXPORT const char *versionString();
+}
+
+#endif // _KDE_VERSION_H_
diff --git a/kdecore/kentities.c b/kdecore/kentities.c
new file mode 100644
index 000000000..8181e5a6c
--- /dev/null
+++ b/kdecore/kentities.c
@@ -0,0 +1,837 @@
+/* ANSI-C code produced by gperf version 3.0.1 */
+/* Command-line: gperf -a -L ANSI-C -E -C -c -o -t -k '*' -Nkde_findEntity -D -Hhash_Entity -Wwordlist_Entity -s 2 kentities.gperf */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 1 "kentities.gperf"
+
+/* This file is part of the KDE libraries
+
+ Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ ----------------------------------------------------------------------------
+
+ kentities.gperf: input file to generate a hash table for entities
+ kentities.c: DO NOT EDIT! generated by the command
+ "gperf -a -L "ANSI-C" -C -G -c -o -t -k '*' -Nkde_findEntity -D -s 2 khtmlentities.gperf > entities.c"
+ from kentities.gperf
+
+ $Id$
+*/
+#line 31 "kentities.gperf"
+struct entity {
+ const char *name;
+ int code;
+};
+/* maximum key range = 924, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash_Entity (register const char *str, register unsigned int len)
+{
+ static const unsigned short asso_values[] =
+ {
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 0,
+ 145, 120, 0, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 125, 315, 35, 60, 325,
+ 5, 5, 0, 130, 932, 10, 0, 20, 110, 120,
+ 100, 0, 45, 40, 10, 135, 0, 932, 0, 15,
+ 50, 932, 932, 932, 932, 932, 932, 0, 15, 70,
+ 0, 20, 200, 250, 295, 10, 285, 5, 140, 90,
+ 15, 5, 65, 195, 5, 100, 25, 25, 130, 0,
+ 75, 190, 30, 35, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+ 932, 932, 932, 932, 932, 932, 932
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[7]];
+ /*FALLTHROUGH*/
+ case 7:
+ hval += asso_values[(unsigned char)str[6]];
+ /*FALLTHROUGH*/
+ case 6:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ hval += asso_values[(unsigned char)str[4]];
+ /*FALLTHROUGH*/
+ case 4:
+ hval += asso_values[(unsigned char)str[3]];
+ /*FALLTHROUGH*/
+ case 3:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ hval += asso_values[(unsigned char)str[1]+1];
+ /*FALLTHROUGH*/
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval;
+}
+
+#ifdef __GNUC__
+__inline
+#endif
+const struct entity *
+kde_findEntity (register const char *str, register unsigned int len)
+{
+ enum
+ {
+ TOTAL_KEYWORDS = 280,
+ MIN_WORD_LENGTH = 2,
+ MAX_WORD_LENGTH = 8,
+ MIN_HASH_VALUE = 8,
+ MAX_HASH_VALUE = 931
+ };
+
+ static const struct entity wordlist_Entity[] =
+ {
+#line 116 "kentities.gperf"
+ {"and", 0x22a5},
+#line 264 "kentities.gperf"
+ {"rho", 0x03c1},
+#line 142 "kentities.gperf"
+ {"darr", 0x2193},
+#line 143 "kentities.gperf"
+ {"dcaron", 0x10f},
+#line 257 "kentities.gperf"
+ {"rarr", 0x2192},
+#line 258 "kentities.gperf"
+ {"rcaron", 0x0159},
+#line 95 "kentities.gperf"
+ {"Tcaron", 0x0164},
+#line 185 "kentities.gperf"
+ {"int", 0x222b},
+#line 214 "kentities.gperf"
+ {"ncaron", 0x0148},
+#line 161 "kentities.gperf"
+ {"eta", 0x03b7},
+#line 150 "kentities.gperf"
+ {"ecaron", 0x011b},
+#line 94 "kentities.gperf"
+ {"Tau", 0x03a4},
+#line 299 "kentities.gperf"
+ {"uarr", 0x2191},
+#line 288 "kentities.gperf"
+ {"tcaron", 0x0165},
+#line 48 "kentities.gperf"
+ {"Chi", 0x03a7},
+#line 312 "kentities.gperf"
+ {"zcaron", 0x017e},
+#line 90 "kentities.gperf"
+ {"Rho", 0x03a1},
+#line 188 "kentities.gperf"
+ {"isin", 0x2208},
+#line 293 "kentities.gperf"
+ {"thorn", 0x00fe},
+#line 46 "kentities.gperf"
+ {"Ccaron", 0x010c},
+#line 287 "kentities.gperf"
+ {"tau", 0x03c4},
+#line 96 "kentities.gperf"
+ {"Theta", 0x0398},
+#line 91 "kentities.gperf"
+ {"Scaron", 0x0160},
+#line 110 "kentities.gperf"
+ {"acute", 0x00b4},
+#line 89 "kentities.gperf"
+ {"Rcaron", 0x0158},
+#line 106 "kentities.gperf"
+ {"Zcaron", 0x017d},
+#line 115 "kentities.gperf"
+ {"amp", 38},
+#line 220 "kentities.gperf"
+ {"nsub", 0x2284},
+#line 290 "kentities.gperf"
+ {"theta", 0x03b8},
+#line 289 "kentities.gperf"
+ {"there4", 0x2234},
+#line 243 "kentities.gperf"
+ {"phi", 0x03c6},
+#line 238 "kentities.gperf"
+ {"para", 0x00b6},
+#line 109 "kentities.gperf"
+ {"acirc", 0x00e2},
+#line 50 "kentities.gperf"
+ {"Dcaron", 0x010e},
+#line 132 "kentities.gperf"
+ {"chi", 0x03c7},
+#line 224 "kentities.gperf"
+ {"ocirc", 0x00f4},
+#line 180 "kentities.gperf"
+ {"icirc", 0x00ee},
+#line 128 "kentities.gperf"
+ {"ccaron", 0x010d},
+#line 251 "kentities.gperf"
+ {"psi", 0x03c8},
+#line 186 "kentities.gperf"
+ {"iota", 0x03b9},
+#line 254 "kentities.gperf"
+ {"radic", 0x221a},
+#line 231 "kentities.gperf"
+ {"or", 0x22a6},
+#line 218 "kentities.gperf"
+ {"not", 0x00ac},
+#line 152 "kentities.gperf"
+ {"ecirc", 0x00ea},
+#line 239 "kentities.gperf"
+ {"part", 0x2202},
+#line 300 "kentities.gperf"
+ {"ucirc", 0x00fb},
+#line 84 "kentities.gperf"
+ {"Phi", 0x03a6},
+#line 69 "kentities.gperf"
+ {"Lambda", 0x039b},
+#line 269 "kentities.gperf"
+ {"scaron", 0x0161},
+#line 229 "kentities.gperf"
+ {"omicron", 0x03bf},
+#line 88 "kentities.gperf"
+ {"QUOT", 34},
+#line 219 "kentities.gperf"
+ {"notin", 0x2209},
+#line 70 "kentities.gperf"
+ {"LT", 60},
+#line 87 "kentities.gperf"
+ {"Psi", 0x03a8},
+#line 72 "kentities.gperf"
+ {"Ncaron", 0x0147},
+#line 62 "kentities.gperf"
+ {"GT", 62},
+#line 227 "kentities.gperf"
+ {"oline", 0x203e},
+#line 222 "kentities.gperf"
+ {"nu", 0x03bd},
+#line 296 "kentities.gperf"
+ {"trade", 0x2122},
+#line 71 "kentities.gperf"
+ {"Mu", 0x039c},
+#line 127 "kentities.gperf"
+ {"cap", 0x2229},
+#line 270 "kentities.gperf"
+ {"sdot", 0x22c5},
+#line 190 "kentities.gperf"
+ {"kappa", 0x03ba},
+#line 68 "kentities.gperf"
+ {"Kappa", 0x039a},
+#line 108 "kentities.gperf"
+ {"aacute", 0x00e1},
+#line 164 "kentities.gperf"
+ {"euro", 0x20ac},
+#line 223 "kentities.gperf"
+ {"oacute", 0x00f3},
+#line 205 "kentities.gperf"
+ {"lt", 60},
+#line 195 "kentities.gperf"
+ {"larr", 0x2190},
+#line 179 "kentities.gperf"
+ {"iacute", 0x00ed},
+#line 249 "kentities.gperf"
+ {"prod", 0x220f},
+#line 247 "kentities.gperf"
+ {"pound", 0x00a3},
+#line 104 "kentities.gperf"
+ {"Yacute", 0x00dd},
+#line 259 "kentities.gperf"
+ {"rceil", 0x2309},
+#line 149 "kentities.gperf"
+ {"eacute", 0x00e9},
+#line 302 "kentities.gperf"
+ {"uml", 0x00a8},
+#line 206 "kentities.gperf"
+ {"macr", 0x00af},
+#line 137 "kentities.gperf"
+ {"crarr", 0x21b5},
+#line 298 "kentities.gperf"
+ {"uacute", 0x00fa},
+#line 265 "kentities.gperf"
+ {"rlm", 0x200f},
+#line 212 "kentities.gperf"
+ {"nabla", 0x2207},
+#line 187 "kentities.gperf"
+ {"iquest", 0x00bf},
+#line 158 "kentities.gperf"
+ {"ensp", 0x2002},
+#line 160 "kentities.gperf"
+ {"equiv", 0x2261},
+#line 233 "kentities.gperf"
+ {"ordm", 0x00ba},
+#line 121 "kentities.gperf"
+ {"atilde", 0x00e3},
+#line 156 "kentities.gperf"
+ {"emsp", 0x2003},
+#line 61 "kentities.gperf"
+ {"Gamma", 0x0393},
+#line 235 "kentities.gperf"
+ {"otilde", 0x00f5},
+#line 148 "kentities.gperf"
+ {"dol", 0x0024},
+#line 77 "kentities.gperf"
+ {"Ocirc", 0x00d4},
+#line 47 "kentities.gperf"
+ {"Ccedil", 0x00c7},
+#line 38 "kentities.gperf"
+ {"Acirc", 0x00c2},
+#line 221 "kentities.gperf"
+ {"ntilde", 0x00f1},
+#line 216 "kentities.gperf"
+ {"ne", 0x2260},
+#line 64 "kentities.gperf"
+ {"Icirc", 0x00ce},
+#line 211 "kentities.gperf"
+ {"mu", 0x03bc},
+#line 66 "kentities.gperf"
+ {"Iota", 0x0399},
+#line 98 "kentities.gperf"
+ {"Ucirc", 0x00db},
+#line 292 "kentities.gperf"
+ {"thinsp", 0x2009},
+#line 201 "kentities.gperf"
+ {"loz", 0x25ca},
+#line 250 "kentities.gperf"
+ {"prop", 0x221d},
+#line 74 "kentities.gperf"
+ {"Nu", 0x039d},
+#line 124 "kentities.gperf"
+ {"beta", 0x03b2},
+#line 184 "kentities.gperf"
+ {"infin", 0x221e},
+#line 129 "kentities.gperf"
+ {"ccedil", 0x00e7},
+#line 80 "kentities.gperf"
+ {"Omicron", 0x039f},
+#line 277 "kentities.gperf"
+ {"sub", 0x2282},
+#line 256 "kentities.gperf"
+ {"raquo", 0x00bb},
+#line 139 "kentities.gperf"
+ {"curren", 0x00a4},
+#line 213 "kentities.gperf"
+ {"nbsp", 0x00a0},
+#line 260 "kentities.gperf"
+ {"rdquo", 0x201d},
+#line 236 "kentities.gperf"
+ {"otimes", 0x2297},
+#line 117 "kentities.gperf"
+ {"ang", 0x2220},
+#line 313 "kentities.gperf"
+ {"zeta", 0x03b6},
+#line 267 "kentities.gperf"
+ {"rsquo", 0x2019},
+#line 266 "kentities.gperf"
+ {"rsaquo", 0x203a},
+#line 123 "kentities.gperf"
+ {"bdquo", 0x201e},
+#line 192 "kentities.gperf"
+ {"lambda", 0x03bb},
+#line 138 "kentities.gperf"
+ {"cup", 0x222a},
+#line 278 "kentities.gperf"
+ {"sube", 0x2286},
+#line 125 "kentities.gperf"
+ {"brvbar", 0x00a6},
+#line 174 "kentities.gperf"
+ {"gt", 62},
+#line 107 "kentities.gperf"
+ {"Zeta", 0x0396},
+#line 76 "kentities.gperf"
+ {"Oacute", 0x00d3},
+#line 37 "kentities.gperf"
+ {"Aacute", 0x00c1},
+#line 103 "kentities.gperf"
+ {"Xi", 0x039e},
+#line 255 "kentities.gperf"
+ {"rang", 0x232a},
+#line 248 "kentities.gperf"
+ {"prime", 0x2032},
+#line 63 "kentities.gperf"
+ {"Iacute", 0x00cd},
+#line 228 "kentities.gperf"
+ {"omega", 0x03c9},
+#line 97 "kentities.gperf"
+ {"Uacute", 0x00da},
+#line 284 "kentities.gperf"
+ {"sup", 0x2283},
+#line 280 "kentities.gperf"
+ {"sup1", 0x00b9},
+#line 183 "kentities.gperf"
+ {"image", 0x2111},
+#line 217 "kentities.gperf"
+ {"ni", 0x220b},
+#line 272 "kentities.gperf"
+ {"shy", 0x00ad},
+#line 118 "kentities.gperf"
+ {"apos", 0x0027},
+#line 134 "kentities.gperf"
+ {"clubs", 0x2663},
+#line 307 "kentities.gperf"
+ {"weierp", 0x2118},
+#line 232 "kentities.gperf"
+ {"ordf", 0x00aa},
+#line 73 "kentities.gperf"
+ {"Ntilde", 0x00d1},
+#line 131 "kentities.gperf"
+ {"cent", 0x00a2},
+#line 196 "kentities.gperf"
+ {"lceil", 0x2308},
+#line 285 "kentities.gperf"
+ {"supe", 0x2287},
+#line 155 "kentities.gperf"
+ {"empty", 0x2205},
+#line 82 "kentities.gperf"
+ {"Otilde", 0x00d5},
+#line 279 "kentities.gperf"
+ {"sum", 0x2211},
+#line 176 "kentities.gperf"
+ {"harr", 0x2194},
+#line 86 "kentities.gperf"
+ {"Prime", 0x2033},
+#line 43 "kentities.gperf"
+ {"Atilde", 0x00c3},
+#line 140 "kentities.gperf"
+ {"dArr", 0x21d3},
+#line 202 "kentities.gperf"
+ {"lrm", 0x200e},
+#line 253 "kentities.gperf"
+ {"rArr", 0x21d2},
+#line 151 "kentities.gperf"
+ {"eague", 0x00e9},
+#line 200 "kentities.gperf"
+ {"lowast", 0x2217},
+#line 41 "kentities.gperf"
+ {"AMP", 38},
+#line 242 "kentities.gperf"
+ {"perp", 0x22a5},
+#line 198 "kentities.gperf"
+ {"le", 0x2264},
+#line 162 "kentities.gperf"
+ {"eth", 0x00f0},
+#line 261 "kentities.gperf"
+ {"real", 0x211c},
+#line 165 "kentities.gperf"
+ {"exist", 0x2203},
+#line 309 "kentities.gperf"
+ {"yacute", 0x00fd},
+#line 244 "kentities.gperf"
+ {"pi", 0x03c0},
+#line 59 "kentities.gperf"
+ {"Eta", 0x0397},
+#line 297 "kentities.gperf"
+ {"uArr", 0x21d1},
+#line 54 "kentities.gperf"
+ {"Ecaron", 0x011a},
+#line 252 "kentities.gperf"
+ {"quot", 34},
+#line 308 "kentities.gperf"
+ {"xi", 0x03be},
+#line 122 "kentities.gperf"
+ {"auml", 0x00e4},
+#line 237 "kentities.gperf"
+ {"ouml", 0x00f6},
+#line 145 "kentities.gperf"
+ {"delta", 0x03b4},
+#line 189 "kentities.gperf"
+ {"iuml", 0x00ef},
+#line 120 "kentities.gperf"
+ {"asymp", 0x2248},
+#line 169 "kentities.gperf"
+ {"frac14", 0x00bc},
+#line 105 "kentities.gperf"
+ {"Yuml", 0x0178},
+#line 119 "kentities.gperf"
+ {"aring", 0x00e5},
+#line 163 "kentities.gperf"
+ {"euml", 0x00eb},
+#line 194 "kentities.gperf"
+ {"laquo", 0x00ab},
+#line 240 "kentities.gperf"
+ {"percnt", 0x0025},
+#line 85 "kentities.gperf"
+ {"Pi", 0x03a0},
+#line 306 "kentities.gperf"
+ {"uuml", 0x00fc},
+#line 197 "kentities.gperf"
+ {"ldquo", 0x201c},
+#line 246 "kentities.gperf"
+ {"plusmn", 0x00b1},
+#line 314 "kentities.gperf"
+ {"zwj", 0x200d},
+#line 136 "kentities.gperf"
+ {"copy", 0x00a9},
+#line 204 "kentities.gperf"
+ {"lsquo", 0x2018},
+#line 203 "kentities.gperf"
+ {"lsaquo", 0x2039},
+#line 271 "kentities.gperf"
+ {"sect", 0x00a7},
+#line 268 "kentities.gperf"
+ {"sbquo", 0x201a},
+#line 135 "kentities.gperf"
+ {"cong", 0x2245},
+#line 305 "kentities.gperf"
+ {"uring", 0x016f},
+#line 310 "kentities.gperf"
+ {"yen", 0x00a5},
+#line 315 "kentities.gperf"
+ {"zwnj", 0x200c},
+#line 79 "kentities.gperf"
+ {"Omega", 0x03a9},
+#line 209 "kentities.gperf"
+ {"middot", 0x00b7},
+#line 166 "kentities.gperf"
+ {"fnof", 0x0192},
+#line 55 "kentities.gperf"
+ {"Ecirc", 0x00ca},
+#line 263 "kentities.gperf"
+ {"rfloor", 0x230b},
+#line 283 "kentities.gperf"
+ {"sup3", 0x00b3},
+#line 93 "kentities.gperf"
+ {"THORN", 0x00de},
+#line 276 "kentities.gperf"
+ {"spades", 0x2660},
+#line 193 "kentities.gperf"
+ {"lang", 0x2329},
+#line 130 "kentities.gperf"
+ {"cedil", 0x00b8},
+#line 157 "kentities.gperf"
+ {"endash", 0x2013},
+#line 126 "kentities.gperf"
+ {"bull", 0x2022},
+#line 51 "kentities.gperf"
+ {"Delta", 0x0394},
+#line 133 "kentities.gperf"
+ {"circ", 0x02c6},
+#line 215 "kentities.gperf"
+ {"ndash", 0x2013},
+#line 154 "kentities.gperf"
+ {"emdash", 0x2014},
+#line 281 "kentities.gperf"
+ {"supl", 0x00b9},
+#line 282 "kentities.gperf"
+ {"sup2", 0x00b2},
+#line 172 "kentities.gperf"
+ {"gamma", 0x03b3},
+#line 147 "kentities.gperf"
+ {"divide", 0x00f7},
+#line 173 "kentities.gperf"
+ {"ge", 0x2265},
+#line 144 "kentities.gperf"
+ {"deg", 0x00b0},
+#line 114 "kentities.gperf"
+ {"alpha", 0x03b1},
+#line 112 "kentities.gperf"
+ {"agrave", 0x00e0},
+#line 262 "kentities.gperf"
+ {"reg", 0x00ae},
+#line 208 "kentities.gperf"
+ {"micro", 0x00b5},
+#line 226 "kentities.gperf"
+ {"ograve", 0x00f2},
+#line 52 "kentities.gperf"
+ {"ETH", 0x00d0},
+#line 182 "kentities.gperf"
+ {"igrave", 0x00ec},
+#line 291 "kentities.gperf"
+ {"thetasym", 0x03d1},
+#line 191 "kentities.gperf"
+ {"lArr", 0x21d0},
+#line 230 "kentities.gperf"
+ {"oplus", 0x2295},
+#line 294 "kentities.gperf"
+ {"tilde", 0x02dc},
+#line 153 "kentities.gperf"
+ {"egrave", 0x00e8},
+#line 275 "kentities.gperf"
+ {"sim", 0x223c},
+#line 146 "kentities.gperf"
+ {"diams", 0x2666},
+#line 301 "kentities.gperf"
+ {"ugrave", 0x00f9},
+#line 245 "kentities.gperf"
+ {"piv", 0x03d6},
+#line 83 "kentities.gperf"
+ {"Ouml", 0x00d6},
+#line 53 "kentities.gperf"
+ {"Eacute", 0x00c9},
+#line 44 "kentities.gperf"
+ {"Auml", 0x00c4},
+#line 159 "kentities.gperf"
+ {"epsilon", 0x03b5},
+#line 67 "kentities.gperf"
+ {"Iuml", 0x00cf},
+#line 170 "kentities.gperf"
+ {"frac34", 0x00be},
+#line 304 "kentities.gperf"
+ {"upsilon", 0x03c5},
+#line 102 "kentities.gperf"
+ {"Uuml", 0x00dc},
+#line 181 "kentities.gperf"
+ {"iexcl", 0x00a1},
+#line 42 "kentities.gperf"
+ {"Aring", 0x00c5},
+#line 207 "kentities.gperf"
+ {"mdash", 0x2014},
+#line 101 "kentities.gperf"
+ {"Uring", 0x016e},
+#line 241 "kentities.gperf"
+ {"permil", 0x2030},
+#line 210 "kentities.gperf"
+ {"minus", 0x2212},
+#line 168 "kentities.gperf"
+ {"frac12", 0x00bd},
+#line 295 "kentities.gperf"
+ {"times", 0x00d7},
+#line 75 "kentities.gperf"
+ {"OElig", 0x0152},
+#line 36 "kentities.gperf"
+ {"AElig", 0x00c6},
+#line 286 "kentities.gperf"
+ {"szlig", 0x00df},
+#line 45 "kentities.gperf"
+ {"Beta", 0x0392},
+#line 171 "kentities.gperf"
+ {"frasl", 0x2044},
+#line 141 "kentities.gperf"
+ {"dagger", 0x2020},
+#line 199 "kentities.gperf"
+ {"lfloor", 0x230a},
+#line 311 "kentities.gperf"
+ {"yuml", 0x00ff},
+#line 167 "kentities.gperf"
+ {"forall", 0x2200},
+#line 234 "kentities.gperf"
+ {"oslash", 0x00f8},
+#line 78 "kentities.gperf"
+ {"Ograve", 0x00d2},
+#line 40 "kentities.gperf"
+ {"Alpha", 0x0391},
+#line 39 "kentities.gperf"
+ {"Agrave", 0x00c0},
+#line 65 "kentities.gperf"
+ {"Igrave", 0x00cc},
+#line 99 "kentities.gperf"
+ {"Ugrave", 0x00d9},
+#line 111 "kentities.gperf"
+ {"aelig", 0x00e6},
+#line 49 "kentities.gperf"
+ {"Dagger", 0x2021},
+#line 100 "kentities.gperf"
+ {"Upsilon", 0x03a5},
+#line 225 "kentities.gperf"
+ {"oelig", 0x0153},
+#line 175 "kentities.gperf"
+ {"hArr", 0x21d4},
+#line 303 "kentities.gperf"
+ {"upsih", 0x03d2},
+#line 177 "kentities.gperf"
+ {"hearts", 0x2665},
+#line 57 "kentities.gperf"
+ {"Eague", 0x00c9},
+#line 92 "kentities.gperf"
+ {"Sigma", 0x03a3},
+#line 81 "kentities.gperf"
+ {"Oslash", 0x00d8},
+#line 60 "kentities.gperf"
+ {"Euml", 0x00cb},
+#line 113 "kentities.gperf"
+ {"alefsym", 0x2135},
+#line 273 "kentities.gperf"
+ {"sigma", 0x03c3},
+#line 56 "kentities.gperf"
+ {"Egrave", 0x00c8},
+#line 58 "kentities.gperf"
+ {"Epsilon", 0x0395},
+#line 178 "kentities.gperf"
+ {"hellip", 0x2026},
+#line 274 "kentities.gperf"
+ {"sigmaf", 0x03c2}
+ };
+
+ static const short lookup[] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, 0, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 1, -1, -1, -1, -1, -1, 2,
+ -1, 3, -1, -1, 4, -1, 5, -1, -1, -1,
+ -1, 6, -1, 7, -1, -1, 8, -1, 9, -1,
+ -1, 10, -1, 11, 12, -1, 13, -1, 14, -1,
+ -1, 15, -1, 16, 17, 18, 19, -1, 20, -1,
+ 21, 22, -1, -1, -1, 23, 24, -1, -1, -1,
+ -1, 25, -1, 26, 27, 28, 29, -1, 30, 31,
+ 32, 33, -1, 34, -1, 35, -1, -1, -1, -1,
+ 36, 37, -1, 38, 39, 40, -1, 41, 42, -1,
+ 43, -1, -1, -1, 44, 45, -1, -1, -1, -1,
+ -1, -1, -1, 46, -1, -1, 47, -1, -1, -1,
+ -1, 48, 49, -1, 50, 51, -1, 52, 53, -1,
+ -1, 54, 55, -1, -1, 56, -1, 57, -1, -1,
+ 58, -1, 59, 60, 61, 62, -1, -1, -1, -1,
+ 63, 64, -1, -1, 65, -1, 66, 67, -1, 68,
+ -1, 69, -1, -1, 70, 71, 72, -1, -1, -1,
+ 73, 74, -1, 75, 76, 77, 78, -1, 79, -1,
+ 80, 81, -1, -1, 82, 83, -1, -1, -1, 84,
+ -1, 85, -1, -1, 86, 87, 88, -1, 89, -1,
+ 90, 91, -1, -1, -1, 92, 93, 94, -1, -1,
+ 95, -1, 96, -1, 97, 98, -1, -1, -1, -1,
+ -1, 99, -1, -1, -1, -1, -1, -1, 100, 101,
+ -1, -1, 102, -1, 103, 104, 105, 106, 107, -1,
+ 108, 109, -1, -1, 110, 111, 112, -1, 113, 114,
+ 115, 116, -1, -1, -1, 117, 118, -1, 119, 120,
+ -1, 121, -1, -1, -1, -1, -1, 122, -1, 123,
+ -1, 124, -1, -1, -1, -1, 125, 126, -1, 127,
+ 128, 129, -1, -1, -1, 130, 131, -1, 132, 133,
+ 134, -1, 135, 136, 137, 138, 139, -1, -1, 140,
+ -1, 141, -1, -1, 142, 143, -1, -1, -1, 144,
+ 145, 146, -1, 147, 148, 149, 150, -1, -1, 151,
+ -1, -1, -1, 152, 153, 154, 155, -1, 156, 157,
+ -1, -1, 158, 159, -1, -1, -1, -1, -1, 160,
+ 161, 162, 163, 164, 165, -1, 166, -1, -1, 167,
+ -1, -1, 168, -1, 169, -1, -1, -1, -1, 170,
+ 171, -1, -1, -1, 172, 173, 174, -1, -1, 175,
+ 176, -1, -1, -1, 177, 178, 179, 180, -1, 181,
+ 182, 183, -1, 184, 185, 186, 187, -1, -1, 188,
+ 189, -1, -1, -1, 190, 191, -1, -1, 192, 193,
+ 194, 195, -1, -1, 196, 197, 198, -1, -1, 199,
+ 200, 201, -1, -1, 202, 203, 204, -1, -1, 205,
+ 206, -1, -1, -1, 207, 208, 209, -1, -1, 210,
+ -1, -1, -1, -1, 211, -1, -1, -1, -1, -1,
+ 212, 213, 214, 215, -1, 216, 217, -1, 218, -1,
+ 219, 220, -1, 221, -1, -1, 222, -1, 223, 224,
+ 225, -1, -1, -1, -1, 226, 227, -1, 228, -1,
+ 229, 230, -1, 231, 232, -1, 233, -1, -1, 234,
+ -1, -1, 235, -1, 236, -1, 237, 238, -1, 239,
+ 240, -1, -1, -1, -1, 241, -1, -1, -1, -1,
+ 242, -1, -1, -1, -1, 243, 244, -1, -1, -1,
+ 245, 246, -1, -1, -1, 247, -1, -1, -1, -1,
+ 248, -1, -1, -1, -1, 249, -1, -1, -1, -1,
+ 250, -1, -1, -1, 251, 252, 253, -1, -1, -1,
+ -1, 254, -1, -1, 255, -1, 256, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 257, -1, -1, -1, -1, 258, -1, -1, -1,
+ 259, 260, -1, -1, -1, -1, 261, -1, -1, -1,
+ -1, 262, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 263, 264, 265, -1, -1,
+ 266, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 267, -1, -1, -1, -1, -1,
+ 268, 269, -1, -1, -1, -1, -1, -1, -1, -1,
+ 270, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 271, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 272, -1, -1, 273,
+ -1, -1, -1, -1, -1, -1, -1, 274, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 275, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 276, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 277, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 278, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 279
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash_Entity (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register int index = lookup[key];
+
+ if (index >= 0)
+ {
+ register const char *s = wordlist_Entity[index].name;
+
+ if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+ return &wordlist_Entity[index];
+ }
+ }
+ }
+ return 0;
+}
+#line 316 "kentities.gperf"
+
+
diff --git a/kdecore/kentities.gperf b/kdecore/kentities.gperf
new file mode 100644
index 000000000..08f712707
--- /dev/null
+++ b/kdecore/kentities.gperf
@@ -0,0 +1,317 @@
+%{
+/* This file is part of the KDE libraries
+
+ Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ ----------------------------------------------------------------------------
+
+ kentities.gperf: input file to generate a hash table for entities
+ kentities.c: DO NOT EDIT! generated by the command
+ "gperf -a -L "ANSI-C" -C -G -c -o -t -k '*' -Nkde_findEntity -D -s 2 khtmlentities.gperf > entities.c"
+ from kentities.gperf
+
+ $Id$
+*/
+%}
+struct entity {
+ const char *name;
+ int code;
+};
+%%
+AElig, 0x00c6
+Aacute, 0x00c1
+Acirc, 0x00c2
+Agrave, 0x00c0
+Alpha, 0x0391
+AMP, 38
+Aring, 0x00c5
+Atilde, 0x00c3
+Auml, 0x00c4
+Beta, 0x0392
+Ccaron, 0x010c
+Ccedil, 0x00c7
+Chi, 0x03a7
+Dagger, 0x2021
+Dcaron, 0x010e
+Delta, 0x0394
+ETH, 0x00d0
+Eacute, 0x00c9
+Ecaron, 0x011a
+Ecirc, 0x00ca
+Egrave, 0x00c8
+Eague, 0x00c9
+Epsilon, 0x0395
+Eta, 0x0397
+Euml, 0x00cb
+Gamma, 0x0393
+GT, 62
+Iacute, 0x00cd
+Icirc, 0x00ce
+Igrave, 0x00cc
+Iota, 0x0399
+Iuml, 0x00cf
+Kappa, 0x039a
+Lambda, 0x039b
+LT, 60
+Mu, 0x039c
+Ncaron, 0x0147
+Ntilde, 0x00d1
+Nu, 0x039d
+OElig, 0x0152
+Oacute, 0x00d3
+Ocirc, 0x00d4
+Ograve, 0x00d2
+Omega, 0x03a9
+Omicron, 0x039f
+Oslash, 0x00d8
+Otilde, 0x00d5
+Ouml, 0x00d6
+Phi, 0x03a6
+Pi, 0x03a0
+Prime, 0x2033
+Psi, 0x03a8
+QUOT, 34
+Rcaron, 0x0158
+Rho, 0x03a1
+Scaron, 0x0160
+Sigma, 0x03a3
+THORN, 0x00de
+Tau, 0x03a4
+Tcaron, 0x0164
+Theta, 0x0398
+Uacute, 0x00da
+Ucirc, 0x00db
+Ugrave, 0x00d9
+Upsilon, 0x03a5
+Uring, 0x016e
+Uuml, 0x00dc
+Xi, 0x039e
+Yacute, 0x00dd
+Yuml, 0x0178
+Zcaron, 0x017d
+Zeta, 0x0396
+aacute, 0x00e1
+acirc, 0x00e2
+acute, 0x00b4
+aelig, 0x00e6
+agrave, 0x00e0
+alefsym, 0x2135
+alpha, 0x03b1
+amp, 38
+and, 0x22a5
+ang, 0x2220
+apos, 0x0027
+aring, 0x00e5
+asymp, 0x2248
+atilde, 0x00e3
+auml, 0x00e4
+bdquo, 0x201e
+beta, 0x03b2
+brvbar, 0x00a6
+bull, 0x2022
+cap, 0x2229
+ccaron, 0x010d
+ccedil, 0x00e7
+cedil, 0x00b8
+cent, 0x00a2
+chi, 0x03c7
+circ, 0x02c6
+clubs, 0x2663
+cong, 0x2245
+copy, 0x00a9
+crarr, 0x21b5
+cup, 0x222a
+curren, 0x00a4
+dArr, 0x21d3
+dagger, 0x2020
+darr, 0x2193
+dcaron, 0x10f
+deg, 0x00b0
+delta, 0x03b4
+diams, 0x2666
+divide, 0x00f7
+dol, 0x0024
+eacute, 0x00e9
+ecaron, 0x011b
+eague, 0x00e9
+ecirc, 0x00ea
+egrave, 0x00e8
+emdash, 0x2014
+empty, 0x2205
+emsp, 0x2003
+endash, 0x2013
+ensp, 0x2002
+epsilon, 0x03b5
+equiv, 0x2261
+eta, 0x03b7
+eth, 0x00f0
+euml, 0x00eb
+euro, 0x20ac
+exist, 0x2203
+fnof, 0x0192
+forall, 0x2200
+frac12, 0x00bd
+frac14, 0x00bc
+frac34, 0x00be
+frasl, 0x2044
+gamma, 0x03b3
+ge, 0x2265
+gt, 62
+hArr, 0x21d4
+harr, 0x2194
+hearts, 0x2665
+hellip, 0x2026
+iacute, 0x00ed
+icirc, 0x00ee
+iexcl, 0x00a1
+igrave, 0x00ec
+image, 0x2111
+infin, 0x221e
+int, 0x222b
+iota, 0x03b9
+iquest, 0x00bf
+isin, 0x2208
+iuml, 0x00ef
+kappa, 0x03ba
+lArr, 0x21d0
+lambda, 0x03bb
+lang, 0x2329
+laquo, 0x00ab
+larr, 0x2190
+lceil, 0x2308
+ldquo, 0x201c
+le, 0x2264
+lfloor, 0x230a
+lowast, 0x2217
+loz, 0x25ca
+lrm, 0x200e
+lsaquo, 0x2039
+lsquo, 0x2018
+lt, 60
+macr, 0x00af
+mdash, 0x2014
+micro, 0x00b5
+middot, 0x00b7
+minus, 0x2212
+mu, 0x03bc
+nabla, 0x2207
+nbsp, 0x00a0
+ncaron, 0x0148
+ndash, 0x2013
+ne, 0x2260
+ni, 0x220b
+not, 0x00ac
+notin, 0x2209
+nsub, 0x2284
+ntilde, 0x00f1
+nu, 0x03bd
+oacute, 0x00f3
+ocirc, 0x00f4
+oelig, 0x0153
+ograve, 0x00f2
+oline, 0x203e
+omega, 0x03c9
+omicron, 0x03bf
+oplus, 0x2295
+or, 0x22a6
+ordf, 0x00aa
+ordm, 0x00ba
+oslash, 0x00f8
+otilde, 0x00f5
+otimes, 0x2297
+ouml, 0x00f6
+para, 0x00b6
+part, 0x2202
+percnt, 0x0025
+permil, 0x2030
+perp, 0x22a5
+phi, 0x03c6
+pi, 0x03c0
+piv, 0x03d6
+plusmn, 0x00b1
+pound, 0x00a3
+prime, 0x2032
+prod, 0x220f
+prop, 0x221d
+psi, 0x03c8
+quot, 34
+rArr, 0x21d2
+radic, 0x221a
+rang, 0x232a
+raquo, 0x00bb
+rarr, 0x2192
+rcaron, 0x0159
+rceil, 0x2309
+rdquo, 0x201d
+real, 0x211c
+reg, 0x00ae
+rfloor, 0x230b
+rho, 0x03c1
+rlm, 0x200f
+rsaquo, 0x203a
+rsquo, 0x2019
+sbquo, 0x201a
+scaron, 0x0161
+sdot, 0x22c5
+sect, 0x00a7
+shy, 0x00ad
+sigma, 0x03c3
+sigmaf, 0x03c2
+sim, 0x223c
+spades, 0x2660
+sub, 0x2282
+sube, 0x2286
+sum, 0x2211
+sup1, 0x00b9
+supl, 0x00b9
+sup2, 0x00b2
+sup3, 0x00b3
+sup, 0x2283
+supe, 0x2287
+szlig, 0x00df
+tau, 0x03c4
+tcaron, 0x0165
+there4, 0x2234
+theta, 0x03b8
+thetasym, 0x03d1
+thinsp, 0x2009
+thorn, 0x00fe
+tilde, 0x02dc
+times, 0x00d7
+trade, 0x2122
+uArr, 0x21d1
+uacute, 0x00fa
+uarr, 0x2191
+ucirc, 0x00fb
+ugrave, 0x00f9
+uml, 0x00a8
+upsih, 0x03d2
+upsilon, 0x03c5
+uring, 0x016f
+uuml, 0x00fc
+weierp, 0x2118
+xi, 0x03be
+yacute, 0x00fd
+yen, 0x00a5
+yuml, 0x00ff
+zcaron, 0x017e
+zeta, 0x03b6
+zwj, 0x200d
+zwnj, 0x200c
+%%
+
diff --git a/kdecore/kextendedsocket.h b/kdecore/kextendedsocket.h
new file mode 100644
index 000000000..b90b999d1
--- /dev/null
+++ b/kdecore/kextendedsocket.h
@@ -0,0 +1,4 @@
+#ifndef KEXTENDEDSOCKET_H
+#define KEXTENDEDSOCKET_H
+#include "kextsock.h"
+#endif
diff --git a/kdecore/kextsock.cpp b/kdecore/kextsock.cpp
new file mode 100644
index 000000000..0ee2664b1
--- /dev/null
+++ b/kdecore/kextsock.cpp
@@ -0,0 +1,2241 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/times.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <netdb.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qglobal.h>
+#include <qstring.h>
+#include <qiodevice.h>
+#include <qsocketnotifier.h>
+#include <qguardedptr.h>
+
+#include "kresolver.h"
+
+#include "kdebug.h"
+#include "kextsock.h"
+#include "ksockaddr.h"
+#include "ksocks.h"
+
+#ifdef __CYGWIN__
+#include "netsupp.h"
+#endif
+
+using namespace KNetwork;
+
+//
+// Internal class definitions
+//
+
+class KExtendedSocketPrivate
+{
+public:
+ int flags; // socket flags
+ int status; // status
+ int syserror; // the system error value
+
+ timeval timeout; // connection/acception timeout
+
+ KResolver resRemote; // the resolved addresses
+ KResolver resLocal; // binding resolution
+ unsigned current; // used by the asynchronous connection
+
+ ::KSocketAddress *local; // local socket address
+ ::KSocketAddress *peer; // peer socket address
+
+ QSocketNotifier *qsnIn, *qsnOut;
+ int inMaxSize, outMaxSize;
+ bool emitRead : 1, emitWrite : 1;
+ mutable bool addressReusable : 1, ipv6only : 1;
+
+ KExtendedSocketPrivate() :
+ flags(0), status(0), syserror(0),
+ current(0), local(0), peer(0),
+ qsnIn(0), qsnOut(0), inMaxSize(-1), outMaxSize(-1), emitRead(false), emitWrite(false),
+ addressReusable(false), ipv6only(false)
+ {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ }
+};
+
+// translate KExtendedSocket flags into KResolver ones
+static bool process_flags(int flags, int& socktype, int& familyMask, int& outflags)
+{
+ switch (flags & (KExtendedSocket::streamSocket | KExtendedSocket::datagramSocket | KExtendedSocket::rawSocket))
+ {
+ case 0:
+ /* No flags given, use default */
+
+ case KExtendedSocket::streamSocket:
+ /* streaming socket requested */
+ socktype = SOCK_STREAM;
+ break;
+
+ case KExtendedSocket::datagramSocket:
+ /* datagram packet socket requested */
+ socktype = SOCK_DGRAM;
+ break;
+
+ case KExtendedSocket::rawSocket:
+ /* raw socket requested. I wouldn't do this if I were you... */
+ socktype = SOCK_RAW;
+ break;
+
+ default:
+ /* the flags were used in an invalid manner */
+ return false;
+ }
+
+ if (flags & KExtendedSocket::knownSocket)
+ {
+ familyMask = 0;
+ if ((flags & KExtendedSocket::unixSocket) == KExtendedSocket::unixSocket)
+ familyMask |= KResolver::UnixFamily;
+
+ switch ((flags & (KExtendedSocket::ipv6Socket|KExtendedSocket::ipv4Socket)))
+ {
+ case KExtendedSocket::ipv4Socket:
+ familyMask |= KResolver::IPv4Family;
+ break;
+ case KExtendedSocket::ipv6Socket:
+ familyMask |= KResolver::IPv6Family;
+ break;
+ case KExtendedSocket::inetSocket:
+ familyMask |= KResolver::InternetFamily;
+ break;
+ }
+
+ // those are all the families we know about
+ }
+ else
+ familyMask = KResolver::KnownFamily;
+
+ /* check other flags */
+ outflags = (flags & KExtendedSocket::passiveSocket ? KResolver::Passive : 0) |
+ (flags & KExtendedSocket::canonName ? KResolver::CanonName : 0) |
+ (flags & KExtendedSocket::noResolve ? KResolver::NoResolve : 0);
+
+ if (getenv("KDE_NO_IPV6"))
+ familyMask &= ~KResolver::IPv6Family;
+
+ return true;
+}
+
+// "skips" at most len bytes from file descriptor fd
+// that is, we will try and read that much data and discard
+// it. We will stop when we have read those or when the read
+// function returns error
+static int skipData(int fd, unsigned len)
+{
+ char buf[1024];
+ unsigned skipped = 0;
+ while (len)
+ {
+ int count = sizeof(buf);
+ if ((unsigned)count > len)
+ count = len;
+ count = KSocks::self()->read(fd, buf, count);
+ if (count == -1)
+ return -1;
+ else
+ {
+ len -= count;
+ skipped += count;
+ }
+ }
+ return skipped;
+}
+
+/*
+ * class KExtendedSocket
+ */
+
+// default constructor
+KExtendedSocket::KExtendedSocket() :
+ sockfd(-1), d(new KExtendedSocketPrivate)
+{
+}
+
+// constructor with hostname
+KExtendedSocket::KExtendedSocket(const QString& host, int port, int flags) :
+ sockfd(-1), d(new KExtendedSocketPrivate)
+{
+ setAddress(host, port);
+ setSocketFlags(flags);
+}
+
+// same
+KExtendedSocket::KExtendedSocket(const QString& host, const QString& service, int flags) :
+ sockfd(-1), d(new KExtendedSocketPrivate)
+{
+ setAddress(host, service);
+ setSocketFlags(flags);
+}
+
+// destroy the class
+KExtendedSocket::~KExtendedSocket()
+{
+ closeNow();
+
+ if (d->local != NULL)
+ delete d->local;
+ if (d->peer != NULL)
+ delete d->peer;
+
+ if (d->qsnIn != NULL)
+ delete d->qsnIn;
+ if (d->qsnOut != NULL)
+ delete d->qsnOut;
+
+ delete d;
+}
+
+void KExtendedSocket::reset()
+{
+ closeNow();
+ release();
+ d->current = 0;
+ d->status = nothing;
+ d->syserror = 0;
+}
+
+int KExtendedSocket::socketStatus() const
+{
+ return d->status;
+}
+
+void KExtendedSocket::setSocketStatus(int newstatus)
+{
+ d->status = newstatus;
+}
+
+void KExtendedSocket::setError(int errorcode, int syserror)
+{
+ setStatus(errorcode);
+ d->syserror = syserror;
+}
+
+int KExtendedSocket::systemError() const
+{
+ return d->syserror;
+}
+
+/*
+ * Sets socket flags
+ * This is only allowed if we are in nothing state
+ */
+int KExtendedSocket::setSocketFlags(int flags)
+{
+ if (d->status > nothing)
+ return -1; // error!
+
+ return d->flags = flags;
+}
+
+int KExtendedSocket::socketFlags() const
+{
+ return d->flags;
+}
+
+/*
+ * Sets socket target hostname
+ * This is only allowed if we are in nothing state
+ */
+bool KExtendedSocket::setHost(const QString& host)
+{
+ if (d->status > nothing)
+ return false; // error!
+
+ d->resRemote.setNodeName(host);
+ return true;
+}
+
+/*
+ * returns the hostname
+ */
+QString KExtendedSocket::host() const
+{
+ return d->resRemote.nodeName();
+}
+
+/*
+ * Sets the socket target port/service
+ * Same thing: only state 'nothing'
+ */
+bool KExtendedSocket::setPort(int port)
+{
+ return setPort(QString::number(port));
+}
+
+bool KExtendedSocket::setPort(const QString& service)
+{
+ if (d->status > nothing)
+ return false; // error
+
+ d->resRemote.setServiceName(service);
+ return true;
+}
+
+/*
+ * returns the service port number
+ */
+QString KExtendedSocket::port() const
+{
+ return d->resRemote.serviceName();
+}
+
+/*
+ * sets the address
+ */
+bool KExtendedSocket::setAddress(const QString& host, int port)
+{
+ return setHost(host) && setPort(port);
+}
+
+/*
+ * the same
+ */
+bool KExtendedSocket::setAddress(const QString& host, const QString& serv)
+{
+ return setHost(host) && setPort(serv);
+}
+
+/*
+ * Sets the bind hostname
+ * This is only valid in the 'nothing' state and if this is not a
+ * passiveSocket socket
+ */
+bool KExtendedSocket::setBindHost(const QString& host)
+{
+ if (d->status > nothing || d->flags & passiveSocket)
+ return false; // error
+
+ d->resLocal.setServiceName(host);
+ return true;
+}
+
+/*
+ * Unsets the bind hostname
+ * same thing
+ */
+bool KExtendedSocket::unsetBindHost()
+{
+ return setBindHost(QString::null);
+}
+
+/*
+ * returns the binding host
+ */
+QString KExtendedSocket::bindHost() const
+{
+ return d->resLocal.serviceName();
+}
+
+/*
+ * Sets the bind port
+ * Same condition as setBindHost
+ */
+bool KExtendedSocket::setBindPort(int port)
+{
+ return setBindPort(QString::number(port));
+}
+
+bool KExtendedSocket::setBindPort(const QString& service)
+{
+ if (d->status > nothing || d->flags & passiveSocket)
+ return false; // error
+
+ d->resLocal.setServiceName(service);
+ return true;
+}
+
+/*
+ * unsets the bind port
+ */
+bool KExtendedSocket::unsetBindPort()
+{
+ return setBindPort(QString::null);
+}
+
+/*
+ * returns the binding port
+ */
+QString KExtendedSocket::bindPort() const
+{
+ return d->resLocal.serviceName();
+}
+
+/*
+ * sets the binding address
+ */
+bool KExtendedSocket::setBindAddress(const QString& host, int port)
+{
+ return setBindHost(host) && setBindPort(port);
+}
+
+/*
+ * same
+ */
+bool KExtendedSocket::setBindAddress(const QString& host, const QString& service)
+{
+ return setBindHost(host) && setBindPort(service);
+}
+
+/*
+ * unsets binding address
+ */
+bool KExtendedSocket::unsetBindAddress()
+{
+ return unsetBindHost() && unsetBindPort();
+}
+
+/*
+ * sets the timeout for the connection
+ */
+bool KExtendedSocket::setTimeout(int secs, int usecs)
+{
+ if (d->status >= connected) // closed?
+ return false;
+
+ d->timeout.tv_sec = secs;
+ d->timeout.tv_usec = usecs;
+ return true;
+}
+
+/*
+ * returns the timeout
+ */
+timeval KExtendedSocket::timeout() const
+{
+ return d->timeout;
+}
+
+/*
+ * Sets the blocking mode on this socket
+ */
+bool KExtendedSocket::setBlockingMode(bool enable)
+{
+ cleanError();
+ if (d->status < created)
+ return false;
+
+ if (sockfd == -1)
+ return false; // error!
+
+ int fdflags = fcntl(sockfd, F_GETFL, 0);
+ if (fdflags == -1)
+ return false; // error!
+
+ if (!enable)
+ fdflags |= O_NONBLOCK;
+ else
+ fdflags &= ~O_NONBLOCK;
+
+ if (fcntl(sockfd, F_SETFL, fdflags) == -1)
+ {
+ setError(IO_UnspecifiedError, errno);
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Returns the blocking mode on the socket
+ */
+bool KExtendedSocket::blockingMode()
+{
+ cleanError();
+ if (d->status < created)
+ return false; // sockets not created are in blocking mode
+
+ if (sockfd == -1)
+ return false; // error
+
+ int fdflags = fcntl(sockfd, F_GETFL, 0);
+ if (fdflags == -1)
+ {
+ setError(IO_UnspecifiedError, errno);
+ return false;
+ }
+ return (fdflags & O_NONBLOCK) == 0; // non-blocking == false
+}
+
+/*
+ * Sets the reusability flag for this socket in the OS
+ */
+bool KExtendedSocket::setAddressReusable(bool enable)
+{
+ cleanError();
+ d->addressReusable = enable;
+ if (d->status < created)
+ return true;
+
+ if (sockfd == -1)
+ return true;
+
+ if (!setAddressReusable(sockfd, enable))
+ {
+ setError(IO_UnspecifiedError, errno);
+ return false;
+ }
+ return true;
+}
+
+bool KExtendedSocket::setAddressReusable(int fd, bool enable)
+{
+ if (fd == -1)
+ return false;
+
+ int on = enable; // just to be on the safe side
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1)
+ return false;
+ return true;
+}
+
+/*
+ * Retrieves the reusability flag for this socket
+ */
+bool KExtendedSocket::addressReusable()
+{
+ cleanError();
+ if (d->status < created)
+ return d->addressReusable;
+
+ if (sockfd == -1)
+ return d->addressReusable;
+
+ int on;
+ socklen_t onsiz = sizeof(on);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, &onsiz) == -1)
+ {
+ setError(IO_UnspecifiedError, errno);
+ return false;
+ }
+
+ return on != 0;
+}
+
+/*
+ * Set the IPV6_V6ONLY flag
+ */
+bool KExtendedSocket::setIPv6Only(bool enable)
+{
+#ifdef IPV6_V6ONLY
+ cleanError();
+
+ d->ipv6only = enable;
+ if (sockfd == -1)
+ return true; // can't set on a non-existing socket
+
+ int on = enable;
+
+ if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&on, sizeof(on)) == -1)
+ {
+ setError(IO_UnspecifiedError, errno);
+ return false;
+ }
+ else
+ return true;
+
+#else
+ // we don't have the IPV6_V6ONLY constant in this system
+ d->ipv6only = enable;
+
+ setError(IO_UnspecifiedError, ENOSYS);
+ return false; // can't set if we don't know about this flag
+#endif
+}
+
+/*
+ * retrieve the IPV6_V6ONLY flag
+ */
+bool KExtendedSocket::isIPv6Only()
+{
+#ifdef IPV6_V6ONLY
+ cleanError();
+
+ if (d->status < created || sockfd == -1)
+ return d->ipv6only;
+
+ int on;
+ socklen_t onsiz = sizeof(on);
+ if (getsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&on, &onsiz) == -1)
+ {
+ setError(IO_UnspecifiedError, errno);
+ return false;
+ }
+
+ return d->ipv6only = on;
+
+#else
+ // we don't have the constant
+ setError(IO_UnspecifiedError, ENOSYS);
+ return false;
+#endif
+}
+
+/*
+ * Sets the buffer sizes in this socket
+ * Also, we create or delete the socket notifiers
+ */
+bool KExtendedSocket::setBufferSize(int rsize, int wsize)
+{
+ cleanError();
+ if (d->status < created)
+ return false;
+
+ if (sockfd == -1)
+ return false;
+
+ if (d->flags & passiveSocket)
+ return false; // no I/O on passive sockets
+
+ if (rsize < -2)
+ return false;
+
+ if (wsize < -2)
+ return false;
+
+ // LOCK BUFFER MUTEX
+
+ // The input socket notifier is always enabled
+ // That happens because we want to be notified of when the socket gets
+ // closed
+ if (d->qsnIn == NULL)
+ {
+ d->qsnIn = new QSocketNotifier(sockfd, QSocketNotifier::Read);
+ QObject::connect(d->qsnIn, SIGNAL(activated(int)), this, SLOT(socketActivityRead()));
+ d->qsnIn->setEnabled(true);
+ }
+
+ if (rsize == 0 && d->flags & inputBufferedSocket)
+ {
+ // user wants to disable input buffering
+ d->flags &= ~inputBufferedSocket;
+
+ consumeReadBuffer(readBufferSize(), NULL, true);
+ d->inMaxSize = 0;
+ }
+ else if (rsize != -2)
+ {
+ // enabling input buffering
+ if (rsize)
+ d->flags |= inputBufferedSocket;
+ d->inMaxSize = rsize;
+
+ if (rsize > 0 && (unsigned)rsize < readBufferSize())
+ // input buffer has more data than the new size; discard
+ consumeReadBuffer(readBufferSize() - rsize, NULL, true);
+
+ }
+
+ if (wsize == 0 && d->flags & outputBufferedSocket)
+ {
+ // disabling output buffering
+ d->flags &= ~outputBufferedSocket;
+ if (d->qsnOut && !d->emitWrite)
+ d->qsnOut->setEnabled(false);
+ consumeWriteBuffer(writeBufferSize());
+ d->outMaxSize = 0;
+ }
+ else if (wsize != -2)
+ {
+ // enabling input buffering
+ if (wsize)
+ d->flags |= outputBufferedSocket;
+ d->outMaxSize = wsize;
+
+ if (wsize > 0 && (unsigned)wsize < writeBufferSize())
+ // output buffer is bigger than it is to become; shrink
+ consumeWriteBuffer(writeBufferSize() - wsize);
+
+ if (d->qsnOut == NULL)
+ {
+ d->qsnOut = new QSocketNotifier(sockfd, QSocketNotifier::Write);
+ QObject::connect(d->qsnOut, SIGNAL(activated(int)), this, SLOT(socketActivityWrite()));
+ // if the class is being created now, there's nothing to write yet
+ // so socketActivityWrite() will get called once and disable
+ // the notifier
+ }
+ }
+
+ // UNLOCK BUFFER MUTEX
+
+ setFlags((mode() & ~IO_Raw) | ((d->flags & bufferedSocket) ? 0 : IO_Raw));
+
+ // check we didn't turn something off we shouldn't
+ if (d->emitWrite && d->qsnOut == NULL)
+ {
+ d->qsnOut = new QSocketNotifier(sockfd, QSocketNotifier::Write);
+ QObject::connect(d->qsnOut, SIGNAL(activated(int)), this, SLOT(socketActivityWrite()));
+ }
+
+ return true;
+}
+
+/*
+ * Finds the local address for this socket
+ * if we have done this already, we return it. Otherwise, we'll have
+ * to find the socket name
+ */
+const ::KSocketAddress *KExtendedSocket::localAddress()
+{
+ if (d->local != NULL)
+ return d->local;
+ if (d->status < bound)
+ return NULL;
+
+ return d->local = localAddress(sockfd);
+}
+
+/*
+ * Same thing, but for peer address. Which means this does not work on
+ * passiveSocket and that we require to be connected already. Also note that
+ * the behavior on connectionless sockets is not defined here.
+ */
+const ::KSocketAddress* KExtendedSocket::peerAddress()
+{
+ if (d->peer != NULL)
+ return d->peer;
+ if (d->flags & passiveSocket || d->status < connected)
+ return NULL;
+
+ return d->peer = peerAddress(sockfd);
+}
+
+/*
+ * Perform the lookup on the addresses given
+ */
+int KExtendedSocket::lookup()
+{
+ if (startAsyncLookup() != 0)
+ return -1;
+
+ if (!d->resRemote.wait() || !d->resLocal.wait())
+ {
+ d->status = nothing;
+ return -1;
+ }
+
+ d->status = lookupDone;
+ if (d->resRemote.error() != KResolver::NoError)
+ return d->resRemote.error();
+ if (d->resLocal.error() != KResolver::NoError)
+ return d->resLocal.error();
+ return 0;
+}
+
+/*
+ * Performs an asynchronous lookup on the given address(es)
+ */
+int KExtendedSocket::startAsyncLookup()
+{
+ cleanError();
+ if (d->status > lookupInProgress)
+ return -1;
+ if (d->status == lookupInProgress)
+ // already in progress
+ return 0;
+
+ /* check socket type flags */
+ int socktype, familyMask, flags;
+ if (!process_flags(d->flags, socktype, familyMask, flags))
+ return -2;
+
+ // perform the global lookup before
+ if (!d->resRemote.isRunning())
+ {
+ d->resRemote.setFlags(flags);
+ d->resRemote.setFamily(familyMask);
+ d->resRemote.setSocketType(socktype);
+ QObject::connect(&d->resRemote, SIGNAL(finished(KResolverResults)),
+ this, SLOT(dnsResultsReady()));
+
+ if (!d->resRemote.start())
+ {
+ setError(IO_LookupError, d->resRemote.error());
+ return d->resRemote.error();
+ }
+ }
+
+ if ((d->flags & passiveSocket) == 0 && !d->resLocal.isRunning())
+ {
+ /* keep flags, but make this passive */
+ flags |= KResolver::Passive;
+ d->resLocal.setFlags(flags);
+ d->resLocal.setFamily(familyMask);
+ d->resLocal.setSocketType(socktype);
+ QObject::connect(&d->resLocal, SIGNAL(finished(KResolverResults)),
+ this, SLOT(dnsResultsReady()));
+
+ if (!d->resLocal.start())
+ {
+ setError(IO_LookupError, d->resLocal.error());
+ return d->resLocal.error();
+ }
+ }
+
+ // if we are here, there were no errors
+ if (d->resRemote.isRunning() || d->resLocal.isRunning())
+ d->status = lookupInProgress; // only if there actually is a running lookup
+ else
+ {
+ d->status = lookupDone;
+ emit lookupFinished(d->resRemote.results().count() +
+ d->resLocal.results().count());
+ }
+ return 0;
+}
+
+void KExtendedSocket::cancelAsyncLookup()
+{
+ cleanError();
+ if (d->status != lookupInProgress)
+ return; // what's to cancel?
+
+ d->status = nothing;
+ d->resLocal.cancel(false);
+ d->resRemote.cancel(false);
+}
+
+int KExtendedSocket::listen(int N)
+{
+ cleanError();
+ if ((d->flags & passiveSocket) == 0 || d->status >= listening)
+ return -2;
+ if (d->status < lookupDone)
+ if (lookup() != 0)
+ return -2; // error!
+ if (d->resRemote.error())
+ return -2;
+
+ // doing the loop:
+ KResolverResults::const_iterator it;
+ KResolverResults res = d->resRemote.results();
+ for (it = res.begin(); it != res.end(); ++it)
+ {
+ //kdDebug(170) << "Trying to listen on " << (*it).address().toString() << endl;
+ sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol());
+ if (sockfd == -1)
+ {
+ // socket failed creating
+ //kdDebug(170) << "Failed to create: " << perror << endl;
+ continue;
+ }
+
+ fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+
+ if (d->addressReusable)
+ setAddressReusable(sockfd, true);
+ setIPv6Only(d->ipv6only);
+ cleanError();
+ if (KSocks::self()->bind(sockfd, (*it).address().address(), (*it).length()) == -1)
+ {
+ //kdDebug(170) << "Failed to bind: " << perror << endl;
+ ::close(sockfd);
+ sockfd = -1;
+ continue;
+ }
+
+ // ok, socket has bound
+ // kdDebug(170) << "Socket bound: " << sockfd << endl;
+
+ d->status = bound;
+ break;
+ }
+
+ if (sockfd == -1)
+ {
+ setError(IO_ListenError, errno);
+ //kdDebug(170) << "Listen error - sockfd is -1 " << endl;
+ return -1;
+ }
+
+ d->status = bound;
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite);
+
+ int retval = KSocks::self()->listen(sockfd, N);
+ if (retval == -1)
+ setError(IO_ListenError, errno);
+ else
+ {
+ d->status = listening;
+ d->qsnIn = new QSocketNotifier(sockfd, QSocketNotifier::Read);
+ QObject::connect(d->qsnIn, SIGNAL(activated(int)), this, SLOT(socketActivityRead()));
+ }
+ return retval == -1 ? -1 : 0;
+}
+
+int KExtendedSocket::accept(KExtendedSocket *&sock)
+{
+ cleanError();
+ sock = NULL;
+ if ((d->flags & passiveSocket) == 0 || d->status >= accepting)
+ return -2;
+ if (d->status < listening)
+ if (listen() < 0)
+ return -2; // error!
+
+ // let's see
+ // if we have a timeout in place, we have to place this socket in non-blocking
+ // mode
+ bool block = blockingMode();
+ struct sockaddr sa;
+ ksocklen_t len = sizeof(sa);
+ sock = NULL;
+
+ if (d->timeout.tv_sec > 0 || d->timeout.tv_usec > 0)
+ {
+ fd_set set;
+
+ setBlockingMode(false); // turn on non-blocking
+ FD_ZERO(&set);
+ FD_SET(sockfd, &set);
+
+ //kdDebug(170).form("Accepting on %d with %d.%06d second timeout\n",
+ // sockfd, d->timeout.tv_sec, d->timeout.tv_usec);
+ // check if there is anything to accept now
+ int retval = KSocks::self()->select(sockfd + 1, &set, NULL, NULL, &d->timeout);
+ if (retval == -1)
+ {
+ setError(IO_UnspecifiedError, errno);
+ return -1; // system error
+ }
+ else if (retval == 0 || !FD_ISSET(sockfd, &set))
+ {
+ setError(IO_TimeOutError, 0);
+ return -3; // timeout
+ }
+ }
+
+ // it's common stuff here
+ int newfd = KSocks::self()->accept(sockfd, &sa, &len);
+
+ if (newfd == -1)
+ {
+ setError(IO_AcceptError, errno);
+ kdWarning(170) << "Error accepting on socket " << sockfd << ":"
+ << perror << endl;
+ return -1;
+ }
+
+ fcntl(newfd, F_SETFD, FD_CLOEXEC);
+
+ //kdDebug(170).form("Socket %d accepted socket %d\n", sockfd, newfd);
+
+ setBlockingMode(block); // restore blocking mode
+
+ sock = new KExtendedSocket;
+ sock->d->status = connected;
+ sock->sockfd = newfd;
+ sock->setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+ sock->setBufferSize(0, 0); // always unbuffered here. User can change that later
+
+ return 0;
+}
+
+/*
+ * tries to connect
+ *
+ * FIXME!
+ * This function is critical path. It has to be cleaned up and made faster
+ */
+int KExtendedSocket::connect()
+{
+ cleanError();
+ if (d->flags & passiveSocket || d->status >= connected)
+ return -2;
+ if (d->status < lookupDone)
+ if (lookup() != 0)
+ return -2;
+
+ timeval end, now;
+ timeval timeout_copy = d->timeout;
+ // Ok, things are a little tricky here
+ // Let me explain
+ // getaddrinfo() will return several different families of sockets
+ // When we have to bind before we connect, we have to make sure we're binding
+ // and connecting to the same family, or things won't work
+
+ KResolverResults remote = d->resRemote.results(),
+ local = d->resLocal.results();
+ KResolverResults::const_iterator it, it2;
+ //kdDebug(170) << "Starting connect to " << host() << '|' << port()
+ // << ": have " << local.count() << " local entries and "
+ // << remote.count() << " remote" << endl;
+
+ int ret = -1;
+ for (it = remote.begin(), it2 = local.begin(); it != remote.end(); ++it)
+ {
+ bool doingtimeout = d->timeout.tv_sec > 0 || d->timeout.tv_usec > 0;
+ if (doingtimeout)
+ {
+ gettimeofday(&end, NULL);
+ end.tv_usec += d->timeout.tv_usec;
+ end.tv_sec += d->timeout.tv_sec;
+ if (end.tv_usec > 1000*1000)
+ {
+ end.tv_usec -= 1000*1000;
+ end.tv_sec++;
+ }
+ //kdDebug(170).form("Connection with timeout of %d.%06d seconds (ends in %d.%06d)\n",
+ // d->timeout.tv_sec, d->timeout.tv_usec, end.tv_sec, end.tv_usec);
+ }
+
+ //kdDebug(170) << "Trying to connect to " << (*it).address().toString() << endl;
+ if (it2 != local.end())
+ {
+// //kdDebug(170) << "Searching bind socket for family " << p->ai_family << endl;
+ if ((*it).family() != (*it2).family())
+ // differing families, scan local for a matching family
+ for (it2 = local.begin(); it2 != local.end(); ++it2)
+ if ((*it).family() == (*it2).family())
+ break;
+
+ if ((*it).family() != (*it2).family())
+ {
+ // no matching families for this
+ //kdDebug(170) << "No matching family for bind socket\n";
+ it2 = local.begin();
+ continue;
+ }
+
+ //kdDebug(170) << "Binding on " << (*it2).address().toString() << " before connect" << endl;
+ errno = 0;
+ sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol());
+ setError(IO_ConnectError, errno);
+ if (sockfd == -1)
+ continue; // cannot create this socket
+ fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+ if (d->addressReusable)
+ setAddressReusable(sockfd, true);
+ setIPv6Only(d->ipv6only);
+ cleanError();
+ if (KSocks::self()->bind(sockfd, (*it2).address(), (*it2).length()))
+ {
+ //kdDebug(170) << "Bind failed: " << perror << endl;
+ ::close(sockfd);
+ sockfd = -1;
+ continue;
+ }
+ }
+ else
+ {
+ // no need to bind, just create
+ sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol());
+ if (sockfd == -1)
+ {
+ setError(IO_ConnectError, errno);
+ continue;
+ }
+ fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+ if (d->addressReusable)
+ setAddressReusable(sockfd, true);
+ setIPv6Only(d->ipv6only);
+ cleanError();
+ }
+
+// kdDebug(170) << "Socket " << sockfd << " created" << endl;
+ d->status = created;
+
+ // check if we have to do timeout
+ if (doingtimeout && KSocks::self()->hasWorkingAsyncConnect())
+ {
+ fd_set rd, wr;
+
+ setBlockingMode(false);
+
+ // now try and connect
+ if (KSocks::self()->connect(sockfd, (*it).address(), (*it).length()) == -1)
+ {
+ // this could be EWOULDBLOCK
+ if (errno != EWOULDBLOCK && errno != EINPROGRESS)
+ {
+ //kdDebug(170) << "Socket " << sockfd << " did not connect: " << perror << endl;
+ setError(IO_ConnectError, errno);
+ ::close(sockfd);
+ sockfd = -1;
+ continue; // nope, another error
+ }
+
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_SET(sockfd, &rd);
+ FD_SET(sockfd, &wr);
+
+ int retval = KSocks::self()->select(sockfd + 1, &rd, &wr, NULL, &d->timeout);
+ if (retval == -1)
+ {
+ setError(IO_FatalError, errno);
+ continue; // system error
+ }
+ else if (retval == 0)
+ {
+ ::close(sockfd);
+ sockfd = -1;
+// kdDebug(170) << "Time out while trying to connect to " <<
+// (*it).address().toString() << endl;
+ setError(IO_TimeOutError, 0);
+ ret = -3; // time out
+
+ d->timeout.tv_usec += timeout_copy.tv_usec;
+ d->timeout.tv_sec += timeout_copy.tv_sec;
+ if (d->timeout.tv_usec < 0)
+ {
+ d->timeout.tv_usec += 1000*1000;
+ d->timeout.tv_sec--;
+ }
+
+ continue;
+ }
+
+ // adjust remaining time
+ gettimeofday(&now, NULL);
+ d->timeout.tv_sec = end.tv_sec - now.tv_sec;
+ d->timeout.tv_usec = end.tv_usec - now.tv_usec;
+ if (d->timeout.tv_usec < 0)
+ {
+ d->timeout.tv_usec += 1000*1000;
+ d->timeout.tv_sec--;
+ }
+// kdDebug(170).form("Socket %d activity; %d.%06d seconds remaining\n",
+// sockfd, d->timeout.tv_sec, d->timeout.tv_usec);
+
+ // this means that an event occurred in the socket
+ int errcode;
+ socklen_t len = sizeof(errcode);
+ retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&errcode,
+ &len);
+ if (retval == -1 || errcode != 0)
+ {
+ // socket did not connect
+ //kdDebug(170) << "Socket " << sockfd << " did not connect: "
+ // << strerror(errcode) << endl;
+ ::close(sockfd);
+ sockfd = -1;
+
+ // this is HIGHLY UNLIKELY
+ if (d->timeout.tv_sec == 0 && d->timeout.tv_usec == 0)
+ {
+ d->status = lookupDone;
+ setError(IO_TimeOutError, 0);
+ return -3; // time out
+ }
+
+ setError(IO_ConnectError, errcode);
+ continue;
+ }
+ }
+
+ // getting here means it connected
+ // setBufferSize() takes care of creating the socket notifiers
+ setBlockingMode(true);
+ d->status = connected;
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+ setBufferSize(d->flags & inputBufferedSocket ? -1 : 0,
+ d->flags & outputBufferedSocket ? -1 : 0);
+ emit connectionSuccess();
+// kdDebug(170) << "Socket " << sockfd << " connected\n";
+ return 0;
+ }
+ else
+ {
+ // without timeouts
+ if (KSocks::self()->connect(sockfd, (*it).address(), (*it).length()) == -1)
+ {
+ //kdDebug(170) << "Socket " << sockfd << " to " << (*it).address().toString()
+ // << " did not connect: " << perror << endl;
+ setError(IO_ConnectError, errno);
+ ::close(sockfd);
+ sockfd = -1;
+ continue;
+ }
+
+ d->status = connected;
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+ setBufferSize(d->flags & inputBufferedSocket ? -1 : 0,
+ d->flags & outputBufferedSocket ? -1 : 0);
+ emit connectionSuccess();
+// kdDebug(170) << "Socket " << sockfd << " connected\n";
+ return 0; // it connected
+ }
+ }
+
+ // getting here means no socket connected or stuff like that
+ emit connectionFailed(d->syserror);
+ //kdDebug(170) << "Failed to connect\n";
+ return ret;
+}
+
+int KExtendedSocket::startAsyncConnect()
+{
+ cleanError();
+ // check status
+ if (d->status >= connected || d->flags & passiveSocket)
+ return -2;
+
+ if (d->status == connecting)
+ // already on async connect
+ return 0;
+
+ // check if we have to do lookup
+ // if we do, then we'll use asynchronous lookup and use
+ // signal lookupFinished to do connection
+ if (d->status < lookupDone)
+ {
+ QObject::connect(this, SIGNAL(lookupFinished(int)), this, SLOT(startAsyncConnectSlot()));
+ if (d->status < lookupInProgress)
+ return startAsyncLookup();
+ else
+ return 0; // we still have to wait
+ }
+
+ // here we have d->status >= lookupDone and <= connecting
+ // we can do our connection
+ d->status = connecting;
+ QGuardedPtr<QObject> p = this;
+ connectionEvent();
+ if (!p)
+ return -1; // We have been deleted.
+ if (d->status < connecting)
+ return -1;
+ return 0;
+}
+
+void KExtendedSocket::cancelAsyncConnect()
+{
+ if (d->status != connecting)
+ return;
+
+ if (sockfd != -1)
+ {
+ // we have a waiting connection
+ if (d->qsnIn)
+ delete d->qsnIn;
+ if (d->qsnOut)
+ delete d->qsnOut;
+ d->qsnIn = d->qsnOut = NULL;
+
+ ::close(sockfd);
+ sockfd = -1;
+ }
+ d->status = lookupDone;
+}
+
+bool KExtendedSocket::open(int mode)
+{
+ if (mode != IO_Raw | IO_ReadWrite)
+ return false; // invalid open mode
+
+ if (d->flags & passiveSocket)
+ return listen() == 0;
+ else if (d->status < connecting)
+ return connect() == 0;
+ else
+ return false;
+}
+
+void KExtendedSocket::close()
+{
+ if (sockfd == -1 || d->status >= closing)
+ return; // nothing to close
+
+ // LOCK BUFFER MUTEX
+ if (d->flags & outputBufferedSocket && writeBufferSize() > 0)
+ {
+ // write buffer not empty, go into closing state
+ d->status = closing;
+ if (d->qsnIn)
+ delete d->qsnIn;
+ d->qsnIn = NULL;
+ // we keep the outgoing socket notifier because we want
+ // to send data, but not receive
+ }
+ else
+ {
+ // nope, write buffer is empty
+ // we can close now
+ if (d->qsnIn)
+ delete d->qsnIn;
+ if (d->qsnOut)
+ delete d->qsnOut;
+ d->qsnIn = d->qsnOut = NULL;
+
+ ::close(sockfd);
+ d->status = done;
+ emit closed(readBufferSize() != 0 ? availRead : 0);
+ }
+ // UNLOCK BUFFER MUTEX
+}
+
+
+void KExtendedSocket::closeNow()
+{
+ if (d->status >= done)
+ return; // nothing to close
+
+ // close the socket
+ delete d->qsnIn;
+ delete d->qsnOut;
+ d->qsnIn = d->qsnOut = NULL;
+
+ if (d->status > connecting && sockfd != -1)
+ {
+ ::close(sockfd);
+ sockfd = -1;
+ }
+ else if (d->status == connecting)
+ cancelAsyncConnect();
+ else if (d->status == lookupInProgress)
+ cancelAsyncLookup();
+
+ d->status = done;
+
+ emit closed(closedNow |
+ (readBufferSize() != 0 ? availRead : 0) |
+ (writeBufferSize() != 0 ? dirtyWrite : 0));
+}
+
+void KExtendedSocket::release()
+{
+ // release our hold on the socket
+ sockfd = -1;
+ d->status = done;
+
+ d->resRemote.cancel(false);
+ d->resLocal.cancel(false);
+
+ if (d->local != NULL)
+ delete d->local;
+ if (d->peer != NULL)
+ delete d->peer;
+
+ d->peer = d->local = NULL;
+
+ if (d->qsnIn != NULL)
+ delete d->qsnIn;
+ if (d->qsnOut != NULL)
+ delete d->qsnOut;
+
+ d->qsnIn = d->qsnOut = NULL;
+
+ // now that the socket notificators are done with, we can flush out the buffers
+ consumeReadBuffer(readBufferSize(), NULL, true);
+ consumeWriteBuffer(writeBufferSize());
+
+ // don't delete d
+ // leave that for the destructor
+}
+
+void KExtendedSocket::flush()
+{
+ cleanError();
+ if (d->status < connected || d->status >= done || d->flags & passiveSocket)
+ return;
+
+ if (sockfd == -1)
+ return;
+
+ if ((d->flags & outputBufferedSocket) == 0)
+ return; // nothing to do
+
+ // LOCK MUTEX
+
+ unsigned written = 0;
+ unsigned offset = outBufIndex; // this happens only for the first
+ while (writeBufferSize() - written > 0)
+ {
+ // we have to write each output buffer in outBuf
+ // but since we can have several very small buffers, we can make things
+ // better by concatenating a few of them into a big buffer
+ // question is: how big should that buffer be? 16 kB should be enough
+
+ QByteArray buf(16384);
+ QByteArray *a = outBuf.first();
+ unsigned count = 0;
+
+ while (a && count + (a->size() - offset) <= buf.size())
+ {
+ memcpy(buf.data() + count, a->data() + offset, a->size() - offset);
+ count += a->size() - offset;
+ offset = 0;
+ a = outBuf.next();
+ }
+
+ // see if we can still fit more
+ if (a && count < buf.size())
+ {
+ // getting here means this buffer (a) is larger than
+ // (buf.size() - count) (even for count == 0).
+ memcpy(buf.data() + count, a->data() + offset, buf.size() - count);
+ offset += buf.size() - count;
+ count = buf.size();
+ }
+
+ // now try to write those bytes
+ int wrote = KSocks::self()->write(sockfd, buf, count);
+
+ if (wrote == -1)
+ {
+ // could be EAGAIN (EWOULDBLOCK)
+ setError(IO_WriteError, errno);
+ break;
+ }
+ written += wrote;
+
+ if ((unsigned)wrote != count)
+ break;
+ }
+ if (written)
+ {
+ consumeWriteBuffer(written);
+ emit bytesWritten(written);
+ }
+
+ // UNLOCK MUTEX
+}
+
+
+Q_LONG KExtendedSocket::readBlock(char *data, Q_ULONG maxlen)
+{
+ cleanError();
+ if (d->status < connected || d->flags & passiveSocket)
+ return -2;
+
+ int retval;
+
+ if ((d->flags & inputBufferedSocket) == 0)
+ {
+ // we aren't buffering this socket, so just pass along
+ // the call to the real read method
+
+ if (sockfd == -1)
+ return -2;
+ if (data)
+ retval = KSocks::self()->read(sockfd, data, maxlen);
+ else
+ retval = skipData(sockfd, maxlen);
+ if (retval == -1)
+ setError(IO_ReadError, errno);
+ }
+ else
+ {
+ // this socket is being buffered. So read from the buffer
+
+ // LOCK BUFFER MUTEX
+
+ retval = consumeReadBuffer(maxlen, data);
+ if (retval == 0)
+ {
+ // consumeReadBuffer returns 0 only if the buffer is
+ // empty
+ if (sockfd == -1)
+ return 0; // buffer is clear now, indicate EOF
+ setError(IO_ReadError, EWOULDBLOCK);
+ retval = -1;
+ }
+
+ // UNLOCK BUFFER MUTEX
+
+ }
+ return retval;
+}
+
+Q_LONG KExtendedSocket::writeBlock(const char *data, Q_ULONG len)
+{
+ cleanError();
+ if (d->status < connected || d->status >= closing || d->flags & passiveSocket)
+ return -2;
+ if (sockfd == -1)
+ return -2;
+
+ if (len == 0)
+ return 0; // what's to write?
+
+ int retval;
+
+ if ((d->flags & outputBufferedSocket) == 0)
+ {
+ // socket not buffered. Just call write
+ retval = KSocks::self()->write(sockfd, data, len);
+ if (retval == -1)
+ setError(IO_WriteError, errno);
+ else
+ emit bytesWritten(retval);
+ }
+ else
+ {
+ // socket is buffered. Feed the write buffer
+
+ // LOCK BUFFER MUTEX
+
+ register unsigned wsize = writeBufferSize();
+ if (d->outMaxSize == (int)wsize) // (int) to get rid of annoying warning
+ {
+ // buffer is full!
+ setError(IO_WriteError, EWOULDBLOCK);
+ retval = -1;
+ }
+ else
+ {
+ if (d->outMaxSize != -1 && wsize + len > (unsigned)d->outMaxSize)
+ // we cannot write all data. Write just as much as to fill the buffer
+ len = d->outMaxSize - wsize;
+
+ // len > 0 here
+ retval = feedWriteBuffer(len, data);
+ if (wsize == 0 || d->emitWrite)
+ // buffer was empty, which means that the notifier is probably disabled
+ d->qsnOut->setEnabled(true);
+ }
+
+ // UNLOCK BUFFER MUTEX
+ }
+
+ return retval;
+}
+
+int KExtendedSocket::peekBlock(char *data, uint maxlen)
+{
+ if (d->status < connected || d->flags & passiveSocket)
+ return -2;
+ if (sockfd == -1)
+ return -2;
+
+ // need to LOCK MUTEX around this call...
+
+ if (d->flags & inputBufferedSocket)
+ return consumeReadBuffer(maxlen, data, false);
+
+ return 0;
+}
+
+int KExtendedSocket::unreadBlock(const char *, uint)
+{
+ // Always return -1, indicating this is not supported
+ setError(IO_ReadError, ENOSYS);
+ return -1;
+}
+
+int KExtendedSocket::bytesAvailable() const
+{
+ if (d->status < connected || d->flags & passiveSocket)
+ return -2;
+
+ // as of now, we don't do any extra processing
+ // we only work in input-buffered sockets
+ if (d->flags & inputBufferedSocket)
+ return KBufferedIO::bytesAvailable();
+
+ return 0; // TODO: FIONREAD ioctl
+}
+
+int KExtendedSocket::waitForMore(int msecs)
+{
+ cleanError();
+ if (d->flags & passiveSocket || d->status < connected || d->status >= closing)
+ return -2;
+ if (sockfd == -1)
+ return -2;
+
+ fd_set rd;
+ FD_ZERO(&rd);
+ FD_SET(sockfd, &rd);
+ timeval tv;
+ tv.tv_sec = msecs / 1000;
+ tv.tv_usec = (msecs % 1000) * 1000;
+
+ int retval = KSocks::self()->select(sockfd + 1, &rd, NULL, NULL, &tv);
+ if (retval == -1)
+ {
+ setError(IO_FatalError, errno);
+ return -1;
+ }
+ else if (retval != 0)
+ socketActivityRead(); // do read processing
+
+ return bytesAvailable();
+}
+
+int KExtendedSocket::getch()
+{
+ unsigned char c;
+ int retval;
+ retval = readBlock((char*)&c, sizeof(c));
+
+ if (retval < 0)
+ return retval;
+ return c;
+}
+
+int KExtendedSocket::putch(int ch)
+{
+ unsigned char c = (char)ch;
+ return writeBlock((char*)&c, sizeof(c));
+}
+
+// sets the emission of the readyRead signal
+void KExtendedSocket::enableRead(bool enable)
+{
+ // check if we can disable the socket notifier
+ // saves us a few cycles
+ // this is so because in buffering mode, we rely on these signals
+ // being emitted to do our I/O. We couldn't disable them here
+ if (!enable && (d->flags & inputBufferedSocket) == 0 && d->qsnIn)
+ d->qsnIn->setEnabled(false);
+ else if (enable && d->qsnIn)
+ // we can enable it always
+ d->qsnIn->setEnabled(true);
+ d->emitRead = enable;
+}
+
+// sets the emission of the readyWrite signal
+void KExtendedSocket::enableWrite(bool enable)
+{
+ // same thing as above
+ if (!enable && (d->flags & outputBufferedSocket) == 0 && d->qsnOut)
+ d->qsnOut->setEnabled(false);
+ else if (enable && d->qsnOut)
+ // we can enable it always
+ d->qsnOut->setEnabled(true);
+ d->emitWrite = enable;
+}
+
+// protected slot
+// this is connected to d->qsnIn::activated(int)
+void KExtendedSocket::socketActivityRead()
+{
+ if (d->flags & passiveSocket)
+ {
+ emit readyAccept();
+ return;
+ }
+ if (d->status == connecting)
+ {
+ connectionEvent();
+ return;
+ }
+ if (d->status != connected)
+ return;
+
+ // do we need to do I/O here?
+ if (d->flags & inputBufferedSocket)
+ {
+ // aye. Do read from the socket and feed our buffer
+ QByteArray a;
+ char buf[1024];
+ int len, totalread = 0;
+
+ // LOCK MUTEX
+
+ unsigned cursize = readBufferSize();
+
+ if (d->inMaxSize == -1 || cursize < (unsigned)d->inMaxSize)
+ {
+ do
+ {
+ // check that we can read that many bytes
+ if (d->inMaxSize != -1 && d->inMaxSize - (cursize + totalread) < sizeof(buf))
+ // no, that would overrun the buffer
+ // note that this will also make us exit the loop
+ len = d->inMaxSize - (cursize + totalread);
+ else
+ len = sizeof(buf);
+
+ len = KSocks::self()->read(sockfd, buf, len);
+ if (len > 0)
+ {
+ // normal read operation
+ a.resize(a.size() + len);
+ memcpy(a.data() + totalread, buf, len);
+ totalread += len; // totalread == a.size() now
+ }
+ else if (len == 0)
+ {
+ // EOF condition here
+ ::close(sockfd);
+ sockfd = -1; // we're closed
+ d->qsnIn->deleteLater();
+ delete d->qsnOut;
+ d->qsnIn = d->qsnOut = NULL;
+ d->status = done;
+ emit closed(involuntary |
+ (readBufferSize() ? availRead : 0) |
+ (writeBufferSize() ? dirtyWrite : 0));
+ return;
+ }
+ else
+ {
+ // error!
+ setError(IO_ReadError, errno);
+ return;
+ }
+ // will loop only for normal read operations
+ }
+ while (len == sizeof(buf));
+
+ feedReadBuffer(a.size(), a.data());
+ }
+
+ // UNLOCK MUTEX
+ }
+ else
+ {
+ // No input buffering, but the notifier fired
+ // That means that either there is data to be read or that the
+ // socket closed.
+
+ // try to read one byte. If we can't, then the socket got closed
+
+ char c;
+ int len = KSocks::self()->recv(sockfd, &c, sizeof(c), MSG_PEEK);
+ if (len == 0)
+ {
+ // yes, it's an EOF condition
+ d->qsnIn->setEnabled(false);
+ ::close(sockfd);
+ sockfd = -1;
+ d->status = done;
+ emit closed(involuntary);
+ return;
+ }
+ }
+
+ if (d->emitRead)
+ emit readyRead();
+}
+
+void KExtendedSocket::socketActivityWrite()
+{
+ if (d->flags & passiveSocket)
+ return;
+ if (d->status == connecting)
+ {
+ connectionEvent();
+ return;
+ }
+ if (d->status != connected && d->status != closing)
+ return;
+
+ flush();
+
+ bool empty = writeBufferSize() == 0;
+
+ if (d->emitWrite && empty)
+ emit readyWrite();
+ else if (!d->emitWrite)
+ {
+ // check if we can disable the notifier
+ d->qsnOut->setEnabled(!empty); // leave it enabled only if we have more data to send
+ }
+ if (d->status == closing && empty)
+ {
+ // done sending the missing data!
+ d->status = done;
+
+ delete d->qsnOut;
+ ::close(sockfd);
+
+ d->qsnOut = NULL;
+ sockfd = -1;
+ emit closed(delayed | (readBufferSize() ? availRead : 0));
+ }
+}
+
+// this function is called whenever we have a "connection event"
+// that is, whenever our asynchronously connecting socket throws
+// an event
+void KExtendedSocket::connectionEvent()
+{
+ if (d->status != connecting)
+ return; // move along. There's nothing to see here
+
+ KResolverResults remote = d->resRemote.results();
+ if (remote.count() == 0)
+ {
+ // We have a problem! Abort?
+ kdError(170) << "KExtendedSocket::connectionEvent() called but no data available!\n";
+ return;
+ }
+
+ int errcode = 0;
+
+ if (sockfd != -1)
+ {
+ // our socket has activity
+ // find out what it was
+ int retval;
+ socklen_t len = sizeof(errcode);
+ retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len);
+
+ if (retval == -1 || errcode != 0)
+ {
+ // socket activity and there was error?
+ // that means the socket probably did not connect
+ if (d->qsnIn)
+ delete d->qsnIn;
+ if (d->qsnOut)
+ delete d->qsnOut;
+ ::close(sockfd);
+
+ sockfd = -1;
+ d->qsnIn = d->qsnOut = NULL;
+ d->current++;
+ setError(IO_ConnectError, errcode);
+ }
+ else
+ {
+ // hmm, socket activity and there was no error?
+ // that means it connected
+ // YAY!
+ cleanError();
+ d->status = connected;
+ setBlockingMode(true);
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+ setBufferSize(d->flags & inputBufferedSocket ? -1 : 0,
+ d->flags & outputBufferedSocket ? -1 : 0);
+ emit connectionSuccess();
+ return;
+ }
+ }
+
+ // ok, we have to try something here
+ // and sockfd == -1
+ KResolverResults local = d->resLocal.results();
+ unsigned localidx = 0;
+ for ( ; d->current < remote.count(); d->current++)
+ {
+ // same code as in connect()
+ if (local.count() != 0)
+ {
+ // scan bindres for a local resuls family
+ for (localidx = 0; localidx < local.count(); localidx++)
+ if (remote[d->current].family() == local[localidx].family())
+ break;
+
+ if (remote[d->current].family() != local[localidx].family())
+ {
+ // no matching families for this
+ continue;
+ }
+
+ errno = 0;
+ sockfd = ::socket(remote[d->current].family(), remote[d->current].socketType(),
+ remote[d->current].protocol());
+ setError(IO_ConnectError, errno);
+ errcode = errno;
+ if (sockfd == -1)
+ continue; // cannot create this socket
+ fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+ if (d->addressReusable)
+ setAddressReusable(sockfd, true);
+ setIPv6Only(d->ipv6only);
+ cleanError();
+ if (KSocks::self()->bind(sockfd, local[localidx].address(),
+ local[localidx].length()) == -1)
+ {
+ ::close(sockfd);
+ sockfd = -1;
+ continue;
+ }
+ }
+ else
+ {
+ // no need to bind, just create
+ sockfd = ::socket(remote[d->current].family(), remote[d->current].socketType(),
+ remote[d->current].protocol());
+ if (sockfd == -1)
+ {
+ setError(IO_ConnectError, errno);
+ errcode = errno;
+ continue;
+ }
+ fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+ if (d->addressReusable)
+ setAddressReusable(sockfd, true);
+ setIPv6Only(d->ipv6only);
+ cleanError();
+ }
+
+ if (KSocks::self()->hasWorkingAsyncConnect())
+ setBlockingMode(false);
+ if (KSocks::self()->connect(sockfd, remote[d->current].address(),
+ remote[d->current].length()) == -1)
+ {
+ if (errno != EWOULDBLOCK && errno != EINPROGRESS)
+ {
+ setError(IO_ConnectError, errno);
+ ::close(sockfd);
+ sockfd = -1;
+ errcode = errno;
+ continue;
+ }
+
+ // error here is either EWOULDBLOCK or EINPROGRESS
+ // so, it is a good condition
+ d->qsnIn = new QSocketNotifier(sockfd, QSocketNotifier::Read);
+ QObject::connect(d->qsnIn, SIGNAL(activated(int)), this, SLOT(socketActivityRead()));
+ d->qsnOut = new QSocketNotifier(sockfd, QSocketNotifier::Write);
+ QObject::connect(d->qsnOut, SIGNAL(activated(int)), this, SLOT(socketActivityWrite()));
+
+ // ok, let the Qt event loop do the selecting for us
+ return;
+ }
+
+ // eh, what?
+ // the non-blocking socket returned valid connection?
+ // already?
+ // I suppose that could happen...
+ cleanError();
+ d->status = connected;
+ setBlockingMode(true);
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+ setBufferSize(d->flags & inputBufferedSocket ? -1 : 0,
+ d->flags & outputBufferedSocket ? -1 : 0);
+ emit connectionSuccess();
+ return;
+ }
+
+ // if we got here, it means that there are no more options to connect
+ d->status = lookupDone; // go back
+ emit connectionFailed(errcode);
+}
+
+void KExtendedSocket::dnsResultsReady()
+{
+ // check that this function was called in a valid state
+ if (d->status != lookupInProgress)
+ return;
+
+ // valid state. Are results fully ready?
+ if (d->resRemote.isRunning() || d->resLocal.isRunning())
+ // no, still waiting for answer in one of the lookups
+ return;
+
+ // ok, we have all results
+ // count how many results we have
+ int n = d->resRemote.results().count() + d->resLocal.results().count();
+
+ if (n)
+ {
+ d->status = lookupDone;
+ cleanError();
+ }
+ else
+ {
+ d->status = nothing;
+ setError(IO_LookupError, KResolver::NoName);
+ }
+
+ emit lookupFinished(n);
+
+ return;
+}
+
+void KExtendedSocket::startAsyncConnectSlot()
+{
+ QObject::disconnect(this, SIGNAL(lookupFinished(int)), this, SLOT(startAsyncConnectSlot()));
+
+ if (d->status == lookupDone)
+ startAsyncConnect();
+}
+
+int KExtendedSocket::resolve(sockaddr *sock, ksocklen_t len, QString &host,
+ QString &port, int flags)
+{
+ kdDebug(170) << "Deprecated function called:" << k_funcinfo << endl;
+
+ int err;
+ char h[NI_MAXHOST], s[NI_MAXSERV];
+
+ h[0] = s[0] = '\0';
+
+ err = getnameinfo(sock, len, h, sizeof(h) - 1, s, sizeof(s) - 1, flags);
+ host = QString::fromUtf8(h);
+ port = QString::fromUtf8(s);
+
+ return err;
+}
+
+int KExtendedSocket::resolve(::KSocketAddress *sock, QString &host, QString &port,
+ int flags)
+{
+ return resolve(sock->data, sock->datasize, host, port, flags);
+}
+
+QPtrList<KAddressInfo> KExtendedSocket::lookup(const QString& host, const QString& port,
+ int userflags, int *error)
+{
+ kdDebug(170) << "Deprecated function called:" << k_funcinfo << endl;
+
+ int socktype, familyMask, flags;
+ unsigned i;
+ QPtrList<KAddressInfo> l;
+
+ /* check socket type flags */
+ if (!process_flags(userflags, socktype, familyMask, flags))
+ return l;
+
+// kdDebug(170) << "Performing lookup on " << host << "|" << port << endl;
+ KResolverResults res = KResolver::resolve(host, port, flags, familyMask);
+ if (res.error())
+ {
+ if (error)
+ *error = res.error();
+ return l;
+ }
+
+ for (i = 0; i < res.count(); i++)
+ {
+ KAddressInfo *ai = new KAddressInfo();
+
+ // I should have known that using addrinfo was going to come
+ // and bite me back some day...
+ ai->ai = (addrinfo *) malloc(sizeof(addrinfo));
+ memset(ai->ai, 0, sizeof(addrinfo));
+
+ ai->ai->ai_family = res[i].family();
+ ai->ai->ai_socktype = res[i].socketType();
+ ai->ai->ai_protocol = res[i].protocol();
+ QString canon = res[i].canonicalName();
+ if (!canon.isEmpty())
+ {
+ ai->ai->ai_canonname = (char *) malloc(canon.length()+1);
+ strcpy(ai->ai->ai_canonname, canon.ascii()); // ASCII here is intentional
+ }
+ if ((ai->ai->ai_addrlen = res[i].length()))
+ {
+ ai->ai->ai_addr = (struct sockaddr *) malloc(res[i].length());
+ memcpy(ai->ai->ai_addr, res[i].address().address(), res[i].length());
+ }
+ else
+ {
+ ai->ai->ai_addr = 0;
+ }
+
+ ai->addr = ::KSocketAddress::newAddress(ai->ai->ai_addr, ai->ai->ai_addrlen);
+
+ l.append(ai);
+ }
+
+ if ( error )
+ *error = 0; // all is fine!
+
+ return l;
+}
+
+::KSocketAddress *KExtendedSocket::localAddress(int fd)
+{
+ ::KSocketAddress *local;
+ struct sockaddr static_sa, *sa = &static_sa;
+ ksocklen_t len = sizeof(static_sa);
+
+ /* find out the socket length, in advance
+ * we use a sockaddr allocated on the heap just not to pass down
+ * a NULL pointer to the first call. Some systems are reported to
+ * set len to 0 if we pass NULL as the sockaddr */
+ if (KSocks::self()->getsockname(fd, sa, &len) == -1)
+ return NULL; // error!
+
+ /* was it enough? */
+ if (len > sizeof(static_sa)
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ || sa->sa_len > sizeof(static_sa)
+#endif
+ )
+ {
+ /* nope, malloc a new socket with the proper size */
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ if (sa->sa_len != len)
+ len = sa->sa_len;
+#endif
+
+ sa = (sockaddr*)malloc(len);
+ if (sa == NULL)
+ return NULL; // out of memory
+
+ if (KSocks::self()->getsockname(fd, sa, &len) == -1)
+ {
+ free(sa);
+ return NULL;
+ }
+
+ local = ::KSocketAddress::newAddress(sa, len);
+ free(sa);
+ }
+ else
+ local = ::KSocketAddress::newAddress(sa, len);
+
+ return local;
+}
+
+/* This is exactly the same code as localAddress, except
+ * we call getpeername here */
+::KSocketAddress *KExtendedSocket::peerAddress(int fd)
+{
+ ::KSocketAddress *peer;
+ struct sockaddr static_sa, *sa = &static_sa;
+ ksocklen_t len = sizeof(static_sa);
+
+ /* find out the socket length, in advance
+ * we use a sockaddr allocated on the heap just not to pass down
+ * a NULL pointer to the first call. Some systems are reported to
+ * set len to 0 if we pass NULL as the sockaddr */
+ if (KSocks::self()->getpeername(fd, sa, &len) == -1)
+ return NULL; // error!
+
+ /* was it enough? */
+ if (len > sizeof(static_sa)
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ || sa->sa_len > sizeof(static_sa)
+#endif
+ )
+ {
+ /* nope, malloc a new socket with the proper size */
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ if (sa->sa_len != len)
+ len = sa->sa_len;
+#endif
+
+ sa = (sockaddr*)malloc(len);
+ if (sa == NULL)
+ return NULL; // out of memory
+
+ if (KSocks::self()->getpeername(fd, sa, &len) == -1)
+ {
+ free(sa);
+ return NULL;
+ }
+
+ peer = ::KSocketAddress::newAddress(sa, len);
+ free(sa);
+ }
+ else
+ peer = ::KSocketAddress::newAddress(sa, len);
+
+ return peer;
+}
+
+QString KExtendedSocket::strError(int code, int syserr)
+{
+ const char * msg;
+ if (code == IO_LookupError)
+ msg = gai_strerror(syserr);
+ else
+ msg = strerror(syserr);
+
+ return QString::fromLocal8Bit(msg);
+}
+
+
+QSocketNotifier *KExtendedSocket::readNotifier() { return d->qsnIn; }
+QSocketNotifier *KExtendedSocket::writeNotifier() { return d->qsnOut; }
+
+/*
+ * class KAddressInfo
+ */
+
+#if 0
+KAddressInfo::KAddressInfo(addrinfo *p)
+{
+ ai = (addrinfo *) malloc(sizeof(addrinfo));
+ memcpy(ai, p, sizeof(addrinfo));
+ ai->ai_next = NULL;
+ if (p->ai_canonname)
+ {
+ ai->ai_canonname = (char *) malloc(strlen(p->ai_canonname)+1);
+ strcpy(ai->ai_canonname, p->ai_canonname);
+ }
+ if (p->ai_addr && p->ai_addrlen)
+ {
+ ai->ai_addr = (struct sockaddr *) malloc(p->ai_addrlen);
+ memcpy(ai->ai_addr, p->ai_addr, p->ai_addrlen);
+ }
+ else
+ {
+ ai->ai_addr = 0;
+ ai->ai_addrlen = 0;
+ }
+
+ addr = ::KSocketAddress::newAddress(ai->ai_addr, ai->ai_addrlen);
+}
+#endif
+KAddressInfo::~KAddressInfo()
+{
+ if (ai && ai->ai_canonname)
+ free(ai->ai_canonname);
+
+ if (ai && ai->ai_addr)
+ free(ai->ai_addr);
+
+ if (ai)
+ free(ai);
+ delete addr;
+}
+
+int KAddressInfo::flags() const
+{
+ return ai->ai_flags;
+}
+
+int KAddressInfo::family() const
+{
+ return ai->ai_family;
+}
+
+int KAddressInfo::socktype() const
+{
+ return ai->ai_socktype;
+}
+
+int KAddressInfo::protocol() const
+{
+ return ai->ai_protocol;
+}
+
+const char* KAddressInfo::canonname() const
+{
+ return ai->ai_canonname;
+}
+
+void KExtendedSocket::virtual_hook( int id, void* data )
+{ KBufferedIO::virtual_hook( id, data ); }
+
+#include "kextsock.moc"
diff --git a/kdecore/kextsock.h b/kdecore/kextsock.h
new file mode 100644
index 000000000..f3d1f5923
--- /dev/null
+++ b/kdecore/kextsock.h
@@ -0,0 +1,1110 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KEXTSOCK_H
+#define KEXTSOCK_H
+
+#include "kdelibs_export.h"
+
+#ifdef Q_OS_UNIX
+
+#include <sys/time.h>
+
+#include <qstring.h>
+#include <qptrlist.h>
+#include <qiodevice.h>
+
+#include "kbufferedio.h"
+#include "ksockaddr.h"
+
+/* External reference to netdb.h */
+struct addrinfo;
+struct kde_addrinfo;
+class KAddressInfo; /* our abstraction of it */
+class QSocketNotifier;
+
+/*
+ * This is extending QIODevice's error codes
+ *
+ * According to qiodevice.h, the last error is IO_UnspecifiedError
+ * These errors will never occur in functions declared in QIODevice
+ * (except open, but you shouldn't call open)
+ */
+#define IO_ListenError (IO_UnspecifiedError+1)
+#define IO_AcceptError (IO_UnspecifiedError+2)
+#define IO_LookupError (IO_UnspecifiedError+3)
+
+class KExtendedSocketPrivate;
+/**
+ * The extended socket class.
+ *
+ * This class should be used instead of KSocket whenever the user needs
+ * fine-grained control over the socket being created. Unlike KSocket, which
+ * does everything at once, without much intervention, KExtendedSocket allows
+ * intervention at every step of the process and the setting of parameters.
+ *
+ * This class allows for the creation of both server and client sockets. The
+ * only difference is that the passiveSocket flag must be passed either to
+ * the constructor or to setSocketFlags(). If passiveSocket is used, the class will
+ * enable functions listen() and accept() and related signals, and will
+ * also disable readBlock() and writeBlock().
+ *
+ * To create a Unix socket, one would pass flag unixSocket to the constructor
+ * or setSocketFlags(). The hostname and service/port can be set to whatever is
+ * necessary. If no hostname is given, but a service/port is, the socket created
+ * will be implementation dependant (usually in /tmp). In any other case, the
+ * fields will be concatenated.
+ *
+ * To create an Internet socket, inetSocket flag can be used. If, on the other
+ * hand a specific IP protocol is desired, ipv4Socket and/or ipv6Socket can be
+ * used.
+ *
+ * Note that the socket type selection flags are cumulative. One could select
+ * Unix and Internet sockets by using unixSocket | inetSocket. Or, for instance,
+ * to make sure only IPv4 and IPv6 sockets are selected, even if future implementations
+ * support newer IP protocols, ipv4Socket | ipv6Socket is your guy.
+ *
+ * @deprecated
+ * This class is now deprecated. Please use the classes in KNetwork for
+ * new programs. In particular, this class is replaced by KNetwork::KStreamSocket
+ * and @ref KNetwork::KServerSocket.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ * @short an extended socket
+ */
+class KDECORE_EXPORT KExtendedSocket: public KBufferedIO // public QObject, public QIODevice
+{
+ Q_OBJECT
+
+public:
+ /**
+ * flags that can be passed down to the member functions
+ */
+ enum Flags
+ {
+ /* socket address families */
+ /*
+ * NOTE: if you change this, you have to change function valid_socket() as well
+ * These values are hard coded!
+ */
+ anySocket = 0x00,
+ knownSocket = 0x01,
+ unixSocket = knownSocket | 0x02,
+ inetSocket = knownSocket | 0x04,
+ ipv4Socket = inetSocket | 0x100,
+ ipv6Socket = inetSocket | 0x200,
+
+ passiveSocket = 0x1000, /* passive socket (i.e., one that accepts connections) */
+ canonName = 0x2000, /* request that the canon name be found */
+ noResolve = 0x4000, /* do not attempt to resolve, treat as numeric host */
+
+ streamSocket = 0x8000, /* request a streaming socket (e.g., TCP) */
+ datagramSocket = 0x10000, /* request a datagram socket (e.g., UDP) */
+ rawSocket = 0x20000, /* request a raw socket. This probably requires privileges */
+
+ inputBufferedSocket = 0x200000, /* buffer input in this socket */
+ outputBufferedSocket = 0x400000, /* buffer output in this socket */
+ bufferedSocket = 0x600000 /* make this a fully buffered socket */
+ };
+
+ /**
+ * status of the class
+ * The status are sequential. If a change to one status is requested,
+ * all the prior status will be passed and their actions, performed
+ */
+ enum SockStatus
+ {
+ // the numbers are scattered so that we leave room for future expansion
+ error = -1, // invalid status!
+
+ nothing = 0, // no status, the class has just been created
+
+ lookupInProgress = 50, // lookup is in progress. Signals will be sent
+ lookupDone = 70, // lookup has been done. Flags cannot be changed
+ // from this point on
+
+ created = 100, // ::socket() has been called, a socket exists
+ bound = 140, // socket has been bound
+
+ connecting = 200, // socket is connecting (not passiveSocket)
+ connected = 220, // socket has connected (not passiveSocket)
+
+ listening = 200, // socket is listening (passiveSocket)
+ accepting = 220, // socket is accepting (passiveSocket)
+
+ closing = 350, // socket is closing (delayed close)
+
+ done = 400 // socket has been closed
+ };
+
+public:
+ /**
+ * Creates an empty KExtendedSocket.
+ */
+ KExtendedSocket();
+
+ /**
+ * Creates a socket with the given hostname and port.
+ *
+ * If this is a connecting (active) socket, the hostname and port specify
+ * the remote address to which we will connect.
+ *
+ * If this is a listening (passive) socket, the hostname and port specify
+ * the address to listen on. In order to listen on every interface
+ * available on this node, set @p host to QString::null. To let the operating
+ * system select a port, set it to 0.
+ *
+ * @sa setAddress
+ * @param host the hostname
+ * @param port the port number
+ * @param flags flags
+ */
+ KExtendedSocket(const QString& host, int port, int flags = 0);
+
+ /**
+ * Creates a socket with the given hostname and service.
+ *
+ * If this is a connecting (active) socket, the hostname and service specify
+ * the remote address to which we will connect.
+ *
+ * If this is a listening (passive) socket, the hostname and service specify
+ * the address to listen on. In order to listen on every interface
+ * available on this node, set @p host to QString::null. To let the operating
+ * system select a port, set the service to "0".
+ *
+ * @sa setAddress
+ * @param host the hostname
+ * @param service the service
+ * @param flags flags
+ */
+ KExtendedSocket(const QString& host, const QString& service, int flags = 0);
+
+ /**
+ * Destroys the socket, disconnecting if still connected and
+ * freeing any related resources still being kept.
+ */
+ virtual ~KExtendedSocket();
+
+ /**
+ * Resets the socket, disconnecting if still connected and
+ * freeing any related resources still being kept.
+ * @since 3.1
+ */
+ void reset();
+
+ /*
+ * --- status, flags and internal variables --- *
+ */
+
+ /**
+ * Returns the class status.
+ * @return the class status
+ * @see ::SockStatus
+ */
+ int socketStatus() const;
+
+ /**
+ * Returns the related system error code
+ * Except for IO_LookupError errors, these are codes found in
+ * errno
+ * @return the system error code
+ */
+ int systemError() const;
+
+ /**
+ * Sets the given flags.
+ * @param flags the flags to be set
+ * @return the new flags status, or -1 if flags can no longer be set
+ */
+ int setSocketFlags(int flags);
+
+ /**
+ * Returns the current flags
+ * @return the current flags
+ * @see ::Flags
+ */
+ int socketFlags() const;
+
+ /**
+ * Sets the hostname to the given value.
+ *
+ * If this is a listening (passive) socket, the hostname is the host to which the socket
+ * will bind in order to listen. If you want to listen in every interface, set it
+ * to "*" or QString::null.
+ *
+ * If this is a connecting (active) socket, the hostname is the host to which we will try
+ * to connect.
+ *
+ * @param host the hostname
+ * @return true on success, false on error
+ */
+ bool setHost(const QString& host);
+
+ /**
+ * Returns the hostname.
+ * @return the hostname or QString::null if no host has been set
+ */
+ QString host() const;
+
+ /**
+ * Sets the port/service.
+ * @param port the port
+ */
+ bool setPort(int port);
+
+ /**
+ * Sets the port/service.
+ *
+ * In the case of Unix-domain sockets, the port is the filename for the socket.
+ * If the name is not an absolute path, "/tmp/" will be prepended.
+ *
+ * @param port the port
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool setPort(const QString& port);
+
+ /**
+ * Returns the port/service. If it is a port, the string contains a number.
+ * @return the port or QString::null if it has not been set.
+ */
+ QString port() const;
+
+ /**
+ * Sets the address where we will connect to.
+ *
+ * See @ref setHost and @ref setPort for information on the parameters.
+ *
+ * @param host the hostname
+ * @param port port number
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool setAddress(const QString& host, int port);
+
+ /**
+ * Sets the address where we will connect to.
+ *
+ * See @ref setHost and @ref setPort for information on the parameters.
+ *
+ * @param host the hostname
+ * @param serv the service
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool setAddress(const QString& host, const QString& serv);
+
+ /**
+ * Sets the hostname to which we will bind locally before connecting.
+ * @param host the hostname
+ * @return false if this is a passiveSocket, otherwise true.
+ */
+ bool setBindHost(const QString& host);
+
+ /**
+ * Unsets the bind hostname. That is, don't request a binding host.
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool unsetBindHost();
+
+ /**
+ * Returns the hostname to which the socket will be/is bound.
+ * @return the host or QString::null if it has not been set.
+ */
+ QString bindHost() const;
+
+ /**
+ * Sets the port/service to which we will bind before connecting
+ * @param port the port number
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool setBindPort(int port);
+
+ /**
+ * Sets the port/service to which we will bind before connecting.
+ * @param service the port number or service name
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool setBindPort(const QString& service);
+
+ /**
+ * Unsets the bind port/service.
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool unsetBindPort();
+
+ /**
+ * Returns the service to which the socket will be/is bound.
+ * @return the host or QString::null if it has not been set.
+ */
+ QString bindPort() const;
+
+ /**
+ * Sets both host and port to which we will bind the socket. Will return
+ * false if this is a passiveSocket.
+ * @param host the hostname
+ * @param port the port number
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool setBindAddress(const QString& host, int port);
+
+ /**
+ * Sets both host and service to which we will bind the socket. Will return
+ * false if this is a passiveSocket.
+ * @param host the hostname
+ * @param service the service
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool setBindAddress(const QString& host, const QString& service);
+
+ /**
+ * Unsets the bind address for the socket. That means that we won't
+ * attempt to bind to an address before connecting.
+ * @return true if successful, false on error (e.g. connection already established)
+ */
+ bool unsetBindAddress();
+
+ /**
+ * Sets the timeout value for the connection (if this is not passiveSocket) or
+ * acception (if it is). In the event the given function
+ * (connect or accept) returns due to time out, it's possible to call it again.
+ *
+ * Setting the timeout to 0 disables the timeout feature.
+ *
+ * @param secs the timeout length, in seconds
+ * @param usecs the timeout complement, in microseconds
+ * @return false if setting timeout makes no sense in the context.
+ */
+ bool setTimeout(int secs, int usecs = 0);
+
+ /**
+ * Returns the timeout value for the connection.
+ * @return the timeout value. 0 if there is no timeout.
+ */
+ timeval timeout() const;
+
+ /**
+ * Sets/unsets blocking mode for the socket. When non-blocking mode is enabled,
+ * I/O operations might return error and set errno to EWOULDBLOCK. Also,
+ * it's not recommended to use this when using the class signals.
+ *
+ * @param enable if true, set blocking mode. False, non-blocking mode.
+ * @return false on error.
+ */
+ bool setBlockingMode(bool enable);
+
+ /**
+ * Returns the current blocking mode for this socket.
+ * @return true if in blocking mode
+ */
+ bool blockingMode();
+
+ /**
+ * Sets/unsets address reusing flag for this socket.
+ *
+ * This function returns true if the value was set correctly. That is NOT
+ * the result of the set.
+ * @param enable if true, set address reusable
+ * @return true on success, false on failure. If the socket was not yet created,
+ * the value is only remembered. In this case the return value is always true.
+ */
+ bool setAddressReusable(bool enable);
+
+ /**
+ * Returns whether this socket's address can be reused
+ * @return true if the address can be reused
+ */
+ bool addressReusable();
+
+ /**
+ * Sets/unsets the v6-only flag for IPv6 sockets.
+ *
+ * When an IPv6 socket is in use, communication with IPv4 sockets is
+ * guaranteed by translating those IPv4 addresses into IPv6 ones
+ * (specifically, the v4-mapped addresses). This flag allows that
+ * behavior to be turned on and off.
+ *
+ * Note that this does not have any effect on sockets that are not
+ * IPv6 and the function will always return false in those cases.
+ * Also note that this flag defaults to off in order to accommodate
+ * existing applications.
+ *
+ * @param enable if true, no IPv4 translation will be performed;
+ * this socket will be restricted to IPv6 communication
+ * @returns true on success, false on failure.
+ * @see localAddress to find out if this is an IPv6 socket
+ */
+ bool setIPv6Only(bool enable);
+
+ /**
+ * Returns the status of the v6-only flag for IPv6 sockets.
+ * @returns true if the flag is set to on; false if it is not. If this
+ * socket is not an IPv6 one, the return value is false.
+ * @see setIPv6Only
+ */
+ bool isIPv6Only();
+
+ /**
+ * Sets the buffer sizes for this socket.
+ *
+ * This implementation allows any size for both parameters. The value given
+ * will be interpreted as the maximum size allowed for the buffers, after
+ * which the I/O functions will stop buffering. The value of -1 will be
+ * interpreted as "unlimited" size. The value of -2 means "no change".
+ *
+ * Note: changing the buffer size to 0 for any buffer will cause the given
+ * buffer's to be discarded. Likewise, setting the size to a value less than
+ * the current size will cause the buffer to be shrunk to the wanted value,
+ * as if the data had been read.
+ * @param rsize read buffer size
+ * @param wsize write buffer size
+ * @return true on success, false if this is not possible in this state (e.g. connection
+ * not established yet)
+ */
+ virtual bool setBufferSize(int rsize, int wsize = -2);
+
+ /**
+ * Returns the local socket address
+ * @return the local socket address, can be 0 if the connection has not been established
+ * yet
+ */
+ const ::KSocketAddress *localAddress();
+
+ /**
+ * Returns the peer socket address. Use KExtendedSocket::resolve() to
+ * resolve this to a human-readable hostname/service or port.
+ * @return the peer address, can be 0 if the connection has not been established yet
+ * or the socket is passive
+ */
+ const ::KSocketAddress *peerAddress();
+
+ /**
+ * Returns the file descriptor
+ * @return the file descriptor. -1 if there is no fd yet.
+ */
+ inline int fd() const
+ { return sockfd; }
+
+ /*
+ * -- socket creation -- *
+ */
+
+ /**
+ * Performs lookup on the addresses we were given before.
+ *
+ * This will perform lookups on the bind addresses if they were given.
+ * @return 0 or an error. Do not rely on the values returned by lookup
+ * as of now. They are not specified.
+ */
+ virtual int lookup();
+
+ /**
+ * Starts an asynchronous lookup for the addresses given.
+ *
+ * When the lookup is done, the lookupReady signal will be emitted.
+ *
+ * Note that, depending on the parameters for the lookup, this function might
+ * know the results without the need for blocking or queuing an
+ * asynchronous lookup. That means that the lookupReady signal might be
+ * emitted by this function, so your code should be prepared for that.
+ *
+ * One such case is when noResolve flag is set.
+ * If this function is able to determine the results without queuing
+ * and the lookup failed, this function will return -1.
+ *
+ * @return 0 on success or -1 on error. Note that
+ * returning 0 means that either we are in the process of doing
+ * lookup or that it has finished already.
+ */
+ virtual int startAsyncLookup();
+
+ /**
+ * Cancels any on-going asynchronous lookups
+ */
+ virtual void cancelAsyncLookup();
+
+ /**
+ * Place the socket in listen mode. The parameters are the same as for
+ * the system listen() call.
+ * @param N the queue length for pending connections
+ * @return 0 on success, -1 on system error (errno
+ * available) and -2 if this is not a passiveSocket.
+ */
+ virtual int listen(int N = 5); // 5 is arbitrary
+
+ /**
+ * Accepts an incoming connection from the socket. If this socket is in
+ * blocking mode, this function will block until a connection is received.
+ * Otherwise, it might return with error. The sock parameter will be
+ * initialised with the newly created socket.
+ *
+ * Upon successful acception (i.e., this function returns 0), the newly
+ * created socket will be already connected. The socket will be unbuffered
+ * and readyRead() and readyWrite() signals will be disabled.
+ *
+ * @param sock a pointer to an KExtendedSocket variable
+ * @return 0 on success, -1 on system error (errno set) and -2 if this is
+ * not a passiveSocket and -3 if this took too long (time out)
+ */
+ virtual int accept(KExtendedSocket *&sock);
+
+ /**
+ * Attempts to connect to the remote host.
+ * After successful connection (return value 0), the socket will be ready
+ * for I/O operations. Note, however, that not all signals may be enabled
+ * for emission by this socket:
+ * @li readyRead and readyWrite signals will be enabled only if
+ * enableRead or enableWrite were called. You can still enable
+ * them by calling those functions, of course.
+ * @li #closed() will only be sent if we are indeed reading from the input
+ * stream. That is, if this socket is buffering the input. See setBufferSize
+ *
+ * Note that, in general, functions inherited/overridden from KBufferedIO will only
+ * work on buffered sockets, like bytesAvailable and bytesToWrite.
+ * @return The return values are:
+ * @li 0: success
+ * @li -1: system error, errno was set accordingly
+ * @li -2: this socket cannot connect(); this is a passiveSocket. It can also
+ * mean that the function was unable to make a connection with the given
+ * bind address or that an asynchronous connection attempt is already
+ * in progress.
+ * @li -3: connection timed out
+ *
+ */
+ virtual int connect();
+
+ /**
+ * Starts an asynchronous connect. This works exactly the same as #connect,
+ * except that the connection result won't be returned.
+ *
+ * Note that those signals might be emitted before this function returns, so your
+ * code should be prepared for that condition.
+ *
+ * You must call cancelAsyncConnect() before you delete the socket if you
+ * call this. Otherwise you will have crashes.
+ *
+ * @return 0 on successful queuing of the connect or -1 on error.
+ * If this function returns 0, then the connectionSuccess() or the
+ * connectionFailed() signals will be emitted.
+ */
+ virtual int startAsyncConnect();
+
+ /**
+ * Cancels any on-going asynchronous connection attempt.
+ */
+ virtual void cancelAsyncConnect();
+
+ /**
+ * Implementation of QIODevice::open() pure virtual function.
+ * This depends on the target host address already being there.
+ * If this is a passiveSocket, this is identical to call listen(); else, if
+ * this is not a passiveSocket and no connection attempt is in progress, this
+ * is like connect(). If one is in progress, this function will fail.
+ * @param mode the open mode. Must be IO_Raw | IO_ReadWrite
+ * @return true if successful, false when an error occurred or the most was
+ * not correct
+ */
+ virtual bool open(int mode = IO_Raw | IO_ReadWrite);
+
+ /**
+ * Closes the socket. If we have data still in the write buffer yet to be
+ * sent, the socket won't be closed right now. It'll be closed after we managed
+ * to send everything out.
+ * If you want to close the socket now, you may want to call flush() first,
+ * and then closeNow().
+ */
+ virtual void close();
+
+ /**
+ * Closes the socket now, discarding the contents of the write buffer, if any.
+ * The read buffer's contents are kept until they are emptied by read operations
+ * or the class is destroyed.
+ */
+ virtual void closeNow();
+
+ /**
+ * Releases the socket and anything we have holding on it. The class cannot
+ * be used anymore. In other words, this is just like closeNow(), but it does
+ * not actually close the socket.
+ *
+ * This is useful if you just want to connect and don't need the rest of the
+ * class.
+ *
+ * Note that the buffers' contents will be discarded.
+ *
+ * Use of this method is discouraged, because the socket created might be such that
+ * normal library routines can't handle (read, write, close, etc.)
+ */
+ virtual void release();
+
+ /*
+ * -- I/O --
+ */
+
+ /**
+ * Flushes the socket buffer. You need not call this method during normal
+ * operation as we will try and send everything as soon as possible.
+ * However, if you want to make sure that data in the buffer is being sent
+ * at this moment, you can call this function. It will try to send as much
+ * data as possible, but it will stop as soon as the kernel cannot receive
+ * any more data, and would possibly block.
+ *
+ * By repeatedly calling this function, the behavior will be like that of
+ * a blocking socket. Indeed, if this function is called with the kernel not
+ * ready to receive data, it will block, unless this is a non-blocking socket.
+ *
+ * This function does not touch the read buffer. You can empty it by calling
+ * readBlock() with a null destination buffer.
+ */
+ virtual void flush();
+
+ /**
+ * Returns length of this socket. This call is not supported on sockets.
+ * @return the length of this socket, or 0 if unsupported
+ */
+ virtual inline Q_ULONG size() const
+ { return 0; }
+
+ /**
+ * Returns relative position from start. This call is not supported on sockets.
+ * @return the relative position from the start, or 0 if unsupported
+ */
+ virtual inline Q_ULONG at() const
+ { return 0; }
+
+ /**
+ * Returns true if we are at position. This is not supported on sockets.
+ * @param i the position to check
+ * @return true if we art at the given position, or always true if unsupported.
+ */
+ virtual inline bool at(int i)
+ { Q_UNUSED(i);return true; }
+
+ /**
+ * Returns true if we are at the end. This is not supported on sockets, but
+ * we always are at the end in a socket...
+ * @return true if we are at the end. Always false if unsupported.
+ */
+ virtual inline bool atEnd() const
+ { return false; }
+
+ /**
+ * Reads a block of data from the socket.
+ *
+ * If the socket is not buffered, this function will simply call the underlying
+ * read method. This function will block if the socket is not on non-blocking mode
+ * (see setBlockingMode) and there is not enough data to be read in the
+ * Operating System yet. If we are in non-blocking operation, the call will
+ * fail in this case.
+ *
+ * However, if we are buffering, this function will instead read from the
+ * buffer while there is available data. This function will never block
+ * in buffering mode, which means that if you try to read while the buffers
+ * are empty, this function will always return -1 and set the system error to
+ * EWOULDBLOCK (aka EAGAIN), so as to mimic non-blocking operation.
+ *
+ * @param data where we will write the read data to
+ * @param maxlen maximum length of data to be read
+ * @return the number of bytes effectively read, or a negative number in case
+ * or an error. If the @p data param is not null, then this is also the number
+ * of bytes copied into that buffer. If the return value is different than
+ * @p maxlen, then this function encountered a situation in which no more
+ * bytes were available. Subsequent calls might cause this function to one
+ * of these behaviours:
+ * @li return an error, with EWOULDBLOCK system error, if we buffering
+ * or we are in non-blocking mode
+ * @li otherwise, it'll block
+ * This function returns 0, if the function detected end-of-file condition
+ * (socket was closed)
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen);
+
+ /**
+ * Writes a block of data to the socket.
+ *
+ * If the socket is not buffered, this function will simply call the underlying
+ * write method. This means that the function might block if that method blocks
+ * as well. That situation is possible if we are not in non-blocking mode and
+ * the operating system buffers are full for this socket. If we are in
+ * non-blocking mode and the operating system buffers are full, this function
+ * will return -1 and the system error will be set to EWOULDBLOCK.
+ *
+ * If we are buffering, this function will simply transfer the data into the
+ * write buffer. This function will then always succeed, as long as there is
+ * enough room in the buffer. If the buffer size was limited and that limit
+ * is reached, this function will copy no more bytes than that limit. Trying
+ * to write with a full buffer will return -1 and set system error to
+ * EWOULDBLOCK.
+ *
+ * @param data the data to write
+ * @param len the length of data to write
+ * @return the number of bytes written from @p data buffer.
+ * The return value might be less than @p len if the output buffers cannot
+ * accommodate that many bytes and -1 in the case of an errro.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len);
+
+ /**
+ * Peeks at a block of data from the socket.
+ *
+ * This is exactly like read, except that the data won't be flushed from the
+ * read buffer.
+ *
+ * If this socket is not buffered, this function will always return with
+ * 0 bytes copied.
+ *
+ * @param data where to store the data
+ * @param maxlen how many bytes to copy, at most
+ * @return the number of bytes copied. 0 does not mean end-of-file
+ * condition.
+ */
+ virtual int peekBlock(char *data, uint maxlen);
+
+ /**
+ * Reimplementation of unreadBlock() method. This is so because unreading in
+ * sockets doesn't make sense, so this function will always return -1 (error)
+ * and set the system error to ENOSYS.
+ * @return always -1 (error)
+ */
+ virtual int unreadBlock(const char *data, uint len);
+
+ /**
+ * Returns the number of available bytes yet to be read via readBlock
+ * and family of functions.
+ *
+ * Note: as of now, this only works on input-buffered sockets. This will
+ * change in the future
+ * @return The number of available bytes, or -1 on error or -2 if this call is invalid
+ * in the current state.
+ */
+ virtual int bytesAvailable() const;
+
+ /**
+ * Waits @p msec milliseconds for more data to be available (use 0 to
+ * wait forever). The return value is the amount of data available for
+ * read in the read buffer.
+ *
+ * @param msec milliseconds to wait
+ * @return -1 in case of system error and -2 in case of invalid socket
+ * state
+ */
+ virtual int waitForMore(int msec);
+
+ /**
+ * Gets a single character (unsigned char) from the stream.
+ * @return the value of the character. Negative if there was an error.
+ */
+ virtual int getch();
+
+ /**
+ * Writes a single character (unsigned char) to the stream. All other bits
+ * will be ignored.
+ * @param ch character to write, converted to char
+ */
+ virtual int putch(int ch);
+
+ /**
+ * Unreads one character from the stream. This is not possible on sockets.
+ * @return always returns -1 on sockets.
+ */
+ virtual int ungetch(int)
+ { return -1; }
+
+ /**
+ * Toggles the emission of the readyRead signal.
+ *
+ * Note that this signal is emitted every time more data is available to be
+ * read, so you might get flooded with it being emitted every time, when in
+ * non-buffered mode. However, in buffered mode, this signal will be
+ * emitted only when there is data coming in from the wire.
+ * By default, this flag is set to false, i.e., signal not being emitted.
+ * @param enable if true, the signal will be emitted
+ */
+ virtual void enableRead(bool enable);
+
+ /**
+ * Toggles the emission of the readyWrite signal.
+ *
+ * Note that this signal is emitted only when the OS is ready to receive more
+ * data, which means that the write buffer is empty. And when that is reached,
+ * this signal will possibly be emitted on every loop, so you might
+ * want to disable it. By default, this flag is set to false.
+ * @param enable if true, the signal will be emitted
+ */
+ virtual void enableWrite(bool enable);
+
+signals:
+ /**
+ * This signal is emitted whenever an asynchronous lookup process is done.
+ * The parameter @p count tells
+ * @param count the number of results
+ */
+ void lookupFinished(int count);
+
+ /**
+ * This signal is emitted whenever we connected asynchronously to a host.
+ */
+ void connectionSuccess();
+
+ /**
+ * This signal is emitted whenever our asynchronous connection attempt
+ * failed to all hosts listed.
+ * @param error the errno code of the last connection attempt
+ */
+ void connectionFailed(int error);
+
+ /**
+ * This signal is emitted whenever this socket is ready to accept another
+ * socket.
+ * @see accept()
+ */
+ void readyAccept();
+
+protected:
+ int sockfd; // file descriptor of the socket
+
+protected slots:
+
+ void socketActivityRead();
+ void socketActivityWrite();
+ void dnsResultsReady();
+ void startAsyncConnectSlot();
+ void connectionEvent();
+
+protected:
+
+ QSocketNotifier *readNotifier();
+ QSocketNotifier *writeNotifier();
+
+private:
+
+ // protection against accidental use
+ KExtendedSocket(KExtendedSocket&);
+ KExtendedSocket& operator=(KExtendedSocket&);
+
+ /**
+ * This is actually a wrapper around getaddrinfo().
+ * @internal
+ */
+ static int doLookup(const QString& host, const QString& serv, addrinfo& hint,
+ kde_addrinfo** result);
+
+protected:
+ /**
+ * Sets the error code
+ */
+ void setError(int errorkind, int error);
+
+ inline void cleanError()
+ { setError(IO_Ok, 0); }
+
+ /**
+ * Sets the socket status. For derived classes only.
+ */
+ void setSocketStatus(int status);
+
+public:
+ /**
+ * Performs resolution on the given socket address.
+ *
+ * That is, tries to resolve the raw form of the socket address into a textual
+ * representation.
+ *
+ * @param sock the socket address
+ * @param len the length of the socket address
+ * @param host where the hostname will be written
+ * @param port where the service-port will be written
+ * @param flags the same flags as getnameinfo()
+ * @returns 0 on success, nonzero otherwise.
+ */
+ static int resolve(sockaddr* sock, ksocklen_t len, QString& host, QString& port, int flags = 0) KDE_DEPRECATED;
+
+ /**
+ * Performs resolution on the given socket address.
+ *
+ * That is, tries to resolve the raw form of the socket address into a textual
+ * representation.
+ *
+ * @param sock the socket address
+ * @param host where the hostname will be written
+ * @param port where the service-port will be written
+ * @param flags the same flags as getnameinfo()
+ * @returns 0 on success, nonzero otherwise.
+ */
+ static int resolve(::KSocketAddress* sock, QString& host, QString& port, int flags = 0) KDE_DEPRECATED;
+
+ /** @deprecated
+ * This function is now deprecated. Please use @ref KNetwork::KResolver::resolve.
+ *
+ * Performs lookup on the given hostname/port combination and returns a list
+ * of matching addresses.
+ * The error code can be transformed into string by KExtendedSocket::strError()
+ * with code of IO_LookupError.
+ *
+ * IMPORTANT: the result values of the QPtrList must be deleted after use. So,
+ * if you don't copy the KAddressInfo objects, the best way to assure that
+ * is to call setAutoDelete(true) on the list right after this function
+ * returns. If you do copy the results out, you must assure that the objects
+ * get deleted when they are not needed any more.
+ *
+ * @param host the hostname to look up
+ * @param port the port/service to look up
+ * @param flags flags to be used when looking up, Flags
+ * @param error pointer to a variable holding the error code
+ * @return a list of KAddressInfos
+ */
+ static QPtrList<KAddressInfo> lookup(const QString& host, const QString& port, int flags = 0, int *error = 0) KDE_DEPRECATED;
+
+ /**
+ * Returns the local socket address
+ * Remember to delete the returned object when it is no longer needed.
+ * @param fd the file descriptor
+ * @return the local socket address or 0 if an error occurred. Delete after use.
+ */
+ static ::KSocketAddress *localAddress(int fd) KDE_DEPRECATED;
+
+ /**
+ * Returns the peer socket address. Use KExtendedSocket::resolve() to
+ * resolve this to a human-readable hostname/service or port.
+ * Remember to delete the returned object when it is no longer needed.
+ * @param fd the file descriptor
+ * @return the peer socket address or 0 if an error occurred. Delete after use.
+ */
+ static ::KSocketAddress *peerAddress(int fd) KDE_DEPRECATED;
+
+ /**
+ * Returns the representing text of this error code
+ * @param code the error code, as seen in status()
+ * @param syserr the system error, as from systemError()
+ * @return the text for the given error code
+ */
+ static QString strError(int code, int syserr);
+
+ /**
+ * Sets/unsets address reusing flag for this socket.
+ *
+ * This function returns true if the value was set correctly. That is NOT
+ * the result of the set.
+ * @param fd the file descriptor
+ * @param enable if true, set address reusable
+ * @return true on success, false on failure.
+ */
+ static bool setAddressReusable(int fd, bool enable) KDE_DEPRECATED;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KExtendedSocketPrivate *d;
+
+ friend class KSocket;
+ friend class KServerSocket;
+};
+
+/** @deprecated
+ * This class is now deprecated. Please see @ref KNetwork::KResolver for the new API.
+ *
+ * Contains information about an internet address. It wraps addrinfo,
+ * see getaddrinfo(3) for more information.
+ */
+class KDECORE_EXPORT KAddressInfo
+{
+private:
+ addrinfo *ai;
+ ::KSocketAddress *addr;
+
+ inline KAddressInfo() : ai(0), addr(0)
+ { }
+
+ // KAddressInfo(addrinfo *ai);
+ KAddressInfo(KAddressInfo&) { }
+ KAddressInfo& operator=(KAddressInfo&) { return *this; }
+
+public:
+ ~KAddressInfo();
+
+ /**
+ * Returns the KAddressInfo's KSocketAddress.
+ * Only valid as long as the KAddressInfo exists.
+ */
+ inline KDE_DEPRECATED operator const ::KSocketAddress*() const
+ { return addr; }
+
+ /**
+ * Returns the KAddressInfo's addrinfo.
+ */
+ inline KDE_DEPRECATED operator const addrinfo&() const
+ { return *ai; }
+
+ /**
+ * Returns a pointer to KAddressInfo's addrinfo.
+ * Only valid as long as the KAddressInfo exists.
+ */
+ inline KDE_DEPRECATED operator const addrinfo*() const
+ { return ai; }
+
+ /**
+ * Returns the KAddressInfo's KSocketAddress.
+ * Only valid as long as the KAddressInfo exists.
+ * @return the KAddressInfo's KSocketAddress.
+ */
+ inline KDE_DEPRECATED const ::KSocketAddress* address() const
+ { return addr; }
+
+ /**
+ * Returns the flags of the address info (see getaddrinfo(3)).
+ * @return the flags of the addres info.
+ */
+ int flags() const KDE_DEPRECATED;
+
+ /**
+ * Returns the family of the address info (see getaddrinfo(3)).
+ * @return the family of the addres info.
+ */
+ int family() const KDE_DEPRECATED;
+
+ /**
+ * Returns the socket type of the address info (see getaddrinfo(3)).
+ * @return the socket type of the addres info.
+ */
+ int socktype() const KDE_DEPRECATED;
+
+ /**
+ * Returns the protocol of the address info (see getaddrinfo(3)).
+ * @return the protocol of the addres info.
+ */
+ int protocol() const KDE_DEPRECATED;
+
+
+ /**
+ * Returns the official name of the host (see getaddrinfo(3)).
+ * Only valid as long as the KAddressInfo exists.
+ * @return the official name of the host
+ */
+ const char* canonname() const KDE_DEPRECATED;
+
+ /**
+ * Returns the length of the KSocketAddress.
+ * @return the KSocketAddress's length
+ */
+ inline int length() const
+ { if (addr) return addr->size(); return 0; }
+
+ friend class KExtendedSocket;
+};
+
+#endif //Q_OS_UNIX
+
+#endif // KEXTSOCK_H
diff --git a/kdecore/kgenericfactory.h b/kdecore/kgenericfactory.h
new file mode 100644
index 000000000..facdcde20
--- /dev/null
+++ b/kdecore/kgenericfactory.h
@@ -0,0 +1,397 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef __kgenericfactory_h__
+#define __kgenericfactory_h__
+
+#include <klibloader.h>
+#include <ktypelist.h>
+#include <kinstance.h>
+#include <kgenericfactory.tcc>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+/* @internal */
+template <class T>
+class KGenericFactoryBase
+{
+public:
+ KGenericFactoryBase( const char *instanceName )
+ : m_instanceName( instanceName )
+ {
+ m_aboutData=0L;
+ s_self = this;
+ m_catalogueInitialized = false;
+ }
+ KGenericFactoryBase( const KAboutData *data )
+ : m_aboutData(data)
+ {
+ s_self = this;
+ m_catalogueInitialized = false;
+ }
+
+ virtual ~KGenericFactoryBase()
+ {
+ if ( s_instance )
+ KGlobal::locale()->removeCatalogue( QString::fromAscii( s_instance->instanceName() ) );
+ delete s_instance;
+ s_instance = 0;
+ s_self = 0;
+ }
+
+ static KInstance *instance();
+
+protected:
+ virtual KInstance *createInstance()
+ {
+ if ( m_aboutData )
+ return new KInstance( m_aboutData );
+ if ( !m_instanceName ) {
+ kdWarning() << "KGenericFactory: instance requested but no instance name or about data passed to the constructor!" << endl;
+ return 0;
+ }
+ return new KInstance( m_instanceName );
+ }
+
+ virtual void setupTranslations( void )
+ {
+ if ( instance() )
+ KGlobal::locale()->insertCatalogue( QString::fromAscii( instance()->instanceName() ) );
+ }
+
+ void initializeMessageCatalogue()
+ {
+ if ( !m_catalogueInitialized )
+ {
+ m_catalogueInitialized = true;
+ setupTranslations();
+ }
+ }
+
+private:
+ QCString m_instanceName;
+ const KAboutData *m_aboutData;
+ bool m_catalogueInitialized;
+
+ static KInstance *s_instance;
+ static KGenericFactoryBase<T> *s_self;
+};
+
+/* @internal */
+template <class T>
+KInstance *KGenericFactoryBase<T>::s_instance = 0;
+
+/* @internal */
+template <class T>
+KGenericFactoryBase<T> *KGenericFactoryBase<T>::s_self = 0;
+
+/* @internal */
+template <class T>
+KInstance *KGenericFactoryBase<T>::instance()
+{
+ if ( !s_instance && s_self )
+ s_instance = s_self->createInstance();
+ return s_instance;
+}
+
+/**
+ * This template provides a generic implementation of a KLibFactory ,
+ * for use with shared library components. It implements the pure virtual
+ * createObject method of KLibFactory and instantiates objects of the
+ * specified class (template argument) when the class name argument of
+ * createObject matches a class name in the given hierarchy.
+ *
+ * In case you are developing a KParts component, skip this file and
+ * go directly to KParts::GenericFactory .
+ *
+ * Note that the class specified as template argument needs to provide
+ * a certain constructor:
+ * <ul>
+ * <li>If the class is derived from QObject then it needs to have
+ * a constructor like:
+ * <code>MyClass( QObject *parent, const char *name,
+ * const QStringList &args );</code>
+ * <li>If the class is derived from QWidget then it needs to have
+ * a constructor like:
+ * <code>MyWidget( QWidget *parent, const char *name,
+ * const QStringList &args);</code>
+ * <li>If the class is derived from KParts::Part then it needs to have
+ * a constructor like:
+ * <code>MyPart( QWidget *parentWidget, const char *widgetName,
+ * QObject *parent, const char *name,
+ * const QStringList &args );</code>
+ * </ul>
+ * The args QStringList passed to the constructor is the args string list
+ * that the caller passed to KLibFactory's create method.
+ *
+ * In addition upon instantiation this template provides a central
+ * KInstance object for your component, accessible through the
+ * static instance() method. The instanceName argument of the
+ * KGenericFactory constructor is passed to the KInstance object.
+ *
+ * The creation of the KInstance object can be customized by inheriting
+ * from this template class and re-implementing the virtual createInstance
+ * method. For example it could look like this:
+ * \code
+ * KInstance *MyFactory::createInstance()
+ * {
+ * return new KInstance( myAboutData );
+ * }
+ * \endcode
+ *
+ * Example of usage of the whole template:
+ * \code
+ * class MyPlugin : public KParts::Plugin
+ * {
+ * Q_ OBJECT
+ * public:
+ * MyPlugin( QObject *parent, const char *name,
+ * const QStringList &args );
+ * ...
+ * };
+ *
+ * K_EXPORT_COMPONENT_FACTORY( libmyplugin, KGenericFactory&lt;MyPlugin&gt; )
+ * \endcode
+ */
+template <class Product, class ParentType = QObject>
+class KGenericFactory : public KLibFactory, public KGenericFactoryBase<Product>
+{
+public:
+ KGenericFactory( const char *instanceName = 0 )
+ : KGenericFactoryBase<Product>( instanceName )
+ {}
+
+ /**
+ * @since 3.3
+ */
+ KGenericFactory( const KAboutData *data )
+ : KGenericFactoryBase<Product>( data )
+ {}
+
+
+protected:
+ virtual QObject *createObject( QObject *parent, const char *name,
+ const char *className, const QStringList &args )
+ {
+ KGenericFactoryBase<Product>::initializeMessageCatalogue();
+ return KDEPrivate::ConcreteFactory<Product, ParentType>
+ ::create( 0, 0, parent, name, className, args );
+ }
+};
+
+/**
+ * This template provides a generic implementation of a KLibFactory ,
+ * for use with shared library components. It implements the pure virtual
+ * createObject method of KLibFactory and instantiates objects of the
+ * specified classes in the given typelist template argument when the class
+ * name argument of createObject matches a class names in the given hierarchy
+ * of classes.
+ *
+ * Note that each class in the specified in the typelist template argument
+ * needs to provide a certain constructor:
+ * <ul>
+ * <li>If the class is derived from QObject then it needs to have
+ * a constructor like:
+ * <code>MyClass( QObject *parent, const char *name,
+ * const QStringList &args );</code>
+ * <li>If the class is derived from QWidget then it needs to have
+ * a constructor like:
+ * <code>MyWidget( QWidget *parent, const char *name,
+ * const QStringList &args);</code>
+ * <li>If the class is derived from KParts::Part then it needs to have
+ * a constructor like:
+ * <code>MyPart( QWidget *parentWidget, const char *widgetName,
+ * QObject *parent, const char *name,
+ * const QStringList &args );</code>
+ * </ul>
+ * The args QStringList passed to the constructor is the args string list
+ * that the caller passed to KLibFactory's create method.
+ *
+ * In addition upon instantiation this template provides a central
+ * KInstance object for your component, accessible through the
+ * static instance() method. The instanceName argument of the
+ * KGenericFactory constructor is passed to the KInstance object.
+ *
+ * The creation of the KInstance object can be customized by inheriting
+ * from this template class and re-implementing the virtual createInstance
+ * method. For example it could look like this:
+ * \code
+ * KInstance *MyFactory::createInstance()
+ * {
+ * return new KInstance( myAboutData );
+ * }
+ * \endcode
+ *
+ * Example of usage of the whole template:
+ * \code
+ * class MyPlugin : public KParts::Plugin
+ * {
+ * Q_ OBJECT
+ * public:
+ * MyPlugin( QObject *parent, const char *name,
+ * const QStringList &args );
+ * ...
+ * };
+ *
+ * class MyDialogComponent : public KDialogBase
+ * {
+ * Q_ OBJECT
+ * public:
+ * MyDialogComponent( QWidget *parentWidget, const char *name,
+ * const QStringList &args );
+ * ...
+ * };
+ *
+ * typedef K_TYPELIST_2( MyPlugin, MyDialogComponent ) Products;
+ * K_EXPORT_COMPONENT_FACTORY( libmyplugin, KGenericFactory&lt;Products&gt; )
+ * \endcode
+ */
+template <class Product, class ProductListTail>
+class KGenericFactory< KTypeList<Product, ProductListTail>, QObject >
+ : public KLibFactory,
+ public KGenericFactoryBase< KTypeList<Product, ProductListTail> >
+{
+public:
+ KGenericFactory( const char *instanceName = 0 )
+ : KGenericFactoryBase< KTypeList<Product, ProductListTail> >( instanceName )
+ {}
+
+ /**
+ * @since 3.3
+ */
+ KGenericFactory( const KAboutData *data )
+ : KGenericFactoryBase< KTypeList<Product, ProductListTail> >( data )
+ {}
+
+
+protected:
+ virtual QObject *createObject( QObject *parent, const char *name,
+ const char *className, const QStringList &args )
+ {
+ this->initializeMessageCatalogue();
+ return KDEPrivate::MultiFactory< KTypeList< Product, ProductListTail > >
+ ::create( 0, 0, parent, name, className, args );
+ }
+};
+
+/**
+ * This template provides a generic implementation of a KLibFactory ,
+ * for use with shared library components. It implements the pure virtual
+ * createObject method of KLibFactory and instantiates objects of the
+ * specified classes in the given typelist template argument when the class
+ * name argument of createObject matches a class names in the given hierarchy
+ * of classes.
+ *
+ * Note that each class in the specified in the typelist template argument
+ * needs to provide a certain constructor:
+ * <ul>
+ * <li>If the class is derived from QObject then it needs to have
+ * a constructor like:
+ * <code>MyClass( QObject *parent, const char *name,
+ * const QStringList &args );</code>
+ * <li>If the class is derived from QWidget then it needs to have
+ * a constructor like:
+ * <code>MyWidget( QWidget *parent, const char *name,
+ * const QStringList &args);</code>
+ * <li>If the class is derived from KParts::Part then it needs to have
+ * a constructor like:
+ * <code>MyPart( QWidget *parentWidget, const char *widgetName,
+ * QObject *parent, const char *name,
+ * const QStringList &args );</code>
+ * </ul>
+ * The args QStringList passed to the constructor is the args string list
+ * that the caller passed to KLibFactory's create method.
+ *
+ * In addition upon instantiation this template provides a central
+ * KInstance object for your component, accessible through the
+ * static instance() method. The instanceName argument of the
+ * KGenericFactory constructor is passed to the KInstance object.
+ *
+ * The creation of the KInstance object can be customized by inheriting
+ * from this template class and re-implementing the virtual createInstance
+ * method. For example it could look like this:
+ * \code
+ * KInstance *MyFactory::createInstance()
+ * {
+ * return new KInstance( myAboutData );
+ * }
+ * \endcode
+ *
+ * Example of usage of the whole template:
+ * \code
+ * class MyPlugin : public KParts::Plugin
+ * {
+ * Q_ OBJECT
+ * public:
+ * MyPlugin( QObject *parent, const char *name,
+ * const QStringList &args );
+ * ...
+ * };
+ *
+ * class MyDialogComponent : public KDialogBase
+ * {
+ * Q_ OBJECT
+ * public:
+ * MyDialogComponent( QWidget *parentWidget, const char *name,
+ * const QStringList &args );
+ * ...
+ * };
+ *
+ * typedef K_TYPELIST_2( MyPlugin, MyDialogComponent ) Products;
+ * K_EXPORT_COMPONENT_FACTORY( libmyplugin, KGenericFactory&lt;Products&gt; )
+ * \endcode
+ */
+template <class Product, class ProductListTail,
+ class ParentType, class ParentTypeListTail>
+class KGenericFactory< KTypeList<Product, ProductListTail>,
+ KTypeList<ParentType, ParentTypeListTail> >
+ : public KLibFactory,
+ public KGenericFactoryBase< KTypeList<Product, ProductListTail> >
+{
+public:
+ KGenericFactory( const char *instanceName = 0 )
+ : KGenericFactoryBase< KTypeList<Product, ProductListTail> >( instanceName )
+ {}
+ /**
+ * @since 3.3
+ */
+ KGenericFactory( const KAboutData *data )
+ : KGenericFactoryBase< KTypeList<Product, ProductListTail> >( data )
+ {}
+
+
+protected:
+ virtual QObject *createObject( QObject *parent, const char *name,
+ const char *className, const QStringList &args )
+ {
+ this->initializeMessageCatalogue();
+ return KDEPrivate::MultiFactory< KTypeList< Product, ProductListTail >,
+ KTypeList< ParentType, ParentTypeListTail > >
+ ::create( 0, 0, parent, name,
+ className, args );
+ }
+};
+
+
+/*
+ * vim: et sw=4
+ */
+
+#endif
+
diff --git a/kdecore/kgenericfactory.tcc b/kdecore/kgenericfactory.tcc
new file mode 100644
index 000000000..41cd77824
--- /dev/null
+++ b/kdecore/kgenericfactory.tcc
@@ -0,0 +1,272 @@
+/*
+ * The Type2Type template and the Inheritance Detector are from
+ * <http://www.cuj.com/experts/1810/alexandr.htm>
+ * (c) Andrei Alexandrescu <andrei@metalanguage.com> and
+ * free for any use.
+ *
+ * The rest is:
+ * Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+// -*- mode: c++ -*-
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the KDE API. It exists for the convenience
+// of KGenericFactory. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef KGENERICFACTORY_TCC
+#define KGENERICFACTORY_TCC
+
+#include <qmetaobject.h>
+#include <ktypelist.h>
+
+namespace KParts
+{
+ class Part;
+}
+
+namespace KDEPrivate
+{
+ template <class Base>
+ struct InheritanceDetector
+ {
+ typedef char ConversionExists;
+ struct ConversionDoesNotExist { char bleh[ 2 ]; };
+ static ConversionExists test( Base * );
+ static ConversionDoesNotExist test( ... );
+ };
+
+ /* Simon: KCC doesn't eat the generic InheritanceDetector<Base>.
+ Instead we have to use concrete specializations :-(
+
+ template <class Base, class Derived>
+ struct InheritanceTest
+ {
+ typedef Derived * DerivedPtr;
+ enum { Result = sizeof( InheritanceDetector<Base>::test( DerivedPtr() ) ) ==
+ sizeof( InheritanceDetector<Base>::ConversionExists ) };
+ };
+ */
+
+ template <class Derived>
+ struct QWidgetInheritanceTest
+ {
+ typedef Derived * DerivedPtr;
+ enum { Result = sizeof( InheritanceDetector<QWidget>::test( DerivedPtr() ) ) ==
+ sizeof( InheritanceDetector<QWidget>::ConversionExists ) };
+ };
+
+ template <class Derived>
+ struct PartInheritanceTest
+ {
+ typedef Derived * DerivedPtr;
+ enum { Result = sizeof( InheritanceDetector<KParts::Part>::test( DerivedPtr() ) ) ==
+ sizeof( InheritanceDetector<KParts::Part>::ConversionExists ) };
+ };
+
+
+ template <bool condition, typename Then, typename Else>
+ struct If
+ {
+ typedef Else Result;
+ };
+
+ template <typename Then, typename Else>
+ struct If<true, Then, Else>
+ {
+ typedef Then Result;
+ };
+
+ // a small helper template, to ease the overloading done in ConcreteFactory
+ // to choose the right constructor for the given class.
+ template <class T>
+ struct Type2Type
+ {
+ typedef T OriginalType;
+ };
+
+ // this template is called from the MultiFactory one. It instantiates
+ // the given class if the className matches. Instantiating is done by
+ // calling the right constructor (a parentwidget/widgetname/parent/name
+ // one for Parts, a parentwidget/widgetname one for widgets and last
+ // but not least the standard default constructor of parent/name .
+ // the choice of the right constructor is done using an ordered inheritance
+ // test.
+ template <class Product, class ParentType = QObject>
+ class ConcreteFactory
+ {
+ public:
+ typedef typename If< PartInheritanceTest< Product >::Result,
+ KParts::Part,
+ typename If< QWidgetInheritanceTest< Product >::Result,
+ QWidget, QObject >::Result >::Result BaseType;
+
+ static inline Product *create( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *className, const QStringList &args )
+ {
+ QMetaObject *metaObject = Product::staticMetaObject();
+ while ( metaObject )
+ {
+ if ( !qstrcmp( className, metaObject->className() ) )
+ return create( parentWidget, widgetName,
+ parent, name, args, Type2Type<BaseType>() );
+ metaObject = metaObject->superClass();
+ }
+ return 0;
+ }
+ private:
+ typedef typename If< QWidgetInheritanceTest<ParentType>::Result,
+ ParentType, QWidget >::Result WidgetParentType;
+
+ static inline Product *create( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const QStringList &args, Type2Type<KParts::Part> )
+ {
+ return new Product( parentWidget, widgetName, parent, name, args );
+ }
+
+ static inline Product *create( QWidget* /*parentWidget*/, const char* /*widgetName*/,
+ QObject *parent, const char *name,
+ const QStringList &args, Type2Type<QWidget> )
+ {
+
+ WidgetParentType *p = dynamic_cast<WidgetParentType *>( parent );
+ if ( parent && !p )
+ return 0;
+ return new Product( p, name, args );
+ }
+
+ static inline Product *create( QWidget* /*parentWidget*/, const char* /*widgetName*/,
+ QObject *parent, const char *name,
+ const QStringList &args, Type2Type<QObject> )
+ {
+ ParentType *p = dynamic_cast<ParentType *>( parent );
+ if ( parent && !p )
+ return 0;
+ return new Product( p, name, args );
+ }
+ };
+
+ // this template is used to iterate through the typelist and call the
+ // concrete factory for each type. the specializations of this template
+ // are the ones actually being responsible for iterating, in fact.
+ template <class Product, class ParentType = QObject>
+ class MultiFactory
+ {
+ public:
+ inline static QObject *create( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *className,
+ const QStringList &args )
+ {
+ return ConcreteFactory<Product, ParentType>::create( parentWidget, widgetName,
+ parent, name, className,
+ args );
+ }
+
+ };
+
+ // this specialized template we 'reach' at the end of a typelist
+ // (the last item in a typelist is the NullType)
+ template <>
+ class MultiFactory<KDE::NullType>
+ {
+ public:
+ inline static QObject *create( QWidget *, const char *, QObject *,
+ const char *, const char *,
+ const QStringList & )
+ { return 0; }
+ };
+
+ // this specialized template we 'reach' at the end of a typelist
+ // (the last item in a typelist is the NullType)
+ template <>
+ class MultiFactory<KDE::NullType, KDE::NullType>
+ {
+ public:
+ inline static QObject *create( QWidget *, const char *, QObject *,
+ const char *, const char *,
+ const QStringList & )
+ { return 0; }
+ };
+
+ template <class Product, class ProductListTail>
+ class MultiFactory< KTypeList<Product, ProductListTail>, QObject >
+ {
+ public:
+ inline static QObject *create( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *className,
+ const QStringList &args )
+ {
+ // try with the head of the typelist first. the head is always
+ // a concrete type.
+ QObject *object = MultiFactory<Product>::create( parentWidget, widgetName,
+ parent, name, className,
+ args );
+
+ if ( !object )
+ object = MultiFactory<ProductListTail>::create( parentWidget, widgetName,
+ parent, name, className,
+ args );
+
+ return object;
+ }
+ };
+
+ template <class Product, class ProductListTail,
+ class ParentType, class ParentTypeListTail>
+ class MultiFactory< KTypeList<Product, ProductListTail>,
+ KTypeList<ParentType, ParentTypeListTail> >
+ {
+ public:
+ inline static QObject *create( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *className,
+ const QStringList &args )
+ {
+ // try with the head of the typelist first. the head is always
+ // a concrete type.
+ QObject *object = MultiFactory<Product, ParentType>
+ ::create( parentWidget, widgetName,
+ parent, name, className, args );
+
+ // if that failed continue by advancing the typelist, calling this
+ // template specialization recursively (with T2 being a typelist) .
+ // at the end we reach the nulltype specialization.
+ if ( !object )
+ object = MultiFactory<ProductListTail, ParentTypeListTail>
+ ::create( parentWidget, widgetName,
+ parent, name, className, args );
+
+ return object;
+ }
+ };
+}
+
+#endif
+
+/*
+ * vim: et sw=4
+ */
diff --git a/kdecore/kglobal.cpp b/kdecore/kglobal.cpp
new file mode 100644
index 000000000..188e8f447
--- /dev/null
+++ b/kdecore/kglobal.cpp
@@ -0,0 +1,264 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kanq <taj@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/*
+* kglobal.cpp -- Implementation of class KGlobal.
+* Author: Sirtaj Singh Kang
+* Version: $Id$
+* Generated: Sat May 1 02:08:43 EST 1999
+*/
+
+#include <qglobal.h>
+#include <qdict.h>
+#include <qptrlist.h>
+#include "kglobal.h"
+
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kcharsets.h>
+#include <kiconloader.h>
+#include <kstandarddirs.h>
+#include <kinstance.h>
+#include "kstaticdeleter.h"
+
+#include <qfont.h>
+
+#ifndef NDEBUG
+#define MYASSERT(x) if (!x) \
+ qFatal("Fatal error: you need to have a KInstance object before\n" \
+ "you do anything that requires it! Examples of this are config\n" \
+ "objects, standard directories or translations.");
+#else
+#define MYASSERT(x) /* nope */
+#endif
+
+static void kglobal_init();
+
+KStandardDirs *KGlobal::dirs()
+{
+ MYASSERT(_instance);
+
+ return _instance->dirs();
+}
+
+KConfig *KGlobal::config()
+{
+ MYASSERT(_instance);
+
+ return _instance->config();
+}
+
+KSharedConfig *KGlobal::sharedConfig()
+{
+ MYASSERT(_instance);
+
+ return _instance->sharedConfig();
+}
+
+KIconLoader *KGlobal::iconLoader()
+{
+ MYASSERT(_instance);
+
+ return _instance->iconLoader();
+}
+
+KInstance *KGlobal::instance()
+{
+ MYASSERT(_instance);
+ return _instance;
+}
+
+KLocale *KGlobal::locale()
+{
+ if( _locale == 0 ) {
+ if (!_instance)
+ return 0;
+ kglobal_init();
+
+ // will set _locale if it works - otherwise 0 is returned
+ KLocale::initInstance();
+ if( _instance->aboutData())
+ _instance->aboutData()->translateInternalProgramName();
+ }
+
+ return _locale;
+}
+
+KCharsets *KGlobal::charsets()
+{
+ if( _charsets == 0 ) {
+ _charsets =new KCharsets();
+ kglobal_init();
+ }
+
+ return _charsets;
+}
+
+void KGlobal::setActiveInstance(KInstance *i)
+{
+ _activeInstance = i;
+ if (i && _locale)
+ _locale->setActiveCatalogue(QString::fromUtf8(i->instanceName()));
+}
+
+/**
+ * Create a static QString
+ *
+ * To be used inside functions(!) like:
+ * static const QString &myString = KGlobal::staticQString("myText");
+ */
+const QString &
+KGlobal::staticQString(const char *str)
+{
+ return staticQString(QString::fromLatin1(str));
+}
+
+class KStringDict : public QDict<QString>
+{
+public:
+ KStringDict() : QDict<QString>(139) { }
+};
+
+/**
+ * Create a static QString
+ *
+ * To be used inside functions(!) like:
+ * static const QString &myString = KGlobal::staticQString(i18n("My Text"));
+ */
+const QString &
+KGlobal::staticQString(const QString &str)
+{
+ if (!_stringDict) {
+ _stringDict = new KStringDict;
+ _stringDict->setAutoDelete( true );
+ kglobal_init();
+ }
+ QString *result = _stringDict->find(str);
+ if (!result)
+ {
+ result = new QString(str);
+ _stringDict->insert(str, result);
+ }
+ return *result;
+}
+
+class KStaticDeleterList: public QPtrList<KStaticDeleterBase>
+{
+public:
+ KStaticDeleterList() { }
+};
+
+void
+KGlobal::registerStaticDeleter(KStaticDeleterBase *obj)
+{
+ if (!_staticDeleters)
+ kglobal_init();
+ if (_staticDeleters->find(obj) == -1)
+ _staticDeleters->append(obj);
+}
+
+void
+KGlobal::unregisterStaticDeleter(KStaticDeleterBase *obj)
+{
+ if (_staticDeleters)
+ _staticDeleters->removeRef(obj);
+}
+
+void
+KGlobal::deleteStaticDeleters()
+{
+ if (!KGlobal::_staticDeleters)
+ return;
+
+ for(;_staticDeleters->count();)
+ {
+ _staticDeleters->take(0)->destructObject();
+ }
+
+ delete KGlobal::_staticDeleters;
+ KGlobal::_staticDeleters = 0;
+}
+
+// The Variables
+
+KStringDict *KGlobal::_stringDict = 0;
+KInstance *KGlobal::_instance = 0;
+KInstance *KGlobal::_activeInstance = 0;
+KLocale *KGlobal::_locale = 0;
+KCharsets *KGlobal::_charsets = 0;
+KStaticDeleterList *KGlobal::_staticDeleters = 0;
+
+#ifdef WIN32
+#include <windows.h>
+static void kglobal_freeAll();
+BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID impLoad )
+{
+ if (reason == DLL_PROCESS_DETACH)
+ kglobal_freeAll();
+ return TRUE;
+}
+#else
+__attribute__((destructor))
+#endif
+static void kglobal_freeAll()
+{
+ delete KGlobal::_locale;
+ KGlobal::_locale = 0;
+ delete KGlobal::_charsets;
+ KGlobal::_charsets = 0;
+ delete KGlobal::_stringDict;
+ KGlobal::_stringDict = 0;
+ KGlobal::deleteStaticDeleters();
+ // so that we don't hold a reference and see memory leaks :/
+ KGlobal::setActiveInstance(0);
+}
+
+static void kglobal_init()
+{
+ if (KGlobal::_staticDeleters)
+ return;
+
+ KGlobal::_staticDeleters = new KStaticDeleterList;
+}
+
+int kasciistricmp( const char *str1, const char *str2 )
+{
+ const unsigned char *s1 = (const unsigned char *)str1;
+ const unsigned char *s2 = (const unsigned char *)str2;
+ int res;
+ unsigned char c1, c2;
+
+ if ( !s1 || !s2 )
+ return s1 ? 1 : (s2 ? -1 : 0);
+ if ( !*s1 || !*s2 )
+ return *s1 ? 1 : (*s2 ? -1 : 0);
+ for (;*s1; ++s1, ++s2) {
+ c1 = *s1; c2 = *s2;
+ if (c1 >= 'A' && c1 <= 'Z')
+ c1 += 'a' - 'A';
+ if (c2 >= 'A' && c2 <= 'Z')
+ c2 += 'a' - 'A';
+
+ if ((res = c1 - c2))
+ break;
+ }
+ return *s1 ? res : (*s2 ? -1 : 0);
+}
+
diff --git a/kdecore/kglobal.h b/kdecore/kglobal.h
new file mode 100644
index 000000000..1c1f75967
--- /dev/null
+++ b/kdecore/kglobal.h
@@ -0,0 +1,237 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kanq <taj@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KGLOBAL_H
+#define _KGLOBAL_H
+
+#include "kdelibs_export.h"
+#include <kinstance.h> // KDE4: class KInstance is enough here
+
+class KCharsets;
+class KConfig;
+class KSharedConfig;
+class KIconLoader;
+class KLocale;
+class KStandardDirs;
+class KStaticDeleterBase;
+class KStaticDeleterList;
+class KStringDict;
+class QString;
+
+/**
+ * Access to the KDE global objects.
+ * KGlobal provides you with pointers of many central
+ * objects that exist only once in the process. It is also
+ * responsible for managing instances of KStaticDeleterBase.
+ *
+ * @see KStaticDeleterBase
+ * @author Sirtaj Singh Kang (taj@kde.org)
+ */
+class KDECORE_EXPORT KGlobal
+{
+public:
+
+ /**
+ * Returns the global instance. There is always at least
+ * one instance of a component in one application (in most
+ * cases the application itself).
+ * @return the global instance
+ */
+ static KInstance *instance();
+
+ /**
+ * Returns the application standard dirs object.
+ * @return the global standard dir object
+ */
+ static KStandardDirs *dirs();
+
+ /**
+ * Returns the general config object.
+ * @return the global configuration object.
+ */
+ static KConfig *config();
+
+ /**
+ * Returns the general config object.
+ * @return the global configuration object.
+ */
+ static KSharedConfig *sharedConfig();
+
+ /**
+ * Returns an iconloader object.
+ * @return the global iconloader object
+ */
+ static KIconLoader *iconLoader();
+
+ /**
+ * Returns the global locale object.
+ * @return the global locale object
+ */
+ static KLocale *locale();
+
+ /**
+ * The global charset manager.
+ * @return the global charset manager
+ */
+ static KCharsets *charsets();
+
+ /**
+ * Creates a static QString.
+ *
+ * To be used inside functions(!) like:
+ * \code
+ * static const QString &myString = KGlobal::staticQString("myText");
+ * \endcode
+ *
+ * !!! Do _NOT_ use: !!!
+ * \code
+ * static QString myString = KGlobal::staticQString("myText");
+ * \endcode
+ * This creates a static object (instead of a static reference)
+ * and as you know static objects are EVIL.
+ * @param str the string to create
+ * @return the static string
+ */
+ static const QString &staticQString(const char *str);
+
+ /**
+ * Creates a static QString.
+ *
+ * To be used inside functions(!) like:
+ * \code
+ * static const QString &myString = KGlobal::staticQString(i18n("My Text"));
+ * \endcode
+ *
+ * !!! Do _NOT_ use: !!!
+ * \code
+ * static QString myString = KGlobal::staticQString(i18n("myText"));
+ * \endcode
+ * This creates a static object (instead of a static reference)
+ * and as you know static objects are EVIL.
+ * @param str the string to create
+ * @return the static string
+ */
+ static const QString &staticQString(const QString &str);
+
+ /**
+ * Registers a static deleter.
+ * @param d the static deleter to register
+ * @see KStaticDeleterBase
+ * @see KStaticDeleter
+ */
+ static void registerStaticDeleter(KStaticDeleterBase *d);
+
+ /**
+ * Unregisters a static deleter.
+ * @param d the static deleter to unregister
+ * @see KStaticDeleterBase
+ * @see KStaticDeleter
+ */
+ static void unregisterStaticDeleter(KStaticDeleterBase *d);
+
+ /**
+ * Calls KStaticDeleterBase::destructObject() on all
+ * registered static deleters and unregisters them all.
+ * @see KStaticDeleterBase
+ * @see KStaticDeleter
+ */
+ static void deleteStaticDeleters();
+
+ //private:
+ static KStringDict *_stringDict;
+ static KInstance *_instance;
+ static KLocale *_locale;
+ static KCharsets *_charsets;
+ static KStaticDeleterList *_staticDeleters;
+
+ /**
+ * The instance currently active (useful in a multi-instance
+ * application, such as a KParts application).
+ * Don't use this - it's mainly for KAboutDialog and KBugReport.
+ * @internal
+ */
+ static void setActiveInstance(KInstance *d);
+ static KInstance *activeInstance() { return _activeInstance; }
+
+ static KInstance *_activeInstance;
+};
+
+/**
+ * \relates KGlobal
+ * A typesafe function to find the minimum of the two arguments.
+ */
+#define KMIN(a,b) kMin(a,b)
+/**
+ * \relates KGlobal
+ * A typesafe function to find the maximum of the two arguments.
+ */
+#define KMAX(a,b) kMax(a,b)
+/**
+ * \relates KGlobal
+ * A typesafe function to determine the absolute value of the argument.
+ */
+#define KABS(a) kAbs(a)
+/**
+ * \relates KGlobal
+ * A typesafe function that returns x if it's between low and high values.
+ * low if x is smaller than then low and high if x is bigger than high.
+ */
+#define KCLAMP(x,low,high) kClamp(x,low,high)
+
+// XXX KDE4: Make kMin, kMax and kClamp return "T" instead of "const T &"!
+template<class T>
+inline const T& kMin (const T& a, const T& b) { return a < b ? a : b; }
+
+template<class T>
+inline const T& kMax (const T& a, const T& b) { return b < a ? a : b; }
+
+template<class T>
+inline T kAbs (const T& a) { return a < 0 ? -a : a; }
+
+template<class T>
+inline const T& kClamp( const T& x, const T& low, const T& high )
+{
+ if ( x < low ) return low;
+ else if ( high < x ) return high;
+ else return x;
+}
+
+/**
+ * Locale-independent qstricmp. Use this for comparing ascii keywords
+ * in a case-insensitive way.
+ * qstricmp fails with e.g. the Turkish locale where 'I'.lower() != 'i'
+ * @since 3.4
+ */
+int KDECORE_EXPORT kasciistricmp( const char *str1, const char *str2 );
+
+
+/**
+ * \mainpage The KDE Core Functionality Library
+ *
+ * All KDE programs use this library to provide basic functionality such
+ * as the configuration system, IPC, internationalization and locale
+ * support, site-independent access to the filesystem and a large number
+ * of other (but no less important) things.
+ *
+ * All KDE applications should link to the kdecore library. Also, using a
+ * KApplication derived class instead of QApplication is almost
+ * mandatory if you expect your application to behave nicely within the
+ * KDE environment.
+ */
+
+#endif // _KGLOBAL_H
+
diff --git a/kdecore/kglobalaccel.cpp b/kdecore/kglobalaccel.cpp
new file mode 100644
index 000000000..9628b34d3
--- /dev/null
+++ b/kdecore/kglobalaccel.cpp
@@ -0,0 +1,139 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kglobalaccel.h"
+#ifdef Q_WS_X11
+#include "kglobalaccel_x11.h"
+#elif defined(Q_WS_WIN)
+#include "kglobalaccel_win.h"
+#elif defined(Q_WS_MACX)
+#include "kglobalaccel_mac.h"
+#else
+#include "kglobalaccel_emb.h"
+#endif
+
+#include <qstring.h>
+#include "kaccelbase.h"
+#include <kdebug.h>
+#include <kshortcut.h>
+#include <klocale.h>
+
+//----------------------------------------------------
+
+KGlobalAccel::KGlobalAccel( QObject* pParent, const char* psName )
+: QObject( pParent, psName )
+{
+ kdDebug(125) << "KGlobalAccel(): this = " << this << endl;
+ d = new KGlobalAccelPrivate();
+}
+
+KGlobalAccel::~KGlobalAccel()
+{
+ kdDebug(125) << "~KGlobalAccel(): this = " << this << endl;
+ delete d;
+}
+
+/*
+void KGlobalAccel::clear()
+ { d->clearActions(); }
+*/
+KAccelActions& KGlobalAccel::actions()
+ { return d->actions(); }
+
+const KAccelActions& KGlobalAccel::actions() const
+ { return d->actions(); }
+
+bool KGlobalAccel::isEnabled()
+ { return ((KAccelBase*)d)->isEnabled(); }
+
+void KGlobalAccel::setEnabled( bool bEnabled )
+ { d->setEnabled( bEnabled ); }
+
+void KGlobalAccel::suspend( bool s )
+ { d->suspend( s ); }
+
+void KGlobalAccel::blockShortcuts( bool block )
+ { KGlobalAccelPrivate::blockShortcuts( block ); }
+
+void KGlobalAccel::disableBlocking( bool disable )
+ { d->disableBlocking( disable ); }
+
+KAccelAction* KGlobalAccel::insert( const QString& sAction, const QString& sDesc, const QString& sHelp,
+ const KShortcut& cutDef3, const KShortcut& cutDef4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable, bool bEnabled )
+{
+ return d->insert( sAction, sDesc, sHelp,
+ cutDef3, cutDef4,
+ pObjSlot, psMethodSlot,
+ bConfigurable, bEnabled );
+}
+
+KAccelAction* KGlobalAccel::insert( const QString& sName, const QString& sDesc )
+ { return d->insert( sName, sDesc ); }
+bool KGlobalAccel::updateConnections()
+ { return d->updateConnections(); }
+
+bool KGlobalAccel::remove( const QString& sAction )
+ { return d->remove( sAction ); }
+
+const KShortcut& KGlobalAccel::shortcut( const QString& sAction ) const
+{
+ const KAccelAction* pAction = d->actions().actionPtr( sAction );
+ return (pAction) ? pAction->shortcut() : KShortcut::null();
+}
+
+bool KGlobalAccel::setShortcut( const QString& sAction, const KShortcut& cut )
+ { return d->setShortcut( sAction, cut ); }
+bool KGlobalAccel::setSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot )
+ { return d->setActionSlot( sAction, pObjSlot, psMethodSlot ); }
+QString KGlobalAccel::label( const QString& sAction ) const
+{
+ const KAccelAction* pAction = d->actions().actionPtr( sAction );
+ return (pAction) ? pAction->label() : QString();
+}
+bool KGlobalAccel::setActionEnabled( const QString& sAction, bool bEnable )
+{
+ return d->setActionEnabled( sAction, bEnable );
+}
+
+const QString& KGlobalAccel::configGroup() const
+ { return d->configGroup(); }
+// for kdemultimedia/kmix
+void KGlobalAccel::setConfigGroup( const QString& s )
+ { d->setConfigGroup( s ); }
+
+bool KGlobalAccel::readSettings( KConfigBase* pConfig )
+ { d->readSettings( pConfig ); return true; }
+bool KGlobalAccel::writeSettings( KConfigBase* pConfig ) const
+ { d->writeSettings( pConfig ); return true; }
+bool KGlobalAccel::writeSettings( KConfigBase* pConfig, bool bGlobal ) const
+{
+ d->setConfigGlobal( bGlobal );
+ d->writeSettings( pConfig );
+ return true;
+}
+
+bool KGlobalAccel::useFourModifierKeys()
+ { return KAccelAction::useFourModifierKeys(); }
+
+void KGlobalAccel::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kglobalaccel.moc"
diff --git a/kdecore/kglobalaccel.h b/kdecore/kglobalaccel.h
new file mode 100644
index 000000000..e4b847cdc
--- /dev/null
+++ b/kdecore/kglobalaccel.h
@@ -0,0 +1,239 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KGLOBALACCEL_H_
+#define _KGLOBALACCEL_H_
+
+#include <qobject.h>
+#include <kshortcut.h>
+
+class QPopupMenu;
+class QWidget;
+class KAccelAction;
+class KAccelActions;
+class KConfigBase;
+
+class KGlobalAccelPrivate;
+
+/**
+* KGlobalAccel allows you to have global accelerators that are independent of
+* the focused window. Unlike KAccel it does not matter which window is
+* currently active.
+*
+* @see KAccel
+* @see KAccelShortcutList
+* @see KKeyChooser
+* @see KKeyDialog
+* @short Configurable global shortcut support
+*/
+class KDECORE_EXPORT KGlobalAccel : public QObject
+{
+ Q_OBJECT
+ public:
+ /**
+ * Creates a new KGlobalAccel object with the given pParent and
+ * psName.
+ * @param pParent the parent of the QObject
+ * @param psName the name of the QObject
+ */
+ KGlobalAccel( QObject* pParent, const char* psName = 0 );
+ virtual ~KGlobalAccel();
+
+ /**
+ * Checks whether the accelerators are enabled.
+ * @return true if the KGlobalAccel is enabled
+ */
+ bool isEnabled();
+
+ /**
+ * Enables or disables the KGlobalAccel
+ * @param bEnabled true if the KGlobalAccel should be enabled, false if it
+ * should be disabled.
+ */
+ void setEnabled( bool bEnabled );
+
+ /**
+ * Create an accelerator action.
+ *
+ * Usage:
+ *\code
+ * insert( "Do Something", i18n("Do Something"),
+ * i18n("This action allows you to do something really great with this program to "
+ * "the currently open document."),
+ * ALT+CTRL+Key_Q, KKey::QtWIN+CTRL+Key_Q, this, SLOT(slotDoSomething()) );
+ *\endcode
+ *
+ * @param sAction The internal name of the action.
+ * @param sLabel An i18n'ized short description of the action displayed when
+ * using KKeyChooser to reconfigure the shortcuts.
+ * @param sWhatsThis An extended description of the action.
+ * @param cutDef3 The default 3 modifier scheme shortcut.
+ * @param cutDef4 The default 4 modifier scheme shortcut.
+ * @param pObjSlot Pointer to the slot object.
+ * @param psMethodSlot Pointer to the slot method.
+ * @param bConfigurable Allow the user to change this shortcut if set to 'true'.
+ * @param bEnabled The action will be activated by the shortcut if set to 'true'.
+ */
+ KAccelAction* insert( const QString& sAction, const QString& sLabel, const QString& sWhatsThis,
+ const KShortcut& cutDef3, const KShortcut& cutDef4,
+ const QObject* pObjSlot, const char* psMethodSlot,
+ bool bConfigurable = true, bool bEnabled = true );
+
+ /**
+ * Removes the accelerator action identified by the name.
+ * Remember to also call updateConnections().
+ * @param sAction the name of the action to remove
+ * @since 3.1
+ */
+ bool remove( const QString& sAction );
+
+ /**
+ * Use this to insert a label into the action list. This will be
+ * displayed when the user configures shortcuts.
+ * @param sName of the of the action to insert
+ * @param sLabel a user-readable (i18n!) name for the action
+ * @return the KAccelAction of the action
+ */
+ KAccelAction* insert( const QString& sName, const QString& sLabel );
+
+ /**
+ * Updates the connections of the accelerations after changing them.
+ * @return true if successful, false otherwise
+ */
+ bool updateConnections();
+
+ /**
+ * Return the shortcut associated with the action named by @p sAction.
+ * @param sAction the name of the action
+ * @return the shortcut. If the action does not exist a null shortcut will be returned.
+ */
+ const KShortcut& shortcut( const QString& sAction ) const;
+ /**
+ * Set the shortcut to be associated with the action named by @p sAction.
+ * @param sAction the name of the action
+ * @param shortcut the shortcut for the action
+ * @return true if successful, false otherwise
+ */
+ bool setShortcut( const QString& sAction, const KShortcut &shortcut );
+ /**
+ * Set the slot to be called when the shortcut of the action named
+ * by @p sAction is pressed.
+ * @param sAction the name of the action
+ * @param pObjSlot the receiver of the signal
+ * @param psMethodSlot the slot to receive the signal
+ * @return true if successful, false otherwise
+ */
+ bool setSlot( const QString& sAction, const QObject* pObjSlot, const char* psMethodSlot );
+
+ /**
+ * Enables or disables action @p sAction.
+ * @since 3.4
+ */
+ bool setActionEnabled( const QString& sAction, bool bEnable );
+ /**
+ * Return the label (i18n'ized short description) associated with the action named by @p sAction.
+ * @param sAction the name of the action
+ * @return the label
+ * @since 3.3
+ */
+ QString label( const QString& sAction ) const;
+
+ /**
+ * Returns the configuration group that is used to save the accelerators.
+ * @return the configuration group
+ * @see KConfig
+ */
+ const QString& configGroup() const;
+
+ /**
+ * Sets the configuration group that is used to save the accelerators.
+ * @param cg the configuration group
+ * @see KConfig
+ */
+ void setConfigGroup( const QString &cg );
+
+ /**
+ * Read all shortcuts from @p pConfig, or (if @p pConfig
+ * is zero) from the application's configuration file
+ * KGlobal::config().
+ * @param pConfig the configuration file to read from, or 0 for the application
+ * configuration file
+ * @return true if successful, false otherwise
+ */
+ bool readSettings( KConfigBase* pConfig = 0 );
+
+ /**
+ * Write the current shortcuts to @p pConfig,
+ * or (if @p pConfig is zero) to the application's
+ * configuration file.
+ * @param pConfig the configuration file to read from, or 0 for the application
+ * configuration file
+ * @return true if successful, false otherwise
+ * @since 3.1
+ */
+ bool writeSettings( KConfigBase* pConfig = 0 ) const;
+ // BCI: merge these two writeSettings methods in KDE 4.0
+ /**
+ * Write the current shortcuts to @p pConfig,
+ * or (if @p pConfig is zero) to the application's
+ * configuration file. Alternatively, if bGlobal is true, then write
+ * to kdeglobals.
+ * @param pConfig the configuration file to read from, or 0 for the application
+ * configuration file
+ * @param bGlobal if true write the configuration to the kde global settings
+ * @return true if successful, false otherwise
+ */
+ bool writeSettings( KConfigBase* pConfig, bool bGlobal ) const;
+
+ /**
+ * @internal -- this a wrapper function to
+ * KAccelActions::useFourModifierKeys().
+ */
+ static bool useFourModifierKeys();
+
+ /**
+ * @internal
+ */
+ static void blockShortcuts( bool block );
+ /**
+ * @internal
+ */
+ void disableBlocking( bool disable );
+
+ /**
+ * @internal
+ */
+ // like setEnabled(), but doesn't ungrab (see in KGlobalAccelPrivate)
+ void suspend( bool s );
+
+private:
+
+ KAccelActions& actions();
+ const KAccelActions& actions() const;
+
+ friend class KGlobalAccelPrivate;
+ friend class KAccelShortcutList;
+protected:
+ /** \internal */
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KGlobalAccelPrivate* d;
+};
+
+#endif // _KGLOBALACCEL_H_
diff --git a/kdecore/kglobalaccel_emb.h b/kdecore/kglobalaccel_emb.h
new file mode 100644
index 000000000..859a53362
--- /dev/null
+++ b/kdecore/kglobalaccel_emb.h
@@ -0,0 +1,18 @@
+#ifndef _KGLOBALACCEL_EMB_H
+#define _KGLOBALACCEL_EMB_H
+
+#include "kaccelbase.h"
+#include "kshortcut.h"
+
+class KGlobalAccelPrivate
+{
+public:
+ KGlobalAccelPrivate();
+
+ virtual void setEnabled( bool bEnabled );
+
+ virtual bool connectKey( KAccelAction&, KKeySequence );
+ virtual bool disconnectKey( KAccelAction&, KKeySequence );
+};
+
+#endif // _KGLOBALACCEL_EMB_H
diff --git a/kdecore/kglobalaccel_mac.h b/kdecore/kglobalaccel_mac.h
new file mode 100644
index 000000000..413842256
--- /dev/null
+++ b/kdecore/kglobalaccel_mac.h
@@ -0,0 +1,31 @@
+#ifndef _KGLOBALACCEL_MAC_H
+#define _KGLOBALACCEL_MAC_H
+
+#include <qwidget.h>
+
+#include "kshortcut.h"
+#include "kaccelbase.h"
+
+class KGlobalAccelPrivate: public KAccelBase
+{
+public:
+ KGlobalAccelPrivate()
+ : KAccelBase(KAccelBase::NATIVE_KEYS)
+ {}
+
+ // reimplemented pure virtuals
+ void setEnabled( bool bEnabled )
+ { Q_UNUSED(bEnabled); }
+ bool emitSignal( Signal signal )
+ { Q_UNUSED(signal); return false; }
+ bool connectKey( KAccelAction& action, const KKeyServer::Key& key)
+ { Q_UNUSED(action); Q_UNUSED(key); return false; }
+ bool connectKey( const KKeyServer::Key& key)
+ { Q_UNUSED(key); return false; }
+ bool disconnectKey( KAccelAction&, const KKeyServer::Key& key)
+ { Q_UNUSED(key); return false; }
+ bool disconnectKey( const KKeyServer::Key& )
+ { return false; }
+};
+
+#endif // _KGLOBALACCEL_EMB_H
diff --git a/kdecore/kglobalaccel_win.cpp b/kdecore/kglobalaccel_win.cpp
new file mode 100644
index 000000000..bfd389627
--- /dev/null
+++ b/kdecore/kglobalaccel_win.cpp
@@ -0,0 +1,345 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#include <qwindowdefs.h>
+#ifdef Q_WS_WIN
+
+#include "kglobalaccel_win.h"
+#include "kglobalaccel.h"
+#include "kkeyserver_x11.h"
+
+#include <qpopupmenu.h>
+#include <qregexp.h>
+#include <qwidget.h>
+#include <qmetaobject.h>
+#include <private/qucomextra_p.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kkeynative.h>
+
+//----------------------------------------------------
+
+static QValueList< KGlobalAccelPrivate* >* all_accels = 0;
+
+KGlobalAccelPrivate::KGlobalAccelPrivate()
+: KAccelBase( KAccelBase::NATIVE_KEYS )
+, m_blocked( false )
+, m_blockingDisabled( false )
+{
+ if( all_accels == NULL )
+ all_accels = new QValueList< KGlobalAccelPrivate* >;
+ all_accels->append( this );
+ m_sConfigGroup = "Global Shortcuts";
+// kapp->installX11EventFilter( this );
+}
+
+KGlobalAccelPrivate::~KGlobalAccelPrivate()
+{
+ // TODO: Need to release all grabbed keys if the main window is not shutting down.
+ //for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
+ // const CodeMod& codemod = it.key();
+ //}
+ all_accels->remove( this );
+ if( all_accels->count() == 0 ) {
+ delete all_accels;
+ all_accels = NULL;
+ }
+}
+
+void KGlobalAccelPrivate::setEnabled( bool bEnable )
+{
+ m_bEnabled = bEnable;
+ //updateConnections();
+}
+
+void KGlobalAccelPrivate::blockShortcuts( bool block )
+{
+ if( all_accels == NULL )
+ return;
+ for( QValueList< KGlobalAccelPrivate* >::ConstIterator it = all_accels->begin();
+ it != all_accels->end();
+ ++it ) {
+ if( (*it)->m_blockingDisabled )
+ continue;
+ (*it)->m_blocked = block;
+ (*it)->updateConnections();
+ }
+}
+
+void KGlobalAccelPrivate::disableBlocking( bool block )
+{
+ m_blockingDisabled = block;
+}
+
+bool KGlobalAccelPrivate::isEnabledInternal() const
+{
+ return KAccelBase::isEnabled() && !m_blocked;
+}
+
+bool KGlobalAccelPrivate::emitSignal( Signal )
+{
+ return false;
+}
+
+bool KGlobalAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
+ { return grabKey( key, true, &action ); }
+bool KGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
+ { return grabKey( key, true, 0 ); }
+bool KGlobalAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
+ { return grabKey( key, false, &action ); }
+bool KGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
+ { return grabKey( key, false, 0 ); }
+
+bool KGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, KAccelAction* pAction )
+{
+ /*
+ if( !key.code() ) {
+ kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
+ return false;
+ }
+
+ // Make sure that grab masks have been initialized.
+ if( g_keyModMaskXOnOrOff == 0 )
+ calculateGrabMasks();
+
+ uchar keyCodeX = key.code();
+ uint keyModX = key.mod() & g_keyModMaskXAccel; // Get rid of any non-relevant bits in mod
+ // HACK: make Alt+Print work
+ if( key.sym() == XK_Sys_Req ) {
+ keyModX |= KKeyServer::modXAlt();
+ keyCodeX = 111;
+ }
+
+ kdDebug(125) << QString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
+ .arg( key.key().toStringInternal() ).arg( bGrab )
+ .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 );
+ if( !keyCodeX )
+ return false;
+
+ // We'll have to grab 8 key modifier combinations in order to cover all
+ // combinations of CapsLock, NumLock, ScrollLock.
+ // Does anyone with more X-savvy know how to set a mask on qt_xrootwin so that
+ // the irrelevant bits are always ignored and we can just make one XGrabKey
+ // call per accelerator? -- ellis
+#ifndef NDEBUG
+ QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
+#endif
+ uint keyModMaskX = ~g_keyModMaskXOnOrOff;
+ for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
+ if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
+#ifndef NDEBUG
+ sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
+#endif
+ if( bGrab )
+ XGrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask,
+ qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
+ else
+ XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin() );
+ }
+ }
+#ifndef NDEBUG
+ kdDebug(125) << sDebug << endl;
+#endif
+
+ bool failed = false;
+ if( bGrab ) {
+#ifdef Q_WS_X11
+ failed = handler.error( true ); // sync now
+#endif
+ // If grab failed, then ungrab any grabs that could possibly succeed
+ if( failed ) {
+ kdDebug(125) << "grab failed!\n";
+ for( uint m = 0; m <= 0xff; m++ ) {
+ if( m & keyModMaskX == 0 )
+ XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | m, qt_xrootwin() );
+ }
+ }
+ }
+ if( !failed )
+ {
+ CodeMod codemod;
+ codemod.code = keyCodeX;
+ codemod.mod = keyModX;
+ if( key.mod() & KKeyServer::MODE_SWITCH )
+ codemod.mod |= KKeyServer::MODE_SWITCH;
+
+ if( bGrab )
+ m_rgCodeModToAction.insert( codemod, pAction );
+ else
+ m_rgCodeModToAction.remove( codemod );
+ }
+ return !failed;*/
+ return false;
+}
+
+/*bool KGlobalAccelPrivate::x11Event( XEvent* pEvent )
+{
+ //kdDebug(125) << "x11EventFilter( type = " << pEvent->type << " )" << endl;
+ switch( pEvent->type ) {
+ case MappingNotify:
+ XRefreshKeyboardMapping( &pEvent->xmapping );
+ x11MappingNotify();
+ return false;
+ case XKeyPress:
+ if( x11KeyPress( pEvent ) )
+ return true;
+ default:
+ return QWidget::x11Event( pEvent );
+ }
+}
+
+void KGlobalAccelPrivate::x11MappingNotify()
+{
+ kdDebug(125) << "KGlobalAccelPrivate::x11MappingNotify()" << endl;
+ if( m_bEnabled ) {
+ // Maybe the X modifier map has been changed.
+ KKeyServer::initializeMods();
+ calculateGrabMasks();
+ // Do new XGrabKey()s.
+ updateConnections();
+ }
+}
+
+bool KGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
+{
+ // do not change this line unless you really really know what you are doing (Matthias)
+ if ( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget() ) {
+ XUngrabKeyboard( qt_xdisplay(), pEvent->xkey.time );
+ XFlush( qt_xdisplay()); // avoid X(?) bug
+ }
+
+ if( !m_bEnabled )
+ return false;
+
+ CodeMod codemod;
+ codemod.code = pEvent->xkey.keycode;
+ codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
+
+ // If numlock is active and a keypad key is pressed, XOR the SHIFT state.
+ // e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left.
+ if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
+ // TODO: what's the xor operator in c++?
+ uint sym = XKeycodeToKeysym( qt_xdisplay(), codemod.code, 0 );
+ // If this is a keypad key,
+ if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
+ switch( sym ) {
+ // Leave the following keys unaltered
+ // FIXME: The proper solution is to see which keysyms don't change when shifted.
+ case XK_KP_Multiply:
+ case XK_KP_Add:
+ case XK_KP_Subtract:
+ case XK_KP_Divide:
+ break;
+ default:
+ if( codemod.mod & KKeyServer::modXShift() )
+ codemod.mod &= ~KKeyServer::modXShift();
+ else
+ codemod.mod |= KKeyServer::modXShift();
+ }
+ }
+ }
+
+ KKeyNative keyNative( pEvent );
+ KKey key = keyNative;
+
+ kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
+ << QString( " keyCodeX: %1 state: %2 keyModX: %3" )
+ .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 ) << endl;
+
+ // Search for which accelerator activated this event:
+ if( !m_rgCodeModToAction.contains( codemod ) ) {
+#ifndef NDEBUG
+ for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
+ KAccelAction* pAction = *it;
+ kdDebug(125) << "\tcode: " << QString::number(it.key().code, 16) << " mod: " << QString::number(it.key().mod, 16)
+ << (pAction ? QString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : QString::null)
+ << endl;
+ }
+#endif
+ return false;
+ }
+ KAccelAction* pAction = m_rgCodeModToAction[codemod];
+
+ if( !pAction ) {
+ static bool recursion_block = false;
+ if( !recursion_block ) {
+ recursion_block = true;
+ QPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
+ connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)) );
+ pMenu->exec( QPoint( 0, 0 ) );
+ disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
+ delete pMenu;
+ recursion_block = false;
+ }
+ } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
+ return false;
+ else
+ activate( pAction, KKeySequence(key) );
+
+ return true;
+}*/
+
+void KGlobalAccelPrivate::activate( KAccelAction* pAction, const KKeySequence& seq )
+{
+ kdDebug(125) << "KGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
+
+ QRegExp rexPassIndex( "([ ]*int[ ]*)" );
+ QRegExp rexPassInfo( " QString" );
+ QRegExp rexIndex( " ([0-9]+)$" );
+
+ // If the slot to be called accepts an integer index
+ // and an index is present at the end of the action's name,
+ // then send the slot the given index #.
+ if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
+ int n = rexIndex.cap(1).toInt();
+ kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
+ int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
+ if( slot_id >= 0 ) {
+ QUObject o[2];
+ static_QUType_int.set(o+1,n);
+ const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
+ }
+ } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
+ int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
+ if( slot_id >= 0 ) {
+ QUObject o[4];
+ static_QUType_QString.set(o+1,pAction->name());
+ static_QUType_QString.set(o+2,pAction->label());
+ static_QUType_ptr.set(o+3,&seq);
+ const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
+ }
+ } else {
+ int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
+ if( slot_id >= 0 )
+ const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, 0 );
+ }
+}
+
+void KGlobalAccelPrivate::slotActivated( int iAction )
+{
+ KAccelAction* pAction = actions().actionPtr( iAction );
+ if( pAction )
+ activate( pAction, KKeySequence() );
+}
+
+#include "kglobalaccel_win.moc"
+
+#endif // !Q_WS_WIN
diff --git a/kdecore/kglobalaccel_win.h b/kdecore/kglobalaccel_win.h
new file mode 100644
index 000000000..d711115cd
--- /dev/null
+++ b/kdecore/kglobalaccel_win.h
@@ -0,0 +1,77 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KGLOBALACCEL_WIN_H
+#define _KGLOBALACCEL_WIN_H
+
+#include <qmap.h>
+#include <qwidget.h>
+
+#include "kaccelbase.h"
+#include "kkeyserver.h"
+#include "kshortcut.h"
+
+/**
+ * @internal
+ */
+class KGlobalAccelPrivate : public QWidget, public KAccelBase
+{
+ friend class KGlobalAccel;
+ Q_OBJECT
+ public:
+ KGlobalAccelPrivate();
+ virtual ~KGlobalAccelPrivate();
+
+ virtual void setEnabled( bool bEnabled );
+
+ virtual bool emitSignal( Signal signal );
+ virtual bool connectKey( KAccelAction& action, const KKeyServer::Key& key );
+ virtual bool connectKey( const KKeyServer::Key& key );
+ virtual bool disconnectKey( KAccelAction& action, const KKeyServer::Key& key );
+ virtual bool disconnectKey( const KKeyServer::Key& key );
+
+ protected:
+
+ /**
+ * @param bGrab Set to true to grab key, false to ungrab key.
+ */
+ bool grabKey( const KKeyServer::Key&, bool bGrab, KAccelAction* );
+
+ /**
+ * Filters X11 events ev for key bindings in the accelerator dictionary.
+ * If a match is found the activated activated is emitted and the function
+ * returns true. Return false if the event is not processed.
+ *
+ * This is public for compatibility only. You do not need to call it.
+ */
+// virtual bool x11Event( XEvent* );
+// void x11MappingNotify();
+// bool x11KeyPress( const XEvent *pEvent );
+ void activate( KAccelAction* pAction, const KKeySequence& seq );
+ virtual bool isEnabledInternal() const;
+ static void blockShortcuts( bool block );
+ void disableBlocking( bool disable );
+
+ protected slots:
+ void slotActivated( int iAction );
+ bool m_blocked;
+ bool m_blockingDisabled;
+};
+
+#endif // _KGLOBALACCEL_WIN_H
diff --git a/kdecore/kglobalaccel_x11.cpp b/kdecore/kglobalaccel_x11.cpp
new file mode 100644
index 000000000..542e04361
--- /dev/null
+++ b/kdecore/kglobalaccel_x11.cpp
@@ -0,0 +1,397 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#include <qwindowdefs.h>
+#ifdef Q_WS_X11
+
+#include "kglobalaccel_x11.h"
+#include "kglobalaccel.h"
+#include "kkeyserver_x11.h"
+
+#include <qpopupmenu.h>
+#include <qregexp.h>
+#include <qwidget.h>
+#include <qmetaobject.h>
+#include <private/qucomextra_p.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kkeynative.h>
+
+#ifdef Q_WS_X11
+#include <kxerrorhandler.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <fixx11h.h>
+
+extern "C" {
+ static int XGrabErrorHandler( Display *, XErrorEvent *e ) {
+ if ( e->error_code != BadAccess ) {
+ kdWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n";
+ }
+ return 1;
+ }
+}
+
+// g_keyModMaskXAccel
+// mask of modifiers which can be used in shortcuts
+// (meta, alt, ctrl, shift)
+// g_keyModMaskXOnOrOff
+// mask of modifiers where we don't care whether they are on or off
+// (caps lock, num lock, scroll lock)
+static uint g_keyModMaskXAccel = 0;
+static uint g_keyModMaskXOnOrOff = 0;
+
+static void calculateGrabMasks()
+{
+ g_keyModMaskXAccel = KKeyServer::accelModMaskX();
+ g_keyModMaskXOnOrOff =
+ KKeyServer::modXLock() |
+ KKeyServer::modXNumLock() |
+ KKeyServer::modXScrollLock() |
+ KKeyServer::modXModeSwitch();
+ //kdDebug() << "g_keyModMaskXAccel = " << g_keyModMaskXAccel
+ // << "g_keyModMaskXOnOrOff = " << g_keyModMaskXOnOrOff << endl;
+}
+
+//----------------------------------------------------
+
+static QValueList< KGlobalAccelPrivate* >* all_accels = 0;
+
+KGlobalAccelPrivate::KGlobalAccelPrivate()
+: KAccelBase( KAccelBase::NATIVE_KEYS )
+, m_blocked( false )
+, m_blockingDisabled( false )
+, m_suspended( false )
+{
+ if( all_accels == NULL )
+ all_accels = new QValueList< KGlobalAccelPrivate* >;
+ all_accels->append( this );
+ m_sConfigGroup = "Global Shortcuts";
+ kapp->installX11EventFilter( this );
+}
+
+KGlobalAccelPrivate::~KGlobalAccelPrivate()
+{
+ // TODO: Need to release all grabbed keys if the main window is not shutting down.
+ //for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
+ // const CodeMod& codemod = it.key();
+ //}
+ all_accels->remove( this );
+ if( all_accels->count() == 0 ) {
+ delete all_accels;
+ all_accels = NULL;
+ }
+}
+
+void KGlobalAccelPrivate::setEnabled( bool bEnable )
+{
+ m_bEnabled = bEnable;
+ updateConnections();
+}
+
+void KGlobalAccelPrivate::blockShortcuts( bool block )
+{
+ if( all_accels == NULL )
+ return;
+ for( QValueList< KGlobalAccelPrivate* >::ConstIterator it = all_accels->begin();
+ it != all_accels->end();
+ ++it ) {
+ if( (*it)->m_blockingDisabled )
+ continue;
+ (*it)->m_blocked = block;
+ (*it)->updateConnections();
+ }
+}
+
+void KGlobalAccelPrivate::disableBlocking( bool block )
+{
+ m_blockingDisabled = block;
+}
+
+bool KGlobalAccelPrivate::isEnabledInternal() const
+{
+ return KAccelBase::isEnabled() && !m_blocked;
+}
+
+// see #117169 - the bug is hard to reproduce, probably somewhere in X, testcase would be probably
+// difficult to make, and so on - just don't release the grabs and only ignore the events instead
+void KGlobalAccelPrivate::suspend( bool s )
+{
+ m_suspended = s;
+}
+
+bool KGlobalAccelPrivate::emitSignal( Signal )
+{
+ return false;
+}
+
+bool KGlobalAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
+ { return grabKey( key, true, &action ); }
+bool KGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
+ { return grabKey( key, true, 0 ); }
+bool KGlobalAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
+ { return grabKey( key, false, &action ); }
+bool KGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
+ { return grabKey( key, false, 0 ); }
+
+bool KGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, KAccelAction* pAction )
+{
+ if( !key.code() ) {
+ kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
+ return false;
+ }
+
+ // Make sure that grab masks have been initialized.
+ if( g_keyModMaskXOnOrOff == 0 )
+ calculateGrabMasks();
+
+ uchar keyCodeX = key.code();
+ uint keyModX = key.mod() & g_keyModMaskXAccel; // Get rid of any non-relevant bits in mod
+ // HACK: make Alt+Print work
+ // only do this for the Xorg default keyboard keycodes,
+ // other mappings (e.g. evdev) don't need or want it
+ if( key.sym() == XK_Sys_Req && XKeycodeToKeysym( qt_xdisplay(), 111, 0 ) == XK_Print ) {
+ keyModX |= KKeyServer::modXAlt();
+ keyCodeX = 111;
+ }
+
+#ifndef __osf__
+// this crashes under Tru64 so .....
+ kdDebug(125) << QString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
+ .arg( key.key().toStringInternal() ).arg( bGrab )
+ .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 );
+#endif
+ if( !keyCodeX )
+ return false;
+
+#ifdef Q_WS_X11
+ KXErrorHandler handler( XGrabErrorHandler );
+#endif
+ // We'll have to grab 8 key modifier combinations in order to cover all
+ // combinations of CapsLock, NumLock, ScrollLock.
+ // Does anyone with more X-savvy know how to set a mask on qt_xrootwin so that
+ // the irrelevant bits are always ignored and we can just make one XGrabKey
+ // call per accelerator? -- ellis
+#ifndef NDEBUG
+ QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
+#endif
+ uint keyModMaskX = ~g_keyModMaskXOnOrOff;
+ for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
+ if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
+#ifndef NDEBUG
+ sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
+#endif
+ if( bGrab )
+ XGrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask,
+ qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
+ else
+ XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin() );
+ }
+ }
+#ifndef NDEBUG
+ kdDebug(125) << sDebug << endl;
+#endif
+
+ bool failed = false;
+ if( bGrab ) {
+#ifdef Q_WS_X11
+ failed = handler.error( true ); // sync now
+#endif
+ // If grab failed, then ungrab any grabs that could possibly succeed
+ if( failed ) {
+ kdDebug(125) << "grab failed!\n";
+ for( uint m = 0; m <= 0xff; m++ ) {
+ if(( m & keyModMaskX ) == 0 )
+ XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | m, qt_xrootwin() );
+ }
+ }
+ }
+ if( !failed )
+ {
+ CodeMod codemod;
+ codemod.code = keyCodeX;
+ codemod.mod = keyModX;
+ if( key.mod() & KKeyServer::MODE_SWITCH )
+ codemod.mod |= KKeyServer::MODE_SWITCH;
+
+ if( bGrab )
+ m_rgCodeModToAction.insert( codemod, pAction );
+ else
+ m_rgCodeModToAction.remove( codemod );
+ }
+ return !failed;
+}
+
+bool KGlobalAccelPrivate::x11Event( XEvent* pEvent )
+{
+ //kdDebug(125) << "x11EventFilter( type = " << pEvent->type << " )" << endl;
+ switch( pEvent->type ) {
+ case MappingNotify:
+ XRefreshKeyboardMapping( &pEvent->xmapping );
+ x11MappingNotify();
+ return false;
+ case XKeyPress:
+ if( x11KeyPress( pEvent ) )
+ return true;
+ default:
+ return QWidget::x11Event( pEvent );
+ }
+}
+
+void KGlobalAccelPrivate::x11MappingNotify()
+{
+ kdDebug(125) << "KGlobalAccelPrivate::x11MappingNotify()" << endl;
+ // Maybe the X modifier map has been changed.
+ KKeyServer::initializeMods();
+ calculateGrabMasks();
+ // Do new XGrabKey()s.
+ updateConnections();
+}
+
+bool KGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
+{
+ // do not change this line unless you really really know what you are doing (Matthias)
+ if ( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget() ) {
+ XUngrabKeyboard( qt_xdisplay(), pEvent->xkey.time );
+ XFlush( qt_xdisplay()); // avoid X(?) bug
+ }
+
+ if( !isEnabledInternal() || m_suspended )
+ return false;
+
+ CodeMod codemod;
+ codemod.code = pEvent->xkey.keycode;
+ codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
+
+ // If numlock is active and a keypad key is pressed, XOR the SHIFT state.
+ // e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left.
+ if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
+ // TODO: what's the xor operator in c++?
+ uint sym = XKeycodeToKeysym( qt_xdisplay(), codemod.code, 0 );
+ // If this is a keypad key,
+ if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
+ switch( sym ) {
+ // Leave the following keys unaltered
+ // FIXME: The proper solution is to see which keysyms don't change when shifted.
+ case XK_KP_Multiply:
+ case XK_KP_Add:
+ case XK_KP_Subtract:
+ case XK_KP_Divide:
+ break;
+ default:
+ if( codemod.mod & KKeyServer::modXShift() )
+ codemod.mod &= ~KKeyServer::modXShift();
+ else
+ codemod.mod |= KKeyServer::modXShift();
+ }
+ }
+ }
+
+ KKeyNative keyNative( pEvent );
+ KKey key = keyNative;
+
+ kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
+ << QString( " keyCodeX: %1 state: %2 keyModX: %3" )
+ .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 ) << endl;
+
+ // Search for which accelerator activated this event:
+ if( !m_rgCodeModToAction.contains( codemod ) ) {
+#ifndef NDEBUG
+ for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
+ KAccelAction* pAction = *it;
+ kdDebug(125) << "\tcode: " << QString::number(it.key().code, 16) << " mod: " << QString::number(it.key().mod, 16)
+ << (pAction ? QString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : QString::null)
+ << endl;
+ }
+#endif
+ return false;
+ }
+
+ KAccelAction* pAction = m_rgCodeModToAction[codemod];
+
+ if( !pAction ) {
+ static bool recursion_block = false;
+ if( !recursion_block ) {
+ recursion_block = true;
+ QPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
+ connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)) );
+ pMenu->exec( QPoint( 0, 0 ) );
+ disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
+ delete pMenu;
+ recursion_block = false;
+ }
+ } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
+ return false;
+ else
+ activate( pAction, KKeySequence(key) );
+
+ return true;
+}
+
+void KGlobalAccelPrivate::activate( KAccelAction* pAction, const KKeySequence& seq )
+{
+ kdDebug(125) << "KGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
+
+ QRegExp rexPassIndex( "([ ]*int[ ]*)" );
+ QRegExp rexPassInfo( " QString" );
+ QRegExp rexIndex( " ([0-9]+)$" );
+
+ // If the slot to be called accepts an integer index
+ // and an index is present at the end of the action's name,
+ // then send the slot the given index #.
+ if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
+ int n = rexIndex.cap(1).toInt();
+ kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
+ int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
+ if( slot_id >= 0 ) {
+ QUObject o[2];
+ static_QUType_int.set(o+1,n);
+ const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
+ }
+ } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
+ int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
+ if( slot_id >= 0 ) {
+ QUObject o[4];
+ static_QUType_QString.set(o+1,pAction->name());
+ static_QUType_QString.set(o+2,pAction->label());
+ static_QUType_ptr.set(o+3,&seq);
+ const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
+ }
+ } else {
+ int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
+ if( slot_id >= 0 )
+ const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, 0 );
+ }
+}
+
+void KGlobalAccelPrivate::slotActivated( int iAction )
+{
+ KAccelAction* pAction = actions().actionPtr( iAction );
+ if( pAction )
+ activate( pAction, KKeySequence() );
+}
+
+#include "kglobalaccel_x11.moc"
+
+#endif // !Q_WS_X11
diff --git a/kdecore/kglobalaccel_x11.h b/kdecore/kglobalaccel_x11.h
new file mode 100644
index 000000000..9c80a1535
--- /dev/null
+++ b/kdecore/kglobalaccel_x11.h
@@ -0,0 +1,109 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KGLOBALACCEL_X11_H
+#define _KGLOBALACCEL_X11_H
+
+#include <qmap.h>
+#include <qwidget.h>
+
+#include "kaccelbase.h"
+#include "kkeyserver_x11.h"
+#include "kshortcut.h"
+
+/**
+ * @internal
+ */
+class KGlobalAccelPrivate : public QWidget, public KAccelBase
+{
+ friend class KGlobalAccel;
+ Q_OBJECT
+ public:
+ KGlobalAccelPrivate();
+ virtual ~KGlobalAccelPrivate();
+
+ virtual void setEnabled( bool bEnabled );
+
+ virtual bool emitSignal( Signal signal );
+ virtual bool connectKey( KAccelAction& action, const KKeyServer::Key& key );
+ virtual bool connectKey( const KKeyServer::Key& key );
+ virtual bool disconnectKey( KAccelAction& action, const KKeyServer::Key& key );
+ virtual bool disconnectKey( const KKeyServer::Key& key );
+
+ protected:
+ /**
+ * @internal
+ * Represents a key code and modifier combination.
+ */
+ class CodeMod
+ {
+ public:
+ /**
+ * The key code of the CodeMod.
+ */
+ uchar code;
+ /**
+ * The modifier flags of the CodeMod.
+ */
+ uint mod;
+
+ /**
+ * Compares two CodeMods.
+ */
+ bool operator < ( const CodeMod& b ) const
+ {
+ if( code < b.code ) return true;
+ if( code == b.code && mod < b.mod ) return true;
+ return false;
+ }
+ };
+ typedef QMap<CodeMod, KAccelAction*> CodeModMap;
+
+ CodeModMap m_rgCodeModToAction;
+
+ /**
+ * @param bGrab Set to true to grab key, false to ungrab key.
+ */
+ bool grabKey( const KKeyServer::Key&, bool bGrab, KAccelAction* );
+
+ /**
+ * Filters X11 events ev for key bindings in the accelerator dictionary.
+ * If a match is found the activated activated is emitted and the function
+ * returns true. Return false if the event is not processed.
+ *
+ * This is public for compatibility only. You do not need to call it.
+ */
+ virtual bool x11Event( XEvent* );
+ void x11MappingNotify();
+ bool x11KeyPress( const XEvent *pEvent );
+ void activate( KAccelAction* pAction, const KKeySequence& seq );
+ virtual bool isEnabledInternal() const;
+ static void blockShortcuts( bool block );
+ void disableBlocking( bool disable );
+ void suspend( bool s );
+
+ protected slots:
+ void slotActivated( int iAction );
+ private:
+ bool m_blocked;
+ bool m_blockingDisabled;
+ bool m_suspended;
+};
+
+#endif // _KGLOBALACCEL_X11_H
diff --git a/kdecore/kglobalsettings.cpp b/kdecore/kglobalsettings.cpp
new file mode 100644
index 000000000..b5539fb22
--- /dev/null
+++ b/kdecore/kglobalsettings.cpp
@@ -0,0 +1,730 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "config.h"
+#include "kglobalsettings.h"
+
+#include <qdir.h>
+#include <qpixmap.h>
+#include <qfontdatabase.h>
+#include <qcursor.h>
+
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <kapplication.h>
+
+#include <kipc.h>
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+#include "qt_windows.h"
+#include <win32_utils.h>
+static QRgb qt_colorref2qrgb(COLORREF col)
+{
+ return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
+}
+#endif
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kshortcut.h>
+#include <kstandarddirs.h>
+#include <kcharsets.h>
+#include <kaccel.h>
+#include <klocale.h>
+#include <qfontinfo.h>
+#include <stdlib.h>
+#include <kprotocolinfo.h>
+
+#ifdef Q_WS_X11
+#include <X11/Xlib.h>
+#endif
+
+QString* KGlobalSettings::s_desktopPath = 0;
+QString* KGlobalSettings::s_autostartPath = 0;
+QString* KGlobalSettings::s_trashPath = 0;
+QString* KGlobalSettings::s_documentPath = 0;
+QFont *KGlobalSettings::_generalFont = 0;
+QFont *KGlobalSettings::_fixedFont = 0;
+QFont *KGlobalSettings::_toolBarFont = 0;
+QFont *KGlobalSettings::_menuFont = 0;
+QFont *KGlobalSettings::_windowTitleFont = 0;
+QFont *KGlobalSettings::_taskbarFont = 0;
+QFont *KGlobalSettings::_largeFont = 0;
+QColor *KGlobalSettings::_kde34Blue = 0;
+QColor *KGlobalSettings::_inactiveBackground = 0;
+QColor *KGlobalSettings::_inactiveForeground = 0;
+QColor *KGlobalSettings::_activeBackground = 0;
+QColor *KGlobalSettings::_buttonBackground = 0;
+QColor *KGlobalSettings::_selectBackground = 0;
+QColor *KGlobalSettings::_linkColor = 0;
+QColor *KGlobalSettings::_visitedLinkColor = 0;
+QColor *KGlobalSettings::alternateColor = 0;
+
+KGlobalSettings::KMouseSettings *KGlobalSettings::s_mouseSettings = 0;
+
+int KGlobalSettings::dndEventDelay()
+{
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readNumEntry("StartDragDist", QApplication::startDragDistance());
+}
+
+bool KGlobalSettings::singleClick()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readBoolEntry("SingleClick", KDE_DEFAULT_SINGLECLICK);
+}
+
+KGlobalSettings::TearOffHandle KGlobalSettings::insertTearOffHandle()
+{
+ int tearoff;
+ bool effectsenabled;
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ effectsenabled = g.readBoolEntry( "EffectsEnabled", false);
+ tearoff = g.readNumEntry("InsertTearOffHandle", KDE_DEFAULT_INSERTTEAROFFHANDLES);
+ return effectsenabled ? (TearOffHandle) tearoff : Disable;
+}
+
+bool KGlobalSettings::changeCursorOverIcon()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readBoolEntry("ChangeCursor", KDE_DEFAULT_CHANGECURSOR);
+}
+
+bool KGlobalSettings::visualActivate()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readBoolEntry("VisualActivate", KDE_DEFAULT_VISUAL_ACTIVATE);
+}
+
+unsigned int KGlobalSettings::visualActivateSpeed()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return
+ g.readNumEntry(
+ "VisualActivateSpeed",
+ KDE_DEFAULT_VISUAL_ACTIVATE_SPEED
+ );
+}
+
+
+
+int KGlobalSettings::autoSelectDelay()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readNumEntry("AutoSelectDelay", KDE_DEFAULT_AUTOSELECTDELAY);
+}
+
+KGlobalSettings::Completion KGlobalSettings::completionMode()
+{
+ int completion;
+ KConfigGroup g( KGlobal::config(), "General" );
+ completion = g.readNumEntry("completionMode", -1);
+ if ((completion < (int) CompletionNone) ||
+ (completion > (int) CompletionPopupAuto))
+ {
+ completion = (int) CompletionPopup; // Default
+ }
+ return (Completion) completion;
+}
+
+bool KGlobalSettings::showContextMenusOnPress ()
+{
+ KConfigGroup g(KGlobal::config(), "ContextMenus");
+ return g.readBoolEntry("ShowOnPress", true);
+}
+
+int KGlobalSettings::contextMenuKey ()
+{
+ KConfigGroup g(KGlobal::config(), "Shortcuts");
+ KShortcut cut (g.readEntry ("PopupMenuContext", "Menu"));
+ return cut.keyCodeQt();
+}
+
+QColor KGlobalSettings::toolBarHighlightColor()
+{
+ initColors();
+ KConfigGroup g( KGlobal::config(), "Toolbar style" );
+ return g.readColorEntry("HighlightColor", _kde34Blue);
+}
+
+QColor KGlobalSettings::inactiveTitleColor()
+{
+#ifdef Q_WS_WIN
+ return qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION));
+#else
+ if (!_inactiveBackground)
+ _inactiveBackground = new QColor(157, 170, 186);
+ KConfigGroup g( KGlobal::config(), "WM" );
+ return g.readColorEntry( "inactiveBackground", _inactiveBackground );
+#endif
+}
+
+QColor KGlobalSettings::inactiveTextColor()
+{
+#ifdef Q_WS_WIN
+ return qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT));
+#else
+ if (!_inactiveForeground)
+ _inactiveForeground = new QColor(221,221,221);
+ KConfigGroup g( KGlobal::config(), "WM" );
+ return g.readColorEntry( "inactiveForeground", _inactiveForeground );
+#endif
+}
+
+QColor KGlobalSettings::activeTitleColor()
+{
+#ifdef Q_WS_WIN
+ return qt_colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION));
+#else
+ initColors();
+ if (!_activeBackground)
+ _activeBackground = new QColor(65,142,220);
+ KConfigGroup g( KGlobal::config(), "WM" );
+ return g.readColorEntry( "activeBackground", _activeBackground);
+#endif
+}
+
+QColor KGlobalSettings::activeTextColor()
+{
+#ifdef Q_WS_WIN
+ return qt_colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT));
+#else
+ KConfigGroup g( KGlobal::config(), "WM" );
+ return g.readColorEntry( "activeForeground", &Qt::white );
+#endif
+}
+
+int KGlobalSettings::contrast()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readNumEntry( "contrast", 7 );
+}
+
+QColor KGlobalSettings::buttonBackground()
+{
+ if (!_buttonBackground)
+ _buttonBackground = new QColor(221,223,228);
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "buttonBackground", _buttonBackground );
+}
+
+QColor KGlobalSettings::buttonTextColor()
+{
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "buttonForeground", &Qt::black );
+}
+
+// IMPORTANT:
+// This function should be get in sync with
+// KApplication::kdisplaySetPalette()
+QColor KGlobalSettings::baseColor()
+{
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "windowBackground", &Qt::white );
+}
+
+// IMPORTANT:
+// This function should be get in sync with
+// KApplication::kdisplaySetPalette()
+QColor KGlobalSettings::textColor()
+{
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "windowForeground", &Qt::black );
+}
+
+// IMPORTANT:
+// This function should be get in sync with
+// KApplication::kdisplaySetPalette()
+QColor KGlobalSettings::highlightedTextColor()
+{
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "selectForeground", &Qt::white );
+}
+
+// IMPORTANT:
+// This function should be get in sync with
+// KApplication::kdisplaySetPalette()
+QColor KGlobalSettings::highlightColor()
+{
+ initColors();
+ if (!_selectBackground)
+ _selectBackground = new QColor(103,141,178);
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "selectBackground", _selectBackground );
+}
+
+QColor KGlobalSettings::alternateBackgroundColor()
+{
+ initColors();
+ KConfigGroup g( KGlobal::config(), "General" );
+ *alternateColor = calculateAlternateBackgroundColor( baseColor() );
+ return g.readColorEntry( "alternateBackground", alternateColor );
+}
+
+QColor KGlobalSettings::calculateAlternateBackgroundColor(const QColor& base)
+{
+ if (base == Qt::white)
+ return QColor(238,246,255);
+ else
+ {
+ int h, s, v;
+ base.hsv( &h, &s, &v );
+ if (v > 128)
+ return base.dark(106);
+ else if (base != Qt::black)
+ return base.light(110);
+
+ return QColor(32,32,32);
+ }
+}
+
+bool KGlobalSettings::shadeSortColumn()
+{
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readBoolEntry( "shadeSortColumn", KDE_DEFAULT_SHADE_SORT_COLUMN );
+}
+
+QColor KGlobalSettings::linkColor()
+{
+ initColors();
+ if (!_linkColor)
+ _linkColor = new QColor(0,0,238);
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "linkColor", _linkColor );
+}
+
+QColor KGlobalSettings::visitedLinkColor()
+{
+ if (!_visitedLinkColor)
+ _visitedLinkColor = new QColor(82,24,139);
+ KConfigGroup g( KGlobal::config(), "General" );
+ return g.readColorEntry( "visitedLinkColor", _visitedLinkColor );
+}
+
+QFont KGlobalSettings::generalFont()
+{
+ if (_generalFont)
+ return *_generalFont;
+
+ // Sync default with kdebase/kcontrol/fonts/fonts.cpp
+ _generalFont = new QFont("Sans Serif", 10);
+ _generalFont->setPointSize(10);
+ _generalFont->setStyleHint(QFont::SansSerif);
+
+ KConfigGroup g( KGlobal::config(), "General" );
+ *_generalFont = g.readFontEntry("font", _generalFont);
+
+ return *_generalFont;
+}
+
+QFont KGlobalSettings::fixedFont()
+{
+ if (_fixedFont)
+ return *_fixedFont;
+
+ // Sync default with kdebase/kcontrol/fonts/fonts.cpp
+ _fixedFont = new QFont("Monospace", 10);
+ _fixedFont->setPointSize(10);
+ _fixedFont->setStyleHint(QFont::TypeWriter);
+
+ KConfigGroup g( KGlobal::config(), "General" );
+ *_fixedFont = g.readFontEntry("fixed", _fixedFont);
+
+ return *_fixedFont;
+}
+
+QFont KGlobalSettings::toolBarFont()
+{
+ if(_toolBarFont)
+ return *_toolBarFont;
+
+ // Sync default with kdebase/kcontrol/fonts/fonts.cpp
+ _toolBarFont = new QFont("Sans Serif", 10);
+ _toolBarFont->setPointSize(10);
+ _toolBarFont->setStyleHint(QFont::SansSerif);
+
+ KConfigGroup g( KGlobal::config(), "General" );
+ *_toolBarFont = g.readFontEntry("toolBarFont", _toolBarFont);
+
+ return *_toolBarFont;
+}
+
+QFont KGlobalSettings::menuFont()
+{
+ if(_menuFont)
+ return *_menuFont;
+
+ // Sync default with kdebase/kcontrol/fonts/fonts.cpp
+ _menuFont = new QFont("Sans Serif", 10);
+ _menuFont->setPointSize(10);
+ _menuFont->setStyleHint(QFont::SansSerif);
+
+ KConfigGroup g( KGlobal::config(), "General" );
+ *_menuFont = g.readFontEntry("menuFont", _menuFont);
+
+ return *_menuFont;
+}
+
+QFont KGlobalSettings::windowTitleFont()
+{
+ if(_windowTitleFont)
+ return *_windowTitleFont;
+
+ // Sync default with kdebase/kcontrol/fonts/fonts.cpp
+ _windowTitleFont = new QFont("Sans Serif", 9, QFont::Bold);
+ _windowTitleFont->setPointSize(10);
+ _windowTitleFont->setStyleHint(QFont::SansSerif);
+
+ KConfigGroup g( KGlobal::config(), "WM" );
+ *_windowTitleFont = g.readFontEntry("activeFont", _windowTitleFont); // inconsistency
+
+ return *_windowTitleFont;
+}
+
+QFont KGlobalSettings::taskbarFont()
+{
+ if(_taskbarFont)
+ return *_taskbarFont;
+
+ // Sync default with kdebase/kcontrol/fonts/fonts.cpp
+ _taskbarFont = new QFont("Sans Serif", 10);
+ _taskbarFont->setPointSize(10);
+ _taskbarFont->setStyleHint(QFont::SansSerif);
+
+ KConfigGroup g( KGlobal::config(), "General" );
+ *_taskbarFont = g.readFontEntry("taskbarFont", _taskbarFont);
+
+ return *_taskbarFont;
+}
+
+
+QFont KGlobalSettings::largeFont(const QString &text)
+{
+ QFontDatabase db;
+ QStringList fam = db.families();
+
+ // Move a bunch of preferred fonts to the front.
+ if (fam.remove("Arial"))
+ fam.prepend("Arial");
+ if (fam.remove("Verdana"))
+ fam.prepend("Verdana");
+ if (fam.remove("Tahoma"))
+ fam.prepend("Tahoma");
+ if (fam.remove("Lucida Sans"))
+ fam.prepend("Lucida Sans");
+ if (fam.remove("Lucidux Sans"))
+ fam.prepend("Lucidux Sans");
+ if (fam.remove("Nimbus Sans"))
+ fam.prepend("Nimbus Sans");
+ if (fam.remove("Gothic I"))
+ fam.prepend("Gothic I");
+
+ if (_largeFont)
+ fam.prepend(_largeFont->family());
+
+ for(QStringList::ConstIterator it = fam.begin();
+ it != fam.end(); ++it)
+ {
+ if (db.isSmoothlyScalable(*it) && !db.isFixedPitch(*it))
+ {
+ QFont font(*it);
+ font.setPixelSize(75);
+ QFontMetrics metrics(font);
+ int h = metrics.height();
+ if ((h < 60) || ( h > 90))
+ continue;
+
+ bool ok = true;
+ for(unsigned int i = 0; i < text.length(); i++)
+ {
+ if (!metrics.inFont(text[i]))
+ {
+ ok = false;
+ break;
+ }
+ }
+ if (!ok)
+ continue;
+
+ font.setPointSize(48);
+ _largeFont = new QFont(font);
+ return *_largeFont;
+ }
+ }
+ _largeFont = new QFont(KGlobalSettings::generalFont());
+ _largeFont->setPointSize(48);
+ return *_largeFont;
+}
+
+void KGlobalSettings::initStatic() // should be called initPaths(). Don't put anything else here.
+{
+ if ( s_desktopPath != 0 )
+ return;
+
+ s_desktopPath = new QString();
+ s_autostartPath = new QString();
+ s_trashPath = new QString();
+ s_documentPath = new QString();
+
+ KConfigGroup g( KGlobal::config(), "Paths" );
+
+ // Desktop Path
+ *s_desktopPath = QDir::homeDirPath() + "/Desktop/";
+ *s_desktopPath = g.readPathEntry( "Desktop", *s_desktopPath);
+ *s_desktopPath = QDir::cleanDirPath( *s_desktopPath );
+ if ( !s_desktopPath->endsWith("/") )
+ s_desktopPath->append('/');
+
+ // Trash Path - TODO remove in KDE4 (kio_trash can't use it for interoperability reasons)
+ *s_trashPath = *s_desktopPath + i18n("Trash") + "/";
+ *s_trashPath = g.readPathEntry( "Trash" , *s_trashPath);
+ *s_trashPath = QDir::cleanDirPath( *s_trashPath );
+ if ( !s_trashPath->endsWith("/") )
+ s_trashPath->append('/');
+ // We need to save it in any case, in case the language changes later on,
+ if ( !g.hasKey( "Trash" ) )
+ {
+ g.writePathEntry( "Trash", *s_trashPath, true, true );
+ g.sync();
+ }
+
+ // Autostart Path
+ *s_autostartPath = KGlobal::dirs()->localkdedir() + "Autostart/";
+ *s_autostartPath = g.readPathEntry( "Autostart" , *s_autostartPath);
+ *s_autostartPath = QDir::cleanDirPath( *s_autostartPath );
+ if ( !s_autostartPath->endsWith("/") )
+ s_autostartPath->append('/');
+
+ // Document Path
+ *s_documentPath = g.readPathEntry( "Documents",
+#ifdef Q_WS_WIN
+ getWin32ShellFoldersPath("Personal")
+#else
+ QDir::homeDirPath()
+#endif
+ );
+ *s_documentPath = QDir::cleanDirPath( *s_documentPath );
+ if ( !s_documentPath->endsWith("/"))
+ s_documentPath->append('/');
+
+ // Make sure this app gets the notifications about those paths
+ if (kapp)
+ kapp->addKipcEventMask(KIPC::SettingsChanged);
+}
+
+void KGlobalSettings::initColors()
+{
+ if (!_kde34Blue) {
+ if (QPixmap::defaultDepth() > 8)
+ _kde34Blue = new QColor(103,141,178);
+ else
+ _kde34Blue = new QColor(0, 0, 192);
+ }
+ if (!alternateColor)
+ alternateColor = new QColor(237, 244, 249);
+}
+
+void KGlobalSettings::rereadFontSettings()
+{
+ delete _generalFont;
+ _generalFont = 0L;
+ delete _fixedFont;
+ _fixedFont = 0L;
+ delete _menuFont;
+ _menuFont = 0L;
+ delete _toolBarFont;
+ _toolBarFont = 0L;
+ delete _windowTitleFont;
+ _windowTitleFont = 0L;
+ delete _taskbarFont;
+ _taskbarFont = 0L;
+}
+
+void KGlobalSettings::rereadPathSettings()
+{
+ kdDebug() << "KGlobalSettings::rereadPathSettings" << endl;
+ delete s_autostartPath;
+ s_autostartPath = 0L;
+ delete s_trashPath;
+ s_trashPath = 0L;
+ delete s_desktopPath;
+ s_desktopPath = 0L;
+ delete s_documentPath;
+ s_documentPath = 0L;
+}
+
+KGlobalSettings::KMouseSettings & KGlobalSettings::mouseSettings()
+{
+ if ( ! s_mouseSettings )
+ {
+ s_mouseSettings = new KMouseSettings;
+ KMouseSettings & s = *s_mouseSettings; // for convenience
+
+#ifndef Q_WS_WIN
+ KConfigGroup g( KGlobal::config(), "Mouse" );
+ QString setting = g.readEntry("MouseButtonMapping");
+ if (setting == "RightHanded")
+ s.handed = KMouseSettings::RightHanded;
+ else if (setting == "LeftHanded")
+ s.handed = KMouseSettings::LeftHanded;
+ else
+ {
+#ifdef Q_WS_X11
+ // get settings from X server
+ // This is a simplified version of the code in input/mouse.cpp
+ // Keep in sync !
+ s.handed = KMouseSettings::RightHanded;
+ unsigned char map[20];
+ int num_buttons = XGetPointerMapping(kapp->getDisplay(), map, 20);
+ if( num_buttons == 2 )
+ {
+ if ( (int)map[0] == 1 && (int)map[1] == 2 )
+ s.handed = KMouseSettings::RightHanded;
+ else if ( (int)map[0] == 2 && (int)map[1] == 1 )
+ s.handed = KMouseSettings::LeftHanded;
+ }
+ else if( num_buttons >= 3 )
+ {
+ if ( (int)map[0] == 1 && (int)map[2] == 3 )
+ s.handed = KMouseSettings::RightHanded;
+ else if ( (int)map[0] == 3 && (int)map[2] == 1 )
+ s.handed = KMouseSettings::LeftHanded;
+ }
+#else
+ // FIXME(E): Implement in Qt Embedded
+#endif
+ }
+#endif //Q_WS_WIN
+ }
+#ifdef Q_WS_WIN
+ //not cached
+ s_mouseSettings->handed = (GetSystemMetrics(SM_SWAPBUTTON) ? KMouseSettings::LeftHanded : KMouseSettings::RightHanded);
+#endif
+ return *s_mouseSettings;
+}
+
+void KGlobalSettings::rereadMouseSettings()
+{
+#ifndef Q_WS_WIN
+ delete s_mouseSettings;
+ s_mouseSettings = 0L;
+#endif
+}
+
+bool KGlobalSettings::isMultiHead()
+{
+#ifdef Q_WS_WIN
+ return GetSystemMetrics(SM_CMONITORS) > 1;
+#else
+ QCString multiHead = getenv("KDE_MULTIHEAD");
+ if (!multiHead.isEmpty()) {
+ return (multiHead.lower() == "true");
+ }
+ return false;
+#endif
+}
+
+bool KGlobalSettings::wheelMouseZooms()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readBoolEntry( "WheelMouseZooms", KDE_DEFAULT_WHEEL_ZOOM );
+}
+
+QRect KGlobalSettings::splashScreenDesktopGeometry()
+{
+ QDesktopWidget *dw = QApplication::desktop();
+
+ if (dw->isVirtualDesktop()) {
+ KConfigGroup group(KGlobal::config(), "Windows");
+ int scr = group.readNumEntry("Unmanaged", -3);
+ if (group.readBoolEntry("XineramaEnabled", true) && scr != -2) {
+ if (scr == -3)
+ scr = dw->screenNumber(QCursor::pos());
+ return dw->screenGeometry(scr);
+ } else {
+ return dw->geometry();
+ }
+ } else {
+ return dw->geometry();
+ }
+}
+
+QRect KGlobalSettings::desktopGeometry(const QPoint& point)
+{
+ QDesktopWidget *dw = QApplication::desktop();
+
+ if (dw->isVirtualDesktop()) {
+ KConfigGroup group(KGlobal::config(), "Windows");
+ if (group.readBoolEntry("XineramaEnabled", true) &&
+ group.readBoolEntry("XineramaPlacementEnabled", true)) {
+ return dw->screenGeometry(dw->screenNumber(point));
+ } else {
+ return dw->geometry();
+ }
+ } else {
+ return dw->geometry();
+ }
+}
+
+QRect KGlobalSettings::desktopGeometry(QWidget* w)
+{
+ QDesktopWidget *dw = QApplication::desktop();
+
+ if (dw->isVirtualDesktop()) {
+ KConfigGroup group(KGlobal::config(), "Windows");
+ if (group.readBoolEntry("XineramaEnabled", true) &&
+ group.readBoolEntry("XineramaPlacementEnabled", true)) {
+ if (w)
+ return dw->screenGeometry(dw->screenNumber(w));
+ else return dw->screenGeometry(-1);
+ } else {
+ return dw->geometry();
+ }
+ } else {
+ return dw->geometry();
+ }
+}
+
+bool KGlobalSettings::showIconsOnPushButtons()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readBoolEntry("ShowIconsOnPushButtons",
+ KDE_DEFAULT_ICON_ON_PUSHBUTTON);
+}
+
+bool KGlobalSettings::showFilePreview(const KURL &url)
+{
+ KConfigGroup g(KGlobal::config(), "PreviewSettings");
+ QString protocol = url.protocol();
+ bool defaultSetting = KProtocolInfo::showFilePreview( protocol );
+ return g.readBoolEntry(protocol, defaultSetting );
+}
+
+bool KGlobalSettings::opaqueResize()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readBoolEntry("OpaqueResize",
+ KDE_DEFAULT_OPAQUE_RESIZE);
+}
+
+int KGlobalSettings::buttonLayout()
+{
+ KConfigGroup g( KGlobal::config(), "KDE" );
+ return g.readNumEntry("ButtonLayout",
+ KDE_DEFAULT_BUTTON_LAYOUT);
+}
diff --git a/kdecore/kglobalsettings.h b/kdecore/kglobalsettings.h
new file mode 100644
index 000000000..4f5977bd2
--- /dev/null
+++ b/kdecore/kglobalsettings.h
@@ -0,0 +1,566 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KGLOBALSETTINGS_H
+#define _KGLOBALSETTINGS_H
+
+#include <qstring.h>
+#include <qcolor.h>
+#include <qfont.h>
+#include "kdelibs_export.h"
+
+#define KDE_DEFAULT_SINGLECLICK true
+#define KDE_DEFAULT_INSERTTEAROFFHANDLES 0
+#define KDE_DEFAULT_AUTOSELECTDELAY -1
+#define KDE_DEFAULT_CHANGECURSOR true
+#define KDE_DEFAULT_LARGE_CURSOR false
+#define KDE_DEFAULT_VISUAL_ACTIVATE true
+#define KDE_DEFAULT_VISUAL_ACTIVATE_SPEED 50
+#define KDE_DEFAULT_WHEEL_ZOOM false
+#define KDE_DEFAULT_ICON_ON_PUSHBUTTON false
+#define KDE_DEFAULT_OPAQUE_RESIZE true
+#define KDE_DEFAULT_BUTTON_LAYOUT 0
+#define KDE_DEFAULT_SHADE_SORT_COLUMN true
+
+class KURL;
+
+/**
+ * Access the KDE global configuration.
+ *
+ * @author David Faure <faure@kde.org>
+ */
+class KDECORE_EXPORT KGlobalSettings
+{
+ public:
+
+ /**
+ * Returns a threshold in pixels for drag & drop operations.
+ * As long as the mouse movement has not exceeded this number
+ * of pixels in either X or Y direction no drag operation may
+ * be started. This prevents spurious drags when the user intended
+ * to click on something but moved the mouse a bit while doing so.
+ *
+ * For this to work you must save the position of the mouse (oldPos)
+ * in the QWidget::mousePressEvent().
+ * When the position of the mouse (newPos)
+ * in a QWidget::mouseMoveEvent() exceeds this threshold
+ * you may start a drag
+ * which should originate from oldPos.
+ *
+ * Example code:
+ * \code
+ * void KColorCells::mousePressEvent( QMouseEvent *e )
+ * {
+ * mOldPos = e->pos();
+ * }
+ *
+ * void KColorCells::mouseMoveEvent( QMouseEvent *e )
+ * {
+ * if( !(e->state() && LeftButton)) return;
+ *
+ * int delay = KGlobalSettings::dndEventDelay();
+ * QPoint newPos = e->pos();
+ * if(newPos.x() > mOldPos.x()+delay || newPos.x() < mOldPos.x()-delay ||
+ * newPos.y() > mOldPos.y()+delay || newPos.y() < mOldPos.y()-delay)
+ * {
+ * // Drag color object
+ * int cell = posToCell(mOldPos); // Find color at mOldPos
+ * if ((cell != -1) && colors[cell].isValid())
+ * {
+ * KColorDrag *d = KColorDrag::makeDrag( colors[cell], this);
+ * d->dragCopy();
+ * }
+ * }
+ * }
+ * \endcode
+ * @return the threshold for drag & drop in pixels
+ */
+
+ static int dndEventDelay();
+
+ /**
+ * Returns whether KDE runs in single (default) or double click
+ * mode.
+ * see http://developer.kde.org/documentation/standards/kde/style/mouse/index.html
+ * @return true if single click mode, or false if double click mode.
+ **/
+ static bool singleClick();
+
+ /**
+ * This enum describes the return type for insertTearOffHandle() whether to insert
+ * a handle or not. Applications who independently want to use handles in their popup menus
+ * should test for Application level before calling the appropriate function in KPopupMenu.
+ * @since 3.1
+ **/
+ enum TearOffHandle {
+ Disable = 0, ///< disable tear-off handles
+ ApplicationLevel, ///< enable on application level
+ Enable ///< enable tear-off handles
+ };
+
+ /**
+ * Returns whether tear-off handles are inserted in KPopupMenus.
+ * @return whether tear-off handles are inserted in KPopupMenus.
+ * @since 3.1
+ **/
+ static TearOffHandle insertTearOffHandle();
+
+ /**
+ * Checks whether the cursor changes over icons.
+ * @return the KDE setting for "change cursor over icon"
+ */
+ static bool changeCursorOverIcon();
+
+ /**
+ * Checks whether to show feedback when in item (specifically an
+ * icon) is activated.
+ * @return whether to show some feedback when an item is activated.
+ */
+ static bool visualActivate();
+
+ /**
+ * Returns the speed of the visual activation feedback.
+ * @return the speed of the visual activation feedback, between
+ * 0 for minimum and 100 for maximum speed
+ */
+ static unsigned int visualActivateSpeed();
+
+ /**
+ * Returns the KDE setting for the auto-select option.
+ *
+ * @return the auto-select delay or -1 if auto-select is disabled.
+ */
+ static int autoSelectDelay();
+
+ /**
+ * Returns the KDE setting for the shortcut key to open
+ * context menus.
+ *
+ * @return the key that pops up context menus.
+ */
+ static int contextMenuKey ();
+
+ /**
+ * Returns the KDE setting for context menus.
+ *
+ * @return whether context menus should be shown on button press
+ * or button release (click).
+ */
+ static bool showContextMenusOnPress ();
+
+ /**
+ * This enum describes the completion mode used for by the KCompletion class.
+ * See <a href="http://developer.kde.org/documentation/standards/kde/style/keys/completion.html">
+ * the styleguide</a>.
+ **/
+ enum Completion {
+ /**
+ * No completion is used.
+ */
+ CompletionNone=1,
+ /**
+ * Text is automatically filled in whenever possible.
+ */
+ CompletionAuto,
+ /**
+ * Same as automatic except shortest match is used for completion.
+ */
+ CompletionMan,
+ /**
+ * Complete text much in the same way as a typical *nix shell would.
+ */
+ CompletionShell,
+ /**
+ * Lists all possible matches in a popup list-box to choose from.
+ */
+ CompletionPopup,
+ /**
+ * Lists all possible matches in a popup list-box to choose from, and automatically
+ * fill the result whenever possible.
+ */
+ CompletionPopupAuto
+ };
+
+ /**
+ * Returns the preferred completion mode setting.
+ *
+ * @return Completion. Default is @p CompletionPopup.
+ */
+ static Completion completionMode();
+
+ /**
+ * Describes the mouse settings.
+ */
+ struct KMouseSettings
+ {
+ enum { RightHanded = 0, LeftHanded = 1 };
+ int handed; // left or right
+ };
+
+ /**
+ * This returns the current mouse settings.
+ * On Windows, settings are retrieved from the system.
+ * @return the current mouse settings
+ */
+ static KMouseSettings & mouseSettings();
+
+ /**
+ * The path to the desktop directory of the current user.
+ * @return the user's desktop directory
+ */
+ static QString desktopPath() { initStatic(); return *s_desktopPath; }
+
+ /**
+ * The path to the autostart directory of the current user.
+ * @return the path of the autostart directory
+ */
+ static QString autostartPath() { initStatic(); return *s_autostartPath; }
+
+ /**
+ * DEPRECATED (starting from kde-3.4).
+ * This isn't where the trash contents is, anymore.
+ * Use KIO::trash() to trash files, "trash:/" to list the trash contents.
+ */
+ static QString trashPath() { initStatic(); return *s_trashPath; }
+ // KDE4: if you want to remove the above, move it to kdesktop/init.cc, which needs
+ // to know the old location of the trash
+
+ /**
+ * The path where documents are stored of the current user.
+ * @return the path of the document directory
+ */
+ static QString documentPath() { initStatic(); return *s_documentPath; }
+
+
+ /**
+ * The default color to use when highlighting toolbar buttons.
+ * @return the toolbar highlight color
+ */
+ static QColor toolBarHighlightColor();
+
+ /**
+ * The default color to use for inactive titles.
+ * @return the inactive title color
+ */
+ static QColor inactiveTitleColor();
+
+ /**
+ * The default color to use for inactive texts.
+ * @return the inactive text color
+ */
+ static QColor inactiveTextColor();
+
+ /**
+ * The default color to use for active titles.
+ * @return the active title color
+ */
+ static QColor activeTitleColor();
+
+ /**
+ * The default color to use for active texts.
+ * @return the active text color
+ */
+ static QColor activeTextColor();
+
+ /**
+ * Returns the contrast for borders.
+ * @return the contrast (between 0 for minimum and 10 for maximum
+ * contrast)
+ */
+ static int contrast();
+
+ /**
+ * Returns the button background color
+ * @return the button background color
+ * @since 3.4
+ */
+ static QColor buttonBackground();
+
+ /**
+ * Returns the button text color
+ * @return the button text color
+ * @since 3.4
+ */
+ static QColor buttonTextColor();
+
+ /**
+ * Returns the default base (background) color.
+ * @return the default base (background) color
+ * @see QColorGroup::base()
+ */
+ static QColor baseColor();
+
+ /**
+ * Returns the default text color.
+ * @return the default text color
+ * @see QColorGroup::text()
+ */
+ static QColor textColor();
+
+ /**
+ * Returns the default link color.
+ * @return the default link color
+ */
+ static QColor linkColor();
+
+ /**
+ * Returns the default color for visited links.
+ * @return the default color for visited links
+ */
+ static QColor visitedLinkColor();
+
+ /**
+ * Returns the default color for highlighted text.
+ * @return the default color for highlighted text
+ * @see QColorGroup::hightlightedText()
+ */
+ static QColor highlightedTextColor();
+
+ /**
+ * Returns the default color for text highlights.
+ * @return the default color for text highlights
+ * @see QColorGroup::hightlight()
+ */
+ static QColor highlightColor();
+
+ /**
+ * Returns the alternate background color used by KListView with
+ * KListViewItem. Any other list that uses alternating background
+ * colors should use this too, to obey to the user's preferences. Returns
+ * an invalid color if the user doesn't want alternating backgrounds.
+ * @return the alternate background color
+ * @see calculateAlternateBackgroundColor
+ */
+ static QColor alternateBackgroundColor();
+
+ /**
+ * Calculates a color based on @p base to be used as alternating
+ * color for e.g. listviews.
+ * @param base the base for the calculation
+ * @return the calculated color
+ * @see alternateBackgroundColor
+ */
+ static QColor calculateAlternateBackgroundColor(const QColor& base);
+
+ /**
+ * Returns if the sorted column in a KListView shall be drawn with a
+ * shaded background color.
+ * @return true if the sorted column shall be shaded
+ * @since 3.4
+ */
+ static bool shadeSortColumn();
+
+ /**
+ * Returns the default general font.
+ * @return the default general font.
+ */
+ static QFont generalFont();
+
+ /**
+ * Returns the default fixed font.
+ * @return the default fixed font.
+ */
+ static QFont fixedFont();
+
+ /**
+ * Returns the default toolbar font.
+ * @return the default toolbar font.
+ */
+ static QFont toolBarFont();
+
+ /**
+ * Returns the default menu font.
+ * @return the default menu font.
+ */
+ static QFont menuFont();
+
+ /**
+ * Returns the default window title font.
+ * @return the default window title font.
+ */
+ static QFont windowTitleFont();
+
+ /**
+ * Returns the default taskbar font.
+ * @return the default taskbar font.
+ */
+ static QFont taskbarFont();
+
+ /**
+ * Returns a font of approx. 48 pt. capable of showing @p text.
+ * @param text the text to test
+ * @return the font that is capable to show the text with 48 pt
+ * @since 3.1
+ */
+ static QFont largeFont(const QString &text = QString::null);
+
+ /**
+ * Returns if the user specified multihead. In case the display
+ * has multiple screens, the return value of this function specifies
+ * if the user wants KDE to run on all of them or just on the primary
+ * On Windows, settings are retrieved from the system.
+ * @return true if the user chose multi head
+ */
+ static bool isMultiHead();
+
+ /**
+ * Typically, QScrollView derived classes can be scrolled fast by
+ * holding down the Ctrl-button during wheel-scrolling.
+ * But QTextEdit and derived classes perform zooming instead of fast
+ * scrolling.
+ *
+ * This value determines whether the user wants to zoom or scroll fast
+ * with Ctrl-wheelscroll.
+ * @return true if the user wishes to zoom with the mouse wheel,
+ * false for scrolling
+ * @since 3.1
+ */
+ static bool wheelMouseZooms();
+
+ /**
+ * This function returns the desktop geometry for an application's splash
+ * screen. It takes into account the user's display settings (number of
+ * screens, Xinerama, etc), and the user's preferences (if KDE should be
+ * Xinerama aware).
+ *
+ * @return the geometry to use for the desktop. Note that it might not
+ * start at (0,0).
+ * @since 3.2
+ */
+ static QRect splashScreenDesktopGeometry();
+
+ /**
+ * This function returns the desktop geometry for an application that needs
+ * to set the geometry of a widget on the screen manually. It takes into
+ * account the user's display settings (number of screens, Xinerama, etc),
+ * and the user's preferences (if KDE should be Xinerama aware).
+ *
+ * Note that this can break in multi-head (not Xinerama) mode because this
+ * point could be on multiple screens. Use with care.
+ *
+ * @param point a reference point for the widget, for instance one that the
+ * widget should be adjacent or on top of.
+ *
+ * @return the geometry to use for the desktop. Note that it might not
+ * start at (0,0).
+ * @since 3.2
+ */
+ static QRect desktopGeometry(const QPoint& point);
+
+ /**
+ * This function returns the desktop geometry for an application that needs
+ * to set the geometry of a widget on the screen manually. It takes into
+ * account the user's display settings (number of screens, Xinerama, etc),
+ * and the user's preferences (if KDE should be Xinerama aware).
+ *
+ * @param w the widget in question. This is used to determine which screen
+ * to use in Xinerama or multi-head mode.
+ *
+ * @return the geometry to use for the desktop. Note that it might not
+ * start at (0,0).
+ * @since 3.2
+ */
+ static QRect desktopGeometry(QWidget* w);
+
+ /**
+ * This function determines if the user wishes to see icons on the
+ * push buttons.
+ *
+ * @return Returns true if user wants to show icons.
+ *
+ * @since 3.2
+ */
+ static bool showIconsOnPushButtons();
+
+ /**
+ * This function determines if the user wishes to see previews
+ * for the selected url
+ *
+ * @return Returns true if user wants to show previews.
+ *
+ * @since 3.2
+ */
+ static bool showFilePreview(const KURL &);
+
+ /**
+ * Whether the user wishes to use opaque resizing. Primarily
+ * intended for QSplitter::setOpaqueResize()
+ *
+ * @return Returns true if user wants to use opaque resizing.
+ *
+ * @since 3.2
+ */
+ static bool opaqueResize();
+
+ /**
+ * The layout scheme to use for dialog buttons
+ *
+ * @return Returns the number of the scheme to use.
+ * @see KDialogBase::setButtonStyle()
+ * @since 3.3
+ */
+ static int buttonLayout();
+
+private:
+ /**
+ * reads in all paths from kdeglobals
+ */
+ static void initStatic();
+ /**
+ * initialize colors
+ */
+ static void initColors();
+ /**
+ * drop cached values for fonts (called by KApplication)
+ */
+ static void rereadFontSettings();
+ /**
+ * drop cached values for paths (called by KApplication)
+ */
+ static void rereadPathSettings();
+ /**
+ * drop cached values for mouse settings (called by KApplication)
+ */
+ static void rereadMouseSettings();
+
+
+ static QString* s_desktopPath;
+ static QString* s_autostartPath;
+ static QString* s_trashPath;
+ static QString* s_documentPath;
+ static QFont *_generalFont;
+ static QFont *_fixedFont;
+ static QFont *_toolBarFont;
+ static QFont *_menuFont;
+ static QFont *_windowTitleFont;
+ static QFont *_taskbarFont;
+ static QFont *_largeFont;
+ static QColor * _kde34Blue;
+ static QColor * _inactiveBackground;
+ static QColor * _inactiveForeground;
+ static QColor * _activeBackground;
+ static QColor * _buttonBackground;
+ static QColor * _selectBackground;
+ static QColor * _linkColor;
+ static QColor * _visitedLinkColor;
+ static QColor * alternateColor;
+ static KMouseSettings *s_mouseSettings;
+
+ friend class KApplication;
+};
+
+#endif
diff --git a/kdecore/kgrantpty.c b/kdecore/kgrantpty.c
new file mode 100644
index 000000000..7d16f5b68
--- /dev/null
+++ b/kdecore/kgrantpty.c
@@ -0,0 +1,179 @@
+/* kgrantpty - helper program for KPty. */
+
+/* This program is based on the glibc2.1 pt_chmod.
+ * It was pulled out from there since both Linux
+ * distributors and other OSes are not able to make
+ * use of the glibc for different reasons.
+ *
+ * THIS IS A ROOT SUID PROGRAM
+ *
+ * Things work as following:
+ *
+ * In konsole we open a master pty. This can be
+ * done by at most one process. Prior to opening the
+ * master pty, the slave pty cannot be opened. Then, in
+ * grantpty, we fork to this program. The trick is, that
+ * the parameter is passed as a file handle, which cannot
+ * be faked, so that we get a secure setuid root chmod/chown
+ * with this program.
+ *
+ * We have to chown/chmod the slave pty to prevent eavesdroping.
+ *
+ * Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
+ * Copyright (c) 1999 by Lars Doelle <lars.doelle@on-line.de>.
+ * GPL applies.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+# define BSD_PTY_HACK
+# include <paths.h>
+# include <dirent.h>
+#endif
+
+#define TTY_GROUP "tty"
+
+int main (int argc, char *argv[])
+{
+ struct stat st;
+ struct group* p;
+ gid_t gid;
+ uid_t uid;
+ mode_t mod;
+ char* tty;
+ int fd;
+
+ /* check preconditions **************************************************/
+ if (argc != 3 || (strcmp(argv[1],"--grant") && strcmp(argv[1],"--revoke")))
+ {
+ printf("usage: %s (--grant|--revoke) <file descriptor>\n"
+ "%s is a helper for the KDE core libraries.\n"
+ "It is not intended to be called from the command line.\n"
+ "It needs to be installed setuid root to function.\n",
+ argv[0], argv[0]);
+ return 1; /* FAIL */
+ }
+
+ if (geteuid () != 0)
+ {
+ fprintf(stderr, "%s not installed setuid root\n", argv[0]);
+ return 1; /* FAIL */
+ }
+
+ fd = atoi(argv[2]);
+
+ /* get slave pty name from master pty file handle *********/
+#ifdef HAVE_PTSNAME
+ tty = ptsname(fd);
+ if (!tty)
+#endif
+ {
+ /* Check that fd is a valid master pseudo terminal. */
+ char *pty = ttyname(fd);
+
+#ifdef BSD_PTY_HACK
+ if (pty == NULL)
+ {
+ /*
+ Hack to make kgrantpty work on some versions of FreeBSD (and possibly
+ other systems): ttyname(3) does not work with a file descriptor opened
+ on a /dev/pty?? device.
+
+ Instead, this code looks through all the devices in /dev for a device
+ which has the same inode as our PTY_FILENO descriptor... if found, we
+ have the name for our pty.
+ */
+
+ struct dirent *dirp;
+ DIR *dp;
+ struct stat dsb;
+
+ if (fstat(fd, &dsb) != -1) {
+ if ((dp = opendir(_PATH_DEV)) != NULL) {
+ while ((dirp = readdir(dp))) {
+ if (dirp->d_fileno != dsb.st_ino)
+ continue;
+ pty = malloc(sizeof(_PATH_DEV) + strlen(dirp->d_name));
+ if (pty) {
+ strcpy(pty, _PATH_DEV);
+ strcat(pty, dirp->d_name);
+ }
+ break;
+ }
+
+ (void) closedir(dp);
+ }
+ }
+ }
+#endif
+
+ if (pty == NULL)
+ {
+ fprintf(stderr,"%s: cannot determine pty name.\n",argv[0]);
+ return 1; /* FAIL */
+ }
+
+ /* matches /dev/pty?? */
+ if (memcmp(pty,"/dev/pty",8))
+ {
+ fprintf(stderr,"%s: determined a strange pty name `%s'.\n",argv[0],pty);
+ return 1; /* FAIL */
+ }
+
+ tty = malloc(strlen(pty) + 1);
+ strcpy(tty,"/dev/tty");
+ strcat(tty,pty+8);
+ }
+
+ /* Check that the returned slave pseudo terminal is a character device. */
+ if (stat(tty, &st) < 0 || !S_ISCHR(st.st_mode))
+ {
+ fprintf(stderr,"%s: found `%s' not to be a character device.\n",argv[0],tty);
+ return 1; /* FAIL */
+ }
+
+ /* setup parameters for the operation ***********************************/
+
+ if (!strcmp(argv[1],"--grant"))
+ {
+ uid = getuid();
+ p = getgrnam(TTY_GROUP);
+ if (!p)
+ p = getgrnam("wheel");
+ gid = p ? p->gr_gid : getgid ();
+ mod = S_IRUSR | S_IWUSR | S_IWGRP;
+ }
+ else
+ {
+ uid = 0;
+ gid = st.st_gid == getgid () ? 0 : -1;
+ mod = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ }
+
+ /* Perform the actual chown/chmod ************************************/
+
+ if (chown(tty, uid, gid) < 0)
+ {
+ fprintf(stderr,"%s: cannot chown %s: %s\n",argv[0],tty,strerror(errno));
+ return 1; /* FAIL */
+ }
+
+ if (chmod(tty, mod) < 0)
+ {
+ fprintf(stderr,"%s: cannot chmod %s: %s\n",argv[0],tty,strerror(errno));
+ return 1; /* FAIL */
+ }
+
+ return 0; /* OK */
+}
diff --git a/kdecore/kiconeffect.cpp b/kdecore/kiconeffect.cpp
new file mode 100644
index 000000000..7746e679e
--- /dev/null
+++ b/kdecore/kiconeffect.cpp
@@ -0,0 +1,770 @@
+/* vi: ts=8 sts=4 sw=4
+ * $Id$
+ *
+ * This file is part of the KDE project, module kdecore.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * with minor additions and based on ideas from
+ * Torsten Rahn <torsten@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qbitmap.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qcolor.h>
+#include <qwidget.h>
+#include <qpainter.h>
+#include <qpen.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kglobalsettings.h>
+#include <kicontheme.h>
+#include "kiconeffect.h"
+
+#if defined(Q_WS_WIN) || defined(Q_WS_MACX)
+static bool qt_use_xrender=true;
+static bool qt_has_xft=true;
+#else
+extern bool qt_use_xrender;
+extern bool qt_has_xft;
+#endif
+class KIconEffectPrivate
+{
+public:
+ QString mKey[6][3];
+ QColor mColor2[6][3];
+};
+
+KIconEffect::KIconEffect()
+{
+ d = new KIconEffectPrivate;
+ init();
+}
+
+KIconEffect::~KIconEffect()
+{
+ delete d;
+ d = 0L;
+}
+
+void KIconEffect::init()
+{
+ KConfig *config = KGlobal::config();
+
+ int i, j, effect=-1;
+ QStringList groups;
+ groups += "Desktop";
+ groups += "Toolbar";
+ groups += "MainToolbar";
+ groups += "Small";
+ groups += "Panel";
+
+ QStringList states;
+ states += "Default";
+ states += "Active";
+ states += "Disabled";
+
+ QStringList::ConstIterator it, it2;
+ QString _togray("togray");
+ QString _colorize("colorize");
+ QString _desaturate("desaturate");
+ QString _togamma("togamma");
+ QString _none("none");
+ QString _tomonochrome("tomonochrome");
+
+ KConfigGroupSaver cs(config, "default");
+
+ for (it=groups.begin(), i=0; it!=groups.end(); it++, i++)
+ {
+ // Default effects
+ mEffect[i][0] = NoEffect;
+ mEffect[i][1] = ((i==0)||(i==4)) ? ToGamma : NoEffect;
+ mEffect[i][2] = ToGray;
+
+ mTrans[i][0] = false;
+ mTrans[i][1] = false;
+ mTrans[i][2] = true;
+ mValue[i][0] = 1.0;
+ mValue[i][1] = ((i==0)||(i==4)) ? 0.7 : 1.0;
+ mValue[i][2] = 1.0;
+ mColor[i][0] = QColor(144,128,248);
+ mColor[i][1] = QColor(169,156,255);
+ mColor[i][2] = QColor(34,202,0);
+ d->mColor2[i][0] = QColor(0,0,0);
+ d->mColor2[i][1] = QColor(0,0,0);
+ d->mColor2[i][2] = QColor(0,0,0);
+
+ config->setGroup(*it + "Icons");
+ for (it2=states.begin(), j=0; it2!=states.end(); it2++, j++)
+ {
+ QString tmp = config->readEntry(*it2 + "Effect");
+ if (tmp == _togray)
+ effect = ToGray;
+ else if (tmp == _colorize)
+ effect = Colorize;
+ else if (tmp == _desaturate)
+ effect = DeSaturate;
+ else if (tmp == _togamma)
+ effect = ToGamma;
+ else if (tmp == _tomonochrome)
+ effect = ToMonochrome;
+ else if (tmp == _none)
+ effect = NoEffect;
+ else
+ continue;
+ if(effect != -1)
+ mEffect[i][j] = effect;
+ mValue[i][j] = config->readDoubleNumEntry(*it2 + "Value");
+ mColor[i][j] = config->readColorEntry(*it2 + "Color");
+ d->mColor2[i][j] = config->readColorEntry(*it2 + "Color2");
+ mTrans[i][j] = config->readBoolEntry(*it2 + "SemiTransparent");
+
+ }
+ }
+}
+
+bool KIconEffect::hasEffect(int group, int state) const
+{
+ return mEffect[group][state] != NoEffect;
+}
+
+QString KIconEffect::fingerprint(int group, int state) const
+{
+ if ( group >= KIcon::LastGroup ) return "";
+ QString cached = d->mKey[group][state];
+ if (cached.isEmpty())
+ {
+ QString tmp;
+ cached = tmp.setNum(mEffect[group][state]);
+ cached += ':';
+ cached += tmp.setNum(mValue[group][state]);
+ cached += ':';
+ cached += mTrans[group][state] ? QString::fromLatin1("trans")
+ : QString::fromLatin1("notrans");
+ if (mEffect[group][state] == Colorize || mEffect[group][state] == ToMonochrome)
+ {
+ cached += ':';
+ cached += mColor[group][state].name();
+ }
+ if (mEffect[group][state] == ToMonochrome)
+ {
+ cached += ':';
+ cached += d->mColor2[group][state].name();
+ }
+
+ d->mKey[group][state] = cached;
+ }
+
+ return cached;
+}
+
+QImage KIconEffect::apply(QImage image, int group, int state) const
+{
+ if (state >= KIcon::LastState)
+ {
+ kdDebug(265) << "Illegal icon state: " << state << "\n";
+ return image;
+ }
+ if (group >= KIcon::LastGroup)
+ {
+ kdDebug(265) << "Illegal icon group: " << group << "\n";
+ return image;
+ }
+ return apply(image, mEffect[group][state], mValue[group][state],
+ mColor[group][state], d->mColor2[group][state], mTrans[group][state]);
+}
+
+QImage KIconEffect::apply(QImage image, int effect, float value, const QColor col, bool trans) const
+{
+ return apply (image, effect, value, col, KGlobalSettings::baseColor(), trans);
+}
+
+QImage KIconEffect::apply(QImage image, int effect, float value, const QColor col, const QColor col2, bool trans) const
+{
+ if (effect >= LastEffect )
+ {
+ kdDebug(265) << "Illegal icon effect: " << effect << "\n";
+ return image;
+ }
+ if (value > 1.0)
+ value = 1.0;
+ else if (value < 0.0)
+ value = 0.0;
+ switch (effect)
+ {
+ case ToGray:
+ toGray(image, value);
+ break;
+ case DeSaturate:
+ deSaturate(image, value);
+ break;
+ case Colorize:
+ colorize(image, col, value);
+ break;
+ case ToGamma:
+ toGamma(image, value);
+ break;
+ case ToMonochrome:
+ toMonochrome(image, col, col2, value);
+ break;
+ }
+ if (trans == true)
+ {
+ semiTransparent(image);
+ }
+ return image;
+}
+
+QPixmap KIconEffect::apply(QPixmap pixmap, int group, int state) const
+{
+ if (state >= KIcon::LastState)
+ {
+ kdDebug(265) << "Illegal icon state: " << state << "\n";
+ return pixmap;
+ }
+ if (group >= KIcon::LastGroup)
+ {
+ kdDebug(265) << "Illegal icon group: " << group << "\n";
+ return pixmap;
+ }
+ return apply(pixmap, mEffect[group][state], mValue[group][state],
+ mColor[group][state], d->mColor2[group][state], mTrans[group][state]);
+}
+
+QPixmap KIconEffect::apply(QPixmap pixmap, int effect, float value,
+ const QColor col, bool trans) const
+{
+ return apply (pixmap, effect, value, col, KGlobalSettings::baseColor(), trans);
+}
+
+QPixmap KIconEffect::apply(QPixmap pixmap, int effect, float value,
+ const QColor col, const QColor col2, bool trans) const
+{
+ QPixmap result;
+
+ if (effect >= LastEffect )
+ {
+ kdDebug(265) << "Illegal icon effect: " << effect << "\n";
+ return result;
+ }
+
+ if ((trans == true) && (effect == NoEffect))
+ {
+ result = pixmap;
+ semiTransparent(result);
+ }
+ else if ( effect != NoEffect )
+ {
+ QImage tmpImg = pixmap.convertToImage();
+ tmpImg = apply(tmpImg, effect, value, col, col2, trans);
+ result.convertFromImage(tmpImg);
+ }
+ else
+ result = pixmap;
+
+ return result;
+}
+
+// Taken from KImageEffect. We don't want to link kdecore to kdeui! As long
+// as this code is not too big, it doesn't seem much of a problem to me.
+
+void KIconEffect::toGray(QImage &img, float value)
+{
+ int pixels = (img.depth() > 8) ? img.width()*img.height()
+ : img.numColors();
+ unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits()
+ : (unsigned int *) img.colorTable();
+ int rval, gval, bval, val, alpha, i;
+ for (i=0; i<pixels; i++)
+ {
+ val = qGray(data[i]);
+ alpha = qAlpha(data[i]);
+ if (value < 1.0)
+ {
+ rval = static_cast<int>(value*val+(1.0-value)*qRed(data[i]));
+ gval = static_cast<int>(value*val+(1.0-value)*qGreen(data[i]));
+ bval = static_cast<int>(value*val+(1.0-value)*qBlue(data[i]));
+ data[i] = qRgba(rval, gval, bval, alpha);
+ } else
+ data[i] = qRgba(val, val, val, alpha);
+ }
+}
+
+void KIconEffect::colorize(QImage &img, const QColor &col, float value)
+{
+ int pixels = (img.depth() > 8) ? img.width()*img.height()
+ : img.numColors();
+ unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits()
+ : (unsigned int *) img.colorTable();
+ int rval, gval, bval, val, alpha, i;
+ float rcol = col.red(), gcol = col.green(), bcol = col.blue();
+ for (i=0; i<pixels; i++)
+ {
+ val = qGray(data[i]);
+ if (val < 128)
+ {
+ rval = static_cast<int>(rcol/128*val);
+ gval = static_cast<int>(gcol/128*val);
+ bval = static_cast<int>(bcol/128*val);
+ }
+ else if (val > 128)
+ {
+ rval = static_cast<int>((val-128)*(2-rcol/128)+rcol-1);
+ gval = static_cast<int>((val-128)*(2-gcol/128)+gcol-1);
+ bval = static_cast<int>((val-128)*(2-bcol/128)+bcol-1);
+ }
+ else // val == 128
+ {
+ rval = static_cast<int>(rcol);
+ gval = static_cast<int>(gcol);
+ bval = static_cast<int>(bcol);
+ }
+ if (value < 1.0)
+ {
+ rval = static_cast<int>(value*rval+(1.0 - value)*qRed(data[i]));
+ gval = static_cast<int>(value*gval+(1.0 - value)*qGreen(data[i]));
+ bval = static_cast<int>(value*bval+(1.0 - value)*qBlue(data[i]));
+ }
+
+ alpha = qAlpha(data[i]);
+ data[i] = qRgba(rval, gval, bval, alpha);
+ }
+}
+
+void KIconEffect::toMonochrome(QImage &img, const QColor &black, const QColor &white, float value) {
+ int pixels = (img.depth() > 8) ? img.width()*img.height() : img.numColors();
+ unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits()
+ : (unsigned int *) img.colorTable();
+ int rval, gval, bval, alpha, i;
+ int rw = white.red(), gw = white.green(), bw = white.blue();
+ int rb = black.red(), gb = black.green(), bb = black.blue();
+
+ double values = 0, sum = 0;
+ bool grayscale = true;
+ // Step 1: determine the average brightness
+ for (i=0; i<pixels; i++) {
+ sum += qGray(data[i])*qAlpha(data[i]) + 255*(255-qAlpha(data[i]));
+ values += 255;
+ if ((qRed(data[i]) != qGreen(data[i]) ) || (qGreen(data[i]) != qBlue(data[i]) ))
+ grayscale = false;
+ }
+ double medium = sum/values;
+
+ // Step 2: Modify the image
+ if (grayscale) {
+ for (i=0; i<pixels; i++) {
+ int v = qRed(data[i]);
+ rval = static_cast<int>( ((255-v)*rb + v*rw)*value/255 + (1.0-value)*qRed(data[i]));
+ gval = static_cast<int>( ((255-v)*gb + v*gw)*value/255 + (1.0-value)*qGreen(data[i]));
+ bval = static_cast<int>( ((255-v)*bb + v*bw)*value/255 + (1.0-value)*qBlue(data[i]));
+
+ alpha = qAlpha(data[i]);
+ data[i] = qRgba(rval, gval, bval, alpha);
+ }
+ }
+ else {
+ for (i=0; i<pixels; i++) {
+ if (qGray(data[i]) <= medium) {
+ rval = static_cast<int>(value*rb+(1.0-value)*qRed(data[i]));
+ gval = static_cast<int>(value*gb+(1.0-value)*qGreen(data[i]));
+ bval = static_cast<int>(value*bb+(1.0-value)*qBlue(data[i]));
+ }
+ else {
+ rval = static_cast<int>(value*rw+(1.0-value)*qRed(data[i]));
+ gval = static_cast<int>(value*gw+(1.0-value)*qGreen(data[i]));
+ bval = static_cast<int>(value*bw+(1.0-value)*qBlue(data[i]));
+ }
+
+ alpha = qAlpha(data[i]);
+ data[i] = qRgba(rval, gval, bval, alpha);
+ }
+ }
+}
+
+void KIconEffect::deSaturate(QImage &img, float value)
+{
+ int pixels = (img.depth() > 8) ? img.width()*img.height()
+ : img.numColors();
+ unsigned int *data = (img.depth() > 8) ? (unsigned int *) img.bits()
+ : (unsigned int *) img.colorTable();
+ QColor color;
+ int h, s, v, i;
+ for (i=0; i<pixels; i++)
+ {
+ color.setRgb(data[i]);
+ color.hsv(&h, &s, &v);
+ color.setHsv(h, (int) (s * (1.0 - value) + 0.5), v);
+ data[i] = qRgba(color.red(), color.green(), color.blue(),
+ qAlpha(data[i]));
+ }
+}
+
+void KIconEffect::toGamma(QImage &img, float value)
+{
+ int pixels = (img.depth() > 8) ? img.width()*img.height()
+ : img.numColors();
+ unsigned int *data = (img.depth() > 8) ? (unsigned int *) img.bits()
+ : (unsigned int *) img.colorTable();
+ QColor color;
+ int i, rval, gval, bval;
+ float gamma;
+ gamma = 1/(2*value+0.5);
+
+ for (i=0; i<pixels; i++)
+ {
+ color.setRgb(data[i]);
+ color.rgb(&rval, &gval, &bval);
+ rval = static_cast<int>(pow(static_cast<float>(rval)/255 , gamma)*255);
+ gval = static_cast<int>(pow(static_cast<float>(gval)/255 , gamma)*255);
+ bval = static_cast<int>(pow(static_cast<float>(bval)/255 , gamma)*255);
+ data[i] = qRgba(rval, gval, bval, qAlpha(data[i]));
+ }
+}
+
+void KIconEffect::semiTransparent(QImage &img)
+{
+ img.setAlphaBuffer(true);
+
+ int x, y;
+ if (img.depth() == 32)
+ {
+ int width = img.width();
+ int height = img.height();
+
+ if (qt_use_xrender && qt_has_xft )
+ for (y=0; y<height; y++)
+ {
+#ifdef WORDS_BIGENDIAN
+ uchar *line = (uchar*) img.scanLine(y);
+#else
+ uchar *line = (uchar*) img.scanLine(y) + 3;
+#endif
+ for (x=0; x<width; x++)
+ {
+ *line >>= 1;
+ line += 4;
+ }
+ }
+ else
+ for (y=0; y<height; y++)
+ {
+ QRgb *line = (QRgb *) img.scanLine(y);
+ for (x=(y%2); x<width; x+=2)
+ line[x] &= 0x00ffffff;
+ }
+
+ } else
+ {
+ // Insert transparent pixel into the clut.
+ int transColor = -1;
+
+ // search for a color that is already transparent
+ for (x=0; x<img.numColors(); x++)
+ {
+ // try to find already transparent pixel
+ if (qAlpha(img.color(x)) < 127)
+ {
+ transColor = x;
+ break;
+ }
+ }
+
+
+ // FIXME: image must have transparency
+ if(transColor < 0 || transColor >= img.numColors())
+ return;
+
+ img.setColor(transColor, 0);
+ if(img.depth() == 8)
+ {
+ for (y=0; y<img.height(); y++)
+ {
+ unsigned char *line = img.scanLine(y);
+ for (x=(y%2); x<img.width(); x+=2)
+ line[x] = transColor;
+ }
+ }
+ else
+ {
+ // SLOOW, but simple, as we would have to
+ // deal with endianess etc on our own here
+ for (y=0; y<img.height(); y++)
+ for (x=(y%2); x<img.width(); x+=2)
+ img.setPixel(x, y, transColor);
+ }
+ }
+}
+
+void KIconEffect::semiTransparent(QPixmap &pix)
+{
+ if ( qt_use_xrender && qt_has_xft )
+ {
+ QImage img=pix.convertToImage();
+ semiTransparent(img);
+ pix.convertFromImage(img);
+ return;
+ }
+
+ QImage img;
+ if (pix.mask() != 0L)
+ img = pix.mask()->convertToImage();
+ else
+ {
+ img.create(pix.size(), 1, 2, QImage::BigEndian);
+ img.fill(1);
+ }
+
+ for (int y=0; y<img.height(); y++)
+ {
+ QRgb *line = (QRgb *) img.scanLine(y);
+ QRgb pattern = (y % 2) ? 0x55555555 : 0xaaaaaaaa;
+ for (int x=0; x<(img.width()+31)/32; x++)
+ line[x] &= pattern;
+ }
+ QBitmap mask;
+ mask.convertFromImage(img);
+ pix.setMask(mask);
+}
+
+QImage KIconEffect::doublePixels(QImage src) const
+{
+ QImage dst;
+ if (src.depth() == 1)
+ {
+ kdDebug(265) << "image depth 1 not supported\n";
+ return dst;
+ }
+
+ int w = src.width();
+ int h = src.height();
+ dst.create(w*2, h*2, src.depth());
+ dst.setAlphaBuffer(src.hasAlphaBuffer());
+
+ int x, y;
+ if (src.depth() == 32)
+ {
+ QRgb *l1, *l2;
+ for (y=0; y<h; y++)
+ {
+ l1 = (QRgb *) src.scanLine(y);
+ l2 = (QRgb *) dst.scanLine(y*2);
+ for (x=0; x<w; x++)
+ {
+ l2[x*2] = l2[x*2+1] = l1[x];
+ }
+ memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine());
+ }
+ } else
+ {
+ for (x=0; x<src.numColors(); x++)
+ dst.setColor(x, src.color(x));
+
+ unsigned char *l1, *l2;
+ for (y=0; y<h; y++)
+ {
+ l1 = src.scanLine(y);
+ l2 = dst.scanLine(y*2);
+ for (x=0; x<w; x++)
+ {
+ l2[x*2] = l1[x];
+ l2[x*2+1] = l1[x];
+ }
+ memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine());
+ }
+ }
+ return dst;
+}
+
+void KIconEffect::overlay(QImage &src, QImage &overlay)
+{
+ if (src.depth() != overlay.depth())
+ {
+ kdDebug(265) << "Image depth src != overlay!\n";
+ return;
+ }
+ if (src.size() != overlay.size())
+ {
+ kdDebug(265) << "Image size src != overlay\n";
+ return;
+ }
+ if (!overlay.hasAlphaBuffer())
+ {
+ kdDebug(265) << "Overlay doesn't have alpha buffer!\n";
+ return;
+ }
+
+ int i, j;
+
+ // We don't do 1 bpp
+
+ if (src.depth() == 1)
+ {
+ kdDebug(265) << "1bpp not supported!\n";
+ return;
+ }
+
+ // Overlay at 8 bpp doesn't use alpha blending
+
+ if (src.depth() == 8)
+ {
+ if (src.numColors() + overlay.numColors() > 255)
+ {
+ kdDebug(265) << "Too many colors in src + overlay!\n";
+ return;
+ }
+
+ // Find transparent pixel in overlay
+ int trans;
+ for (trans=0; trans<overlay.numColors(); trans++)
+ {
+ if (qAlpha(overlay.color(trans)) == 0)
+ {
+ kdDebug(265) << "transparent pixel found at " << trans << "\n";
+ break;
+ }
+ }
+ if (trans == overlay.numColors())
+ {
+ kdDebug(265) << "transparent pixel not found!\n";
+ return;
+ }
+
+ // Merge color tables
+ int nc = src.numColors();
+ src.setNumColors(nc + overlay.numColors());
+ for (i=0; i<overlay.numColors(); i++)
+ {
+ src.setColor(nc+i, overlay.color(i));
+ }
+
+ // Overwrite nontransparent pixels.
+ unsigned char *oline, *sline;
+ for (i=0; i<src.height(); i++)
+ {
+ oline = overlay.scanLine(i);
+ sline = src.scanLine(i);
+ for (j=0; j<src.width(); j++)
+ {
+ if (oline[j] != trans)
+ sline[j] = oline[j]+nc;
+ }
+ }
+ }
+
+ // Overlay at 32 bpp does use alpha blending
+
+ if (src.depth() == 32)
+ {
+ QRgb *oline, *sline;
+ int r1, g1, b1, a1;
+ int r2, g2, b2, a2;
+
+ for (i=0; i<src.height(); i++)
+ {
+ oline = (QRgb *) overlay.scanLine(i);
+ sline = (QRgb *) src.scanLine(i);
+
+ for (j=0; j<src.width(); j++)
+ {
+ r1 = qRed(oline[j]);
+ g1 = qGreen(oline[j]);
+ b1 = qBlue(oline[j]);
+ a1 = qAlpha(oline[j]);
+
+ r2 = qRed(sline[j]);
+ g2 = qGreen(sline[j]);
+ b2 = qBlue(sline[j]);
+ a2 = qAlpha(sline[j]);
+
+ r2 = (a1 * r1 + (0xff - a1) * r2) >> 8;
+ g2 = (a1 * g1 + (0xff - a1) * g2) >> 8;
+ b2 = (a1 * b1 + (0xff - a1) * b2) >> 8;
+ a2 = QMAX(a1, a2);
+
+ sline[j] = qRgba(r2, g2, b2, a2);
+ }
+ }
+ }
+
+ return;
+}
+
+ void
+KIconEffect::visualActivate(QWidget * widget, QRect rect)
+{
+ if (!KGlobalSettings::visualActivate())
+ return;
+
+ uint actSpeed = KGlobalSettings::visualActivateSpeed();
+
+ uint actCount = QMIN(rect.width(), rect.height()) / 2;
+
+ // Clip actCount to range 1..10.
+
+ if (actCount < 1)
+ actCount = 1;
+
+ else if (actCount > 10)
+ actCount = 10;
+
+ // Clip actSpeed to range 1..100.
+
+ if (actSpeed < 1)
+ actSpeed = 1;
+
+ else if (actSpeed > 100)
+ actSpeed = 100;
+
+ // actSpeed needs to be converted to actDelay.
+ // actDelay is inversely proportional to actSpeed and needs to be
+ // divided up into actCount portions.
+ // We also convert the us value to ms.
+
+ unsigned int actDelay = (1000 * (100 - actSpeed)) / actCount;
+
+ //kdDebug() << "actCount=" << actCount << " actDelay=" << actDelay << endl;
+
+ QPoint c = rect.center();
+
+ QPainter p(widget);
+
+ // Use NotROP to avoid having to repaint the pixmap each time.
+ p.setPen(QPen(Qt::black, 2, Qt::DotLine));
+ p.setRasterOp(Qt::NotROP);
+
+ // The spacing between the rects we draw.
+ // Use the minimum of width and height to avoid painting outside the
+ // pixmap area.
+ //unsigned int delta(QMIN(rect.width() / actCount, rect.height() / actCount));
+
+ // Support for rectangles by David
+ unsigned int deltaX = rect.width() / actCount;
+ unsigned int deltaY = rect.height() / actCount;
+
+ for (unsigned int i = 1; i < actCount; i++) {
+
+ int w = i * deltaX;
+ int h = i * deltaY;
+
+ rect.setRect(c.x() - w / 2, c.y() - h / 2, w, h);
+
+ p.drawRect(rect);
+ p.flush();
+
+ usleep(actDelay);
+
+ p.drawRect(rect);
+ }
+}
+
diff --git a/kdecore/kiconeffect.h b/kdecore/kiconeffect.h
new file mode 100644
index 000000000..6cc568ac2
--- /dev/null
+++ b/kdecore/kiconeffect.h
@@ -0,0 +1,230 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdecore.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * with minor additions and based on ideas from
+ * Torsten Rahn <torsten@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#ifndef __KIconEffect_h_Included__
+#define __KIconEffect_h_Included__
+
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qcolor.h>
+#include <qrect.h>
+#include "kdelibs_export.h"
+
+class QWidget;
+
+class KIconEffectPrivate;
+
+/**
+ * Applies effects to icons.
+ *
+ * This class applies effects to icons depending on their state and
+ * group. For example, it can be used to make all disabled icons
+ * in a toolbar gray.
+ * @see KIcon
+ */
+class KDECORE_EXPORT KIconEffect
+{
+public:
+ /**
+ * Create a new KIconEffect.
+ */
+ KIconEffect();
+ ~KIconEffect();
+
+ /**
+ * This is the enumeration of all possible icon effects.
+ * Note that 'LastEffect' is no valid icon effect but only
+ * used internally to check for invalid icon effects.
+ *
+ * @li NoEffect: Don't apply any icon effect
+ * @li ToGray: Tints the icon gray
+ * @li Colorize: Tints the icon with an other color
+ * @li ToGamma: Change the gamma value of the icon
+ * @li DeSaturate: Reduce the saturation of the icon
+ * @li ToMonochrome: Produces a monochrome icon
+ */
+ enum Effects { NoEffect, ToGray, Colorize, ToGamma, DeSaturate,
+ ToMonochrome, ///< @since 3.4
+ LastEffect };
+
+ /**
+ * Rereads configuration.
+ */
+ void init();
+
+ /**
+ * Tests whether an effect has been configured for the given icon group.
+ * @param group the group to check, see KIcon::Group
+ * @param state the state to check, see KIcon::States
+ * @returns true if an effect is configured for the given @p group
+ * in @p state, otherwise false.
+ * @see KIcon::Group
+ * KIcon::States
+ */
+ bool hasEffect(int group, int state) const;
+
+ /**
+ * Returns a fingerprint for the effect by encoding
+ * the given @p group and @p state into a QString. This
+ * is useful for caching.
+ * @param group the group, see KIcon::Group
+ * @param state the state, see KIcon::States
+ * @return the fingerprint of the given @p group+@p state
+ */
+ QString fingerprint(int group, int state) const;
+
+ /**
+ * Applies an effect to an image. The effect to apply depends on the
+ * @p group and @p state parameters, and is configured by the user.
+ * @param src The image.
+ * @param group The group for the icon, see KIcon::Group
+ * @param state The icon's state, see KIcon::States
+ * @return An image with the effect applied.
+ */
+ QImage apply(QImage src, int group, int state) const;
+
+ /**
+ * Applies an effect to an image.
+ * @param src The image.
+ * @param effect The effect to apply, one of KIconEffect::Effects.
+ * @param value Strength of the effect. 0 <= @p value <= 1.
+ * @param rgb Color parameter for effects that need one.
+ * @param trans Add Transparency if trans = true.
+ * @return An image with the effect applied.
+ */
+ // KDE4: make them references
+ QImage apply(QImage src, int effect, float value, const QColor rgb, bool trans) const;
+ /**
+ * @since 3.4
+ */
+ QImage apply(QImage src, int effect, float value, const QColor rgb, const QColor rgb2, bool trans) const;
+
+ /**
+ * Applies an effect to a pixmap.
+ * @param src The pixmap.
+ * @param group The group for the icon, see KIcon::Group
+ * @param state The icon's state, see KIcon::States
+ * @return A pixmap with the effect applied.
+ */
+ QPixmap apply(QPixmap src, int group, int state) const;
+
+ /**
+ * Applies an effect to a pixmap.
+ * @param src The pixmap.
+ * @param effect The effect to apply, one of KIconEffect::Effects.
+ * @param value Strength of the effect. 0 <= @p value <= 1.
+ * @param rgb Color parameter for effects that need one.
+ * @param trans Add Transparency if trans = true.
+ * @return A pixmap with the effect applied.
+ */
+ QPixmap apply(QPixmap src, int effect, float value, const QColor rgb, bool trans) const;
+ /**
+ * @since 3.4
+ */
+ QPixmap apply(QPixmap src, int effect, float value, const QColor rgb, const QColor rgb2, bool trans) const;
+
+ /**
+ * Returns an image twice as large, consisting of 2x2 pixels.
+ * @param src the image.
+ * @return the scaled image.
+ */
+ QImage doublePixels(QImage src) const;
+
+ /**
+ * Provides visual feedback to show activation of an icon on a widget.
+ *
+ * Not strictly an 'icon effect', but in practice that's what it looks
+ * like.
+ *
+ * This method does nothing if the global 'Visual feedback on activation'
+ * option is not activated (See kcontrol/Peripherals/Mouse).
+ *
+ * @param widget The widget on which the effect should be painted
+ * @param rect This rectangle defines the effect's borders
+ */
+ static void visualActivate(QWidget *widget, QRect rect);
+
+ /**
+ * Tints an image gray.
+ *
+ * @param image The image
+ * @param value Strength of the effect. 0 <= @p value <= 1
+ */
+ static void toGray(QImage &image, float value);
+
+ /**
+ * Colorizes an image with a specific color.
+ *
+ * @param image The image
+ * @param col The color with which the @p image is tinted
+ * @param value Strength of the effect. 0 <= @p value <= 1
+ */
+ static void colorize(QImage &image, const QColor &col, float value);
+
+ /**
+ * Produces a monochrome icon with a given foreground and background color
+ *
+ * @param image The image
+ * @param white The color with which the white parts of @p image are painted
+ * @param black The color with which the black parts of @p image are painted
+ * @param value Strength of the effect. 0 <= @p value <= 1
+ * @since 3.4
+ */
+ static void toMonochrome(QImage &image, const QColor &black, const QColor &white, float value);
+
+ /**
+ * Desaturates an image.
+ *
+ * @param image The image
+ * @param value Strength of the effect. 0 <= @p value <= 1
+ */
+ static void deSaturate(QImage &image, float value);
+
+ /**
+ * Changes the gamma value of an image.
+ *
+ * @param image The image
+ * @param value Strength of the effect. 0 <= @p value <= 1
+ */
+ static void toGamma(QImage &image, float value);
+
+ /**
+ * Renders an image semi-transparent.
+ *
+ * @param image The image
+ */
+ static void semiTransparent(QImage &image);
+
+ /**
+ * Renders a pixmap semi-transparent.
+ *
+ * @param pixmap The pixmap
+ */
+ static void semiTransparent(QPixmap &pixmap);
+
+ /**
+ * Overlays an image with an other image.
+ *
+ * @param src The image
+ * @param overlay The image to overlay @p src with
+ */
+ static void overlay(QImage &src, QImage &overlay);
+
+private:
+ int mEffect[6][3];
+ float mValue[6][3];
+ QColor mColor[6][3];
+ bool mTrans[6][3];
+ KIconEffectPrivate *d;
+};
+
+#endif
diff --git a/kdecore/kiconloader.cpp b/kdecore/kiconloader.cpp
new file mode 100644
index 000000000..3c2a7be40
--- /dev/null
+++ b/kdecore/kiconloader.cpp
@@ -0,0 +1,1408 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * $Id$
+ *
+ * This file is part of the KDE project, module kdecore.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * Antonio Larrosa <larrosa@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ *
+ * kiconloader.cpp: An icon loader for KDE with theming functionality.
+ */
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <qintdict.h>
+#include <qpixmap.h>
+#include <qpixmapcache.h>
+#include <qimage.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qiconset.h>
+#include <qmovie.h>
+#include <qbitmap.h>
+
+#include <kapplication.h>
+#include <kipc.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <kinstance.h>
+
+#include <kicontheme.h>
+#include <kiconloader.h>
+#include <kiconeffect.h>
+
+#include <sys/types.h>
+#include <stdlib.h> //for abs
+#include <unistd.h> //for readlink
+#include <dirent.h>
+#include <config.h>
+#include <assert.h>
+
+#ifdef HAVE_LIBART
+#include "svgicons/ksvgiconengine.h"
+#include "svgicons/ksvgiconpainter.h"
+#endif
+
+#include "kiconloader_p.h"
+
+/*** KIconThemeNode: A node in the icon theme dependancy tree. ***/
+
+KIconThemeNode::KIconThemeNode(KIconTheme *_theme)
+{
+ theme = _theme;
+}
+
+KIconThemeNode::~KIconThemeNode()
+{
+ delete theme;
+}
+
+void KIconThemeNode::printTree(QString& dbgString) const
+{
+ /* This method doesn't have much sense anymore, so maybe it should
+ be removed in the (near?) future */
+ dbgString += "(";
+ dbgString += theme->name();
+ dbgString += ")";
+}
+
+void KIconThemeNode::queryIcons(QStringList *result,
+ int size, KIcon::Context context) const
+{
+ // add the icons of this theme to it
+ *result += theme->queryIcons(size, context);
+}
+
+void KIconThemeNode::queryIconsByContext(QStringList *result,
+ int size, KIcon::Context context) const
+{
+ // add the icons of this theme to it
+ *result += theme->queryIconsByContext(size, context);
+}
+
+KIcon KIconThemeNode::findIcon(const QString& name, int size,
+ KIcon::MatchType match) const
+{
+ return theme->iconPath(name, size, match);
+}
+
+
+/*** KIconGroup: Icon type description. ***/
+
+struct KIconGroup
+{
+ int size;
+ bool dblPixels;
+ bool alphaBlending;
+};
+
+#define KICONLOADER_CHECKS
+#ifdef KICONLOADER_CHECKS
+// Keep a list of recently created and destroyed KIconLoader instances in order
+// to detect bugs like #68528.
+struct KIconLoaderDebug
+ {
+ KIconLoaderDebug( KIconLoader* l, const QString& a )
+ : loader( l ), appname( a ), valid( true )
+ {}
+ KIconLoaderDebug() {}; // this QValueList feature annoys me
+ KIconLoader* loader;
+ QString appname;
+ bool valid;
+ QString delete_bt;
+ };
+
+static QValueList< KIconLoaderDebug > *kiconloaders;
+#endif
+
+/*** KIconLoader: the icon loader ***/
+
+KIconLoader::KIconLoader(const QString& _appname, KStandardDirs *_dirs)
+{
+#ifdef KICONLOADER_CHECKS
+ if( kiconloaders == NULL )
+ kiconloaders = new QValueList< KIconLoaderDebug>();
+ // check for the (very unlikely case) that new KIconLoader gets allocated
+ // at exactly same address like some previous one
+ for( QValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
+ it != kiconloaders->end();
+ )
+ {
+ if( (*it).loader == this )
+ it = kiconloaders->remove( it );
+ else
+ ++it;
+ }
+ kiconloaders->append( KIconLoaderDebug( this, _appname ));
+#endif
+ d = new KIconLoaderPrivate;
+ d->q = this;
+ d->mpGroups = 0L;
+ d->imgDict.setAutoDelete(true);
+ d->links.setAutoDelete(true);
+
+ if (kapp) {
+ kapp->addKipcEventMask(KIPC::IconChanged);
+ QObject::connect(kapp, SIGNAL(updateIconLoaders()), d, SLOT(reconfigure()));
+ }
+
+ init( _appname, _dirs );
+}
+
+void KIconLoader::reconfigure( const QString& _appname, KStandardDirs *_dirs )
+{
+ d->links.clear();
+ d->imgDict.clear();
+ d->mThemesInTree.clear();
+ d->lastImage.reset();
+ d->lastImageKey = QString::null;
+ delete [] d->mpGroups;
+
+ init( _appname, _dirs );
+}
+
+void KIconLoader::init( const QString& _appname, KStandardDirs *_dirs )
+{
+ // If this is unequal to 0, the iconloader is initialized
+ // successfully.
+ d->mpThemeRoot = 0L;
+
+ d->appname = _appname;
+ d->extraDesktopIconsLoaded = false;
+ d->delayedLoading = false;
+
+ if (_dirs)
+ d->mpDirs = _dirs;
+ else
+ d->mpDirs = KGlobal::dirs();
+
+ QString appname = _appname;
+ if (appname.isEmpty())
+ appname = KGlobal::instance()->instanceName();
+
+ // Add the default theme and its base themes to the theme tree
+ KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
+ if (!def->isValid())
+ {
+ delete def;
+ // warn, as this is actually a small penalty hit
+ kdDebug(264) << "Couldn't find current icon theme, falling back to default." << endl;
+ def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
+ if (!def->isValid())
+ {
+ kdError(264) << "Error: standard icon theme"
+ << " \"" << KIconTheme::defaultThemeName() << "\" "
+ << " not found!" << endl;
+ d->mpGroups=0L;
+ return;
+ }
+ }
+ d->mpThemeRoot = new KIconThemeNode(def);
+ d->links.append(d->mpThemeRoot);
+ d->mThemesInTree += KIconTheme::current();
+ addBaseThemes(d->mpThemeRoot, appname);
+
+ // These have to match the order in kicontheme.h
+ static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", 0L };
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs(config, "dummy");
+
+ // loading config and default sizes
+ d->mpGroups = new KIconGroup[(int) KIcon::LastGroup];
+ for (KIcon::Group i=KIcon::FirstGroup; i<KIcon::LastGroup; i++)
+ {
+ if (groups[i] == 0L)
+ break;
+ config->setGroup(QString::fromLatin1(groups[i]) + "Icons");
+ d->mpGroups[i].size = config->readNumEntry("Size", 0);
+ d->mpGroups[i].dblPixels = config->readBoolEntry("DoublePixels", false);
+ if (QPixmap::defaultDepth()>8)
+ d->mpGroups[i].alphaBlending = config->readBoolEntry("AlphaBlending", true);
+ else
+ d->mpGroups[i].alphaBlending = false;
+
+ if (!d->mpGroups[i].size)
+ d->mpGroups[i].size = d->mpThemeRoot->theme->defaultSize(i);
+ }
+
+ // Insert application specific themes at the top.
+ d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
+ appname + "/pics/");
+ // ################## KDE4: consider removing the toolbar directory
+ d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
+ appname + "/toolbar/");
+
+ // Add legacy icon dirs.
+ QStringList dirs;
+ dirs += d->mpDirs->resourceDirs("icon");
+ dirs += d->mpDirs->resourceDirs("pixmap");
+ dirs += d->mpDirs->resourceDirs("xdgdata-icon");
+ dirs += "/usr/share/pixmaps";
+ // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
+ dirs += d->mpDirs->resourceDirs("xdgdata-pixmap");
+ for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it)
+ d->mpDirs->addResourceDir("appicon", *it);
+
+#ifndef NDEBUG
+ QString dbgString = "Theme tree: ";
+ d->mpThemeRoot->printTree(dbgString);
+ kdDebug(264) << dbgString << endl;
+#endif
+}
+
+KIconLoader::~KIconLoader()
+{
+#ifdef KICONLOADER_CHECKS
+ for( QValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
+ it != kiconloaders->end();
+ ++it )
+ {
+ if( (*it).loader == this )
+ {
+ (*it).valid = false;
+ (*it).delete_bt = kdBacktrace();
+ break;
+ }
+ }
+#endif
+ /* antlarr: There's no need to delete d->mpThemeRoot as it's already
+ deleted when the elements of d->links are deleted */
+ d->mpThemeRoot=0;
+ delete[] d->mpGroups;
+ delete d;
+}
+
+void KIconLoader::enableDelayedIconSetLoading( bool enable )
+{
+ d->delayedLoading = enable;
+}
+
+bool KIconLoader::isDelayedIconSetLoadingEnabled() const
+{
+ return d->delayedLoading;
+}
+
+void KIconLoader::addAppDir(const QString& appname)
+{
+ d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
+ appname + "/pics/");
+ // ################## KDE4: consider removing the toolbar directory
+ d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
+ appname + "/toolbar/");
+ addAppThemes(appname);
+}
+
+void KIconLoader::addAppThemes(const QString& appname)
+{
+ if ( KIconTheme::current() != KIconTheme::defaultThemeName() )
+ {
+ KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
+ if (def->isValid())
+ {
+ KIconThemeNode* node = new KIconThemeNode(def);
+ d->links.append(node);
+ addBaseThemes(node, appname);
+ }
+ else
+ delete def;
+ }
+
+ KIconTheme *def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
+ KIconThemeNode* node = new KIconThemeNode(def);
+ d->links.append(node);
+ addBaseThemes(node, appname);
+}
+
+void KIconLoader::addBaseThemes(KIconThemeNode *node, const QString &appname)
+{
+ QStringList lst = node->theme->inherits();
+ QStringList::ConstIterator it;
+
+ for (it=lst.begin(); it!=lst.end(); ++it)
+ {
+ if( d->mThemesInTree.contains(*it) && (*it) != "hicolor")
+ continue;
+ KIconTheme *theme = new KIconTheme(*it,appname);
+ if (!theme->isValid()) {
+ delete theme;
+ continue;
+ }
+ KIconThemeNode *n = new KIconThemeNode(theme);
+ d->mThemesInTree.append(*it);
+ d->links.append(n);
+ addBaseThemes(n, appname);
+ }
+}
+
+void KIconLoader::addExtraDesktopThemes()
+{
+ if ( d->extraDesktopIconsLoaded ) return;
+
+ QStringList list;
+ QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
+ QStringList::ConstIterator it;
+ char buf[1000];
+ int r;
+ for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
+ {
+ QDir dir(*it);
+ if (!dir.exists())
+ continue;
+ QStringList lst = dir.entryList("default.*", QDir::Dirs);
+ QStringList::ConstIterator it2;
+ for (it2=lst.begin(); it2!=lst.end(); ++it2)
+ {
+ if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
+ && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
+ continue;
+ r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
+ if ( r>0 )
+ {
+ buf[r]=0;
+ QDir dir2( buf );
+ QString themeName=dir2.dirName();
+
+ if (!list.contains(themeName))
+ list.append(themeName);
+ }
+ }
+ }
+
+ for (it=list.begin(); it!=list.end(); ++it)
+ {
+ if ( d->mThemesInTree.contains(*it) )
+ continue;
+ if ( *it == QString("default.kde") ) continue;
+
+ KIconTheme *def = new KIconTheme( *it, "" );
+ KIconThemeNode* node = new KIconThemeNode(def);
+ d->mThemesInTree.append(*it);
+ d->links.append(node);
+ addBaseThemes(node, "" );
+ }
+
+ d->extraDesktopIconsLoaded=true;
+
+}
+
+bool KIconLoader::extraDesktopThemesAdded() const
+{
+ return d->extraDesktopIconsLoaded;
+}
+
+QString KIconLoader::removeIconExtension(const QString &name) const
+{
+ int extensionLength=0;
+
+ QString ext = name.right(4);
+
+ static const QString &png_ext = KGlobal::staticQString(".png");
+ static const QString &xpm_ext = KGlobal::staticQString(".xpm");
+ if (ext == png_ext || ext == xpm_ext)
+ extensionLength=4;
+#ifdef HAVE_LIBART
+ else
+ {
+ static const QString &svgz_ext = KGlobal::staticQString(".svgz");
+ static const QString &svg_ext = KGlobal::staticQString(".svg");
+
+ if (name.right(5) == svgz_ext)
+ extensionLength=5;
+ else if (ext == svg_ext)
+ extensionLength=4;
+ }
+#endif
+
+ if ( extensionLength > 0 )
+ {
+ return name.left(name.length() - extensionLength);
+ }
+ return name;
+}
+
+QString KIconLoader::removeIconExtensionInternal(const QString &name) const
+{
+ QString name_noext = removeIconExtension(name);
+
+#ifndef NDEBUG
+ if (name != name_noext)
+ {
+ kdDebug(264) << "Application " << KGlobal::instance()->instanceName()
+ << " loads icon " << name << " with extension." << endl;
+ }
+#endif
+
+ return name_noext;
+}
+
+KIcon KIconLoader::findMatchingIcon(const QString& name, int size) const
+{
+ KIcon icon;
+
+ const QString *ext[4];
+ int count=0;
+ static const QString &png_ext = KGlobal::staticQString(".png");
+ ext[count++]=&png_ext;
+#ifdef HAVE_LIBART
+ static const QString &svgz_ext = KGlobal::staticQString(".svgz");
+ ext[count++]=&svgz_ext;
+ static const QString &svg_ext = KGlobal::staticQString(".svg");
+ ext[count++]=&svg_ext;
+#endif
+ static const QString &xpm_ext = KGlobal::staticQString(".xpm");
+ ext[count++]=&xpm_ext;
+
+ /* JRT: To follow the XDG spec, the order in which we look for an
+ icon 1s:
+
+ png, svgz, svg, xpm exact match
+ png, svgz, svg, xpm best match
+ next theme in inheritance tree : png, svgz, svg, xpm exact match
+ png, svgz, svg, xpm best match
+ next theme in inheritance tree : png, svgz, svg, xpm exact match
+ png, svgz, svg, xpm best match
+ and so on
+
+ */
+ for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
+ themeNode = d->links.next() )
+ {
+ for (int i = 0 ; i < count ; i++)
+ {
+ icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchExact);
+ if (icon.isValid()) goto icon_found ;
+ }
+
+ for (int i = 0 ; i < count ; i++)
+ {
+ icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchBest);
+ if (icon.isValid()) goto icon_found;
+ }
+ }
+ icon_found:
+ return icon;
+}
+
+inline QString KIconLoader::unknownIconPath( int size ) const
+{
+ static const QString &str_unknown = KGlobal::staticQString("unknown");
+
+ KIcon icon = findMatchingIcon(str_unknown, size);
+ if (!icon.isValid())
+ {
+ kdDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
+ << size << endl;
+ return QString::null;
+ }
+ return icon.path;
+}
+
+// Finds the absolute path to an icon.
+
+QString KIconLoader::iconPath(const QString& _name, int group_or_size,
+ bool canReturnNull) const
+{
+ if (d->mpThemeRoot == 0L)
+ return QString::null;
+
+ if (!QDir::isRelativePath(_name))
+ return _name;
+
+ QString name = removeIconExtensionInternal( _name );
+
+ QString path;
+ if (group_or_size == KIcon::User)
+ {
+ static const QString &png_ext = KGlobal::staticQString(".png");
+ static const QString &xpm_ext = KGlobal::staticQString(".xpm");
+ path = d->mpDirs->findResource("appicon", name + png_ext);
+
+#ifdef HAVE_LIBART
+ static const QString &svgz_ext = KGlobal::staticQString(".svgz");
+ static const QString &svg_ext = KGlobal::staticQString(".svg");
+ if (path.isEmpty())
+ path = d->mpDirs->findResource("appicon", name + svgz_ext);
+ if (path.isEmpty())
+ path = d->mpDirs->findResource("appicon", name + svg_ext);
+#endif
+ if (path.isEmpty())
+ path = d->mpDirs->findResource("appicon", name + xpm_ext);
+ return path;
+ }
+
+ if (group_or_size >= KIcon::LastGroup)
+ {
+ kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
+ return path;
+ }
+
+ int size;
+ if (group_or_size >= 0)
+ size = d->mpGroups[group_or_size].size;
+ else
+ size = -group_or_size;
+
+ if (_name.isEmpty()) {
+ if (canReturnNull)
+ return QString::null;
+ else
+ return unknownIconPath(size);
+ }
+
+ KIcon icon = findMatchingIcon(name, size);
+
+ if (!icon.isValid())
+ {
+ // Try "User" group too.
+ path = iconPath(name, KIcon::User, true);
+ if (!path.isEmpty() || canReturnNull)
+ return path;
+
+ if (canReturnNull)
+ return QString::null;
+ else
+ return unknownIconPath(size);
+ }
+ return icon.path;
+}
+
+QPixmap KIconLoader::loadIcon(const QString& _name, KIcon::Group group, int size,
+ int state, QString *path_store, bool canReturnNull) const
+{
+ QString name = _name;
+ QPixmap pix;
+ QString key;
+ bool absolutePath=false, favIconOverlay=false;
+
+ if (d->mpThemeRoot == 0L)
+ return pix;
+
+ // Special case for absolute path icons.
+ if (name.startsWith("favicons/"))
+ {
+ favIconOverlay = true;
+ name = locateLocal("cache", name+".png");
+ }
+ if (!QDir::isRelativePath(name)) absolutePath=true;
+
+ static const QString &str_unknown = KGlobal::staticQString("unknown");
+
+ // Special case for "User" icons.
+ if (group == KIcon::User)
+ {
+ key = "$kicou_";
+ key += QString::number(size); key += '_';
+ key += name;
+ bool inCache = QPixmapCache::find(key, pix);
+ if (inCache && (path_store == 0L))
+ return pix;
+
+ QString path = (absolutePath) ? name :
+ iconPath(name, KIcon::User, canReturnNull);
+ if (path.isEmpty())
+ {
+ if (canReturnNull)
+ return pix;
+ // We don't know the desired size: use small
+ path = iconPath(str_unknown, KIcon::Small, true);
+ if (path.isEmpty())
+ {
+ kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
+ return pix;
+ }
+ }
+
+ if (path_store != 0L)
+ *path_store = path;
+ if (inCache)
+ return pix;
+ QImage img(path);
+ if (size != 0)
+ img=img.smoothScale(size,size);
+
+ pix.convertFromImage(img);
+ QPixmapCache::insert(key, pix);
+ return pix;
+ }
+
+ // Regular case: Check parameters
+
+ if ((group < -1) || (group >= KIcon::LastGroup))
+ {
+ kdDebug(264) << "Illegal icon group: " << group << endl;
+ group = KIcon::Desktop;
+ }
+
+ int overlay = (state & KIcon::OverlayMask);
+ state &= ~KIcon::OverlayMask;
+ if ((state < 0) || (state >= KIcon::LastState))
+ {
+ kdDebug(264) << "Illegal icon state: " << state << endl;
+ state = KIcon::DefaultState;
+ }
+
+ if (size == 0 && group < 0)
+ {
+ kdDebug(264) << "Neither size nor group specified!" << endl;
+ group = KIcon::Desktop;
+ }
+
+ if (!absolutePath)
+ {
+ if (!canReturnNull && name.isEmpty())
+ name = str_unknown;
+ else
+ name = removeIconExtensionInternal(name);
+ }
+
+ // If size == 0, use default size for the specified group.
+ if (size == 0)
+ {
+ size = d->mpGroups[group].size;
+ }
+ favIconOverlay = favIconOverlay && size > 22;
+
+ // Generate a unique cache key for the icon.
+
+ key = "$kico_";
+ key += name; key += '_';
+ key += QString::number(size); key += '_';
+
+ QString overlayStr = QString::number( overlay );
+
+ QString noEffectKey = key + '_' + overlayStr;
+
+ if (group >= 0)
+ {
+ key += d->mpEffect.fingerprint(group, state);
+ if (d->mpGroups[group].dblPixels)
+ key += QString::fromLatin1(":dblsize");
+ } else
+ key += QString::fromLatin1("noeffect");
+ key += '_';
+ key += overlayStr;
+
+ // Is the icon in the cache?
+ bool inCache = QPixmapCache::find(key, pix);
+ if (inCache && (path_store == 0L))
+ return pix;
+
+ QImage *img = 0;
+ int iconType;
+ int iconThreshold;
+
+ if ( ( path_store != 0L ) ||
+ noEffectKey != d->lastImageKey )
+ {
+ // No? load it.
+ KIcon icon;
+ if (absolutePath && !favIconOverlay)
+ {
+ icon.context=KIcon::Any;
+ icon.type=KIcon::Scalable;
+ icon.path=name;
+ }
+ else
+ {
+ if (!name.isEmpty())
+ icon = findMatchingIcon(favIconOverlay ? QString("www") : name, size);
+
+ if (!icon.isValid())
+ {
+ // Try "User" icon too. Some apps expect this.
+ if (!name.isEmpty())
+ pix = loadIcon(name, KIcon::User, size, state, path_store, true);
+ if (!pix.isNull() || canReturnNull) {
+ QPixmapCache::insert(key, pix);
+ return pix;
+ }
+
+ icon = findMatchingIcon(str_unknown, size);
+ if (!icon.isValid())
+ {
+ kdDebug(264)
+ << "Warning: could not find \"Unknown\" icon for size = "
+ << size << endl;
+ return pix;
+ }
+ }
+ }
+
+ if (path_store != 0L)
+ *path_store = icon.path;
+ if (inCache)
+ return pix;
+
+ // Use the extension as the format. Works for XPM and PNG, but not for SVG
+ QString ext = icon.path.right(3).upper();
+ if(ext != "SVG" && ext != "VGZ")
+ {
+ img = new QImage(icon.path, ext.latin1());
+ if (img->isNull()) {
+ delete img;
+ return pix;
+ }
+ }
+#ifdef HAVE_LIBART
+ else
+ {
+ // Special stuff for SVG icons
+ KSVGIconEngine *svgEngine = new KSVGIconEngine();
+
+ if(svgEngine->load(size, size, icon.path))
+ img = svgEngine->painter()->image();
+ else
+ img = new QImage();
+
+ delete svgEngine;
+ }
+#endif
+
+ iconType = icon.type;
+ iconThreshold = icon.threshold;
+
+ d->lastImage = img->copy();
+ d->lastImageKey = noEffectKey;
+ d->lastIconType = iconType;
+ d->lastIconThreshold = iconThreshold;
+ }
+ else
+ {
+ img = new QImage( d->lastImage.copy() );
+ iconType = d->lastIconType;
+ iconThreshold = d->lastIconThreshold;
+ }
+
+ // Blend in all overlays
+ if (overlay)
+ {
+ QImage *ovl;
+ KIconTheme *theme = d->mpThemeRoot->theme;
+ if ((overlay & KIcon::LockOverlay) &&
+ ((ovl = loadOverlay(theme->lockOverlay(), size)) != 0L))
+ KIconEffect::overlay(*img, *ovl);
+ if ((overlay & KIcon::LinkOverlay) &&
+ ((ovl = loadOverlay(theme->linkOverlay(), size)) != 0L))
+ KIconEffect::overlay(*img, *ovl);
+ if ((overlay & KIcon::ZipOverlay) &&
+ ((ovl = loadOverlay(theme->zipOverlay(), size)) != 0L))
+ KIconEffect::overlay(*img, *ovl);
+ if ((overlay & KIcon::ShareOverlay) &&
+ ((ovl = loadOverlay(theme->shareOverlay(), size)) != 0L))
+ KIconEffect::overlay(*img, *ovl);
+ if (overlay & KIcon::HiddenOverlay)
+ {
+ if (img->depth() != 32)
+ *img = img->convertDepth(32);
+ for (int y = 0; y < img->height(); y++)
+ {
+ QRgb *line = reinterpret_cast<QRgb *>(img->scanLine(y));
+ for (int x = 0; x < img->width(); x++)
+ line[x] = (line[x] & 0x00ffffff) | (QMIN(0x80, qAlpha(line[x])) << 24);
+ }
+ }
+ }
+
+ // Scale the icon and apply effects if necessary
+ if (iconType == KIcon::Scalable && size != img->width())
+ {
+ *img = img->smoothScale(size, size);
+ }
+ if (iconType == KIcon::Threshold && size != img->width())
+ {
+ if ( abs(size-img->width())>iconThreshold )
+ *img = img->smoothScale(size, size);
+ }
+ if (group >= 0 && d->mpGroups[group].dblPixels)
+ {
+ *img = d->mpEffect.doublePixels(*img);
+ }
+ if (group >= 0)
+ {
+ *img = d->mpEffect.apply(*img, group, state);
+ }
+
+ if (favIconOverlay)
+ {
+ QImage favIcon(name, "PNG");
+ int x = img->width() - favIcon.width() - 1,
+ y = img->height() - favIcon.height() - 1;
+ if( favIcon.depth() != 32 )
+ favIcon = favIcon.convertDepth( 32 );
+ if( img->depth() != 32 )
+ *img = img->convertDepth( 32 );
+ for( int line = 0;
+ line < favIcon.height();
+ ++line )
+ {
+ QRgb* fpos = reinterpret_cast< QRgb* >( favIcon.scanLine( line ));
+ QRgb* ipos = reinterpret_cast< QRgb* >( img->scanLine( line + y )) + x;
+ for( int i = 0;
+ i < favIcon.width();
+ ++i, ++fpos, ++ipos )
+ *ipos = qRgba( ( qRed( *ipos ) * ( 255 - qAlpha( *fpos )) + qRed( *fpos ) * qAlpha( *fpos )) / 255,
+ ( qGreen( *ipos ) * ( 255 - qAlpha( *fpos )) + qGreen( *fpos ) * qAlpha( *fpos )) / 255,
+ ( qBlue( *ipos ) * ( 255 - qAlpha( *fpos )) + qBlue( *fpos ) * qAlpha( *fpos )) / 255,
+ ( qAlpha( *ipos ) * ( 255 - qAlpha( *fpos )) + qAlpha( *fpos ) * qAlpha( *fpos )) / 255 );
+ }
+ }
+
+ pix.convertFromImage(*img);
+
+ delete img;
+
+ QPixmapCache::insert(key, pix);
+ return pix;
+}
+
+QImage *KIconLoader::loadOverlay(const QString &name, int size) const
+{
+ QString key = name + '_' + QString::number(size);
+ QImage *image = d->imgDict.find(key);
+ if (image != 0L)
+ return image;
+
+ KIcon icon = findMatchingIcon(name, size);
+ if (!icon.isValid())
+ {
+ kdDebug(264) << "Overlay " << name << "not found." << endl;
+ return 0L;
+ }
+ image = new QImage(icon.path);
+ // In some cases (since size in findMatchingIcon() is more a hint than a
+ // constraint) image->size can be != size. If so perform rescaling.
+ if ( size != image->width() )
+ *image = image->smoothScale( size, size );
+ d->imgDict.insert(key, image);
+ return image;
+}
+
+
+
+QMovie KIconLoader::loadMovie(const QString& name, KIcon::Group group, int size) const
+{
+ QString file = moviePath( name, group, size );
+ if (file.isEmpty())
+ return QMovie();
+ int dirLen = file.findRev('/');
+ QString icon = iconPath(name, size ? -size : group, true);
+ if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
+ return QMovie();
+ return QMovie(file);
+}
+
+QString KIconLoader::moviePath(const QString& name, KIcon::Group group, int size) const
+{
+ if (!d->mpGroups) return QString::null;
+
+ if ( (group < -1 || group >= KIcon::LastGroup) && group != KIcon::User )
+ {
+ kdDebug(264) << "Illegal icon group: " << group << endl;
+ group = KIcon::Desktop;
+ }
+ if (size == 0 && group < 0)
+ {
+ kdDebug(264) << "Neither size nor group specified!" << endl;
+ group = KIcon::Desktop;
+ }
+
+ QString file = name + ".mng";
+ if (group == KIcon::User)
+ {
+ file = d->mpDirs->findResource("appicon", file);
+ }
+ else
+ {
+ if (size == 0)
+ size = d->mpGroups[group].size;
+
+ KIcon icon;
+
+ for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
+ themeNode = d->links.next() )
+ {
+ icon = themeNode->theme->iconPath(file, size, KIcon::MatchExact);
+ if (icon.isValid()) goto icon_found ;
+
+ icon = themeNode->theme->iconPath(file, size, KIcon::MatchBest);
+ if (icon.isValid()) goto icon_found ;
+ }
+
+ icon_found:
+ file = icon.isValid() ? icon.path : QString::null;
+ }
+ return file;
+}
+
+
+QStringList KIconLoader::loadAnimated(const QString& name, KIcon::Group group, int size) const
+{
+ QStringList lst;
+
+ if (!d->mpGroups) return lst;
+
+ if ((group < -1) || (group >= KIcon::LastGroup))
+ {
+ kdDebug(264) << "Illegal icon group: " << group << endl;
+ group = KIcon::Desktop;
+ }
+ if ((size == 0) && (group < 0))
+ {
+ kdDebug(264) << "Neither size nor group specified!" << endl;
+ group = KIcon::Desktop;
+ }
+
+ QString file = name + "/0001";
+ if (group == KIcon::User)
+ {
+ file = d->mpDirs->findResource("appicon", file + ".png");
+ } else
+ {
+ if (size == 0)
+ size = d->mpGroups[group].size;
+ KIcon icon = findMatchingIcon(file, size);
+ file = icon.isValid() ? icon.path : QString::null;
+
+ }
+ if (file.isEmpty())
+ return lst;
+
+ QString path = file.left(file.length()-8);
+ DIR* dp = opendir( QFile::encodeName(path) );
+ if(!dp)
+ return lst;
+
+ struct dirent* ep;
+ while( ( ep = readdir( dp ) ) != 0L )
+ {
+ QString fn(QFile::decodeName(ep->d_name));
+ if(!(fn.left(4)).toUInt())
+ continue;
+
+ lst += path + fn;
+ }
+ closedir ( dp );
+ lst.sort();
+ return lst;
+}
+
+KIconTheme *KIconLoader::theme() const
+{
+ if (d->mpThemeRoot) return d->mpThemeRoot->theme;
+ return 0L;
+}
+
+int KIconLoader::currentSize(KIcon::Group group) const
+{
+ if (!d->mpGroups) return -1;
+
+ if (group < 0 || group >= KIcon::LastGroup)
+ {
+ kdDebug(264) << "Illegal icon group: " << group << endl;
+ return -1;
+ }
+ return d->mpGroups[group].size;
+}
+
+QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
+{
+ QDir dir(iconsDir);
+ QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
+ QStringList result;
+ QStringList::ConstIterator it;
+ for (it=lst.begin(); it!=lst.end(); ++it)
+ result += iconsDir + "/" + *it;
+ return result;
+}
+
+QStringList KIconLoader::queryIconsByContext(int group_or_size,
+ KIcon::Context context) const
+{
+ QStringList result;
+ if (group_or_size >= KIcon::LastGroup)
+ {
+ kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
+ return result;
+ }
+ int size;
+ if (group_or_size >= 0)
+ size = d->mpGroups[group_or_size].size;
+ else
+ size = -group_or_size;
+
+ for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
+ themeNode = d->links.next() )
+ themeNode->queryIconsByContext(&result, size, context);
+
+ // Eliminate duplicate entries (same icon in different directories)
+ QString name;
+ QStringList res2, entries;
+ QStringList::ConstIterator it;
+ for (it=result.begin(); it!=result.end(); ++it)
+ {
+ int n = (*it).findRev('/');
+ if (n == -1)
+ name = *it;
+ else
+ name = (*it).mid(n+1);
+ name = removeIconExtension(name);
+ if (!entries.contains(name))
+ {
+ entries += name;
+ res2 += *it;
+ }
+ }
+ return res2;
+
+}
+
+QStringList KIconLoader::queryIcons(int group_or_size, KIcon::Context context) const
+{
+ QStringList result;
+ if (group_or_size >= KIcon::LastGroup)
+ {
+ kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
+ return result;
+ }
+ int size;
+ if (group_or_size >= 0)
+ size = d->mpGroups[group_or_size].size;
+ else
+ size = -group_or_size;
+
+ for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
+ themeNode = d->links.next() )
+ themeNode->queryIcons(&result, size, context);
+
+ // Eliminate duplicate entries (same icon in different directories)
+ QString name;
+ QStringList res2, entries;
+ QStringList::ConstIterator it;
+ for (it=result.begin(); it!=result.end(); ++it)
+ {
+ int n = (*it).findRev('/');
+ if (n == -1)
+ name = *it;
+ else
+ name = (*it).mid(n+1);
+ name = removeIconExtension(name);
+ if (!entries.contains(name))
+ {
+ entries += name;
+ res2 += *it;
+ }
+ }
+ return res2;
+}
+
+// used by KIconDialog to find out which contexts to offer in a combobox
+bool KIconLoader::hasContext(KIcon::Context context) const
+{
+ for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
+ themeNode = d->links.next() )
+ if( themeNode->theme->hasContext( context ))
+ return true;
+ return false;
+}
+
+KIconEffect * KIconLoader::iconEffect() const
+{
+ return &d->mpEffect;
+}
+
+bool KIconLoader::alphaBlending(KIcon::Group group) const
+{
+ if (!d->mpGroups) return false;
+
+ if (group < 0 || group >= KIcon::LastGroup)
+ {
+ kdDebug(264) << "Illegal icon group: " << group << endl;
+ return false;
+ }
+ return d->mpGroups[group].alphaBlending;
+}
+
+QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size, bool canReturnNull)
+{
+ return loadIconSet( name, group, size, canReturnNull, true );
+}
+
+QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size)
+{
+ return loadIconSet( name, group, size, false );
+}
+
+/*** class for delayed icon loading for QIconSet ***/
+
+class KIconFactory
+ : public QIconFactory
+ {
+ public:
+ KIconFactory( const QString& iconName_P, KIcon::Group group_P,
+ int size_P, KIconLoader* loader_P );
+ KIconFactory( const QString& iconName_P, KIcon::Group group_P,
+ int size_P, KIconLoader* loader_P, bool canReturnNull );
+ virtual QPixmap* createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode, QIconSet::State );
+ private:
+ QString iconName;
+ KIcon::Group group;
+ int size;
+ KIconLoader* loader;
+ bool canReturnNull;
+ };
+
+
+QIconSet KIconLoader::loadIconSet( const QString& name, KIcon::Group g, int s,
+ bool canReturnNull, bool immediateExistenceCheck)
+{
+ if ( !d->delayedLoading )
+ return loadIconSetNonDelayed( name, g, s, canReturnNull );
+
+ if (g < -1 || g > 6) {
+ kdDebug() << "KIconLoader::loadIconSet " << name << " " << (int)g << " " << s << endl;
+ qDebug("%s", kdBacktrace().latin1());
+ abort();
+ }
+
+ if(canReturnNull && immediateExistenceCheck)
+ { // we need to find out if the icon actually exists
+ QPixmap pm = loadIcon( name, g, s, KIcon::DefaultState, NULL, true );
+ if( pm.isNull())
+ return QIconSet();
+
+ QIconSet ret( pm );
+ ret.installIconFactory( new KIconFactory( name, g, s, this ));
+ return ret;
+ }
+
+ QIconSet ret;
+ ret.installIconFactory( new KIconFactory( name, g, s, this, canReturnNull ));
+ return ret;
+}
+
+QIconSet KIconLoader::loadIconSetNonDelayed( const QString& name,
+ KIcon::Group g,
+ int s, bool canReturnNull )
+{
+ QIconSet iconset;
+ QPixmap tmp = loadIcon(name, g, s, KIcon::ActiveState, NULL, canReturnNull);
+ iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Active );
+ // we don't use QIconSet's resizing anyway
+ iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Active );
+ tmp = loadIcon(name, g, s, KIcon::DisabledState, NULL, canReturnNull);
+ iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Disabled );
+ iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Disabled );
+ tmp = loadIcon(name, g, s, KIcon::DefaultState, NULL, canReturnNull);
+ iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Normal );
+ iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Normal );
+ return iconset;
+}
+
+KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
+ int size_P, KIconLoader* loader_P )
+ : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
+{
+ canReturnNull = false;
+ setAutoDelete( true );
+}
+
+KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
+ int size_P, KIconLoader* loader_P, bool canReturnNull_P )
+ : iconName( iconName_P ), group( group_P ), size( size_P ),
+ loader( loader_P ), canReturnNull( canReturnNull_P)
+{
+ setAutoDelete( true );
+}
+
+QPixmap* KIconFactory::createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode mode_P, QIconSet::State )
+ {
+#ifdef KICONLOADER_CHECKS
+ bool found = false;
+ for( QValueList< KIconLoaderDebug >::Iterator it = kiconloaders->begin();
+ it != kiconloaders->end();
+ ++it )
+ {
+ if( (*it).loader == loader )
+ {
+ found = true;
+ if( !(*it).valid )
+ {
+#ifdef NDEBUG
+ loader = KGlobal::iconLoader();
+ iconName = "no_way_man_you_will_get_broken_icon";
+#else
+ kdWarning() << "Using already destroyed KIconLoader for loading an icon!" << endl;
+ kdWarning() << "Appname:" << (*it).appname << ", icon:" << iconName << endl;
+ kdWarning() << "Deleted at:" << endl;
+ kdWarning() << (*it).delete_bt << endl;
+ kdWarning() << "Current:" << endl;
+ kdWarning() << kdBacktrace() << endl;
+ abort();
+ return NULL;
+#endif
+ }
+ break;
+ }
+ }
+ if( !found )
+ {
+#ifdef NDEBUG
+ loader = KGlobal::iconLoader();
+ iconName = "no_way_man_you_will_get_broken_icon";
+#else
+ kdWarning() << "Using unknown KIconLoader for loading an icon!" << endl;
+ kdWarning() << "Icon:" << iconName << endl;
+ kdWarning() << kdBacktrace() << endl;
+ abort();
+ return NULL;
+#endif
+ }
+#endif
+ // QIconSet::Mode to KIcon::State conversion
+ static const KIcon::States tbl[] = { KIcon::DefaultState, KIcon::DisabledState, KIcon::ActiveState };
+ int state = KIcon::DefaultState;
+ if( mode_P <= QIconSet::Active )
+ state = tbl[ mode_P ];
+ if( group >= 0 && state == KIcon::ActiveState )
+ { // active and normal icon are usually the same
+ if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState )
+ == loader->iconEffect()->fingerprint(group, KIcon::DefaultState ))
+ return 0; // so let QIconSet simply duplicate it
+ }
+ // ignore passed size
+ // ignore passed state (i.e. on/off)
+ QPixmap pm = loader->loadIcon( iconName, group, size, state, 0, canReturnNull );
+ return new QPixmap( pm );
+ }
+
+// Easy access functions
+
+QPixmap DesktopIcon(const QString& name, int force_size, int state,
+ KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIcon(name, KIcon::Desktop, force_size, state);
+}
+
+QPixmap DesktopIcon(const QString& name, KInstance *instance)
+{
+ return DesktopIcon(name, 0, KIcon::DefaultState, instance);
+}
+
+QIconSet DesktopIconSet(const QString& name, int force_size, KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIconSet( name, KIcon::Desktop, force_size );
+}
+
+QPixmap BarIcon(const QString& name, int force_size, int state,
+ KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIcon(name, KIcon::Toolbar, force_size, state);
+}
+
+QPixmap BarIcon(const QString& name, KInstance *instance)
+{
+ return BarIcon(name, 0, KIcon::DefaultState, instance);
+}
+
+QIconSet BarIconSet(const QString& name, int force_size, KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIconSet( name, KIcon::Toolbar, force_size );
+}
+
+QPixmap SmallIcon(const QString& name, int force_size, int state,
+ KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIcon(name, KIcon::Small, force_size, state);
+}
+
+QPixmap SmallIcon(const QString& name, KInstance *instance)
+{
+ return SmallIcon(name, 0, KIcon::DefaultState, instance);
+}
+
+QIconSet SmallIconSet(const QString& name, int force_size, KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIconSet( name, KIcon::Small, force_size );
+}
+
+QPixmap MainBarIcon(const QString& name, int force_size, int state,
+ KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIcon(name, KIcon::MainToolbar, force_size, state);
+}
+
+QPixmap MainBarIcon(const QString& name, KInstance *instance)
+{
+ return MainBarIcon(name, 0, KIcon::DefaultState, instance);
+}
+
+QIconSet MainBarIconSet(const QString& name, int force_size, KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIconSet( name, KIcon::MainToolbar, force_size );
+}
+
+QPixmap UserIcon(const QString& name, int state, KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIcon(name, KIcon::User, 0, state);
+}
+
+QPixmap UserIcon(const QString& name, KInstance *instance)
+{
+ return UserIcon(name, KIcon::DefaultState, instance);
+}
+
+QIconSet UserIconSet(const QString& name, KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->loadIconSet( name, KIcon::User );
+}
+
+int IconSize(KIcon::Group group, KInstance *instance)
+{
+ KIconLoader *loader = instance->iconLoader();
+ return loader->currentSize(group);
+}
+
+QPixmap KIconLoader::unknown()
+{
+ QPixmap pix;
+ if ( QPixmapCache::find("unknown", pix) )
+ return pix;
+
+ QString path = KGlobal::iconLoader()->iconPath("unknown", KIcon::Small, true);
+ if (path.isEmpty())
+ {
+ kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
+ pix.resize(32,32);
+ } else
+ {
+ pix.load(path);
+ QPixmapCache::insert("unknown", pix);
+ }
+
+ return pix;
+}
+
+void KIconLoaderPrivate::reconfigure()
+{
+ q->reconfigure(appname, mpDirs);
+}
+
+#include "kiconloader_p.moc"
diff --git a/kdecore/kiconloader.h b/kdecore/kiconloader.h
new file mode 100644
index 000000000..7c445b962
--- /dev/null
+++ b/kdecore/kiconloader.h
@@ -0,0 +1,553 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdecore.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * Antonio Larrosa <larrosa@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#ifndef __KIconLoader_h_Included__
+#define __KIconLoader_h_Included__
+
+#include <qstring.h>
+#include <qpixmap.h>
+#include <qiconset.h>
+
+// Grmbl, X headers.....
+#ifdef Status
+#define KIconLoaderXStatus Status
+#undef Status
+#endif
+#include <qmovie.h>
+#ifdef KIconLoaderXStatus
+#define Status int
+#undef KIconLoaderXStatus
+#endif
+
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kicontheme.h>
+
+struct KIconGroup;
+class KIconThemeNode;
+class KConfig;
+struct KIconLoaderPrivate;
+class KStandardDirs;
+class KIconEffect;
+
+
+/**
+ * Iconloader for KDE.
+ *
+ * KIconLoader will load the current icon theme and all its base themes.
+ * Icons will be searched in any of these themes. Additionally, it caches
+ * icons and applies effects according the the user's preferences.
+ *
+ * In KDE, it is encouraged to load icons by "Group". An icon group is a
+ * location on the screen where icons are being used. Standard groups are:
+ * Desktop, Toolbar, MainToolbar, Small and Panel. Each group has some
+ * centrally configured properties bound to it, including the icon size
+ * and effects. This makes it possible to offer a consistent icon look in
+ * all KDE applications.
+ *
+ * The standard groups are defined below.
+ *
+ * @li KIcon::Desktop: Icons in the iconview of konqueror, kdesktop and similar apps.
+ * @li KIcon::Toolbar: Icons in toolbars.
+ * @li KIcon::MainToolbar: Icons in the main toolbars.
+ * @li KIcon::Small: Various small (typical 16x16) places: titlebars, listviews
+ * and menu entries.
+ * @li KIcon::Panel: Icons in kicker's panel
+ *
+ * The icons are stored on disk in an icon theme or in a standalone
+ * directory. The icon theme directories contain multiple sizes and/or
+ * depths for the same icon. The iconloader will load the correct one based
+ * on the icon group and the current theme. Icon themes are stored globally
+ * in share/icons, or, application specific in share/apps/$appdir/icons.
+ *
+ * The standalone directories contain just one version of an icon. The
+ * directories that are searched are: $appdir/pics and $appdir/toolbar.
+ * Icons in these directories can be loaded by using the special group
+ * "User".
+ *
+ */
+class KDECORE_EXPORT KIconLoader
+{
+public:
+
+ /**
+ * Constructs an iconloader.
+ * @param appname Add the data directories of this application to the
+ * icon search path for the "User" group. The default argument adds the
+ * directories of the current application.
+ * @param dirs the KStandardDirs object to use. If null the global one is used
+ *
+ * Usually, you use the default iconloader, which can be accessed via
+ * KGlobal::iconLoader(), so you hardly ever have to create an
+ * iconloader object yourself. That one is the current KInstance's
+ * (typically KApplication's) iconloader.
+ * @see KGlobal::iconLoader()
+ * @see KInstance::iconLoader()
+ */
+ KIconLoader(const QString& appname=QString::null, KStandardDirs *dirs = 0);
+
+ /**
+ * Cleanup
+ */
+ ~KIconLoader();
+
+ /**
+ * Adds @p appname to the list of application specific directories.
+ * @param appname The application name.
+ */
+ void addAppDir(const QString& appname);
+
+ /**
+ * Loads an icon. It will try very hard to find an icon which is
+ * suitable. If no exact match is found, a close match is searched.
+ * If neither an exact nor a close match is found, a null pixmap or
+ * the "unknown" pixmap is returned, depending on the value of the
+ * @p canReturnNull parameter.
+ *
+ * @param name The name of the icon, without extension.
+ * @param group The icon group. This will specify the size of and effects to
+ * be applied to the icon.
+ * @param size If nonzero, this overrides the size specified by @p group.
+ * See KIcon::StdSizes.
+ * @param state The icon state: @p DefaultState, @p ActiveState or
+ * @p DisabledState. Depending on the user's preferences, the iconloader
+ * may apply a visual effect to hint about its state.
+ * @param path_store If not null, the path of the icon is stored here.
+ * @param canReturnNull Can return a null pixmap? If false, the
+ * "unknown" pixmap is returned when no appropriate icon has been found.
+ * @return the QPixmap. Can be null when not found, depending on
+ * @p canReturnNull.
+ */
+ QPixmap loadIcon(const QString& name, KIcon::Group group, int size=0,
+ int state=KIcon::DefaultState, QString *path_store=0L,
+ bool canReturnNull=false) const;
+
+ /**
+ * Creates an icon set, that will do on-demand loading of the icon.
+ * Loading itself is done by calling loadIcon .
+ *
+ * @param name The name of the icon, without extension.
+ * @param group The icon group. This will specify the size of and effects to
+ * be applied to the icon.
+ * @param size If nonzero, this overrides the size specified by @p group.
+ * See KIcon::StdSizes.
+ * @param canReturnNull Can return a null iconset? If false, iconset
+ * containing the "unknown" pixmap is returned when no appropriate icon has
+ * been found.
+ * @param immediateExistenceCheck If true on-demand icon loading will be
+ * disabled for canReturnNull and a null iconset may be returned immediately
+ * @return the icon set. Can be null when not found, depending on
+ * @p canReturnNull.
+ * @since 3.5
+ */
+ QIconSet loadIconSet(const QString& name, KIcon::Group group, int size,
+ bool canReturnNull, bool immediateExistenceCheck);
+
+ // KDE4 merge as (const QString&,KIcon::Group,int=0,bool=false,bool=true);
+ /**
+ * Creates an icon set, that will do on-demand loading of the icon.
+ * Loading itself is done by calling loadIcon .
+ *
+ * @param name The name of the icon, without extension.
+ * @param group The icon group. This will specify the size of and effects to
+ * be applied to the icon.
+ * @param size If nonzero, this overrides the size specified by @p group.
+ * See KIcon::StdSizes.
+ * @param canReturnNull Can return a null iconset? If false, iconset
+ * containing the "unknown" pixmap is returned when no appropriate icon has
+ * been found.
+ * @return the icon set. Can be null when not found, depending on
+ * @p canReturnNull.
+ * @since 3.1
+ */
+ QIconSet loadIconSet(const QString& name, KIcon::Group group, int size,
+ bool canReturnNull);
+
+ // KDE4 merge as (const QString&,KIcon::Group,int=0,bool=false,bool=true);
+ /**
+ * Creates an icon set, that will do on-demand loading of the icon.
+ * Loading itself is done by calling loadIcon .
+ *
+ * @param name The name of the icon, without extension.
+ * @param group The icon group. This will specify the size of and effects to
+ * be applied to the icon.
+ * @param size If nonzero, this overrides the size specified by @p group.
+ * See KIcon::StdSizes.
+ * @return the icon set. Can be null when not found
+ */
+ QIconSet loadIconSet(const QString& name, KIcon::Group group, int size=0);
+
+ /**
+ * Returns the path of an icon.
+ * @param name The name of the icon, without extension. If an absolute
+ * path is supplied for this parameter, iconPath will return it
+ * directly.
+ * @param group_or_size If positive, search icons whose size is
+ * specified by the icon group @p group_or_size. If negative, search
+ * icons whose size is - @p group_or_size.
+ * See KIcon::Group and KIcon::StdSizes
+ * @param canReturnNull Can return a null string? If not, a path to the
+ * "unknown" icon will be returned.
+ * @return the path of an icon, can be null or the "unknown" icon when
+ * not found, depending on @p canReturnNull.
+ */
+ QString iconPath(const QString& name, int group_or_size,
+ bool canReturnNull=false) const;
+
+ /**
+ * Loads an animated icon.
+ * @param name The name of the icon.
+ * @param group The icon group. See loadIcon().
+ * @param size Override the default size for @p group.
+ * See KIcon::StdSizes.
+ * @return A QMovie object. Can be null if not found.
+ */
+ QMovie loadMovie(const QString& name, KIcon::Group group, int size=0) const;
+
+ /**
+ * Returns the path to an animated icon.
+ * @param name The name of the icon.
+ * @param group The icon group. See loadIcon().
+ * @param size Override the default size for @p group.
+ * See KIcon::StdSizes.
+ * @return the full path to the movie, ready to be passed to QMovie's constructor.
+ * Empty string if not found.
+ */
+ QString moviePath(const QString& name, KIcon::Group group, int size=0) const;
+
+ /**
+ * Loads an animated icon as a series of still frames. If you want to load
+ * a .mng animation as QMovie instead, please use loadMovie() instead.
+ * @param name The name of the icon.
+ * @param group The icon group. See loadIcon().
+ * @param size Override the default size for @p group.
+ * See KIcon::StdSizes.
+ * @return A QStringList containing the absolute path of all the frames
+ * making up the animation.
+ */
+ QStringList loadAnimated(const QString& name, KIcon::Group group, int size=0) const;
+
+ /**
+ * Queries all available icons for a specific group, having a specific
+ * context.
+ * @param group_or_size If positive, search icons whose size is
+ * specified by the icon group @p group_or_size. If negative, search
+ * icons whose size is - @p group_or_size.
+ * See KIcon::Group and KIcon::StdSizes
+ * @param context The icon context.
+ * @return a list of all icons
+ */
+ QStringList queryIcons(int group_or_size, KIcon::Context context=KIcon::Any) const;
+
+ /**
+ * Queries all available icons for a specific context.
+ * @param group_or_size The icon preferred group or size. If available
+ * at this group or size, those icons will be returned, in other case,
+ * icons of undefined size will be returned. Positive numbers are groups,
+ * negative numbers are negated sizes. See KIcon::Group and
+ * KIcon::StdSizes
+ * @param context The icon context.
+ * @return A QStringList containing the icon names
+ * available for that context
+ */
+ QStringList queryIconsByContext(int group_or_size,
+ KIcon::Context context=KIcon::Any) const;
+
+ /**
+ * @internal
+ */
+ bool hasContext( KIcon::Context context ) const;
+
+ /**
+ * Returns a list of all icons (*.png or *.xpm extension) in the
+ * given directory.
+ * @param iconsDir the directory to search in
+ * @return A QStringList containing the icon paths
+ * @since 3.1
+ */
+ QStringList queryIconsByDir( const QString& iconsDir ) const;
+
+ /**
+ * Returns the current size of the group.
+ * @param group the group to check.
+ * @return the current size for an icon group.
+ */
+ int currentSize(KIcon::Group group) const;
+
+ /**
+ * Returns a pointer to the current theme. Can be used to query
+ * available and default sizes for groups.
+ * @return a pointer to the current theme. 0 if no theme set.
+ */
+ KIconTheme *theme() const;
+
+ /**
+ * Returns a pointer to the KIconEffect object used by the icon loader.
+ * @return the KIconEffect.
+ */
+ KIconEffect *iconEffect() const;
+
+ /**
+ * Called by KInstance::newIconLoader to reconfigure the icon loader.
+ * @param _appname the new application name
+ * @param _dirs the new standard directories. If 0, the directories
+ * from KGlobal will be taken.
+ */
+ void reconfigure( const QString& _appname, KStandardDirs *_dirs );
+
+ /**
+ * Returns the unknown icon. An icon that is used when no other icon
+ * can be found.
+ * @return the unknown pixmap
+ */
+ static QPixmap unknown();
+
+ /**
+ * Checks whether the user wants to blend the icons with the background
+ * using the alpha channel information for a given group.
+ * @param group the group to check
+ * @return true if alpha blending is desired
+ * @obsolete
+ */
+ bool alphaBlending( KIcon::Group group ) const;
+
+ /**
+ * Adds all the default themes from other desktops at the end of
+ * the list of icon themes.
+ * @since 3.1
+ */
+ void addExtraDesktopThemes();
+
+ /**
+ * Returns if the default icon themes of other desktops have been added
+ * to the list of icon themes where icons are searched.
+ * @since 3.1
+ */
+ bool extraDesktopThemesAdded() const;
+
+ /**
+ * Enables on-demand icon loading for QIconSets using QIconFactory.
+ * Icons loaded via loadIconSet() will be loaded as soon as they
+ * need to be displayed, not earlier.
+ *
+ * Note that enabling or disabling this only affects loadIconSet()
+ * calls after this setting is changed.
+ *
+ * The default is disabled, as the iconloader object must not be
+ * destroyed before all those iconsets are destroyed.
+ *
+ * (Some broken applications use temporary KIconLoader objects).
+ * Every KInstance 's iconloader has this feature enabled.
+ *
+ * @param enable true to enable delayed icon loading, false to disable
+ * @see isDelayedIconSetLoadingEnabled()
+ * @see QIconFactory
+ * @since 3.1
+ */
+ void enableDelayedIconSetLoading( bool enable );
+
+ /**
+ * Checks whether delayed loading for QIconSet is enabled.
+ * @return whether icons for QIconSets will be loaded on demand.
+ * @see enableDelayedIconSetLoading()
+ * @see QIconFactory
+ * @since 3.1
+ */
+ bool isDelayedIconSetLoadingEnabled() const;
+
+
+ private:
+ /**
+ * @internal
+ */
+ void init( const QString& _appname, KStandardDirs *_dirs );
+
+ /**
+ * @internal
+ * tries to find an icon with the name. It tries some extension and
+ * match strategies
+ */
+ KIcon findMatchingIcon(const QString& name, int size) const;
+
+ /**
+ * @internal
+ * Loads and caches an overlay.
+ */
+ QImage *loadOverlay(const QString& name, int size) const;
+
+ /**
+ * @internal
+ * Adds themes installed in the application's directory.
+ **/
+ void addAppThemes(const QString& appname);
+
+ /**
+ * Adds all themes that are part of this node and the themes
+ * below (the fallbacks of the theme) in the tree.
+ * @internal
+ */
+ void addBaseThemes(KIconThemeNode *node, const QString &appname);
+
+ /**
+ * @internal
+ * return the path for the unknown icon in that size
+ * @since 3.1
+ */
+ QString unknownIconPath( int size ) const;
+
+ /**
+ * Checks if name ends in one of the supported icon formats (i.e. .png)
+ * and returns the name without the extension if it does.
+ *
+ * Otherwise name is returned unchanged.
+ *
+ * Currently supported:
+ * - png
+ * - xpm
+ * - svg (if libart is being used)
+ * - svgz (if libart is being used)
+ *
+ * TODO: KDE 4 make public & static
+ * @since 3.1
+ */
+ QString removeIconExtension(const QString &name) const;
+
+ /**
+ * Same as removeIconExtension except it prints a debug message
+ * if an extension is removed to help catch programming errors.
+ *
+ * @see findMatchingIcon()
+ * @see iconPath()
+ *
+ * TODO: KDE 4 make static
+ */
+ QString removeIconExtensionInternal(const QString &name) const;
+
+ /**
+ * Loads all the different sizes for an iconset.
+ */
+ QIconSet loadIconSetNonDelayed( const QString& name, KIcon::Group group,
+ int size, bool canReturnNull );
+
+ // @internal the data object
+ KIconLoaderPrivate *d;
+};
+
+/**
+ * \relates KIconLoader
+ * Load a desktop icon.
+ */
+KDECORE_EXPORT QPixmap DesktopIcon(const QString& name, int size=0,
+ int state=KIcon::DefaultState,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a desktop icon.
+ */
+KDECORE_EXPORT QPixmap DesktopIcon(const QString& name, KInstance *instance);
+
+/**
+ * \relates KIconLoader
+ * Load a desktop icon, and apply the necessary effects to get an IconSet.
+ */
+KDECORE_EXPORT QIconSet DesktopIconSet(const QString& name, int size=0,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a toolbar icon.
+ */
+KDECORE_EXPORT QPixmap BarIcon(const QString& name, int size=0, int state=KIcon::DefaultState,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a toolbar icon.
+ */
+KDECORE_EXPORT QPixmap BarIcon(const QString& name, KInstance *instance);
+
+/**
+ * \relates KIconLoader
+ * Load a toolbar icon, and apply the necessary effects to get an IconSet.
+ */
+KDECORE_EXPORT QIconSet BarIconSet(const QString& name, int size=0,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a small icon.
+ */
+KDECORE_EXPORT QPixmap SmallIcon(const QString& name, int size=0,
+ int state=KIcon::DefaultState,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a small icon.
+ */
+KDECORE_EXPORT QPixmap SmallIcon(const QString& name, KInstance *instance);
+
+/**
+ * \relates KIconLoader
+ * Load a small icon, and apply the necessary effects to get an IconSet.
+ */
+KDECORE_EXPORT QIconSet SmallIconSet(const QString& name, int size=0,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a main toolbar icon.
+ */
+KDECORE_EXPORT QPixmap MainBarIcon(const QString& name, int size=0,
+ int state=KIcon::DefaultState,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a main toolbar icon.
+ */
+KDECORE_EXPORT QPixmap MainBarIcon(const QString& name, KInstance *instance);
+
+/**
+ * \relates KIconLoader
+ * Load a main toolbar icon, and apply the effects to get an IconSet.
+ */
+KDECORE_EXPORT QIconSet MainBarIconSet(const QString& name, int size=0,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a user icon. User icons are searched in $appdir/pics.
+ */
+KDECORE_EXPORT QPixmap UserIcon(const QString& name, int state=KIcon::DefaultState,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Load a user icon. User icons are searched in $appdir/pics.
+ */
+KDECORE_EXPORT QPixmap UserIcon(const QString& name, KInstance *instance);
+
+/**
+ * \relates KIconLoader
+ * Load a user icon, and apply the effects to get an IconSet.
+ */
+KDECORE_EXPORT QIconSet UserIconSet(const QString& name,
+ KInstance *instance=KGlobal::instance());
+
+/**
+ * \relates KIconLoader
+ * Returns the current icon size for a specific group.
+ */
+KDECORE_EXPORT int IconSize(KIcon::Group group, KInstance *instance=KGlobal::instance());
+
+#endif // __KIconLoader_h_Included__
diff --git a/kdecore/kiconloader_p.h b/kdecore/kiconloader_p.h
new file mode 100644
index 000000000..a3201137b
--- /dev/null
+++ b/kdecore/kiconloader_p.h
@@ -0,0 +1,60 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdecore.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * Antonio Larrosa <larrosa@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#ifndef __KIconLoader_p_h_Included__
+#define __KIconLoader_p_h_Included__
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <kicontheme.h>
+#include <kiconloader.h>
+#include <kiconeffect.h>
+#include <qdict.h>
+
+class KIconThemeNode
+{
+public:
+ KIconThemeNode(KIconTheme *_theme);
+ ~KIconThemeNode();
+
+ void queryIcons(QStringList *lst, int size, KIcon::Context context) const;
+ void queryIconsByContext(QStringList *lst, int size, KIcon::Context context) const;
+ KIcon findIcon(const QString& name, int size, KIcon::MatchType match) const;
+ void printTree(QString& dbgString) const;
+
+ KIconTheme *theme;
+};
+
+class KIconLoaderPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QStringList mThemesInTree;
+ KIconGroup *mpGroups;
+ KIconThemeNode *mpThemeRoot;
+ KStandardDirs *mpDirs;
+ KIconLoader *q;
+ KIconEffect mpEffect;
+ QDict<QImage> imgDict;
+ QImage lastImage; // last loaded image without effect applied
+ QString lastImageKey; // key for icon without effect
+ QString appname;
+ int lastIconType; // see KIcon::type
+ int lastIconThreshold; // see KIcon::threshold
+ QPtrList<KIconThemeNode> links;
+ bool extraDesktopIconsLoaded;
+ bool delayedLoading;
+
+public slots:
+ void reconfigure();
+};
+
+#endif // __KIconLoader_p_h_Included__
diff --git a/kdecore/kicontheme.cpp b/kdecore/kicontheme.cpp
new file mode 100644
index 000000000..f695052fe
--- /dev/null
+++ b/kdecore/kicontheme.cpp
@@ -0,0 +1,605 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * $Id$
+ *
+ * This file is part of the KDE project, module kdecore.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * Antonio Larrosa <larrosa@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ *
+ * kicontheme.cpp: Lowlevel icon theme handling.
+ */
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <config.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+#include <qpixmap.h>
+#include <qpixmapcache.h>
+#include <qimage.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <kinstance.h>
+
+#include "kicontheme.h"
+
+class KIconThemePrivate
+{
+public:
+ QString example, screenshot;
+ QString linkOverlay, lockOverlay, zipOverlay, shareOverlay;
+ bool hidden;
+ KSharedConfig::Ptr sharedConfig;
+};
+
+/**
+ * A subdirectory in an icon theme.
+ */
+class KIconThemeDir
+{
+public:
+ KIconThemeDir(const QString& dir, const KConfigBase *config);
+
+ bool isValid() const { return mbValid; }
+ QString iconPath(const QString& name) const;
+ QStringList iconList() const;
+ QString dir() const { return mDir; }
+
+ KIcon::Context context() const { return mContext; }
+ KIcon::Type type() const { return mType; }
+ int size() const { return mSize; }
+ int minSize() const { return mMinSize; }
+ int maxSize() const { return mMaxSize; }
+ int threshold() const { return mThreshold; }
+
+private:
+ bool mbValid;
+ KIcon::Type mType;
+ KIcon::Context mContext;
+ int mSize, mMinSize, mMaxSize;
+ int mThreshold;
+
+ QString mDir;
+};
+
+
+/*** KIconTheme ***/
+
+KIconTheme::KIconTheme(const QString& name, const QString& appName)
+{
+ d = new KIconThemePrivate;
+
+ QStringList icnlibs;
+ QStringList::ConstIterator it, itDir;
+ QStringList themeDirs;
+ QString cDir;
+
+ // Applications can have local additions to the global "locolor" and
+ // "hicolor" icon themes. For these, the _global_ theme description
+ // files are used..
+
+ if (!appName.isEmpty() &&
+ ( name == "crystalsvg" || name== "hicolor" || name == "locolor" ) )
+ {
+ icnlibs = KGlobal::dirs()->resourceDirs("data");
+ for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
+ {
+ cDir = *it + appName + "/icons/" + name;
+ if (QFile::exists( cDir ))
+ themeDirs += cDir + "/";
+ }
+ }
+ // Find the theme description file. These are always global.
+
+ icnlibs = KGlobal::dirs()->resourceDirs("icon");
+ icnlibs += KGlobal::dirs()->resourceDirs("xdgdata-icon");
+ icnlibs += "/usr/share/pixmaps";
+ // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
+ icnlibs += KGlobal::dirs()->resourceDirs("xdgdata-pixmap");
+ for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
+ {
+ cDir = *it + name + "/";
+ if (KStandardDirs::exists(cDir))
+ {
+ themeDirs += cDir;
+ if (mDir.isEmpty()
+ && (KStandardDirs::exists( cDir + "index.desktop") || KStandardDirs::exists( cDir + "index.theme")))
+ mDir = cDir;
+ }
+ }
+
+ if (mDir.isEmpty())
+ {
+ kdDebug(264) << "Icon theme " << name << " not found.\n";
+ return;
+ }
+
+ QString fileName, mainSection;
+ if(QFile::exists(mDir + "index.desktop")) {
+ fileName = mDir + "index.desktop";
+ mainSection="KDE Icon Theme";
+ } else {
+ fileName = mDir + "index.theme";
+ mainSection="Icon Theme";
+ }
+ // Use KSharedConfig to avoid parsing the file many times, from each kinstance.
+ // Need to keep a ref to it to make this useful
+ d->sharedConfig = KSharedConfig::openConfig( fileName, true /*readonly*/, false /*useKDEGlobals*/ );
+ KConfig& cfg = *d->sharedConfig;
+ //was: KSimpleConfig cfg(fileName);
+
+ cfg.setGroup(mainSection);
+ mName = cfg.readEntry("Name");
+ mDesc = cfg.readEntry("Comment");
+ mDepth = cfg.readNumEntry("DisplayDepth", 32);
+ mInherits = cfg.readListEntry("Inherits");
+ if ( name != "crystalsvg" )
+ for ( QStringList::Iterator it = mInherits.begin(); it != mInherits.end(); ++it )
+ if ( *it == "default" || *it == "hicolor" ) *it="crystalsvg";
+
+ d->hidden = cfg.readBoolEntry("Hidden", false);
+ d->example = cfg.readPathEntry("Example");
+ d->screenshot = cfg.readPathEntry("ScreenShot");
+ d->linkOverlay = cfg.readEntry("LinkOverlay", "link");
+ d->lockOverlay = cfg.readEntry("LockOverlay", "lock");
+ d->zipOverlay = cfg.readEntry("ZipOverlay", "zip");
+ d->shareOverlay = cfg.readEntry("ShareOverlay","share");
+
+ QStringList dirs = cfg.readPathListEntry("Directories");
+ mDirs.setAutoDelete(true);
+ for (it=dirs.begin(); it!=dirs.end(); ++it)
+ {
+ cfg.setGroup(*it);
+ for (itDir=themeDirs.begin(); itDir!=themeDirs.end(); ++itDir)
+ {
+ if (KStandardDirs::exists(*itDir + *it + "/"))
+ {
+ KIconThemeDir *dir = new KIconThemeDir(*itDir + *it, &cfg);
+ if (!dir->isValid())
+ {
+ kdDebug(264) << "Icon directory " << *itDir << " group " << *it << " not valid.\n";
+ delete dir;
+ }
+ else
+ mDirs.append(dir);
+ }
+ }
+ }
+
+ // Expand available sizes for scalable icons to their full range
+ int i;
+ QMap<int,QValueList<int> > scIcons;
+ for (KIconThemeDir *dir=mDirs.first(); dir!=0L; dir=mDirs.next())
+ {
+ if ((dir->type() == KIcon::Scalable) && !scIcons.contains(dir->size()))
+ {
+ QValueList<int> lst;
+ for (i=dir->minSize(); i<=dir->maxSize(); i++)
+ lst += i;
+ scIcons[dir->size()] = lst;
+ }
+ }
+
+ QStringList groups;
+ groups += "Desktop";
+ groups += "Toolbar";
+ groups += "MainToolbar";
+ groups += "Small";
+ groups += "Panel";
+ const int defDefSizes[] = { 32, 22, 22, 16, 32 };
+ cfg.setGroup(mainSection);
+ for (it=groups.begin(), i=0; it!=groups.end(); ++it, i++)
+ {
+ mDefSize[i] = cfg.readNumEntry(*it + "Default", defDefSizes[i]);
+ QValueList<int> exp, lst = cfg.readIntListEntry(*it + "Sizes");
+ QValueList<int>::ConstIterator it2;
+ for (it2=lst.begin(); it2!=lst.end(); ++it2)
+ {
+ if (scIcons.contains(*it2))
+ exp += scIcons[*it2];
+ else
+ exp += *it2;
+ }
+ mSizes[i] = exp;
+ }
+
+}
+
+KIconTheme::~KIconTheme()
+{
+ delete d;
+}
+
+bool KIconTheme::isValid() const
+{
+ return !mDirs.isEmpty();
+}
+
+bool KIconTheme::isHidden() const
+{
+ return d->hidden;
+}
+
+QString KIconTheme::example() const { return d->example; }
+QString KIconTheme::screenshot() const { return d->screenshot; }
+QString KIconTheme::linkOverlay() const { return d->linkOverlay; }
+QString KIconTheme::lockOverlay() const { return d->lockOverlay; }
+QString KIconTheme::zipOverlay() const { return d->zipOverlay; }
+QString KIconTheme::shareOverlay() const { return d->shareOverlay; }
+
+int KIconTheme::defaultSize(KIcon::Group group) const
+{
+ if ((group < 0) || (group >= KIcon::LastGroup))
+ {
+ kdDebug(264) << "Illegal icon group: " << group << "\n";
+ return -1;
+ }
+ return mDefSize[group];
+}
+
+QValueList<int> KIconTheme::querySizes(KIcon::Group group) const
+{
+ QValueList<int> empty;
+ if ((group < 0) || (group >= KIcon::LastGroup))
+ {
+ kdDebug(264) << "Illegal icon group: " << group << "\n";
+ return empty;
+ }
+ return mSizes[group];
+}
+
+QStringList KIconTheme::queryIcons(int size, KIcon::Context context) const
+{
+ int delta = 1000, dw;
+
+ QPtrListIterator<KIconThemeDir> dirs(mDirs);
+ KIconThemeDir *dir;
+
+ // Try to find exact match
+ QStringList result;
+ for ( ; dirs.current(); ++dirs)
+ {
+ dir = dirs.current();
+ if ((context != KIcon::Any) && (context != dir->context()))
+ continue;
+ if ((dir->type() == KIcon::Fixed) && (dir->size() == size))
+ {
+ result += dir->iconList();
+ continue;
+ }
+ if ((dir->type() == KIcon::Scalable) &&
+ (size >= dir->minSize()) && (size <= dir->maxSize()))
+ {
+ result += dir->iconList();
+ continue;
+ }
+ if ((dir->type() == KIcon::Threshold) &&
+ (abs(size-dir->size())<dir->threshold()))
+ result+=dir->iconList();
+ }
+
+ return result;
+
+ dirs.toFirst();
+
+ // Find close match
+ KIconThemeDir *best = 0L;
+ for ( ; dirs.current(); ++dirs)
+ {
+ dir = dirs.current();
+ if ((context != KIcon::Any) && (context != dir->context()))
+ continue;
+ dw = dir->size() - size;
+ if ((dw > 6) || (abs(dw) >= abs(delta)))
+ continue;
+ delta = dw;
+ best = dir;
+ }
+ if (best == 0L)
+ return QStringList();
+
+ return best->iconList();
+}
+
+QStringList KIconTheme::queryIconsByContext(int size, KIcon::Context context) const
+{
+ QPtrListIterator<KIconThemeDir> dirs(mDirs);
+ int dw;
+ KIconThemeDir *dir;
+
+ // We want all the icons for a given context, but we prefer icons
+ // of size size . Note that this may (will) include duplicate icons
+ //QStringList iconlist[34]; // 33 == 48-16+1
+ QStringList iconlist[128]; // 33 == 48-16+1
+ // Usually, only the 0, 6 (22-16), 10 (32-22), 16 (48-32 or 32-16),
+ // 26 (48-22) and 32 (48-16) will be used, but who knows if someone
+ // will make icon themes with different icon sizes.
+
+ for ( ; dirs.current(); ++dirs)
+ {
+ dir = dirs.current();
+ if ((context != KIcon::Any) && (context != dir->context()))
+ continue;
+ dw = abs(dir->size() - size);
+ iconlist[(dw<127)?dw:127]+=dir->iconList();
+ }
+
+ QStringList iconlistResult;
+ for (int i=0; i<128; i++) iconlistResult+=iconlist[i];
+
+ return iconlistResult;
+}
+
+bool KIconTheme::hasContext(KIcon::Context context) const
+{
+ QPtrListIterator<KIconThemeDir> dirs(mDirs);
+ KIconThemeDir *dir;
+
+ for ( ; dirs.current(); ++dirs)
+ {
+ dir = dirs.current();
+ if ((context == KIcon::Any) || (context == dir->context()))
+ return true;
+ }
+ return false;
+}
+
+KIcon KIconTheme::iconPath(const QString& name, int size, KIcon::MatchType match) const
+{
+ KIcon icon;
+ QString path;
+ int delta = -1000, dw;
+ KIconThemeDir *dir;
+
+ dw = 1000; // shut up, gcc
+ QPtrListIterator<KIconThemeDir> dirs(mDirs);
+ for ( ; dirs.current(); ++dirs)
+ {
+ dir = dirs.current();
+
+ if (match == KIcon::MatchExact)
+ {
+ if ((dir->type() == KIcon::Fixed) && (dir->size() != size))
+ continue;
+ if ((dir->type() == KIcon::Scalable) &&
+ ((size < dir->minSize()) || (size > dir->maxSize())))
+ continue;
+ if ((dir->type() == KIcon::Threshold) &&
+ (abs(dir->size()-size) > dir->threshold()))
+ continue;
+ } else
+ {
+ // dw < 0 means need to scale up to get an icon of the requested size
+ if (dir->type() == KIcon::Fixed)
+ {
+ dw = dir->size() - size;
+ } else if (dir->type() == KIcon::Scalable)
+ {
+ if (size < dir->minSize())
+ dw = dir->minSize() - size;
+ else if (size > dir->maxSize())
+ dw = dir->maxSize() - size;
+ else
+ dw = 0;
+ } else if (dir->type() == KIcon::Threshold)
+ {
+ if (size < dir->size() - dir->threshold())
+ dw = dir->size() - dir->threshold() - size;
+ else if (size > dir->size() + dir->threshold())
+ dw = dir->size() + dir->threshold() - size;
+ else
+ dw = 0;
+ }
+ /* Skip this if we've found a closer one, unless
+ it's a downscale, and we only had upscales befores.
+ This is to avoid scaling up unless we have to,
+ since that looks very ugly */
+ if ((abs(dw) >= abs(delta)) ||
+ (delta > 0 && dw < 0))
+ continue;
+ }
+
+ path = dir->iconPath(name);
+ if (path.isEmpty())
+ continue;
+ icon.path = path;
+ icon.size = dir->size();
+ icon.type = dir->type();
+ icon.threshold = dir->threshold();
+ icon.context = dir->context();
+
+ // if we got in MatchExact that far, we find no better
+ if (match == KIcon::MatchExact)
+ return icon;
+ else
+ {
+ delta = dw;
+ if (delta==0) return icon; // We won't find a better match anyway
+ }
+ }
+ return icon;
+}
+
+// static
+QString *KIconTheme::_theme = 0L;
+
+// static
+QStringList *KIconTheme::_theme_list = 0L;
+
+// static
+QString KIconTheme::current()
+{
+ // Static pointer because of unloading problems wrt DSO's.
+ if (_theme != 0L)
+ return *_theme;
+
+ _theme = new QString();
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver saver(config, "Icons");
+ *_theme = config->readEntry("Theme",defaultThemeName());
+ if ( *_theme == QString::fromLatin1("hicolor") ) *_theme = defaultThemeName();
+/* if (_theme->isEmpty())
+ {
+ if (QPixmap::defaultDepth() > 8)
+ *_theme = defaultThemeName();
+ else
+ *_theme = QString::fromLatin1("locolor");
+ }*/
+ return *_theme;
+}
+
+// static
+QStringList KIconTheme::list()
+{
+ // Static pointer because of unloading problems wrt DSO's.
+ if (_theme_list != 0L)
+ return *_theme_list;
+
+ _theme_list = new QStringList();
+ QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
+ icnlibs += (KGlobal::dirs()->resourceDirs("xdgdata-icon"));
+ icnlibs += "/usr/share/pixmaps";
+ // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
+ icnlibs += KGlobal::dirs()->resourceDirs("xdgdata-pixmap");
+ QStringList::ConstIterator it;
+ for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
+ {
+ QDir dir(*it);
+ if (!dir.exists())
+ continue;
+ QStringList lst = dir.entryList(QDir::Dirs);
+ QStringList::ConstIterator it2;
+ for (it2=lst.begin(); it2!=lst.end(); ++it2)
+ {
+ if ((*it2 == ".") || (*it2 == "..") || (*it2).startsWith("default.") )
+ continue;
+ if (!KStandardDirs::exists(*it + *it2 + "/index.desktop") && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
+ continue;
+ KIconTheme oink(*it2);
+ if (!oink.isValid()) continue;
+
+ if (!_theme_list->contains(*it2))
+ _theme_list->append(*it2);
+ }
+ }
+ return *_theme_list;
+}
+
+// static
+void KIconTheme::reconfigure()
+{
+ delete _theme;
+ _theme=0L;
+ delete _theme_list;
+ _theme_list=0L;
+}
+
+// static
+QString KIconTheme::defaultThemeName()
+{
+ return QString::fromLatin1("crystalsvg");
+}
+
+/*** KIconThemeDir ***/
+
+KIconThemeDir::KIconThemeDir(const QString& dir, const KConfigBase *config)
+{
+ mbValid = false;
+ mDir = dir;
+ mSize = config->readNumEntry("Size");
+ mMinSize = 1; // just set the variables to something
+ mMaxSize = 50; // meaningful in case someone calls minSize or maxSize
+ mType = KIcon::Fixed;
+
+ if (mSize == 0)
+ return;
+
+ QString tmp = config->readEntry("Context");
+ if (tmp == "Devices")
+ mContext = KIcon::Device;
+ else if (tmp == "MimeTypes")
+ mContext = KIcon::MimeType;
+ else if (tmp == "FileSystems")
+ mContext = KIcon::FileSystem;
+ else if (tmp == "Applications")
+ mContext = KIcon::Application;
+ else if (tmp == "Actions")
+ mContext = KIcon::Action;
+ else if (tmp == "Animations")
+ mContext = KIcon::Animation;
+ else if (tmp == "Categories")
+ mContext = KIcon::Category;
+ else if (tmp == "Emblems")
+ mContext = KIcon::Emblem;
+ else if (tmp == "Emotes")
+ mContext = KIcon::Emote;
+ else if (tmp == "International")
+ mContext = KIcon::International;
+ else if (tmp == "Places")
+ mContext = KIcon::Place;
+ else if (tmp == "Status")
+ mContext = KIcon::StatusIcon;
+ else {
+ kdDebug(264) << "Invalid Context= line for icon theme: " << mDir << "\n";
+ return;
+ }
+ tmp = config->readEntry("Type");
+ if (tmp == "Fixed")
+ mType = KIcon::Fixed;
+ else if (tmp == "Scalable")
+ mType = KIcon::Scalable;
+ else if (tmp == "Threshold")
+ mType = KIcon::Threshold;
+ else {
+ kdDebug(264) << "Invalid Type= line for icon theme: " << mDir << "\n";
+ return;
+ }
+ if (mType == KIcon::Scalable)
+ {
+ mMinSize = config->readNumEntry("MinSize", mSize);
+ mMaxSize = config->readNumEntry("MaxSize", mSize);
+ } else if (mType == KIcon::Threshold)
+ mThreshold = config->readNumEntry("Threshold", 2);
+ mbValid = true;
+}
+
+QString KIconThemeDir::iconPath(const QString& name) const
+{
+ if (!mbValid)
+ return QString::null;
+ QString file = mDir + "/" + name;
+
+ if (access(QFile::encodeName(file), R_OK) == 0)
+ return file;
+
+ return QString::null;
+}
+
+QStringList KIconThemeDir::iconList() const
+{
+ QDir dir(mDir);
+#ifdef HAVE_LIBART
+ QStringList lst = dir.entryList("*.png;*.svg;*.svgz;*.xpm", QDir::Files);
+#else
+ QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
+#endif
+ QStringList result;
+ QStringList::ConstIterator it;
+ for (it=lst.begin(); it!=lst.end(); ++it)
+ result += mDir + "/" + *it;
+ return result;
+}
diff --git a/kdecore/kicontheme.h b/kdecore/kicontheme.h
new file mode 100644
index 000000000..424586df7
--- /dev/null
+++ b/kdecore/kicontheme.h
@@ -0,0 +1,368 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdecore.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * Antonio Larrosa <larrosa@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ *
+ */
+
+#ifndef __KIconTheme_h_Included__
+#define __KIconTheme_h_Included__
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include "kdelibs_export.h"
+
+class KConfig;
+class KIconThemeDir;
+
+class KIconThemePrivate;
+
+class KIconPrivate;
+
+/**
+ * One icon as found by KIconTheme. Also serves as a namespace containing
+ * icon related constants.
+ * @see KIconEffect
+ * @see KIconTheme
+ * @see KIconLoader
+ */
+class KDECORE_EXPORT KIcon
+{
+public:
+ KIcon() { size = 0; }
+
+ /**
+ * Return true if this icon is valid, false otherwise.
+ */
+ bool isValid() const { return size != 0; }
+
+ /**
+ * Defines the context of the icon.
+ */
+ enum Context {
+ Any, ///< Some icon with unknown purpose.
+ Action, ///< An action icon (e.g. 'save', 'print').
+ Application, ///< An icon that represents an application.
+ Device, ///< An icon that represents a device.
+ FileSystem, ///< An icon that represents a file system.
+ MimeType, ///< An icon that represents a mime type (or file type).
+ Animation, ///< An icon that is animated.
+ Category, ///< An icon that represents a category.
+ Emblem, ///< An icon that adds information to an existing icon.
+ Emote, ///< An icon that expresses an emotion.
+ International, ///< An icon that represents a country's flag.
+ Place, ///< An icon that represents a location (e.g. 'home', 'trash').
+ StatusIcon ///< An icon that represents an event.
+ };
+
+ /**
+ * The type of the icon.
+ */
+ enum Type {
+ Fixed, ///< Fixed-size icon.
+ Scalable, ///< Scalable-size icon.
+ Threshold ///< A threshold icon.
+ };
+
+ /**
+ * The type of a match.
+ */
+ enum MatchType {
+ MatchExact, ///< Only try to find an exact match.
+ MatchBest ///< Take the best match if there is no exact match.
+
+ };
+
+ // if you add a group here, make sure to change the config reading in
+ // KIconLoader too
+ /**
+ * The group of the icon.
+ */
+ enum Group {
+ /// No group
+ NoGroup=-1,
+ /// Desktop icons
+ Desktop=0,
+ /// First group
+ FirstGroup=0,
+ /// Toolbar icons
+ Toolbar,
+ /// Main toolbar icons
+ MainToolbar,
+ /// Small icons
+ Small,
+ /// Panel (Kicker) icons
+ Panel,
+ /// Last group
+ LastGroup,
+ /// User icons
+ User
+ };
+
+ /**
+ * These are the standard sizes for icons.
+ */
+ enum StdSizes {
+ /// small icons for menu entries
+ SizeSmall=16,
+ /// slightly larger small icons for toolbars, panels, etc
+ SizeSmallMedium=22,
+ /// medium sized icons for the desktop
+ SizeMedium=32,
+ /// large sized icons for the panel
+ SizeLarge=48,
+ /// huge sized icons for iconviews
+ SizeHuge=64,
+ /// enormous sized icons for iconviews
+ SizeEnormous=128
+ };
+
+ /**
+ * Defines the possible states of an icon.
+ */
+ enum States { DefaultState, ///< The default state.
+ ActiveState, ///< Icon is active.
+ DisabledState, ///< Icon is disabled.
+ LastState ///< Last state (last constant)
+ };
+
+ /**
+ * This defines an overlay, a semi-transparent image that is
+ * projected onto the icon. They are used to show that the file
+ * represented by the icon is, for example, locked, zipped or hidden.
+ */
+ enum Overlays {
+ LockOverlay=0x100, ///< a file is locked
+ ZipOverlay=0x200, ///< a file is zipped
+ LinkOverlay=0x400, ///< a file is a link
+ HiddenOverlay=0x800, ///< a file is hidden
+ ShareOverlay=0x1000, ///< a file is shared
+ OverlayMask = ~0xff
+ };
+
+ /**
+ * The size in pixels of the icon.
+ */
+ int size;
+
+ /**
+ * The context of the icon.
+ */
+ Context context;
+
+ /**
+ * The type of the icon: Fixed, Scalable or Threshold.
+ **/
+ Type type;
+
+ /**
+ * The threshold in case type == Threshold
+ */
+ int threshold;
+
+ /**
+ * The full path of the icon.
+ */
+ QString path;
+
+private:
+ KIconPrivate *d;
+};
+
+inline KIcon::Group& operator++(KIcon::Group& group) { group = static_cast<KIcon::Group>(group+1); return group; }
+inline KIcon::Group operator++(KIcon::Group& group,int) { KIcon::Group ret = group; ++group; return ret; }
+
+/**
+ * Class to use/access icon themes in KDE. This class is used by the
+ * iconloader but can be used by others too.
+ * @see KIconLoader
+ */
+class KDECORE_EXPORT KIconTheme
+{
+public:
+ /**
+ * Load an icon theme by name.
+ * @param name the name of the theme (e.g. "hicolor" or "keramik")
+ * @param appName the name of the application. Can be null. This argument
+ * allows applications to have themed application icons.
+ */
+ KIconTheme(const QString& name, const QString& appName=QString::null);
+ ~KIconTheme();
+
+ /**
+ * The stylized name of the icon theme.
+ * @return the (human-readable) name of the theme
+ */
+ QString name() const { return mName; }
+
+ /**
+ * A description for the icon theme.
+ * @return a human-readable description of the theme, QString::null
+ * if there is none
+ */
+ QString description() const { return mDesc; }
+
+ /**
+ * Return the name of the "example" icon. This can be used to
+ * present the theme to the user.
+ * @return the name of the example icon, QString::null if there is none
+ */
+ QString example() const;
+
+ /**
+ * Return the name of the screenshot.
+ * @return the name of the screenshot, QString::null if there is none
+ */
+ QString screenshot() const;
+
+ /**
+ * Returns the name of this theme's link overlay.
+ * @return the name of the link overlay
+ */
+ QString linkOverlay() const;
+
+ /**
+ * Returns the name of this theme's zip overlay.
+ * @return the name of the zip overlay
+ */
+ QString zipOverlay() const;
+
+ /**
+ * Returns the name of this theme's lock overlay.
+ * @return the name of the lock overlay
+ */
+ QString lockOverlay() const;
+
+ /**
+ * Returns the name of this theme's share overlay.
+ * @return the name of the share overlay
+ * @since 3.1
+ */
+ QString shareOverlay () const;
+
+ /**
+ * Returns the toplevel theme directory.
+ * @return the directory of the theme
+ */
+ QString dir() const { return mDir; }
+
+ /**
+ * The themes this icon theme falls back on.
+ * @return a list of icon themes that are used as fall-backs
+ */
+ QStringList inherits() const { return mInherits; }
+
+ /**
+ * The icon theme exists?
+ * @return true if the icon theme is valid
+ */
+ bool isValid() const;
+
+ /**
+ * The icon theme should be hidden to the user?
+ * @return true if the icon theme is hidden
+ * @since 3.1
+ */
+ bool isHidden() const;
+
+ /**
+ * The minimum display depth required for this theme. This can either
+ * be 8 or 32.
+ * @return the minimum bpp (8 or 32)
+ */
+ int depth() const { return mDepth; }
+
+ /**
+ * The default size of this theme for a certain icon group.
+ * @param group The icon group. See KIcon::Group.
+ * @return The default size in pixels for the given icon group.
+ */
+ int defaultSize(KIcon::Group group) const;
+
+ /**
+ * Query available sizes for a group.
+ * @param group The icon group. See KIcon::Group.
+ * @return a list of available sized for the given group
+ */
+ QValueList<int> querySizes(KIcon::Group group) const;
+
+ /**
+ * Query available icons for a size and context.
+ * @param size the size of the icons
+ * @param context the context of the icons
+ * @return the list of icon names
+ */
+ QStringList queryIcons(int size, KIcon::Context context = KIcon::Any) const;
+
+ /**
+ * Query available icons for a context and preferred size.
+ * @param size the size of the icons
+ * @param context the context of the icons
+ * @return the list of icon names
+ */
+ QStringList queryIconsByContext(int size, KIcon::Context context = KIcon::Any) const;
+
+
+ /**
+ * Lookup an icon in the theme.
+ * @param name The name of the icon, without extension.
+ * @param size The desired size of the icon.
+ * @param match The matching mode. KIcon::MatchExact returns an icon
+ * only if matches exactly. KIcon::MatchBest returns the best matching
+ * icon.
+ * @return A KIcon class that describes the icon. If an icon is found,
+ * @see KIcon::isValid will return true, and false otherwise.
+ */
+ KIcon iconPath(const QString& name, int size, KIcon::MatchType match) const;
+
+ /**
+ * Returns true if the theme has any icons for the given context.
+ * @since 3.5.5
+ */
+ bool hasContext( KIcon::Context context ) const;
+
+ /**
+ * List all icon themes installed on the system, global and local.
+ * @return the list of all icon themes
+ */
+ static QStringList list();
+
+ /**
+ * Returns the current icon theme.
+ * @return the name of the current theme
+ */
+ static QString current();
+
+ /**
+ * Reconfigure the theme.
+ */
+ static void reconfigure();
+
+ /**
+ * Returns the default icon theme.
+ * @return the name of the default theme name
+ * @since 3.1
+ */
+ static QString defaultThemeName();
+
+private:
+ int mDefSize[8];
+ QValueList<int> mSizes[8];
+
+ int mDepth;
+ QString mDir, mName, mDesc;
+ QStringList mInherits;
+ QPtrList<KIconThemeDir> mDirs;
+ KIconThemePrivate *d;
+
+ static QString *_theme;
+ static QStringList *_theme_list;
+};
+
+#endif
diff --git a/kdecore/kidna.cpp b/kdecore/kidna.cpp
new file mode 100644
index 000000000..f3289b26c
--- /dev/null
+++ b/kdecore/kidna.cpp
@@ -0,0 +1,63 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kidna.h"
+
+#ifndef Q_WS_WIN //TODO kresolver not ported
+#include "kresolver.h"
+#endif
+#include <kdebug.h>
+
+#ifndef Q_WS_WIN //TODO knetwork not ported
+using namespace KNetwork;
+#endif
+
+QCString KIDNA::toAsciiCString(const QString &idna)
+{
+#ifndef Q_WS_WIN //TODO kresolver not ported
+ return KResolver::domainToAscii(idna);
+#else
+ return QCString();
+#endif
+}
+
+QString KIDNA::toAscii(const QString &idna)
+{
+ if (idna.length() && (idna[0] == "."))
+ {
+ QString host = QString::fromLatin1(toAsciiCString(idna.mid(1)));
+ if (host.isEmpty())
+ return QString::null; // Error
+ return idna[0] + host;
+ }
+ return QString::fromLatin1(toAsciiCString(idna));
+}
+
+QString KIDNA::toUnicode(const QString &idna)
+{
+#ifndef Q_WS_WIN //TODO kresolver not ported
+ if (idna.length() && (idna[0] == "."))
+ return idna[0] + KResolver::domainToUnicode(idna.mid(1));
+ return KResolver::domainToUnicode(idna);
+#else
+ return QString::null;
+#endif
+}
diff --git a/kdecore/kidna.h b/kdecore/kidna.h
new file mode 100644
index 000000000..a8b04200b
--- /dev/null
+++ b/kdecore/kidna.h
@@ -0,0 +1,51 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KIDNA_H
+#define _KIDNA_H
+
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+namespace KIDNA {
+ /**
+ * Converts an International Domain Name @p idna to
+ * its ASCII representation
+ *
+ * If conversion is not possible, an empty string is returned.
+ */
+ KDECORE_EXPORT QCString toAsciiCString(const QString &idna);
+
+ /**
+ * Converts an International Domain Name @p idna to
+ * its ASCII representation
+ *
+ * If conversion is not possible, an empty string is returned.
+ */
+ KDECORE_EXPORT QString toAscii(const QString &idna);
+
+ /**
+ * Converts an International Domain Name @p idna to
+ * its UNICODE representation
+ */
+ KDECORE_EXPORT QString toUnicode(const QString &idna);
+}
+
+#endif /* _KIDNA_H */
diff --git a/kdecore/kinstance.cpp b/kdecore/kinstance.cpp
new file mode 100644
index 000000000..cc1e0837d
--- /dev/null
+++ b/kdecore/kinstance.cpp
@@ -0,0 +1,283 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "kinstance.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "kconfig.h"
+#include "klocale.h"
+#include "kcharsets.h"
+#include "kiconloader.h"
+#include "kaboutdata.h"
+#include "kstandarddirs.h"
+#include "kdebug.h"
+#include "kglobal.h"
+#include "kmimesourcefactory.h"
+
+#include <qfont.h>
+
+#include "config.h"
+#ifndef NDEBUG
+ #include <assert.h>
+ #include <qptrdict.h>
+ static QPtrList<KInstance> *allInstances = 0;
+ static QPtrDict<QCString> *allOldInstances = 0;
+ #define DEBUG_ADD do { if (!allInstances) { allInstances = new QPtrList<KInstance>(); allOldInstances = new QPtrDict<QCString>(); } allInstances->append(this); allOldInstances->insert( this, new QCString( _name)); } while (false);
+ #define DEBUG_REMOVE do { allInstances->removeRef(this); } while (false);
+ #define DEBUG_CHECK_ALIVE do { if (!allInstances->contains((KInstance*)this)) { QCString *old = allOldInstances->find((KInstance*)this); qWarning("ACCESSING DELETED KINSTANCE! (%s)", old ? old->data() : "<unknown>"); assert(false); } } while (false);
+#else
+ #define DEBUG_ADD
+ #define DEBUG_REMOVE
+ #define DEBUG_CHECK_ALIVE
+#endif
+
+class KInstancePrivate
+{
+public:
+ KInstancePrivate ()
+ {
+ mimeSourceFactory = 0L;
+ }
+
+ ~KInstancePrivate ()
+ {
+ delete mimeSourceFactory;
+ }
+
+ KMimeSourceFactory* mimeSourceFactory;
+ QString configName;
+ bool ownAboutdata;
+ KSharedConfig::Ptr sharedConfig;
+};
+
+KInstance::KInstance( const QCString& name)
+ : _dirs (0L),
+ _config (0L),
+ _iconLoader (0L),
+ _name( name ), _aboutData( new KAboutData( name, "", 0 ) )
+{
+ DEBUG_ADD
+ Q_ASSERT(!name.isEmpty());
+ if (!KGlobal::_instance)
+ {
+ KGlobal::_instance = this;
+ KGlobal::setActiveInstance(this);
+ }
+
+ d = new KInstancePrivate ();
+ d->ownAboutdata = true;
+}
+
+KInstance::KInstance( const KAboutData * aboutData )
+ : _dirs (0L),
+ _config (0L),
+ _iconLoader (0L),
+ _name( aboutData->appName() ), _aboutData( aboutData )
+{
+ DEBUG_ADD
+ Q_ASSERT(!_name.isEmpty());
+
+ if (!KGlobal::_instance)
+ {
+ KGlobal::_instance = this;
+ KGlobal::setActiveInstance(this);
+ }
+
+ d = new KInstancePrivate ();
+ d->ownAboutdata = false;
+}
+
+KInstance::KInstance( KInstance* src )
+ : _dirs ( src->_dirs ),
+ _config ( src->_config ),
+ _iconLoader ( src->_iconLoader ),
+ _name( src->_name ), _aboutData( src->_aboutData )
+{
+ DEBUG_ADD
+ Q_ASSERT(!_name.isEmpty());
+
+ if (!KGlobal::_instance || KGlobal::_instance == src )
+ {
+ KGlobal::_instance = this;
+ KGlobal::setActiveInstance(this);
+ }
+
+ d = new KInstancePrivate ();
+ d->ownAboutdata = src->d->ownAboutdata;
+ d->sharedConfig = src->d->sharedConfig;
+
+ src->_dirs = 0L;
+ src->_config = 0L;
+ src->_iconLoader = 0L;
+ src->_aboutData = 0L;
+ delete src;
+}
+
+KInstance::~KInstance()
+{
+ DEBUG_CHECK_ALIVE
+
+ if (d->ownAboutdata)
+ delete _aboutData;
+ _aboutData = 0;
+
+ delete d;
+ d = 0;
+
+ delete _iconLoader;
+ _iconLoader = 0;
+
+ // delete _config; // Do not delete, stored in d->sharedConfig
+ _config = 0;
+ delete _dirs;
+ _dirs = 0;
+
+ if (KGlobal::_instance == this)
+ KGlobal::_instance = 0;
+ if (KGlobal::activeInstance() == this)
+ KGlobal::setActiveInstance(0);
+ DEBUG_REMOVE
+}
+
+
+KStandardDirs *KInstance::dirs() const
+{
+ DEBUG_CHECK_ALIVE
+ if( _dirs == 0 ) {
+ _dirs = new KStandardDirs( );
+ if (_config) {
+ if (_dirs->addCustomized(_config))
+ _config->reparseConfiguration();
+ } else
+ config(); // trigger adding of possible customized dirs
+ }
+
+ return _dirs;
+}
+
+extern bool kde_kiosk_exception;
+extern bool kde_kiosk_admin;
+
+KConfig *KInstance::config() const
+{
+ DEBUG_CHECK_ALIVE
+ if( _config == 0 ) {
+ if ( !d->configName.isEmpty() )
+ {
+ d->sharedConfig = KSharedConfig::openConfig( d->configName );
+
+ // Check whether custom config files are allowed.
+ d->sharedConfig->setGroup( "KDE Action Restrictions" );
+ QString kioskException = d->sharedConfig->readEntry("kiosk_exception");
+ if (d->sharedConfig->readBoolEntry( "custom_config", true))
+ {
+ d->sharedConfig->setGroup(QString::null);
+ }
+ else
+ {
+ d->sharedConfig = 0;
+ }
+
+ }
+
+ if ( d->sharedConfig == 0 )
+ {
+ if ( !_name.isEmpty() )
+ d->sharedConfig = KSharedConfig::openConfig( _name + "rc");
+ else
+ d->sharedConfig = KSharedConfig::openConfig( QString::null );
+ }
+
+ // Check if we are excempt from kiosk restrictions
+ if (kde_kiosk_admin && !kde_kiosk_exception && !QCString(getenv("KDE_KIOSK_NO_RESTRICTIONS")).isEmpty())
+ {
+ kde_kiosk_exception = true;
+ d->sharedConfig = 0;
+ return config(); // Reread...
+ }
+
+ _config = d->sharedConfig;
+ if (_dirs)
+ if (_dirs->addCustomized(_config))
+ _config->reparseConfiguration();
+ }
+
+ return _config;
+}
+
+KSharedConfig *KInstance::sharedConfig() const
+{
+ DEBUG_CHECK_ALIVE
+ if (_config == 0)
+ (void) config(); // Initialize config
+
+ return d->sharedConfig;
+}
+
+void KInstance::setConfigName(const QString &configName)
+{
+ DEBUG_CHECK_ALIVE
+ d->configName = configName;
+}
+
+KIconLoader *KInstance::iconLoader() const
+{
+ DEBUG_CHECK_ALIVE
+ if( _iconLoader == 0 ) {
+ _iconLoader = new KIconLoader( _name, dirs() );
+ _iconLoader->enableDelayedIconSetLoading( true );
+ }
+
+ return _iconLoader;
+}
+
+void KInstance::newIconLoader() const
+{
+ DEBUG_CHECK_ALIVE
+ KIconTheme::reconfigure();
+ _iconLoader->reconfigure( _name, dirs() );
+}
+
+const KAboutData * KInstance::aboutData() const
+{
+ DEBUG_CHECK_ALIVE
+ return _aboutData;
+}
+
+QCString KInstance::instanceName() const
+{
+ DEBUG_CHECK_ALIVE
+ return _name;
+}
+
+KMimeSourceFactory* KInstance::mimeSourceFactory () const
+{
+ DEBUG_CHECK_ALIVE
+ if (!d->mimeSourceFactory)
+ {
+ d->mimeSourceFactory = new KMimeSourceFactory(_iconLoader);
+ d->mimeSourceFactory->setInstance(const_cast<KInstance *>(this));
+ }
+
+ return d->mimeSourceFactory;
+}
+
+void KInstance::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
diff --git a/kdecore/kinstance.h b/kdecore/kinstance.h
new file mode 100644
index 000000000..88678ba99
--- /dev/null
+++ b/kdecore/kinstance.h
@@ -0,0 +1,159 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KINSTANCE_H
+#define _KINSTANCE_H
+
+class KStandardDirs;
+class KAboutData;
+class KConfig;
+class KIconLoader;
+class KCharsets;
+class QFont;
+class KInstancePrivate;
+class KMimeSourceFactory;
+class KSharedConfig;
+
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+
+/**
+ * Access to KDE global objects for use in shared libraries. In
+ * practical terms, this class is used in KDE components. This allows
+ * components to store things that normally would be accessed by
+ * KGlobal.
+ *
+ * @author Torben Weis
+ */
+class KDECORE_EXPORT KInstance
+{
+ friend class KStandardDirs;
+
+ public:
+ /**
+ * Constructor.
+ * @param instanceName the name of the instance
+ */
+ KInstance( const QCString& instanceName) ;
+
+ /**
+ * Constructor.
+ * When building a KInstance that is not your KApplication,
+ * make sure that the KAboutData and the KInstance have the same life time.
+ * You have to destroy both, since the instance doesn't own the about data.
+ * Don't build a KAboutData on the stack in this case !
+ * Building a KAboutData on the stack is only ok for usage with
+ * KCmdLineArgs and KApplication (not destroyed until the app exits).
+ * @param aboutData data about this instance (see KAboutData)
+ */
+ KInstance( const KAboutData * aboutData );
+
+ /*
+ * @internal
+ * Only for K(Unique)Application
+ * Initialize from src and delete it.
+ */
+
+ KInstance( KInstance* src );
+
+ /**
+ * Destructor.
+ */
+ virtual ~KInstance();
+
+ /**
+ * Returns the application standard dirs object.
+ * @return The KStandardDirs of the application.
+ */
+ KStandardDirs *dirs() const;
+
+ /**
+ * Returns the general config object ("appnamerc").
+ * @return the KConfig object for the instance.
+ */
+ KConfig *config() const;
+
+ /**
+ * Returns the general config object ("appnamerc").
+ * @return the KConfig object for the instance.
+ */
+ KSharedConfig *sharedConfig() const;
+
+ /**
+ * Returns an iconloader object.
+ * @return the iconloader object.
+ */
+ KIconLoader *iconLoader() const;
+
+ /**
+ * Re-allocate the global iconloader.
+ */
+ void newIconLoader() const;
+
+ /**
+ * Returns the about data of this instance
+ * Warning, can be 0L
+ * @return the about data of the instance, or 0 if it has
+ * not been set yet
+ */
+ const KAboutData *aboutData() const;
+
+ /**
+ * Returns the name of the instance
+ * @return the instance name, can be null if the KInstance has been
+ * created with a null name
+ */
+ QCString instanceName() const;
+
+ /**
+ * Returns the KMimeSourceFactory of the instance.
+ * Mainly added for API completeness and future extensibility.
+ * @return the KMimeSourceFactory set as default for this application.
+ */
+ KMimeSourceFactory* mimeSourceFactory () const;
+
+protected:
+ /**
+ * Copy Constructor is not allowed
+ */
+ KInstance( const KInstance& );
+
+ /**
+ * Set name of default config file.
+ * @param name the name of the default config file
+ * @since 3.1
+ */
+ void setConfigName(const QString &name);
+
+private:
+ mutable KStandardDirs *_dirs;
+
+ mutable KConfig *_config;
+ mutable KIconLoader *_iconLoader;
+
+ QCString _name;
+ const KAboutData *_aboutData;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KInstancePrivate *d;
+};
+
+#endif
+
diff --git a/kdecore/kipc.cpp b/kdecore/kipc.cpp
new file mode 100644
index 000000000..087f28c86
--- /dev/null
+++ b/kdecore/kipc.cpp
@@ -0,0 +1,112 @@
+/* This file is part of the KDE libraries
+
+ Copyright (C) 1999 Mattias Ettrich (ettrich@kde.org)
+ Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+/*
+ * kipc.cpp: Send a message to one/all KDE apps.
+ *
+ * $Id$
+ */
+#include "config.h"
+
+#include <qwindowdefs.h>
+
+#if defined Q_WS_X11
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <kxerrorhandler.h>
+#endif
+
+#include <kipc.h>
+
+
+#if defined Q_WS_X11
+static long getSimpleProperty(Window w, Atom a)
+{
+ Atom real_type;
+ int format;
+ unsigned long n, extra, res = 0;
+ int status;
+ unsigned char *p = 0;
+
+ status = XGetWindowProperty(qt_xdisplay(), w, a, 0L, 1L, False, a,
+ &real_type, &format, &n, &extra, &p);
+ if ((status == Success) && (n == 1) && (format == 32))
+ res = *(unsigned long*)p;
+ if (p) XFree(p);
+ return res;
+}
+#endif
+
+void KIPC::sendMessage(Message msg, WId w, int data)
+{
+#if defined Q_WS_X11
+ static Atom a = 0;
+ if (a == 0)
+ a = XInternAtom(qt_xdisplay(), "KIPC_COMM_ATOM", False);
+ XEvent ev;
+ ev.xclient.type = ClientMessage;
+ ev.xclient.display = qt_xdisplay();
+ ev.xclient.window = (Window) w;
+ ev.xclient.message_type = a;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = msg;
+ ev.xclient.data.l[1] = data;
+ XSendEvent(qt_xdisplay(), (Window) w, False, 0L, &ev);
+
+ // KDE 1 support
+ static Atom kde1 = 0;
+ if ( msg == PaletteChanged || msg == FontChanged ) {
+ if ( kde1 == 0 )
+ kde1 = XInternAtom(qt_xdisplay(), "KDEChangeGeneral", False );
+ ev.xclient.message_type = kde1;
+ XSendEvent(qt_xdisplay(), (Window) w, False, 0L, &ev);
+ }
+
+#endif
+}
+
+
+void KIPC::sendMessageAll(Message msg, int data)
+{
+#if defined Q_WS_X11
+ unsigned int i, nrootwins;
+ Window dw1, dw2, *rootwins = 0;
+ Display *dpy = qt_xdisplay();
+ int screen_count = ScreenCount(dpy);
+
+ KXErrorHandler handler;
+ for (int s = 0; s < screen_count; s++) {
+ Window root = RootWindow(dpy, s);
+
+ XQueryTree(dpy, root, &dw1, &dw2, &rootwins, &nrootwins);
+ Atom a = XInternAtom(qt_xdisplay(), "KDE_DESKTOP_WINDOW", False);
+ for (i = 0; i < nrootwins; i++)
+ {
+ if (getSimpleProperty(rootwins[i], a) != 0L)
+ sendMessage(msg, rootwins[i], data);
+ }
+ XFree((char *) rootwins);
+ }
+ XSync(dpy,False);
+#endif
+}
+
diff --git a/kdecore/kipc.h b/kdecore/kipc.h
new file mode 100644
index 000000000..d50697926
--- /dev/null
+++ b/kdecore/kipc.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE libraries
+
+ Copyright (C) 1999 Mattias Ettrich (ettrich@kde.org)
+ Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KIPC_h_Included__
+#define __KIPC_h_Included__
+
+#include <qwindowdefs.h>
+#include "kdelibs_export.h"
+
+/**
+ * This class implements a very simple IPC mechanism for KDE. You can send
+ * a message of a predefined type to either a specific application, or to all
+ * KDE application on the current display. The message can carry one integer of
+ * data.
+ *
+ * KIPC is mainly used in KDE for sending "Change Messages", i.e. a message to
+ * all KDE apps that a certain setting (the font, for example) has changed.
+ * For anything more complex it is recommended to use DCOP -- the Desktop
+ * Communications Protocol.
+ *
+ * Messages with id code < 32 are called "System Messages". These are
+ * directly handled by KApplication. Examples are: PaletteChanged and
+ * StyleChanged. Messages with id code >= 32 are user messages. KApplication
+ * emits the signal kipcMessage(id,arg) for each user message it receives.
+ *
+ * KIPC is implemented using X11 ClientMessage events.
+ *
+ * @see KApplication::kipcMessage()
+ * @author Geert Jansen <jansen@kde.org>
+ */
+class KDECORE_EXPORT KIPC
+{
+public:
+ /**
+ * A identifier for messages. Messages below UserMessage are system
+ * messages, messages above can be defined by the user.
+ */
+ enum Message { PaletteChanged=0, FontChanged, StyleChanged,
+ BackgroundChanged, SettingsChanged, IconChanged, ToolbarStyleChanged,
+ ClipboardConfigChanged, /// @since 3.1
+ BlockShortcuts, /// @since 3.5
+ UserMessage=32 };
+
+ /**
+ * Send a message to a specific application.
+ *
+ * @param msg The message to send.
+ * @param w The window id of a toplevel window of the target application.
+ * @param data An optional integer of data.
+ */
+ static void sendMessage(Message msg, WId w, int data=0);
+
+ /**
+ * Send a message to all KDE application on the current display.
+ *
+ * @param msg The message to send.
+ * @param data An optional integer of data.
+ */
+ static void sendMessageAll(Message msg, int data=0);
+};
+#endif
diff --git a/kdecore/kkeynative.h b/kdecore/kkeynative.h
new file mode 100644
index 000000000..47b4ad677
--- /dev/null
+++ b/kdecore/kkeynative.h
@@ -0,0 +1,258 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Ellis Whitehead <ellis@kde.org>
+
+ Win32 port:
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KKEYNATIVE_H
+#define __KKEYNATIVE_H
+
+#include <kshortcut.h>
+
+#ifdef Q_WS_X11
+typedef union _XEvent XEvent;
+#endif
+
+class KKeyNativePrivate;
+/**
+ * Representation of a key in the format native of the windowing system (eg. X11).
+ * @see KKey
+ */
+class KDECORE_EXPORT KKeyNative
+{
+ public:
+ /**
+ * Creates a new null KKey.
+ * @see clear()
+ * @see isNull()
+ * @see null()
+ */
+ KKeyNative();
+
+#ifdef Q_WS_X11
+ /**
+ * Extracts a new native key from the given xevent.
+ * @param xevent the XEvent that contains the key
+ */
+ KKeyNative( const XEvent* xevent );
+#endif
+
+ /**
+ * Creates a new native key for the given KKey code.
+ * @param key the KKey that contains the generic key
+ */
+ KKeyNative( const KKey& key );
+
+ /**
+ * Copy constructor.
+ */
+ KKeyNative( const KKeyNative& );
+
+ /**
+ * @internal
+ */
+ KKeyNative( uint code, uint mod, uint sym );
+ ~KKeyNative();
+
+ /**
+ * Clears the key. The key is null after calling this function.
+ * @see isNull()
+ */
+ void clear();
+
+#ifdef Q_WS_X11
+ /**
+ * Initializes the native key by extracting the information
+ * from the given xevent.
+ * @param xevent the XEvent that contains the key
+ * @return true if successful, false otherwise
+ */
+ bool init( const XEvent* xevent );
+#endif
+
+ /**
+ * Creates a new native key for the given KKey code.
+ * @param key the KKey that contains the generic key
+ * @return true if successful, false otherwise
+ */
+ bool init( const KKey& key );
+
+ /**
+ * Copies the given key into this key.
+ * @param key the key to copy
+ * @return true if successful, false otherwise
+ */
+ bool init( const KKeyNative& key );
+
+ /**
+ * Copies the given key into this key.
+ * @param key the key to copy
+ * @return this key
+ */
+ KKeyNative& operator =( const KKeyNative& key )
+ { init( key ); return *this; }
+
+ /**
+ * Returns the qt key code.
+ * @return the qt key code or 0 if there is no key set.
+ * @see Qt::Key
+ */
+
+ int keyCodeQt() const;
+
+ /**
+ * Returns the KKey representation of this key.
+ * @return the KKey representation
+ */
+ KKey key() const;
+
+ /**
+ * Converts this key to its KKey representation.
+ * @return the KKey representation
+ * @see key()
+ */
+ operator KKey() const { return key(); }
+
+ /**
+ * The native keycode of the key.
+ * @return the native keycode
+ */
+ uint code() const;
+
+ /**
+ * The native modifier flags of the key.
+ * @return the native modifier flags
+ */
+ uint mod() const;
+
+ /**
+ * The native symbol (KeySym) of the key.
+ * @return the native symbol (KeySym)
+ */
+ uint sym() const;
+
+ /**
+ * Returns true if the key is null (after clear() or empty
+ * constructor).
+ * @return true if the key is null
+ * @see clear()
+ * @see null()
+ */
+ bool isNull() const;
+
+ /**
+ * Compares this key with the given KKeyNative object. Returns a
+ * negative number if the given KKeyNative is larger, 0 if they
+ * are equal and a positive number this KKeyNative is larger. The
+ * returned value is the difference between the symbol, modifier
+ * or code, whatever is non-zero first.
+ *
+ * @param key the key to compare with this key
+ * @return a negative number if the given KKeyNative is larger, 0 if
+ * they are equal and a positive number this KKeyNative is larger
+ */
+ int compare( const KKeyNative& key ) const;
+
+ /**
+ * Compares the symbol, modifiers and code of both keys.
+ * @see compare()
+ */
+ bool operator == ( const KKeyNative& key ) const
+ { return compare( key ) == 0; }
+
+ /**
+ * Compares the symbol, modifiers and code of both keys.
+ * @see compare()
+ */
+ bool operator != ( const KKeyNative& key ) const
+ { return compare( key ) != 0; }
+
+ /**
+ * Compares the symbol, modifiers and code of both keys.
+ * @see compare()
+ */
+ bool operator < ( const KKeyNative& key ) const
+ { return compare( key ) < 0; }
+
+ /**
+ * Returns a null key.
+ * @return the null key
+ * @see isNull()
+ * @see clear()
+ */
+ static KKeyNative& null();
+
+ // General query functions. //
+ /**
+ * Checks whether the keyboard has a Win key.
+ * @return true if the keyboard has a Win key
+ */
+ static bool keyboardHasWinKey();
+
+#ifdef Q_WS_X11
+ /**
+ * Returns the equivalent X modifier mask of the given modifier flag.
+ * @param modFlag the mod flags to test
+ * @return the equivalent native flags of the window system
+ */
+ static uint modX( KKey::ModFlag modFlag );
+
+ /**
+ * Returns bitwise OR'ed mask containing Shift, Ctrl, Alt, and
+ * Win (if available).
+ * @return the mask of Shift, Ctrl, Alt and Win.
+ */
+ static uint accelModMaskX();
+
+ /**
+ * Returns the X11 NumLock modifier mask/flag.
+ * @return the X11 NumLock modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ static uint modXNumLock();
+
+ /**
+ * Returns the X11 Lock modifier mask/flag.
+ * @return the X11 Lock modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ static uint modXLock();
+
+ /**
+ * Returns the X11 ScrollLock modifier mask/flag.
+ * @return the X11 ScrollLock modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ static uint modXScrollLock();
+
+ /**
+ * Returns the X11 Mode_switch modifier mask/flag.
+ * @return the X11 Mode_switch modifier mask/flag.
+ * @see accelModMaskX()
+ * @since 3.5
+ */
+ static uint modXModeSwitch();
+#endif
+
+ private:
+ uint m_code, m_mod, m_sym;
+ KKeyNativePrivate* d;
+};
+
+#endif // !__KKEYNATIVE_H
diff --git a/kdecore/kkeynative_x11.cpp b/kdecore/kkeynative_x11.cpp
new file mode 100644
index 000000000..c0f00eecf
--- /dev/null
+++ b/kdecore/kkeynative_x11.cpp
@@ -0,0 +1,201 @@
+/*
+ Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
+
+ Win32 port:
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qnamespace.h>
+#include <qwindowdefs.h>
+
+#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_MACX) // Only compile this module if we're compiling for X11, mac or win32
+
+#include "kkeynative.h"
+#include "kkeyserver_x11.h"
+
+#include <qmap.h>
+#include <qstringlist.h>
+#include "kckey.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+#ifdef Q_WS_X11
+#define XK_MISCELLANY
+#define XK_XKB_KEYS
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysymdef.h>
+#include <ctype.h>
+#endif
+
+//---------------------------------------------------------------------
+
+static KKeyNative* gx_pkey = 0;
+
+//---------------------------------------------------------------------
+// KKeyNative
+//---------------------------------------------------------------------
+
+KKeyNative::KKeyNative() { clear(); }
+KKeyNative::KKeyNative( const KKey& key ) { init( key ); }
+KKeyNative::KKeyNative( const KKeyNative& key ) { init( key ); }
+#ifdef Q_WS_X11
+KKeyNative::KKeyNative( const XEvent* pEvent ) { init( pEvent ); }
+#endif
+
+KKeyNative::KKeyNative( uint code, uint mod, uint sym )
+{
+ m_code = code;
+ m_mod = mod;
+ m_sym = sym;
+}
+
+KKeyNative::~KKeyNative()
+ { }
+
+void KKeyNative::clear()
+{
+ m_code = 0;
+ m_mod = 0;
+ m_sym = 0;
+}
+
+#ifdef Q_WS_X11
+bool KKeyNative::init( const XEvent* pEvent )
+{
+ KeySym keySym;
+ m_code = pEvent->xkey.keycode;
+ m_mod = pEvent->xkey.state;
+ XLookupString( (XKeyEvent*) pEvent, 0, 0, &keySym, 0 );
+ m_sym = (uint) keySym;
+ return true;
+}
+#endif
+
+bool KKeyNative::init( const KKey& key )
+{
+#ifdef Q_WS_WIN
+ m_sym = key.sym();
+ m_code = m_sym; //key.keyCodeQt();
+ m_mod = key.m_mod;
+#elif !defined(Q_WS_WIN) && !defined(Q_WS_MACX)
+ // Get any extra mods required by the sym.
+ // E.g., XK_Plus requires SHIFT on the en layout.
+ m_sym = key.sym();
+ uint modExtra = KKeyServer::Sym(m_sym).getModsRequired();
+ // Get the X modifier equivalent.
+ if( !m_sym || !KKeyServer::modToModX( key.modFlags() | modExtra, m_mod ) ) {
+ m_sym = m_mod = 0;
+ m_code = 0;
+ return false;
+ }
+
+ // XKeysymToKeycode returns the wrong keycode for XK_Print and XK_Break.
+ // Specifically, it returns the code for SysReq instead of Print
+ // Only do this for the default Xorg layout, other keycode mappings
+ // (e.g. evdev) don't need or want it.
+ if( m_sym == XK_Print && !(m_mod & Mod1Mask) &&
+ XKeycodeToKeysym( qt_xdisplay(), 111, 0 ) == XK_Print )
+ m_code = 111; // code for Print
+ else if( m_sym == XK_Break || (m_sym == XK_Pause && (m_mod & ControlMask)) &&
+ XKeycodeToKeysym( qt_xdisplay(), 114, 0 ) == XK_Pause )
+ m_code = 114;
+ else
+ m_code = XKeysymToKeycode( qt_xdisplay(), m_sym );
+
+ if( !m_code && m_sym )
+ kdDebug(125) << "Couldn't get code for sym" << endl;
+ // Now get the true sym formed by the modifiers
+ // E.g., Shift+Equal => Plus on the en layout.
+ if( key.modFlags() && ( ( m_sym < XK_Home || m_sym > XK_Begin ) &&
+ m_sym != XK_Insert && m_sym != XK_Delete ))
+ KKeyServer::codeXToSym( m_code, m_mod, m_sym );
+#endif
+ return true;
+}
+
+bool KKeyNative::init( const KKeyNative& key )
+{
+ m_code = key.m_code;
+ m_mod = key.m_mod;
+ m_sym = key.m_sym;
+ return true;
+}
+
+uint KKeyNative::code() const { return m_code; }
+uint KKeyNative::mod() const { return m_mod; }
+uint KKeyNative::sym() const { return m_sym; }
+
+bool KKeyNative::isNull() const
+{
+ return m_sym == 0;
+}
+
+int KKeyNative::compare( const KKeyNative& key ) const
+{
+ if( m_sym != key.m_sym ) return m_sym - key.m_sym;
+ if( m_mod != key.m_mod ) return m_mod - key.m_mod;
+ if( m_code != key.m_code ) return m_code - key.m_code;
+ return 0;
+}
+
+KKeyNative& KKeyNative::null()
+{
+ if( !gx_pkey )
+ gx_pkey = new KKeyNative;
+ if( !gx_pkey->isNull() )
+ gx_pkey->clear();
+ return *gx_pkey;
+}
+
+KKey KKeyNative::key() const
+{
+#ifdef Q_WS_WIN
+ return KKey( m_sym, m_mod );
+#else
+ uint modSpec;
+ if( KKeyServer::modXToMod( m_mod, modSpec ) )
+ return KKey( m_sym, modSpec );
+ else
+ return KKey();
+#endif
+}
+
+int KKeyNative::keyCodeQt() const
+{
+ int keyQt = KKeyServer::Sym(m_sym).qt(), modQt;
+
+ if( keyQt != Qt::Key_unknown && KKeyServer::modXToModQt( m_mod, modQt ) )
+ return keyQt | modQt;
+
+ return 0;
+}
+
+bool KKeyNative::keyboardHasWinKey() { return KKeyServer::keyboardHasWinKey(); }
+
+#ifdef Q_WS_X11
+uint KKeyNative::modX( KKey::ModFlag modFlag ) { return KKeyServer::modX( modFlag ); }
+uint KKeyNative::accelModMaskX() { return KKeyServer::accelModMaskX(); }
+uint KKeyNative::modXNumLock() { return KKeyServer::modXNumLock(); }
+uint KKeyNative::modXLock() { return KKeyServer::modXLock(); }
+uint KKeyNative::modXScrollLock() { return KKeyServer::modXScrollLock(); }
+uint KKeyNative::modXModeSwitch() { return KKeyServer::modXModeSwitch(); }
+#endif
+
+#endif // Q_WS_X11
diff --git a/kdecore/kkeyserver.h b/kdecore/kkeyserver.h
new file mode 100644
index 000000000..ef673ea9a
--- /dev/null
+++ b/kdecore/kkeyserver.h
@@ -0,0 +1,29 @@
+/*
+ Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
+
+ Win32 port:
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KKEYSERVER_H
+#define _KKEYSERVER_H
+
+//FOR COMPATIBILITY
+#include "kkeyserver_x11.h"
+
+#endif // !_KKEYSERVER_H
diff --git a/kdecore/kkeyserver_x11.cpp b/kdecore/kkeyserver_x11.cpp
new file mode 100644
index 000000000..bda0feb36
--- /dev/null
+++ b/kdecore/kkeyserver_x11.cpp
@@ -0,0 +1,1052 @@
+/*
+ Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
+
+ Win32 port:
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <qnamespace.h>
+#include <qwindowdefs.h>
+
+#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_MACX) // Only compile this module if we're compiling for X11, mac or win32
+
+#include "kkeyserver_x11.h"
+#include "kkeynative.h"
+#include "kshortcut.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#ifdef Q_WS_X11
+# define XK_MISCELLANY
+# define XK_XKB_KEYS
+# include <X11/X.h>
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/keysymdef.h>
+# define X11_ONLY(arg) arg, //allows to omit an argument
+#else
+# include <kckey.h>
+# define X11_ONLY(arg)
+# define XK_ISO_Left_Tab Qt::Key_Backtab
+# define XK_BackSpace Qt::Key_Backspace
+# define XK_Sys_Req Qt::Key_SysReq
+# define XK_Caps_Lock Qt::Key_CapsLock
+# define XK_Num_Lock Qt::Key_NumLock
+# define XK_Scroll_Lock Qt::Key_ScrollLock
+# define XK_Prior Qt::Key_Prior
+# define XK_Next Qt::Key_Next
+#endif
+
+namespace KKeyServer
+{
+
+//---------------------------------------------------------------------
+// Data Structures
+//---------------------------------------------------------------------
+
+struct Mod
+{
+ int m_mod;
+};
+
+//---------------------------------------------------------------------
+// Array Structures
+//---------------------------------------------------------------------
+
+struct ModInfo
+{
+ KKey::ModFlag mod;
+ int modQt;
+#ifdef Q_WS_X11
+ uint modX;
+#endif
+ const char* psName;
+ QString sLabel;
+};
+
+struct SymVariation
+{
+ uint sym, symVariation;
+ bool bActive;
+};
+
+struct SymName
+{
+ uint sym;
+ const char* psName;
+};
+
+struct TransKey {
+ int keySymQt;
+ uint keySymX;
+};
+
+//---------------------------------------------------------------------
+// Arrays
+//---------------------------------------------------------------------
+
+static ModInfo g_rgModInfo[KKey::MOD_FLAG_COUNT] =
+{
+ { KKey::SHIFT, Qt::SHIFT, X11_ONLY(ShiftMask) I18N_NOOP("Shift"), QString() },
+ { KKey::CTRL, Qt::CTRL, X11_ONLY(ControlMask) I18N_NOOP("Ctrl"), QString() },
+ { KKey::ALT, Qt::ALT, X11_ONLY(Mod1Mask) I18N_NOOP("Alt"), QString() },
+ { KKey::WIN, KKey::QtWIN, X11_ONLY(Mod4Mask) I18N_NOOP("Win"), QString() }
+};
+
+// Special Names List
+static const SymName g_rgSymNames[] = {
+ { XK_ISO_Left_Tab, "Backtab" },
+ { XK_BackSpace, I18N_NOOP("Backspace") },
+ { XK_Sys_Req, I18N_NOOP("SysReq") },
+ { XK_Caps_Lock, I18N_NOOP("CapsLock") },
+ { XK_Num_Lock, I18N_NOOP("NumLock") },
+ { XK_Scroll_Lock, I18N_NOOP("ScrollLock") },
+ { XK_Prior, I18N_NOOP("PageUp") },
+ { XK_Next, I18N_NOOP("PageDown") },
+#ifdef sun
+ { XK_F11, I18N_NOOP("Stop") },
+ { XK_F12, I18N_NOOP("Again") },
+ { XK_F13, I18N_NOOP("Props") },
+ { XK_F14, I18N_NOOP("Undo") },
+ { XK_F15, I18N_NOOP("Front") },
+ { XK_F16, I18N_NOOP("Copy") },
+ { XK_F17, I18N_NOOP("Open") },
+ { XK_F18, I18N_NOOP("Paste") },
+ { XK_F19, I18N_NOOP("Find") },
+ { XK_F20, I18N_NOOP("Cut") },
+ { XK_F22, I18N_NOOP("Print") },
+#endif
+ { 0, 0 }
+};
+
+#ifdef Q_WS_X11
+static SymVariation g_rgSymVariation[] =
+{
+ { '/', XK_KP_Divide, false },
+ { '*', XK_KP_Multiply, false },
+ { '-', XK_KP_Subtract, false },
+ { '+', XK_KP_Add, false },
+ { XK_Return, XK_KP_Enter, false },
+ { 0, 0, false }
+};
+
+// TODO: Add Mac key names list: Key_Backspace => "Delete", Key_Delete => "Del"
+
+// These are the X equivalents to the Qt keycodes 0x1000 - 0x1026
+static const TransKey g_rgQtToSymX[] =
+{
+ { Qt::Key_Escape, XK_Escape },
+ { Qt::Key_Tab, XK_Tab },
+ { Qt::Key_Backtab, XK_ISO_Left_Tab },
+ { Qt::Key_Backspace, XK_BackSpace },
+ { Qt::Key_Return, XK_Return },
+ { Qt::Key_Enter, XK_KP_Enter },
+ { Qt::Key_Insert, XK_Insert },
+ { Qt::Key_Delete, XK_Delete },
+ { Qt::Key_Pause, XK_Pause },
+#ifdef sun
+ { Qt::Key_Print, XK_F22 },
+#else
+ { Qt::Key_Print, XK_Print },
+#endif
+ { Qt::Key_SysReq, XK_Sys_Req },
+ { Qt::Key_Home, XK_Home },
+ { Qt::Key_End, XK_End },
+ { Qt::Key_Left, XK_Left },
+ { Qt::Key_Up, XK_Up },
+ { Qt::Key_Right, XK_Right },
+ { Qt::Key_Down, XK_Down },
+ { Qt::Key_Prior, XK_Prior },
+ { Qt::Key_Next, XK_Next },
+ //{ Qt::Key_Shift, 0 },
+ //{ Qt::Key_Control, 0 },
+ //{ Qt::Key_Meta, 0 },
+ //{ Qt::Key_Alt, 0 },
+ { Qt::Key_CapsLock, XK_Caps_Lock },
+ { Qt::Key_NumLock, XK_Num_Lock },
+ { Qt::Key_ScrollLock, XK_Scroll_Lock },
+ { Qt::Key_F1, XK_F1 },
+ { Qt::Key_F2, XK_F2 },
+ { Qt::Key_F3, XK_F3 },
+ { Qt::Key_F4, XK_F4 },
+ { Qt::Key_F5, XK_F5 },
+ { Qt::Key_F6, XK_F6 },
+ { Qt::Key_F7, XK_F7 },
+ { Qt::Key_F8, XK_F8 },
+ { Qt::Key_F9, XK_F9 },
+ { Qt::Key_F10, XK_F10 },
+ { Qt::Key_F11, XK_F11 },
+ { Qt::Key_F12, XK_F12 },
+ { Qt::Key_F13, XK_F13 },
+ { Qt::Key_F14, XK_F14 },
+ { Qt::Key_F15, XK_F15 },
+ { Qt::Key_F16, XK_F16 },
+ { Qt::Key_F17, XK_F17 },
+ { Qt::Key_F18, XK_F18 },
+ { Qt::Key_F19, XK_F19 },
+ { Qt::Key_F20, XK_F20 },
+ { Qt::Key_F21, XK_F21 },
+ { Qt::Key_F22, XK_F22 },
+ { Qt::Key_F23, XK_F23 },
+ { Qt::Key_F24, XK_F24 },
+ { Qt::Key_F25, XK_F25 },
+ { Qt::Key_F26, XK_F26 },
+ { Qt::Key_F27, XK_F27 },
+ { Qt::Key_F28, XK_F28 },
+ { Qt::Key_F29, XK_F29 },
+ { Qt::Key_F30, XK_F30 },
+ { Qt::Key_F31, XK_F31 },
+ { Qt::Key_F32, XK_F32 },
+ { Qt::Key_F33, XK_F33 },
+ { Qt::Key_F34, XK_F34 },
+ { Qt::Key_F35, XK_F35 },
+ { Qt::Key_Super_L, XK_Super_L },
+ { Qt::Key_Super_R, XK_Super_R },
+ { Qt::Key_Menu, XK_Menu },
+ { Qt::Key_Hyper_L, XK_Hyper_L },
+ { Qt::Key_Hyper_R, XK_Hyper_R },
+ { Qt::Key_Help, XK_Help },
+ //{ Qt::Key_Direction_L, XK_Direction_L }, These keys don't exist in X11
+ //{ Qt::Key_Direction_R, XK_Direction_R },
+
+ { '/', XK_KP_Divide },
+ { '*', XK_KP_Multiply },
+ { '-', XK_KP_Subtract },
+ { '+', XK_KP_Add },
+ { Qt::Key_Return, XK_KP_Enter }
+#if QT_VERSION >= 0x030100
+
+// the next lines are taken from XFree > 4.0 (X11/XF86keysyms.h), defining some special
+// multimedia keys. They are included here as not every system has them.
+#define XF86XK_Standby 0x1008FF10
+#define XF86XK_AudioLowerVolume 0x1008FF11
+#define XF86XK_AudioMute 0x1008FF12
+#define XF86XK_AudioRaiseVolume 0x1008FF13
+#define XF86XK_AudioPlay 0x1008FF14
+#define XF86XK_AudioStop 0x1008FF15
+#define XF86XK_AudioPrev 0x1008FF16
+#define XF86XK_AudioNext 0x1008FF17
+#define XF86XK_HomePage 0x1008FF18
+#define XF86XK_Calculator 0x1008FF1D
+#define XF86XK_Mail 0x1008FF19
+#define XF86XK_Start 0x1008FF1A
+#define XF86XK_Search 0x1008FF1B
+#define XF86XK_AudioRecord 0x1008FF1C
+#define XF86XK_Back 0x1008FF26
+#define XF86XK_Forward 0x1008FF27
+#define XF86XK_Stop 0x1008FF28
+#define XF86XK_Refresh 0x1008FF29
+#define XF86XK_Favorites 0x1008FF30
+#define XF86XK_AudioPause 0x1008FF31
+#define XF86XK_AudioMedia 0x1008FF32
+#define XF86XK_MyComputer 0x1008FF33
+#define XF86XK_OpenURL 0x1008FF38
+#define XF86XK_Launch0 0x1008FF40
+#define XF86XK_Launch1 0x1008FF41
+#define XF86XK_Launch2 0x1008FF42
+#define XF86XK_Launch3 0x1008FF43
+#define XF86XK_Launch4 0x1008FF44
+#define XF86XK_Launch5 0x1008FF45
+#define XF86XK_Launch6 0x1008FF46
+#define XF86XK_Launch7 0x1008FF47
+#define XF86XK_Launch8 0x1008FF48
+#define XF86XK_Launch9 0x1008FF49
+#define XF86XK_LaunchA 0x1008FF4A
+#define XF86XK_LaunchB 0x1008FF4B
+#define XF86XK_LaunchC 0x1008FF4C
+#define XF86XK_LaunchD 0x1008FF4D
+#define XF86XK_LaunchE 0x1008FF4E
+#define XF86XK_LaunchF 0x1008FF4F
+// end of XF86keysyms.h
+ ,
+ { Qt::Key_Standby, XF86XK_Standby },
+ { Qt::Key_VolumeDown, XF86XK_AudioLowerVolume },
+ { Qt::Key_VolumeMute, XF86XK_AudioMute },
+ { Qt::Key_VolumeUp, XF86XK_AudioRaiseVolume },
+ { Qt::Key_MediaPlay, XF86XK_AudioPlay },
+ { Qt::Key_MediaStop, XF86XK_AudioStop },
+ { Qt::Key_MediaPrev, XF86XK_AudioPrev },
+ { Qt::Key_MediaNext, XF86XK_AudioNext },
+ { Qt::Key_HomePage, XF86XK_HomePage },
+ { Qt::Key_LaunchMail, XF86XK_Mail },
+ { Qt::Key_Search, XF86XK_Search },
+ { Qt::Key_MediaRecord, XF86XK_AudioRecord },
+ { Qt::Key_LaunchMedia, XF86XK_AudioMedia },
+ { Qt::Key_Launch1, XF86XK_Calculator },
+ { Qt::Key_Back, XF86XK_Back },
+ { Qt::Key_Forward, XF86XK_Forward },
+ { Qt::Key_Stop, XF86XK_Stop },
+ { Qt::Key_Refresh, XF86XK_Refresh },
+ { Qt::Key_Favorites, XF86XK_Favorites },
+ { Qt::Key_Launch0, XF86XK_MyComputer },
+ { Qt::Key_OpenUrl, XF86XK_OpenURL },
+ { Qt::Key_Launch2, XF86XK_Launch0 },
+ { Qt::Key_Launch3, XF86XK_Launch1 },
+ { Qt::Key_Launch4, XF86XK_Launch2 },
+ { Qt::Key_Launch5, XF86XK_Launch3 },
+ { Qt::Key_Launch6, XF86XK_Launch4 },
+ { Qt::Key_Launch7, XF86XK_Launch5 },
+ { Qt::Key_Launch8, XF86XK_Launch6 },
+ { Qt::Key_Launch9, XF86XK_Launch7 },
+ { Qt::Key_LaunchA, XF86XK_Launch8 },
+ { Qt::Key_LaunchB, XF86XK_Launch9 },
+ { Qt::Key_LaunchC, XF86XK_LaunchA },
+ { Qt::Key_LaunchD, XF86XK_LaunchB },
+ { Qt::Key_LaunchE, XF86XK_LaunchC },
+ { Qt::Key_LaunchF, XF86XK_LaunchD },
+#endif
+};
+#endif //Q_WS_X11
+
+//---------------------------------------------------------------------
+// Initialization
+//---------------------------------------------------------------------
+static bool g_bInitializedMods, g_bInitializedVariations, g_bInitializedKKeyLabels;
+static bool g_bMacLabels;
+#ifdef Q_WS_X11
+static uint g_modXNumLock, g_modXScrollLock, g_modXModeSwitch;
+
+bool initializeMods()
+{
+ XModifierKeymap* xmk = XGetModifierMapping( qt_xdisplay() );
+
+ g_rgModInfo[3].modX = g_modXNumLock = g_modXScrollLock = g_modXModeSwitch = 0;
+
+ int min_keycode, max_keycode;
+ int keysyms_per_keycode = 0;
+ XDisplayKeycodes( qt_xdisplay(), &min_keycode, &max_keycode );
+ XFree( XGetKeyboardMapping( qt_xdisplay(), min_keycode, 1, &keysyms_per_keycode ));
+ // Qt assumes that Alt is always Mod1Mask, so start at Mod2Mask.
+ for( int i = Mod2MapIndex; i < 8; i++ ) {
+ uint mask = (1 << i);
+ uint keySymX = NoSymbol;
+ // This used to be only XKeycodeToKeysym( ... , 0 ), but that fails with XFree4.3.99
+ // and X.org R6.7 , where for some reason only ( ... , 1 ) works. I have absolutely no
+ // idea what the problem is, but searching all posibilities until something valid is
+ // found fixes the problem.
+ for( int j = 0; j < xmk->max_keypermod && keySymX == NoSymbol; ++j )
+ for( int k = 0; k < keysyms_per_keycode && keySymX == NoSymbol; ++k )
+ keySymX = XKeycodeToKeysym( qt_xdisplay(), xmk->modifiermap[xmk->max_keypermod * i + j], k );
+ switch( keySymX ) {
+ case XK_Num_Lock: g_modXNumLock = mask; break; // Normally Mod2Mask
+ case XK_Super_L:
+ case XK_Super_R: g_rgModInfo[3].modX = mask; break; // Win key, Normally Mod4Mask
+ case XK_Meta_L:
+ case XK_Meta_R: if( !g_rgModInfo[3].modX ) g_rgModInfo[3].modX = mask; break; // Win alternate
+ case XK_Scroll_Lock: g_modXScrollLock = mask; break; // Normally Mod5Mask
+ case XK_Mode_switch: g_modXModeSwitch = mask; break;
+ }
+ }
+
+ XFreeModifiermap( xmk );
+
+ //KConfigGroupSaver cgs( KGlobal::config(), "Keyboard" );
+ // read in mod that win should be attached to
+
+ g_bInitializedMods = true;
+
+ kdDebug(125) << "KKeyServer::initializeMods(): Win Mod = 0x" << QString::number(g_rgModInfo[3].modX, 16) << endl;
+ return true;
+}
+
+static void initializeVariations()
+{
+ for( int i = 0; g_rgSymVariation[i].sym != 0; i++ )
+ g_rgSymVariation[i].bActive = (XKeysymToKeycode( qt_xdisplay(), g_rgSymVariation[i].symVariation ) != 0);
+ g_bInitializedVariations = true;
+}
+#endif //Q_WS_X11
+
+static void intializeKKeyLabels()
+{
+ KConfigGroupSaver cgs( KGlobal::config(), "Keyboard" );
+ g_rgModInfo[0].sLabel = KGlobal::config()->readEntry( "Label Shift", i18n(g_rgModInfo[0].psName) );
+ g_rgModInfo[1].sLabel = KGlobal::config()->readEntry( "Label Ctrl", i18n(g_rgModInfo[1].psName) );
+ g_rgModInfo[2].sLabel = KGlobal::config()->readEntry( "Label Alt", i18n(g_rgModInfo[2].psName) );
+ g_rgModInfo[3].sLabel = KGlobal::config()->readEntry( "Label Win", i18n(g_rgModInfo[3].psName) );
+ g_bMacLabels = (g_rgModInfo[2].sLabel == "Command");
+ g_bInitializedKKeyLabels = true;
+}
+
+//---------------------------------------------------------------------
+// class Mod
+//---------------------------------------------------------------------
+
+/*void Mod::init( const QString& s )
+{
+
+}*/
+
+//---------------------------------------------------------------------
+// class Sym
+//---------------------------------------------------------------------
+
+bool Sym::initQt( int keyQt )
+{
+ int symQt = keyQt & 0xffff;
+
+ if( (keyQt & Qt::UNICODE_ACCEL) || symQt < 0x1000 ) {
+ m_sym = QChar(symQt).lower().unicode();
+ return true;
+ }
+
+#ifdef Q_WS_WIN
+ m_sym = symQt;
+ return true;
+#elif defined(Q_WS_X11)
+ for( uint i = 0; i < sizeof(g_rgQtToSymX)/sizeof(TransKey); i++ ) {
+ if( g_rgQtToSymX[i].keySymQt == symQt ) {
+ m_sym = g_rgQtToSymX[i].keySymX;
+ return true;
+ }
+ }
+
+ m_sym = 0;
+ if( symQt != Qt::Key_Shift && symQt != Qt::Key_Control && symQt != Qt::Key_Alt &&
+ symQt != Qt::Key_Meta && symQt != Qt::Key_Direction_L && symQt != Qt::Key_Direction_R )
+ kdDebug(125) << "Sym::initQt( " << QString::number(keyQt,16) << " ): failed to convert key." << endl;
+ return false;
+#elif defined(Q_WS_MACX)
+ m_sym = symQt;
+ return true;
+#endif
+}
+
+bool Sym::init( const QString& s )
+{
+ // If it's a single character, get unicode value.
+ if( s.length() == 1 ) {
+ m_sym = s[0].lower().unicode();
+ return true;
+ }
+
+ // Look up in special names list
+ for( int i = 0; g_rgSymNames[i].sym != 0; i++ ) {
+ if( qstricmp( s.latin1(), g_rgSymNames[i].psName ) == 0 ) {
+ m_sym = g_rgSymNames[i].sym;
+ return true;
+ }
+ }
+
+#ifdef Q_WS_WIN
+ // search for name in KKeys array
+ for ( KKeys const *pKey = kde_KKEYS; pKey->code != 0xffff; pKey++) {
+ if( qstricmp( s.latin1(), pKey->name ) == 0 ) {
+ m_sym = pKey->code;
+ return true;
+ }
+ }
+ m_sym = 0;
+#elif defined(Q_WS_X11)
+ // search X list: 's' as is, all lower, first letter in caps
+ m_sym = XStringToKeysym( s.latin1() );
+ if( !m_sym ) {
+ m_sym = XStringToKeysym( s.lower().latin1() );
+ if( !m_sym ) {
+ QString s2 = s;
+ s2[0] = s2[0].upper();
+ m_sym = XStringToKeysym( s2.latin1() );
+ }
+ }
+#endif
+ return m_sym != 0;
+}
+
+int Sym::qt() const
+{
+ if( m_sym < 0x1000 ) {
+ if( m_sym >= 'a' && m_sym <= 'z' )
+ return QChar(m_sym).upper();
+ return m_sym;
+ }
+#ifdef Q_WS_WIN
+ if( m_sym < 0x3000 )
+ return m_sym;
+#elif defined(Q_WS_X11)
+ if( m_sym < 0x3000 )
+ return m_sym | Qt::UNICODE_ACCEL;
+
+ for( uint i = 0; i < sizeof(g_rgQtToSymX)/sizeof(TransKey); i++ )
+ if( g_rgQtToSymX[i].keySymX == m_sym )
+ return g_rgQtToSymX[i].keySymQt;
+#endif
+ return Qt::Key_unknown;
+}
+
+QString Sym::toString( bool bUserSpace ) const
+{
+ if( m_sym == 0 )
+ return QString::null;
+
+ // If it's a unicode character,
+#ifdef Q_WS_WIN
+ else if( m_sym < 0x1000 ) {
+#else
+ else if( m_sym < 0x3000 ) {
+#endif
+ QChar c = QChar(m_sym).upper();
+ // Print all non-space characters directly when output is user-visible.
+ // Otherwise only print alphanumeric latin1 characters directly (A,B,C,1,2,3).
+ if( (c.latin1() && c.isLetterOrNumber())
+ || (bUserSpace && !c.isSpace()) )
+ return c;
+ }
+
+ // Look up in special names list
+ for( int i = 0; g_rgSymNames[i].sym != 0; i++ ) {
+ if( m_sym == g_rgSymNames[i].sym )
+ return bUserSpace ? i18n(g_rgSymNames[i].psName) : QString(g_rgSymNames[i].psName);
+ }
+
+ QString s;
+#ifdef Q_WS_WIN
+ s = QKeySequence( m_sym );
+#elif defined(Q_WS_X11)
+ // Get X-name
+ s = XKeysymToString( m_sym );
+#endif
+ capitalizeKeyname( s );
+ return bUserSpace ? i18n("QAccel", s.latin1()) : s;
+}
+
+QString Sym::toStringInternal() const { return toString( false ); }
+QString Sym::toString() const { return toString( true ); }
+
+uint Sym::getModsRequired() const
+{
+ uint mod = 0;
+#ifdef Q_WS_X11
+ // FIXME: This might not be true on all keyboard layouts!
+ if( m_sym == XK_Sys_Req ) return KKey::ALT;
+ if( m_sym == XK_Break ) return KKey::CTRL;
+
+ if( m_sym < 0x3000 ) {
+ QChar c(m_sym);
+ if( c.isLetter() && c.lower() != c.upper() && m_sym == c.upper().unicode() )
+ return KKey::SHIFT;
+ }
+
+ uchar code = XKeysymToKeycode( qt_xdisplay(), m_sym );
+ if( code ) {
+ // need to check index 0 before the others, so that a null-mod
+ // can take precedence over the others, in case the modified
+ // key produces the same symbol.
+ if( m_sym == XKeycodeToKeysym( qt_xdisplay(), code, 0 ) )
+ ;
+ else if( m_sym == XKeycodeToKeysym( qt_xdisplay(), code, 1 ) )
+ mod = KKey::SHIFT;
+ else if( m_sym == XKeycodeToKeysym( qt_xdisplay(), code, 2 ) )
+ mod = KKeyServer::MODE_SWITCH;
+ else if( m_sym == XKeycodeToKeysym( qt_xdisplay(), code, 3 ) )
+ mod = KKey::SHIFT | KKeyServer::MODE_SWITCH;
+ }
+#endif
+ return mod;
+}
+
+uint Sym::getSymVariation() const
+{
+#ifdef Q_WS_X11
+ if( !g_bInitializedVariations )
+ initializeVariations();
+ for( int i = 0; g_rgSymVariation[i].sym != 0; i++ )
+ if( g_rgSymVariation[i].sym == m_sym && g_rgSymVariation[i].bActive )
+ return g_rgSymVariation[i].symVariation;
+#endif
+ return 0;
+}
+
+void Sym::capitalizeKeyname( QString& s )
+{
+ s[0] = s[0].upper();
+ int len = s.length();
+ if( s.endsWith( "left" ) ) s[len-4] = 'L';
+ else if( s.endsWith( "right" ) ) s[len-5] = 'R';
+ else if( s == "Sysreq" ) s[len-3] = 'R';
+}
+
+//---------------------------------------------------------------------
+// Public functions
+//---------------------------------------------------------------------
+
+#ifdef Q_WS_X11
+uint modX( KKey::ModFlag mod )
+{
+ if( mod == KKey::WIN && !g_bInitializedMods )
+ initializeMods();
+
+ for( uint i = 0; i < KKey::MOD_FLAG_COUNT; i++ ) {
+ if( g_rgModInfo[i].mod == mod )
+ return g_rgModInfo[i].modX;
+ }
+ return 0;
+}
+
+bool keyboardHasWinKey() { if( !g_bInitializedMods ) { initializeMods(); } return g_rgModInfo[3].modX != 0; }
+uint modXShift() { return ShiftMask; }
+uint modXLock() { return LockMask; }
+uint modXCtrl() { return ControlMask; }
+uint modXAlt() { return Mod1Mask; }
+uint modXNumLock() { if( !g_bInitializedMods ) { initializeMods(); } return g_modXNumLock; }
+uint modXWin() { if( !g_bInitializedMods ) { initializeMods(); } return g_rgModInfo[3].modX; }
+uint modXScrollLock() { if( !g_bInitializedMods ) { initializeMods(); } return g_modXScrollLock; }
+uint modXModeSwitch() { if( !g_bInitializedMods ) { initializeMods(); } return g_modXModeSwitch; }
+
+uint accelModMaskX()
+{
+ if( !g_bInitializedMods )
+ initializeMods();
+ return ShiftMask | ControlMask | Mod1Mask | g_rgModInfo[3].modX;
+}
+#endif //Q_WS_X11
+
+bool keyQtToSym( int keyQt, uint& keySym )
+{
+ Sym sym;
+ if( sym.initQt( keyQt ) ) {
+ keySym = sym.m_sym;
+ return true;
+ } else
+ return false;
+}
+
+bool keyQtToMod( int keyQt, uint& mod )
+{
+ mod = 0;
+
+ if( keyQt & Qt::SHIFT ) mod |= KKey::SHIFT;
+ if( keyQt & Qt::CTRL ) mod |= KKey::CTRL;
+ if( keyQt & Qt::ALT ) mod |= KKey::ALT;
+ if( keyQt & Qt::META ) mod |= KKey::WIN;
+
+ return true;
+}
+
+bool symToKeyQt( uint keySym, int& keyQt )
+{
+ Sym sym( keySym );
+ keyQt = sym.qt();
+ return (keyQt != Qt::Key_unknown);
+}
+
+bool modToModQt( uint mod, int& modQt )
+{
+ modQt = 0;
+ for( int i = 0; i < KKey::MOD_FLAG_COUNT; i++ ) {
+ if( mod & g_rgModInfo[i].mod ) {
+ if( !g_rgModInfo[i].modQt ) {
+ modQt = 0;
+ return false;
+ }
+ modQt |= g_rgModInfo[i].modQt;
+ }
+ }
+ return true;
+}
+
+#ifdef Q_WS_WIN
+//wrapped
+bool modXToModQt( uint modX, int& modQt )
+{
+ return modToModQt( modX, modQt );
+}
+
+KDECORE_EXPORT int qtButtonStateToMod( Qt::ButtonState s )
+{
+ int modQt = 0;
+ if (s & Qt::ShiftButton) modQt |= KKey::SHIFT;
+ if (s & Qt::ControlButton) modQt |= KKey::CTRL;
+ if (s & Qt::AltButton) modQt |= KKey::ALT;
+ return modQt;
+}
+
+bool keyboardHasWinKey() {
+//! TODO
+ return true;
+}
+
+#elif defined(Q_WS_MACX)
+
+bool modXToModQt(uint modX, int& modQt)
+{
+ return modToModQt( modX, modQt );
+}
+
+bool keyboardHasWinKey() {
+//! TODO - A win key on the Mac...?
+ return false;
+}
+
+bool modXToMod( uint , uint& )
+{
+ return false;
+}
+#elif defined(Q_WS_X11)
+
+bool modToModX( uint mod, uint& modX )
+{
+ if( !g_bInitializedMods )
+ initializeMods();
+
+ modX = 0;
+ for( int i = 0; i < KKey::MOD_FLAG_COUNT; i++ ) {
+ if( mod & g_rgModInfo[i].mod ) {
+ if( !g_rgModInfo[i].modX ) {
+ kdDebug(125) << "Invalid modifier flag." << endl;
+ modX = 0;
+ return false;
+ }
+ modX |= g_rgModInfo[i].modX;
+ }
+ }
+ // TODO: document 0x2000 flag
+ if( mod & 0x2000 )
+ modX |= 0x2000;
+ return true;
+}
+
+bool modXToModQt( uint modX, int& modQt )
+{
+ if( !g_bInitializedMods )
+ initializeMods();
+
+ modQt = 0;
+ for( int i = 0; i < KKey::MOD_FLAG_COUNT; i++ ) {
+ if( modX & g_rgModInfo[i].modX ) {
+ if( !g_rgModInfo[i].modQt ) {
+ modQt = 0;
+ return false;
+ }
+ modQt |= g_rgModInfo[i].modQt;
+ }
+ }
+ return true;
+}
+
+bool modXToMod( uint modX, uint& mod )
+{
+ if( !g_bInitializedMods )
+ initializeMods();
+
+ mod = 0;
+ for( int i = 0; i < KKey::MOD_FLAG_COUNT; i++ ) {
+ if( modX & g_rgModInfo[i].modX )
+ mod |= g_rgModInfo[i].mod;
+ }
+ return true;
+}
+
+bool codeXToSym( uchar codeX, uint modX, uint& sym )
+{
+ KeySym keySym;
+ XKeyPressedEvent event;
+
+ event.type = KeyPress;
+ event.display = qt_xdisplay();
+ event.state = modX;
+ event.keycode = codeX;
+
+ XLookupString( &event, 0, 0, &keySym, 0 );
+ sym = (uint) keySym;
+ return true;
+}
+#endif //!Q_WS_WIN
+
+static QString modToString( uint mod, bool bUserSpace )
+{
+ if( bUserSpace && !g_bInitializedKKeyLabels )
+ intializeKKeyLabels();
+
+ QString s;
+ for( int i = KKey::MOD_FLAG_COUNT-1; i >= 0; i-- ) {
+ if( mod & g_rgModInfo[i].mod ) {
+ if( !s.isEmpty() )
+ s += '+';
+ s += (bUserSpace)
+ ? g_rgModInfo[i].sLabel
+ : QString(g_rgModInfo[i].psName);
+ }
+ }
+ return s;
+}
+
+QString modToStringInternal( uint mod ) { return modToString( mod, false ); }
+QString modToStringUser( uint mod ) { return modToString( mod, true ); }
+
+uint stringUserToMod( const QString& mod )
+{
+ if( !g_bInitializedKKeyLabels )
+ intializeKKeyLabels();
+
+ QString s;
+ for( int i = KKey::MOD_FLAG_COUNT-1; i >= 0; i-- ) {
+ if( mod.lower() == g_rgModInfo[i].sLabel.lower())
+ return g_rgModInfo[i].mod;
+ }
+ return 0;
+}
+
+/*void keySymModToKeyX( uint sym, uint mod, unsigned char *pKeyCodeX, uint *pKeySymX, uint *pKeyModX )
+{
+...
+ uint keySymQt;
+ uint keySymX = 0;
+ unsigned char keyCodeX = 0;
+ uint keyModX = 0;
+
+ const char *psKeySym = 0;
+
+ if( !g_bInitialized )
+ Initialize();
+
+ // Get code of just the primary key
+ keySymQt = keyCombQt & 0xffff;
+
+ // If unicode value beneath 0x1000 (special Qt codes begin thereafter),
+ if( keySymQt < 0x1000 ) {
+ // For reasons unbeknownst to me, Qt converts 'a-z' to 'A-Z'.
+ // So convert it back to lowercase if SHIFT isn't held down.
+ if( keySymQt >= Qt::Key_A && keySymQt <= Qt::Key_Z && !(keyCombQt & Qt::SHIFT) )
+ keySymQt = tolower( keySymQt );
+ keySymX = keySymQt;
+ }
+ // Else, special key (e.g. Delete, F1, etc.)
+ else {
+ for( int i = 0; i < NB_KEYS; i++ ) {
+ if( keySymQt == (uint) KKEYS[i].code ) {
+ psKeySym = KKEYS[i].name;
+ //kdDebug(125) << " symbol found: \"" << psKeySym << "\"" << endl;
+ break;
+ }
+ }
+
+ // Get X key symbol. Only works if Qt name is same as X name.
+ if( psKeySym ) {
+ QString sKeySym = psKeySym;
+
+ // Check for lower-case equalent first because most
+ // X11 names are all lower-case.
+ keySymX = XStringToKeysym( sKeySym.lower().ascii() );
+ if( keySymX == 0 )
+ keySymX = XStringToKeysym( psKeySym );
+ }
+
+ if( keySymX == 0 )
+ keySymX = getSymXEquiv( keySymQt );
+ }
+
+ if( keySymX != 0 ) {
+ // Get X keyboard code
+ keyCodeX = XKeysymToKeycode( qt_xdisplay(), keySymX );
+ // Add ModeSwitch modifier bit, if necessary
+ keySymXMods( keySymX, 0, &keyModX );
+
+ // Get X modifier flags
+ for( int i = 0; i < MOD_KEYS; i++ ) {
+ if( keyCombQt & g_aModKeys[i].keyModMaskQt ) {
+ if( g_aModKeys[i].keyModMaskX )
+ keyModX |= g_aModKeys[i].keyModMaskX;
+ // Qt key calls for a modifier which the current
+ // X modifier map doesn't support.
+ else {
+ keySymX = 0;
+ keyCodeX = 0;
+ keyModX = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ // Take care of complications:
+ // The following keys will not have been correctly interpreted,
+ // because their shifted values are not activated with the
+ // Shift key, but rather something else. They are also
+ // defined twice under different keycodes.
+ // keycode 111 & 92: Print Sys_Req -> Sys_Req = Alt+Print
+ // keycode 110 & 114: Pause Break -> Break = Ctrl+Pause
+ if( (keyCodeX == 92 || keyCodeX == 111) &&
+ XKeycodeToKeysym( qt_xdisplay(), 92, 0 ) == XK_Print &&
+ XKeycodeToKeysym( qt_xdisplay(), 111, 0 ) == XK_Print )
+ {
+ // If Alt is pressed, then we need keycode 92, keysym XK_Sys_Req
+ if( keyModX & keyModXAlt() ) {
+ keyCodeX = 92;
+ keySymX = XK_Sys_Req;
+ }
+ // Otherwise, keycode 111, keysym XK_Print
+ else {
+ keyCodeX = 111;
+ keySymX = XK_Print;
+ }
+ }
+ else if( (keyCodeX == 110 || keyCodeX == 114) &&
+ XKeycodeToKeysym( qt_xdisplay(), 110, 0 ) == XK_Pause &&
+ XKeycodeToKeysym( qt_xdisplay(), 114, 0 ) == XK_Pause )
+ {
+ if( keyModX & keyModXCtrl() ) {
+ keyCodeX = 114;
+ keySymX = XK_Break;
+ } else {
+ keyCodeX = 110;
+ keySymX = XK_Pause;
+ }
+ }
+
+ if( pKeySymX ) *pKeySymX = keySymX;
+ if( pKeyCodeX ) *pKeyCodeX = keyCodeX;
+ if( pKeyModX ) *pKeyModX = keyModX;
+}*/
+
+//---------------------------------------------------------------------
+// Key
+//---------------------------------------------------------------------
+
+bool Key::init( const KKey& key, bool bQt )
+{
+ if( bQt ) {
+ m_code = CODE_FOR_QT;
+ m_sym = key.keyCodeQt();
+ } else {
+ KKeyNative keyNative( key );
+ *this = keyNative;
+ }
+ return true;
+}
+
+KKey Key::key() const
+{
+ if( m_code == CODE_FOR_QT )
+ return KKey( keyCodeQt() );
+ else {
+#if defined(Q_WS_WIN) || defined(Q_WS_MACX)
+ return KKey();
+#else
+ uint mod;
+ modXToMod( m_mod, mod );
+ return KKey( m_sym, mod );
+#endif
+ }
+}
+
+Key& Key::operator =( const KKeyNative& key )
+{
+ m_code = key.code(); m_mod = key.mod(); m_sym = key.sym();
+ return *this;
+}
+
+int Key::compare( const Key& b ) const
+{
+ if( m_code == CODE_FOR_QT )
+ return m_sym - b.m_sym;
+ if( m_sym != b.m_sym ) return m_sym - b.m_sym;
+ if( m_mod != b.m_mod ) return m_mod - b.m_mod;
+ return m_code - b.m_code;
+}
+
+//---------------------------------------------------------------------
+// Variations
+//---------------------------------------------------------------------
+
+// TODO: allow for sym to have variations, such as Plus => { Plus, KP_Add }
+void Variations::init( const KKey& key, bool bQt )
+{
+ if( key.isNull() ) {
+ m_nVariations = 0;
+ return;
+ }
+
+ m_nVariations = 1;
+ m_rgkey[0] = KKeyNative(key);
+ uint symVar = Sym(key.sym()).getSymVariation();
+ if( symVar ) {
+ uint modReq = Sym(m_rgkey[0].sym()).getModsRequired();
+ uint modReqVar = Sym(symVar).getModsRequired();
+ // If 'key' doesn't require any mods that are inherent in
+ // the primary key but not required for the alternate,
+ if( (key.modFlags() & modReq) == (key.modFlags() & modReqVar) ) {
+ m_rgkey[1] = KKeyNative(KKey(symVar, key.modFlags()));
+ m_nVariations = 2;
+ }
+ }
+
+ if( bQt ) {
+ uint nVariations = 0;
+ for( uint i = 0; i < m_nVariations; i++ ) {
+ int keyQt = KKeyNative( m_rgkey[i].code(), m_rgkey[i].mod(), m_rgkey[i].sym() ).keyCodeQt();
+ if( keyQt )
+ m_rgkey[nVariations++].setKeycodeQt( keyQt );
+ }
+ m_nVariations = nVariations;
+
+ // Two different native codes may produce a single
+ // Qt code. Search for duplicates.
+ for( uint i = 1; i < m_nVariations; i++ ) {
+ for( uint j = 0; j < i; j++ ) {
+ // If key is already present in list, then remove it.
+ if( m_rgkey[i].keyCodeQt() == m_rgkey[j].keyCodeQt() ) {
+ for( uint k = i; k < m_nVariations - 1; k++ )
+ m_rgkey[k].setKeycodeQt( m_rgkey[k+1].keyCodeQt() );
+ m_nVariations--;
+ i--;
+ break;
+ }
+ }
+ }
+ }
+}
+
+} // end of namespace KKeyServer block
+
+// FIXME: This needs to be moved to kshortcut.cpp, and create a
+// KKeyServer::method which it will call.
+// Alt+SysReq => Alt+Print
+// Ctrl+Shift+Plus => Ctrl+Plus (en)
+// Ctrl+Shift+Equal => Ctrl+Plus
+// Ctrl+Pause => Ctrl+Break
+void KKey::simplify()
+{
+#ifdef Q_WS_X11
+ if( m_sym == XK_Sys_Req ) {
+ m_sym = XK_Print;
+ m_mod |= ALT;
+ } else if( m_sym == XK_ISO_Left_Tab ) {
+ m_sym = XK_Tab;
+ m_mod |= SHIFT;
+ } else {
+ // Shift+Equal => Shift+Plus (en)
+ m_sym = KKeyNative(*this).sym();
+ }
+
+ // If this is a letter, don't remove any modifiers.
+ if( m_sym < 0x3000 && QChar(m_sym).isLetter() )
+ m_sym = QChar(m_sym).lower().unicode();
+
+ // Remove modifers from modifier list which are implicit in the symbol.
+ // Ex. Shift+Plus => Plus (en)
+ m_mod &= ~KKeyServer::Sym(m_sym).getModsRequired();
+#endif
+}
+
+#endif //Q_WS_X11 || Q_WS_WIN
+
diff --git a/kdecore/kkeyserver_x11.h b/kdecore/kkeyserver_x11.h
new file mode 100644
index 000000000..73c800db2
--- /dev/null
+++ b/kdecore/kkeyserver_x11.h
@@ -0,0 +1,477 @@
+/*
+ Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
+
+ Win32 port:
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KKEYSERVER_X11_H
+#define _KKEYSERVER_X11_H
+
+#include "kshortcut.h"
+#include "kkeynative.h"
+
+/**
+ * A collection of functions for the conversion of key presses and
+ * their modifiers from the window system specific format
+ * to the generic format and vice-versa.
+ */
+namespace KKeyServer
+{
+ /**
+ * Supplement enum KKey::ModFlag
+ * @since 3.1
+ */
+ enum ExtraModFlag { MODE_SWITCH = 0x2000 };
+
+ /**
+ * Represents a key symbol.
+ * @see KKey
+ * @see KKeyServer
+ */
+ struct KDECORE_EXPORT Sym
+ {
+ public:
+ /// the actual value of the symbol
+ uint m_sym;
+
+ /// Creates a null symbol.
+ Sym()
+ { m_sym = 0; }
+ /**
+ * Creates asymbol with the given value.
+ * @param sym the value
+ */
+ Sym( uint sym )
+ { m_sym = sym; }
+ /**
+ * Creates a symbol from the given string description.
+ * @param s the description of the symbol
+ * @see toString()
+ */
+ Sym( const QString& s )
+ { init( s ); }
+
+ /**
+ * Initializes the symbol with the given Qt key code.
+ * @param keyQt the qt key code
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ */
+ bool initQt( int keyQt );
+
+ /**
+ * Initializes the key with the given string description.
+ * @param s the string description
+ * @return true if successful, false otherwise
+ * @see toString()
+ */
+ bool init( const QString &s );
+
+ /**
+ * Returns the qt key code of the symbol.
+ * @return the qt key code
+ */
+ int qt() const;
+
+ /**
+ * @internal
+ */
+ QString toStringInternal() const;
+
+ /**
+ * Returns the string representation of the symbol.
+ * @return the string representation of the symbol
+ */
+ QString toString() const;
+
+ /**
+ * Returns the mods that are required for this symbol as
+ * ORed KKey::ModFlag's. For example, Break requires a
+ * Ctrl to be valid.
+ * @return the required KKey::ModFlag's
+ * @see KKey::ModFlag
+ */
+ uint getModsRequired() const;
+
+ /**
+ * TODO: please find out what this method does and document it
+ */
+ uint getSymVariation() const;
+
+ /**
+ * Casts the symbol to its integer representation.
+ */
+ operator uint() const { return m_sym; }
+
+ /**
+ * Overloaded operator to convert ints to Sym.
+ */
+ Sym& operator =( uint sym ) { m_sym = sym; return *this; }
+
+ private:
+ QString toString( bool bUserSpace ) const;
+
+ static void capitalizeKeyname( QString& );
+ };
+
+ /**
+ * Represents a key press.
+ * @see KKey
+ */
+ struct KDECORE_EXPORT Key
+ {
+ /// Code for native Keys in Qt
+ enum { CODE_FOR_QT = 256 };
+
+ /// The code of the key
+ uint m_code;
+
+ /// The modifiers of the key
+ uint m_mod;
+
+ /// The symbol of the key
+ uint m_sym;
+
+ /**
+ * Initializes the key with a KKey.
+ * @param key the key to get the data from
+ * @param bQt true to take the Qt keycode, false
+ * for the native key code
+ * @see Qt::Key
+ * @see KKeyNative
+ */
+ bool init( const KKey& key, bool bQt );
+
+ /**
+ * Checks whether the key code is a native code.
+ * @return true if native code of the window system,
+ * false if it is a Qt keycode
+ * @see Qt::Key
+ * @see KKeyNative
+ */
+ bool isNative() const { return m_code != CODE_FOR_QT; }
+
+ /**
+ * Returns the code of the key.
+ * @return the code of the key
+ */
+ uint code() const { return m_code; }
+
+ /**
+ * Returns the modifiers of the key.
+ * @return the modifiers of the key
+ */
+ uint mod() const { return m_mod; }
+
+ /**
+ * Returns the symbol of the key.
+ * @return the symbol of the key
+ */
+ uint sym() const { return m_sym; }
+
+ /**
+ * Returns the qt key code.
+ * @return the qt key code
+ */
+ int keyCodeQt() const { return (int) m_sym; }
+
+ /**
+ * Sets the qt key code.
+ * @param keyQt the qt key code
+ */
+ void setKeycodeQt( int keyQt )
+ { m_code = CODE_FOR_QT; m_sym = keyQt; }
+
+ /**
+ * Initializes this key with a KKeyNative.
+ * @return this key
+ */
+ Key& operator =( const KKeyNative& key );
+
+ /**
+ * Compares this key with the given Key object. Returns a
+ * negative number if the given Key is larger, 0 if they
+ * are equal and a positive number this Key is larger. The
+ * returned value is the difference between the symbol, modifier
+ * or code, whatever is non-zero first.
+ *
+ * @param key the key to compare with this key
+ * @return a negative number if the given Key is larger, 0 if
+ * they are equal and a positive number this Key is larger
+ */
+ int compare( const Key& key ) const;
+
+ /**
+ * Compares the symbol, modifiers and code of both keys.
+ * @see compare()
+ */
+ bool operator ==( const Key& b ) const
+ { return compare( b ) == 0; }
+
+ /**
+ * Compares the symbol, modifiers and code of both keys.
+ * @see compare()
+ */
+ bool operator <( const Key& b ) const
+ { return compare( b ) < 0; }
+
+ /**
+ * Converts this Key to a KKey.
+ * @return the KKey
+ */
+ KKey key() const;
+ };
+
+ /**
+ * TODO: please document this class
+ */
+ struct KDECORE_EXPORT Variations
+ {
+ enum { MAX_VARIATIONS = 4 };
+
+ Key m_rgkey[MAX_VARIATIONS];
+ uint m_nVariations;
+
+ Variations() { m_nVariations = 0; }
+
+ void init( const KKey&, bool bQt );
+
+ uint count() const { return m_nVariations; }
+ const Key& key( uint i ) const { return m_rgkey[i]; }
+ };
+
+ /// TODO: please document
+ KDECORE_EXPORT bool initializeMods();
+
+ /**
+ * Returns the equivalent X modifier mask of the given modifier flag.
+ * @param modFlag the generic flags to check
+ * @return the window system specific flags
+ */
+ KDECORE_EXPORT uint modX( KKey::ModFlag modFlag );
+
+ /**
+ * Returns true if the current keyboard layout supports the Win key.
+ * Specifically, whether the Super or Meta keys are assigned to an X modifier.
+ * @return true if the keyboard has a Win key
+ * @see modXWin()
+ */
+ KDECORE_EXPORT bool keyboardHasWinKey();
+
+ /**
+ * Returns the X11 Shift modifier mask/flag.
+ * @return the X11 Shift modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ KDECORE_EXPORT uint modXShift();
+
+ /**
+ * Returns the X11 Lock modifier mask/flag.
+ * @return the X11 Lock modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ KDECORE_EXPORT uint modXLock();
+
+ /**
+ * Returns the X11 Ctrl modifier mask/flag.
+ * @return the X11 Ctrl modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ KDECORE_EXPORT uint modXCtrl();
+
+ /**
+ * Returns the X11 Alt (Mod1) modifier mask/flag.
+ * @return the X11 Alt (Mod1) modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ KDECORE_EXPORT uint modXAlt();
+
+ /**
+ * Returns the X11 NumLock modifier mask/flag.
+ * @return the X11 NumLock modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ KDECORE_EXPORT uint modXNumLock();
+
+ /**
+ * Returns the X11 Win (Mod3) modifier mask/flag.
+ * @return the X11 Win (Mod3) modifier mask/flag.
+ * @see keyboardHasWinKey()
+ * @see accelModMaskX()
+ */
+ KDECORE_EXPORT uint modXWin();
+
+ /**
+ * Returns the X11 ScrollLock modifier mask/flag.
+ * @return the X11 ScrollLock modifier mask/flag.
+ * @see accelModMaskX()
+ */
+ KDECORE_EXPORT uint modXScrollLock();
+
+ /**
+ * Returns the X11 Mode_switch modifier mask/flag.
+ * @return the X11 Mode_switch modifier mask/flag.
+ * @see accelModMaskX()
+ * @since 3.5
+ */
+ KDECORE_EXPORT uint modXModeSwitch();
+
+ /**
+ * Returns bitwise OR'ed mask containing Shift, Ctrl, Alt, and
+ * Win (if available).
+ * @see modXShift()
+ * @see modXLock()
+ * @see modXCtrl()
+ * @see modXAlt()
+ * @see modXNumLock()
+ * @see modXWin()
+ * @see modXScrollLock()
+ */
+ KDECORE_EXPORT uint accelModMaskX();
+
+ /**
+ * Extracts the symbol from the given Qt key and
+ * converts it to a symbol.
+ * @param keyQt the qt key code
+ * @param sym if successful, the symbol will be written here
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ * @see Sym
+ */
+ KDECORE_EXPORT bool keyQtToSym( int keyQt, uint& sym );
+
+ /**
+ * Extracts the modifiers from the given Qt key and
+ * converts them in a mask of ORed KKey::ModFlag modifiers.
+ * @param keyQt the qt key code
+ * @param mod if successful, the modifiers will be written here
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ */
+ KDECORE_EXPORT bool keyQtToMod( int keyQt, uint& mod );
+
+ /**
+ * Converts the given symbol to a Qt key code.
+ * @param sym the symbol
+ * @param keyQt if successful, the qt key code will be written here
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ * @see Sym
+ */
+ KDECORE_EXPORT bool symToKeyQt( uint sym, int& keyQt );
+
+ /**
+ * Converts the mask of ORed KKey::ModFlag modifiers to
+ * a mask of ORed Qt key code modifiers.
+ * @param mod the mask of KKey::ModFlag modifiers
+ * @param modQt the mask of Qt key code modifiers will be written here,
+ * if successful
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ * @see KKey
+ */
+ KDECORE_EXPORT bool modToModQt( uint mod, int& modQt );
+
+ /**
+ * Converts the mask of ORed KKey::ModFlag modifiers to
+ * a mask of ORed X11 modifiers.
+ * @param mod the mask of KKey::ModFlag modifiers
+ * @param modX the mask of X11 modifiers will be written here,
+ * if successful
+ * @return true if successful, false otherwise
+ * @see KKey
+ */
+ KDECORE_EXPORT bool modToModX( uint mod, uint& modX );
+
+ /**
+ * Converts the mask of ORed X11 modifiers to
+ * a mask of ORed Qt key code modifiers.
+ * @param modX the mask of X11 modifiers
+ * @param modQt the mask of Qt key code modifiers will be written here
+ * if successful
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ */
+ //wrapped for win32
+ KDECORE_EXPORT bool modXToModQt( uint modX, int& modQt );
+
+ /**
+ * Converts the Qt-compatible button state to x11 modifier.
+ */
+ KDECORE_EXPORT int qtButtonStateToMod( Qt::ButtonState s );
+
+ /**
+ * Converts the mask of ORed X11 modifiers to
+ * a mask of ORed KKey::ModFlag modifiers.
+ * @param modX the mask of X11 modifiers
+ * @param mod the mask of KKey::ModFlag modifiers will be written here,
+ * if successful
+ * @return true if successful, false otherwise
+ * @see KKey
+ */
+ KDECORE_EXPORT bool modXToMod( uint modX, uint& mod );
+
+ /**
+ * Converts a X11 key code and a mask of ORed X11 modifiers
+ * into a X11 symbol.
+ * converts it to a symbol.
+ * @param codeX the X11 key code
+ * @param modX the mask of ORed X11 modifiers
+ * @param symX if successful, the X11 symbol will be written here
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ * @see Sym
+ */
+ KDECORE_EXPORT bool codeXToSym( uchar codeX, uint modX, uint& symX );
+
+ /**
+ * @internal
+ */
+ KDECORE_EXPORT QString modToStringInternal( uint mod );
+
+ /**
+ * Converts the mask of ORed KKey::ModFlag modifiers to a
+ * user-readable string.
+ * @param mod the mask of ORed KKey::ModFlag modifiers
+ * @return the user-readable string
+ */
+ KDECORE_EXPORT QString modToStringUser( uint mod );
+
+ /**
+ * Converts the modifier given as user-readable string
+ * to KKey::ModFlag modifier, or 0.
+ * @internal
+ * @since 3.5
+ */
+ KDECORE_EXPORT uint stringUserToMod( const QString& mod );
+
+ /**
+ * @internal
+ * Unimplemented?
+ */
+ KDECORE_EXPORT bool stringToSymMod( const QString&, uint& sym, uint& mod );
+
+ /**
+ * @internal
+ * Unimplemented?
+ */
+ KDECORE_EXPORT void keyQtToKeyX( uint keyCombQt, unsigned char *pKeyCodeX, uint *pKeySymX, uint *pKeyModX );
+}
+
+#endif // !_KKEYSERVER_X11_H
diff --git a/kdecore/klargefile.h b/kdecore/klargefile.h
new file mode 100644
index 000000000..2eb6bfa22
--- /dev/null
+++ b/kdecore/klargefile.h
@@ -0,0 +1,27 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KDE_LARGEFILE_H_
+#define _KDE_LARGEFILE_H_
+
+/* TODO: remove this file in KDE4 */
+
+#include <kde_file.h>
+
+#endif
diff --git a/kdecore/klibloader.cpp b/kdecore/klibloader.cpp
new file mode 100644
index 000000000..e994d7274
--- /dev/null
+++ b/kdecore/klibloader.cpp
@@ -0,0 +1,580 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000 Michael Matz <matz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "config.h"
+
+#include <config.h>
+#include <qclipboard.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qtimer.h>
+#include <qobjectdict.h>
+
+#include "kapplication.h"
+#include "klibloader.h"
+#include "kstandarddirs.h"
+#include "kdebug.h"
+#include "klocale.h"
+
+#include "ltdl.h"
+
+template class QAsciiDict<KLibrary>;
+
+#include <stdlib.h> //getenv
+
+
+#if HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+#ifdef RTLD_GLOBAL
+# define LT_GLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_GLOBAL DL_GLOBAL
+# endif
+#endif /* !RTLD_GLOBAL */
+#ifndef LT_GLOBAL
+# define LT_GLOBAL 0
+#endif /* !LT_GLOBAL */
+
+
+class KLibLoaderPrivate
+{
+public:
+ QPtrList<KLibWrapPrivate> loaded_stack;
+ QPtrList<KLibWrapPrivate> pending_close;
+ enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
+
+ QString errorMessage;
+};
+
+KLibLoader* KLibLoader::s_self = 0;
+
+// -------------------------------------------------------------------------
+
+KLibFactory::KLibFactory( QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+}
+
+KLibFactory::~KLibFactory()
+{
+// kdDebug(150) << "Deleting KLibFactory " << this << endl;
+}
+
+QObject* KLibFactory::create( QObject* parent, const char* name, const char* classname, const QStringList &args )
+{
+ QObject* obj = createObject( parent, name, classname, args );
+ if ( obj )
+ emit objectCreated( obj );
+ return obj;
+}
+
+
+QObject* KLibFactory::createObject( QObject*, const char*, const char*, const QStringList &)
+{
+ return 0;
+}
+
+
+// -----------------------------------------------
+
+KLibrary::KLibrary( const QString& libname, const QString& filename, void * handle )
+{
+ /* Make sure, we have a KLibLoader */
+ (void) KLibLoader::self();
+ m_libname = libname;
+ m_filename = filename;
+ m_handle = handle;
+ m_factory = 0;
+ m_timer = 0;
+}
+
+KLibrary::~KLibrary()
+{
+// kdDebug(150) << "Deleting KLibrary " << this << " " << m_libname << endl;
+ if ( m_timer && m_timer->isActive() )
+ m_timer->stop();
+
+ // If any object is remaining, delete
+ if ( m_objs.count() > 0 )
+ {
+ QPtrListIterator<QObject> it( m_objs );
+ for ( ; it.current() ; ++it )
+ {
+ kdDebug(150) << "Factory still has object " << it.current() << " " << it.current()->name () << " Library = " << m_libname << endl;
+ disconnect( it.current(), SIGNAL( destroyed() ),
+ this, SLOT( slotObjectDestroyed() ) );
+ }
+ m_objs.setAutoDelete(true);
+ m_objs.clear();
+ }
+
+ if ( m_factory ) {
+// kdDebug(150) << " ... deleting the factory " << m_factory << endl;
+ delete m_factory;
+ m_factory = 0L;
+ }
+}
+
+QString KLibrary::name() const
+{
+ return m_libname;
+}
+
+QString KLibrary::fileName() const
+{
+ return m_filename;
+}
+
+KLibFactory* KLibrary::factory()
+{
+ if ( m_factory )
+ return m_factory;
+
+ QCString symname;
+ symname.sprintf("init_%s", name().latin1() );
+
+ void* sym = symbol( symname );
+ if ( !sym )
+ {
+ KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer an %2 function." ).arg( name(), "init_" + name() );
+ kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
+ return 0;
+ }
+
+ typedef KLibFactory* (*t_func)();
+ t_func func = (t_func)sym;
+ m_factory = func();
+
+ if( !m_factory )
+ {
+ KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer a KDE compatible factory." ).arg( name() );
+ kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
+ return 0;
+ }
+
+ connect( m_factory, SIGNAL( objectCreated( QObject * ) ),
+ this, SLOT( slotObjectCreated( QObject * ) ) );
+
+ return m_factory;
+}
+
+void* KLibrary::symbol( const char* symname ) const
+{
+ void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
+ if ( !sym )
+ {
+ KLibLoader::self()->d->errorMessage = "KLibrary: " + QString::fromLocal8Bit( lt_dlerror() );
+ kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
+ return 0;
+ }
+
+ return sym;
+}
+
+bool KLibrary::hasSymbol( const char* symname ) const
+{
+ void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
+ return (sym != 0L );
+}
+
+void KLibrary::unload() const
+{
+ if (KLibLoader::s_self)
+ KLibLoader::s_self->unloadLibrary(QFile::encodeName(name()));
+}
+
+void KLibrary::slotObjectCreated( QObject *obj )
+{
+ if ( !obj )
+ return;
+
+ if ( m_timer && m_timer->isActive() )
+ m_timer->stop();
+
+ if ( m_objs.containsRef( obj ) )
+ return; // we know this object already
+
+ connect( obj, SIGNAL( destroyed() ),
+ this, SLOT( slotObjectDestroyed() ) );
+
+ m_objs.append( obj );
+}
+
+void KLibrary::slotObjectDestroyed()
+{
+ m_objs.removeRef( sender() );
+
+ if ( m_objs.count() == 0 )
+ {
+// kdDebug(150) << "KLibrary: shutdown timer for " << name() << " started!"
+// << endl;
+
+ if ( !m_timer )
+ {
+ m_timer = new QTimer( this, "klibrary_shutdown_timer" );
+ connect( m_timer, SIGNAL( timeout() ),
+ this, SLOT( slotTimeout() ) );
+ }
+
+ // as long as it's not stable make the timeout short, for debugging
+ // pleasure (matz)
+ //m_timer->start( 1000*60, true );
+ m_timer->start( 1000*10, true );
+ }
+}
+
+void KLibrary::slotTimeout()
+{
+ if ( m_objs.count() != 0 )
+ return;
+
+ /* Don't go through KLibLoader::unloadLibrary(), because that uses the
+ ref counter, but this timeout means to unconditionally close this library
+ The destroyed() signal will take care to remove us from all lists.
+ */
+ delete this;
+}
+
+// -------------------------------------------------
+
+/* This helper class is needed, because KLibraries can go away without
+ being unloaded. So we need some info about KLibraries even after its
+ death. */
+class KLibWrapPrivate
+{
+public:
+ KLibWrapPrivate(KLibrary *l, lt_dlhandle h);
+
+ KLibrary *lib;
+ enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
+ int ref_count;
+ lt_dlhandle handle;
+ QString name;
+ QString filename;
+};
+
+KLibWrapPrivate::KLibWrapPrivate(KLibrary *l, lt_dlhandle h)
+ : lib(l), ref_count(1), handle(h), name(l->name()), filename(l->fileName())
+{
+ unload_mode = UNKNOWN;
+ if (lt_dlsym(handle, "__kde_do_not_unload") != 0) {
+// kdDebug(150) << "Will not unload " << name << endl;
+ unload_mode = DONT_UNLOAD;
+ } else if (lt_dlsym(handle, "__kde_do_unload") != 0) {
+ unload_mode = UNLOAD;
+ }
+}
+
+KLibLoader* KLibLoader::self()
+{
+ if ( !s_self )
+ s_self = new KLibLoader;
+ return s_self;
+}
+
+void KLibLoader::cleanUp()
+{
+ if ( !s_self )
+ return;
+
+ delete s_self;
+ s_self = 0L;
+}
+
+KLibLoader::KLibLoader( QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+ s_self = this;
+ d = new KLibLoaderPrivate;
+ lt_dlinit();
+ d->unload_mode = KLibLoaderPrivate::UNKNOWN;
+ if (getenv("KDE_NOUNLOAD") != 0)
+ d->unload_mode = KLibLoaderPrivate::DONT_UNLOAD;
+ else if (getenv("KDE_DOUNLOAD") != 0)
+ d->unload_mode = KLibLoaderPrivate::UNLOAD;
+ d->loaded_stack.setAutoDelete( true );
+}
+
+KLibLoader::~KLibLoader()
+{
+// kdDebug(150) << "Deleting KLibLoader " << this << " " << name() << endl;
+
+ QAsciiDictIterator<KLibWrapPrivate> it( m_libs );
+ for (; it.current(); ++it )
+ {
+ kdDebug(150) << "The KLibLoader contains the library " << it.current()->name
+ << " (" << it.current()->lib << ")" << endl;
+ d->pending_close.append(it.current());
+ }
+
+ close_pending(0);
+
+ delete d;
+ d = 0L;
+}
+
+static inline QCString makeLibName( const char* name )
+{
+ QCString libname(name);
+ // only append ".la" if there is no extension
+ // this allows to load non-libtool libraries as well
+ // (mhk, 20000228)
+ int pos = libname.findRev('/');
+ if (pos < 0)
+ pos = 0;
+ if (libname.find('.', pos) < 0)
+ libname += ".la";
+ return libname;
+}
+
+//static
+QString KLibLoader::findLibrary( const char * name, const KInstance * instance )
+{
+ QCString libname = makeLibName( name );
+
+ // only look up the file if it is not an absolute filename
+ // (mhk, 20000228)
+ QString libfile;
+ if (!QDir::isRelativePath(libname))
+ libfile = QFile::decodeName( libname );
+ else
+ {
+ libfile = instance->dirs()->findResource( "module", libname );
+ if ( libfile.isEmpty() )
+ {
+ libfile = instance->dirs()->findResource( "lib", libname );
+#ifndef NDEBUG
+ if ( !libfile.isEmpty() && libname.left(3) == "lib" ) // don't warn for kdeinit modules
+ kdDebug(150) << "library " << libname << " not found under 'module' but under 'lib'" << endl;
+#endif
+ }
+ }
+ return libfile;
+}
+
+
+KLibrary* KLibLoader::globalLibrary( const char *name )
+{
+KLibrary *tmp;
+int olt_dlopen_flag = lt_dlopen_flag;
+
+ lt_dlopen_flag |= LT_GLOBAL;
+ kdDebug(150) << "Loading the next library global with flag "
+ << lt_dlopen_flag
+ << "." << endl;
+ tmp = library(name);
+ lt_dlopen_flag = olt_dlopen_flag;
+
+return tmp;
+}
+
+
+KLibrary* KLibLoader::library( const char *name )
+{
+ if (!name)
+ return 0;
+
+ KLibWrapPrivate* wrap = m_libs[name];
+ if (wrap) {
+ /* Nothing to do to load the library. */
+ wrap->ref_count++;
+ return wrap->lib;
+ }
+
+ /* Test if this library was loaded at some time, but got
+ unloaded meanwhile, whithout being dlclose()'ed. */
+ QPtrListIterator<KLibWrapPrivate> it(d->loaded_stack);
+ for (; it.current(); ++it) {
+ if (it.current()->name == name)
+ wrap = it.current();
+ }
+
+ if (wrap) {
+ d->pending_close.removeRef(wrap);
+ if (!wrap->lib) {
+ /* This lib only was in loaded_stack, but not in m_libs. */
+ wrap->lib = new KLibrary( name, wrap->filename, wrap->handle );
+ }
+ wrap->ref_count++;
+ } else {
+ QString libfile = findLibrary( name );
+ if ( libfile.isEmpty() )
+ {
+ const QCString libname = makeLibName( name );
+#ifndef NDEBUG
+ kdDebug(150) << "library=" << name << ": No file named " << libname << " found in paths." << endl;
+#endif
+ d->errorMessage = i18n("Library files for \"%1\" not found in paths.").arg(libname);
+ return 0;
+ }
+
+ lt_dlhandle handle = lt_dlopen( QFile::encodeName(libfile) );
+ if ( !handle )
+ {
+ const char* errmsg = lt_dlerror();
+ if(errmsg)
+ d->errorMessage = QString::fromLocal8Bit(errmsg);
+ else
+ d->errorMessage = QString::null;
+ return 0;
+ }
+ else
+ d->errorMessage = QString::null;
+
+ KLibrary *lib = new KLibrary( name, libfile, handle );
+ wrap = new KLibWrapPrivate(lib, handle);
+ d->loaded_stack.prepend(wrap);
+ }
+ m_libs.insert( name, wrap );
+
+ connect( wrap->lib, SIGNAL( destroyed() ),
+ this, SLOT( slotLibraryDestroyed() ) );
+
+ return wrap->lib;
+}
+
+QString KLibLoader::lastErrorMessage() const
+{
+ return d->errorMessage;
+}
+
+void KLibLoader::unloadLibrary( const char *libname )
+{
+ KLibWrapPrivate *wrap = m_libs[ libname ];
+ if (!wrap)
+ return;
+ if (--wrap->ref_count)
+ return;
+
+// kdDebug(150) << "closing library " << libname << endl;
+
+ m_libs.remove( libname );
+
+ disconnect( wrap->lib, SIGNAL( destroyed() ),
+ this, SLOT( slotLibraryDestroyed() ) );
+ close_pending( wrap );
+}
+
+KLibFactory* KLibLoader::factory( const char* name )
+{
+ KLibrary* lib = library( name );
+ if ( !lib )
+ return 0;
+
+ return lib->factory();
+}
+
+void KLibLoader::slotLibraryDestroyed()
+{
+ const KLibrary *lib = static_cast<const KLibrary *>( sender() );
+
+ QAsciiDictIterator<KLibWrapPrivate> it( m_libs );
+ for (; it.current(); ++it )
+ if ( it.current()->lib == lib )
+ {
+ KLibWrapPrivate *wrap = it.current();
+ wrap->lib = 0; /* the KLibrary object is already away */
+ m_libs.remove( it.currentKey() );
+ close_pending( wrap );
+ return;
+ }
+}
+
+void KLibLoader::close_pending(KLibWrapPrivate *wrap)
+{
+ if (wrap && !d->pending_close.containsRef( wrap ))
+ d->pending_close.append( wrap );
+
+ /* First delete all KLibrary objects in pending_close, but _don't_ unload
+ the DSO behind it. */
+ QPtrListIterator<KLibWrapPrivate> it(d->pending_close);
+ for (; it.current(); ++it) {
+ wrap = it.current();
+ if (wrap->lib) {
+ disconnect( wrap->lib, SIGNAL( destroyed() ),
+ this, SLOT( slotLibraryDestroyed() ) );
+ KLibrary* to_delete = wrap->lib;
+ wrap->lib = 0L; // unset first, because KLibrary dtor can cause
+ delete to_delete; // recursive call to close_pending()
+ }
+ }
+
+ if (d->unload_mode == KLibLoaderPrivate::DONT_UNLOAD) {
+ d->pending_close.clear();
+ return;
+ }
+
+ bool deleted_one = false;
+ while ((wrap = d->loaded_stack.first())) {
+ /* Let's first see, if we want to try to unload this lib.
+ If the env. var KDE_DOUNLOAD is set, we try to unload every lib.
+ If not, we look at the lib itself, and unload it only, if it exports
+ the symbol __kde_do_unload. */
+ if (d->unload_mode != KLibLoaderPrivate::UNLOAD
+ && wrap->unload_mode != KLibWrapPrivate::UNLOAD)
+ break;
+
+ /* Now ensure, that the libs are only unloaded in the reverse direction
+ they were loaded. */
+ if (!d->pending_close.containsRef( wrap )) {
+ if (!deleted_one)
+ /* Only diagnose, if we really haven't deleted anything. */
+// kdDebug(150) << "try to dlclose " << wrap->name << ": not yet" << endl;
+ break;
+ }
+
+// kdDebug(150) << "try to dlclose " << wrap->name << ": yes, done." << endl;
+
+ if ( !deleted_one ) {
+ /* Only do the hack once in this loop.
+ WABA: *HACK*
+ We need to make sure to clear the clipboard before unloading a DSO
+ because the DSO could have defined an object derived from QMimeSource
+ and placed that on the clipboard. */
+ /*kapp->clipboard()->clear();*/
+
+ /* Well.. let's do something more subtle... convert the clipboard context
+ to text. That should be safe as it only uses objects defined by Qt. */
+ if( kapp->clipboard()->ownsSelection()) {
+ kapp->clipboard()->setText(
+ kapp->clipboard()->text( QClipboard::Selection ), QClipboard::Selection );
+ }
+ if( kapp->clipboard()->ownsClipboard()) {
+ kapp->clipboard()->setText(
+ kapp->clipboard()->text( QClipboard::Clipboard ), QClipboard::Clipboard );
+ }
+ }
+
+ deleted_one = true;
+ lt_dlclose(wrap->handle);
+ d->pending_close.removeRef(wrap);
+ /* loaded_stack is AutoDelete, so wrap is freed */
+ d->loaded_stack.remove();
+ }
+}
+
+void KLibLoader::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KLibFactory::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "klibloader.moc"
diff --git a/kdecore/klibloader.h b/kdecore/klibloader.h
new file mode 100644
index 000000000..1230f9944
--- /dev/null
+++ b/kdecore/klibloader.h
@@ -0,0 +1,405 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KLIBLOADER_H
+#define KLIBLOADER_H
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qasciidict.h>
+#include <qptrlist.h>
+#include <kglobal.h>
+
+#include <stdlib.h> // For backwards compatibility
+
+class KInstance;
+class QTimer;
+class KLibrary;
+class KLibFactory;
+class KLibFactoryPrivate;
+class KLibLoaderPrivate;
+class KLibraryPrivate;
+
+# define K_EXPORT_COMPONENT_FACTORY( libname, factory ) \
+ extern "C" { KDE_EXPORT void *init_##libname() { return new factory; } }
+
+/**
+ * @short Represents a dynamically loaded library.
+ *
+ * KLibrary allows you to look up symbols of the shared library.
+ * Use KLibLoader to create a new instance of KLibrary.
+ *
+ * @see KLibLoader
+ * @author Torben Weis <weis@kde.org>
+ */
+class KDECORE_EXPORT KLibrary : public QObject
+{
+ friend class KLibLoader;
+ friend class QAsciiDict<KLibrary>;
+
+ Q_OBJECT
+public:
+ /**
+ * Don't create KLibrary objects on your own. Instead use KLibLoader.
+ */
+ KLibrary( const QString& libname, const QString& filename, void * handle );
+
+ /**
+ * Returns the name of the library.
+ * @return The name of the library like "libkspread".
+ */
+ QString name() const;
+
+ /**
+ * Returns the file name of the library.
+ * @return The filename of the library, for example "/opt/kde2&/lib/libkspread.la"
+ */
+ QString fileName() const;
+
+ /**
+ * Returns the factory of the library.
+ * @return The factory of the library if there is any, otherwise 0
+ */
+ KLibFactory* factory();
+
+ /**
+ * Looks up a symbol from the library. This is a very low level
+ * function that you usually don't want to use. Usually you should
+ * check using hasSymbol() whether the symbol actually exists,
+ * otherwise a warning will be printed.
+ * @param name the name of the symbol to look up
+ * @return the address of the symbol, or 0 if it does not exist
+ * @see hasSymbol
+ */
+ void* symbol( const char* name ) const;
+
+ /**
+ * Looks up a symbol from the library. This is a very low level
+ * function that you usually don't want to use.
+ * Unlike symbol(), this method doesn't warn if the symbol doesn't exist,
+ * so if the symbol might or might not exist, better use hasSymbol() before symbol().
+ * @param name the name of the symbol to check
+ * @return true if the symbol exists
+ * @since 3.1
+ */
+ bool hasSymbol( const char* name ) const;
+
+ /**
+ * Unloads the library.
+ * This typically results in the deletion of this object. You should
+ * not reference its pointer after calling this function.
+ */
+ void unload() const;
+
+private slots:
+ void slotObjectCreated( QObject *obj );
+ void slotObjectDestroyed();
+ void slotTimeout();
+
+private:
+ /**
+ * @internal
+ * Don't destruct KLibrary objects yourself. Instead use unload() instead.
+ */
+ ~KLibrary();
+
+ QString m_libname;
+ QString m_filename;
+ KLibFactory* m_factory;
+ void * m_handle;
+ QPtrList<QObject> m_objs;
+ QTimer *m_timer;
+ KLibraryPrivate *d;
+};
+
+class KLibWrapPrivate;
+
+/**
+ * The KLibLoader allows you to load libraries dynamically at runtime.
+ * Dependent libraries are loaded automatically.
+ *
+ * KLibLoader follows the singleton pattern. You can not create multiple
+ * instances. Use self() to get a pointer to the loader.
+ *
+ * @see KLibrary
+ * @author Torben Weis <weis@kde.org>
+ */
+class KDECORE_EXPORT KLibLoader : public QObject
+{
+ friend class KLibrary;
+
+ Q_OBJECT
+public:
+ /**
+ * You should NEVER destruct an instance of KLibLoader
+ * until you know what you are doing. This will release
+ * the loaded libraries.
+ */
+ ~KLibLoader();
+
+ /**
+ * Loads and initializes a library. Loading a library multiple times is
+ * handled gracefully.
+ *
+ * This is a convenience function that returns the factory immediately
+ * @param libname This is the library name without extension. Usually that is something like
+ * "libkspread". The function will then search for a file named
+ * "libkspread.la" in the KDE library paths.
+ * The *.la files are created by libtool and contain
+ * important information especially about the libraries dependencies
+ * on other shared libs. Loading a "libfoo.so" could not solve the
+ * dependencies problem.
+ *
+ * You can, however, give a library name ending in ".so"
+ * (or whatever is used on your platform), and the library
+ * will be loaded without resolving dependencies. Use with caution.
+ * @return the KLibFactory, or 0 if the library does not exist or it does
+ * not have a factory
+ * @see library
+ */
+ KLibFactory* factory( const char* libname );
+
+ /**
+ * Loads and initializes a library. Loading a library multiple times is
+ * handled gracefully.
+ *
+ * @param libname This is the library name without extension. Usually that is something like
+ * "libkspread". The function will then search for a file named
+ * "libkspread.la" in the KDE library paths.
+ * The *.la files are created by libtool and contain
+ * important information especially about the libraries dependencies
+ * on other shared libs. Loading a "libfoo.so" could not solve the
+ * dependencies problem.
+ *
+ * You can, however, give a library name ending in ".so"
+ * (or whatever is used on your platform), and the library
+ * will be loaded without resolving dependencies. Use with caution.
+ * @return KLibrary is invalid (0) when the library couldn't be dlopened. in such
+ * a case you can retrieve the error message by calling KLibLoader::lastErrorMessage()
+ *
+ * @see factory
+ */
+ virtual KLibrary* library( const char* libname );
+
+ /**
+ * Loads and initializes a library. Loading a library multiple times is
+ * handled gracefully. The library is loaded such that the symbols are
+ * globally accessible so libraries with dependencies can be loaded
+ * sequentially.
+ *
+ * @param name This is the library name without extension. Usually that is something like
+ * "libkspread". The function will then search for a file named
+ * "libkspread.la" in the KDE library paths.
+ * The *.la files are created by libtool and contain
+ * important information especially about the libraries dependencies
+ * on other shared libs. Loading a "libfoo.so" could not solve the
+ * dependencies problem.
+ *
+ * You can, however, give a library name ending in ".so"
+ * (or whatever is used on your platform), and the library
+ * will be loaded without resolving dependencies. Use with caution.
+ * @return KLibrariy is invalid (0) when the library couldn't be dlopened. in such
+ * a case you can retrieve the error message by calling KLibLoader::lastErrorMessage()
+ *
+ * @see factory
+ */
+ KLibrary* globalLibrary( const char *name );
+
+ /**
+ * Returns an error message that can be useful to debug the problem.
+ * Returns QString::null if the last call to library() was successful.
+ * You can call this function more than once. The error message is only
+ * reset by a new call to library().
+ * @return the last error message, or QString::null if there was no error
+ */
+ QString lastErrorMessage() const;
+
+ /**
+ * Unloads the library with the given name.
+ * @param libname This is the library name without extension. Usually that is something like
+ * "libkspread". The function will then search for a file named
+ * "libkspread.la" in the KDE library paths.
+ * The *.la files are created by libtool and contain
+ * important information especially about the libraries dependencies
+ * on other shared libs. Loading a "libfoo.so" could not solve the
+ * dependencies problem.
+ *
+ * You can, however, give a library name ending in ".so"
+ * (or whatever is used on your platform), and the library
+ * will be loaded without resolving dependencies. Use with caution.
+ */
+ virtual void unloadLibrary( const char *libname );
+
+ /**
+ * Returns a pointer to the factory. Use this function to get an instance
+ * of KLibLoader.
+ * @return a pointer to the loader. If no loader exists until now
+ * then one is created.
+ */
+ static KLibLoader* self();
+
+ /**
+ * @internal
+ * Internal Method, called by the KApplication destructor.
+ * Do not call it.
+ * This is what makes it possible to rely on ~KLibFactory
+ * being called in all cases, whether the library is unloaded
+ * while the application is running or when exiting.
+ */
+ static void cleanUp();
+
+ /**
+ * Helper method which looks for a library in the standard paths
+ * ("module" and "lib" resources).
+ * Made public for code that doesn't use KLibLoader itself, but still
+ * wants to open modules.
+ * @param name of the library. If it is not a path, the function searches in
+ * the "module" and "lib" resources. If there is no extension,
+ * ".la" will be appended.
+ * @param instance a KInstance used to get the standard paths
+ */
+ static QString findLibrary( const char * name, const KInstance * instance = KGlobal::instance() );
+
+protected:
+ KLibLoader( QObject* parent = 0, const char* name = 0 );
+
+private slots:
+ void slotLibraryDestroyed();
+private:
+ void close_pending( KLibWrapPrivate * );
+ QAsciiDict<KLibWrapPrivate> m_libs;
+
+ static KLibLoader* s_self;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KLibLoaderPrivate *d;
+};
+
+/**
+ * If you develop a library that is to be loaded dynamically at runtime, then
+ * you should return a pointer to your factory. The K_EXPORT_COMPONENT_FACTORY
+ * macro is provided for this purpose:
+ * \code
+ * K_EXPORT_COMPONENT_FACTORY( libkspread, KSpreadFactory )
+ * \endcode
+ *
+ * The first macro argument is the name of your library, the second specifies the name
+ * of your factory.
+ *
+ * NOTE: you probably want to use KGenericFactory<PluginClassName>
+ * instead of writing your own factory.
+ *
+ * In the constructor of your factory you should create an instance of KInstance
+ * like this:
+ * \code
+ * s_global = new KInstance( "kspread" );
+ * \endcode
+ * This KInstance is comparable to KGlobal used by normal applications.
+ * It allows you to find resource files (images, XML, sound etc.) belonging
+ * to the library.
+ *
+ * If you want to load a library, use KLibLoader. You can query KLibLoader
+ * directly for a pointer to the libraries factory by using the KLibLoader::factory()
+ * function.
+ *
+ * The KLibFactory is used to create the components, the library has to offer.
+ * The factory of KSpread for example will create instances of KSpreadDoc,
+ * while the Konqueror factory will create KonqView widgets.
+ * All objects created by the factory must be derived from QObject, since QObject
+ * offers type safe casting.
+ *
+ * KLibFactory is an abstract class. Reimplement the
+ * createObject() method to give it functionality.
+ *
+ * @author Torben Weis <weis@kde.org>
+ */
+class KDECORE_EXPORT KLibFactory : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a new factory.
+ * @param parent the parent of the QObject, 0 for no parent
+ * @param name the name of the QObject, 0 for no name
+ */
+ KLibFactory( QObject* parent = 0, const char* name = 0 );
+ virtual ~KLibFactory();
+
+ /**
+ * Creates a new object. The returned object has to be derived from
+ * the requested classname.
+ *
+ * It is valid behavior to create different kinds of objects
+ * depending on the requested @p classname. For example a koffice
+ * library may usually return a pointer to KoDocument. But
+ * if asked for a "QWidget", it could create a wrapper widget,
+ * that encapsulates the Koffice specific features.
+ *
+ * create() automatically emits a signal objectCreated to tell
+ * the library about its newly created object. This is very
+ * important for reference counting, and allows unloading the
+ * library automatically once all its objects have been destroyed.
+ *
+ * @param parent the parent of the QObject, 0 for no parent
+ * @param name the name of the QObject, 0 for no name
+ * @param classname the name of the class
+ * @param args a list of arguments
+ */
+
+ QObject* create( QObject* parent = 0, const char* name = 0, const char* classname = "QObject", const QStringList &args = QStringList() );
+
+signals:
+ /**
+ * Emitted in #create
+ * @param obj the new object
+ */
+ void objectCreated( QObject *obj );
+
+
+protected:
+
+ /**
+ * Creates a new object. The returned object has to be derived from
+ * the requested classname.
+ *
+ * It is valid behavior to create different kinds of objects
+ * depending on the requested @p className. For example a koffice
+ * library may usually return a pointer to KoDocument. But
+ * if asked for a "QWidget", it could create a wrapper widget,
+ * that encapsulates the Koffice specific features.
+ *
+ * This function is called by #create()
+ * @param parent the parent of the QObject, 0 for no parent
+ * @param name the name of the QObject, 0 for no name
+ * @param className the name of the class
+ * @param args a list of arguments
+ */
+ virtual QObject* createObject( QObject* parent = 0, const char* name = 0,
+ const char* className = "QObject",
+ const QStringList &args = QStringList() ) = 0;
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KLibFactoryPrivate *d;
+};
+
+#endif
diff --git a/kdecore/klocale.cpp b/kdecore/klocale.cpp
new file mode 100644
index 000000000..1ca1f035e
--- /dev/null
+++ b/kdecore/klocale.cpp
@@ -0,0 +1,2448 @@
+// -*- c-basic-offset: 2 -*-
+/* This file is part of the KDE libraries
+ Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1999-2002 Hans Petter Bieker <bieker@kde.org>
+ Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <stdlib.h> // getenv
+
+#include <qtextcodec.h>
+#include <qfile.h>
+#include <qprinter.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+#include "kcatalogue.h"
+#include "kglobal.h"
+#include "kstandarddirs.h"
+#include "ksimpleconfig.h"
+#include "kinstance.h"
+#include "kconfig.h"
+#include "kdebug.h"
+#include "kcalendarsystem.h"
+#include "kcalendarsystemfactory.h"
+#include "klocale.h"
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+#endif
+
+static const char * const SYSTEM_MESSAGES = "kdelibs";
+
+static const char *maincatalogue = 0;
+
+class KLocalePrivate
+{
+public:
+ int weekStartDay;
+ bool nounDeclension;
+ bool dateMonthNamePossessive;
+ QStringList languageList;
+ QStringList catalogNames; // list of all catalogs (regardless of language)
+ QValueList<KCatalogue> catalogues; // list of all loaded catalogs, contains one instance per catalog name and language
+ QString encoding;
+ QTextCodec * codecForEncoding;
+ KConfig * config;
+ bool formatInited;
+ int /*QPrinter::PageSize*/ pageSize;
+ KLocale::MeasureSystem measureSystem;
+ QStringList langTwoAlpha;
+ KConfig *languages;
+
+ QString calendarType;
+ KCalendarSystem * calendar;
+ bool utf8FileEncoding;
+ QString appName;
+#ifdef Q_WS_WIN
+ char win32SystemEncoding[3+7]; //"cp " + lang ID
+#endif
+};
+
+static KLocale *this_klocale = 0;
+
+KLocale::KLocale( const QString & catalog, KConfig * config )
+{
+ d = new KLocalePrivate;
+ d->config = config;
+ d->languages = 0;
+ d->calendar = 0;
+ d->formatInited = false;
+
+ initEncoding(0);
+ initFileNameEncoding(0);
+
+ KConfig *cfg = d->config;
+ this_klocale = this;
+ if (!cfg) cfg = KGlobal::instance()->config();
+ this_klocale = 0;
+ Q_ASSERT( cfg );
+
+ d->appName = catalog;
+ initLanguageList( cfg, config == 0);
+ initMainCatalogues(catalog);
+}
+
+QString KLocale::_initLanguage(KConfigBase *config)
+{
+ if (this_klocale)
+ {
+ // ### HPB Why this cast??
+ this_klocale->initLanguageList((KConfig *) config, true);
+ // todo: adapt current catalog list: remove unused languages, insert main catalogs, if not already found
+ return this_klocale->language();
+ }
+ return QString::null;
+}
+
+void KLocale::initMainCatalogues(const QString & catalog)
+{
+ // Use the first non-null string.
+ QString mainCatalogue = catalog;
+ if (maincatalogue)
+ mainCatalogue = QString::fromLatin1(maincatalogue);
+
+ if (mainCatalogue.isEmpty()) {
+ kdDebug(173) << "KLocale instance created called without valid "
+ << "catalog! Give an argument or call setMainCatalogue "
+ << "before init" << endl;
+ }
+ else {
+ // do not use insertCatalogue here, that would already trigger updateCatalogs
+ d->catalogNames.append( mainCatalogue ); // application catalog
+ d->catalogNames.append( SYSTEM_MESSAGES ); // always include kdelibs.mo
+ d->catalogNames.append( "kio" ); // always include kio.mo
+ updateCatalogues(); // evaluate this for all languages
+ }
+}
+
+void KLocale::initLanguageList(KConfig * config, bool useEnv)
+{
+ KConfigGroupSaver saver(config, "Locale");
+
+ m_country = config->readEntry( "Country" );
+ if ( m_country.isEmpty() )
+ m_country = defaultCountry();
+
+ // Reset the list and add the new languages
+ QStringList languageList;
+ if ( useEnv )
+ languageList += QStringList::split
+ (':', QFile::decodeName( ::getenv("KDE_LANG") ));
+
+ languageList += config->readListEntry("Language", ':');
+
+ // same order as setlocale use
+ if ( useEnv )
+ {
+ // HPB: Only run splitLocale on the environment variables..
+ QStringList langs;
+
+ langs << QFile::decodeName( ::getenv("LC_ALL") );
+ langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
+ langs << QFile::decodeName( ::getenv("LANG") );
+
+ for ( QStringList::Iterator it = langs.begin();
+ it != langs.end();
+ ++it )
+ {
+ QString ln, ct, chrset;
+ splitLocale(*it, ln, ct, chrset);
+
+ if (!ct.isEmpty()) {
+ langs.insert(it, ln + '_' + ct);
+ if (!chrset.isEmpty())
+ langs.insert(it, ln + '_' + ct + '.' + chrset);
+ }
+
+ langs.insert(it, ln);
+ }
+
+ languageList += langs;
+ }
+
+ // now we have a language list -- let's use the first OK language
+ setLanguage( languageList );
+}
+
+void KLocale::initPluralTypes()
+{
+ for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
+ it != d->catalogues.end();
+ ++it )
+ {
+ QString language = (*it).language();
+ int pt = pluralType( language );
+ (*it).setPluralType( pt );
+ }
+}
+
+
+int KLocale::pluralType( const QString & language )
+{
+ for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
+ it != d->catalogues.end();
+ ++it )
+ {
+ if ( ((*it).name() == SYSTEM_MESSAGES ) && ((*it).language() == language )) {
+ return pluralType( *it );
+ }
+ }
+ // kdelibs.mo does not seem to exist for this language
+ return -1;
+}
+
+int KLocale::pluralType( const KCatalogue& catalog )
+{
+ const char* pluralFormString =
+ I18N_NOOP("_: Dear translator, please do not translate this string "
+ "in any form, but pick the _right_ value out of "
+ "NoPlural/TwoForms/French... If not sure what to do mail "
+ "thd@kde.org and coolo@kde.org, they will tell you. "
+ "Better leave that out if unsure, the programs will "
+ "crash!!\nDefinition of PluralForm - to be set by the "
+ "translator of kdelibs.po");
+ QString pf (catalog.translate( pluralFormString));
+ if ( pf.isEmpty() ) {
+ return -1;
+ }
+ else if ( pf == "NoPlural" )
+ return 0;
+ else if ( pf == "TwoForms" )
+ return 1;
+ else if ( pf == "French" )
+ return 2;
+ else if ( pf == "OneTwoRest" )
+ return 3;
+ else if ( pf == "Russian" )
+ return 4;
+ else if ( pf == "Polish" )
+ return 5;
+ else if ( pf == "Slovenian" )
+ return 6;
+ else if ( pf == "Lithuanian" )
+ return 7;
+ else if ( pf == "Czech" )
+ return 8;
+ else if ( pf == "Slovak" )
+ return 9;
+ else if ( pf == "Maltese" )
+ return 10;
+ else if ( pf == "Arabic" )
+ return 11;
+ else if ( pf == "Balcan" )
+ return 12;
+ else if ( pf == "Macedonian" )
+ return 13;
+ else if ( pf == "Gaeilge" )
+ return 14;
+ else {
+ kdWarning(173) << "Definition of PluralForm is none of "
+ << "NoPlural/"
+ << "TwoForms/"
+ << "French/"
+ << "OneTwoRest/"
+ << "Russian/"
+ << "Polish/"
+ << "Slovenian/"
+ << "Lithuanian/"
+ << "Czech/"
+ << "Slovak/"
+ << "Arabic/"
+ << "Balcan/"
+ << "Macedonian/"
+ << "Gaeilge/"
+ << "Maltese: " << pf << endl;
+ exit(1);
+ }
+}
+
+void KLocale::doFormatInit() const
+{
+ if ( d->formatInited ) return;
+
+ KLocale * that = const_cast<KLocale *>(this);
+ that->initFormat();
+
+ d->formatInited = true;
+}
+
+void KLocale::initFormat()
+{
+ KConfig *config = d->config;
+ if (!config) config = KGlobal::instance()->config();
+ Q_ASSERT( config );
+
+ kdDebug(173) << "KLocale::initFormat" << endl;
+
+ // make sure the config files are read using the correct locale
+ // ### Why not add a KConfigBase::setLocale( const KLocale * )?
+ // ### Then we could remove this hack
+ KLocale *lsave = KGlobal::_locale;
+ KGlobal::_locale = this;
+
+ KConfigGroupSaver saver(config, "Locale");
+
+ KSimpleConfig entry(locate("locale",
+ QString::fromLatin1("l10n/%1/entry.desktop")
+ .arg(m_country)), true);
+ entry.setGroup("KCM Locale");
+
+ // Numeric
+#define readConfigEntry(key, default, save) \
+ save = entry.readEntry(key, QString::fromLatin1(default)); \
+ save = config->readEntry(key, save);
+
+#define readConfigNumEntry(key, default, save, type) \
+ save = (type)entry.readNumEntry(key, default); \
+ save = (type)config->readNumEntry(key, save);
+
+#define readConfigBoolEntry(key, default, save) \
+ save = entry.readBoolEntry(key, default); \
+ save = config->readBoolEntry(key, save);
+
+ readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
+ readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
+ m_thousandsSeparator.replace( QString::fromLatin1("$0"), QString::null );
+ //kdDebug(173) << "m_thousandsSeparator=" << m_thousandsSeparator << endl;
+
+ readConfigEntry("PositiveSign", "", m_positiveSign);
+ readConfigEntry("NegativeSign", "-", m_negativeSign);
+
+ // Monetary
+ readConfigEntry("CurrencySymbol", "$", m_currencySymbol);
+ readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
+ readConfigEntry("MonetaryThousandsSeparator", ",",
+ m_monetaryThousandsSeparator);
+ m_monetaryThousandsSeparator.replace(QString::fromLatin1("$0"), QString::null);
+
+ readConfigNumEntry("FracDigits", 2, m_fracDigits, int);
+ readConfigBoolEntry("PositivePrefixCurrencySymbol", true,
+ m_positivePrefixCurrencySymbol);
+ readConfigBoolEntry("NegativePrefixCurrencySymbol", true,
+ m_negativePrefixCurrencySymbol);
+ readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney,
+ m_positiveMonetarySignPosition, SignPosition);
+ readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround,
+ m_negativeMonetarySignPosition, SignPosition);
+
+
+ // Date and time
+ readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
+ readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
+ readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
+ readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int);
+
+ // other
+ readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int);
+ readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem,
+ MeasureSystem);
+ readConfigEntry("CalendarSystem", "gregorian", d->calendarType);
+ delete d->calendar;
+ d->calendar = 0; // ### HPB Is this the correct place?
+
+ //Grammatical
+ //Precedence here is l10n / i18n / config file
+ KSimpleConfig language(locate("locale",
+ QString::fromLatin1("%1/entry.desktop")
+ .arg(m_language)), true);
+ language.setGroup("KCM Locale");
+#define read3ConfigBoolEntry(key, default, save) \
+ save = entry.readBoolEntry(key, default); \
+ save = language.readBoolEntry(key, save); \
+ save = config->readBoolEntry(key, save);
+
+ read3ConfigBoolEntry("NounDeclension", false, d->nounDeclension);
+ read3ConfigBoolEntry("DateMonthNamePossessive", false,
+ d->dateMonthNamePossessive);
+
+ // end of hack
+ KGlobal::_locale = lsave;
+}
+
+bool KLocale::setCountry(const QString & country)
+{
+ // Check if the file exists too??
+ if ( country.isEmpty() )
+ return false;
+
+ m_country = country;
+
+ d->formatInited = false;
+
+ return true;
+}
+
+QString KLocale::catalogueFileName(const QString & language,
+ const KCatalogue & catalog)
+{
+ QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
+ .arg( language )
+ .arg( catalog.name() );
+
+ return locate( "locale", path );
+}
+
+bool KLocale::setLanguage(const QString & language)
+{
+ if ( d->languageList.contains( language ) ) {
+ d->languageList.remove( language );
+ }
+ d->languageList.prepend( language ); // let us consider this language to be the most important one
+
+ m_language = language; // remember main language for shortcut evaluation
+
+ // important when called from the outside and harmless when called before populating the
+ // catalog name list
+ updateCatalogues();
+
+ d->formatInited = false;
+
+ return true; // Maybe the mo-files for this language are empty, but in principle we can speak all languages
+}
+
+bool KLocale::setLanguage(const QStringList & languages)
+{
+ QStringList languageList( languages );
+ // This list might contain
+ // 1) some empty strings that we have to eliminate
+ // 2) duplicate entries like in de:fr:de, where we have to keep the first occurrance of a language in order
+ // to preserve the order of precenence of the user => iterate backwards
+ // 3) languages into which the application is not translated. For those languages we should not even load kdelibs.mo or kio.po.
+ // these langugage have to be dropped. Otherwise we get strange side effects, e.g. with Hebrew:
+ // the right/left switch for languages that write from
+ // right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have kdelibs.mo
+ // but nothing from appname.mo, you get a mostly English app with layout from right to left.
+ // That was considered to be a bug by the Hebrew translators.
+ for( QStringList::Iterator it = languageList.fromLast();
+ it != languageList.begin(); --it )
+ {
+ // kdDebug() << "checking " << (*it) << endl;
+ bool bIsTranslated = isApplicationTranslatedInto( *it );
+ if ( languageList.contains(*it) > 1 || (*it).isEmpty() || (!bIsTranslated) ) {
+ // kdDebug() << "removing " << (*it) << endl;
+ it = languageList.remove( it );
+ }
+ }
+ // now this has left the first element of the list unchecked.
+ // The question why this is the case is left as an exercise for the reader...
+ // Besides the list might have been empty all the way, so check that too.
+ if ( languageList.begin() != languageList.end() ) {
+ QStringList::Iterator it = languageList.begin(); // now pointing to the first element
+ // kdDebug() << "checking " << (*it) << endl;
+ if( (*it).isEmpty() || !(isApplicationTranslatedInto( *it )) ) {
+ // kdDebug() << "removing " << (*it) << endl;
+ languageList.remove( it ); // that's what the iterator was for...
+ }
+ }
+
+ if ( languageList.isEmpty() ) {
+ // user picked no language, so we assume he/she speaks English.
+ languageList.append( defaultLanguage() );
+ }
+ m_language = languageList.first(); // keep this for shortcut evaluations
+
+ d->languageList = languageList; // keep this new list of languages to use
+ d->langTwoAlpha.clear(); // Flush cache
+
+ // important when called from the outside and harmless when called before populating the
+ // catalog name list
+ updateCatalogues();
+
+ return true; // we found something. Maybe it's only English, but we found something
+}
+
+bool KLocale::isApplicationTranslatedInto( const QString & language)
+{
+ if ( language.isEmpty() ) {
+ return false;
+ }
+
+ if ( language == defaultLanguage() ) {
+ // en_us is always "installed"
+ return true;
+ }
+
+ QString appName = d->appName;
+ if (maincatalogue) {
+ appName = QString::fromLatin1(maincatalogue);
+ }
+ // sorry, catalogueFileName requires catalog object,k which we do not have here
+ // path finding was supposed to be moved completely to KCatalogue. The interface cannot
+ // be changed that far during deep freeze. So in order to fix the bug now, we have
+ // duplicated code for file path evaluation. Cleanup will follow later. We could have e.g.
+ // a static method in KCataloge that can translate between these file names.
+ // a stat
+ QString sFileName = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
+ .arg( language )
+ .arg( appName );
+ // kdDebug() << "isApplicationTranslatedInto: filename " << sFileName << endl;
+
+ QString sAbsFileName = locate( "locale", sFileName );
+ // kdDebug() << "isApplicationTranslatedInto: absname " << sAbsFileName << endl;
+ return ! sAbsFileName.isEmpty();
+}
+
+void KLocale::splitLocale(const QString & aStr,
+ QString & language,
+ QString & country,
+ QString & chrset)
+{
+ QString str = aStr;
+
+ // just in case, there is another language appended
+ int f = str.find(':');
+ if (f >= 0)
+ str.truncate(f);
+
+ country = QString::null;
+ chrset = QString::null;
+ language = QString::null;
+
+ f = str.find('.');
+ if (f >= 0)
+ {
+ chrset = str.mid(f + 1);
+ str.truncate(f);
+ }
+
+ f = str.find('_');
+ if (f >= 0)
+ {
+ country = str.mid(f + 1);
+ str.truncate(f);
+ }
+
+ language = str;
+}
+
+QString KLocale::language() const
+{
+ return m_language;
+}
+
+QString KLocale::country() const
+{
+ return m_country;
+}
+
+QString KLocale::monthName(int i, bool shortName) const
+{
+ if ( shortName )
+ switch ( i )
+ {
+ case 1: return translate("January", "Jan");
+ case 2: return translate("February", "Feb");
+ case 3: return translate("March", "Mar");
+ case 4: return translate("April", "Apr");
+ case 5: return translate("May short", "May");
+ case 6: return translate("June", "Jun");
+ case 7: return translate("July", "Jul");
+ case 8: return translate("August", "Aug");
+ case 9: return translate("September", "Sep");
+ case 10: return translate("October", "Oct");
+ case 11: return translate("November", "Nov");
+ case 12: return translate("December", "Dec");
+ }
+ else
+ switch (i)
+ {
+ case 1: return translate("January");
+ case 2: return translate("February");
+ case 3: return translate("March");
+ case 4: return translate("April");
+ case 5: return translate("May long", "May");
+ case 6: return translate("June");
+ case 7: return translate("July");
+ case 8: return translate("August");
+ case 9: return translate("September");
+ case 10: return translate("October");
+ case 11: return translate("November");
+ case 12: return translate("December");
+ }
+
+ return QString::null;
+}
+
+QString KLocale::monthNamePossessive(int i, bool shortName) const
+{
+ if ( shortName )
+ switch ( i )
+ {
+ case 1: return translate("of January", "of Jan");
+ case 2: return translate("of February", "of Feb");
+ case 3: return translate("of March", "of Mar");
+ case 4: return translate("of April", "of Apr");
+ case 5: return translate("of May short", "of May");
+ case 6: return translate("of June", "of Jun");
+ case 7: return translate("of July", "of Jul");
+ case 8: return translate("of August", "of Aug");
+ case 9: return translate("of September", "of Sep");
+ case 10: return translate("of October", "of Oct");
+ case 11: return translate("of November", "of Nov");
+ case 12: return translate("of December", "of Dec");
+ }
+ else
+ switch (i)
+ {
+ case 1: return translate("of January");
+ case 2: return translate("of February");
+ case 3: return translate("of March");
+ case 4: return translate("of April");
+ case 5: return translate("of May long", "of May");
+ case 6: return translate("of June");
+ case 7: return translate("of July");
+ case 8: return translate("of August");
+ case 9: return translate("of September");
+ case 10: return translate("of October");
+ case 11: return translate("of November");
+ case 12: return translate("of December");
+ }
+
+ return QString::null;
+}
+
+QString KLocale::weekDayName (int i, bool shortName) const
+{
+ return calendar()->weekDayName(i, shortName);
+}
+
+void KLocale::insertCatalogue( const QString & catalog )
+{
+ if ( !d->catalogNames.contains( catalog) ) {
+ d->catalogNames.append( catalog );
+ }
+ updateCatalogues( ); // evaluate the changed list and generate the neccessary KCatalog objects
+}
+
+void KLocale::updateCatalogues( )
+{
+ // some changes have occured. Maybe we have learned or forgotten some languages.
+ // Maybe the language precedence has changed.
+ // Maybe we have learned or forgotten some catalog names.
+ // Now examine the list of KCatalogue objects and change it according to the new circumstances.
+
+ // this could be optimized: try to reuse old KCatalog objects, but remember that the order of
+ // catalogs might have changed: e.g. in this fashion
+ // 1) move all catalogs into a temporary list
+ // 2) iterate over all languages and catalog names
+ // 3.1) pick the catalog from the saved list, if it already exists
+ // 3.2) else create a new catalog.
+ // but we will do this later.
+
+ for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
+ it != d->catalogues.end(); )
+ {
+ it = d->catalogues.remove(it);
+ }
+
+ // now iterate over all languages and all wanted catalog names and append or create them in the right order
+ // the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs de/kio etc.
+ // and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be in trouble with a language
+ // sequende nds,en_US, de. In this case en_US must hide everything below in the language list.
+ for ( QStringList::ConstIterator itLangs = d->languageList.begin();
+ itLangs != d->languageList.end(); ++itLangs)
+ {
+ for ( QStringList::ConstIterator itNames = d->catalogNames.begin();
+ itNames != d->catalogNames.end(); ++itNames)
+ {
+ KCatalogue cat( *itNames, *itLangs ); // create Catalog for this name and this language
+ d->catalogues.append( cat );
+ }
+ }
+ initPluralTypes(); // evaluate the plural type for all languages and remember this in each KCatalogue
+}
+
+
+
+
+void KLocale::removeCatalogue(const QString &catalog)
+{
+ if ( d->catalogNames.contains( catalog )) {
+ d->catalogNames.remove( catalog );
+ if (KGlobal::_instance)
+ updateCatalogues(); // walk through the KCatalogue instances and weed out everything we no longer need
+ }
+}
+
+void KLocale::setActiveCatalogue(const QString &catalog)
+{
+ if ( d->catalogNames.contains( catalog ) ) {
+ d->catalogNames.remove( catalog );
+ d->catalogNames.prepend( catalog );
+ updateCatalogues(); // walk through the KCatalogue instances and adapt to the new order
+ }
+}
+
+KLocale::~KLocale()
+{
+ delete d->calendar;
+ delete d->languages;
+ delete d;
+ d = 0L;
+}
+
+QString KLocale::translate_priv(const char *msgid,
+ const char *fallback,
+ const char **translated,
+ int* pluralType ) const
+{
+ if ( pluralType) {
+ *pluralType = -1; // unless we find something more precise
+ }
+ if (!msgid || !msgid[0])
+ {
+ kdWarning() << "KLocale: trying to look up \"\" in catalog. "
+ << "Fix the program" << endl;
+ return QString::null;
+ }
+
+ if ( useDefaultLanguage() ) { // shortcut evaluation if en_US is main language: do not consult the catalogs
+ return QString::fromUtf8( fallback );
+ }
+
+ for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
+ it != d->catalogues.end();
+ ++it )
+ {
+ // shortcut evaluation: once we have arrived at en_US (default language) we cannot consult
+ // the catalog as it will not have an assiciated mo-file. For this default language we can
+ // immediately pick the fallback string.
+ if ( (*it).language() == defaultLanguage() ) {
+ return QString::fromUtf8( fallback );
+ }
+
+ const char * text = (*it).translate( msgid );
+
+ if ( text )
+ {
+ // we found it
+ if (translated) {
+ *translated = text;
+ }
+ if ( pluralType) {
+ *pluralType = (*it).pluralType(); // remember the plural type information from the catalog that was used
+ }
+ return QString::fromUtf8( text );
+ }
+ }
+
+ // Always use UTF-8 if the string was not found
+ return QString::fromUtf8( fallback );
+}
+
+QString KLocale::translate(const char* msgid) const
+{
+ return translate_priv(msgid, msgid);
+}
+
+QString KLocale::translate( const char *index, const char *fallback) const
+{
+ if (!index || !index[0] || !fallback || !fallback[0])
+ {
+ kdDebug(173) << "KLocale: trying to look up \"\" in catalog. "
+ << "Fix the program" << endl;
+ return QString::null;
+ }
+
+ if ( useDefaultLanguage() )
+ return QString::fromUtf8( fallback );
+
+ char *newstring = new char[strlen(index) + strlen(fallback) + 5];
+ sprintf(newstring, "_: %s\n%s", index, fallback);
+ // as copying QString is very fast, it looks slower as it is ;/
+ QString r = translate_priv(newstring, fallback);
+ delete [] newstring;
+
+ return r;
+}
+
+static QString put_n_in(const QString &orig, unsigned long n)
+{
+ QString ret = orig;
+ int index = ret.find("%n");
+ if (index == -1)
+ return ret;
+ ret.replace(index, 2, QString::number(n));
+ return ret;
+}
+
+#define EXPECT_LENGTH(x) \
+ if (forms.count() != x) { \
+ kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \
+ return QString( "BROKEN TRANSLATION %1" ).arg( singular ); }
+
+QString KLocale::translate( const char *singular, const char *plural,
+ unsigned long n ) const
+{
+ if (!singular || !singular[0] || !plural || !plural[0])
+ {
+ kdWarning() << "KLocale: trying to look up \"\" in catalog. "
+ << "Fix the program" << endl;
+ return QString::null;
+ }
+
+ char *newstring = new char[strlen(singular) + strlen(plural) + 6];
+ sprintf(newstring, "_n: %s\n%s", singular, plural);
+ // as copying QString is very fast, it looks slower as it is ;/
+ int pluralType = -1;
+ QString r = translate_priv(newstring, 0, 0, &pluralType);
+ delete [] newstring;
+
+ if ( r.isEmpty() || useDefaultLanguage() || pluralType == -1) {
+ if ( n == 1 ) {
+ return put_n_in( QString::fromUtf8( singular ), n );
+ } else {
+ QString tmp = QString::fromUtf8( plural );
+#ifndef NDEBUG
+ if (tmp.find("%n") == -1) {
+ kdDebug() << "the message for i18n should contain a '%n'! " << plural << endl;
+ }
+#endif
+ return put_n_in( tmp, n );
+ }
+ }
+
+ QStringList forms = QStringList::split( "\n", r, false );
+ switch ( pluralType ) {
+ case 0: // NoPlural
+ EXPECT_LENGTH( 1 );
+ return put_n_in( forms[0], n);
+ case 1: // TwoForms
+ EXPECT_LENGTH( 2 );
+ if ( n == 1 )
+ return put_n_in( forms[0], n);
+ else
+ return put_n_in( forms[1], n);
+ case 2: // French
+ EXPECT_LENGTH( 2 );
+ if ( n == 1 || n == 0 )
+ return put_n_in( forms[0], n);
+ else
+ return put_n_in( forms[1], n);
+ case 3: // OneTwoRest
+ EXPECT_LENGTH( 3 );
+ if ( n == 1 )
+ return put_n_in( forms[0], n);
+ else if ( n == 2 )
+ return put_n_in( forms[1], n);
+ else
+ return put_n_in( forms[2], n);
+ case 4: // Russian, corrected by mok
+ EXPECT_LENGTH( 3 );
+ if ( n%10 == 1 && n%100 != 11)
+ return put_n_in( forms[0], n); // odin fail
+ else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20))
+ return put_n_in( forms[1], n); // dva faila
+ else
+ return put_n_in( forms[2], n); // desyat' failov
+ case 5: // Polish
+ EXPECT_LENGTH( 3 );
+ if ( n == 1 )
+ return put_n_in( forms[0], n);
+ else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) )
+ return put_n_in( forms[1], n);
+ else
+ return put_n_in( forms[2], n);
+ case 6: // Slovenian
+ EXPECT_LENGTH( 4 );
+ if ( n%100 == 1 )
+ return put_n_in( forms[1], n); // ena datoteka
+ else if ( n%100 == 2 )
+ return put_n_in( forms[2], n); // dve datoteki
+ else if ( n%100 == 3 || n%100 == 4 )
+ return put_n_in( forms[3], n); // tri datoteke
+ else
+ return put_n_in( forms[0], n); // sto datotek
+ case 7: // Lithuanian
+ EXPECT_LENGTH( 3 );
+ if ( n%10 == 0 || (n%100>=11 && n%100<=19) )
+ return put_n_in( forms[2], n);
+ else if ( n%10 == 1 )
+ return put_n_in( forms[0], n);
+ else
+ return put_n_in( forms[1], n);
+ case 8: // Czech - use modern form which is equivalent to Slovak
+ case 9: // Slovak
+ EXPECT_LENGTH( 3 );
+ if ( n == 1 )
+ return put_n_in( forms[0], n);
+ else if (( n >= 2 ) && ( n <= 4 ))
+ return put_n_in( forms[1], n);
+ else
+ return put_n_in( forms[2], n);
+ case 10: // Maltese
+ EXPECT_LENGTH( 4 );
+ if ( n == 1 )
+ return put_n_in( forms[0], n );
+ else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
+ return put_n_in( forms[1], n );
+ else if ( n%100 > 10 && n%100 < 20 )
+ return put_n_in( forms[2], n );
+ else
+ return put_n_in( forms[3], n );
+ case 11: // Arabic
+ EXPECT_LENGTH( 4 );
+ if (n == 1)
+ return put_n_in(forms[0], n);
+ else if (n == 2)
+ return put_n_in(forms[1], n);
+ else if ( n < 11)
+ return put_n_in(forms[2], n);
+ else
+ return put_n_in(forms[3], n);
+ case 12: // Balcan
+ EXPECT_LENGTH( 3 );
+ if (n != 11 && n % 10 == 1)
+ return put_n_in(forms[0], n);
+ else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
+ return put_n_in(forms[1], n);
+ else
+ return put_n_in(forms[2], n);
+ case 13: // Macedonian
+ EXPECT_LENGTH(3);
+ if (n % 10 == 1)
+ return put_n_in(forms[0], n);
+ else if (n % 10 == 2)
+ return put_n_in(forms[1], n);
+ else
+ return put_n_in(forms[2], n);
+ case 14: // Gaeilge
+ EXPECT_LENGTH(5);
+ if (n == 1) // "ceann amhain"
+ return put_n_in(forms[0], n);
+ else if (n == 2) // "dha cheann"
+ return put_n_in(forms[1], n);
+ else if (n < 7) // "%n cinn"
+ return put_n_in(forms[2], n);
+ else if (n < 11) // "%n gcinn"
+ return put_n_in(forms[3], n);
+ else // "%n ceann"
+ return put_n_in(forms[4], n);
+ }
+ kdFatal() << "The function should have been returned in another way\n";
+
+ return QString::null;
+}
+
+QString KLocale::translateQt( const char *context, const char *source,
+ const char *message) const
+{
+ if (!source || !source[0]) {
+ kdWarning() << "KLocale: trying to look up \"\" in catalog. "
+ << "Fix the program" << endl;
+ return QString::null;
+ }
+
+ if ( useDefaultLanguage() ) {
+ return QString::null;
+ }
+
+ char *newstring = 0;
+ const char *translation = 0;
+ QString r;
+
+ if ( message && message[0]) {
+ char *newstring = new char[strlen(source) + strlen(message) + 5];
+ sprintf(newstring, "_: %s\n%s", source, message);
+ const char *translation = 0;
+ // as copying QString is very fast, it looks slower as it is ;/
+ r = translate_priv(newstring, source, &translation);
+ delete [] newstring;
+ if (translation)
+ return r;
+ }
+
+ if ( context && context[0] && message && message[0]) {
+ newstring = new char[strlen(context) + strlen(message) + 5];
+ sprintf(newstring, "_: %s\n%s", context, message);
+ // as copying QString is very fast, it looks slower as it is ;/
+ r = translate_priv(newstring, source, &translation);
+ delete [] newstring;
+ if (translation)
+ return r;
+ }
+
+ r = translate_priv(source, source, &translation);
+ if (translation)
+ return r;
+ return QString::null;
+}
+
+bool KLocale::nounDeclension() const
+{
+ doFormatInit();
+ return d->nounDeclension;
+}
+
+bool KLocale::dateMonthNamePossessive() const
+{
+ doFormatInit();
+ return d->dateMonthNamePossessive;
+}
+
+int KLocale::weekStartDay() const
+{
+ doFormatInit();
+ return d->weekStartDay;
+}
+
+bool KLocale::weekStartsMonday() const //deprecated
+{
+ doFormatInit();
+ return (d->weekStartDay==1);
+}
+
+QString KLocale::decimalSymbol() const
+{
+ doFormatInit();
+ return m_decimalSymbol;
+}
+
+QString KLocale::thousandsSeparator() const
+{
+ doFormatInit();
+ return m_thousandsSeparator;
+}
+
+QString KLocale::currencySymbol() const
+{
+ doFormatInit();
+ return m_currencySymbol;
+}
+
+QString KLocale::monetaryDecimalSymbol() const
+{
+ doFormatInit();
+ return m_monetaryDecimalSymbol;
+}
+
+QString KLocale::monetaryThousandsSeparator() const
+{
+ doFormatInit();
+ return m_monetaryThousandsSeparator;
+}
+
+QString KLocale::positiveSign() const
+{
+ doFormatInit();
+ return m_positiveSign;
+}
+
+QString KLocale::negativeSign() const
+{
+ doFormatInit();
+ return m_negativeSign;
+}
+
+int KLocale::fracDigits() const
+{
+ doFormatInit();
+ return m_fracDigits;
+}
+
+bool KLocale::positivePrefixCurrencySymbol() const
+{
+ doFormatInit();
+ return m_positivePrefixCurrencySymbol;
+}
+
+bool KLocale::negativePrefixCurrencySymbol() const
+{
+ doFormatInit();
+ return m_negativePrefixCurrencySymbol;
+}
+
+KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
+{
+ doFormatInit();
+ return m_positiveMonetarySignPosition;
+}
+
+KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
+{
+ doFormatInit();
+ return m_negativeMonetarySignPosition;
+}
+
+static inline void put_it_in( QChar *buffer, uint& index, const QString &s )
+{
+ for ( uint l = 0; l < s.length(); l++ )
+ buffer[index++] = s.at( l );
+}
+
+static inline void put_it_in( QChar *buffer, uint& index, int number )
+{
+ buffer[index++] = number / 10 + '0';
+ buffer[index++] = number % 10 + '0';
+}
+
+// insert (thousands)-"separator"s into the non-fractional part of str
+static void _insertSeparator(QString &str, const QString &separator,
+ const QString &decimalSymbol)
+{
+ // leave fractional part untouched
+ QString mainPart = str.section(decimalSymbol, 0, 0);
+ QString fracPart = str.section(decimalSymbol, 1, 1,
+ QString::SectionIncludeLeadingSep);
+
+ for (int pos = mainPart.length() - 3; pos > 0; pos -= 3)
+ mainPart.insert(pos, separator);
+
+ str = mainPart + fracPart;
+}
+
+QString KLocale::formatMoney(double num,
+ const QString & symbol,
+ int precision) const
+{
+ // some defaults
+ QString currency = symbol.isNull()
+ ? currencySymbol()
+ : symbol;
+ if (precision < 0) precision = fracDigits();
+
+ // the number itself
+ bool neg = num < 0;
+ QString res = QString::number(neg?-num:num, 'f', precision);
+
+ // Replace dot with locale decimal separator
+ res.replace(QChar('.'), monetaryDecimalSymbol());
+
+ // Insert the thousand separators
+ _insertSeparator(res, monetaryThousandsSeparator(), monetaryDecimalSymbol());
+
+ // set some variables we need later
+ int signpos = neg
+ ? negativeMonetarySignPosition()
+ : positiveMonetarySignPosition();
+ QString sign = neg
+ ? negativeSign()
+ : positiveSign();
+
+ switch (signpos)
+ {
+ case ParensAround:
+ res.prepend('(');
+ res.append (')');
+ break;
+ case BeforeQuantityMoney:
+ res.prepend(sign);
+ break;
+ case AfterQuantityMoney:
+ res.append(sign);
+ break;
+ case BeforeMoney:
+ currency.prepend(sign);
+ break;
+ case AfterMoney:
+ currency.append(sign);
+ break;
+ }
+
+ if (neg?negativePrefixCurrencySymbol():
+ positivePrefixCurrencySymbol())
+ {
+ res.prepend(' ');
+ res.prepend(currency);
+ } else {
+ res.append (' ');
+ res.append (currency);
+ }
+
+ return res;
+}
+
+QString KLocale::formatMoney(const QString &numStr) const
+{
+ return formatMoney(numStr.toDouble());
+}
+
+QString KLocale::formatNumber(double num, int precision) const
+{
+ if (precision == -1) precision = 2;
+ // no need to round since QString::number does this for us
+ return formatNumber(QString::number(num, 'f', precision), false, 0);
+}
+
+QString KLocale::formatLong(long num) const
+{
+ return formatNumber((double)num, 0);
+}
+
+QString KLocale::formatNumber(const QString &numStr) const
+{
+ return formatNumber(numStr, true, 2);
+}
+
+// increase the digit at 'position' by one
+static void _inc_by_one(QString &str, int position)
+{
+ for (int i = position; i >= 0; i--)
+ {
+ char last_char = str[i].latin1();
+ switch(last_char)
+ {
+ case '0':
+ str[i] = '1';
+ break;
+ case '1':
+ str[i] = '2';
+ break;
+ case '2':
+ str[i] = '3';
+ break;
+ case '3':
+ str[i] = '4';
+ break;
+ case '4':
+ str[i] = '5';
+ break;
+ case '5':
+ str[i] = '6';
+ break;
+ case '6':
+ str[i] = '7';
+ break;
+ case '7':
+ str[i] = '8';
+ break;
+ case '8':
+ str[i] = '9';
+ break;
+ case '9':
+ str[i] = '0';
+ if (i == 0) str.prepend('1');
+ continue;
+ case '.':
+ continue;
+ }
+ break;
+ }
+}
+
+// Cut off if more digits in fractional part than 'precision'
+static void _round(QString &str, int precision)
+{
+ int decimalSymbolPos = str.find('.');
+
+ if (decimalSymbolPos == -1)
+ if (precision == 0) return;
+ else if (precision > 0) // add dot if missing (and needed)
+ {
+ str.append('.');
+ decimalSymbolPos = str.length() - 1;
+ }
+
+ // fill up with more than enough zeroes (in case fractional part too short)
+ str.append(QString().fill('0', precision));
+
+ // Now decide whether to round up or down
+ char last_char = str[decimalSymbolPos + precision + 1].latin1();
+ switch (last_char)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ // nothing to do, rounding down
+ break;
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ _inc_by_one(str, decimalSymbolPos + precision);
+ break;
+ default:
+ break;
+ }
+
+ decimalSymbolPos = str.find('.');
+ str.truncate(decimalSymbolPos + precision + 1);
+
+ // if precision == 0 delete also '.'
+ if (precision == 0) str = str.section('.', 0, 0);
+}
+
+QString KLocale::formatNumber(const QString &numStr, bool round,
+ int precision) const
+{
+ QString tmpString = numStr;
+ if ((round && precision < 0) ||
+ ! QRegExp("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$").exactMatch(tmpString))
+ return numStr;
+
+
+ // Skip the sign (for now)
+ bool neg = (tmpString[0] == '-');
+ if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
+
+ // Split off exponential part (including 'e'-symbol)
+ QString mantString = tmpString.section('e', 0, 0,
+ QString::SectionCaseInsensitiveSeps);
+ QString expString = tmpString.section('e', 1, 1,
+ QString::SectionCaseInsensitiveSeps |
+ QString::SectionIncludeLeadingSep);
+
+ if (round) _round(mantString, precision);
+
+ // Replace dot with locale decimal separator
+ mantString.replace(QChar('.'), decimalSymbol());
+
+ // Insert the thousand separators
+ _insertSeparator(mantString, thousandsSeparator(), decimalSymbol());
+
+ // How can we know where we should put the sign?
+ mantString.prepend(neg?negativeSign():positiveSign());
+
+ return mantString + expString;
+}
+
+QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
+{
+ const QString rst = shortFormat?dateFormatShort():dateFormat();
+
+ QString buffer;
+
+ if ( ! pDate.isValid() ) return buffer;
+
+ bool escape = false;
+
+ int year = calendar()->year(pDate);
+ int month = calendar()->month(pDate);
+
+ for ( uint format_index = 0; format_index < rst.length(); ++format_index )
+ {
+ if ( !escape )
+ {
+ if ( rst.at( format_index ).unicode() == '%' )
+ escape = true;
+ else
+ buffer.append(rst.at(format_index));
+ }
+ else
+ {
+ switch ( rst.at( format_index ).unicode() )
+ {
+ case '%':
+ buffer.append('%');
+ break;
+ case 'Y':
+ buffer.append(calendar()->yearString(pDate, false));
+ break;
+ case 'y':
+ buffer.append(calendar()->yearString(pDate, true));
+ break;
+ case 'n':
+ buffer.append(calendar()->monthString(pDate, true));
+ break;
+ case 'e':
+ buffer.append(calendar()->dayString(pDate, true));
+ break;
+ case 'm':
+ buffer.append(calendar()->monthString(pDate, false));
+ break;
+ case 'b':
+ if (d->nounDeclension && d->dateMonthNamePossessive)
+ buffer.append(calendar()->monthNamePossessive(month, year, true));
+ else
+ buffer.append(calendar()->monthName(month, year, true));
+ break;
+ case 'B':
+ if (d->nounDeclension && d->dateMonthNamePossessive)
+ buffer.append(calendar()->monthNamePossessive(month, year, false));
+ else
+ buffer.append(calendar()->monthName(month, year, false));
+ break;
+ case 'd':
+ buffer.append(calendar()->dayString(pDate, false));
+ break;
+ case 'a':
+ buffer.append(calendar()->weekDayName(pDate, true));
+ break;
+ case 'A':
+ buffer.append(calendar()->weekDayName(pDate, false));
+ break;
+ default:
+ buffer.append(rst.at(format_index));
+ break;
+ }
+ escape = false;
+ }
+ }
+ return buffer;
+}
+
+void KLocale::setMainCatalogue(const char *catalog)
+{
+ maincatalogue = catalog;
+}
+
+double KLocale::readNumber(const QString &_str, bool * ok) const
+{
+ QString str = _str.stripWhiteSpace();
+ bool neg = str.find(negativeSign()) == 0;
+ if (neg)
+ str.remove( 0, negativeSign().length() );
+
+ /* will hold the scientific notation portion of the number.
+ Example, with 2.34E+23, exponentialPart == "E+23"
+ */
+ QString exponentialPart;
+ int EPos;
+
+ EPos = str.find('E', 0, false);
+
+ if (EPos != -1)
+ {
+ exponentialPart = str.mid(EPos);
+ str = str.left(EPos);
+ }
+
+ int pos = str.find(decimalSymbol());
+ QString major;
+ QString minor;
+ if ( pos == -1 )
+ major = str;
+ else
+ {
+ major = str.left(pos);
+ minor = str.mid(pos + decimalSymbol().length());
+ }
+
+ // Remove thousand separators
+ int thlen = thousandsSeparator().length();
+ int lastpos = 0;
+ while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
+ {
+ // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
+ int fromEnd = major.length() - pos;
+ if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
+ || pos - lastpos > 3 // More than 3 digits between two separators -> error
+ || pos == 0 // Can't start with a separator
+ || (lastpos>0 && pos-lastpos!=3)) // Must have exactly 3 digits between two separators
+ {
+ if (ok) *ok = false;
+ return 0.0;
+ }
+
+ lastpos = pos;
+ major.remove( pos, thlen );
+ }
+ if (lastpos>0 && major.length()-lastpos!=3) // Must have exactly 3 digits after the last separator
+ {
+ if (ok) *ok = false;
+ return 0.0;
+ }
+
+ QString tot;
+ if (neg) tot = '-';
+
+ tot += major + '.' + minor + exponentialPart;
+
+ return tot.toDouble(ok);
+}
+
+double KLocale::readMoney(const QString &_str, bool * ok) const
+{
+ QString str = _str.stripWhiteSpace();
+ bool neg = false;
+ bool currencyFound = false;
+ QString symbol = currencySymbol();
+ // First try removing currency symbol from either end
+ int pos = str.find(symbol);
+ if ( pos == 0 || pos == (int) str.length()-symbol.length() )
+ {
+ str.remove(pos,symbol.length());
+ str = str.stripWhiteSpace();
+ currencyFound = true;
+ }
+ if (str.isEmpty())
+ {
+ if (ok) *ok = false;
+ return 0;
+ }
+ // Then try removing negative sign from either end
+ // (with a special case for parenthesis)
+ if (negativeMonetarySignPosition() == ParensAround)
+ {
+ if (str[0] == '(' && str[str.length()-1] == ')')
+ {
+ neg = true;
+ str.remove(str.length()-1,1);
+ str.remove(0,1);
+ }
+ }
+ else
+ {
+ int i1 = str.find(negativeSign());
+ if ( i1 == 0 || i1 == (int) str.length()-1 )
+ {
+ neg = true;
+ str.remove(i1,negativeSign().length());
+ }
+ }
+ if (neg) str = str.stripWhiteSpace();
+
+ // Finally try again for the currency symbol, if we didn't find
+ // it already (because of the negative sign being in the way).
+ if ( !currencyFound )
+ {
+ pos = str.find(symbol);
+ if ( pos == 0 || pos == (int) str.length()-symbol.length() )
+ {
+ str.remove(pos,symbol.length());
+ str = str.stripWhiteSpace();
+ }
+ }
+
+ // And parse the rest as a number
+ pos = str.find(monetaryDecimalSymbol());
+ QString major;
+ QString minior;
+ if (pos == -1)
+ major = str;
+ else
+ {
+ major = str.left(pos);
+ minior = str.mid(pos + monetaryDecimalSymbol().length());
+ }
+
+ // Remove thousand separators
+ int thlen = monetaryThousandsSeparator().length();
+ int lastpos = 0;
+ while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
+ {
+ // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
+ int fromEnd = major.length() - pos;
+ if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
+ || pos - lastpos > 3 // More than 3 digits between two separators -> error
+ || pos == 0 // Can't start with a separator
+ || (lastpos>0 && pos-lastpos!=3)) // Must have exactly 3 digits between two separators
+ {
+ if (ok) *ok = false;
+ return 0.0;
+ }
+ lastpos = pos;
+ major.remove( pos, thlen );
+ }
+ if (lastpos>0 && major.length()-lastpos!=3) // Must have exactly 3 digits after the last separator
+ {
+ if (ok) *ok = false;
+ return 0.0;
+ }
+
+ QString tot;
+ if (neg) tot = '-';
+ tot += major + '.' + minior;
+ return tot.toDouble(ok);
+}
+
+/**
+ * helper function to read integers
+ * @param str
+ * @param pos the position to start at. It will be updated when we parse it.
+ * @return the integer read in the string, or -1 if no string
+ */
+static int readInt(const QString &str, uint &pos)
+{
+ if (!str.at(pos).isDigit()) return -1;
+ int result = 0;
+ for (; str.length() > pos && str.at(pos).isDigit(); pos++)
+ {
+ result *= 10;
+ result += str.at(pos).digitValue();
+ }
+
+ return result;
+}
+
+QDate KLocale::readDate(const QString &intstr, bool* ok) const
+{
+ QDate date;
+ date = readDate(intstr, ShortFormat, ok);
+ if (date.isValid()) return date;
+ return readDate(intstr, NormalFormat, ok);
+}
+
+QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
+{
+ QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
+ return readDate( intstr, fmt, ok );
+}
+
+QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
+{
+ //kdDebug() << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl;
+ QString str = intstr.simplifyWhiteSpace().lower();
+ int day = -1, month = -1;
+ // allow the year to be omitted if not in the format
+ int year = calendar()->year(QDate::currentDate());
+ uint strpos = 0;
+ uint fmtpos = 0;
+
+ int iLength; // Temporary variable used when reading input
+
+ bool error = false;
+
+ while (fmt.length() > fmtpos && str.length() > strpos && !error)
+ {
+
+ QChar c = fmt.at(fmtpos++);
+
+ if (c != '%') {
+ if (c.isSpace() && str.at(strpos).isSpace())
+ strpos++;
+ else if (c != str.at(strpos++))
+ error = true;
+ }
+ else
+ {
+ int j;
+ // remove space at the beginning
+ if (str.length() > strpos && str.at(strpos).isSpace())
+ strpos++;
+
+ c = fmt.at(fmtpos++);
+ switch (c)
+ {
+ case 'a':
+ case 'A':
+
+ error = true;
+ j = 1;
+ while (error && (j < 8)) {
+ QString s = calendar()->weekDayName(j, c == 'a').lower();
+ int len = s.length();
+ if (str.mid(strpos, len) == s)
+ {
+ strpos += len;
+ error = false;
+ }
+ j++;
+ }
+ break;
+ case 'b':
+ case 'B':
+
+ error = true;
+ if (d->nounDeclension && d->dateMonthNamePossessive) {
+ j = 1;
+ while (error && (j < 13)) {
+ QString s = calendar()->monthNamePossessive(j, year, c == 'b').lower();
+ int len = s.length();
+ if (str.mid(strpos, len) == s) {
+ month = j;
+ strpos += len;
+ error = false;
+ }
+ j++;
+ }
+ }
+ j = 1;
+ while (error && (j < 13)) {
+ QString s = calendar()->monthName(j, year, c == 'b').lower();
+ int len = s.length();
+ if (str.mid(strpos, len) == s) {
+ month = j;
+ strpos += len;
+ error = false;
+ }
+ j++;
+ }
+ break;
+ case 'd':
+ case 'e':
+ day = calendar()->dayStringToInteger(str.mid(strpos), iLength);
+ strpos += iLength;
+
+ error = iLength <= 0;
+ break;
+
+ case 'n':
+ case 'm':
+ month = calendar()->monthStringToInteger(str.mid(strpos), iLength);
+ strpos += iLength;
+
+ error = iLength <= 0;
+ break;
+
+ case 'Y':
+ case 'y':
+ year = calendar()->yearStringToInteger(str.mid(strpos), iLength);
+ strpos += iLength;
+
+ error = iLength <= 0;
+ break;
+ }
+ }
+ }
+
+ /* for a match, we should reach the end of both strings, not just one of
+ them */
+ if ( fmt.length() > fmtpos || str.length() > strpos )
+ {
+ error = true;
+ }
+
+ //kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl;
+ if ( year != -1 && month != -1 && day != -1 && !error)
+ {
+ if (ok) *ok = true;
+
+ QDate result;
+ calendar()->setYMD(result, year, month, day);
+
+ return result;
+ }
+ else
+ {
+ if (ok) *ok = false;
+ return QDate(); // invalid date
+ }
+}
+
+QTime KLocale::readTime(const QString &intstr, bool *ok) const
+{
+ QTime _time;
+ _time = readTime(intstr, WithSeconds, ok);
+ if (_time.isValid()) return _time;
+ return readTime(intstr, WithoutSeconds, ok);
+}
+
+QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const
+{
+ QString str = intstr.simplifyWhiteSpace().lower();
+ QString Format = timeFormat().simplifyWhiteSpace();
+ if (flags & WithoutSeconds)
+ Format.remove(QRegExp(".%S"));
+
+ int hour = -1, minute = -1;
+ int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0; // don't require seconds
+ bool g_12h = false;
+ bool pm = false;
+ uint strpos = 0;
+ uint Formatpos = 0;
+
+ while (Format.length() > Formatpos || str.length() > strpos)
+ {
+ if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
+
+ QChar c = Format.at(Formatpos++);
+
+ if (c != '%')
+ {
+ if (c.isSpace())
+ strpos++;
+ else if (c != str.at(strpos++))
+ goto error;
+ continue;
+ }
+
+ // remove space at the beginning
+ if (str.length() > strpos && str.at(strpos).isSpace())
+ strpos++;
+
+ c = Format.at(Formatpos++);
+ switch (c)
+ {
+ case 'p':
+ {
+ QString s;
+ s = translate("pm").lower();
+ int len = s.length();
+ if (str.mid(strpos, len) == s)
+ {
+ pm = true;
+ strpos += len;
+ }
+ else
+ {
+ s = translate("am").lower();
+ len = s.length();
+ if (str.mid(strpos, len) == s) {
+ pm = false;
+ strpos += len;
+ }
+ else
+ goto error;
+ }
+ }
+ break;
+
+ case 'k':
+ case 'H':
+ g_12h = false;
+ hour = readInt(str, strpos);
+ if (hour < 0 || hour > 23)
+ goto error;
+
+ break;
+
+ case 'l':
+ case 'I':
+ g_12h = true;
+ hour = readInt(str, strpos);
+ if (hour < 1 || hour > 12)
+ goto error;
+
+ break;
+
+ case 'M':
+ minute = readInt(str, strpos);
+ if (minute < 0 || minute > 59)
+ goto error;
+
+ break;
+
+ case 'S':
+ second = readInt(str, strpos);
+ if (second < 0 || second > 59)
+ goto error;
+
+ break;
+ }
+ }
+ if (g_12h) {
+ hour %= 12;
+ if (pm) hour += 12;
+ }
+
+ if (ok) *ok = true;
+ return QTime(hour, minute, second);
+
+ error:
+ if (ok) *ok = false;
+ // ######## KDE4: remove this
+ return QTime(-1, -1, -1); // return invalid date if it didn't work
+}
+
+//BIC: merge with below
+QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const
+{
+ return formatTime( pTime, includeSecs, false );
+}
+
+QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
+{
+ const QString rst = timeFormat();
+
+ // only "pm/am" here can grow, the rest shrinks, but
+ // I'm rather safe than sorry
+ QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
+
+ uint index = 0;
+ bool escape = false;
+ int number = 0;
+
+ for ( uint format_index = 0; format_index < rst.length(); format_index++ )
+ {
+ if ( !escape )
+ {
+ if ( rst.at( format_index ).unicode() == '%' )
+ escape = true;
+ else
+ buffer[index++] = rst.at( format_index );
+ }
+ else
+ {
+ switch ( rst.at( format_index ).unicode() )
+ {
+ case '%':
+ buffer[index++] = '%';
+ break;
+ case 'H':
+ put_it_in( buffer, index, pTime.hour() );
+ break;
+ case 'I':
+ if ( isDuration )
+ put_it_in( buffer, index, pTime.hour() );
+ else
+ put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
+ break;
+ case 'M':
+ put_it_in( buffer, index, pTime.minute() );
+ break;
+ case 'S':
+ if (includeSecs)
+ put_it_in( buffer, index, pTime.second() );
+ else if ( index > 0 )
+ {
+ // we remove the separator sign before the seconds and
+ // assume that works everywhere
+ --index;
+ break;
+ }
+ break;
+ case 'k':
+ number = pTime.hour();
+ case 'l':
+ // to share the code
+ if ( rst.at( format_index ).unicode() == 'l' )
+ number = isDuration ? pTime.hour() : (pTime.hour() + 11) % 12 + 1;
+ if ( number / 10 )
+ buffer[index++] = number / 10 + '0';
+ buffer[index++] = number % 10 + '0';
+ break;
+ case 'p':
+ if ( !isDuration )
+ {
+ QString s;
+ if ( pTime.hour() >= 12 )
+ put_it_in( buffer, index, translate("pm") );
+ else
+ put_it_in( buffer, index, translate("am") );
+ }
+ break;
+ default:
+ buffer[index++] = rst.at( format_index );
+ break;
+ }
+ escape = false;
+ }
+ }
+ QString ret( buffer, index );
+ delete [] buffer;
+ if ( isDuration ) // eliminate trailing-space due to " %p"
+ return ret.stripWhiteSpace();
+ else
+ return ret;
+}
+
+bool KLocale::use12Clock() const
+{
+ if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
+ (timeFormat().contains(QString::fromLatin1("%l")) > 0))
+ return true;
+ else
+ return false;
+}
+
+QString KLocale::languages() const
+{
+ return d->languageList.join( QString::fromLatin1(":") );
+}
+
+QStringList KLocale::languageList() const
+{
+ return d->languageList;
+}
+
+QString KLocale::formatDateTime(const QDateTime &pDateTime,
+ bool shortFormat,
+ bool includeSeconds) const
+{
+ return translate("concatenation of dates and time", "%1 %2")
+ .arg( formatDate( pDateTime.date(), shortFormat ) )
+ .arg( formatTime( pDateTime.time(), includeSeconds ) );
+}
+
+QString i18n(const char* text)
+{
+ register KLocale *instance = KGlobal::locale();
+ if (instance)
+ return instance->translate(text);
+ return QString::fromUtf8(text);
+}
+
+QString i18n(const char* index, const char *text)
+{
+ register KLocale *instance = KGlobal::locale();
+ if (instance)
+ return instance->translate(index, text);
+ return QString::fromUtf8(text);
+}
+
+QString i18n(const char* singular, const char* plural, unsigned long n)
+{
+ register KLocale *instance = KGlobal::locale();
+ if (instance)
+ return instance->translate(singular, plural, n);
+ if (n == 1)
+ return put_n_in(QString::fromUtf8(singular), n);
+ else
+ return put_n_in(QString::fromUtf8(plural), n);
+}
+
+void KLocale::initInstance()
+{
+ if (KGlobal::_locale)
+ return;
+
+ KInstance *app = KGlobal::instance();
+ if (app) {
+ KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName()));
+
+ // only do this for the global instance
+ QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding());
+ }
+ else
+ kdDebug(173) << "no app name available using KLocale - nothing to do\n";
+}
+
+QString KLocale::langLookup(const QString &fname, const char *rtype)
+{
+ QStringList search;
+
+ // assemble the local search paths
+ const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
+
+ // look up the different languages
+ for (int id=localDoc.count()-1; id >= 0; --id)
+ {
+ QStringList langs = KGlobal::locale()->languageList();
+ langs.append( "en" );
+ langs.remove( defaultLanguage() );
+ QStringList::ConstIterator lang;
+ for (lang = langs.begin(); lang != langs.end(); ++lang)
+ search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
+ }
+
+ // try to locate the file
+ QStringList::Iterator it;
+ for (it = search.begin(); it != search.end(); ++it)
+ {
+ kdDebug(173) << "Looking for help in: " << *it << endl;
+
+ QFileInfo info(*it);
+ if (info.exists() && info.isFile() && info.isReadable())
+ return *it;
+ }
+
+ return QString::null;
+}
+
+bool KLocale::useDefaultLanguage() const
+{
+ return language() == defaultLanguage();
+}
+
+void KLocale::initEncoding(KConfig *)
+{
+ const int mibDefault = 4; // ISO 8859-1
+
+ // This all made more sense when we still had the EncodingEnum config key.
+ setEncoding( QTextCodec::codecForLocale()->mibEnum() );
+
+ if ( !d->codecForEncoding )
+ {
+ kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl;
+ setEncoding(mibDefault);
+ }
+
+ Q_ASSERT( d->codecForEncoding );
+}
+
+void KLocale::initFileNameEncoding(KConfig *)
+{
+ // If the following environment variable is set, assume all filenames
+ // are in UTF-8 regardless of the current C locale.
+ d->utf8FileEncoding = getenv("KDE_UTF8_FILENAMES") != 0;
+ if (d->utf8FileEncoding)
+ {
+ QFile::setEncodingFunction(KLocale::encodeFileNameUTF8);
+ QFile::setDecodingFunction(KLocale::decodeFileNameUTF8);
+ }
+ // Otherwise, stay with QFile's default filename encoding functions
+ // which, on Unix platforms, use the locale's codec.
+}
+
+QCString KLocale::encodeFileNameUTF8( const QString & fileName )
+{
+ return fileName.utf8();
+}
+
+QString KLocale::decodeFileNameUTF8( const QCString & localFileName )
+{
+ return QString::fromUtf8(localFileName);
+}
+
+void KLocale::setDateFormat(const QString & format)
+{
+ doFormatInit();
+ m_dateFormat = format.stripWhiteSpace();
+}
+
+void KLocale::setDateFormatShort(const QString & format)
+{
+ doFormatInit();
+ m_dateFormatShort = format.stripWhiteSpace();
+}
+
+void KLocale::setDateMonthNamePossessive(bool possessive)
+{
+ doFormatInit();
+ d->dateMonthNamePossessive = possessive;
+}
+
+void KLocale::setTimeFormat(const QString & format)
+{
+ doFormatInit();
+ m_timeFormat = format.stripWhiteSpace();
+}
+
+void KLocale::setWeekStartsMonday(bool start) //deprecated
+{
+ doFormatInit();
+ if (start)
+ d->weekStartDay = 1;
+ else
+ d->weekStartDay = 7;
+}
+
+void KLocale::setWeekStartDay(int day)
+{
+ doFormatInit();
+ if (day>7 || day<1)
+ d->weekStartDay = 1; //Monday is default
+ else
+ d->weekStartDay = day;
+}
+
+QString KLocale::dateFormat() const
+{
+ doFormatInit();
+ return m_dateFormat;
+}
+
+QString KLocale::dateFormatShort() const
+{
+ doFormatInit();
+ return m_dateFormatShort;
+}
+
+QString KLocale::timeFormat() const
+{
+ doFormatInit();
+ return m_timeFormat;
+}
+
+void KLocale::setDecimalSymbol(const QString & symbol)
+{
+ doFormatInit();
+ m_decimalSymbol = symbol.stripWhiteSpace();
+}
+
+void KLocale::setThousandsSeparator(const QString & separator)
+{
+ doFormatInit();
+ // allow spaces here
+ m_thousandsSeparator = separator;
+}
+
+void KLocale::setPositiveSign(const QString & sign)
+{
+ doFormatInit();
+ m_positiveSign = sign.stripWhiteSpace();
+}
+
+void KLocale::setNegativeSign(const QString & sign)
+{
+ doFormatInit();
+ m_negativeSign = sign.stripWhiteSpace();
+}
+
+void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
+{
+ doFormatInit();
+ m_positiveMonetarySignPosition = signpos;
+}
+
+void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
+{
+ doFormatInit();
+ m_negativeMonetarySignPosition = signpos;
+}
+
+void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
+{
+ doFormatInit();
+ m_positivePrefixCurrencySymbol = prefix;
+}
+
+void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
+{
+ doFormatInit();
+ m_negativePrefixCurrencySymbol = prefix;
+}
+
+void KLocale::setFracDigits(int digits)
+{
+ doFormatInit();
+ m_fracDigits = digits;
+}
+
+void KLocale::setMonetaryThousandsSeparator(const QString & separator)
+{
+ doFormatInit();
+ // allow spaces here
+ m_monetaryThousandsSeparator = separator;
+}
+
+void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
+{
+ doFormatInit();
+ m_monetaryDecimalSymbol = symbol.stripWhiteSpace();
+}
+
+void KLocale::setCurrencySymbol(const QString & symbol)
+{
+ doFormatInit();
+ m_currencySymbol = symbol.stripWhiteSpace();
+}
+
+int KLocale::pageSize() const
+{
+ doFormatInit();
+ return d->pageSize;
+}
+
+void KLocale::setPageSize(int pageSize)
+{
+ // #### check if it's in range??
+ doFormatInit();
+ d->pageSize = pageSize;
+}
+
+KLocale::MeasureSystem KLocale::measureSystem() const
+{
+ doFormatInit();
+ return d->measureSystem;
+}
+
+void KLocale::setMeasureSystem(MeasureSystem value)
+{
+ doFormatInit();
+ d->measureSystem = value;
+}
+
+QString KLocale::defaultLanguage()
+{
+ return QString::fromLatin1("en_US");
+}
+
+QString KLocale::defaultCountry()
+{
+ return QString::fromLatin1("C");
+}
+
+const char * KLocale::encoding() const
+{
+#ifdef Q_WS_WIN
+ if (0==qstrcmp("System", codecForEncoding()->name()))
+ {
+ //win32 returns "System" codec name here but KDE apps expect a real name:
+ strcpy(d->win32SystemEncoding, "cp ");
+ if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT),
+ LOCALE_IDEFAULTANSICODEPAGE, d->win32SystemEncoding+3, sizeof(d->win32SystemEncoding)-3-1 ))
+ {
+ return d->win32SystemEncoding;
+ }
+ }
+#endif
+ return codecForEncoding()->name();
+}
+
+int KLocale::encodingMib() const
+{
+ return codecForEncoding()->mibEnum();
+}
+
+int KLocale::fileEncodingMib() const
+{
+ if (d->utf8FileEncoding)
+ return 106;
+ return codecForEncoding()->mibEnum();
+}
+
+QTextCodec * KLocale::codecForEncoding() const
+{
+ return d->codecForEncoding;
+}
+
+bool KLocale::setEncoding(int mibEnum)
+{
+ QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
+ if (codec)
+ d->codecForEncoding = codec;
+
+ return codec != 0;
+}
+
+QStringList KLocale::languagesTwoAlpha() const
+{
+ if (d->langTwoAlpha.count())
+ return d->langTwoAlpha;
+
+ const QStringList &origList = languageList();
+
+ QStringList result;
+
+ KConfig config(QString::fromLatin1("language.codes"), true, false);
+ config.setGroup("TwoLetterCodes");
+
+ for ( QStringList::ConstIterator it = origList.begin();
+ it != origList.end();
+ ++it )
+ {
+ QString lang = *it;
+ QStringList langLst;
+ if (config.hasKey( lang ))
+ langLst = config.readListEntry( lang );
+ else
+ {
+ int i = lang.find('_');
+ if (i >= 0)
+ lang.truncate(i);
+ langLst << lang;
+ }
+
+ for ( QStringList::ConstIterator langIt = langLst.begin();
+ langIt != langLst.end();
+ ++langIt )
+ {
+ if ( !(*langIt).isEmpty() && !result.contains( *langIt ) )
+ result += *langIt;
+ }
+ }
+ d->langTwoAlpha = result;
+ return result;
+}
+
+QStringList KLocale::allLanguagesTwoAlpha() const
+{
+ if (!d->languages)
+ d->languages = new KConfig("all_languages", true, false, "locale");
+
+ return d->languages->groupList();
+}
+
+QString KLocale::twoAlphaToLanguageName(const QString &code) const
+{
+ if (!d->languages)
+ d->languages = new KConfig("all_languages", true, false, "locale");
+
+ QString groupName = code;
+ const int i = groupName.find('_');
+ groupName.replace(0, i, groupName.left(i).lower());
+
+ d->languages->setGroup(groupName);
+ return d->languages->readEntry("Name");
+}
+
+QStringList KLocale::allCountriesTwoAlpha() const
+{
+ QStringList countries;
+ QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
+ for(QStringList::ConstIterator it = paths.begin();
+ it != paths.end(); ++it)
+ {
+ QString code = (*it).mid((*it).length()-16, 2);
+ if (code != "/C")
+ countries.append(code);
+ }
+ return countries;
+}
+
+QString KLocale::twoAlphaToCountryName(const QString &code) const
+{
+ KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale");
+ cfg.setGroup("KCM Locale");
+ return cfg.readEntry("Name");
+}
+
+void KLocale::setCalendar(const QString & calType)
+{
+ doFormatInit();
+
+ d->calendarType = calType;
+
+ delete d->calendar;
+ d->calendar = 0;
+}
+
+QString KLocale::calendarType() const
+{
+ doFormatInit();
+
+ return d->calendarType;
+}
+
+const KCalendarSystem * KLocale::calendar() const
+{
+ doFormatInit();
+
+ // Check if it's the correct calendar?!?
+ if ( !d->calendar )
+ d->calendar = KCalendarSystemFactory::create( d->calendarType, this );
+
+ return d->calendar;
+}
+
+KLocale::KLocale(const KLocale & rhs)
+{
+ d = new KLocalePrivate;
+
+ *this = rhs;
+}
+
+KLocale & KLocale::operator=(const KLocale & rhs)
+{
+ // Numbers and money
+ m_decimalSymbol = rhs.m_decimalSymbol;
+ m_thousandsSeparator = rhs.m_thousandsSeparator;
+ m_currencySymbol = rhs.m_currencySymbol;
+ m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
+ m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
+ m_positiveSign = rhs.m_positiveSign;
+ m_negativeSign = rhs.m_negativeSign;
+ m_fracDigits = rhs.m_fracDigits;
+ m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
+ m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
+ m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
+ m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
+
+ // Date and time
+ m_timeFormat = rhs.m_timeFormat;
+ m_dateFormat = rhs.m_dateFormat;
+ m_dateFormatShort = rhs.m_dateFormatShort;
+
+ m_language = rhs.m_language;
+ m_country = rhs.m_country;
+
+ // the assignment operator works here
+ *d = *rhs.d;
+ d->languages = 0; // Don't copy languages
+ d->calendar = 0; // Don't copy the calendar
+
+ return *this;
+}
+
+bool KLocale::setCharset(const QString & ) { return true; }
+QString KLocale::charset() const { return QString::fromLatin1("UTF-8"); }
+
+// KDE4: remove
+#if 0
+void nothing() { i18n("&Next"); }
+#endif
diff --git a/kdecore/klocale.h b/kdecore/klocale.h
new file mode 100644
index 000000000..437e4780c
--- /dev/null
+++ b/kdecore/klocale.h
@@ -0,0 +1,1340 @@
+// -*- c-basic-offset: 2 -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+ Copyright (C) 1999-2003 Hans Petter Bieker <bieker@kde.org>
+ Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KLOCALE_H
+#define _KLOCALE_H
+
+#include <qstring.h>
+#include <kdelibs_export.h>
+
+class QStringList;
+class QTextCodec;
+class QDate;
+class QTime;
+class QDateTime;
+
+class KGlobal;
+class KConfig;
+class KConfigBase;
+class KLocalePrivate;
+class KCatalogue;
+class KCalendarSystem;
+
+/**
+ * \file klocale.h
+ */
+
+#ifndef I18N_NOOP
+/**
+ * \relates KLocale
+ * I18N_NOOP marks a string to be translated without translating it.
+ * Do not use this unless you know you need it.
+ * http://developer.kde.org/documentation/other/developer-faq.html#q2.11.2
+ */
+#define I18N_NOOP(x) x
+#endif
+
+#ifndef I18N_NOOP2
+/**
+ * \relates KLocale
+ * If the string is too ambiguous to be translated well to a non-english
+ * language, use this instead of I18N_NOOP to separate lookup string and english.
+ * \warning You need to call i18n( comment, stringVar ) later on, not just i18n( stringVar ).
+ * \since 3.3
+ */
+#define I18N_NOOP2(comment,x) x
+#endif
+
+/**
+ * \relates KLocale
+ * i18n is the function that does everything you need to translate
+ * a string. You just wrap around every user visible string a i18n
+ * call to get a QString with the string in the user's preferred
+ * language.
+ *
+ * The argument must be an UTF-8 encoded string (If you only use
+ * characters that are in US-ASCII, you're on the safe side. But
+ * for e.g. German umlauts or French accents should be recoded to
+ * UTF-8)
+ **/
+KDECORE_EXPORT QString i18n(const char *text);
+
+/**
+ * \relates KLocale
+ * If the string is too ambiguous to be translated well to a non-english
+ * language, use this form of i18n to separate lookup string and english
+ * text.
+ * @see translate
+ **/
+KDECORE_EXPORT QString i18n(const char *comment, const char *text);
+
+/**
+ * \relates KLocale
+ * If you want to handle plural forms, use this form of i18n.
+ * @param singular the singular form of the word, for example "file".
+ * @param plural the plural form of the word. Must contain a "%n" that will
+ * be replaced by the number @p n, for example "%n files"
+ * @param n the number
+ * @return the correct singular or plural for the selected language,
+ * depending on n
+ * @see translate
+ **/
+KDECORE_EXPORT QString i18n(const char *singular, const char *plural, unsigned long n);
+
+/**
+ * \relates KLocale
+ * Qt3's uic generates i18n( "msg", "comment" ) calls which conflict
+ * with our i18n method. We use uic -tr tr2i18n to redirect
+ * to the right i18n() function
+**/
+inline QString tr2i18n(const char* message, const char* =0) {
+ return i18n(message);
+}
+
+/**
+ *
+ * KLocale provides support for country specific stuff like
+ * the national language.
+ *
+ * KLocale supports translating, as well as specifying the format
+ * for numbers, currency, time, and date.
+ *
+ * @author Stephan Kulow <coolo@kde.org>, Preston Brown <pbrown@kde.org>,
+ * Hans Petter Bieker <bieker@kde.org>, Lukas Tinkl <lukas.tinkl@suse.cz>
+ * @short class for supporting locale settings and national language
+ */
+class KDECORE_EXPORT KLocale
+{
+ friend class KGlobal; // for initInstance()
+public:
+ /**
+ * Constructs a KLocale with the given catalog name.
+ * The constructor looks for an entry Locale/Language in the
+ * configuration file.
+ * If no config file is specified, it will also look for languages
+ * using the environment variables (KDE_LANG, LC_MESSAGES, LC_ALL, LANG),
+ * as well as the global configuration file. If KLocale is not able to use
+ * any of the specified languages, the default language (en_US) will be
+ * used.
+ *
+ * If you specify a configuration file, it has to be valid until
+ * the KLocale object is destroyed.
+ *
+ * @param catalog The name of the main language file
+ * @param config The configuration file to use.
+ */
+ KLocale( const QString& catalog, KConfig *config = 0 );
+
+ /**
+ * Copy constructor.
+ */
+ KLocale( const KLocale & rhs );
+
+ /**
+ * Assignment operator.
+ */
+ KLocale& operator= ( const KLocale & rhs );
+
+ /**
+ * Destructor.
+ */
+ ~KLocale();
+
+ /**
+ * Translates the string into the corresponding string in
+ * the national language, if available. If not, returns
+ * the string itself.
+ * There is a KDE wide message file that contains the most
+ * often used phrases, so we can avoid duplicating the
+ * translation of these phrases. If a phrase is not found
+ * in the catalog given to the constructor, it will search
+ * in the system catalog. This makes it possible to override
+ * some phrases for your needs.
+ *
+ * The argument must be an UTF-8 encoded string (If you only use
+ * characters that are in US-ASCII you're on the safe side. But
+ * for e.g. german umlauts or french accents should be recoded to
+ * UTF-8)
+ *
+ * @param index The lookup text and default text, if not found.
+ */
+ QString translate( const char *index ) const;
+
+ /**
+ * Translates the string into the corresponding string in the
+ * national language, if available.
+ *
+ * The real contents of the string is in the argument fallback,
+ * but the meaning of it is coded into the argument index.
+ * In some cases you'll need this function, when english is
+ * too ambiguous to express it.
+ *
+ * Most of the times the translators will tell you if it can't
+ * be translated as it, but think of cases as "New", where the
+ * translations differs depending on what is New.
+ * Or simple cases as "Open", that can be used to express something
+ * is open or it can be used to express that you want something to
+ * open... There are tons of such examples.
+ *
+ * If translate("Open") is not enough to translate it well, use
+ * translate("To Open", "Open") or translate("Is Open", "Open").
+ * The english user will see "Open" in both cases, but the translated
+ * version may vary. Of course you can also use i18n()
+ *
+ * @param comment the comment. The lookup text is made out of comment + @p fallback
+ * @param fallback the default text, if not found
+ * @return translation
+ */
+ QString translate( const char *comment, const char *fallback) const;
+
+ /**
+ * Used to get the correct, translated singular or plural of a
+ * word.
+ * @param singular the singular form of the word, for example "file".
+ * @param plural the plural form of the word. Must contain a "%n" that will
+ * be replaced by the number @p n, for example "%n files"
+ * @param n the number
+ * @return the correct singular or plural for the selected language,
+ * depending on n
+ */
+ QString translate( const char *singular, const char *plural,
+ unsigned long n) const;
+
+ /**
+ * Changes the current encoding.
+ *
+ * @param mibEnum The mib of the preferred codec
+ *
+ * @return True on success.
+ */
+ bool setEncoding(int mibEnum);
+
+ /**
+ * Changes the current language. The current language will be left
+ * unchanged if failed. It will force a reload of the country specific
+ * configuration as well.
+ *
+ * @param language The language code.
+ *
+ * @return True on success.
+ */
+ bool setLanguage(const QString & language);
+
+ /**
+ * Changes the list of prefed languages for the locale. The first valid
+ * language in the list will be used, or the default (en_US) language
+ * will be used if non of the specified languages were available.
+ *
+ * @param languages The list of language codes.
+ *
+ * @return True if one of the specified languages were used.
+ */
+ bool setLanguage(const QStringList & languages);
+
+ /**
+ * Changes the current country. The current country will be left
+ * unchanged if failed. It will force a reload of the country specific
+ * configuration.
+ *
+ * @param country The ISO 3166 country code.
+ *
+ * @return True on success.
+ */
+ bool setCountry(const QString & country);
+
+ /**
+ * Various positions for where to place the positive or negative
+ * sign when they are related to a monetary value.
+ */
+ enum SignPosition { ParensAround = 0, BeforeQuantityMoney = 1,
+ AfterQuantityMoney = 2,
+ BeforeMoney = 3, AfterMoney = 4 };
+
+ /**
+ * Returns what a decimal point should look like ("." or "," etc.)
+ * according to the current locale or user settings.
+ *
+ * @return The decimal symbol used by locale.
+ */
+ QString decimalSymbol() const;
+
+ /**
+ * Returns what the thousands separator should look
+ * like ("," or "." etc.)
+ * according to the current locale or user settings.
+ *
+ * @return The thousands separator used by locale.
+ */
+ QString thousandsSeparator() const;
+
+ /**
+ * Returns what the symbol denoting currency in the current locale
+ * as as defined by user settings should look like.
+ *
+ * @return The default currency symbol used by locale.
+ */
+ QString currencySymbol() const;
+
+ /**
+ * Returns what a decimal point should look like ("." or "," etc.)
+ * for monetary values, according to the current locale or user
+ * settings.
+ *
+ * @return The monetary decimal symbol used by locale.
+ */
+ QString monetaryDecimalSymbol() const;
+
+ /**
+ * Returns what a thousands separator for monetary values should
+ * look like ("," or " " etc.) according to the current locale or
+ * user settings.
+ *
+ * @return The monetary thousands separator used by locale.
+ */
+ QString monetaryThousandsSeparator() const;
+
+ /**
+ * Returns what a positive sign should look like ("+", " ", etc.)
+ * according to the current locale or user settings.
+ *
+ * @return The positive sign used by locale.
+ */
+ QString positiveSign() const;
+
+ /**
+ * Returns what a negative sign should look like ("-", etc.)
+ * according to the current locale or user settings.
+ *
+ * @return The negative sign used by locale.
+ */
+ QString negativeSign() const;
+
+ /**
+ * The number of fractional digits to include in numeric/monetary
+ * values (usually 2).
+ *
+ * @return Default number of fractional digits used by locale.
+ */
+ int fracDigits() const;
+
+ /**
+ * If and only if the currency symbol precedes a positive value,
+ * this will be true.
+ *
+ * @return Where to print the currency symbol for positive numbers.
+ */
+ bool positivePrefixCurrencySymbol() const;
+
+ /**
+ * If and only if the currency symbol precedes a negative value,
+ * this will be true.
+ *
+ * @return True if the currency symbol precedes negative numbers.
+ */
+ bool negativePrefixCurrencySymbol() const;
+
+ /**
+ * Returns the position of a positive sign in relation to a
+ * monetary value.
+ *
+ * @return Where/how to print the positive sign.
+ * @see SignPosition
+ */
+ SignPosition positiveMonetarySignPosition() const;
+
+ /**
+ * Denotes where to place a negative sign in relation to a
+ * monetary value.
+ *
+ * @return Where/how to print the negative sign.
+ * @see SignPosition
+ */
+ SignPosition negativeMonetarySignPosition() const;
+
+ /**
+ * Given a double, converts that to a numeric string containing
+ * the localized monetary equivalent.
+ *
+ * e.g. given 123456, return "$ 123,456.00".
+ *
+ * @param num The number we want to format
+ * @param currency The currency symbol you want.
+ * @param digits Number of fractional digits, or -1 for the default
+ * value
+ *
+ * @return The number of money as a localized string
+ * @see fracDigits()
+ */
+ QString formatMoney(double num,
+ const QString & currency = QString::null,
+ int digits = -1) const;
+
+ /**
+ * Given a double, converts that to a numeric string containing
+ * the localized numeric equivalent.
+ *
+ * e.g. given 123456.78F, return "123,456.78" (for some European country).
+ * If precision isn't specified, 2 is used.
+ *
+ * This function is a wrapper that is provided for convenience.
+ *
+ * @param num The number to convert
+ * @param precision Number of fractional digits used.
+ *
+ * @return The number as a localized string
+ * @see formatNumber(const QString, bool, int)
+ */
+ QString formatNumber(double num, int precision = -1) const;
+
+ /**
+ * @deprecated
+ *
+ * KDE 4.0: merge with formatNumber(const QString int)
+ *
+ * calls formatNumber(numStr, 2)
+ */
+ QString formatNumber(const QString &numStr) const KDE_DEPRECATED;
+
+ /**
+ * Given a string representing a number, converts that to a numeric
+ * string containing the localized numeric equivalent.
+ *
+ * e.g. given 123456.78F, return "123,456.78" (for some European country).
+ *
+ * @param numStr The number to convert
+ * @param round Round fractional digits.
+ * @param precision Number of fractional digits used.
+ *
+ * @return The number as a localized string
+ * @since 3.5
+ */
+ QString formatNumber(const QString &numStr, bool round, int precision) const;
+
+ /**
+ * Given an integer, converts that to a numeric string containing
+ * the localized numeric equivalent.
+ *
+ * e.g. given 123456L, return "123,456" (for some European country).
+ *
+ * @param num The number to convert
+ *
+ * @return The number as a localized string
+ * @since 3.2
+ */
+ QString formatLong(long num) const;
+
+ /**
+ * Use this to determine whether nouns are declined in
+ * locale's language. This property should remain
+ * read-only (no setter function)
+ *
+ * @return If nouns are declined
+ * @since 3.1
+ */
+ bool nounDeclension() const;
+
+ /**
+ * Returns a string formatted to the current locale's conventions
+ * regarding dates.
+ *
+ * @param pDate The date to be formated.
+ * @param shortFormat True for non text dates.
+ *
+ * @return The date as a string
+ */
+ QString formatDate(const QDate &pDate, bool shortFormat = false) const;
+
+ /**
+ * Use this to determine whether in dates a possessive form of month
+ * name is preferred ("of January" rather than "January")
+ *
+ * @return If possessive form should be used
+ * @since 3.1
+ */
+ bool dateMonthNamePossessive() const;
+
+ /**
+ * Returns a string formatted to the current locale's conventions
+ * regarding times.
+ *
+ * @param pTime The time to be formated.
+ * @param includeSecs if true, seconds are included in the output,
+ * otherwise only hours and minutes are formatted.
+ * @param isDuration if true, the given time is a duration, not a clock time.
+ * This means "am/pm" shouldn't be displayed.
+ *
+ * @return The time as a string
+ */
+ QString formatTime(const QTime &pTime, bool includeSecs, bool isDuration /*=false*/) const;
+
+ /**
+ * Returns a string formatted to the current locale's conventions
+ * regarding times.
+ *
+ * @param pTime The time to be formated.
+ * @param includeSecs if true, seconds are included in the output,
+ * otherwise only hours and minutes are formatted.
+ *
+ * @return The time as a string
+ */
+ QString formatTime(const QTime &pTime, bool includeSecs = false) const; // BIC: merge with above
+
+ /**
+ * Use this to determine if the user wants a 12 hour clock.
+ *
+ * @return If the user wants 12h clock
+ */
+ bool use12Clock() const;
+
+ /**
+ * @deprecated
+ *
+ * Please use the weekStartDay method instead.
+ *
+ * Use this to determine if the user wants the week to start on Monday.
+ *
+ * @return true if the week starts on Monday
+ */
+ bool weekStartsMonday() const KDE_DEPRECATED; //### remove for KDE 4.0
+
+ /**
+ * Use this to determine which day is the first day of the week.
+ *
+ * @return an integer (Monday=1..Sunday=7)
+ * @since 3.1
+ */
+ int weekStartDay() const;
+
+ /**
+ * @deprecated
+ *
+ * Returns a string containing the name of the month name used in the Gregorian calendar.
+ *
+ * @param i the month number of the year starting at 1/January.
+ * @param shortName we will return the short version of the string.
+ *
+ * @return The name of the month
+ *
+ * Typically the correct replacement for this deprecated class is
+ * calendar()->monthString(), which requires a QDate (rather than an
+ * integer month) or both a month and a year.
+ * This will work across different calendars.
+ * Note that you also need to add
+ * \code
+ * #include <kcalendarsystem.h>
+ * \endcode
+ * to the applicable file.
+ */
+ QString monthName(int i, bool shortName = false) const KDE_DEPRECATED;
+
+ /**
+ * @deprecated
+ *
+ * Returns a string containing the possessive form of the month name used in the Gregorian calendar.
+ * ("of January", "of February", etc.)
+ * It's needed in long format dates in some languages.
+ *
+ * @param i the month number of the year starting at 1/January.
+ * @param shortName we will return the short version of the string.
+ *
+ * @return The possessive form of the name of the month
+ * @since 3.1
+ *
+ * Typically the correct replacement for this deprecated class is
+ * calendar()->monthNamePossessive(), which requires a QDate (rather than
+ * an integer month) or both a month and a year.
+ * This will work across different calendars.
+ * Note that you also need to add
+ * \code
+ * #include <kcalendarsystem.h>
+ * \endcode
+ * to the applicable file.
+ */
+ QString monthNamePossessive(int i, bool shortName = false) const KDE_DEPRECATED;
+
+ /**
+ * @deprecated use calendar()->weekDayName
+ *
+ * Returns a string containing the name of the week day used in the Gregorian calendar.
+ *
+ * @param i the day number of the week starting at 1/Monday.
+ * @param shortName we will return the short version of the string.
+ *
+ * @return The name of the day
+ */
+ QString weekDayName(int i, bool shortName = false) const KDE_DEPRECATED;
+
+ /**
+ * Returns a pointer to the calendar system object.
+ *
+ * @return the current calendar system instance
+ * @since 3.2
+ */
+ const KCalendarSystem * calendar() const;
+
+ /**
+ * Returns the name of the calendar system that is currently being
+ * used by the system.
+ *
+ * @return the name of the calendar system
+ * @since 3.2
+ */
+ QString calendarType() const;
+
+ /**
+ * Changes the current calendar system to the calendar specified.
+ * Currently "gregorian" and "hijri" are supported. If the calendar
+ * system specified is not found, gregorian will be used.
+ *
+ * @param calendarType the name of the calendar type
+ * @since 3.2
+ */
+ void setCalendar(const QString & calendarType);
+
+ /**
+ * Returns a string formated to the current locale's conventions
+ * regarding both date and time.
+ *
+ * @param pDateTime The date and time to be formated.
+ * @param shortFormat using the short date format.
+ * @param includeSecs using the short date format.
+ *
+ * @return The date and time as a string
+ */
+ QString formatDateTime(const QDateTime &pDateTime,
+ bool shortFormat = true,
+ bool includeSecs = false) const;
+
+ /**
+ * Converts a localized monetary string to a double.
+ *
+ * @param numStr the string we want to convert.
+ * @param ok the boolean that is set to false if it's not a number.
+ * If @p ok is 0, it will be ignored
+ *
+ * @return The string converted to a double
+ */
+ double readMoney(const QString &numStr, bool * ok = 0) const;
+
+ /**
+ * Converts a localized numeric string to a double.
+ *
+ * @param numStr the string we want to convert.
+ * @param ok the boolean that is set to false if it's not a number.
+ * If @p ok is 0, it will be ignored
+ *
+ * @return The string converted to a double
+ */
+ double readNumber(const QString &numStr, bool * ok = 0) const;
+
+ /**
+ * Converts a localized date string to a QDate.
+ * The bool pointed by ok will be invalid if the date entered was not valid.
+ *
+ * @param str the string we want to convert.
+ * @param ok the boolean that is set to false if it's not a valid date.
+ * If @p ok is 0, it will be ignored
+ *
+ * @return The string converted to a QDate
+ */
+ QDate readDate(const QString &str, bool* ok = 0) const;
+
+ /**
+ * Converts a localized date string to a QDate, using the specified format.
+ * You will usually not want to use this method.
+ */
+ QDate readDate( const QString &intstr, const QString &fmt, bool* ok = 0) const;
+
+ enum ReadDateFlags {
+ NormalFormat = 1,
+ ShortFormat = 2
+ };
+
+ /**
+ * Converts a localized date string to a QDate.
+ * This method is stricter than readDate(str,&ok): it will either accept
+ * a date in full format or a date in short format, depending on @p flags.
+ *
+ * @param str the string we want to convert.
+ * @param flags whether the date string is to be in full format or in short format.
+ * @param ok the boolean that is set to false if it's not a valid date.
+ * If @p ok is 0, it will be ignored
+ *
+ * @return The string converted to a QDate
+ * @since 3.2
+ */
+ QDate readDate(const QString &str, ReadDateFlags flags, bool *ok = 0) const;
+
+ /**
+ * Converts a localized time string to a QTime.
+ * This method will try to parse it with seconds, then without seconds.
+ * The bool pointed to by @p ok will be set to false if the time entered was
+ * not valid.
+ *
+ * @param str the string we want to convert.
+ * @param ok the boolean that is set to false if it's not a valid time.
+ * If @p ok is 0, it will be ignored
+ *
+ * @return The string converted to a QTime
+ */
+ QTime readTime(const QString &str, bool* ok = 0) const;
+
+ enum ReadTimeFlags {
+ WithSeconds = 0, // default (no flag set)
+ WithoutSeconds = 1
+ }; // (maybe use this enum as a bitfield, if adding independent features?)
+ /**
+ * Converts a localized time string to a QTime.
+ * This method is stricter than readTime(str,&ok): it will either accept
+ * a time with seconds or a time without seconds.
+ * Use this method when the format is known by the application.
+ *
+ * @param str the string we want to convert.
+ * @param flags whether the time string is expected to contain seconds or not.
+ * @param ok the boolean that is set to false if it's not a valid time.
+ * If @p ok is 0, it will be ignored
+ *
+ * @return The string converted to a QTime
+ * @since 3.2
+ */
+ QTime readTime(const QString &str, ReadTimeFlags flags, bool *ok = 0) const;
+
+ /**
+ * Returns the language used by this object. The domain AND the
+ * library translation must be available in this language.
+ * defaultLanguage() is returned by default, if no other available.
+ *
+ * @return The currently used language.
+ */
+ QString language() const;
+
+ /**
+ * Returns the country code of the country where the user lives.
+ * defaultCountry() is returned by default, if no other available.
+ *
+ * @return The country code for the user.
+ */
+ QString country() const;
+
+ /**
+ * Returns the preferred languages as ISO 639-1 codes. This means
+ * that information about country is removed. If the internal language
+ * code might be represented by more than one 639-1 code, they will all be
+ * listed (but only once).
+ *
+ * If the selected languages are "nn, nb, pt_BR", you will get:
+ * "nn, nb, pt".
+ *
+ * @return List of language codes
+ *
+ * @see languageList
+ */
+ QStringList languagesTwoAlpha() const;
+
+ /**
+ * Returns the languages selected by user. The codes returned here is the
+ * internal language codes.
+ *
+ * @return List of language codes
+ *
+ * @see languagesTwoAlpha
+ */
+ QStringList languageList() const;
+
+ /**
+ * Returns the user's preferred encoding.
+ *
+ * @return The name of the preferred encoding
+ *
+ * @see codecForEncoding
+ * @see encodingMib
+ */
+ const char * encoding() const;
+
+ /**
+ * Returns the user's preferred encoding.
+ *
+ * @return The Mib of the preferred encoding
+ *
+ * @see encoding
+ * @see codecForEncoding
+ */
+ int encodingMib() const;
+ /**
+ * Returns the user's preferred encoding. Should never be NULL.
+ *
+ * @return The codec for the preferred encoding
+ *
+ * @see encoding
+ * @see encodingMib
+ */
+ QTextCodec * codecForEncoding() const;
+
+ /**
+ * Returns the file encoding.
+ *
+ * @return The Mib of the file encoding
+ *
+ * @see QFile::encodeName
+ * @see QFile::decodeName
+ */
+ int fileEncodingMib() const;
+
+ /**
+ * Changes the current date format.
+ *
+ * The format of the date is a string which contains variables that will
+ * be replaced:
+ * @li %Y with the century (e.g. "19" for "1984")
+ * @li %y with the lower 2 digits of the year (e.g. "84" for "1984")
+ * @li %n with the month (January="1", December="12")
+ * @li %m with the month with two digits (January="01", December="12")
+ * @li %e with the day of the month (e.g. "1" on the first of march)
+ * @li %d with the day of the month with two digits(e.g. "01" on the first of march)
+ * @li %b with the short form of the month (e.g. "Jan" for January)
+ * @li %B with the long form of the month (e.g. "January")
+ * @li %a with the short form of the weekday (e.g. "Wed" for Wednesday)
+ * @li %A with the long form of the weekday (e.g. "Wednesday" for Wednesday)
+ *
+ * Everything else in the format string will be taken as is.
+ * For example, March 20th 1989 with the format "%y:%m:%d" results
+ * in "89:03:20".
+ *
+ * @param format The new date format
+ */
+ void setDateFormat(const QString & format);
+ /**
+ * Changes the current short date format.
+ *
+ * The format of the date is a string which contains variables that will
+ * be replaced:
+ * @li %Y with the century (e.g. "19" for "1984")
+ * @li %y with the lower 2 digits of the year (e.g. "84" for "1984")
+ * @li %n with the month (January="1", December="12")
+ * @li %m with the month with two digits (January="01", December="12")
+ * @li %e with the day of the month (e.g. "1" on the first of march)
+ * @li %d with the day of the month with two digits(e.g. "01" on the first of march)
+ * @li %b with the short form of the month (e.g. "Jan" for January)
+ * @li %B with the long form of the month (e.g. "January")
+ * @li %a with the short form of the weekday (e.g. "Wed" for Wednesday)
+ * @li %A with the long form of the weekday (e.g. "Wednesday" for Wednesday)
+ *
+ * Everything else in the format string will be taken as is.
+ * For example, March 20th 1989 with the format "%y:%m:%d" results
+ * in "89:03:20".
+ *
+ * @param format The new short date format
+ */
+ void setDateFormatShort(const QString & format);
+ /**
+ * Changes the form of month name used in dates.
+ *
+ * @param possessive True if possessive forms should be used
+ * @since 3.1
+ */
+ void setDateMonthNamePossessive(bool possessive);
+ /**
+ * Changes the current time format.
+ *
+ * The format of the time is string a which contains variables that will
+ * be replaced:
+ * @li %H with the hour in 24h format and 2 digits (e.g. 5pm is "17", 5am is "05")
+ * @li %k with the hour in 24h format and one digits (e.g. 5pm is "17", 5am is "5")
+ * @li %I with the hour in 12h format and 2 digits (e.g. 5pm is "05", 5am is "05")
+ * @li %l with the hour in 12h format and one digits (e.g. 5pm is "5", 5am is "5")
+ * @li %M with the minute with 2 digits (e.g. the minute of 07:02:09 is "02")
+ * @li %S with the seconds with 2 digits (e.g. the minute of 07:02:09 is "09")
+ * @li %p with pm or am (e.g. 17.00 is "pm", 05.00 is "am")
+ *
+ * Everything else in the format string will be taken as is.
+ * For example, 5.23pm with the format "%H:%M" results
+ * in "17:23".
+ *
+ * @param format The new time format
+ */
+ void setTimeFormat(const QString & format);
+
+ /**
+ * @deprecated
+ *
+ * Please use setWeekStartDay instead.
+ *
+ * Changes how KLocale defines the first day in week.
+ *
+ * @param start True if Monday is the first day in the week
+ */
+ void setWeekStartsMonday(bool start) KDE_DEPRECATED; //### remove for KDE 4.0
+
+ /**
+ * Changes how KLocale defines the first day in week.
+ *
+ * @param day first day of the week (Monday=1..Sunday=7) as integer
+ * @since 3.1
+ */
+ void setWeekStartDay(int day);
+ /**
+ * Returns the currently selected date format.
+ *
+ * @return Current date format.
+ * @see setDateFormat()
+ */
+ QString dateFormat() const;
+ /**
+ * Returns the currently selected short date format.
+ *
+ * @return Current short date format.
+ * @see setDateFormatShort()
+ */
+ QString dateFormatShort() const;
+ /**
+ * Returns the currently selected time format.
+ *
+ * @return Current time format.
+ * @see setTimeFormat()
+ */
+ QString timeFormat() const;
+
+ /**
+ * Changes the symbol used to identify the decimal pointer.
+ *
+ * @param symbol The new decimal symbol.
+ */
+ void setDecimalSymbol(const QString & symbol);
+ /**
+ * Changes the separator used to group digits when formating numbers.
+ *
+ * @param separator The new thousands separator.
+ */
+ void setThousandsSeparator(const QString & separator);
+ /**
+ * Changes the sign used to identify a positive number. Normally this is
+ * left blank.
+ *
+ * @param sign Sign used for positive numbers.
+ */
+ void setPositiveSign(const QString & sign);
+ /**
+ * Changes the sign used to identify a negative number.
+ *
+ * @param sign Sign used for negative numbers.
+ */
+ void setNegativeSign(const QString & sign);
+ /**
+ * Changes the sign position used for positive monetary values.
+ *
+ * @param signpos The new sign position
+ */
+ void setPositiveMonetarySignPosition(SignPosition signpos);
+ /**
+ * Changes the sign position used for negative monetary values.
+ *
+ * @param signpos The new sign position
+ */
+ void setNegativeMonetarySignPosition(SignPosition signpos);
+ /**
+ * Changes the position where the currency symbol should be printed for
+ * positive monetary values.
+ *
+ * @param prefix True if the currency symbol should be prefixed instead of
+ * postfixed
+ */
+ void setPositivePrefixCurrencySymbol(bool prefix);
+ /**
+ * Changes the position where the currency symbol should be printed for
+ * negative monetary values.
+ *
+ * @param prefix True if the currency symbol should be prefixed instead of
+ * postfixed
+ */
+ void setNegativePrefixCurrencySymbol(bool prefix);
+ /**
+ * Changes the number of digits used when formating numbers.
+ *
+ * @param digits The default number of digits to use.
+ */
+ void setFracDigits(int digits);
+ /**
+ * Changes the separator used to group digits when formating monetary values.
+ *
+ * @param separator The new thousands separator.
+ */
+ void setMonetaryThousandsSeparator(const QString & separator);
+ /**
+ * Changes the symbol used to identify the decimal pointer for monetary
+ * values.
+ *
+ * @param symbol The new decimal symbol.
+ */
+ void setMonetaryDecimalSymbol(const QString & symbol);
+ /**
+ * Changes the current currency symbol.
+ *
+ * @param symbol The new currency symbol
+ */
+ void setCurrencySymbol(const QString & symbol);
+
+ /**
+ * Returns the preferred page size for printing.
+ *
+ * @return The preferred page size, cast it to QPrinter::PageSize
+ */
+ int pageSize() const;
+
+ /**
+ * Changes the preferred page size when printing.
+ *
+ * @param paperFormat the new preferred page size in the format QPrinter::PageSize
+ */
+ void setPageSize(int paperFormat);
+
+ /**
+ * The Metric system will give you information in mm, while the
+ * Imperial system will give you information in inches.
+ */
+ enum MeasureSystem { Metric, Imperial };
+
+ /**
+ * Returns which measuring system we use.
+ *
+ * @return The preferred measuring system
+ */
+ MeasureSystem measureSystem() const;
+
+ /**
+ * Changes the preferred measuring system.
+ *
+ * @return value The preferred measuring system
+ */
+ void setMeasureSystem(MeasureSystem value);
+
+ /**
+ * Adds another catalog to search for translation lookup.
+ * This function is useful for extern libraries and/or code,
+ * that provide there own messages.
+ *
+ * If the catalog does not exist for the chosen language,
+ * it will be ignored and en_US will be used.
+ *
+ * @param catalog The catalog to add.
+ */
+ void insertCatalogue(const QString& catalog);
+
+ /**
+ * Removes a catalog for translation lookup.
+ * @param catalog The catalog to remove.
+ * @see insertCatalogue()
+ */
+ void removeCatalogue(const QString &catalog);
+
+ /**
+ * Sets the active catalog for translation lookup.
+ * @param catalog The catalog to activate.
+ */
+ void setActiveCatalogue(const QString &catalog);
+
+ /**
+ * Translates a message as a QTranslator is supposed to.
+ * The parameters are similar to i18n(), but the result
+ * value has other semantics (it can be QString::null)
+ * @since 3.1
+ **/
+ QString translateQt(const char *context,
+ const char *sourceText,
+ const char *message) const;
+
+ /**
+ * Returns list of all known ISO 639-1 codes.
+ * @return a list of all language codes
+ * @since 3.1
+ */
+ QStringList allLanguagesTwoAlpha() const;
+
+ /**
+ * Convert a ISO 639-1 code to a human readable form.
+ * @param code the language ISO 639-1 code
+ * @return the human readable form
+ * @since 3.1
+ */
+ QString twoAlphaToLanguageName(const QString &code) const;
+
+ /**
+ * Returns list of all known country codes.
+ * @return a list of all country codes
+ * @since 3.1
+ */
+ QStringList allCountriesTwoAlpha() const;
+
+ /**
+ * Convert a country code to a human readable form.
+ * @param code the country code
+ * @return the human readable form of the country name
+ * @since 3.1
+ */
+ QString twoAlphaToCountryName(const QString &code) const;
+
+ /**
+ * Returns the parts of the parameter str understood as language setting
+ * the format is language_COUNTRY.charset
+ *
+ * @param str The string to split.
+ * @param language This will be set to the language part of the string.
+ * @param country This will be set to the country part of the string.
+ * @param charset This will be set to the charset part of the string.
+ */
+ static void splitLocale(const QString & str,
+ QString & language,
+ QString & country,
+ QString & charset);
+
+ /**
+ * Use this as main catalog for *all* KLocales, if not the appname
+ * will be used. This function is best to be the very first instruction
+ * in your program's main function as it only has an effect before the
+ * first KLocale object is created.
+ *
+ * @param catalog Catalogue to override all other main catalogues.
+ */
+ static void setMainCatalogue(const char *catalog);
+
+ /**
+ * Finds localized resource in resourceDir( rtype ) + \<lang> + fname.
+ *
+ * @param fname relative path to find
+ * @param rtype resource type to use
+ */
+ static QString langLookup(const QString &fname, const char *rtype = "html");
+
+ /**
+ * Returns the name of the internal language.
+ *
+ * @return Name of the default language
+ */
+ static QString defaultLanguage();
+
+ /**
+ * Returns the name of the default country.
+ *
+ * @return Name of the default country
+ */
+ static QString defaultCountry();
+
+
+ /**
+ * @internal Called from KConfigBackend to initialize language.
+ */
+ static QString _initLanguage(KConfigBase *config);
+
+#ifdef KDE_NO_COMPAT
+private:
+#endif
+ /**
+ * @deprecated
+ * use formatMoney(double)
+ */
+ QString formatMoney(const QString &numStr) const KDE_DEPRECATED;
+
+ /**
+ * @deprecated
+ * Use languageList()
+ *
+ * @return String containing language codes separated by colons
+ */
+ QString languages() const KDE_DEPRECATED;
+
+ /**
+ * @deprecated
+ * @return True
+ */
+ bool setCharset(const QString & charset) KDE_DEPRECATED;
+
+ /**
+ * @deprecated
+ * @see encoding
+ */
+ QString charset() const KDE_DEPRECATED;
+
+protected:
+ /**
+ * @internal Creates a KLocale object for KGlobal and inits the locale
+ * pointer.
+ */
+ static void initInstance();
+
+private:
+ /**
+ * @internal Inits the localization part of the instance with the config
+ * object.
+ *
+ * @param config The configuration object used for init.
+ */
+ void initFormat(KConfig *config);
+
+ /**
+ * @internal Initializes the catalogs appname, kdelibs and kio for all chosen languages.
+ *
+ * @param config The configuration object used for init
+ * @param useEnv True if we should use environment variables
+ */
+ void initMainCatalogues(const QString & catalog);
+
+ /**
+ * @internal Initializes the list of valid languages from the user's point of view. This is the list of
+ * languages that the user picks in kcontrol. The config object should be valid and contain the global
+ * entries.
+ *
+ * @param config The configuration object used for init
+ * @param useEnv True if we should use environment variables
+ */
+ void initLanguageList(KConfig * config, bool useEnv);
+
+ /**
+ * @internal Figures out which encoding the user prefers.
+ *
+ * @param config The configuration object used for init
+ */
+ void initEncoding(KConfig * config);
+
+ /**
+ * @internal Figures out which encoding the user prefers for filenames
+ * and sets up the appropriate QFile encoding and decoding functions.
+ */
+ void initFileNameEncoding(KConfig *config);
+
+ /**
+ * @internal A QFile filename encoding function (QFile::encodeFn).
+ */
+ static QCString encodeFileNameUTF8( const QString & fileName );
+
+ /**
+ * @internal QFile filename decoding function (QFile::decodeFn).
+ */
+ static QString decodeFileNameUTF8( const QCString & localFileName );
+
+ /**
+ * @internal Changes the file name of the catalog to the correct
+ * one.
+ */
+ void initCatalogue( KCatalogue & catalog );
+
+ /**
+ * @internal Ensures that the format configuration is read.
+ */
+ void doFormatInit() const;
+
+ /**
+ * @internal Reads the format configuration from disk.
+ */
+ void initFormat();
+
+ /**
+ * @internal function used by the two translate versions
+ */
+ QString translate_priv(const char *index,
+ const char *text,
+ const char ** original = 0,
+ int* pluralType = 0) const;
+
+ /**
+ * @internal function used to determine if we are using the en_US translation
+ */
+ bool useDefaultLanguage() const;
+
+ /**
+ * @internal Checks if the specified language is installed
+ */
+ bool isLanguageInstalled(const QString & language) const;
+
+ /**
+ * @internal evaluate the list of catalogs and check that all instances for all languages are loaded
+ * and that they are sorted according to the catalog names
+ */
+ void updateCatalogues( );
+
+ /**
+ * @internal Find the plural type for all loaded catalogs
+ */
+ void initPluralTypes( );
+ /**
+ * @internal Find the plural type for a language. Look this up in the corresponding kdelibs.po.
+ *
+ * @param language The language to examine
+ */
+ int pluralType( const QString & language );
+
+ /**
+ * @internal Find the plural type information for a given catalog. This catalog will be a kdelibs.mo. Method
+ * just exists to make code more readable.
+ *
+ * @param language The language to examine
+ */
+ int pluralType( const KCatalogue& catalog );
+ /**
+ * @internal Find catalog for given language and given catalog name.
+ *
+ * @param language language of the catalog
+ * @param name name of the catalog
+ */
+ // const KCatalogue * catalog( const QString & language, const QString & name );
+
+
+ /**
+ * @internal Retrieves the file name of the catalog, or QString::null
+ * if not found.
+ */
+ static QString catalogueFileName(const QString & language,
+ const KCatalogue & catalog);
+public:
+ /**
+ * @internal Checks whether or not theFind catalog for given language and given catalog name.
+ *
+ * @param language language to check
+ */
+ bool isApplicationTranslatedInto( const QString & language);
+
+private:
+ // Numbers and money
+ QString m_decimalSymbol;
+ QString m_thousandsSeparator;
+ QString m_currencySymbol;
+ QString m_monetaryDecimalSymbol;
+ QString m_monetaryThousandsSeparator;
+ QString m_positiveSign;
+ QString m_negativeSign;
+ int m_fracDigits;
+ SignPosition m_positiveMonetarySignPosition;
+ SignPosition m_negativeMonetarySignPosition;
+
+ // Date and time
+ QString m_timeFormat;
+ QString m_dateFormat;
+ QString m_dateFormatShort;
+
+ QString m_language;
+ QString m_country;
+
+ bool m_weekStartsMonday; //### remove for KDE 4.0
+ bool m_positivePrefixCurrencySymbol;
+ bool m_negativePrefixCurrencySymbol;
+
+ KLocalePrivate *d;
+};
+
+#endif
diff --git a/kdecore/klockfile.cpp b/kdecore/klockfile.cpp
new file mode 100644
index 000000000..41946a36a
--- /dev/null
+++ b/kdecore/klockfile.cpp
@@ -0,0 +1,376 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2004 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <klockfile.h>
+
+#include <config.h>
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <kde_file.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kglobal.h>
+#include <ktempfile.h>
+
+// TODO: http://www.spinnaker.de/linux/nfs-locking.html
+// TODO: Make regression test
+
+class KLockFile::KLockFilePrivate {
+public:
+ QString file;
+ int staleTime;
+ bool isLocked;
+ bool recoverLock;
+ bool linkCountSupport;
+ QTime staleTimer;
+ KDE_struct_stat statBuf;
+ int pid;
+ QString hostname;
+ QString instance;
+ QString lockRecoverFile;
+};
+
+
+// 30 seconds
+KLockFile::KLockFile(const QString &file)
+{
+ d = new KLockFilePrivate();
+ d->file = file;
+ d->staleTime = 30;
+ d->isLocked = false;
+ d->recoverLock = false;
+ d->linkCountSupport = true;
+}
+
+KLockFile::~KLockFile()
+{
+ unlock();
+ delete d;
+}
+
+int
+KLockFile::staleTime() const
+{
+ return d->staleTime;
+}
+
+
+void
+KLockFile::setStaleTime(int _staleTime)
+{
+ d->staleTime = _staleTime;
+}
+
+static bool statResultIsEqual(KDE_struct_stat &st_buf1, KDE_struct_stat &st_buf2)
+{
+#define FIELD_EQ(what) (st_buf1.what == st_buf2.what)
+ return FIELD_EQ(st_dev) && FIELD_EQ(st_ino) &&
+ FIELD_EQ(st_uid) && FIELD_EQ(st_gid) && FIELD_EQ(st_nlink);
+#undef FIELD_EQ
+}
+
+static bool testLinkCountSupport(const QCString &fileName)
+{
+ KDE_struct_stat st_buf;
+ // Check if hardlinks raise the link count at all?
+ ::link( fileName, fileName+".test" );
+ int result = KDE_lstat( fileName, &st_buf );
+ ::unlink( fileName+".test" );
+ return ((result == 0) && (st_buf.st_nlink == 2));
+}
+
+static KLockFile::LockResult lockFile(const QString &lockFile, KDE_struct_stat &st_buf, bool &linkCountSupport)
+{
+ QCString lockFileName = QFile::encodeName( lockFile );
+ int result = KDE_lstat( lockFileName, &st_buf );
+ if (result == 0)
+ return KLockFile::LockFail;
+
+ KTempFile uniqueFile(lockFile, QString::null, 0644);
+ uniqueFile.setAutoDelete(true);
+ if (uniqueFile.status() != 0)
+ return KLockFile::LockError;
+
+ char hostname[256];
+ hostname[0] = 0;
+ gethostname(hostname, 255);
+ hostname[255] = 0;
+ QCString instanceName = KCmdLineArgs::appName();
+
+ (*(uniqueFile.textStream())) << QString::number(getpid()) << endl
+ << instanceName << endl
+ << hostname << endl;
+ uniqueFile.close();
+
+ QCString uniqueName = QFile::encodeName( uniqueFile.name() );
+
+#ifdef Q_OS_UNIX
+ // Create lock file
+ result = ::link( uniqueName, lockFileName );
+ if (result != 0)
+ return KLockFile::LockError;
+
+ if (!linkCountSupport)
+ return KLockFile::LockOK;
+#else
+ //TODO for win32
+ return KLockFile::LockOK;
+#endif
+
+ KDE_struct_stat st_buf2;
+ result = KDE_lstat( uniqueName, &st_buf2 );
+ if (result != 0)
+ return KLockFile::LockError;
+
+ result = KDE_lstat( lockFileName, &st_buf );
+ if (result != 0)
+ return KLockFile::LockError;
+
+ if (!statResultIsEqual(st_buf, st_buf2) || S_ISLNK(st_buf.st_mode) || S_ISLNK(st_buf2.st_mode))
+ {
+ // SMBFS supports hardlinks by copying the file, as a result the above test will always fail
+ if ((st_buf.st_nlink == 1) && (st_buf2.st_nlink == 1) && (st_buf.st_ino != st_buf2.st_ino))
+ {
+ linkCountSupport = testLinkCountSupport(uniqueName);
+ if (!linkCountSupport)
+ return KLockFile::LockOK; // Link count support is missing... assume everything is OK.
+ }
+ return KLockFile::LockFail;
+ }
+
+ return KLockFile::LockOK;
+}
+
+static KLockFile::LockResult deleteStaleLock(const QString &lockFile, KDE_struct_stat &st_buf, bool &linkCountSupport)
+{
+ // This is dangerous, we could be deleting a new lock instead of
+ // the old stale one, let's be very careful
+
+ // Create temp file
+ KTempFile ktmpFile(lockFile);
+ if (ktmpFile.status() != 0)
+ return KLockFile::LockError;
+
+ QCString lckFile = QFile::encodeName(lockFile);
+ QCString tmpFile = QFile::encodeName(ktmpFile.name());
+ ktmpFile.close();
+ ktmpFile.unlink();
+
+#ifdef Q_OS_UNIX
+ // link to lock file
+ if (::link(lckFile, tmpFile) != 0)
+ return KLockFile::LockFail; // Try again later
+#else
+ //TODO for win32
+ return KLockFile::LockOK;
+#endif
+
+ // check if link count increased with exactly one
+ // and if the lock file still matches
+ KDE_struct_stat st_buf1;
+ KDE_struct_stat st_buf2;
+ memcpy(&st_buf1, &st_buf, sizeof(KDE_struct_stat));
+ st_buf1.st_nlink++;
+ if ((KDE_lstat(tmpFile, &st_buf2) == 0) && statResultIsEqual(st_buf1, st_buf2))
+ {
+ if ((KDE_lstat(lckFile, &st_buf2) == 0) && statResultIsEqual(st_buf1, st_buf2))
+ {
+ // - - if yes, delete lock file, delete temp file, retry lock
+ qWarning("WARNING: deleting stale lockfile %s", lckFile.data());
+ ::unlink(lckFile);
+ ::unlink(tmpFile);
+ return KLockFile::LockOK;
+ }
+ }
+
+ // SMBFS supports hardlinks by copying the file, as a result the above test will always fail
+ if (linkCountSupport)
+ {
+ linkCountSupport = testLinkCountSupport(tmpFile);
+ }
+
+ if (!linkCountSupport &&
+ (KDE_lstat(lckFile, &st_buf2) == 0) &&
+ statResultIsEqual(st_buf, st_buf2))
+ {
+ // Without support for link counts we will have a little race condition
+ qWarning("WARNING: deleting stale lockfile %s", lckFile.data());
+ ::unlink(lckFile);
+ ::unlink(tmpFile);
+ return KLockFile::LockOK;
+ }
+
+ // Failed to delete stale lock file
+ qWarning("WARNING: Problem deleting stale lockfile %s", lckFile.data());
+ ::unlink(tmpFile);
+ return KLockFile::LockFail;
+}
+
+
+KLockFile::LockResult KLockFile::lock(int options)
+{
+ if (d->isLocked)
+ return KLockFile::LockOK;
+
+ KLockFile::LockResult result;
+ int hardErrors = 5;
+ int n = 5;
+ while(true)
+ {
+ KDE_struct_stat st_buf;
+ result = lockFile(d->file, st_buf, d->linkCountSupport);
+ if (result == KLockFile::LockOK)
+ {
+ d->staleTimer = QTime();
+ break;
+ }
+ else if (result == KLockFile::LockError)
+ {
+ d->staleTimer = QTime();
+ if (--hardErrors == 0)
+ {
+ break;
+ }
+ }
+ else // KLockFile::Fail
+ {
+ if (!d->staleTimer.isNull() && !statResultIsEqual(d->statBuf, st_buf))
+ d->staleTimer = QTime();
+
+ if (!d->staleTimer.isNull())
+ {
+ bool isStale = false;
+ if ((d->pid > 0) && !d->hostname.isEmpty())
+ {
+ // Check if hostname is us
+ char hostname[256];
+ hostname[0] = 0;
+ gethostname(hostname, 255);
+ hostname[255] = 0;
+
+ if (d->hostname == hostname)
+ {
+ // Check if pid still exists
+ int res = ::kill(d->pid, 0);
+ if ((res == -1) && (errno == ESRCH))
+ isStale = true;
+ }
+ }
+ if (d->staleTimer.elapsed() > (d->staleTime*1000))
+ isStale = true;
+
+ if (isStale)
+ {
+ if ((options & LockForce) == 0)
+ return KLockFile::LockStale;
+
+ result = deleteStaleLock(d->file, d->statBuf, d->linkCountSupport);
+
+ if (result == KLockFile::LockOK)
+ {
+ // Lock deletion successful
+ d->staleTimer = QTime();
+ continue; // Now try to get the new lock
+ }
+ else if (result != KLockFile::LockFail)
+ {
+ return result;
+ }
+ }
+ }
+ else
+ {
+ memcpy(&(d->statBuf), &st_buf, sizeof(KDE_struct_stat));
+ d->staleTimer.start();
+
+ d->pid = -1;
+ d->hostname = QString::null;
+ d->instance = QString::null;
+
+ QFile file(d->file);
+ if (file.open(IO_ReadOnly))
+ {
+ QTextStream ts(&file);
+ if (!ts.atEnd())
+ d->pid = ts.readLine().toInt();
+ if (!ts.atEnd())
+ d->instance = ts.readLine();
+ if (!ts.atEnd())
+ d->hostname = ts.readLine();
+ }
+ }
+ }
+
+ if ((options & LockNoBlock) != 0)
+ break;
+
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = n*((KApplication::random() % 200)+100);
+ if (n < 2000)
+ n = n * 2;
+
+#ifdef Q_OS_UNIX
+ select(0, 0, 0, 0, &tv);
+#else
+ //TODO for win32
+#endif
+ }
+ if (result == LockOK)
+ d->isLocked = true;
+ return result;
+}
+
+bool KLockFile::isLocked() const
+{
+ return d->isLocked;
+}
+
+void KLockFile::unlock()
+{
+ if (d->isLocked)
+ {
+ ::unlink(QFile::encodeName(d->file));
+ d->isLocked = false;
+ }
+}
+
+bool KLockFile::getLockInfo(int &pid, QString &hostname, QString &appname)
+{
+ if (d->pid == -1)
+ return false;
+ pid = d->pid;
+ hostname = d->hostname;
+ appname = d->instance;
+ return true;
+}
diff --git a/kdecore/klockfile.h b/kdecore/klockfile.h
new file mode 100644
index 000000000..b48d09926
--- /dev/null
+++ b/kdecore/klockfile.h
@@ -0,0 +1,123 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2004 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KLOCKFILE_H_
+#define _KLOCKFILE_H_
+
+#include <qstring.h>
+#include <qdatetime.h>
+
+#include <ksharedptr.h>
+/**
+ * The KLockFile class provides NFS safe lockfiles.
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ * @since 3.3
+ */
+class KDECORE_EXPORT KLockFile : public KShared
+{
+public:
+ typedef KSharedPtr<KLockFile> Ptr;
+
+ KLockFile(const QString &file);
+
+ /**
+ * Destroys the object, releasing the lock if held
+ **/
+ ~KLockFile();
+
+ /**
+ * Possible return values of the lock function.
+ */
+ enum LockResult {
+ /**
+ * Lock was acquired successfully
+ */
+ LockOK = 0,
+
+ /**
+ * The lock could not be acquired because it is held by another process
+ */
+ LockFail,
+
+ /**
+ * The lock could not be acquired due to an error
+ */
+ LockError,
+
+ /**
+ * A stale lock has been detected
+ */
+ LockStale
+ };
+
+ enum LockOptions {
+ /**
+ * Return immediately, do not wait for the lock to become available
+ */
+ LockNoBlock = 1,
+
+ /**
+ * Automatically remove a lock when a lock is detected that is stale
+ * for more than staleTime() seconds.
+ */
+ LockForce = 2
+ };
+
+ /**
+ * Attempt to acquire the lock
+ *
+ * @param options A set of @ref LockOptions OR'ed together.
+ */
+ LockResult lock(int options=0);
+
+ /**
+ * Returns whether the lock is held or not
+ */
+ bool isLocked() const;
+
+ /**
+ * Release the lock
+ */
+ void unlock();
+
+ /**
+ * Return the time in seconds after which a lock is considered stale
+ * The default is 30.
+ */
+ int staleTime() const;
+
+ /**
+ * Set the time in seconds after which a lock is considered stale
+ */
+ void setStaleTime(int _staleTime);
+
+ /**
+ * Returns the pid, hostname and appname of the process holding
+ * the lock after the lock functon has returned with LockStale.
+ * @returns false if the pid and hostname could not be determined
+ */
+ bool getLockInfo(int &pid, QString &hostname, QString &appname);
+
+private:
+ class KLockFilePrivate;
+ KLockFilePrivate *d;
+};
+
+#endif
diff --git a/kdecore/kmacroexpander.cpp b/kdecore/kmacroexpander.cpp
new file mode 100644
index 000000000..f098f68e4
--- /dev/null
+++ b/kdecore/kmacroexpander.cpp
@@ -0,0 +1,529 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2002-2003 Oswald Buddenhagen <ossi@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kmacroexpander.h>
+
+#include <qvaluestack.h>
+#include <qregexp.h>
+
+KMacroExpanderBase::KMacroExpanderBase( QChar c )
+{
+ escapechar = c;
+}
+
+KMacroExpanderBase::~KMacroExpanderBase()
+{
+}
+
+void
+KMacroExpanderBase::setEscapeChar( QChar c )
+{
+ escapechar = c;
+}
+
+QChar
+KMacroExpanderBase::escapeChar() const
+{
+ return escapechar;
+}
+
+void KMacroExpanderBase::expandMacros( QString &str )
+{
+ uint pos;
+ int len;
+ QChar ec( escapechar );
+ QStringList rst;
+ QString rsts;
+
+ for (pos = 0; pos < str.length(); ) {
+ if (ec != (char)0) {
+ if (str.unicode()[pos] != ec)
+ goto nohit;
+ if (!(len = expandEscapedMacro( str, pos, rst )))
+ goto nohit;
+ } else {
+ if (!(len = expandPlainMacro( str, pos, rst )))
+ goto nohit;
+ }
+ if (len < 0) {
+ pos -= len;
+ continue;
+ }
+ rsts = rst.join( " " );
+ rst.clear();
+ str.replace( pos, len, rsts );
+ pos += rsts.length();
+ continue;
+ nohit:
+ pos++;
+ }
+}
+
+
+namespace KMacroExpander {
+
+ /** @intern Quoting state of the expander code. Not available publicly. */
+ enum Quoting { noquote, singlequote, doublequote, dollarquote,
+ paren, subst, group, math };
+ typedef struct {
+ Quoting current;
+ bool dquote;
+ } State;
+ typedef struct {
+ QString str;
+ uint pos;
+ } Save;
+
+}
+
+using namespace KMacroExpander;
+
+bool KMacroExpanderBase::expandMacrosShellQuote( QString &str, uint &pos )
+{
+ int len;
+ uint pos2;
+ QChar ec( escapechar );
+ State state = { noquote, false };
+ QValueStack<State> sstack;
+ QValueStack<Save> ostack;
+ QStringList rst;
+ QString rsts;
+
+ while (pos < str.length()) {
+ QChar cc( str.unicode()[pos] );
+ if (ec != (char)0) {
+ if (cc != ec)
+ goto nohit;
+ if (!(len = expandEscapedMacro( str, pos, rst )))
+ goto nohit;
+ } else {
+ if (!(len = expandPlainMacro( str, pos, rst )))
+ goto nohit;
+ }
+ if (len < 0) {
+ pos -= len;
+ continue;
+ }
+ if (state.dquote) {
+ rsts = rst.join( " " );
+ rsts.replace( QRegExp("([$`\"\\\\])"), "\\\\1" );
+ } else if (state.current == dollarquote) {
+ rsts = rst.join( " " );
+ rsts.replace( QRegExp("(['\\\\])"), "\\\\1" );
+ } else if (state.current == singlequote) {
+ rsts = rst.join( " " );
+ rsts.replace( '\'', "'\\''");
+ } else {
+ if (rst.isEmpty()) {
+ str.remove( pos, len );
+ continue;
+ } else {
+ rsts = "'";
+#if 0 // this could pay off if join() would be cleverer and the strings were long
+ for (QStringList::Iterator it = rst.begin(); it != rst.end(); ++it)
+ (*it).replace( '\'', "'\\''" );
+ rsts += rst.join( "' '" );
+#else
+ for (QStringList::ConstIterator it = rst.begin(); it != rst.end(); ++it) {
+ if (it != rst.begin())
+ rsts += "' '";
+ QString trsts( *it );
+ trsts.replace( '\'', "'\\''" );
+ rsts += trsts;
+ }
+#endif
+ rsts += "'";
+ }
+ }
+ rst.clear();
+ str.replace( pos, len, rsts );
+ pos += rsts.length();
+ continue;
+ nohit:
+ if (state.current == singlequote) {
+ if (cc == '\'')
+ state = sstack.pop();
+ } else if (cc == '\\') {
+ // always swallow the char -> prevent anomalies due to expansion
+ pos += 2;
+ continue;
+ } else if (state.current == dollarquote) {
+ if (cc == '\'')
+ state = sstack.pop();
+ } else if (cc == '$') {
+ cc = str[++pos];
+ if (cc == '(') {
+ sstack.push( state );
+ if (str[pos + 1] == '(') {
+ Save sav = { str, pos + 2 };
+ ostack.push( sav );
+ state.current = math;
+ pos += 2;
+ continue;
+ } else {
+ state.current = paren;
+ state.dquote = false;
+ }
+ } else if (cc == '{') {
+ sstack.push( state );
+ state.current = subst;
+ } else if (!state.dquote) {
+ if (cc == '\'') {
+ sstack.push( state );
+ state.current = dollarquote;
+ } else if (cc == '"') {
+ sstack.push( state );
+ state.current = doublequote;
+ state.dquote = true;
+ }
+ }
+ // always swallow the char -> prevent anomalies due to expansion
+ } else if (cc == '`') {
+ str.replace( pos, 1, "$( " ); // add space -> avoid creating $((
+ pos2 = pos += 3;
+ for (;;) {
+ if (pos2 >= str.length()) {
+ pos = pos2;
+ return false;
+ }
+ cc = str.unicode()[pos2];
+ if (cc == '`')
+ break;
+ if (cc == '\\') {
+ cc = str[++pos2];
+ if (cc == '$' || cc == '`' || cc == '\\' ||
+ (cc == '"' && state.dquote))
+ {
+ str.remove( pos2 - 1, 1 );
+ continue;
+ }
+ }
+ pos2++;
+ }
+ str[pos2] = ')';
+ sstack.push( state );
+ state.current = paren;
+ state.dquote = false;
+ continue;
+ } else if (state.current == doublequote) {
+ if (cc == '"')
+ state = sstack.pop();
+ } else if (cc == '\'') {
+ if (!state.dquote) {
+ sstack.push( state );
+ state.current = singlequote;
+ }
+ } else if (cc == '"') {
+ if (!state.dquote) {
+ sstack.push( state );
+ state.current = doublequote;
+ state.dquote = true;
+ }
+ } else if (state.current == subst) {
+ if (cc == '}')
+ state = sstack.pop();
+ } else if (cc == ')') {
+ if (state.current == math) {
+ if (str[pos + 1] == ')') {
+ state = sstack.pop();
+ pos += 2;
+ } else {
+ // false hit: the $(( was a $( ( in fact
+ // ash does not care, but bash does
+ pos = ostack.top().pos;
+ str = ostack.top().str;
+ ostack.pop();
+ state.current = paren;
+ state.dquote = false;
+ sstack.push( state );
+ }
+ continue;
+ } else if (state.current == paren)
+ state = sstack.pop();
+ else
+ break;
+ } else if (cc == '}') {
+ if (state.current == KMacroExpander::group)
+ state = sstack.pop();
+ else
+ break;
+ } else if (cc == '(') {
+ sstack.push( state );
+ state.current = paren;
+ } else if (cc == '{') {
+ sstack.push( state );
+ state.current = KMacroExpander::group;
+ }
+ pos++;
+ }
+ return sstack.empty();
+}
+
+bool KMacroExpanderBase::expandMacrosShellQuote( QString &str )
+{
+ uint pos = 0;
+ return expandMacrosShellQuote( str, pos ) && pos == str.length();
+}
+
+int KMacroExpanderBase::expandPlainMacro( const QString &, uint, QStringList & )
+{ qFatal( "KMacroExpanderBase::expandPlainMacro called!" ); return 0; }
+
+int KMacroExpanderBase::expandEscapedMacro( const QString &, uint, QStringList & )
+{ qFatal( "KMacroExpanderBase::expandEscapedMacro called!" ); return 0; }
+
+
+//////////////////////////////////////////////////
+
+template<class KT,class VT>
+class KMacroMapExpander : public KMacroExpanderBase {
+
+public:
+ KMacroMapExpander( const QMap<KT,VT> &map, QChar c = '%' ) :
+ KMacroExpanderBase( c ), macromap( map ) {}
+
+protected:
+ virtual int expandPlainMacro( const QString &str, uint pos, QStringList &ret );
+ virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
+
+private:
+ QMap<KT,VT> macromap;
+};
+
+static QStringList &operator+=( QStringList &s, const QString &n) { s << n; return s; }
+
+////////
+
+static bool
+isIdentifier( uint c )
+{
+ return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
+}
+
+////////
+
+template<class VT>
+class KMacroMapExpander<QChar,VT> : public KMacroExpanderBase {
+
+public:
+ KMacroMapExpander( const QMap<QChar,VT> &map, QChar c = '%' ) :
+ KMacroExpanderBase( c ), macromap( map ) {}
+
+protected:
+ virtual int expandPlainMacro( const QString &str, uint pos, QStringList &ret );
+ virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
+
+private:
+ QMap<QChar,VT> macromap;
+};
+
+template<class VT>
+int
+KMacroMapExpander<QChar,VT>::expandPlainMacro( const QString &str, uint pos, QStringList &ret )
+{
+ QMapConstIterator<QChar,VT> it = macromap.find(str[pos]);
+ if (it != macromap.end()) {
+ ret += it.data();
+ return 1;
+ }
+ return 0;
+}
+
+template<class VT>
+int
+KMacroMapExpander<QChar,VT>::expandEscapedMacro( const QString &str, uint pos, QStringList &ret )
+{
+ if (str[pos + 1] == escapeChar()) {
+ ret += QString( escapeChar() );
+ return 2;
+ }
+ QMapConstIterator<QChar,VT> it = macromap.find(str[pos+1]);
+ if (it != macromap.end()) {
+ ret += it.data();
+ return 2;
+ }
+
+ return 0;
+}
+
+template<class VT>
+class KMacroMapExpander<QString,VT> : public KMacroExpanderBase {
+
+public:
+ KMacroMapExpander( const QMap<QString,VT> &map, QChar c = '%' ) :
+ KMacroExpanderBase( c ), macromap( map ) {}
+
+protected:
+ virtual int expandPlainMacro( const QString &str, uint pos, QStringList &ret );
+ virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
+
+private:
+ QMap<QString,VT> macromap;
+};
+
+template<class VT>
+int
+KMacroMapExpander<QString,VT>::expandPlainMacro( const QString &str, uint pos, QStringList &ret )
+{
+ if (isIdentifier( str[pos - 1].unicode() ))
+ return 0;
+ uint sl;
+ for (sl = 0; isIdentifier( str[pos + sl].unicode() ); sl++);
+ if (!sl)
+ return 0;
+ QMapConstIterator<QString,VT> it =
+ macromap.find( QConstString( str.unicode() + pos, sl ).string() );
+ if (it != macromap.end()) {
+ ret += it.data();
+ return sl;
+ }
+ return 0;
+}
+
+template<class VT>
+int
+KMacroMapExpander<QString,VT>::expandEscapedMacro( const QString &str, uint pos, QStringList &ret )
+{
+ if (str[pos + 1] == escapeChar()) {
+ ret += QString( escapeChar() );
+ return 2;
+ }
+ uint sl, rsl, rpos;
+ if (str[pos + 1] == '{') {
+ rpos = pos + 2;
+ for (sl = 0; str[rpos + sl] != '}'; sl++)
+ if (rpos + sl >= str.length())
+ return 0;
+ rsl = sl + 3;
+ } else {
+ rpos = pos + 1;
+ for (sl = 0; isIdentifier( str[rpos + sl].unicode() ); sl++);
+ rsl = sl + 1;
+ }
+ if (!sl)
+ return 0;
+ QMapConstIterator<QString,VT> it =
+ macromap.find( QConstString( str.unicode() + rpos, sl ).string() );
+ if (it != macromap.end()) {
+ ret += it.data();
+ return rsl;
+ }
+ return 0;
+}
+
+////////////
+
+int
+KCharMacroExpander::expandPlainMacro( const QString &str, uint pos, QStringList &ret )
+{
+ if (expandMacro( str[pos], ret ))
+ return 1;
+ return 0;
+}
+
+int
+KCharMacroExpander::expandEscapedMacro( const QString &str, uint pos, QStringList &ret )
+{
+ if (str[pos + 1] == escapeChar()) {
+ ret += QString( escapeChar() );
+ return 2;
+ }
+ if (expandMacro( str[pos+1], ret ))
+ return 2;
+ return 0;
+}
+
+int
+KWordMacroExpander::expandPlainMacro( const QString &str, uint pos, QStringList &ret )
+{
+ if (isIdentifier( str[pos - 1].unicode() ))
+ return 0;
+ uint sl;
+ for (sl = 0; isIdentifier( str[pos + sl].unicode() ); sl++);
+ if (!sl)
+ return 0;
+ if (expandMacro( QConstString( str.unicode() + pos, sl ).string(), ret ))
+ return sl;
+ return 0;
+}
+
+int
+KWordMacroExpander::expandEscapedMacro( const QString &str, uint pos, QStringList &ret )
+{
+ if (str[pos + 1] == escapeChar()) {
+ ret += QString( escapeChar() );
+ return 2;
+ }
+ uint sl, rsl, rpos;
+ if (str[pos + 1] == '{') {
+ rpos = pos + 2;
+ for (sl = 0; str[rpos + sl] != '}'; sl++)
+ if (rpos + sl >= str.length())
+ return 0;
+ rsl = sl + 3;
+ } else {
+ rpos = pos + 1;
+ for (sl = 0; isIdentifier( str[rpos + sl].unicode() ); sl++);
+ rsl = sl + 1;
+ }
+ if (!sl)
+ return 0;
+ if (expandMacro( QConstString( str.unicode() + rpos, sl ).string(), ret ))
+ return rsl;
+ return 0;
+}
+
+////////////
+
+template<class KT,class VT>
+inline QString
+TexpandMacros( const QString &ostr, const QMap<KT,VT> &map, QChar c )
+{
+ QString str( ostr );
+ KMacroMapExpander<KT,VT> kmx( map, c );
+ kmx.expandMacros( str );
+ return str;
+}
+
+template<class KT,class VT>
+inline QString
+TexpandMacrosShellQuote( const QString &ostr, const QMap<KT,VT> &map, QChar c )
+{
+ QString str( ostr );
+ KMacroMapExpander<KT,VT> kmx( map, c );
+ if (!kmx.expandMacrosShellQuote( str ))
+ return QString::null;
+ return str;
+}
+
+// public API
+namespace KMacroExpander {
+
+ QString expandMacros( const QString &ostr, const QMap<QChar,QString> &map, QChar c ) { return TexpandMacros( ostr, map, c ); }
+ QString expandMacrosShellQuote( const QString &ostr, const QMap<QChar,QString> &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
+ QString expandMacros( const QString &ostr, const QMap<QString,QString> &map, QChar c ) { return TexpandMacros( ostr, map, c ); }
+ QString expandMacrosShellQuote( const QString &ostr, const QMap<QString,QString> &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
+ QString expandMacros( const QString &ostr, const QMap<QChar,QStringList> &map, QChar c ) { return TexpandMacros( ostr, map, c ); }
+ QString expandMacrosShellQuote( const QString &ostr, const QMap<QChar,QStringList> &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
+ QString expandMacros( const QString &ostr, const QMap<QString,QStringList> &map, QChar c ) { return TexpandMacros( ostr, map, c ); }
+ QString expandMacrosShellQuote( const QString &ostr, const QMap<QString,QStringList> &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
+
+} // namespace
diff --git a/kdecore/kmacroexpander.h b/kdecore/kmacroexpander.h
new file mode 100644
index 000000000..deb12e284
--- /dev/null
+++ b/kdecore/kmacroexpander.h
@@ -0,0 +1,380 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2002-2003 Oswald Buddenhagen <ossi@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KMACROEXPANDER_H
+#define _KMACROEXPANDER_H
+
+#include <qstringlist.h>
+#include <qstring.h>
+#include <qmap.h>
+#include "kdelibs_export.h"
+
+/**
+ * Abstract base class for the worker classes behind the KMacroExpander namespace
+ * and the KCharMacroExpander and KWordMacroExpander classes.
+ *
+ * @since 3.1.3
+ * @author Oswald Buddenhagen <ossi@kde.org>
+ */
+class KDECORE_EXPORT KMacroExpanderBase {
+
+public:
+ /**
+ * Constructor.
+ * @param c escape char indicating start of macros, or QChar::null for none
+ */
+ KMacroExpanderBase( QChar c = '%' );
+
+ /**
+ * Destructor.
+ */
+ virtual ~KMacroExpanderBase();
+
+ /**
+ * Perform safe macro expansion (substitution) on a string.
+ *
+ * @param str the string in which macros are expanded in-place
+ */
+ void expandMacros( QString &str );
+
+ /*
+ * Perform safe macro expansion (substitution) on a string for use
+ * in shell commands.
+ *
+ * Explicitly supported shell constructs:
+ * \ '' "" $'' $"" {} () $(()) ${} $() ``
+ *
+ * Implicitly supported shell constructs:
+ * (())
+ *
+ * Unsupported shell constructs that will cause problems:
+ * @li Shortened "case $v in pat)" syntax. Use "case $v in (pat)" instead.
+ *
+ * The rest of the shell (incl. bash) syntax is simply ignored,
+ * as it is not expected to cause problems.
+ *
+ * Note that bash contains a bug which makes macro expansion within
+ * double quoted substitutions ("${VAR:-%macro}") inherently insecure.
+ *
+ * @param str the string in which macros are expanded in-place
+ * @param pos the position inside the string at which parsing/substitution
+ * should start, and upon exit where processing stopped
+ * @return false if the string could not be parsed and therefore no safe
+ * substitution was possible. Note that macros will have been processed
+ * up to the point where the error occurred. An unmatched closing paren
+ * or brace outside any shell construct is @em not an error (unlike in
+ * the function below), but still prematurely terminates processing.
+ */
+ bool expandMacrosShellQuote( QString &str, uint &pos );
+
+ /**
+ * Same as above, but always starts at position 0, and unmatched closing
+ * parens and braces are treated as errors.
+ */
+ bool expandMacrosShellQuote( QString &str );
+
+ /**
+ * Set the macro escape character.
+ * @param c escape char indicating start of macros, or QChar::null if none
+ */
+ void setEscapeChar( QChar c );
+
+ /**
+ * Obtain the macro escape character.
+ * @return escape char indicating start of macros, or QChar::null if none
+ */
+ QChar escapeChar() const;
+
+protected:
+ /**
+ * This function is called for every single char within the string if
+ * the escape char is QChar::null. It should determine whether the
+ * string starting at @p pos within @p str is a valid macro and return
+ * the substitution value for it if so.
+ * @param str the input string
+ * @param pos the offset within @p str
+ * @param ret return value: the string to substitute for the macro
+ * @return if greater than zero, the number of chars at @p pos in @p str
+ * to substitute with @p ret (i.e., a valid macro was found). if less
+ * than zero, subtract this value from @p pos (to skip a macro, i.e.,
+ * substitute it with itself). zero requests no special action.
+ */
+ virtual int expandPlainMacro( const QString &str, uint pos, QStringList &ret );
+
+ /**
+ * This function is called every time the escape char is found if it is
+ * not QChar::null. It should determine whether the
+ * string starting at @p pos witin @p str is a valid macro and return
+ * the substitution value for it if so.
+ * @param str the input string
+ * @param pos the offset within @p str. Note that this is the position of
+ * the occurrence of the escape char
+ * @param ret return value: the string to substitute for the macro
+ * @return if greater than zero, the number of chars at @p pos in @p str
+ * to substitute with @p ret (i.e., a valid macro was found). if less
+ * than zero, subtract this value from @p pos (to skip a macro, i.e.,
+ * substitute it with itself). zero requests no special action.
+ */
+ virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
+
+private:
+ QChar escapechar;
+};
+
+/**
+ * Abstract base class for simple word macro substitutors. Use this instead of
+ * the functions in the KMacroExpander namespace if speculatively pre-filling
+ * the substitution map would be too expensive.
+ *
+ * A typical application:
+ *
+ * \code
+ * class MyClass {
+ * ...
+ * private:
+ * QString m_str;
+ * ...
+ * friend class MyExpander;
+ * };
+ *
+ * class MyExpander : public KWordMacroExpander {
+ * public:
+ * MyExpander( MyClass *_that ) : KWordMacroExpander(), that( _that ) {}
+ * protected:
+ * virtual bool expandMacro( const QString &str, QStringList &ret );
+ * private:
+ * MyClass *that;
+ * };
+ *
+ * bool MyExpander::expandMacro( const QString &str, QStringList &ret )
+ * {
+ * if (str == "macro") {
+ * ret += complexOperation( that->m_str );
+ * return true;
+ * }
+ * return false;
+ * }
+ *
+ * ... MyClass::...(...)
+ * {
+ * QString str;
+ * ...
+ * MyExpander mx( this );
+ * mx.expandMacrosShellQuote( str );
+ * ...
+ * }
+ * \endcode
+ *
+ * Alternatively MyClass could inherit from KWordMacroExpander directly.
+ *
+ * @since 3.3
+ * @author Oswald Buddenhagen <ossi@kde.org>
+ */
+class KDECORE_EXPORT KWordMacroExpander : public KMacroExpanderBase {
+
+public:
+ /**
+ * Constructor.
+ * @param c escape char indicating start of macros, or QChar::null for none
+ */
+ KWordMacroExpander( QChar c = '%' ) : KMacroExpanderBase( c ) {}
+
+protected:
+ virtual int expandPlainMacro( const QString &str, uint pos, QStringList &ret );
+ virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
+
+ /**
+ * Return substitution list @p ret for string macro @p str.
+ * @param str the macro to expand
+ * @param ret return variable reference. It is guaranteed to be empty
+ * when expandMacro is entered.
+ * @return @c true iff @p chr was a recognized macro name
+ */
+ virtual bool expandMacro( const QString &str, QStringList &ret ) = 0;
+};
+
+/**
+ * Abstract base class for single char macro substitutors. Use this instead of
+ * the functions in the KMacroExpander namespace if speculatively pre-filling
+ * the substitution map would be too expensive.
+ *
+ * See KWordMacroExpander for a sample application.
+ *
+ * @since 3.3
+ * @author Oswald Buddenhagen <ossi@kde.org>
+ */
+class KDECORE_EXPORT KCharMacroExpander : public KMacroExpanderBase {
+
+public:
+ /**
+ * Constructor.
+ * @param c escape char indicating start of macros, or QChar::null for none
+ */
+ KCharMacroExpander( QChar c = '%' ) : KMacroExpanderBase( c ) {}
+
+protected:
+ virtual int expandPlainMacro( const QString &str, uint pos, QStringList &ret );
+ virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
+
+ /**
+ * Return substitution list @p ret for single-character macro @p chr.
+ * @param chr the macro to expand
+ * @param ret return variable reference. It is guaranteed to be empty
+ * when expandMacro is entered.
+ * @return @c true iff @p chr was a recognized macro name
+ */
+ virtual bool expandMacro( QChar chr, QStringList &ret ) = 0;
+};
+
+/**
+ * A group of functions providing macro expansion (substitution) in strings,
+ * optionally with quoting appropriate for shell execution.
+ * @since 3.1.3
+ */
+namespace KMacroExpander {
+ /**
+ * Perform safe macro expansion (substitution) on a string.
+ * The escape char must be quoted with itself to obtain its literal
+ * representation in the resulting string.
+ *
+ * @param str The string to expand
+ * @param map map with substitutions
+ * @param c escape char indicating start of macro, or QChar::null if none
+ * @return the string with all valid macros expanded
+ *
+ * \code
+ * // Code example
+ * QMap<QChar,QString> map;
+ * map.insert('u', "/tmp/myfile.txt");
+ * map.insert('n', "My File");
+ * QString s = "%% Title: %u:%n";
+ * s = KMacroExpander::expandMacros(s, map);
+ * // s is now "% Title: /tmp/myfile.txt:My File";
+ * \endcode
+ */
+ KDECORE_EXPORT QString expandMacros( const QString &str, const QMap<QChar,QString> &map, QChar c = '%' );
+
+ /**
+ * Perform safe macro expansion (substitution) on a string for use
+ * in shell commands.
+ * The escape char must be quoted with itself to obtain its literal
+ * representation in the resulting string.
+ *
+ * @param str The string to expand
+ * @param map map with substitutions
+ * @param c escape char indicating start of macro, or QChar::null if none
+ * @return the string with all valid macros expanded, or a null string
+ * if a shell syntax error was detected in the command
+ *
+ * \code
+ * // Code example
+ * QMap<QChar,QString> map;
+ * map.insert('u', "/tmp/myfile.txt");
+ * map.insert('n', "My File");
+ * QString s = "kedit --caption %n %u";
+ * s = KMacroExpander::expandMacrosShellQuote(s, map);
+ * // s is now "kedit --caption 'My File' '/tmp/myfile.txt'";
+ * system(QFile::encodeName(s));
+ * \endcode
+ */
+ KDECORE_EXPORT QString expandMacrosShellQuote( const QString &str, const QMap<QChar,QString> &map, QChar c = '%' );
+
+ /**
+ * Perform safe macro expansion (substitution) on a string.
+ * The escape char must be quoted with itself to obtain its literal
+ * representation in the resulting string.
+ * Macro names can consist of chars in the range [A-Za-z0-9_];
+ * use braces to delimit macros from following words starting
+ * with these chars, or to use other chars for macro names.
+ *
+ * @param str The string to expand
+ * @param map map with substitutions
+ * @param c escape char indicating start of macro, or QChar::null if none
+ * @return the string with all valid macros expanded
+ *
+ * \code
+ * // Code example
+ * QMap<QString,QString> map;
+ * map.insert("url", "/tmp/myfile.txt");
+ * map.insert("name", "My File");
+ * QString s = "Title: %{url}-%name";
+ * s = KMacroExpander::expandMacros(s, map);
+ * // s is now "Title: /tmp/myfile.txt-My File";
+ * \endcode
+ */
+ KDECORE_EXPORT QString expandMacros( const QString &str, const QMap<QString,QString> &map, QChar c = '%' );
+
+ /**
+ * Perform safe macro expansion (substitution) on a string for use
+ * in shell commands.
+ * The escape char must be quoted with itself to obtain its literal
+ * representation in the resulting string.
+ * Macro names can consist of chars in the range [A-Za-z0-9_];
+ * use braces to delimit macros from following words starting
+ * with these chars, or to use other chars for macro names.
+ *
+ * @param str The string to expand
+ * @param map map with substitutions
+ * @param c escape char indicating start of macro, or QChar::null if none
+ * @return the string with all valid macros expanded, or a null string
+ * if a shell syntax error was detected in the command
+ *
+ * \code
+ * // Code example
+ * QMap<QString,QString> map;
+ * map.insert("url", "/tmp/myfile.txt");
+ * map.insert("name", "My File");
+ * QString s = "kedit --caption %name %{url}";
+ * s = KMacroExpander::expandMacrosShellQuote(s, map);
+ * // s is now "kedit --caption 'My File' '/tmp/myfile.txt'";
+ * system(QFile::encodeName(s));
+ * \endcode
+ */
+ KDECORE_EXPORT QString expandMacrosShellQuote( const QString &str, const QMap<QString,QString> &map, QChar c = '%' );
+
+ /**
+ * Same as above, except that the macros expand to string lists that
+ * are simply join(" ")ed together.
+ */
+ KDECORE_EXPORT QString expandMacros( const QString &str, const QMap<QChar,QStringList> &map, QChar c = '%' );
+ /**
+ * Same as above, except that the macros expand to string lists that
+ * are simply join(" ")ed together.
+ */
+ KDECORE_EXPORT QString expandMacros( const QString &str, const QMap<QString,QStringList> &map, QChar c = '%' );
+
+ /**
+ * Same as above, except that the macros expand to string lists.
+ * If the macro appears inside a quoted string, the list is simply
+ * join(" ")ed together; otherwise every element expands to a separate
+ * quoted string.
+ */
+ KDECORE_EXPORT QString expandMacrosShellQuote( const QString &str, const QMap<QChar,QStringList> &map, QChar c = '%' );
+ /**
+ * Same as above, except that the macros expand to string lists.
+ * If the macro appears inside a quoted string, the list is simply
+ * join(" ")ed together; otherwise every element expands to a separate
+ * quoted string.
+ */
+ KDECORE_EXPORT QString expandMacrosShellQuote( const QString &str, const QMap<QString,QStringList> &map, QChar c = '%' );
+}
+
+#endif /* _KMACROEXPANDER_H */
diff --git a/kdecore/kmanagerselection.cpp b/kdecore/kmanagerselection.cpp
new file mode 100644
index 000000000..f82df9ff1
--- /dev/null
+++ b/kdecore/kmanagerselection.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+
+ $Id$
+
+ Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+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 OR COPYRIGHT HOLDERS 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.
+
+****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <qobject.h>
+#ifdef Q_WS_X11 // FIXME(E)
+
+#include "kmanagerselection.h"
+
+#include <kdebug.h>
+#include <qwidget.h>
+#include <kapplication.h>
+#include <kxerrorhandler.h>
+#include <X11/Xatom.h>
+
+class KSelectionOwnerPrivate
+ : public QWidget
+ {
+ public:
+ KSelectionOwnerPrivate( KSelectionOwner* owner );
+ protected:
+ virtual bool x11Event( XEvent* ev );
+ private:
+ KSelectionOwner* owner;
+ };
+
+KSelectionOwnerPrivate::KSelectionOwnerPrivate( KSelectionOwner* owner_P )
+ : owner( owner_P )
+ {
+ kapp->installX11EventFilter( this );
+ }
+
+bool KSelectionOwnerPrivate::x11Event( XEvent* ev_P )
+ {
+ return owner->filterEvent( ev_P );
+ }
+
+KSelectionOwner::KSelectionOwner( Atom selection_P, int screen_P, QObject* parent_P )
+ : QObject( parent_P ),
+ selection( selection_P ),
+ screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
+ window( None ),
+ timestamp( CurrentTime ),
+ extra1( 0 ), extra2( 0 ),
+ d( new KSelectionOwnerPrivate( this ))
+ {
+ }
+
+KSelectionOwner::KSelectionOwner( const char* selection_P, int screen_P, QObject* parent_P )
+ : QObject( parent_P ),
+ selection( XInternAtom( qt_xdisplay(), selection_P, False )),
+ screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
+ window( None ),
+ timestamp( CurrentTime ),
+ extra1( 0 ), extra2( 0 ),
+ d( new KSelectionOwnerPrivate( this ))
+ {
+ }
+
+KSelectionOwner::~KSelectionOwner()
+ {
+ release();
+ delete d;
+ }
+
+bool KSelectionOwner::claim( bool force_P, bool force_kill_P )
+ {
+ if( manager_atom == None )
+ getAtoms();
+ if( timestamp != CurrentTime )
+ release();
+ Display* const dpy = qt_xdisplay();
+ Window prev_owner = XGetSelectionOwner( dpy, selection );
+ if( prev_owner != None )
+ {
+ if( !force_P )
+ {
+// kdDebug() << "Selection already owned, failing" << endl;
+ return false;
+ }
+ XSelectInput( dpy, prev_owner, StructureNotifyMask );
+ }
+ XSetWindowAttributes attrs;
+ attrs.override_redirect = True;
+ window = XCreateWindow( dpy, RootWindow( dpy, screen ), 0, 0, 1, 1,
+ 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect, &attrs );
+// kdDebug() << "Using owner window " << window << endl;
+ Atom tmp = XA_ATOM;
+ XSelectInput( dpy, window, PropertyChangeMask );
+ XChangeProperty( dpy, window, XA_ATOM, XA_ATOM, 32, PropModeReplace,
+ reinterpret_cast< unsigned char* >( &tmp ), 1 );
+ XEvent ev;
+ XSync( dpy, False );
+ XCheckTypedWindowEvent( dpy, window, PropertyNotify, &ev ); // get a timestamp
+ timestamp = ev.xproperty.time;
+ XSelectInput( dpy, window, StructureNotifyMask ); // for DestroyNotify
+ XSetSelectionOwner( dpy, selection, window, timestamp );
+ Window new_owner = XGetSelectionOwner( dpy, selection );
+ if( new_owner != window )
+ {
+// kdDebug() << "Failed to claim selection : " << new_owner << endl;
+ XDestroyWindow( dpy, window );
+ timestamp = CurrentTime;
+ return false;
+ }
+ if( prev_owner != None )
+ {
+// kdDebug() << "Waiting for previous owner to disown" << endl;
+ for( int cnt = 0;
+ ;
+ ++cnt )
+ {
+ if( XCheckTypedWindowEvent( dpy, prev_owner, DestroyNotify, &ev ) == True )
+ break;
+ struct timeval tm = { 0, 50000 }; // 50 ms
+ select( 0, NULL, NULL, NULL, &tm );
+ if( cnt == 19 )
+ {
+ if( force_kill_P )
+ {
+// kdDebug() << "Killing previous owner" << endl;
+ XKillClient( dpy, prev_owner );
+ }
+ break;
+ }
+ }
+ }
+ ev.type = ClientMessage;
+ ev.xclient.window = RootWindow( dpy, screen );
+ ev.xclient.display = dpy;
+ ev.xclient.message_type = manager_atom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[ 0 ] = timestamp;
+ ev.xclient.data.l[ 1 ] = selection;
+ ev.xclient.data.l[ 2 ] = window;
+ ev.xclient.data.l[ 3 ] = extra1;
+ ev.xclient.data.l[ 4 ] = extra2;
+ XSendEvent( dpy, RootWindow( dpy, screen ), False, StructureNotifyMask, &ev );
+// kdDebug() << "Claimed selection" << endl;
+ return true;
+ }
+
+// destroy resource first
+void KSelectionOwner::release()
+ {
+ if( timestamp == CurrentTime )
+ return;
+ XDestroyWindow( qt_xdisplay(), window ); // also makes the selection not owned
+// kdDebug() << "Releasing selection" << endl;
+ timestamp = CurrentTime;
+ }
+
+Window KSelectionOwner::ownerWindow() const
+ {
+ if( timestamp == CurrentTime )
+ return None;
+ return window;
+ }
+
+void KSelectionOwner::setData( long extra1_P, long extra2_P )
+ {
+ extra1 = extra1_P;
+ extra2 = extra2_P;
+ }
+
+bool KSelectionOwner::filterEvent( XEvent* ev_P )
+ {
+ if( timestamp != CurrentTime && ev_P->xany.window == window )
+ {
+ if( handleMessage( ev_P ))
+ return true;
+ }
+ switch( ev_P->type )
+ {
+ case SelectionClear:
+ {
+ if( timestamp == CurrentTime || ev_P->xselectionclear.selection != selection )
+ return false;
+ timestamp = CurrentTime;
+// kdDebug() << "Lost selection" << endl;
+ emit lostOwnership();
+ XSelectInput( qt_xdisplay(), window, 0 );
+ XDestroyWindow( qt_xdisplay(), window );
+ return false;
+ }
+ case DestroyNotify:
+ {
+ if( timestamp == CurrentTime || ev_P->xdestroywindow.window != window )
+ return false;
+ timestamp = CurrentTime;
+// kdDebug() << "Lost selection (destroyed)" << endl;
+ emit lostOwnership();
+ return false;
+ }
+ case SelectionNotify:
+ {
+ if( timestamp == CurrentTime || ev_P->xselection.selection != selection )
+ return false;
+ // ignore?
+ return false;
+ }
+ case SelectionRequest:
+ filter_selection_request( ev_P->xselectionrequest );
+ return false;
+ }
+ return false;
+ }
+
+bool KSelectionOwner::handleMessage( XEvent* )
+ {
+ return false;
+ }
+
+void KSelectionOwner::filter_selection_request( XSelectionRequestEvent& ev_P )
+ {
+ if( timestamp == CurrentTime || ev_P.selection != selection )
+ return;
+ if( ev_P.time != CurrentTime
+ && ev_P.time - timestamp > 1U << 31 )
+ return; // too old or too new request
+// kdDebug() << "Got selection request" << endl;
+ bool handled = false;
+ if( ev_P.target == xa_multiple )
+ {
+ if( ev_P.property != None )
+ {
+ const int MAX_ATOMS = 100; // no need to handle more?
+ int format;
+ Atom type;
+ unsigned long items;
+ unsigned long after;
+ unsigned char* data;
+ if( XGetWindowProperty( qt_xdisplay(), ev_P.requestor, ev_P.property, 0,
+ MAX_ATOMS, False, AnyPropertyType, &type, &format, &items, &after,
+ &data ) == Success && format == 32 && items % 2 == 0 )
+ {
+ bool handled_array[ MAX_ATOMS ];
+ Atom* atoms = reinterpret_cast< Atom* >( data );
+ for( unsigned int i = 0;
+ i < items / 2;
+ ++i )
+ handled_array[ i ] = handle_selection(
+ atoms[ i * 2 ], atoms[ i * 2 + 1 ], ev_P.requestor );
+ bool all_handled = true;
+ for( unsigned int i = 0;
+ i < items / 2;
+ ++i )
+ if( !handled_array[ i ] )
+ {
+ all_handled = false;
+ atoms[ i * 2 + 1 ] = None;
+ }
+ if( !all_handled )
+ XChangeProperty( qt_xdisplay(), ev_P.requestor, ev_P.property, XA_ATOM,
+ 32, PropModeReplace, reinterpret_cast< unsigned char* >( atoms ), items );
+ handled = true;
+ XFree( data );
+ }
+ }
+ }
+ else
+ {
+ if( ev_P.property == None ) // obsolete client
+ ev_P.property = ev_P.target;
+ handled = handle_selection( ev_P.target, ev_P.property, ev_P.requestor );
+ }
+ XEvent ev;
+ ev.xselection.type = SelectionNotify;
+ ev.xselection.display = qt_xdisplay();
+ ev.xselection.requestor = ev_P.requestor;
+ ev.xselection.target = ev_P.target;
+ ev.xselection.property = handled ? ev_P.property : None;
+ XSendEvent( qt_xdisplay(), ev_P.requestor, False, 0, &ev );
+ }
+
+bool KSelectionOwner::handle_selection( Atom target_P, Atom property_P, Window requestor_P )
+ {
+ if( target_P == xa_timestamp )
+ {
+// kdDebug() << "Handling timestamp request" << endl;
+ XChangeProperty( qt_xdisplay(), requestor_P, property_P, XA_INTEGER, 32,
+ PropModeReplace, reinterpret_cast< unsigned char* >( &timestamp ), 1 );
+ }
+ else if( target_P == xa_targets )
+ replyTargets( property_P, requestor_P );
+ else if( genericReply( target_P, property_P, requestor_P ))
+ ; // handled
+ else
+ return false; // unknown
+ return true;
+ }
+
+void KSelectionOwner::replyTargets( Atom property_P, Window requestor_P )
+ {
+ Atom atoms[ 3 ] = { xa_multiple, xa_timestamp, xa_targets };
+// kdDebug() << "Handling targets request" << endl;
+ XChangeProperty( qt_xdisplay(), requestor_P, property_P, XA_ATOM, 32, PropModeReplace,
+ reinterpret_cast< unsigned char* >( atoms ), 3 );
+ }
+
+bool KSelectionOwner::genericReply( Atom, Atom, Window )
+ {
+ return false;
+ }
+
+void KSelectionOwner::getAtoms()
+ {
+ if( manager_atom == None )
+ {
+ Atom atoms[ 4 ];
+ const char* const names[] =
+ { "MANAGER", "MULTIPLE", "TARGETS", "TIMESTAMP" };
+ XInternAtoms( qt_xdisplay(), const_cast< char** >( names ), 4, False, atoms );
+ manager_atom = atoms[ 0 ];
+ xa_multiple = atoms[ 1];
+ xa_targets = atoms[ 2 ];
+ xa_timestamp = atoms[ 3 ];
+ }
+ }
+
+Atom KSelectionOwner::manager_atom = None;
+Atom KSelectionOwner::xa_multiple = None;
+Atom KSelectionOwner::xa_targets = None;
+Atom KSelectionOwner::xa_timestamp = None;
+
+//*******************************************
+// KSelectionWatcher
+//*******************************************
+
+
+class KSelectionWatcherPrivate
+ : public QWidget
+ {
+ public:
+ KSelectionWatcherPrivate( KSelectionWatcher* watcher );
+ protected:
+ virtual bool x11Event( XEvent* ev );
+ private:
+ KSelectionWatcher* watcher;
+ };
+
+KSelectionWatcherPrivate::KSelectionWatcherPrivate( KSelectionWatcher* watcher_P )
+ : watcher( watcher_P )
+ {
+ kapp->installX11EventFilter( this );
+ }
+
+bool KSelectionWatcherPrivate::x11Event( XEvent* ev_P )
+ {
+ watcher->filterEvent( ev_P );
+ return false;
+ }
+
+
+KSelectionWatcher::KSelectionWatcher( Atom selection_P, int screen_P, QObject* parent_P )
+ : QObject( parent_P ),
+ selection( selection_P ),
+ screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
+ selection_owner( None ),
+ d( new KSelectionWatcherPrivate( this ))
+ {
+ init();
+ }
+
+KSelectionWatcher::KSelectionWatcher( const char* selection_P, int screen_P, QObject* parent_P )
+ : QObject( parent_P ),
+ selection( XInternAtom( qt_xdisplay(), selection_P, False )),
+ screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
+ selection_owner( None ),
+ d( new KSelectionWatcherPrivate( this ))
+ {
+ init();
+ }
+
+KSelectionWatcher::~KSelectionWatcher()
+ {
+ delete d;
+ }
+
+void KSelectionWatcher::init()
+ {
+ if( manager_atom == None )
+ {
+ Display* const dpy = qt_xdisplay();
+ manager_atom = XInternAtom( dpy, "MANAGER", False );
+ XWindowAttributes attrs;
+ XGetWindowAttributes( dpy, RootWindow( dpy, screen ), &attrs );
+ long event_mask = attrs.your_event_mask;
+ // StructureNotifyMask on the root window is needed
+ XSelectInput( dpy, RootWindow( dpy, screen ), event_mask | StructureNotifyMask );
+ }
+ }
+
+Window KSelectionWatcher::owner()
+ {
+ Display* const dpy = qt_xdisplay();
+ KXErrorHandler handler;
+ Window current_owner = XGetSelectionOwner( dpy, selection );
+ if( current_owner == None )
+ return None;
+ if( current_owner == selection_owner )
+ return selection_owner;
+ XSelectInput( dpy, current_owner, StructureNotifyMask );
+ if( !handler.error( true ) && current_owner == XGetSelectionOwner( dpy, selection ))
+ {
+// kdDebug() << "isOwner: " << current_owner << endl;
+ selection_owner = current_owner;
+ emit newOwner( selection_owner );
+ }
+ else
+ selection_owner = None;
+ return selection_owner;
+ }
+
+// void return value in order to allow more watchers in one process
+void KSelectionWatcher::filterEvent( XEvent* ev_P )
+ {
+ if( ev_P->type == ClientMessage )
+ {
+// kdDebug() << "got ClientMessage" << endl;
+ if( ev_P->xclient.message_type != manager_atom
+ || ev_P->xclient.data.l[ 1 ] != static_cast< long >( selection ))
+ return;
+// kdDebug() << "handling message" << endl;
+ if( static_cast< long >( owner()) == ev_P->xclient.data.l[ 2 ] )
+ {
+ // owner() emits newOwner() if needed, no need to do it twice
+ }
+ return;
+ }
+ if( ev_P->type == DestroyNotify )
+ {
+ if( selection_owner == None || ev_P->xdestroywindow.window != selection_owner )
+ return;
+ selection_owner = None; // in case the exactly same ID gets reused as the owner
+ if( owner() == None )
+ emit lostOwner(); // it must be safe to delete 'this' in a slot
+ return;
+ }
+ return;
+ }
+
+Atom KSelectionWatcher::manager_atom = None;
+
+void KSelectionOwner::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KSelectionWatcher::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kmanagerselection.moc"
+#endif
diff --git a/kdecore/kmanagerselection.h b/kdecore/kmanagerselection.h
new file mode 100644
index 000000000..9b277b998
--- /dev/null
+++ b/kdecore/kmanagerselection.h
@@ -0,0 +1,229 @@
+/****************************************************************************
+
+ Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
+
+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 OR COPYRIGHT HOLDERS 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.
+
+****************************************************************************/
+
+#ifndef __KMANAGERSELECTION_H
+#define __KMANAGERSELECTION_H
+
+#include <qobject.h>
+#include <kdelibs_export.h>
+
+#ifdef Q_WS_X11 // FIXME(E)
+
+#include <X11/Xlib.h>
+
+class KSelectionOwnerPrivate;
+
+/**
+ This class implements claiming and owning manager selections, as described
+ in the ICCCM, section 2.8. The selection atom is passed to the constructor,
+ claim() attemps to claim ownership of the selection, release() gives up
+ the selection ownership. Signal lostOwnership() is emitted when the selection
+ is claimed by another owner.
+ @since 3.2
+ @short ICCCM manager selection owner
+*/
+class KDECORE_EXPORT KSelectionOwner
+ : public QObject
+ {
+ Q_OBJECT
+ public:
+ /**
+ * This constructor initializes the object, but doesn't perform any
+ * operation on the selection.
+ *
+ * @param selection atom representing the manager selection
+ * @param screen X screen, or -1 for default
+ * @param parent parent object, or NULL if there is none
+ */
+ KSelectionOwner( Atom selection, int screen = -1, QObject* parent = NULL );
+ /**
+ * @overload
+ * This constructor accepts the selection name and creates the appropriate atom
+ * for it automatically.
+ *
+ * @param selection name of the manager selection
+ * @param screen X screen, or -1 for default
+ * @param parent parent object, or NULL if there is none
+ */
+ KSelectionOwner( const char* selection, int screen = -1, QObject* parent = NULL );
+ /**
+ * Destructor. Calls release().
+ */
+ virtual ~KSelectionOwner();
+ /**
+ * This function attemps to claim ownership of the manager selection, using
+ * the current X timestamp. If @p force is false, and the selection is already
+ * owned, the selection is not claimed, and false is returned. If claiming
+ * is forced and the selection is owned by another client, it is waited for up to 1 second
+ * for the previous owner to disown the selection, if @p force_kill is true,
+ * and the previous owner fails to disown the selection in time,
+ * it will be forcibly killed. True is returned after successfully claiming
+ * ownership of the selection.
+ */
+ bool claim( bool force, bool force_kill = true );
+ /**
+ * If the selection is owned, the ownership is given up.
+ */
+ void release();
+ /**
+ * If the selection is owned, returns the window used internally
+ * for owning the selection.
+ */
+ Window ownerWindow() const; // None if not owning the selection
+ /**
+ * @internal
+ */
+ bool filterEvent( XEvent* ev_P ); // internal
+ signals:
+ /**
+ * This signal is emitted if the selection was owned and the ownership
+ * has been lost due to another client claiming it, this signal is emitted.
+ * IMPORTANT: It's not safe to delete the instance in a slot connected
+ * to this signal.
+ */
+ void lostOwnership();
+ protected:
+ /**
+ * Called for every X event received on the window used for owning
+ * the selection. If true is returned, the event is filtered out.
+ */
+ virtual bool handleMessage( XEvent* ev );
+ /**
+ * Called when a SelectionRequest event is received. A reply should
+ * be sent using the selection handling mechanism described in the ICCCM
+ * section 2.
+ *
+ * @param target requested target type
+ * @param property property to use for the reply data
+ * @param requestor requestor window
+ */
+ virtual bool genericReply( Atom target, Atom property, Window requestor );
+ /**
+ * Called to announce the supported targets, as described in the ICCCM
+ * section 2.6. The default implementation announces the required targets
+ * MULTIPLE, TIMESTAMP and TARGETS.
+ */
+ virtual void replyTargets( Atom property, Window requestor );
+ /**
+ * Called to create atoms needed for claiming the selection and
+ * communication using the selection handling mechanism. The default
+ * implementation must be called if reimplemented. This method
+ * may be called repeatedly.
+ */
+ virtual void getAtoms();
+ /**
+ * Sets extra data to be sent in the message sent to root window
+ * after successfully claiming a selection. These extra data
+ * are in data.l[3] and data.l[4] fields of the XClientMessage.
+ */
+ void setData( long extra1, long extra2 );
+ private:
+ void filter_selection_request( XSelectionRequestEvent& ev_P );
+ bool handle_selection( Atom target_P, Atom property_P, Window requestor_P );
+ const Atom selection;
+ const int screen;
+ Window window;
+ Time timestamp;
+ long extra1, extra2;
+ static Atom manager_atom;
+ static Atom xa_multiple;
+ static Atom xa_targets;
+ static Atom xa_timestamp;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ KSelectionOwnerPrivate* d;
+ };
+
+class KSelectionWatcherPrivate;
+
+/**
+ This class implements watching manager selections, as described in the ICCCM
+ section 2.8. It emits signal newOwner() when a new owner claim the selection,
+ and emits lostOwner() when the selection ownership is given up. To find
+ out current owner of the selection, owner() can be used.
+ @since 3.2
+ @short ICCCM manager selection watching
+*/
+class KDECORE_EXPORT KSelectionWatcher
+ : public QObject
+ {
+ Q_OBJECT
+ public:
+ /**
+ * This constructor initializes the object, but doesn't perform any
+ * operation on the selection.
+ *
+ * @param selection atom representing the manager selection
+ * @param screen X screen, or -1 for default
+ * @param parent parent object, or NULL if there is none
+ */
+ KSelectionWatcher( Atom selection, int screen = -1, QObject* parent = NULL );
+ /**
+ * @overload
+ * This constructor accepts the selection name and creates the appropriate atom
+ * for it automatically.
+ *
+ * @param selection name of the manager selection
+ * @param screen X screen, or -1 for default
+ * @param parent parent object, or NULL if there is none
+ */
+ KSelectionWatcher( const char* selection, int screen = -1, QObject* parent = NULL );
+ virtual ~KSelectionWatcher();
+ /**
+ * Return the current owner of the manager selection, if any.
+ */
+ Window owner();
+ /**
+ * @internal
+ */
+ void filterEvent( XEvent* ev_P ); // internal
+ signals:
+ /**
+ * This signal is emitted when the selection is successfully claimed by a new
+ * owner.
+ * @param owner the new owner of the selection
+ */
+ void newOwner( Window owner );
+ /**
+ * This signal is emitted when the selection is given up, i.e. there's no
+ * owner. Note that the selection may be immediatelly claimed again,
+ * so the newOwner() signal may be emitted right after this one.
+ * It's safe to delete the instance in a slot connected to this signal.
+ */
+ void lostOwner();
+ private:
+ void init();
+ const Atom selection;
+ const int screen;
+ Window selection_owner;
+ static Atom manager_atom;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ KSelectionWatcherPrivate* d;
+ };
+
+#endif
+#endif
diff --git a/kdecore/kmdcodec.cpp b/kdecore/kmdcodec.cpp
new file mode 100644
index 000000000..10fca9307
--- /dev/null
+++ b/kdecore/kmdcodec.cpp
@@ -0,0 +1,1510 @@
+/*
+ Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org>
+ Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License (LGPL)
+ version 2 as published by the Free Software Foundation.
+
+ 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 Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ RFC 1321 "MD5 Message-Digest Algorithm" Copyright (C) 1991-1992.
+ RSA Data Security, Inc. Created 1991. All rights reserved.
+
+ The KMD5 class is based on a C++ implementation of
+ "RSA Data Security, Inc. MD5 Message-Digest Algorithm" by
+ Mordechai T. Abzug, Copyright (c) 1995. This implementation
+ passes the test-suite as defined in RFC 1321.
+
+ The encoding and decoding utilities in KCodecs with the exception of
+ quoted-printable are based on the java implementation in HTTPClient
+ package by Ronald Tschalär Copyright (C) 1996-1999.
+
+ The quoted-printable codec as described in RFC 2045, section 6.7. is by
+ Rik Hemsley (C) 2001.
+
+ KMD4 class based on the LGPL code of Copyright (C) 2001 Nikos Mavroyanopoulos
+ The algorithm is due to Ron Rivest. This code is based on code
+ written by Colin Plumb in 1993.
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <kdebug.h>
+#include "kmdcodec.h"
+
+#define KMD5_S11 7
+#define KMD5_S12 12
+#define KMD5_S13 17
+#define KMD5_S14 22
+#define KMD5_S21 5
+#define KMD5_S22 9
+#define KMD5_S23 14
+#define KMD5_S24 20
+#define KMD5_S31 4
+#define KMD5_S32 11
+#define KMD5_S33 16
+#define KMD5_S34 23
+#define KMD5_S41 6
+#define KMD5_S42 10
+#define KMD5_S43 15
+#define KMD5_S44 21
+
+const char KCodecs::Base64EncMap[64] =
+{
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
+ 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F
+};
+
+const char KCodecs::Base64DecMap[128] =
+{
+ 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,
+ 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x3C, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const char KCodecs::UUEncMap[64] =
+{
+ 0x60, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F
+};
+
+const char KCodecs::UUDecMap[128] =
+{
+ 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, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 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
+};
+
+const char KCodecs::hexChars[16] =
+{
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+const unsigned int KCodecs::maxQPLineLength = 70;
+
+
+/******************************** KCodecs ********************************/
+// strchr(3) for broken systems.
+static int rikFindChar(register const char * _s, const char c)
+{
+ register const char * s = _s;
+
+ while (true)
+ {
+ if ((0 == *s) || (c == *s)) break; ++s;
+ if ((0 == *s) || (c == *s)) break; ++s;
+ if ((0 == *s) || (c == *s)) break; ++s;
+ if ((0 == *s) || (c == *s)) break; ++s;
+ }
+
+ return s - _s;
+}
+
+QCString KCodecs::quotedPrintableEncode(const QByteArray& in, bool useCRLF)
+{
+ QByteArray out;
+ quotedPrintableEncode (in, out, useCRLF);
+ return QCString (out.data(), out.size()+1);
+}
+
+QCString KCodecs::quotedPrintableEncode(const QCString& str, bool useCRLF)
+{
+ if (str.isEmpty())
+ return "";
+
+ QByteArray in (str.length());
+ memcpy (in.data(), str.data(), str.length());
+ return quotedPrintableEncode(in, useCRLF);
+}
+
+void KCodecs::quotedPrintableEncode(const QByteArray& in, QByteArray& out, bool useCRLF)
+{
+ out.resize (0);
+ if (in.isEmpty())
+ return;
+
+ char *cursor;
+ const char *data;
+ unsigned int lineLength;
+ unsigned int pos;
+
+ const unsigned int length = in.size();
+ const unsigned int end = length - 1;
+
+
+ // Reasonable guess for output size when we're encoding
+ // mostly-ASCII data. It doesn't really matter, because
+ // the underlying allocation routines are quite efficient,
+ // but it's nice to have 0 allocations in many cases.
+ out.resize ((length*12)/10);
+ cursor = out.data();
+ data = in.data();
+ lineLength = 0;
+ pos = 0;
+
+ for (unsigned int i = 0; i < length; i++)
+ {
+ unsigned char c (data[i]);
+
+ // check if we have to enlarge the output buffer, use
+ // a safety margin of 16 byte
+ pos = cursor-out.data();
+ if (out.size()-pos < 16) {
+ out.resize(out.size()+4096);
+ cursor = out.data()+pos;
+ }
+
+ // Plain ASCII chars just go straight out.
+
+ if ((c >= 33) && (c <= 126) && ('=' != c))
+ {
+ *cursor++ = c;
+ ++lineLength;
+ }
+
+ // Spaces need some thought. We have to encode them at eol (or eof).
+
+ else if (' ' == c)
+ {
+ if
+ (
+ (i >= length)
+ ||
+ ((i < end) && ((useCRLF && ('\r' == data[i + 1]) && ('\n' == data[i + 2]))
+ ||
+ (!useCRLF && ('\n' == data[i + 1]))))
+ )
+ {
+ *cursor++ = '=';
+ *cursor++ = '2';
+ *cursor++ = '0';
+
+ lineLength += 3;
+ }
+ else
+ {
+ *cursor++ = ' ';
+ ++lineLength;
+ }
+ }
+ // If we find a line break, just let it through.
+ else if ((useCRLF && ('\r' == c) && (i < end) && ('\n' == data[i + 1])) ||
+ (!useCRLF && ('\n' == c)))
+ {
+ lineLength = 0;
+
+ if (useCRLF) {
+ *cursor++ = '\r';
+ *cursor++ = '\n';
+ ++i;
+ } else {
+ *cursor++ = '\n';
+ }
+ }
+
+ // Anything else is converted to =XX.
+
+ else
+ {
+ *cursor++ = '=';
+ *cursor++ = hexChars[c / 16];
+ *cursor++ = hexChars[c % 16];
+
+ lineLength += 3;
+ }
+
+ // If we're approaching the maximum line length, do a soft line break.
+
+ if ((lineLength > maxQPLineLength) && (i < end))
+ {
+ if (useCRLF) {
+ *cursor++ = '=';
+ *cursor++ = '\r';
+ *cursor++ = '\n';
+ } else {
+ *cursor++ = '=';
+ *cursor++ = '\n';
+ }
+
+ lineLength = 0;
+ }
+ }
+
+ out.truncate(cursor - out.data());
+}
+
+QCString KCodecs::quotedPrintableDecode(const QByteArray & in)
+{
+ QByteArray out;
+ quotedPrintableDecode (in, out);
+ return QCString (out.data(), out.size()+1);
+}
+
+QCString KCodecs::quotedPrintableDecode(const QCString & str)
+{
+ if (str.isEmpty())
+ return "";
+
+ QByteArray in (str.length());
+ memcpy (in.data(), str.data(), str.length());
+ return quotedPrintableDecode (in);
+}
+
+void KCodecs::quotedPrintableDecode(const QByteArray& in, QByteArray& out)
+{
+ // clear out the output buffer
+ out.resize (0);
+ if (in.isEmpty())
+ return;
+
+ char *cursor;
+ const char *data;
+ const unsigned int length = in.size();
+
+ data = in.data();
+ out.resize (length);
+ cursor = out.data();
+
+ for (unsigned int i = 0; i < length; i++)
+ {
+ char c(in[i]);
+
+ if ('=' == c)
+ {
+ if (i < length - 2)
+ {
+ char c1 = in[i + 1];
+ char c2 = in[i + 2];
+
+ if (('\n' == c1) || ('\r' == c1 && '\n' == c2))
+ {
+ // Soft line break. No output.
+ if ('\r' == c1)
+ i += 2; // CRLF line breaks
+ else
+ i += 1;
+ }
+ else
+ {
+ // =XX encoded byte.
+
+ int hexChar0 = rikFindChar(hexChars, c1);
+ int hexChar1 = rikFindChar(hexChars, c2);
+
+ if (hexChar0 < 16 && hexChar1 < 16)
+ {
+ *cursor++ = char((hexChar0 * 16) | hexChar1);
+ i += 2;
+ }
+ }
+ }
+ }
+ else
+ {
+ *cursor++ = c;
+ }
+ }
+
+ out.truncate(cursor - out.data());
+}
+
+QCString KCodecs::base64Encode( const QCString& str, bool insertLFs )
+{
+ if ( str.isEmpty() )
+ return "";
+
+ QByteArray in (str.length());
+ memcpy( in.data(), str.data(), str.length() );
+ return base64Encode( in, insertLFs );
+}
+
+QCString KCodecs::base64Encode( const QByteArray& in, bool insertLFs )
+{
+ QByteArray out;
+ base64Encode( in, out, insertLFs );
+ return QCString( out.data(), out.size()+1 );
+}
+
+void KCodecs::base64Encode( const QByteArray& in, QByteArray& out,
+ bool insertLFs )
+{
+ // clear out the output buffer
+ out.resize (0);
+ if ( in.isEmpty() )
+ return;
+
+ unsigned int sidx = 0;
+ unsigned int didx = 0;
+ const char* data = in.data();
+ const unsigned int len = in.size();
+
+ unsigned int out_len = ((len+2)/3)*4;
+
+ // Deal with the 76 characters or less per
+ // line limit specified in RFC 2045 on a
+ // pre request basis.
+ insertLFs = (insertLFs && out_len > 76);
+ if ( insertLFs )
+ out_len += ((out_len-1)/76);
+
+ int count = 0;
+ out.resize( out_len );
+
+ // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
+ if ( len > 1 )
+ {
+ while (sidx < len-2)
+ {
+ if ( insertLFs )
+ {
+ if ( count && (count%76) == 0 )
+ out[didx++] = '\n';
+ count += 4;
+ }
+ out[didx++] = Base64EncMap[(data[sidx] >> 2) & 077];
+ out[didx++] = Base64EncMap[(data[sidx+1] >> 4) & 017 |
+ (data[sidx] << 4) & 077];
+ out[didx++] = Base64EncMap[(data[sidx+2] >> 6) & 003 |
+ (data[sidx+1] << 2) & 077];
+ out[didx++] = Base64EncMap[data[sidx+2] & 077];
+ sidx += 3;
+ }
+ }
+
+ if (sidx < len)
+ {
+ if ( insertLFs && (count > 0) && (count%76) == 0 )
+ out[didx++] = '\n';
+
+ out[didx++] = Base64EncMap[(data[sidx] >> 2) & 077];
+ if (sidx < len-1)
+ {
+ out[didx++] = Base64EncMap[(data[sidx+1] >> 4) & 017 |
+ (data[sidx] << 4) & 077];
+ out[didx++] = Base64EncMap[(data[sidx+1] << 2) & 077];
+ }
+ else
+ {
+ out[didx++] = Base64EncMap[(data[sidx] << 4) & 077];
+ }
+ }
+
+ // Add padding
+ while (didx < out.size())
+ {
+ out[didx] = '=';
+ didx++;
+ }
+}
+
+QCString KCodecs::base64Decode( const QCString& str )
+{
+ if ( str.isEmpty() )
+ return "";
+
+ QByteArray in( str.length() );
+ memcpy( in.data(), str.data(), str.length() );
+ return base64Decode( in );
+}
+
+QCString KCodecs::base64Decode( const QByteArray& in )
+{
+ QByteArray out;
+ base64Decode( in, out );
+ return QCString( out.data(), out.size()+1 );
+}
+
+void KCodecs::base64Decode( const QByteArray& in, QByteArray& out )
+{
+ out.resize(0);
+ if ( in.isEmpty() )
+ return;
+
+ unsigned int count = 0;
+ unsigned int len = in.size(), tail = len;
+ const char* data = in.data();
+
+ // Deal with possible *nix "BEGIN" marker!!
+ while ( count < len && (data[count] == '\n' || data[count] == '\r' ||
+ data[count] == '\t' || data[count] == ' ') )
+ count++;
+
+ if ( count == len )
+ return;
+
+ if ( strncasecmp(data+count, "begin", 5) == 0 )
+ {
+ count += 5;
+ while ( count < len && data[count] != '\n' && data[count] != '\r' )
+ count++;
+
+ while ( count < len && (data[count] == '\n' || data[count] == '\r') )
+ count ++;
+
+ data += count;
+ tail = (len -= count);
+ }
+
+ // Find the tail end of the actual encoded data even if
+ // there is/are trailing CR and/or LF.
+ while ( tail > 0
+ && ( data[tail-1] == '=' || data[tail-1] == '\n' || data[tail-1] == '\r' ) )
+ if ( data[--tail] != '=' ) len = tail;
+
+ unsigned int outIdx = 0;
+ out.resize( (count=len) );
+ for (unsigned int idx = 0; idx < count; idx++)
+ {
+ // Adhere to RFC 2045 and ignore characters
+ // that are not part of the encoding table.
+ unsigned char ch = data[idx];
+ if ((ch > 47 && ch < 58) || (ch > 64 && ch < 91) ||
+ (ch > 96 && ch < 123) || ch == '+' || ch == '/' || ch == '=')
+ {
+ out[outIdx++] = Base64DecMap[ch];
+ }
+ else
+ {
+ len--;
+ tail--;
+ }
+ }
+
+ // kdDebug() << "Tail size = " << tail << ", Length size = " << len << endl;
+
+ // 4-byte to 3-byte conversion
+ len = (tail>(len/4)) ? tail-(len/4) : 0;
+ unsigned int sidx = 0, didx = 0;
+ if ( len > 1 )
+ {
+ while (didx < len-2)
+ {
+ out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx+1] >> 4) & 003));
+ out[didx+1] = (((out[sidx+1] << 4) & 255) | ((out[sidx+2] >> 2) & 017));
+ out[didx+2] = (((out[sidx+2] << 6) & 255) | (out[sidx+3] & 077));
+ sidx += 4;
+ didx += 3;
+ }
+ }
+
+ if (didx < len)
+ out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx+1] >> 4) & 003));
+
+ if (++didx < len )
+ out[didx] = (((out[sidx+1] << 4) & 255) | ((out[sidx+2] >> 2) & 017));
+
+ // Resize the output buffer
+ if ( len == 0 || len < out.size() )
+ out.resize(len);
+}
+
+QCString KCodecs::uuencode( const QCString& str )
+{
+ if ( str.isEmpty() )
+ return "";
+
+ QByteArray in;
+ in.resize( str.length() );
+ memcpy( in.data(), str.data(), str.length() );
+ return uuencode( in );
+}
+
+QCString KCodecs::uuencode( const QByteArray& in )
+{
+ QByteArray out;
+ uuencode( in, out );
+ return QCString( out.data(), out.size()+1 );
+}
+
+void KCodecs::uuencode( const QByteArray& in, QByteArray& out )
+{
+ out.resize( 0 );
+ if( in.isEmpty() )
+ return;
+
+ unsigned int sidx = 0;
+ unsigned int didx = 0;
+ unsigned int line_len = 45;
+
+ const char nl[] = "\n";
+ const char* data = in.data();
+ const unsigned int nl_len = strlen(nl);
+ const unsigned int len = in.size();
+
+ out.resize( (len+2)/3*4 + ((len+line_len-1)/line_len)*(nl_len+1) );
+ // split into lines, adding line-length and line terminator
+ while (sidx+line_len < len)
+ {
+ // line length
+ out[didx++] = UUEncMap[line_len];
+
+ // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
+ for (unsigned int end = sidx+line_len; sidx < end; sidx += 3)
+ {
+ out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
+ out[didx++] = UUEncMap[(data[sidx+1] >> 4) & 017 |
+ (data[sidx] << 4) & 077];
+ out[didx++] = UUEncMap[(data[sidx+2] >> 6) & 003 |
+ (data[sidx+1] << 2) & 077];
+ out[didx++] = UUEncMap[data[sidx+2] & 077];
+ }
+
+ // line terminator
+ //for (unsigned int idx=0; idx < nl_len; idx++)
+ //out[didx++] = nl[idx];
+ memcpy(out.data()+didx, nl, nl_len);
+ didx += nl_len;
+ }
+
+ // line length
+ out[didx++] = UUEncMap[len-sidx];
+ // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
+ while (sidx+2 < len)
+ {
+ out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
+ out[didx++] = UUEncMap[(data[sidx+1] >> 4) & 017 |
+ (data[sidx] << 4) & 077];
+ out[didx++] = UUEncMap[(data[sidx+2] >> 6) & 003 |
+ (data[sidx+1] << 2) & 077];
+ out[didx++] = UUEncMap[data[sidx+2] & 077];
+ sidx += 3;
+ }
+
+ if (sidx < len-1)
+ {
+ out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
+ out[didx++] = UUEncMap[(data[sidx+1] >> 4) & 017 |
+ (data[sidx] << 4) & 077];
+ out[didx++] = UUEncMap[(data[sidx+1] << 2) & 077];
+ out[didx++] = UUEncMap[0];
+ }
+ else if (sidx < len)
+ {
+ out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
+ out[didx++] = UUEncMap[(data[sidx] << 4) & 077];
+ out[didx++] = UUEncMap[0];
+ out[didx++] = UUEncMap[0];
+ }
+
+ // line terminator
+ memcpy(out.data()+didx, nl, nl_len);
+ didx += nl_len;
+
+ // sanity check
+ if ( didx != out.size() )
+ out.resize( 0 );
+}
+
+QCString KCodecs::uudecode( const QCString& str )
+{
+ if ( str.isEmpty() )
+ return "";
+
+ QByteArray in;
+ in.resize( str.length() );
+ memcpy( in.data(), str.data(), str.length() );
+ return uudecode( in );
+}
+
+QCString KCodecs::uudecode( const QByteArray& in )
+{
+ QByteArray out;
+ uudecode( in, out );
+ return QCString( out.data(), out.size()+1 );
+}
+
+void KCodecs::uudecode( const QByteArray& in, QByteArray& out )
+{
+ out.resize( 0 );
+ if( in.isEmpty() )
+ return;
+
+ unsigned int sidx = 0;
+ unsigned int didx = 0;
+ unsigned int len = in.size();
+ unsigned int line_len, end;
+ const char* data = in.data();
+
+ // Deal with *nix "BEGIN"/"END" separators!!
+ unsigned int count = 0;
+ while ( count < len && (data[count] == '\n' || data[count] == '\r' ||
+ data[count] == '\t' || data[count] == ' ') )
+ count ++;
+
+ bool hasLF = false;
+ if ( strncasecmp( data+count, "begin", 5) == 0 )
+ {
+ count += 5;
+ while ( count < len && data[count] != '\n' && data[count] != '\r' )
+ count ++;
+
+ while ( count < len && (data[count] == '\n' || data[count] == '\r') )
+ count ++;
+
+ data += count;
+ len -= count;
+ hasLF = true;
+ }
+
+ out.resize( len/4*3 );
+ while ( sidx < len )
+ {
+ // get line length (in number of encoded octets)
+ line_len = UUDecMap[ (unsigned char) data[sidx++]];
+ // ascii printable to 0-63 and 4-byte to 3-byte conversion
+ end = didx+line_len;
+ char A, B, C, D;
+ if (end > 2) {
+ while (didx < end-2)
+ {
+ A = UUDecMap[(unsigned char) data[sidx]];
+ B = UUDecMap[(unsigned char) data[sidx+1]];
+ C = UUDecMap[(unsigned char) data[sidx+2]];
+ D = UUDecMap[(unsigned char) data[sidx+3]];
+ out[didx++] = ( ((A << 2) & 255) | ((B >> 4) & 003) );
+ out[didx++] = ( ((B << 4) & 255) | ((C >> 2) & 017) );
+ out[didx++] = ( ((C << 6) & 255) | (D & 077) );
+ sidx += 4;
+ }
+ }
+
+ if (didx < end)
+ {
+ A = UUDecMap[(unsigned char) data[sidx]];
+ B = UUDecMap[(unsigned char) data[sidx+1]];
+ out[didx++] = ( ((A << 2) & 255) | ((B >> 4) & 003) );
+ }
+
+ if (didx < end)
+ {
+ B = UUDecMap[(unsigned char) data[sidx+1]];
+ C = UUDecMap[(unsigned char) data[sidx+2]];
+ out[didx++] = ( ((B << 4) & 255) | ((C >> 2) & 017) );
+ }
+
+ // skip padding
+ while (sidx < len && data[sidx] != '\n' && data[sidx] != '\r')
+ sidx++;
+
+ // skip end of line
+ while (sidx < len && (data[sidx] == '\n' || data[sidx] == '\r'))
+ sidx++;
+
+ // skip the "END" separator when present.
+ if ( hasLF && strncasecmp( data+sidx, "end", 3) == 0 )
+ break;
+ }
+
+ if ( didx < out.size() )
+ out.resize( didx );
+}
+
+/******************************** KMD5 ********************************/
+KMD5::KMD5()
+{
+ init();
+}
+
+KMD5::KMD5(const char *in, int len)
+{
+ init();
+ update(in, len);
+}
+
+KMD5::KMD5(const QByteArray& in)
+{
+ init();
+ update( in );
+}
+
+KMD5::KMD5(const QCString& in)
+{
+ init();
+ update( in );
+}
+
+void KMD5::update(const QByteArray& in)
+{
+ update(in.data(), int(in.size()));
+}
+
+void KMD5::update(const QCString& in)
+{
+ update(in.data(), int(in.length()));
+}
+
+void KMD5::update(const unsigned char* in, int len)
+{
+ if (len < 0)
+ len = qstrlen(reinterpret_cast<const char*>(in));
+
+ if (!len)
+ return;
+
+ if (m_finalized) {
+ kdWarning() << "KMD5::update called after state was finalized!" << endl;
+ return;
+ }
+
+ Q_UINT32 in_index;
+ Q_UINT32 buffer_index;
+ Q_UINT32 buffer_space;
+ Q_UINT32 in_length = static_cast<Q_UINT32>( len );
+
+ buffer_index = static_cast<Q_UINT32>((m_count[0] >> 3) & 0x3F);
+
+ if ( (m_count[0] += (in_length << 3))<(in_length << 3) )
+ m_count[1]++;
+
+ m_count[1] += (in_length >> 29);
+ buffer_space = 64 - buffer_index;
+
+ if (in_length >= buffer_space)
+ {
+ memcpy (m_buffer + buffer_index, in, buffer_space);
+ transform (m_buffer);
+
+ for (in_index = buffer_space; in_index + 63 < in_length;
+ in_index += 64)
+ transform (reinterpret_cast<const unsigned char*>(in+in_index));
+
+ buffer_index = 0;
+ }
+ else
+ in_index=0;
+
+ memcpy(m_buffer+buffer_index, in+in_index, in_length-in_index);
+}
+
+bool KMD5::update(QIODevice& file)
+{
+ char buffer[1024];
+ int len;
+
+ while ((len=file.readBlock(reinterpret_cast<char*>(buffer), sizeof(buffer))) > 0)
+ update(buffer, len);
+
+ return file.atEnd();
+}
+
+void KMD5::finalize ()
+{
+ if (m_finalized) return;
+
+ Q_UINT8 bits[8];
+ Q_UINT32 index, padLen;
+ static const unsigned char PADDING[64]=
+ {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ encode (bits, m_count, 8);
+ //memcpy( bits, m_count, 8 );
+
+ // Pad out to 56 mod 64.
+ index = static_cast<Q_UINT32>((m_count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ update (reinterpret_cast<const char*>(PADDING), padLen);
+
+ // Append length (before padding)
+ update (reinterpret_cast<const char*>(bits), 8);
+
+ // Store state in digest
+ encode (m_digest, m_state, 16);
+ //memcpy( m_digest, m_state, 16 );
+
+ // Fill sensitive information with zero's
+ memset ( (void *)m_buffer, 0, sizeof(*m_buffer));
+
+ m_finalized = true;
+}
+
+
+bool KMD5::verify( const KMD5::Digest& digest)
+{
+ finalize();
+ return (0 == memcmp(rawDigest(), digest, sizeof(KMD5::Digest)));
+}
+
+bool KMD5::verify( const QCString& hexdigest)
+{
+ finalize();
+ return (0 == strcmp(hexDigest().data(), hexdigest));
+}
+
+const KMD5::Digest& KMD5::rawDigest()
+{
+ finalize();
+ return m_digest;
+}
+
+void KMD5::rawDigest( KMD5::Digest& bin )
+{
+ finalize();
+ memcpy( bin, m_digest, 16 );
+}
+
+
+QCString KMD5::hexDigest()
+{
+ QCString s(33);
+
+ finalize();
+ sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
+ m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
+ m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
+
+ return s;
+}
+
+void KMD5::hexDigest(QCString& s)
+{
+ finalize();
+ s.resize(33);
+ sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
+ m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
+ m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
+}
+
+QCString KMD5::base64Digest()
+{
+ QByteArray ba(16);
+
+ finalize();
+ memcpy(ba.data(), m_digest, 16);
+ return KCodecs::base64Encode(ba);
+}
+
+
+void KMD5::init()
+{
+ d = 0;
+ reset();
+}
+
+void KMD5::reset()
+{
+ m_finalized = false;
+
+ m_count[0] = 0;
+ m_count[1] = 0;
+
+ m_state[0] = 0x67452301;
+ m_state[1] = 0xefcdab89;
+ m_state[2] = 0x98badcfe;
+ m_state[3] = 0x10325476;
+
+ memset ( m_buffer, 0, sizeof(*m_buffer));
+ memset ( m_digest, 0, sizeof(*m_digest));
+}
+
+void KMD5::transform( const unsigned char block[64] )
+{
+
+ Q_UINT32 a = m_state[0], b = m_state[1], c = m_state[2], d = m_state[3], x[16];
+
+ decode (x, block, 64);
+ //memcpy( x, block, 64 );
+
+ Q_ASSERT(!m_finalized); // not just a user error, since the method is private
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], KMD5_S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], KMD5_S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], KMD5_S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], KMD5_S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], KMD5_S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], KMD5_S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], KMD5_S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], KMD5_S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], KMD5_S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], KMD5_S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], KMD5_S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], KMD5_S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], KMD5_S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], KMD5_S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], KMD5_S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], KMD5_S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], KMD5_S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], KMD5_S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], KMD5_S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], KMD5_S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], KMD5_S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], KMD5_S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], KMD5_S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], KMD5_S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], KMD5_S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], KMD5_S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], KMD5_S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], KMD5_S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], KMD5_S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], KMD5_S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], KMD5_S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], KMD5_S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], KMD5_S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], KMD5_S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], KMD5_S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], KMD5_S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], KMD5_S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], KMD5_S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], KMD5_S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], KMD5_S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], KMD5_S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], KMD5_S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], KMD5_S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], KMD5_S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], KMD5_S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], KMD5_S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], KMD5_S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], KMD5_S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], KMD5_S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], KMD5_S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], KMD5_S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], KMD5_S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], KMD5_S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], KMD5_S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], KMD5_S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], KMD5_S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], KMD5_S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], KMD5_S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], KMD5_S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], KMD5_S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], KMD5_S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], KMD5_S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], KMD5_S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], KMD5_S44, 0xeb86d391); /* 64 */
+
+ m_state[0] += a;
+ m_state[1] += b;
+ m_state[2] += c;
+ m_state[3] += d;
+
+ memset ( static_cast<void *>(x), 0, sizeof(x) );
+}
+
+inline Q_UINT32 KMD5::rotate_left (Q_UINT32 x, Q_UINT32 n)
+{
+ return (x << n) | (x >> (32-n)) ;
+}
+
+inline Q_UINT32 KMD5::F (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
+{
+ return (x & y) | (~x & z);
+}
+
+inline Q_UINT32 KMD5::G (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
+{
+ return (x & z) | (y & ~z);
+}
+
+inline Q_UINT32 KMD5::H (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
+{
+ return x ^ y ^ z;
+}
+
+inline Q_UINT32 KMD5::I (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
+{
+ return y ^ (x | ~z);
+}
+
+void KMD5::FF ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
+ Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac )
+{
+ a += F(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
+
+void KMD5::GG ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
+ Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac)
+{
+ a += G(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
+
+void KMD5::HH ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
+ Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac )
+{
+ a += H(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
+
+void KMD5::II ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
+ Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac )
+{
+ a += I(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
+
+
+void KMD5::encode ( unsigned char* output, Q_UINT32 *in, Q_UINT32 len )
+{
+#if !defined(WORDS_BIGENDIAN)
+ memcpy(output, in, len);
+
+#else
+ Q_UINT32 i, j;
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ {
+ output[j] = static_cast<Q_UINT8>((in[i] & 0xff));
+ output[j+1] = static_cast<Q_UINT8>(((in[i] >> 8) & 0xff));
+ output[j+2] = static_cast<Q_UINT8>(((in[i] >> 16) & 0xff));
+ output[j+3] = static_cast<Q_UINT8>(((in[i] >> 24) & 0xff));
+ }
+#endif
+}
+
+// Decodes in (Q_UINT8) into output (Q_UINT32). Assumes len is a
+// multiple of 4.
+void KMD5::decode (Q_UINT32 *output, const unsigned char* in, Q_UINT32 len)
+{
+#if !defined(WORDS_BIGENDIAN)
+ memcpy(output, in, len);
+
+#else
+ Q_UINT32 i, j;
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = static_cast<Q_UINT32>(in[j]) |
+ (static_cast<Q_UINT32>(in[j+1]) << 8) |
+ (static_cast<Q_UINT32>(in[j+2]) << 16) |
+ (static_cast<Q_UINT32>(in[j+3]) << 24);
+#endif
+}
+
+
+
+/**************************************************************/
+
+
+
+/***********************************************************/
+
+KMD4::KMD4()
+{
+ init();
+}
+
+KMD4::KMD4(const char *in, int len)
+{
+ init();
+ update(in, len);
+}
+
+KMD4::KMD4(const QByteArray& in)
+{
+ init();
+ update( in );
+}
+
+KMD4::KMD4(const QCString& in)
+{
+ init();
+ update( in );
+}
+
+void KMD4::update(const QByteArray& in)
+{
+ update(in.data(), int(in.size()));
+}
+
+void KMD4::update(const QCString& in)
+{
+ update(in.data(), int(in.length()));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void KMD4::update(const unsigned char *in, int len)
+{
+ if (len < 0)
+ len = qstrlen(reinterpret_cast<const char*>(in));
+
+ if (!len)
+ return;
+
+ if (m_finalized) {
+ kdWarning() << "KMD4::update called after state was finalized!" << endl;
+ return;
+ }
+
+ Q_UINT32 t;
+
+ /* Update bitcount */
+
+ t = m_count[0];
+ if ((m_count[0] = t + ((Q_UINT32) len << 3)) < t)
+ m_count[1]++; /* Carry from low to high */
+ m_count[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t)
+ {
+ Q_UINT8 *p = &m_buffer[ t ];
+
+ t = 64 - t;
+ if ((Q_UINT32)len < t)
+ {
+ memcpy (p, in, len);
+ return;
+ }
+ memcpy (p, in, t);
+ byteReverse (m_buffer, 16);
+ transform (m_state, (Q_UINT32*) m_buffer);
+ in += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64)
+ {
+ memcpy (m_buffer, in, 64);
+ byteReverse (m_buffer, 16);
+ transform (m_state, (Q_UINT32 *) m_buffer);
+ in += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy (m_buffer, in, len);
+}
+
+bool KMD4::update(QIODevice& file)
+{
+ char buffer[1024];
+ int len;
+
+ while ((len=file.readBlock(reinterpret_cast<char*>(buffer), sizeof(buffer))) > 0)
+ update(buffer, len);
+
+ return file.atEnd();
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void KMD4::finalize()
+{
+ unsigned int count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (m_count[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = m_buffer + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8)
+ {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset (p, 0, count);
+ byteReverse (m_buffer, 16);
+ transform (m_state, (Q_UINT32*) m_buffer);
+
+ /* Now fill the next block with 56 bytes */
+ memset (m_buffer, 0, 56);
+ }
+ else
+ {
+ /* Pad block to 56 bytes */
+ memset (p, 0, count - 8);
+ }
+ byteReverse (m_buffer, 14);
+
+ /* Append length in bits and transform */
+ ((Q_UINT32 *) m_buffer)[14] = m_count[0];
+ ((Q_UINT32 *) m_buffer)[15] = m_count[1];
+
+ transform (m_state, (Q_UINT32 *) m_buffer);
+ byteReverse ((unsigned char *) m_state, 4);
+
+ memcpy (m_digest, m_state, 16);
+ memset ( (void *)m_buffer, 0, sizeof(*m_buffer));
+
+ m_finalized = true;
+}
+
+bool KMD4::verify( const KMD4::Digest& digest)
+{
+ finalize();
+ return (0 == memcmp(rawDigest(), digest, sizeof(KMD4::Digest)));
+}
+
+bool KMD4::verify( const QCString& hexdigest)
+{
+ finalize();
+ return (0 == strcmp(hexDigest().data(), hexdigest));
+}
+
+const KMD4::Digest& KMD4::rawDigest()
+{
+ finalize();
+ return m_digest;
+}
+
+void KMD4::rawDigest( KMD4::Digest& bin )
+{
+ finalize();
+ memcpy( bin, m_digest, 16 );
+}
+
+QCString KMD4::hexDigest()
+{
+ QCString s(33);
+
+ finalize();
+ sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
+ m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
+ m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
+// kdDebug() << "KMD4::hexDigest() " << s << endl;
+ return s;
+}
+
+void KMD4::hexDigest(QCString& s)
+{
+ finalize();
+ s.resize(33);
+ sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
+ m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
+ m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
+}
+
+QCString KMD4::base64Digest()
+{
+ QByteArray ba(16);
+
+ finalize();
+ memcpy(ba.data(), m_digest, 16);
+ return KCodecs::base64Encode(ba);
+}
+
+
+void KMD4::init()
+{
+ d = 0;
+ reset();
+}
+
+/*
+ * Start MD4 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void KMD4::reset()
+{
+ m_finalized = false;
+
+ m_state[0] = 0x67452301;
+ m_state[1] = 0xefcdab89;
+ m_state[2] = 0x98badcfe;
+ m_state[3] = 0x10325476;
+
+ m_count[0] = 0;
+ m_count[1] = 0;
+
+ memset ( m_buffer, 0, sizeof(*m_buffer));
+ memset ( m_digest, 0, sizeof(*m_digest));
+}
+
+//#define rotl32(x,n) (((x) << ((Q_UINT32)(n))) | ((x) >> (32 - (Q_UINT32)(n))))
+
+inline Q_UINT32 KMD4::rotate_left (Q_UINT32 x, Q_UINT32 n)
+{
+ return (x << n) | (x >> (32-n)) ;
+}
+
+inline Q_UINT32 KMD4::F (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
+{
+ return (x & y) | (~x & z);
+}
+
+inline Q_UINT32 KMD4::G (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
+{
+ return ((x) & (y)) | ((x) & (z)) | ((y) & (z));
+}
+
+inline Q_UINT32 KMD4::H (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
+{
+ return x ^ y ^ z;
+}
+
+inline void KMD4::FF ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
+ Q_UINT32 x, Q_UINT32 s )
+{
+ a += F(b, c, d) + x;
+ a = rotate_left (a, s);
+}
+
+inline void KMD4::GG ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
+ Q_UINT32 x, Q_UINT32 s)
+{
+ a += G(b, c, d) + x + (Q_UINT32)0x5a827999;
+ a = rotate_left (a, s);
+}
+
+inline void KMD4::HH ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
+ Q_UINT32 x, Q_UINT32 s )
+{
+ a += H(b, c, d) + x + (Q_UINT32)0x6ed9eba1;
+ a = rotate_left (a, s);
+}
+
+void KMD4::byteReverse( unsigned char *buf, Q_UINT32 len )
+{
+#ifdef WORDS_BIGENDIAN
+ Q_UINT32 *b = (Q_UINT32*) buf;
+ while ( len > 0 ) {
+ *b = ((((*b) & 0xff000000) >> 24) | (((*b) & 0x00ff0000) >> 8) |
+ (((*b) & 0x0000ff00) << 8) | (((*b) & 0x000000ff) << 24));
+ len--;
+ b++;
+ }
+#else
+ Q_UNUSED(buf)
+ Q_UNUSED(len)
+#endif
+}
+
+/*
+ * The core of the MD4 algorithm
+ */
+void KMD4::transform( Q_UINT32 buf[4], Q_UINT32 const in[16] )
+{
+ Q_UINT32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ FF (a, b, c, d, in[0], 3); /* 1 */
+ FF (d, a, b, c, in[1], 7); /* 2 */
+ FF (c, d, a, b, in[2], 11); /* 3 */
+ FF (b, c, d, a, in[3], 19); /* 4 */
+ FF (a, b, c, d, in[4], 3); /* 5 */
+ FF (d, a, b, c, in[5], 7); /* 6 */
+ FF (c, d, a, b, in[6], 11); /* 7 */
+ FF (b, c, d, a, in[7], 19); /* 8 */
+ FF (a, b, c, d, in[8], 3); /* 9 */
+ FF (d, a, b, c, in[9], 7); /* 10 */
+ FF (c, d, a, b, in[10], 11); /* 11 */
+ FF (b, c, d, a, in[11], 19); /* 12 */
+ FF (a, b, c, d, in[12], 3); /* 13 */
+ FF (d, a, b, c, in[13], 7); /* 14 */
+ FF (c, d, a, b, in[14], 11); /* 15 */
+ FF (b, c, d, a, in[15], 19); /* 16 */
+
+ GG (a, b, c, d, in[0], 3); /* 17 */
+ GG (d, a, b, c, in[4], 5); /* 18 */
+ GG (c, d, a, b, in[8], 9); /* 19 */
+ GG (b, c, d, a, in[12], 13); /* 20 */
+ GG (a, b, c, d, in[1], 3); /* 21 */
+ GG (d, a, b, c, in[5], 5); /* 22 */
+ GG (c, d, a, b, in[9], 9); /* 23 */
+ GG (b, c, d, a, in[13], 13); /* 24 */
+ GG (a, b, c, d, in[2], 3); /* 25 */
+ GG (d, a, b, c, in[6], 5); /* 26 */
+ GG (c, d, a, b, in[10], 9); /* 27 */
+ GG (b, c, d, a, in[14], 13); /* 28 */
+ GG (a, b, c, d, in[3], 3); /* 29 */
+ GG (d, a, b, c, in[7], 5); /* 30 */
+ GG (c, d, a, b, in[11], 9); /* 31 */
+ GG (b, c, d, a, in[15], 13); /* 32 */
+
+ HH (a, b, c, d, in[0], 3); /* 33 */
+ HH (d, a, b, c, in[8], 9); /* 34 */
+ HH (c, d, a, b, in[4], 11); /* 35 */
+ HH (b, c, d, a, in[12], 15); /* 36 */
+ HH (a, b, c, d, in[2], 3); /* 37 */
+ HH (d, a, b, c, in[10], 9); /* 38 */
+ HH (c, d, a, b, in[6], 11); /* 39 */
+ HH (b, c, d, a, in[14], 15); /* 40 */
+ HH (a, b, c, d, in[1], 3); /* 41 */
+ HH (d, a, b, c, in[9], 9); /* 42 */
+ HH (c, d, a, b, in[5], 11); /* 43 */
+ HH (b, c, d, a, in[13], 15); /* 44 */
+ HH (a, b, c, d, in[3], 3); /* 45 */
+ HH (d, a, b, c, in[11], 9); /* 46 */
+ HH (c, d, a, b, in[7], 11); /* 47 */
+ HH (b, c, d, a, in[15], 15); /* 48 */
+
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
diff --git a/kdecore/kmdcodec.h b/kdecore/kmdcodec.h
new file mode 100644
index 000000000..7b1023393
--- /dev/null
+++ b/kdecore/kmdcodec.h
@@ -0,0 +1,745 @@
+/*
+ Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org>
+ Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License (LGPL)
+ version 2 as published by the Free Software Foundation.
+
+ 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 Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ RFC 1321 "MD5 Message-Digest Algorithm" Copyright (C) 1991-1992.
+ RSA Data Security, Inc. Created 1991. All rights reserved.
+
+ The KMD5 class is based on a C++ implementation of
+ "RSA Data Security, Inc. MD5 Message-Digest Algorithm" by
+ Mordechai T. Abzug, Copyright (c) 1995. This implementation
+ passes the test-suite as defined in RFC 1321.
+
+ The encoding and decoding utilities in KCodecs with the exception of
+ quoted-printable are based on the java implementation in HTTPClient
+ package by Ronald Tschalär Copyright (C) 1996-1999.
+
+ The quoted-printable codec as described in RFC 2045, section 6.7. is by
+ Rik Hemsley (C) 2001.
+*/
+
+#ifndef _KMDBASE_H
+#define _KMDBASE_H
+
+#define KBase64 KCodecs
+
+#include <qglobal.h>
+#include <qstring.h>
+#include <qiodevice.h>
+#include "kdelibs_export.h"
+
+/**
+ * A wrapper class for the most commonly used encoding and
+ * decoding algorithms. Currently there is support for encoding
+ * and decoding input using base64, uu and the quoted-printable
+ * specifications.
+ *
+ * \b Usage:
+ *
+ * \code
+ * QCString input = "Aladdin:open sesame";
+ * QCString result = KCodecs::base64Encode(input);
+ * cout << "Result: " << result.data() << endl;
+ * \endcode
+ *
+ * <pre>
+ * Output should be
+ * Result: QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+ * </pre>
+ *
+ * The above example makes use of the convenience functions
+ * (ones that accept/return null-terminated strings) to encode/decode
+ * a string. If what you need is to encode or decode binary data, then
+ * it is highly recommended that you use the functions that take an input
+ * and output QByteArray as arguments. These functions are specifically
+ * tailored for encoding and decoding binary data.
+ *
+ * @short A collection of commonly used encoding and decoding algorithms.
+ * @author Dawit Alemayehu <adawit@kde.org>
+ * @author Rik Hemsley <rik@kde.org>
+ */
+class KDECORE_EXPORT KCodecs
+{
+public:
+
+ /**
+ * Encodes the given data using the quoted-printable algorithm.
+ *
+ * @param in data to be encoded.
+ * @param useCRLF if true the input data is expected to have
+ * CRLF line breaks and the output will have CRLF line
+ * breaks, too.
+ * @return quoted-printable encoded string.
+ */
+ static QCString quotedPrintableEncode(const QByteArray & in,
+ bool useCRLF = true);
+
+ /**
+ * @overload
+ *
+ * Same as above except it accepts a null terminated
+ * string instead an array.
+ *
+ * @param str string to be encoded.
+ * @param useCRLF if true the input data is expected to have
+ * CRLF line breaks and the output will have CRLF line
+ * breaks, too.
+ * @return quoted-printable encoded string.
+ */
+ static QCString quotedPrintableEncode(const QCString & str,
+ bool useCRLF = true);
+
+ /**
+ * Encodes the given data using the quoted-printable algorithm.
+ *
+ * Use this function if you want the result of the encoding
+ * to be placed in another array which cuts down the number
+ * of copy operation that have to be performed in the process.
+ * This is also the preferred method for encoding binary data.
+ *
+ * NOTE: the output array is first reset and then resized
+ * appropriately before use, hence, all data stored in the
+ * output array will be lost.
+ *
+ * @param in data to be encoded.
+ * @param out encoded data.
+ * @param useCRLF if true the input data is expected to have
+ * CRLF line breaks and the output will have CRLF line
+ * breaks, too.
+ */
+ static void quotedPrintableEncode(const QByteArray & in, QByteArray& out,
+ bool useCRLF);
+
+ /**
+ * Decodes a quoted-printable encoded data.
+ *
+ * Accepts data with CRLF or standard unix line breaks.
+ *
+ * @param in data to be decoded.
+ * @return decoded string.
+ */
+ static QCString quotedPrintableDecode(const QByteArray & in);
+
+ /**
+ * @overload
+ *
+ * Same as above except it accepts a null terminated
+ * string instead an array.
+ *
+ * @param str string to be decoded.
+ * @return decoded string.
+ */
+ static QCString quotedPrintableDecode(const QCString & str);
+
+ /**
+ * Decodes a quoted-printable encoded data.
+ *
+ * Accepts data with CRLF or standard unix line breaks.
+ * Use this function if you want the result of the decoding
+ * to be placed in another array which cuts down the number
+ * of copy operation that have to be performed in the process.
+ * This is also the preferred method for decoding an encoded
+ * binary data.
+ *
+ * NOTE: the output array is first reset and then resized
+ * appropriately before use, hence, all data stored in the
+ * output array will be lost.
+ *
+ * @param in data to be decoded.
+ * @param out decoded data.
+ */
+ static void quotedPrintableDecode(const QByteArray & in, QByteArray& out);
+
+
+ /**
+ * Encodes the given data using the uuencode algorithm.
+ *
+ * The output is split into lines starting with the number of
+ * encoded octets in the line and ending with a newline. No
+ * line is longer than 45 octets (60 characters), excluding the
+ * line terminator.
+ *
+ * @param in data to be uuencoded
+ * @return uuencoded string.
+ */
+ static QCString uuencode( const QByteArray& in );
+
+ /**
+ * @overload
+ *
+ * Same as the above functions except it accepts
+ * a null terminated string instead an array.
+ *
+ * @param str string to be uuencoded.
+ * @return encoded string.
+ */
+ static QCString uuencode( const QCString& str );
+
+ /**
+ * Encodes the given data using the uuencode algorithm.
+ *
+ * Use this function if you want the result of the encoding
+ * to be placed in another array and cut down the number of
+ * copy operation that have to be performed in the process.
+ * This is the preffered method for encoding binary data.
+ *
+ * NOTE: the output array is first reset and then resized
+ * appropriately before use, hence, all data stored in the
+ * output array will be lost.
+ *
+ * @param in data to be uuencoded.
+ * @param out uudecoded data.
+ */
+ static void uuencode( const QByteArray& in, QByteArray& out );
+
+ /**
+ * Decodes the given data using the uudecode algorithm.
+ *
+ * Any 'begin' and 'end' lines like those generated by
+ * the utilities in unix and unix-like OS will be
+ * automatically ignored.
+ *
+ * @param in data to be decoded.
+ * @return decoded string.
+ */
+ static QCString uudecode( const QByteArray& in );
+
+ /**
+ * @overload
+ *
+ * Same as the above functions except it accepts
+ * a null terminated string instead an array.
+ *
+ * @param str string to be decoded.
+ * @return uudecoded string.
+ */
+ static QCString uudecode( const QCString& str );
+
+ /**
+ * Decodes the given data using the uudecode algorithm.
+ *
+ * Use this function if you want the result of the decoding
+ * to be placed in another array which cuts down the number
+ * of copy operation that have to be performed in the process.
+ * This is the preferred method for decoding binary data.
+ *
+ * Any 'begin' and 'end' lines like those generated by
+ * the utilities in unix and unix-like OS will be
+ * automatically ignored.
+ *
+ * NOTE: the output array is first reset and then resized
+ * appropriately before use, hence, all data stored in the
+ * output array will be lost.
+ *
+ * @param in data to be decoded.
+ * @param out uudecoded data.
+ */
+ static void uudecode( const QByteArray& in, QByteArray& out );
+
+
+ /**
+ * Encodes the given data using the base64 algorithm.
+ *
+ * The boolean argument determines if the encoded data is
+ * going to be restricted to 76 characters or less per line
+ * as specified by RFC 2045. If @p insertLFs is true, then
+ * there will be 76 characters or less per line.
+ *
+ * @param in data to be encoded.
+ * @param insertLFs limit the number of characters per line.
+ *
+ * @return base64 encoded string.
+ */
+ static QCString base64Encode( const QByteArray& in, bool insertLFs = false);
+
+ /**
+ * @overload
+ *
+ * Same as the above functions except it accepts
+ * a null terminated string instead an array.
+ *
+ * @param str string to be encoded.
+ * @param insertLFs limit the number of characters per line.
+ * @return decoded string.
+ */
+ static QCString base64Encode( const QCString& str, bool insertLFs = false );
+
+ /**
+ * Encodes the given data using the base64 algorithm.
+ *
+ * Use this function if you want the result of the encoding
+ * to be placed in another array which cuts down the number
+ * of copy operation that have to be performed in the process.
+ * This is also the preferred method for encoding binary data.
+ *
+ * The boolean argument determines if the encoded data is going
+ * to be restricted to 76 characters or less per line as specified
+ * by RFC 2045. If @p insertLFs is true, then there will be 76
+ * characters or less per line.
+ *
+ * NOTE: the output array is first reset and then resized
+ * appropriately before use, hence, all data stored in the
+ * output array will be lost.
+ *
+ * @param in data to be encoded.
+ * @param out encoded data.
+ * @param insertLFs limit the number of characters per line.
+ */
+ static void base64Encode( const QByteArray& in, QByteArray& out,
+ bool insertLFs = false );
+
+ /**
+ * Decodes the given data that was encoded using the
+ * base64 algorithm.
+ *
+ * @param in data to be decoded.
+ * @return decoded string.
+ */
+ static QCString base64Decode( const QByteArray& in );
+
+ /**
+ * @overload
+ *
+ * Same as the above functions except it accepts
+ * a null terminated string instead an array.
+ *
+ * @param str string to be decoded.
+ * @return decoded string.
+ */
+ static QCString base64Decode( const QCString& str );
+
+ /**
+ * Decodes the given data that was encoded with the base64
+ * algorithm.
+ *
+ * Use this function if you want the result of the decoding
+ * to be placed in another array which cuts down the number
+ * of copy operation that have to be performed in the process.
+ * This is also the preferred method for decoding an encoded
+ * binary data.
+ *
+ * NOTE: the output array is first reset and then resized
+ * appropriately before use, hence, all data stored in the
+ * output array will be lost.
+ *
+ * @param in data to be decoded.
+ * @param out decoded data.
+ */
+ static void base64Decode( const QByteArray& in, QByteArray& out );
+
+
+private:
+ KCodecs();
+
+private:
+ static const char UUEncMap[64];
+ static const char UUDecMap[128];
+ static const char Base64EncMap[64];
+ static const char Base64DecMap[128];
+ static const char hexChars[16];
+ static const unsigned int maxQPLineLength;
+};
+
+class KMD5Private;
+/**
+ * @short An adapted C++ implementation of RSA Data Securities MD5 algorithm.
+ *
+ * The default constructor is designed to provide much the same
+ * functionality as the most commonly used C-implementation, while
+ * the other three constructors are meant to further simplify the
+ * process of obtaining a digest by calculating the result in a
+ * single step.
+ *
+ * KMD5 is state-based, that means you can add new contents with
+ * update() as long as you didn't request the digest value yet.
+ * After the digest value was requested, the object is "finalized"
+ * and you have to call reset() to be able to do another calculation
+ * with it. The reason for this behavior is that upon requesting
+ * the message digest KMD5 has to pad the received contents up to a
+ * 64 byte boundary to calculate its value. After this operation it
+ * is not possible to resume consuming data.
+ *
+ * \b Usage:
+ *
+ * A common usage of this class:
+ *
+ * \code
+ * const char* test1;
+ * KMD5::Digest rawResult;
+ *
+ * test1 = "This is a simple test.";
+ * KMD5 context (test1);
+ * cout << "Hex Digest output: " << context.hexDigest().data() << endl;
+ * \endcode
+ *
+ * To cut down on the unnecessary overhead of creating multiple KMD5
+ * objects, you can simply invoke reset() to reuse the same object
+ * in making another calculation:
+ *
+ * \code
+ * context.reset ();
+ * context.update ("TWO");
+ * context.update ("THREE");
+ * cout << "Hex Digest output: " << context.hexDigest().data() << endl;
+ * \endcode
+ *
+ * @author Dirk Mueller <mueller@kde.org>, Dawit Alemayehu <adawit@kde.org>
+ */
+
+class KDECORE_EXPORT KMD5
+{
+public:
+
+ typedef unsigned char Digest[16];
+
+ KMD5();
+
+ /**
+ * Constructor that updates the digest for the given string.
+ *
+ * @param in C string or binary data
+ * @param len if negative, calculates the length by using
+ * strlen on the first parameter, otherwise
+ * it trusts the given length (does not stop on NUL byte).
+ */
+ KMD5(const char* in, int len = -1);
+
+ /**
+ * @overload
+ *
+ * Same as above except it accepts a QByteArray as its argument.
+ */
+ KMD5(const QByteArray& a );
+
+ /**
+ * @overload
+ *
+ * Same as above except it accepts a QCString as its argument.
+ */
+ KMD5(const QCString& a );
+
+ /**
+ * Updates the message to be digested. Be sure to add all data
+ * before you read the digest. After reading the digest, you
+ * can <b>not</b> add more data!
+ *
+ * @param in message to be added to digest
+ * @param len the length of the given message.
+ */
+ void update(const char* in, int len = -1) { update(reinterpret_cast<const unsigned char*>(in), len); }
+
+ /**
+ * @overload
+ */
+ void update(const unsigned char* in, int len = -1);
+
+ /**
+ * @overload
+ *
+ * @param in message to be added to the digest (QByteArray).
+ */
+ void update(const QByteArray& in );
+
+ /**
+ * @overload
+ *
+ * @param in message to be added to the digest (QCString).
+ */
+ void update(const QCString& in );
+
+ /**
+ * @overload
+ *
+ * reads the data from an I/O device, i.e. from a file (QFile).
+ *
+ * NOTE that the file must be open for reading.
+ *
+ * @param file a pointer to FILE as returned by calls like f{d,re}open
+ *
+ * @returns false if an error occurred during reading.
+ */
+ bool update(QIODevice& file);
+
+ /**
+ * Calling this function will reset the calculated message digest.
+ * Use this method to perform another message digest calculation
+ * without recreating the KMD5 object.
+ */
+ void reset();
+
+ /**
+ * @return the raw representation of the digest
+ */
+ const Digest& rawDigest ();
+
+ /**
+ * Fills the given array with the binary representation of the
+ * message digest.
+ *
+ * Use this method if you do not want to worry about making
+ * copy of the digest once you obtain it.
+ *
+ * @param bin an array of 16 characters ( char[16] )
+ */
+ void rawDigest( KMD5::Digest& bin );
+
+ /**
+ * Returns the value of the calculated message digest in
+ * a hexadecimal representation.
+ */
+ QCString hexDigest ();
+
+ /**
+ * @overload
+ */
+ void hexDigest(QCString&);
+
+ /**
+ * Returns the value of the calculated message digest in
+ * a base64-encoded representation.
+ */
+ QCString base64Digest ();
+
+ /**
+ * returns true if the calculated digest for the given
+ * message matches the given one.
+ */
+ bool verify( const KMD5::Digest& digest);
+
+ /**
+ * @overload
+ */
+ bool verify(const QCString&);
+
+protected:
+ /**
+ * Performs the real update work. Note
+ * that length is implied to be 64.
+ */
+ void transform( const unsigned char buffer[64] );
+
+ /**
+ * finalizes the digest
+ */
+ void finalize();
+
+private:
+ KMD5(const KMD5& u);
+ KMD5& operator=(const KMD5& md);
+
+ void init();
+ void encode( unsigned char* output, Q_UINT32 *in, Q_UINT32 len );
+ void decode( Q_UINT32 *output, const unsigned char* in, Q_UINT32 len );
+
+ Q_UINT32 rotate_left( Q_UINT32 x, Q_UINT32 n );
+ Q_UINT32 F( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z );
+ Q_UINT32 G( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z );
+ Q_UINT32 H( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z );
+ Q_UINT32 I( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z );
+ void FF( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x,
+ Q_UINT32 s, Q_UINT32 ac );
+ void GG( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x,
+ Q_UINT32 s, Q_UINT32 ac );
+ void HH( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x,
+ Q_UINT32 s, Q_UINT32 ac );
+ void II( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x,
+ Q_UINT32 s, Q_UINT32 ac );
+
+private:
+ Q_UINT32 m_state[4];
+ Q_UINT32 m_count[2];
+ Q_UINT8 m_buffer[64];
+ Digest m_digest;
+ bool m_finalized;
+
+ KMD5Private* d;
+};
+
+/**
+ * @short An adapted C++ implementation of the MD4 Message-Digest algorithm.
+ * @since 3.4
+ *
+ * The class usage is the same as KMD5.
+ */
+class KDECORE_EXPORT KMD4
+{
+public:
+
+ typedef unsigned char Digest[16];
+
+ KMD4();
+
+ /**
+ * Constructor that updates the digest for the given string.
+ *
+ * @param in C string or binary data
+ * @param len if negative, calculates the length by using
+ * strlen on the first parameter, otherwise
+ * it trusts the given length (does not stop on NUL byte).
+ */
+ KMD4(const char* in, int len = -1);
+
+ /**
+ * @overload
+ *
+ * Same as above except it accepts a QByteArray as its argument.
+ */
+ KMD4(const QByteArray& a );
+
+ /**
+ * @overload
+ *
+ * Same as above except it accepts a QCString as its argument.
+ */
+ KMD4(const QCString& a );
+
+ /**
+ * Updates the message to be digested. Be sure to add all data
+ * before you read the digest. After reading the digest, you
+ * can <b>not</b> add more data!
+ *
+ * @param in message to be added to digest
+ * @param len the length of the given message.
+ */
+ void update(const char* in, int len = -1) { update(reinterpret_cast<const unsigned char*>(in), len); }
+
+ /**
+ * @overload
+ */
+ void update(const unsigned char* in, int len = -1);
+
+ /**
+ * @overload
+ *
+ * @param in message to be added to the digest (QByteArray).
+ */
+ void update(const QByteArray& in );
+
+ /**
+ * @overload
+ *
+ * @param in message to be added to the digest (QCString).
+ */
+ void update(const QCString& in );
+
+ /**
+ * @overload
+ *
+ * reads the data from an I/O device, i.e. from a file (QFile).
+ *
+ * NOTE that the file must be open for reading.
+ *
+ * @param file a pointer to FILE as returned by calls like f{d,re}open
+ *
+ * @returns false if an error occurred during reading.
+ */
+ bool update(QIODevice& file);
+
+ /**
+ * Calling this function will reset the calculated message digest.
+ * Use this method to perform another message digest calculation
+ * without recreating the KMD4 object.
+ */
+ void reset();
+
+ /**
+ * @return the raw representation of the digest
+ */
+ const Digest& rawDigest ();
+
+ /**
+ * Fills the given array with the binary representation of the
+ * message digest.
+ *
+ * Use this method if you do not want to worry about making
+ * copy of the digest once you obtain it.
+ *
+ * @param bin an array of 16 characters ( char[16] )
+ */
+ void rawDigest( KMD4::Digest& bin );
+
+ /**
+ * Returns the value of the calculated message digest in
+ * a hexadecimal representation.
+ */
+ QCString hexDigest ();
+
+ /**
+ * @overload
+ */
+ void hexDigest(QCString&);
+
+ /**
+ * Returns the value of the calculated message digest in
+ * a base64-encoded representation.
+ */
+ QCString base64Digest ();
+
+ /**
+ * returns true if the calculated digest for the given
+ * message matches the given one.
+ */
+ bool verify( const KMD4::Digest& digest);
+
+ /**
+ * @overload
+ */
+ bool verify(const QCString&);
+
+protected:
+ /**
+ * Performs the real update work. Note
+ * that length is implied to be 64.
+ */
+ void transform( Q_UINT32 buf[4], Q_UINT32 const in[16] );
+
+ /**
+ * finalizes the digest
+ */
+ void finalize();
+
+private:
+ KMD4(const KMD4& u);
+ KMD4& operator=(const KMD4& md);
+
+ void init();
+
+ void byteReverse( unsigned char *buf, Q_UINT32 len );
+
+ Q_UINT32 rotate_left( Q_UINT32 x, Q_UINT32 n );
+ Q_UINT32 F( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z );
+ Q_UINT32 G( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z );
+ Q_UINT32 H( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z );
+ void FF( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x,
+ Q_UINT32 s );
+ void GG( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x,
+ Q_UINT32 s );
+ void HH( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x,
+ Q_UINT32 s );
+
+private:
+ Q_UINT32 m_state[4];
+ Q_UINT32 m_count[2];
+ Q_UINT8 m_buffer[64];
+ Digest m_digest;
+ bool m_finalized;
+
+ class KMD4Private;
+ KMD4Private* d;
+};
+
+
+#endif
diff --git a/kdecore/kmdcodec_compat.h b/kdecore/kmdcodec_compat.h
new file mode 100644
index 000000000..f2ed3b580
--- /dev/null
+++ b/kdecore/kmdcodec_compat.h
@@ -0,0 +1,4 @@
+#ifdef __GNUC__
+#warning #include <kio/kmdcodec.h> is deprecated, use #include <kmdcodec.h> instead.
+#endif
+#include "../kmdcodec.h"
diff --git a/kdecore/kmimesourcefactory.cpp b/kdecore/kmimesourcefactory.cpp
new file mode 100644
index 000000000..a74d69fc8
--- /dev/null
+++ b/kdecore/kmimesourcefactory.cpp
@@ -0,0 +1,106 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kiconloader.h>
+
+#include "kmimesourcefactory.h"
+
+class KMimeSourceFactoryPrivate
+{
+public:
+ inline KMimeSourceFactoryPrivate (KIconLoader* loader) : m_iconLoader(loader), m_instance(0L) {}
+ inline KIconLoader *iconLoader()
+ {
+ // If we don't have either of these, things are looking grim.
+ Q_ASSERT(m_instance || m_iconLoader);
+
+ if (m_iconLoader)
+ return m_iconLoader;
+
+ return m_instance->iconLoader();
+ }
+
+ KIconLoader *m_iconLoader;
+ KInstance *m_instance;
+};
+
+KMimeSourceFactory::KMimeSourceFactory (KIconLoader* loader)
+ : QMimeSourceFactory (),
+ d (new KMimeSourceFactoryPrivate (loader))
+{
+}
+
+KMimeSourceFactory::~KMimeSourceFactory()
+{
+ delete d;
+}
+
+QString KMimeSourceFactory::makeAbsolute (const QString& absOrRelName, const QString& context) const
+{
+ QString myName;
+ QString myContext;
+
+ const int pos = absOrRelName.find ('|');
+ if (pos > -1)
+ {
+ myContext = absOrRelName.left (pos);
+ myName = absOrRelName.right (absOrRelName.length() - myContext.length() - 1);
+ }
+
+ QString result;
+
+ if (myContext == "desktop")
+ {
+ result = d->iconLoader()->iconPath (myName, KIcon::Desktop);
+ }
+ else if (myContext == "toolbar")
+ {
+ result = d->iconLoader()->iconPath (myName, KIcon::Toolbar);
+ }
+ else if (myContext == "maintoolbar")
+ {
+ result = d->iconLoader()->iconPath (myName, KIcon::MainToolbar);
+ }
+ else if (myContext == "small")
+ {
+ result = d->iconLoader()->iconPath (myName, KIcon::Small);
+ }
+ else if (myContext == "user")
+ {
+ result = d->iconLoader()->iconPath (myName, KIcon::User);
+ }
+
+ if (result.isEmpty())
+ result = QMimeSourceFactory::makeAbsolute (absOrRelName, context);
+
+ return result;
+}
+
+void KMimeSourceFactory::setInstance(KInstance *instance)
+{
+ d->m_instance = instance;
+}
+
+void KMimeSourceFactory::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
diff --git a/kdecore/kmimesourcefactory.h b/kdecore/kmimesourcefactory.h
new file mode 100644
index 000000000..ec73621a7
--- /dev/null
+++ b/kdecore/kmimesourcefactory.h
@@ -0,0 +1,85 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (C) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KMIMESOURCEFACTORY_H
+#define KMIMESOURCEFACTORY_H
+
+#include <qmime.h>
+#include <kglobal.h>
+
+class KMimeSourceFactoryPrivate;
+class KInstance;
+
+/**
+ * An extension to QMimeSourceFactory that uses KIconLoader to
+ * find images.
+ *
+ * Normally you don't have to instantiate this class at all, KApplication does that for
+ * you automagically and sets QMimeSourceFactory::setDefaultFactory().
+ *
+ * @author Peter Putzer <putzer@kde.org>
+ */
+class KDECORE_EXPORT KMimeSourceFactory : public QMimeSourceFactory
+{
+public:
+
+ /**
+ * Constructor.
+ *
+ * @param loader is the iconloader used to find images.
+ */
+ KMimeSourceFactory (KIconLoader* loader = KGlobal::iconLoader());
+
+ /**
+ * Destructor.
+ */
+ virtual ~KMimeSourceFactory();
+
+ /**
+ * This function is maps an absolute or relative name for a resource to
+ * the absolute one.
+ *
+ * To load an icon, prepend the @p category name before the @p icon name, in the style
+ * of \<category>|\<icon>.
+ *
+ * Example:
+ * \code "<img src=\"user|ksysv_start\"/>", "<img src="\desktop|trash\">", ...
+ * \endcode
+ *
+ * @param abs_or_rel_name is the absolute or relative pathname.
+ * @param context is the path of the context object for the queried resource. Almost always empty.
+ */
+ virtual QString makeAbsolute (const QString& abs_or_rel_name, const QString& context) const;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ /**
+ * @internal
+ * Associate with a KInstance so we can pull its iconLoader() when need arises.
+ */
+ friend class KInstance;
+ void setInstance(KInstance *);
+
+ KMimeSourceFactoryPrivate* d;
+};
+
+#endif // KMIMESOURCEFACTORY_H
diff --git a/kdecore/kmountpoint.cpp b/kdecore/kmountpoint.cpp
new file mode 100644
index 000000000..a04780a37
--- /dev/null
+++ b/kdecore/kmountpoint.cpp
@@ -0,0 +1,385 @@
+/*
+ *
+ * This file is part of the KDE libraries
+ * Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ *
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <qfile.h>
+
+#include "kstandarddirs.h"
+
+#include "kmountpoint.h"
+
+#ifdef HAVE_VOLMGT
+#include <volmgt.h>
+#endif
+#ifdef HAVE_SYS_MNTTAB_H
+#include <sys/mnttab.h>
+#endif
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#elif defined(HAVE_SYS_MNTENT_H)
+#include <sys/mntent.h>
+#endif
+
+// This is the *BSD branch
+#ifdef HAVE_SYS_MOUNT_H
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <sys/mount.h>
+#endif
+
+#ifdef HAVE_FSTAB_H
+#include <fstab.h>
+#endif
+#if defined(_AIX)
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <sys/vfs.h>
+/* AIX does not prototype mntctl anywhere that I can find */
+#ifndef mntctl
+extern "C" {
+int mntctl(int command, int size, void* buffer);
+}
+#endif
+extern "C" struct vfs_ent *getvfsbytype(int vfsType);
+extern "C" void endvfsent( );
+#endif
+
+
+#ifndef HAVE_GETMNTINFO
+# ifdef _PATH_MOUNTED
+// On some Linux, MNTTAB points to /etc/fstab !
+# undef MNTTAB
+# define MNTTAB _PATH_MOUNTED
+# else
+# ifndef MNTTAB
+# ifdef MTAB_FILE
+# define MNTTAB MTAB_FILE
+# else
+# define MNTTAB "/etc/mnttab"
+# endif
+# endif
+# endif
+#endif
+
+
+
+#ifdef _OS_SOLARIS_
+#define FSTAB "/etc/vfstab"
+#else
+#define FSTAB "/etc/fstab"
+#endif
+
+
+
+KMountPoint::KMountPoint()
+{
+}
+
+KMountPoint::~KMountPoint()
+{
+}
+
+#ifdef HAVE_SETMNTENT
+#define SETMNTENT setmntent
+#define ENDMNTENT endmntent
+#define STRUCT_MNTENT struct mntent *
+#define STRUCT_SETMNTENT FILE *
+#define GETMNTENT(file, var) ((var = getmntent(file)) != 0)
+#define MOUNTPOINT(var) var->mnt_dir
+#define MOUNTTYPE(var) var->mnt_type
+#define MOUNTOPTIONS(var) var->mnt_opts
+#define FSNAME(var) var->mnt_fsname
+#else
+#define SETMNTENT fopen
+#define ENDMNTENT fclose
+#define STRUCT_MNTENT struct mnttab
+#define STRUCT_SETMNTENT FILE *
+#define GETMNTENT(file, var) (getmntent(file, &var) == 0)
+#define MOUNTPOINT(var) var.mnt_mountp
+#define MOUNTTYPE(var) var.mnt_fstype
+#define MOUNTOPTIONS(var) var.mnt_mntopts
+#define FSNAME(var) var.mnt_special
+#endif
+
+KMountPoint::List KMountPoint::possibleMountPoints(int infoNeeded)
+{
+ KMountPoint::List result;
+
+#ifdef HAVE_SETMNTENT
+ STRUCT_SETMNTENT fstab;
+ if ((fstab = SETMNTENT(FSTAB, "r")) == 0)
+ return result;
+
+ STRUCT_MNTENT fe;
+ while (GETMNTENT(fstab, fe))
+ {
+ KMountPoint *mp = new KMountPoint();
+ mp->m_mountedFrom = QFile::decodeName(FSNAME(fe));
+
+ mp->m_mountPoint = QFile::decodeName(MOUNTPOINT(fe));
+ mp->m_mountType = QFile::decodeName(MOUNTTYPE(fe));
+
+ //Devices using supermount have their device names in the mount options
+ //instead of the device field. That's why we need to read the mount options
+ if (infoNeeded & NeedMountOptions || (mp->m_mountType == "supermount"))
+ {
+ QString options = QFile::decodeName(MOUNTOPTIONS(fe));
+ mp->m_mountOptions = QStringList::split(',', options);
+ }
+
+ if(mp->m_mountType == "supermount")
+ mp->m_mountedFrom = devNameFromOptions(mp->m_mountOptions);
+
+ if (infoNeeded & NeedRealDeviceName)
+ {
+ if (mp->m_mountedFrom.startsWith("/"))
+ mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom);
+ }
+ // TODO: Strip trailing '/' ?
+ result.append(mp);
+ }
+ ENDMNTENT(fstab);
+#else
+ QFile f(FSTAB);
+ if ( !f.open(IO_ReadOnly) )
+ return result;
+
+ QTextStream t (&f);
+ QString s;
+
+ while (! t.eof())
+ {
+ s=t.readLine().simplifyWhiteSpace();
+ if ( s.isEmpty() || (s[0] == '#'))
+ continue;
+
+ // not empty or commented out by '#'
+ QStringList item = QStringList::split(' ', s);
+
+#ifdef _OS_SOLARIS_
+ if (item.count() < 5)
+ continue;
+#else
+ if (item.count() < 4)
+ continue;
+#endif
+
+ KMountPoint *mp = new KMountPoint();
+
+ int i = 0;
+ mp->m_mountedFrom = item[i++];
+#ifdef _OS_SOLARIS_
+ //device to fsck
+ i++;
+#endif
+ mp->m_mountPoint = item[i++];
+ mp->m_mountType = item[i++];
+ QString options = item[i++];
+
+ if (infoNeeded & NeedMountOptions)
+ {
+ mp->m_mountOptions = QStringList::split(',', options);
+ }
+
+ if (infoNeeded & NeedRealDeviceName)
+ {
+ if (mp->m_mountedFrom.startsWith("/"))
+ mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom);
+ }
+ // TODO: Strip trailing '/' ?
+ result.append(mp);
+ } //while
+
+ f.close();
+#endif
+ return result;
+}
+
+KMountPoint::List KMountPoint::currentMountPoints(int infoNeeded)
+{
+ KMountPoint::List result;
+
+#ifdef HAVE_GETMNTINFO
+
+#ifdef GETMNTINFO_USES_STATVFS
+ struct statvfs *mounted;
+#else
+ struct statfs *mounted;
+#endif
+
+ int num_fs = getmntinfo(&mounted, MNT_NOWAIT);
+
+ for (int i=0;i<num_fs;i++)
+ {
+ KMountPoint *mp = new KMountPoint();
+ mp->m_mountedFrom = QFile::decodeName(mounted[i].f_mntfromname);
+ mp->m_mountPoint = QFile::decodeName(mounted[i].f_mntonname);
+
+#ifdef __osf__
+ mp->m_mountType = QFile::decodeName(mnt_names[mounted[i].f_type]);
+#else
+ mp->m_mountType = QFile::decodeName(mounted[i].f_fstypename);
+#endif
+
+ if (infoNeeded & NeedMountOptions)
+ {
+ struct fstab *ft = getfsfile(mounted[i].f_mntonname);
+ QString options = QFile::decodeName(ft->fs_mntops);
+ mp->m_mountOptions = QStringList::split(',', options);
+ }
+
+ if (infoNeeded & NeedRealDeviceName)
+ {
+ if (mp->m_mountedFrom.startsWith("/"))
+ mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom);
+ }
+ // TODO: Strip trailing '/' ?
+ result.append(mp);
+ }
+
+#elif defined(_AIX)
+
+ struct vmount *mntctl_buffer;
+ struct vmount *vm;
+ char *mountedfrom;
+ char *mountedto;
+ int fsname_len, num;
+ int buf_sz = 4096;
+
+ mntctl_buffer = (struct vmount*)malloc(buf_sz);
+ num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
+ if (num == 0)
+ {
+ buf_sz = *(int*)mntctl_buffer;
+ free(mntctl_buffer);
+ mntctl_buffer = (struct vmount*)malloc(buf_sz);
+ num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
+ }
+
+ if (num > 0)
+ {
+ /* iterate through items in the vmount structure: */
+ vm = (struct vmount *)mntctl_buffer;
+ for ( ; num > 0; num-- )
+ {
+ /* get the name of the mounted file systems: */
+ fsname_len = vmt2datasize(vm, VMT_STUB);
+ mountedto = (char*)malloc(fsname_len + 1);
+ mountedto[fsname_len] = '\0';
+ strncpy(mountedto, (char *)vmt2dataptr(vm, VMT_STUB), fsname_len);
+
+ fsname_len = vmt2datasize(vm, VMT_OBJECT);
+ mountedfrom = (char*)malloc(fsname_len + 1);
+ mountedfrom[fsname_len] = '\0';
+ strncpy(mountedfrom, (char *)vmt2dataptr(vm, VMT_OBJECT), fsname_len);
+
+ /* Look up the string for the file system type,
+ * as listed in /etc/vfs.
+ * ex.: nfs,jfs,afs,cdrfs,sfs,cachefs,nfs3,autofs
+ */
+ struct vfs_ent* ent = getvfsbytype(vm->vmt_gfstype);
+
+ KMountPoint *mp = new KMountPoint();
+ mp->m_mountedFrom = QFile::decodeName(mountedfrom);
+ mp->m_mountPoint = QFile::decodeName(mountedto);
+ mp->m_mountType = QFile::decodeName(ent->vfsent_name);
+
+ free(mountedfrom);
+ free(mountedto);
+
+ if (infoNeeded & NeedMountOptions)
+ {
+ // TODO
+ }
+
+ if (infoNeeded & NeedRealDeviceName)
+ {
+ if (mp->m_mountedFrom.startsWith("/"))
+ mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom);
+ }
+
+ result.append(mp);
+
+ /* goto the next vmount structure: */
+ vm = (struct vmount *)((char *)vm + vm->vmt_length);
+ }
+
+ endvfsent( );
+ }
+
+ free( mntctl_buffer );
+#elif defined(Q_WS_WIN)
+ //TODO?
+#else
+ STRUCT_SETMNTENT mnttab;
+ if ((mnttab = SETMNTENT(MNTTAB, "r")) == 0)
+ return result;
+
+ STRUCT_MNTENT fe;
+ while (GETMNTENT(mnttab, fe))
+ {
+ KMountPoint *mp = new KMountPoint();
+ mp->m_mountedFrom = QFile::decodeName(FSNAME(fe));
+
+ mp->m_mountPoint = QFile::decodeName(MOUNTPOINT(fe));
+ mp->m_mountType = QFile::decodeName(MOUNTTYPE(fe));
+
+ //Devices using supermount have their device names in the mount options
+ //instead of the device field. That's why we need to read the mount options
+ if (infoNeeded & NeedMountOptions || (mp->m_mountType == "supermount"))
+ {
+ QString options = QFile::decodeName(MOUNTOPTIONS(fe));
+ mp->m_mountOptions = QStringList::split(',', options);
+ }
+
+ if (mp->m_mountType == "supermount")
+ mp->m_mountedFrom = devNameFromOptions(mp->m_mountOptions);
+
+ if (infoNeeded & NeedRealDeviceName)
+ {
+ if (mp->m_mountedFrom.startsWith("/"))
+ mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom);
+ }
+ // TODO: Strip trailing '/' ?
+ result.append(mp);
+ }
+ ENDMNTENT(mnttab);
+#endif
+ return result;
+}
+
+QString KMountPoint::devNameFromOptions(const QStringList &options)
+{
+ // Search options to find the device name
+ for ( QStringList::ConstIterator it = options.begin(); it != options.end(); ++it)
+ {
+ if( (*it).startsWith("dev="))
+ return QString(*it).remove("dev=");
+ }
+ return QString("none");
+}
diff --git a/kdecore/kmountpoint.h b/kdecore/kmountpoint.h
new file mode 100644
index 000000000..ee3ea3941
--- /dev/null
+++ b/kdecore/kmountpoint.h
@@ -0,0 +1,116 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KMOUNTPOINT_H_
+#define _KMOUNTPOINT_H_
+
+#include <qptrlist.h>
+#include <qstringlist.h>
+
+#include <ksharedptr.h>
+
+/**
+ * The KMountPoint class provides information about mounted and unmounted disks.
+ * It provides a system independent interface to fstab.
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ * @since 3.2
+ */
+class KDECORE_EXPORT KMountPoint : public KShared
+{
+ typedef signed long long int filesize_t;
+public:
+ typedef KSharedPtr<KMountPoint> Ptr;
+ typedef QValueList<Ptr> List;
+public:
+ enum { NeedMountOptions = 1, NeedRealDeviceName = 2 };
+
+ /**
+ * This function gives a list of all possible mountpoints. (fstab)
+ * @param infoNeeded Flags that specify which additional information
+ * should be fetched.
+ */
+ static KMountPoint::List possibleMountPoints(int infoNeeded=0);
+
+ /**
+ * This function gives a list of all currently used mountpoints. (mtab)
+ * @param infoNeeded Flags that specify which additional information
+ * should be fetched.
+ */
+ static KMountPoint::List currentMountPoints(int infoNeeded=0);
+
+ /**
+ * Where this filesystem gets mounted from.
+ * This can refer to a device, a remote server or something else.
+ */
+ QString mountedFrom() const { return m_mountedFrom; }
+
+ /**
+ * Canonical name of the device where the filesystem got mounted from.
+ * (Or empty, if not a device)
+ * Only available when the NeedRealDeviceName flag was set.
+ */
+ QString realDeviceName() const { return m_device; }
+
+ /**
+ * Path where the filesystem is mounted or can be mounted.
+ */
+ QString mountPoint() const { return m_mountPoint; }
+
+ /**
+ * Type of filesystem
+ */
+ QString mountType() const { return m_mountType; }
+
+ /**
+ * Options used to mount the filesystem.
+ * Only available when the NeedMountOptions flag was set.
+ */
+ QStringList mountOptions() const { return m_mountOptions; }
+
+ /**
+ * When using supermount, the device name is in the options field
+ * as dev=/my/device
+ * @since 3.4
+ */
+ static QString devNameFromOptions(const QStringList &options);
+
+ /**
+ * Destructor
+ */
+ ~KMountPoint();
+
+private:
+ /**
+ * Constructor
+ */
+ KMountPoint();
+
+ QString m_mountedFrom;
+ QString m_device;
+ QString m_mountPoint;
+ QString m_mountType;
+ QStringList m_mountOptions;
+
+ class KMountPointPrivate;
+ KMountPointPrivate *d;
+};
+
+#endif // _KMOUNTPOINT_H_
+
diff --git a/kdecore/kmultipledrag.cpp b/kdecore/kmultipledrag.cpp
new file mode 100644
index 000000000..03ad74294
--- /dev/null
+++ b/kdecore/kmultipledrag.cpp
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 "kmultipledrag.h"
+#include "kdebug.h"
+
+#ifndef QT_NO_DRAGANDDROP
+
+KMultipleDrag::KMultipleDrag( QWidget *dragSource, const char *name )
+ : QDragObject( dragSource, name )
+{
+ m_dragObjects.setAutoDelete( true );
+}
+
+void KMultipleDrag::addDragObject( QDragObject *dragObject )
+{
+ //kdDebug() << "KMultipleDrag::addDragObject" << endl;
+ m_dragObjects.append( dragObject );
+ // We need to find out how many formats this dragObject supports
+ int i = 0;
+ while ( dragObject->format( i ) )
+ ++i;
+ m_numberFormats.append( i ); // e.g. if it supports two formats, 0 and 1, store 2.
+}
+
+QByteArray KMultipleDrag::encodedData( const char *mime ) const
+{
+ //kdDebug() << "KMultipleDrag::encodedData " << mime << endl;
+ // Iterate over the drag objects, and find the format in the right one
+ QPtrListIterator<QDragObject> it( m_dragObjects );
+ for ( ; it.current(); ++it )
+ {
+ for ( int i = 0; it.current()->format( i ); ++i )
+ {
+ if ( ::qstrcmp( it.current()->format( i ), mime ) == 0 )
+ return it.current()->encodedData( mime );
+ }
+ }
+ return QByteArray();
+}
+
+const char* KMultipleDrag::format( int i ) const
+{
+ //kdDebug() << "KMultipleDrag::format " << i << endl;
+ // example: m_numberFormats: 1, 4
+ // m_dragObjects: storeddrag, textdrag
+ // i=0 -> storeddrag->format( 0 )
+ // i=1 -> textdrag->format( 0 )
+ // i=2 -> textdrag->format( 1 )
+ // etc.
+ QValueList<int>::ConstIterator nit = m_numberFormats.begin();
+ QValueList<int>::ConstIterator nend = m_numberFormats.end();
+ QPtrListIterator<QDragObject> it( m_dragObjects );
+ for ( ; nit != nend && i >= *nit ; ++nit, ++it )
+ i -= *nit;
+ if ( it.current() )
+ return it.current()->format( i );
+ return 0;
+}
+
+void KMultipleDrag::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kmultipledrag.moc"
+
+#endif
diff --git a/kdecore/kmultipledrag.h b/kdecore/kmultipledrag.h
new file mode 100644
index 000000000..bb08c86cc
--- /dev/null
+++ b/kdecore/kmultipledrag.h
@@ -0,0 +1,105 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 KMULTIPLEDRAG_H
+#define KMULTIPLEDRAG_H
+
+#ifndef QT_NO_DRAGANDDROP
+
+#include <qdragobject.h>
+#include <qvaluelist.h>
+#include "kdelibs_export.h"
+
+class KMultipleDragPrivate;
+/**
+ * This class makes it easy for applications to provide a drag object
+ * (for drag-n-drop or for clipboard) that has several representations
+ * of the same data, under different formats.
+ *
+ * Instead of creating a specific class for each case (as would otherwise
+ * be necessary), you can simply create independent drag objects (e.g.
+ * a QImageDrag object and a KURLDrag object), and bundle them together
+ * using KMultipleDrag.
+ *
+ * Sample code for this:
+ *
+ * \code
+ * KMultipleDrag *drag = new KMultipleDrag( parentWidget );
+ * drag->addDragObject( new QImageDrag( someQImage, 0 ) );
+ * drag->addDragObject( new KURLDrag( someKURL, 0 ) );
+ * drag->drag();
+ * \endcode
+ *
+ * Note that the drag objects added to the multiple drag become owned by it.
+ * For that reason their parent should be 0.
+ *
+ * @author David Faure <faure@kde.org>
+ */
+class KDECORE_EXPORT KMultipleDrag : public QDragObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Create a new KMultipleDrag object.
+ * @param dragSource the parent object which is the source of the data,
+ * 0 for a parent-less object
+ * @param name the name of the object, can be 0
+ */
+ KMultipleDrag( QWidget *dragSource = 0, const char *name = 0 );
+
+ /**
+ * Call this to add each underlying drag object to the multiple drag object.
+ * The drag object should not have a parent because the multiple drag object
+ * will own it.
+ *
+ * @param dragObject the drag object to add. Should have no parent object.
+ */
+ void addDragObject( QDragObject *dragObject );
+
+ /**
+ * Returns the data of a drag object with that supports the given
+ * mime type.
+ * @param mime the mime type to search
+ * @return the data, or a null byte array if not found
+ * @reimp
+ */
+ virtual QByteArray encodedData( const char *mime ) const;
+
+ /**
+ * Returns the @p i'th supported format, or 0.
+ * @param i the number of the format to check
+ * @return the format with the number @p i, or 0 otherwise
+ * @reimp
+ */
+ virtual const char* format( int i ) const;
+
+protected:
+// KDE4: make private
+ QPtrList<QDragObject> m_dragObjects;
+ QValueList<int> m_numberFormats;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KMultipleDragPrivate* d;
+};
+
+#endif // QT_NO_DRAGANDDROP
+
+#endif // KMULTIPLEDRAG_H
diff --git a/kdecore/knotifyclient.cpp b/kdecore/knotifyclient.cpp
new file mode 100644
index 000000000..ab3032c35
--- /dev/null
+++ b/kdecore/knotifyclient.cpp
@@ -0,0 +1,363 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Charles Samuels <charles@altair.dhs.org>
+ 2000 Malte Starostik <starosti@zedat.fu-berlin.de>
+ 2000,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "knotifyclient.h"
+
+#include <qdatastream.h>
+#include <qptrstack.h>
+
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <dcopclient.h>
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+
+static const char daemonName[] = "knotify";
+
+static bool canAvoidStartupEvent( const QString& event, const QString& appname, int present )
+{
+ static bool checkAvoid = true;
+ if( !checkAvoid )
+ return false;
+ if(( appname != "kwin" && appname != "ksmserver" ) || present > 0 ) {
+ checkAvoid = false;
+ return false;
+ }
+ // startkde event is in global events file
+ static KConfig* configfile = appname != "ksmserver"
+ ? new KConfig( appname + ".eventsrc", true, false )
+ : new KConfig( "knotify.eventsrc", true, false );
+ static KConfig* eventsfile = appname != "ksmserver"
+ ? new KConfig( appname + "/eventsrc", true, false, "data" )
+ : new KConfig( "knotify/eventsrc", true, false, "data" );
+ configfile->setGroup( event );
+ eventsfile->setGroup( event );
+ int ev1 = configfile->readNumEntry( "presentation", -2 );
+ int ev2 = eventsfile->readNumEntry( "default_presentation", -2 );
+ if(( ev1 == -2 && ev2 == -2 ) // unknown
+ || ev1 > 0 // configured to have presentation
+ || ( ev1 == -2 && ev2 > 0 )) { // not configured, has default presentation
+ checkAvoid = false;
+ return false;
+ }
+ return true;
+}
+
+static int sendNotifyEvent(const QString &message, const QString &text,
+ int present, int level, const QString &sound,
+ const QString &file, int winId )
+{
+ if (!kapp) return 0;
+
+ DCOPClient *client=kapp->dcopClient();
+ if (!client->isAttached())
+ {
+ client->attach();
+ if (!client->isAttached())
+ return 0;
+ }
+
+ QString appname = KNotifyClient::instance()->instanceName();
+
+ if( canAvoidStartupEvent( message, appname, present ))
+ return -1; // done "successfully" - there will be no event presentation
+
+ int uniqueId = kMax( 1, kapp->random() ); // must not be 0 -- means failure!
+
+ // knotify daemon needs toplevel window
+ QWidget* widget = QWidget::find( (WId)winId );
+ if( widget )
+ winId = (int)widget->topLevelWidget()->winId();
+
+ QByteArray data;
+ QDataStream ds(data, IO_WriteOnly);
+ ds << message << appname << text << sound << file << present << level
+ << winId << uniqueId;
+
+ if ( !KNotifyClient::startDaemon() )
+ return 0;
+
+ if ( client->send(daemonName, "Notify", "notify(QString,QString,QString,QString,QString,int,int,int,int)", data) )
+ {
+ return uniqueId;
+ }
+
+ return 0;
+}
+
+int KNotifyClient::event( StandardEvent type, const QString& text )
+{
+ return event( 0, type, text );
+}
+
+int KNotifyClient::event(const QString &message, const QString &text)
+{
+ return event(0, message, text);
+}
+
+int KNotifyClient::userEvent(const QString &text, int present, int level,
+ const QString &sound, const QString &file)
+{
+ return userEvent( 0, text, present, level, sound, file );
+}
+
+
+int KNotifyClient::event( int winId, StandardEvent type, const QString& text )
+{
+ QString message;
+ switch ( type ) {
+ case cannotOpenFile:
+ message = QString::fromLatin1("cannotopenfile");
+ break;
+ case warning:
+ message = QString::fromLatin1("warning");
+ break;
+ case fatalError:
+ message = QString::fromLatin1("fatalerror");
+ break;
+ case catastrophe:
+ message = QString::fromLatin1("catastrophe");
+ break;
+ case notification: // fall through
+ default:
+ message = QString::fromLatin1("notification");
+ break;
+ }
+
+ return sendNotifyEvent( message, text, Default, Default,
+ QString::null, QString::null, winId );
+}
+
+int KNotifyClient::event(int winId, const QString &message,
+ const QString &text)
+{
+ return sendNotifyEvent(message, text, Default, Default, QString::null, QString::null, winId);
+}
+
+int KNotifyClient::userEvent(int winId, const QString &text, int present,
+ int level,
+ const QString &sound, const QString &file)
+{
+ return sendNotifyEvent(QString::null, text, present, level, sound, file, winId);
+}
+
+int KNotifyClient::getPresentation(const QString &eventname)
+{
+ int present;
+ if (eventname.isEmpty()) return Default;
+
+ KConfig eventsfile( KNotifyClient::instance()->instanceName()+".eventsrc", true, false);
+ eventsfile.setGroup(eventname);
+
+ present=eventsfile.readNumEntry("presentation", -1);
+
+ return present;
+}
+
+QString KNotifyClient::getFile(const QString &eventname, int present)
+{
+ if (eventname.isEmpty()) return QString::null;
+
+ KConfig eventsfile( KNotifyClient::instance()->instanceName()+".eventsrc", true, false);
+ eventsfile.setGroup(eventname);
+
+ switch (present)
+ {
+ case (Sound):
+ return eventsfile.readPathEntry("soundfile");
+ case (Logfile):
+ return eventsfile.readPathEntry("logfile");
+ }
+
+ return QString::null;
+}
+
+int KNotifyClient::getDefaultPresentation(const QString &eventname)
+{
+ int present;
+ if (eventname.isEmpty()) return Default;
+
+ KConfig eventsfile( KNotifyClient::instance()->instanceName()+"/eventsrc", true, false, "data");
+ eventsfile.setGroup(eventname);
+
+ present=eventsfile.readNumEntry("default_presentation", -1);
+
+ return present;
+}
+
+QString KNotifyClient::getDefaultFile(const QString &eventname, int present)
+{
+ if (eventname.isEmpty()) return QString::null;
+
+ KConfig eventsfile( KNotifyClient::instance()->instanceName()+"/eventsrc", true, false, "data");
+ eventsfile.setGroup(eventname);
+
+ switch (present)
+ {
+ case (Sound):
+ return eventsfile.readPathEntry("default_sound");
+ case (Logfile):
+ return eventsfile.readPathEntry("default_logfile");
+ }
+
+ return QString::null;
+}
+
+bool KNotifyClient::startDaemon()
+{
+ static bool firstTry = true;
+ if (!kapp->dcopClient()->isApplicationRegistered(daemonName)) {
+ if( firstTry ) {
+ firstTry = false;
+ return KApplication::startServiceByDesktopName(daemonName) == 0;
+ }
+ return false;
+ }
+ return true;
+}
+
+
+void KNotifyClient::beep(const QString& reason)
+{
+ if ( !kapp || KNotifyClient::Instance::currentInstance()->useSystemBell() ) {
+ QApplication::beep();
+ return;
+ }
+
+ DCOPClient *client=kapp->dcopClient();
+ if (!client->isAttached())
+ {
+ client->attach();
+ if (!client->isAttached() || !client->isApplicationRegistered(daemonName))
+ {
+ QApplication::beep();
+ return;
+ }
+ }
+ // The kaccess daemon handles visual and other audible beeps
+ if ( client->isApplicationRegistered( "kaccess" ) )
+ {
+ QApplication::beep();
+ return;
+ }
+
+ KNotifyClient::event(KNotifyClient::notification, reason);
+}
+
+
+KInstance * KNotifyClient::instance() {
+ return KNotifyClient::Instance::current();
+}
+
+
+class KNotifyClient::InstanceStack
+{
+public:
+ InstanceStack() { m_defaultInstance = 0; }
+ virtual ~InstanceStack() { delete m_defaultInstance; }
+ void push(Instance *instance) { m_instances.push(instance); }
+
+ void pop(Instance *instance)
+ {
+ if (m_instances.top() == instance)
+ m_instances.pop();
+ else if (!m_instances.isEmpty())
+ {
+ kdWarning(160) << "Tried to remove an Instance that is not the current," << endl;
+ kdWarning(160) << "Resetting to the main KApplication." << endl;
+ m_instances.clear();
+ }
+ else
+ kdWarning(160) << "Tried to remove an Instance, but the stack was empty." << endl;
+ }
+
+ Instance *currentInstance()
+ {
+ if (m_instances.isEmpty())
+ {
+ m_defaultInstance = new Instance(kapp);
+ }
+ return m_instances.top();
+ }
+
+private:
+ QPtrStack<Instance> m_instances;
+ Instance *m_defaultInstance;
+};
+
+KNotifyClient::InstanceStack * KNotifyClient::Instance::s_instances = 0L;
+static KStaticDeleter<KNotifyClient::InstanceStack > instancesDeleter;
+
+struct KNotifyClient::InstancePrivate
+{
+ KInstance *instance;
+ bool useSystemBell;
+};
+
+KNotifyClient::Instance::Instance(KInstance *instance)
+{
+ d = new InstancePrivate;
+ d->instance = instance;
+ instances()->push(this);
+
+ KConfig *config = instance->config();
+ KConfigGroupSaver cs( config, "General" );
+ d->useSystemBell = config->readBoolEntry( "UseSystemBell", false );
+}
+
+KNotifyClient::Instance::~Instance()
+{
+ if (s_instances)
+ s_instances->pop(this);
+ delete d;
+}
+
+KNotifyClient::InstanceStack *KNotifyClient::Instance::instances()
+{
+ if (!s_instances)
+ instancesDeleter.setObject(s_instances, new InstanceStack);
+ return s_instances;
+}
+
+bool KNotifyClient::Instance::useSystemBell() const
+{
+ return d->useSystemBell;
+}
+
+
+// static methods
+
+// We always return a valid KNotifyClient::Instance here. If no special one
+// is available, we have a default-instance with kapp as KInstance.
+// We make sure to always have that default-instance in the stack, because
+// the stack might have gotten cleared in the destructor.
+// We can't use QStack::setAutoDelete( true ), because no instance besides
+// our default instance is owned by us.
+KNotifyClient::Instance * KNotifyClient::Instance::currentInstance()
+{
+ return instances()->currentInstance();
+}
+
+KInstance *KNotifyClient::Instance::current()
+{
+ return currentInstance()->d->instance;
+}
diff --git a/kdecore/knotifyclient.h b/kdecore/knotifyclient.h
new file mode 100644
index 000000000..e7be1798e
--- /dev/null
+++ b/kdecore/knotifyclient.h
@@ -0,0 +1,325 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Charles Samuels <charles@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KNOTIFY_CLIENT
+#define _KNOTIFY_CLIENT
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+class KInstance;
+#undef None // X11 headers...
+
+/**
+ * This namespace provides a method for issuing events to a KNotifyServer
+ * call KNotifyClient::event("eventname"); to issue it.
+ * On installation, there should be a file called
+ * $KDEDIR/share/apps/appname/eventsrc which contains the events.
+ *
+ * The file looks like this:
+ * \code
+ * [!Global!]
+ * IconName=Filename (e.g. kdesktop, without any extension)
+ * Comment=FriendlyNameOfApp
+ *
+ * [eventname]
+ * Name=FriendlyNameOfEvent
+ * Comment=Description Of Event
+ * default_sound=filetoplay.wav
+ * default_logfile=logfile.txt
+ * default_commandline=command
+ * default_presentation=1
+ * ...
+ * \endcode
+ * default_presentation contains these ORed events:
+ * None=0, Sound=1, Messagebox=2, Logfile=4, Stderr=8, PassivePopup=16,
+ * Execute=32, Taskbar=64
+ *
+ * KNotify will search for sound files given with a relative path first in
+ * the application's sound directory (share/apps/Application Name/sounds), then in
+ * the KDE global sound directory (share/sounds).
+ *
+ * You can also use the "nopresentation" key, with any the presentations
+ * ORed. Those that are in that field will not appear in the kcontrol
+ * module. This was intended for software like KWin to not allow a window-opening
+ * that opens a window (e.g., allowing to disable KMessageBoxes from appearing)
+ * If the user edits the eventsrc file manually, it will appear. This only
+ * affects the KcmNotify.
+ *
+ * You can also use the following events, which are system controlled
+ * and do not need to be placed in your eventsrc:
+ *
+ *<ul>
+ * <li>cannotopenfile
+ * <li>notification
+ * <li>warning
+ * <li>fatalerror
+ * <li>catastrophe
+ *</ul>
+ *
+ * The events can be configured in an application using KNotifyDialog, which is part of KIO.
+ *
+ * @author Charles Samuels <charles@kde.org>
+ */
+
+
+namespace KNotifyClient
+{
+ struct InstancePrivate;
+ class InstanceStack;
+
+ /**
+ * Makes it possible to use KNotifyClient with a KInstance
+ * that is not the application.
+ *
+ * Use like this:
+ * \code
+ * KNotifyClient::Instance(myInstance);
+ * KNotifyClient::event("MyEvent");
+ * \endcode
+ *
+ * @short Enables KNotifyClient to use a different KInstance
+ */
+ class KDECORE_EXPORT Instance
+ {
+ public:
+ /**
+ * Constructs a KNotifyClient::Instance to make KNotifyClient use
+ * the specified KInstance for the event configuration.
+ * @param instance the instance for the event configuration
+ */
+ Instance(KInstance *instance);
+ /**
+ * Destructs the KNotifyClient::Instance and resets KNotifyClient
+ * to the previously used KInstance.
+ */
+ ~Instance();
+ /**
+ * Checks whether the system bell should be used.
+ * @returns true if this instance should use the System bell instead
+ * of KNotify.
+ */
+ bool useSystemBell() const;
+ /**
+ * Returns the currently active KInstance.
+ * @return the active KInstance
+ */
+ static KInstance *current();
+
+ /**
+ * Returns the current KNotifyClient::Instance (not the KInstance).
+ * @return the active Instance
+ */
+ static Instance *currentInstance();
+
+ private:
+ static InstanceStack *instances();
+ InstancePrivate *d;
+ static InstanceStack *s_instances;
+ };
+
+
+ /**
+ * Describes the notification method.
+ */
+ enum {
+ Default = -1,
+ None = 0,
+ Sound = 1,
+ Messagebox = 2,
+ Logfile = 4,
+ Stderr = 8,
+ PassivePopup = 16, ///< @since 3.1
+ Execute = 32, ///< @since 3.1
+ Taskbar = 64 ///< @since 3.2
+ };
+
+ /**
+ * Describes the level of the error.
+ */
+ enum {
+ Notification=1,
+ Warning=2,
+ Error=4,
+ Catastrophe=8
+ };
+
+ /**
+ * default events you can use
+ */
+ enum StandardEvent {
+ cannotOpenFile,
+ notification,
+ warning,
+ fatalError,
+ catastrophe
+ };
+
+ /**
+ * This starts the KNotify Daemon, if it's not already started.
+ * This will be useful for games that use sound effects. Run this
+ * at the start of the program, and there won't be a pause when it is
+ * first triggered.
+ * @return true if daemon is running (always true at the moment)
+ **/
+ KDECORE_EXPORT bool startDaemon();
+
+//#ifndef KDE_NO_COMPAT
+ /**
+ * @deprecated
+ * @param message The name of the event
+ * @param text The text to put in a dialog box. This won't be shown if
+ * the user connected the event to sound, only. Can be QString::null.
+ * @return a value > 0, unique for this event if successful, 0 otherwise
+ */
+ KDECORE_EXPORT int event(const QString &message, const QString &text=QString::null) KDE_DEPRECATED;
+
+ /**
+ * @deprecated
+ * Allows to easily emit standard events.
+ * @param event The event you want to raise.
+ * @param text The text explaining the event you raise. Can be QString::null.
+ * @return a value > 0, unique for this event if successful, 0 otherwise
+ */
+ KDECORE_EXPORT int event( StandardEvent event, const QString& text=QString::null ) KDE_DEPRECATED;
+
+ /**
+ * @deprecated
+ * Will fire an event that's not registered.
+ * @param text The error message text, if applicable
+ * @param present The presentation method(s) of the event
+ * @param level The error message level, defaulting to "Default"
+ * @param sound The sound file to play if selected with @p present
+ * @param file The log file to append the message to if selected with @p present
+ * @return a value > 0, unique for this event if successful, 0 otherwise
+ */
+ KDECORE_EXPORT int userEvent(const QString &text=QString::null, int present=Default, int level=Default,
+ const QString &sound=QString::null, const QString &file=QString::null) KDE_DEPRECATED;
+
+//#endif
+
+ /**
+ * This should be the most used method in here.
+ * Pass the origin-widget's winId() here so that a PassivePopup can be
+ * placed appropriately.
+ *
+ * Call it by KNotifyClient::event(widget->winId(), "EventName");
+ * It will use KApplication::kApplication->dcopClient() to communicate to
+ * the server
+ * @param winId The winId() of the widget where the event originates
+ * @param message The name of the event
+ * @param text The text to put in a dialog box. This won't be shown if
+ * the user connected the event to sound, only. Can be QString::null.
+ * @return a value > 0, unique for this event if successful, 0 otherwise
+ * @since 3.1.1
+ */
+ // KDE4: use WId instead of int
+ KDECORE_EXPORT int event( int winId, const QString& message,
+ const QString& text = QString::null );
+
+ /**
+ * You should
+ * pass the origin-widget's winId() here so that a PassivePopup can be
+ * placed appropriately.
+ * @param winId The winId() of the widget where the event originates
+ * @param event The event you want to raise
+ * @param text The text to put in a dialog box. This won't be shown if
+ * the user connected the event to sound, only. Can be QString::null.
+ * @return a value > 0, unique for this event if successful, 0 otherwise
+ * @since 3.1.1
+ */
+ // KDE4: use WId instead of int
+ KDECORE_EXPORT int event( int winId, StandardEvent event,
+ const QString& text = QString::null );
+
+ /**
+ * Will fire an event that's not registered.
+ * You should
+ * pass the origin-widget's winId() here so that a PassivePopup can be
+ * placed appropriately.
+ * @param winId The winId() of the originating widget
+ * @param text The error message text, if applicable
+ * @param present The presentation method(s) of the event
+ * @param level The error message level, defaulting to "Default"
+ * @param sound The sound file to play if selected with @p present
+ * @param file The log file to append the message to if selected with @p present
+ * @return a value > 0, unique for this event if successful, 0 otherwise
+ * @since 3.1.1
+ */
+ // KDE4: use WId instead of int
+ KDECORE_EXPORT int userEvent(int winId, const QString &text=QString::null, int present=Default, int level=Default,
+ const QString &sound=QString::null, const QString &file=QString::null);
+
+ /**
+ * This is a simple substitution for QApplication::beep().
+ * It simply calls
+ * \code
+ * KNotifyClient::event( KNotifyClient::notification, reason );
+ * \endcode
+ * @param reason the reason, can be QString::null.
+ */
+ KDECORE_EXPORT void beep(const QString& reason=QString::null);
+
+ /**
+ * Gets the presentation associated with a certain event name
+ * Remeber that they may be ORed:
+ * \code
+ * if (present & KNotifyClient::Sound) { [Yes, sound is a default] }
+ * \endcode
+ * @param eventname the event name to check
+ * @return the presentation methods
+ */
+ KDECORE_EXPORT int getPresentation(const QString &eventname);
+
+ /**
+ * Gets the default file associated with a certain event name
+ * The control panel module will list all the event names
+ * This has the potential for being slow.
+ * @param eventname the name of the event
+ * @param present the presentation method
+ * @return the associated file. Can be QString::null if not found.
+ */
+ KDECORE_EXPORT QString getFile(const QString &eventname, int present);
+
+ /**
+ * Gets the default presentation for the event of this program.
+ * Remember that the Presentation may be ORed. Try this:
+ * \code
+ * if (present & KNotifyClient::Sound) { [Yes, sound is a default] }
+ * \endcode
+ * @return the presentation methods
+ */
+ KDECORE_EXPORT int getDefaultPresentation(const QString &eventname);
+
+ /**
+ * Gets the default File for the event of this program.
+ * It gets it in relation to present.
+ * Some events don't apply to this function ("Message Box")
+ * Some do (Sound)
+ * @param eventname the name of the event
+ * @param present the presentation method
+ * @return the default file. Can be QString::null if not found.
+ */
+ KDECORE_EXPORT QString getDefaultFile(const QString &eventname, int present);
+
+ /**
+ * Shortcut to KNotifyClient::Instance::current() :)
+ * @returns the current KInstance.
+ */
+ KDECORE_EXPORT KInstance * instance();
+}
+
+#endif
diff --git a/kdecore/kpalette.cpp b/kdecore/kpalette.cpp
new file mode 100644
index 000000000..293dc293e
--- /dev/null
+++ b/kdecore/kpalette.cpp
@@ -0,0 +1,237 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+//-----------------------------------------------------------------------------
+// KDE color palette
+
+#include "kpalette.h"
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <ksavefile.h>
+#include <kstringhandler.h>
+
+template class QPtrList<KPalette::kolor>;
+
+QStringList
+KPalette::getPaletteList()
+{
+ QStringList paletteList;
+ KGlobal::dirs()->findAllResources("config", "colors/*", false, true, paletteList);
+
+ int strip = strlen("colors/");
+ for(QStringList::Iterator it = paletteList.begin();
+ it != paletteList.end();
+ it++)
+ {
+ (*it) = (*it).mid(strip);
+ }
+
+ return paletteList;
+}
+
+KPalette::KPalette(const QString &name)
+ : mName(name)
+{
+ mKolorList.setAutoDelete(true);
+ if (mName.isEmpty()) return;
+
+ QString filename = locate("config", "colors/"+mName);
+ if (filename.isEmpty()) return;
+
+ QFile paletteFile(filename);
+ if (!paletteFile.exists()) return;
+ if (!paletteFile.open(IO_ReadOnly)) return;
+
+ uint maxLength = 1024;
+ QString line;
+
+ // Read first line
+ // Expected "GIMP Palette"
+ if (paletteFile.readLine(line, maxLength) == -1) return;
+ if (line.find(" Palette") == -1) return;
+
+ while( paletteFile.readLine(line, maxLength) != -1)
+ {
+ if (line[0] == '#')
+ {
+ // This is a comment line
+ line = line.mid(1); // Strip '#'
+ line = line.stripWhiteSpace(); // Strip remaining white space..
+ if (!line.isEmpty())
+ {
+ mDesc += line+"\n"; // Add comment to description
+ }
+ }
+ else
+ {
+ // This is a color line, hopefully
+ line = line.stripWhiteSpace();
+ if (line.isEmpty()) continue;
+ int red, green, blue;
+ int pos = 0;
+ if (sscanf(line.ascii(), "%d %d %d%n", &red, &green, &blue, &pos) >= 3)
+ {
+ if (red > 255) red = 255;
+ if (red < 0) red = 0;
+ if (green > 255) green = 255;
+ if (green < 0) green = 0;
+ if (blue > 255) blue = 255;
+ if (blue < 0) blue = 0;
+ kolor *node = new kolor();
+ node->color.setRgb(red, green, blue);
+ node->name = line.mid(pos).stripWhiteSpace();
+ if (node->name.isNull()) node->name = "";
+ mKolorList.append( node );
+ }
+ }
+ }
+}
+
+KPalette::KPalette(const KPalette &p)
+ : mName(p.mName), mDesc(p.mDesc), mEditable(p.mEditable)
+{
+ mKolorList.setAutoDelete(true);
+ // Make a deep copy of the color list
+ // We can't iterate a const list :(
+ // DF: yes you can - use the proper iterator, not first/next
+ QPtrList<kolor> *nonConstList = (QPtrList<kolor> *) &p.mKolorList;
+ for(kolor *node = nonConstList->first(); node; node = nonConstList->next())
+ {
+ mKolorList.append(new kolor(*node));
+ }
+}
+
+KPalette::~KPalette()
+{
+ // Need auto-save?
+}
+
+bool
+KPalette::save()
+{
+ QString filename = locateLocal("config", "colors/"+mName);
+ KSaveFile sf(filename);
+ if (sf.status() != 0) return false;
+
+ QTextStream *str = sf.textStream();
+
+ QString description = mDesc.stripWhiteSpace();
+ description = "#"+QStringList::split("\n", description, true).join("\n#");
+
+ (*str) << "KDE RGB Palette\n";
+ (*str) << description << "\n";
+ // We can't iterate a const list :(
+ // DF: yes you can - use the proper iterator, not first/next
+ QPtrList<kolor> *nonConstList = (QPtrList<kolor> *) (&mKolorList);
+ for(kolor *node = nonConstList->first(); node; node = nonConstList->next())
+ {
+ int r,g,b;
+ node->color.rgb(&r, &g, &b);
+ (*str) << r << " " << g << " " << b << " " << node->name << "\n";
+ }
+ return sf.close();
+}
+
+
+KPalette&
+KPalette::operator=( const KPalette &p)
+{
+ if (&p == this) return *this;
+ mKolorList.clear();
+ // Make a deep copy of the color list
+ // We can't iterate a const list :(
+ // DF: yes you can - use the proper iterator, not first/next
+ QPtrList<kolor> *nonConstList = (QPtrList<kolor> *) &p.mKolorList;
+ for(kolor *node = nonConstList->first(); node; node = nonConstList->next())
+ {
+ mKolorList.append(new kolor(*node));
+ }
+ mName = p.mName;
+ mDesc = p.mDesc;
+ mEditable = p.mEditable;
+ return *this;
+}
+
+QColor
+KPalette::color(int index)
+{
+ if ((index < 0) || (index >= nrColors()))
+ return QColor();
+
+ kolor *node = mKolorList.at(index);
+ if (!node)
+ return QColor();
+
+ return node->color;
+}
+
+int
+KPalette::findColor(const QColor &color) const
+{
+ int index;
+ QPtrListIterator<kolor> it( mKolorList );
+ for (index = 0; it.current(); ++it, ++index)
+ {
+ if (it.current()->color == color)
+ return index;
+ }
+ return -1;
+}
+
+QString
+KPalette::colorName(int index)
+{
+ if ((index < 0) || (index >= nrColors()))
+ return QString::null;
+
+ kolor *node = mKolorList.at(index);
+ if (!node)
+ return QString::null;
+
+ return node->name;
+}
+
+int
+KPalette::addColor(const QColor &newColor, const QString &newColorName)
+{
+ kolor *node = new kolor();
+ node->color = newColor;
+ node->name = newColorName;
+ mKolorList.append( node );
+ return nrColors()-1;
+}
+
+int
+KPalette::changeColor(int index,
+ const QColor &newColor,
+ const QString &newColorName)
+{
+ if ((index < 0) || (index >= nrColors()))
+ return -1;
+
+ kolor *node = mKolorList.at(index);
+ if (!node)
+ return -1;
+
+ node->color = newColor;
+ node->name = newColorName;
+ return index;
+}
diff --git a/kdecore/kpalette.h b/kdecore/kpalette.h
new file mode 100644
index 000000000..93103c33a
--- /dev/null
+++ b/kdecore/kpalette.h
@@ -0,0 +1,228 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version
+ 2 of the License.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+//-----------------------------------------------------------------------------
+// KDE color palette.
+
+#ifndef KDELIBS_KPALETTE_H
+#define KDELIBS_KPALETTE_H
+
+#include <qcolor.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include "kdelibs_export.h"
+
+class KPalettePrivate;
+
+/**
+ * Class for handling Palettes.
+ *
+ * This class makes it easy to handle palettes.
+ * A palette is a set of colors. This class can read
+ * and write palettes from and to a file.
+ *
+ * This class uses the "GIMP" palette file format.
+ *
+ * This class is totally unrelated to QPalette.
+ *
+ * @author Waldo Bastian (bastian@kde.org)
+ **/
+class KDECORE_EXPORT KPalette
+{
+public:
+ /**
+ * Query which KDE palettes are installed.
+ *
+ * @return A list with a palette names.
+ */
+ static QStringList getPaletteList();
+
+ /**
+ * KPalette constructor. Creates a KPalette from a file
+ * the filename is derived from the name.
+ * @param name The name of palette as returned by getPaletteList()
+ **/
+ KPalette(const QString &name=QString::null);
+
+ /**
+ * KPalette copy constructor.
+ **/
+ KPalette(const KPalette &);
+
+ /**
+ * KPalette destructor.
+ **/
+ virtual ~KPalette();
+
+ /**
+ * KPalette assignment operator
+ **/
+ KPalette& operator=( const KPalette &);
+
+ /**
+ * Save the palette
+ *
+ * @return 'true' if successful
+ **/
+ bool save();
+
+ /**
+ * Get the description of the palette.
+ * @return the description of the palette.
+ **/
+ QString description() const
+ { return mDesc; }
+
+ /**
+ * Set the description of the palette.
+ * @param desc the new description
+ **/
+ void setDescription(const QString &desc)
+ { mDesc = desc; }
+
+ /**
+ * Get the name of the palette.
+ * @return the name of the palette
+ **/
+ QString name() const
+ { return mName; }
+
+ /**
+ * Set the name of the palette.
+ * @param name the name of the palette
+ **/
+ void setName(const QString &name)
+ { mName = name; }
+
+ /**
+ * Used to specify whether a palette may be edited.
+ * @see editable()
+ * @see setEditable()
+ */
+ enum Editable { Yes, ///< Palette may be edited
+ No, ///< Palette may not be edited
+ Ask ///< Ask user before editing
+ };
+
+ /**
+ * Returns whether the palette may be edited.
+ * @return the state of the palette
+ **/
+ Editable editable() const
+ { return mEditable; }
+
+ /**
+ * Change whether the palette may be edited.
+ * @param editable the state of the palette
+ **/
+ void setEditable(Editable editable)
+ { mEditable = editable; }
+
+ /**
+ * Return the number of colors in the palette.
+ * @return the number of colors
+ **/
+ int nrColors() const
+ { return (int) mKolorList.count(); }
+
+ /**
+ * Find color by index.
+ * @param index the index of the desired color
+ * @return The @p index -th color of the palette, null if not found.
+ **/
+ QColor color(int index);
+
+ /**
+ * Find index by @p color.
+ * @param color the color to find
+ * @return The index of the color in the palette or -1 if the
+ * color is not found.
+ **/
+ int findColor(const QColor &color) const;
+
+ /**
+ * Find color name by @p index.
+ * @param index the index of the color
+ * @return The name of the @p index -th color.
+ * Note that not all palettes have named the colors. Null is
+ * returned if the color does not exist or has no name.
+ **/
+ QString colorName(int index);
+
+ /**
+ * Find color name by @p color.
+ * @return The name of color according to this palette.
+ * Note that not all palettes have named the colors.
+ * Note also that each palette can give the same color
+ * a different name.
+ **/
+ QString colorName(const QColor &color)
+ { return colorName( findColor(color)); }
+
+ /**
+ * Add a color.
+ * @param newColor The color to add.
+ * @param newColorName The name of the color, null to remove
+ * the name.
+ * @return The index of the added color.
+ **/
+ int addColor(const QColor &newColor,
+ const QString &newColorName = QString::null);
+
+ /**
+ * Change a color.
+ * @param index Index of the color to change
+ * @param newColor The new color.
+ * @param newColorName The new color name, null to remove
+ * the name.
+ * @return The index of the new color or -1 if the color couldn't
+ * be changed.
+ **/
+ int changeColor(int index,
+ const QColor &newColor,
+ const QString &newColorName = QString::null);
+
+ /**
+ * Change a color.
+ * @param oldColor The original color
+ * @param newColor The new color.
+ * @param newColorName The new color name, null to remove
+ * the name.
+ * @return The index of the new color or -1 if the color couldn't
+ * be changed.
+ **/
+ int changeColor(const QColor &oldColor,
+ const QColor &newColor,
+ const QString &newColorName = QString::null)
+ { return changeColor( findColor(oldColor), newColor, newColorName); }
+
+private:
+ typedef struct { QColor color; QString name; } kolor;
+ QPtrList<kolor> mKolorList;
+
+ QString mName;
+ QString mDesc;
+ Editable mEditable;
+
+ KPalettePrivate *d;
+};
+
+
+#endif // KDELIBS_KPALETTE_H
+
diff --git a/kdecore/kpixmapprovider.cpp b/kdecore/kpixmapprovider.cpp
new file mode 100644
index 000000000..1745e68f6
--- /dev/null
+++ b/kdecore/kpixmapprovider.cpp
@@ -0,0 +1,27 @@
+/* This file is part of the KDE libraries
+
+ Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License (LGPL) as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kpixmapprovider.h"
+
+KPixmapProvider::~KPixmapProvider() {}
+
+void KPixmapProvider::virtual_hook( int , void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
diff --git a/kdecore/kpixmapprovider.h b/kdecore/kpixmapprovider.h
new file mode 100644
index 000000000..fb7ac7d0a
--- /dev/null
+++ b/kdecore/kpixmapprovider.h
@@ -0,0 +1,55 @@
+/* This file is part of the KDE libraries
+
+ Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License (LGPL) as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KPIXMAPPROVIDER_H
+#define KPIXMAPPROVIDER_H
+
+#include <qpixmap.h>
+#include "kdelibs_export.h"
+
+/**
+ * A tiny abstract class with just one method:
+ * pixmapFor()
+ *
+ * It will be called whenever an icon is searched for @p text.
+ *
+ * Used e.g. by KHistoryCombo
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @short an abstract interface for looking up icons
+ */
+class KDECORE_EXPORT KPixmapProvider
+{
+public:
+ virtual ~KPixmapProvider();
+ /**
+ * You may subclass this and return a pixmap of size @p size for @p text.
+ * @param text the text that is associated with the pixmap
+ * @param size the size of the icon in pixels, 0 for defaylt size.
+ * See KIcon::StdSize.
+ * @return the pixmap for the arguments, or null if there is none
+ */
+ virtual QPixmap pixmapFor( const QString& text, int size = 0 ) = 0;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+
+#endif // KPIXMAPPROVIDER_H
diff --git a/kdecore/kprocctrl.cpp b/kdecore/kprocctrl.cpp
new file mode 100644
index 000000000..363d2d8ef
--- /dev/null
+++ b/kdecore/kprocctrl.cpp
@@ -0,0 +1,277 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kprocess.h"
+#include "kprocctrl.h"
+
+#include <config.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qsocketnotifier.h>
+
+KProcessController *KProcessController::theKProcessController;
+int KProcessController::refCount;
+
+void KProcessController::ref()
+{
+ if( !refCount ) {
+ theKProcessController = new KProcessController;
+ setupHandlers();
+ }
+ refCount++;
+}
+
+void KProcessController::deref()
+{
+ refCount--;
+ if( !refCount ) {
+ resetHandlers();
+ delete theKProcessController;
+ theKProcessController = 0;
+ }
+}
+
+KProcessController::KProcessController()
+ : needcheck( false )
+{
+ if( pipe( fd ) )
+ {
+ perror( "pipe" );
+ abort();
+ }
+
+ fcntl( fd[0], F_SETFL, O_NONBLOCK ); // in case slotDoHousekeeping is called without polling first
+ fcntl( fd[1], F_SETFL, O_NONBLOCK ); // in case it fills up
+ fcntl( fd[0], F_SETFD, FD_CLOEXEC );
+ fcntl( fd[1], F_SETFD, FD_CLOEXEC );
+
+ notifier = new QSocketNotifier( fd[0], QSocketNotifier::Read );
+ notifier->setEnabled( true );
+ QObject::connect( notifier, SIGNAL(activated(int)),
+ SLOT(slotDoHousekeeping()));
+}
+
+KProcessController::~KProcessController()
+{
+ delete notifier;
+
+ close( fd[0] );
+ close( fd[1] );
+}
+
+
+extern "C" {
+static void theReaper( int num )
+{
+ KProcessController::theSigCHLDHandler( num );
+}
+}
+
+#ifdef Q_OS_UNIX
+struct sigaction KProcessController::oldChildHandlerData;
+#endif
+bool KProcessController::handlerSet = false;
+
+void KProcessController::setupHandlers()
+{
+ if( handlerSet )
+ return;
+ handlerSet = true;
+
+#ifdef Q_OS_UNIX
+ struct sigaction act;
+ sigemptyset( &act.sa_mask );
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction( SIGPIPE, &act, 0L );
+
+ act.sa_handler = theReaper;
+ act.sa_flags = SA_NOCLDSTOP;
+ // CC: take care of SunOS which automatically restarts interrupted system
+ // calls (and thus does not have SA_RESTART)
+#ifdef SA_RESTART
+ act.sa_flags |= SA_RESTART;
+#endif
+ sigaction( SIGCHLD, &act, &oldChildHandlerData );
+
+ sigaddset( &act.sa_mask, SIGCHLD );
+ // Make sure we don't block this signal. gdb tends to do that :-(
+ sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
+#else
+ //TODO: win32
+#endif
+}
+
+void KProcessController::resetHandlers()
+{
+ if( !handlerSet )
+ return;
+ handlerSet = false;
+
+#ifdef Q_OS_UNIX
+ sigaction( SIGCHLD, &oldChildHandlerData, 0 );
+#else
+ //TODO: win32
+#endif
+ // there should be no problem with SIGPIPE staying SIG_IGN
+}
+
+// the pipe is needed to sync the child reaping with our event processing,
+// as otherwise there are race conditions, locking requirements, and things
+// generally get harder
+void KProcessController::theSigCHLDHandler( int arg )
+{
+ int saved_errno = errno;
+
+ char dummy = 0;
+ ::write( theKProcessController->fd[1], &dummy, 1 );
+
+#ifdef Q_OS_UNIX
+ if( oldChildHandlerData.sa_handler != SIG_IGN &&
+ oldChildHandlerData.sa_handler != SIG_DFL )
+ oldChildHandlerData.sa_handler( arg ); // call the old handler
+#else
+ //TODO: win32
+#endif
+
+ errno = saved_errno;
+}
+
+int KProcessController::notifierFd() const
+{
+ return fd[0];
+}
+
+void KProcessController::unscheduleCheck()
+{
+ char dummy[16]; // somewhat bigger - just in case several have queued up
+ if( ::read( fd[0], dummy, sizeof(dummy) ) > 0 )
+ needcheck = true;
+}
+
+void
+KProcessController::rescheduleCheck()
+{
+ if( needcheck )
+ {
+ needcheck = false;
+ char dummy = 0;
+ ::write( fd[1], &dummy, 1 );
+ }
+}
+
+void KProcessController::slotDoHousekeeping()
+{
+ char dummy[16]; // somewhat bigger - just in case several have queued up
+ ::read( fd[0], dummy, sizeof(dummy) );
+
+ int status;
+ again:
+ QValueListIterator<KProcess*> it( kProcessList.begin() );
+ QValueListIterator<KProcess*> eit( kProcessList.end() );
+ while( it != eit )
+ {
+ KProcess *prc = *it;
+ if( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 )
+ {
+ prc->processHasExited( status );
+ // the callback can nuke the whole process list and even 'this'
+ if (!theKProcessController)
+ return;
+ goto again;
+ }
+ ++it;
+ }
+ QValueListIterator<int> uit( unixProcessList.begin() );
+ QValueListIterator<int> ueit( unixProcessList.end() );
+ while( uit != ueit )
+ {
+ if( waitpid( *uit, 0, WNOHANG ) > 0 )
+ {
+ uit = unixProcessList.remove( uit );
+ deref(); // counterpart to addProcess, can invalidate 'this'
+ } else
+ ++uit;
+ }
+}
+
+bool KProcessController::waitForProcessExit( int timeout )
+{
+#ifdef Q_OS_UNIX
+ for(;;)
+ {
+ struct timeval tv, *tvp;
+ if (timeout < 0)
+ tvp = 0;
+ else
+ {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+
+ fd_set fds;
+ FD_ZERO( &fds );
+ FD_SET( fd[0], &fds );
+
+ switch( select( fd[0]+1, &fds, 0, 0, tvp ) )
+ {
+ case -1:
+ if( errno == EINTR )
+ continue;
+ // fall through; should never happen
+ case 0:
+ return false;
+ default:
+ slotDoHousekeeping();
+ return true;
+ }
+ }
+#else
+ //TODO: win32
+ return false;
+#endif
+}
+
+void KProcessController::addKProcess( KProcess* p )
+{
+ kProcessList.append( p );
+}
+
+void KProcessController::removeKProcess( KProcess* p )
+{
+ kProcessList.remove( p );
+}
+
+void KProcessController::addProcess( int pid )
+{
+ unixProcessList.append( pid );
+ ref(); // make sure we stay around when the KProcess goes away
+}
+
+#include "kprocctrl.moc"
diff --git a/kdecore/kprocctrl.h b/kdecore/kprocctrl.h
new file mode 100644
index 000000000..104c8d9e5
--- /dev/null
+++ b/kdecore/kprocctrl.h
@@ -0,0 +1,150 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KPROCCTRL_H__
+#define __KPROCCTRL_H__
+
+#include <qvaluelist.h>
+
+#include "kprocess.h"
+
+class QSocketNotifier;
+
+/**
+ * @short Used internally by KProcess
+ * @internal
+ * @author Christian Czezatke <e9025461@student.tuwien.ac.at>
+ *
+ * A class for internal use by KProcess only. -- Exactly one instance
+ * of this class is created by KApplication.
+ *
+ * This class takes care of the actual (UN*X) signal handling.
+ */
+class KDECORE_EXPORT KProcessController : public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Create an instance if none exists yet.
+ * Called by KApplication::KApplication()
+ */
+ static void ref();
+
+ /**
+ * Destroy the instance if one exists and it is not referenced any more.
+ * Called by KApplication::~KApplication()
+ */
+ static void deref();
+
+ /**
+ * Only a single instance of this class is allowed at a time,
+ * and this static variable is used to track the one instance.
+ */
+ static KProcessController *theKProcessController; // kde4: rename: instance
+
+ /**
+ * Automatically called upon SIGCHLD. Never call it directly.
+ * If your application (or some library it uses) redirects SIGCHLD,
+ * the new signal handler (and only it) should call the old handler
+ * returned by sigaction().
+ * @internal
+ */
+ static void theSigCHLDHandler(int signal); // KDE4: private
+
+ /**
+ * Wait for any process to exit and handle their exit without
+ * starting an event loop.
+ * This function may cause KProcess to emit any of its signals.
+ *
+ * @param timeout the timeout in seconds. -1 means no timeout.
+ * @return true if a process exited, false
+ * if no process exited within @p timeout seconds.
+ * @since 3.1
+ */
+ bool waitForProcessExit(int timeout);
+
+ /**
+ * Call this function to defer processing of the data that became available
+ * on notifierFd().
+ * @since 3.2
+ */
+ void unscheduleCheck();
+
+ /**
+ * This function @em must be called at some point after calling
+ * unscheduleCheck().
+ * @since 3.2
+ */
+ void rescheduleCheck();
+
+ /*
+ * Obtain the file descriptor KProcessController uses to get notified
+ * about process exits. select() or poll() on it if you create a custom
+ * event loop that needs to act upon SIGCHLD.
+ * @return the file descriptor of the reading end of the notification pipe
+ * @since 3.2
+ */
+ int notifierFd() const;
+
+ /**
+ * @internal
+ */
+ void addKProcess( KProcess* );
+ /**
+ * @internal
+ */
+ void removeKProcess( KProcess* );
+ /**
+ * @internal
+ */
+ void addProcess( int pid );
+
+private slots:
+ void slotDoHousekeeping();
+
+private:
+ friend class I_just_love_gcc;
+
+ int fd[2];
+ bool needcheck;
+ QSocketNotifier *notifier;
+ QValueList<KProcess*> kProcessList;
+ QValueList<int> unixProcessList;
+
+ static void setupHandlers();
+ static void resetHandlers();
+ static struct sigaction oldChildHandlerData;
+ static bool handlerSet;
+
+ static int refCount;
+
+ // Disallow instantiation
+ KProcessController();
+ ~KProcessController();
+
+ // Disallow assignment and copy-construction
+ KProcessController( const KProcessController& );
+ KProcessController& operator= ( const KProcessController& );
+};
+
+
+
+#endif
+
diff --git a/kdecore/kprocess.cpp b/kdecore/kprocess.cpp
new file mode 100644
index 000000000..286790bcb
--- /dev/null
+++ b/kdecore/kprocess.cpp
@@ -0,0 +1,1137 @@
+/*
+
+ $Id$
+
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include "kprocess.h"
+#include "kprocctrl.h"
+#include "kpty.h"
+
+#include <config.h>
+
+#ifdef __sgi
+#define __svr4__
+#endif
+
+#ifdef __osf__
+#define _OSF_SOURCE
+#include <float.h>
+#endif
+
+#ifdef _AIX
+#define _ALL_SOURCE
+#endif
+
+#ifdef Q_OS_UNIX
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_SYS_STROPTS_H
+#include <sys/stropts.h> // Defines I_PUSH
+#define _NEW_TTY_CTRL
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <qfile.h>
+#include <qsocketnotifier.h>
+#include <qapplication.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kuser.h>
+
+
+//////////////////
+// private data //
+//////////////////
+
+class KProcessPrivate {
+public:
+ KProcessPrivate() :
+ usePty(KProcess::NoCommunication),
+ addUtmp(false), useShell(false),
+#ifdef Q_OS_UNIX
+ pty(0),
+#endif
+ priority(0)
+ {
+ }
+
+ KProcess::Communication usePty;
+ bool addUtmp : 1;
+ bool useShell : 1;
+
+#ifdef Q_OS_UNIX
+ KPty *pty;
+#endif
+
+ int priority;
+
+ QMap<QString,QString> env;
+ QString wd;
+ QCString shell;
+ QCString executable;
+};
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KProcess::KProcess( QObject* parent, const char *name )
+ : QObject( parent, name ),
+ run_mode(NotifyOnExit),
+ runs(false),
+ pid_(0),
+ status(0),
+ keepPrivs(false),
+ innot(0),
+ outnot(0),
+ errnot(0),
+ communication(NoCommunication),
+ input_data(0),
+ input_sent(0),
+ input_total(0)
+{
+ KProcessController::ref();
+ KProcessController::theKProcessController->addKProcess(this);
+
+ d = new KProcessPrivate;
+
+ out[0] = out[1] = -1;
+ in[0] = in[1] = -1;
+ err[0] = err[1] = -1;
+}
+
+KProcess::KProcess()
+ : QObject(),
+ run_mode(NotifyOnExit),
+ runs(false),
+ pid_(0),
+ status(0),
+ keepPrivs(false),
+ innot(0),
+ outnot(0),
+ errnot(0),
+ communication(NoCommunication),
+ input_data(0),
+ input_sent(0),
+ input_total(0)
+{
+ KProcessController::ref();
+ KProcessController::theKProcessController->addKProcess(this);
+
+ d = new KProcessPrivate;
+
+ out[0] = out[1] = -1;
+ in[0] = in[1] = -1;
+ err[0] = err[1] = -1;
+}
+
+void
+KProcess::setEnvironment(const QString &name, const QString &value)
+{
+ d->env.insert(name, value);
+}
+
+void
+KProcess::setWorkingDirectory(const QString &dir)
+{
+ d->wd = dir;
+}
+
+void
+KProcess::setupEnvironment()
+{
+ QMap<QString,QString>::Iterator it;
+ for(it = d->env.begin(); it != d->env.end(); ++it)
+ {
+ setenv(QFile::encodeName(it.key()).data(),
+ QFile::encodeName(it.data()).data(), 1);
+ }
+ if (!d->wd.isEmpty())
+ {
+ chdir(QFile::encodeName(d->wd).data());
+ }
+}
+
+void
+KProcess::setRunPrivileged(bool keepPrivileges)
+{
+ keepPrivs = keepPrivileges;
+}
+
+bool
+KProcess::runPrivileged() const
+{
+ return keepPrivs;
+}
+
+bool
+KProcess::setPriority(int prio)
+{
+#ifdef Q_OS_UNIX
+ if (runs) {
+ if (setpriority(PRIO_PROCESS, pid_, prio))
+ return false;
+ } else {
+ if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
+ return false;
+ }
+#endif
+ d->priority = prio;
+ return true;
+}
+
+KProcess::~KProcess()
+{
+ if (run_mode != DontCare)
+ kill(SIGKILL);
+ detach();
+
+#ifdef Q_OS_UNIX
+ delete d->pty;
+#endif
+ delete d;
+
+ KProcessController::theKProcessController->removeKProcess(this);
+ KProcessController::deref();
+}
+
+void KProcess::detach()
+{
+ if (runs) {
+ KProcessController::theKProcessController->addProcess(pid_);
+ runs = false;
+ pid_ = 0; // close without draining
+ commClose(); // Clean up open fd's and socket notifiers.
+ }
+}
+
+void KProcess::setBinaryExecutable(const char *filename)
+{
+ d->executable = filename;
+}
+
+bool KProcess::setExecutable(const QString& proc)
+{
+ if (runs) return false;
+
+ if (proc.isEmpty()) return false;
+
+ if (!arguments.isEmpty())
+ arguments.remove(arguments.begin());
+ arguments.prepend(QFile::encodeName(proc));
+
+ return true;
+}
+
+KProcess &KProcess::operator<<(const QStringList& args)
+{
+ QStringList::ConstIterator it = args.begin();
+ for ( ; it != args.end() ; ++it )
+ arguments.append(QFile::encodeName(*it));
+ return *this;
+}
+
+KProcess &KProcess::operator<<(const QCString& arg)
+{
+ return operator<< (arg.data());
+}
+
+KProcess &KProcess::operator<<(const char* arg)
+{
+ arguments.append(arg);
+ return *this;
+}
+
+KProcess &KProcess::operator<<(const QString& arg)
+{
+ arguments.append(QFile::encodeName(arg));
+ return *this;
+}
+
+void KProcess::clearArguments()
+{
+ arguments.clear();
+}
+
+bool KProcess::start(RunMode runmode, Communication comm)
+{
+ if (runs) {
+ kdDebug(175) << "Attempted to start an already running process" << endl;
+ return false;
+ }
+
+ uint n = arguments.count();
+ if (n == 0) {
+ kdDebug(175) << "Attempted to start a process without arguments" << endl;
+ return false;
+ }
+#ifdef Q_OS_UNIX
+ char **arglist;
+ QCString shellCmd;
+ if (d->useShell)
+ {
+ if (d->shell.isEmpty()) {
+ kdDebug(175) << "Invalid shell specified" << endl;
+ return false;
+ }
+
+ for (uint i = 0; i < n; i++) {
+ shellCmd += arguments[i];
+ shellCmd += " "; // CC: to separate the arguments
+ }
+
+ arglist = static_cast<char **>(malloc( 4 * sizeof(char *)));
+ arglist[0] = d->shell.data();
+ arglist[1] = (char *) "-c";
+ arglist[2] = shellCmd.data();
+ arglist[3] = 0;
+ }
+ else
+ {
+ arglist = static_cast<char **>(malloc( (n + 1) * sizeof(char *)));
+ for (uint i = 0; i < n; i++)
+ arglist[i] = arguments[i].data();
+ arglist[n] = 0;
+ }
+
+ run_mode = runmode;
+
+ if (!setupCommunication(comm))
+ {
+ kdDebug(175) << "Could not setup Communication!" << endl;
+ free(arglist);
+ return false;
+ }
+
+ // We do this in the parent because if we do it in the child process
+ // gdb gets confused when the application runs from gdb.
+#ifdef HAVE_INITGROUPS
+ struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
+#endif
+
+ int fd[2];
+ if (pipe(fd))
+ fd[0] = fd[1] = -1; // Pipe failed.. continue
+
+ // we don't use vfork() because
+ // - it has unclear semantics and is not standardized
+ // - we do way too much magic in the child
+ pid_ = fork();
+ if (pid_ == 0) {
+ // The child process
+
+ close(fd[0]);
+ // Closing of fd[1] indicates that the execvp() succeeded!
+ fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+
+ if (!commSetupDoneC())
+ kdDebug(175) << "Could not finish comm setup in child!" << endl;
+
+ // reset all signal handlers
+ struct sigaction act;
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ for (int sig = 1; sig < NSIG; sig++)
+ sigaction(sig, &act, 0L);
+
+ if (d->priority)
+ setpriority(PRIO_PROCESS, 0, d->priority);
+
+ if (!runPrivileged())
+ {
+ setgid(getgid());
+#ifdef HAVE_INITGROUPS
+ if (pw)
+ initgroups(pw->pw_name, pw->pw_gid);
+#endif
+ if (geteuid() != getuid())
+ setuid(getuid());
+ if (geteuid() != getuid())
+ _exit(1);
+ }
+
+ setupEnvironment();
+
+ if (runmode == DontCare || runmode == OwnGroup)
+ setsid();
+
+ const char *executable = arglist[0];
+ if (!d->executable.isEmpty())
+ executable = d->executable.data();
+ execvp(executable, arglist);
+
+ char resultByte = 1;
+ write(fd[1], &resultByte, 1);
+ _exit(-1);
+ } else if (pid_ == -1) {
+ // forking failed
+
+ // commAbort();
+ pid_ = 0;
+ free(arglist);
+ return false;
+ }
+ // the parent continues here
+ free(arglist);
+
+ if (!commSetupDoneP())
+ kdDebug(175) << "Could not finish comm setup in parent!" << endl;
+
+ // Check whether client could be started.
+ close(fd[1]);
+ for(;;)
+ {
+ char resultByte;
+ int n = ::read(fd[0], &resultByte, 1);
+ if (n == 1)
+ {
+ // exec() failed
+ close(fd[0]);
+ waitpid(pid_, 0, 0);
+ pid_ = 0;
+ commClose();
+ return false;
+ }
+ if (n == -1)
+ {
+ if (errno == EINTR)
+ continue; // Ignore
+ }
+ break; // success
+ }
+ close(fd[0]);
+
+ runs = true;
+ switch (runmode)
+ {
+ case Block:
+ for (;;)
+ {
+ commClose(); // drain only, unless obsolete reimplementation
+ if (!runs)
+ {
+ // commClose detected data on the process exit notifification pipe
+ KProcessController::theKProcessController->unscheduleCheck();
+ if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
+ {
+ commClose(); // this time for real (runs is false)
+ KProcessController::theKProcessController->rescheduleCheck();
+ break;
+ }
+ runs = true; // for next commClose() iteration
+ }
+ else
+ {
+ // commClose is an obsolete reimplementation and waited until
+ // all output channels were closed (or it was interrupted).
+ // there is a chance that it never gets here ...
+ waitpid(pid_, &status, 0);
+ runs = false;
+ break;
+ }
+ }
+ // why do we do this? i think this signal should be emitted _only_
+ // after the process has successfully run _asynchronously_ --ossi
+ emit processExited(this);
+ break;
+ default: // NotifyOnExit & OwnGroup
+ input_data = 0; // Discard any data for stdin that might still be there
+ break;
+ }
+ return true;
+#else
+ //TODO
+ return false;
+#endif
+}
+
+
+
+bool KProcess::kill(int signo)
+{
+#ifdef Q_OS_UNIX
+ if (runs && pid_ > 0 && !::kill(run_mode == OwnGroup ? -pid_ : pid_, signo))
+ return true;
+#endif
+ return false;
+}
+
+
+
+bool KProcess::isRunning() const
+{
+ return runs;
+}
+
+
+
+pid_t KProcess::pid() const
+{
+ return pid_;
+}
+
+#ifndef timersub
+# define timersub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
+
+bool KProcess::wait(int timeout)
+{
+ if (!runs)
+ return true;
+
+#ifndef __linux__
+ struct timeval etv;
+#endif
+ struct timeval tv, *tvp;
+ if (timeout < 0)
+ tvp = 0;
+ else
+ {
+#ifndef __linux__
+ gettimeofday(&etv, 0);
+ etv.tv_sec += timeout;
+#else
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+#endif
+ tvp = &tv;
+ }
+
+#ifdef Q_OS_UNIX
+ int fd = KProcessController::theKProcessController->notifierFd();
+ for(;;)
+ {
+ fd_set fds;
+ FD_ZERO( &fds );
+ FD_SET( fd, &fds );
+
+#ifndef __linux__
+ if (tvp)
+ {
+ gettimeofday(&tv, 0);
+ timersub(&etv, &tv, &tv);
+ if (tv.tv_sec < 0)
+ tv.tv_sec = tv.tv_usec = 0;
+ }
+#endif
+
+ switch( select( fd+1, &fds, 0, 0, tvp ) )
+ {
+ case -1:
+ if( errno == EINTR )
+ break;
+ // fall through; should happen if tvp->tv_sec < 0
+ case 0:
+ KProcessController::theKProcessController->rescheduleCheck();
+ return false;
+ default:
+ KProcessController::theKProcessController->unscheduleCheck();
+ if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
+ {
+ processHasExited(status);
+ KProcessController::theKProcessController->rescheduleCheck();
+ return true;
+ }
+ }
+ }
+#endif //Q_OS_UNIX
+ return false;
+}
+
+
+
+bool KProcess::normalExit() const
+{
+ return (pid_ != 0) && !runs && WIFEXITED(status);
+}
+
+
+bool KProcess::signalled() const
+{
+ return (pid_ != 0) && !runs && WIFSIGNALED(status);
+}
+
+
+bool KProcess::coreDumped() const
+{
+#ifdef WCOREDUMP
+ return signalled() && WCOREDUMP(status);
+#else
+ return false;
+#endif
+}
+
+
+int KProcess::exitStatus() const
+{
+ return WEXITSTATUS(status);
+}
+
+
+int KProcess::exitSignal() const
+{
+ return WTERMSIG(status);
+}
+
+
+bool KProcess::writeStdin(const char *buffer, int buflen)
+{
+ // if there is still data pending, writing new data
+ // to stdout is not allowed (since it could also confuse
+ // kprocess ...)
+ if (input_data != 0)
+ return false;
+
+ if (communication & Stdin) {
+ input_data = buffer;
+ input_sent = 0;
+ input_total = buflen;
+ innot->setEnabled(true);
+ if (input_total)
+ slotSendData(0);
+ return true;
+ } else
+ return false;
+}
+
+void KProcess::suspend()
+{
+ if (outnot)
+ outnot->setEnabled(false);
+}
+
+void KProcess::resume()
+{
+ if (outnot)
+ outnot->setEnabled(true);
+}
+
+bool KProcess::closeStdin()
+{
+ if (communication & Stdin) {
+ communication = (Communication) (communication & ~Stdin);
+ delete innot;
+ innot = 0;
+ if (!(d->usePty & Stdin))
+ close(in[1]);
+ in[1] = -1;
+ return true;
+ } else
+ return false;
+}
+
+bool KProcess::closeStdout()
+{
+ if (communication & Stdout) {
+ communication = (Communication) (communication & ~Stdout);
+ delete outnot;
+ outnot = 0;
+ if (!(d->usePty & Stdout))
+ close(out[0]);
+ out[0] = -1;
+ return true;
+ } else
+ return false;
+}
+
+bool KProcess::closeStderr()
+{
+ if (communication & Stderr) {
+ communication = (Communication) (communication & ~Stderr);
+ delete errnot;
+ errnot = 0;
+ if (!(d->usePty & Stderr))
+ close(err[0]);
+ err[0] = -1;
+ return true;
+ } else
+ return false;
+}
+
+bool KProcess::closePty()
+{
+#ifdef Q_OS_UNIX
+ if (d->pty && d->pty->masterFd() >= 0) {
+ if (d->addUtmp)
+ d->pty->logout();
+ d->pty->close();
+ return true;
+ } else
+ return false;
+#else
+ return false;
+#endif
+}
+
+void KProcess::closeAll()
+{
+ closeStdin();
+ closeStdout();
+ closeStderr();
+ closePty();
+}
+
+/////////////////////////////
+// protected slots //
+/////////////////////////////
+
+
+
+void KProcess::slotChildOutput(int fdno)
+{
+ if (!childOutput(fdno))
+ closeStdout();
+}
+
+
+void KProcess::slotChildError(int fdno)
+{
+ if (!childError(fdno))
+ closeStderr();
+}
+
+
+void KProcess::slotSendData(int)
+{
+ if (input_sent == input_total) {
+ innot->setEnabled(false);
+ input_data = 0;
+ emit wroteStdin(this);
+ } else {
+ int result = ::write(in[1], input_data+input_sent, input_total-input_sent);
+ if (result >= 0)
+ {
+ input_sent += result;
+ }
+ else if ((errno != EAGAIN) && (errno != EINTR))
+ {
+ kdDebug(175) << "Error writing to stdin of child process" << endl;
+ closeStdin();
+ }
+ }
+}
+
+void KProcess::setUseShell(bool useShell, const char *shell)
+{
+ d->useShell = useShell;
+ if (shell && *shell)
+ d->shell = shell;
+ else
+// #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
+ // Solaris POSIX ...
+ if (!access( "/usr/xpg4/bin/sh", X_OK ))
+ d->shell = "/usr/xpg4/bin/sh";
+ else
+ // ... which links here anyway
+ if (!access( "/bin/ksh", X_OK ))
+ d->shell = "/bin/ksh";
+ else
+ // dunno, maybe superfluous?
+ if (!access( "/usr/ucb/sh", X_OK ))
+ d->shell = "/usr/ucb/sh";
+ else
+#endif
+ d->shell = "/bin/sh";
+}
+
+#ifdef Q_OS_UNIX
+void KProcess::setUsePty(Communication usePty, bool addUtmp)
+{
+ d->usePty = usePty;
+ d->addUtmp = addUtmp;
+ if (usePty) {
+ if (!d->pty)
+ d->pty = new KPty;
+ } else {
+ delete d->pty;
+ d->pty = 0;
+ }
+}
+
+KPty *KProcess::pty() const
+{
+ return d->pty;
+}
+#endif //Q_OS_UNIX
+
+QString KProcess::quote(const QString &arg)
+{
+ QChar q('\'');
+ return QString(arg).replace(q, "'\\''").prepend(q).append(q);
+}
+
+
+//////////////////////////////
+// private member functions //
+//////////////////////////////
+
+
+void KProcess::processHasExited(int state)
+{
+ // only successfully run NotifyOnExit processes ever get here
+
+ status = state;
+ runs = false; // do this before commClose, so it knows we're dead
+
+ commClose(); // cleanup communication sockets
+
+ if (run_mode != DontCare)
+ emit processExited(this);
+}
+
+
+
+int KProcess::childOutput(int fdno)
+{
+ if (communication & NoRead) {
+ int len = -1;
+ emit receivedStdout(fdno, len);
+ errno = 0; // Make sure errno doesn't read "EAGAIN"
+ return len;
+ }
+ else
+ {
+ char buffer[1025];
+ int len;
+
+ len = ::read(fdno, buffer, 1024);
+
+ if (len > 0) {
+ buffer[len] = 0; // Just in case.
+ emit receivedStdout(this, buffer, len);
+ }
+ return len;
+ }
+}
+
+int KProcess::childError(int fdno)
+{
+ char buffer[1025];
+ int len;
+
+ len = ::read(fdno, buffer, 1024);
+
+ if (len > 0) {
+ buffer[len] = 0; // Just in case.
+ emit receivedStderr(this, buffer, len);
+ }
+ return len;
+}
+
+
+int KProcess::setupCommunication(Communication comm)
+{
+#ifdef Q_OS_UNIX
+ // PTY stuff //
+ if (d->usePty)
+ {
+ // cannot communicate on both stderr and stdout if they are both on the pty
+ if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
+ kdWarning(175) << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl;
+ return 0;
+ }
+ if (!d->pty->open())
+ return 0;
+
+ int rcomm = comm & d->usePty;
+ int mfd = d->pty->masterFd();
+ if (rcomm & Stdin)
+ in[1] = mfd;
+ if (rcomm & Stdout)
+ out[0] = mfd;
+ if (rcomm & Stderr)
+ err[0] = mfd;
+ }
+
+ communication = comm;
+
+ comm = (Communication) (comm & ~d->usePty);
+ if (comm & Stdin) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, in))
+ goto fail0;
+ fcntl(in[0], F_SETFD, FD_CLOEXEC);
+ fcntl(in[1], F_SETFD, FD_CLOEXEC);
+ }
+ if (comm & Stdout) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, out))
+ goto fail1;
+ fcntl(out[0], F_SETFD, FD_CLOEXEC);
+ fcntl(out[1], F_SETFD, FD_CLOEXEC);
+ }
+ if (comm & Stderr) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, err))
+ goto fail2;
+ fcntl(err[0], F_SETFD, FD_CLOEXEC);
+ fcntl(err[1], F_SETFD, FD_CLOEXEC);
+ }
+ return 1; // Ok
+ fail2:
+ if (comm & Stdout)
+ {
+ close(out[0]);
+ close(out[1]);
+ out[0] = out[1] = -1;
+ }
+ fail1:
+ if (comm & Stdin)
+ {
+ close(in[0]);
+ close(in[1]);
+ in[0] = in[1] = -1;
+ }
+ fail0:
+ communication = NoCommunication;
+#endif //Q_OS_UNIX
+ return 0; // Error
+}
+
+
+
+int KProcess::commSetupDoneP()
+{
+ int rcomm = communication & ~d->usePty;
+ if (rcomm & Stdin)
+ close(in[0]);
+ if (rcomm & Stdout)
+ close(out[1]);
+ if (rcomm & Stderr)
+ close(err[1]);
+ in[0] = out[1] = err[1] = -1;
+
+ // Don't create socket notifiers if no interactive comm is to be expected
+ if (run_mode != NotifyOnExit && run_mode != OwnGroup)
+ return 1;
+
+ if (communication & Stdin) {
+ fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL));
+ innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this);
+ Q_CHECK_PTR(innot);
+ innot->setEnabled(false); // will be enabled when data has to be sent
+ QObject::connect(innot, SIGNAL(activated(int)),
+ this, SLOT(slotSendData(int)));
+ }
+
+ if (communication & Stdout) {
+ outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
+ Q_CHECK_PTR(outnot);
+ QObject::connect(outnot, SIGNAL(activated(int)),
+ this, SLOT(slotChildOutput(int)));
+ if (communication & NoRead)
+ suspend();
+ }
+
+ if (communication & Stderr) {
+ errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
+ Q_CHECK_PTR(errnot);
+ QObject::connect(errnot, SIGNAL(activated(int)),
+ this, SLOT(slotChildError(int)));
+ }
+
+ return 1;
+}
+
+
+
+int KProcess::commSetupDoneC()
+{
+ int ok = 1;
+#ifdef Q_OS_UNIX
+
+ if (d->usePty & Stdin) {
+ if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
+ } else if (communication & Stdin) {
+ if (dup2(in[0], STDIN_FILENO) < 0) ok = 0;
+ } else {
+ int null_fd = open( "/dev/null", O_RDONLY );
+ if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
+ close( null_fd );
+ }
+ struct linger so;
+ memset(&so, 0, sizeof(so));
+ if (d->usePty & Stdout) {
+ if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
+ } else if (communication & Stdout) {
+ if (dup2(out[1], STDOUT_FILENO) < 0 ||
+ setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
+ ok = 0;
+ if (communication & MergedStderr) {
+ if (dup2(out[1], STDERR_FILENO) < 0)
+ ok = 0;
+ }
+ }
+ if (d->usePty & Stderr) {
+ if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
+ } else if (communication & Stderr) {
+ if (dup2(err[1], STDERR_FILENO) < 0 ||
+ setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
+ ok = 0;
+ }
+
+ // don't even think about closing all open fds here or anywhere else
+
+ // PTY stuff //
+ if (d->usePty) {
+ d->pty->setCTty();
+ if (d->addUtmp)
+ d->pty->login(KUser(KUser::UseRealUserID).loginName().local8Bit().data(), getenv("DISPLAY"));
+ }
+#endif //Q_OS_UNIX
+
+ return ok;
+}
+
+
+
+void KProcess::commClose()
+{
+ closeStdin();
+
+#ifdef Q_OS_UNIX
+ if (pid_) { // detached, failed, and killed processes have no output. basta. :)
+ // If both channels are being read we need to make sure that one socket
+ // buffer doesn't fill up whilst we are waiting for data on the other
+ // (causing a deadlock). Hence we need to use select.
+
+ int notfd = KProcessController::theKProcessController->notifierFd();
+
+ while ((communication & (Stdout | Stderr)) || runs) {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ struct timeval timeout, *p_timeout;
+
+ int max_fd = 0;
+ if (communication & Stdout) {
+ FD_SET(out[0], &rfds);
+ max_fd = out[0];
+ }
+ if (communication & Stderr) {
+ FD_SET(err[0], &rfds);
+ if (err[0] > max_fd)
+ max_fd = err[0];
+ }
+ if (runs) {
+ FD_SET(notfd, &rfds);
+ if (notfd > max_fd)
+ max_fd = notfd;
+ // If the process is still running we block until we
+ // receive data or the process exits.
+ p_timeout = 0; // no timeout
+ } else {
+ // If the process has already exited, we only check
+ // the available data, we don't wait for more.
+ timeout.tv_sec = timeout.tv_usec = 0; // timeout immediately
+ p_timeout = &timeout;
+ }
+
+ int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
+ if (fds_ready < 0) {
+ if (errno == EINTR)
+ continue;
+ break;
+ } else if (!fds_ready)
+ break;
+
+ if ((communication & Stdout) && FD_ISSET(out[0], &rfds))
+ slotChildOutput(out[0]);
+
+ if ((communication & Stderr) && FD_ISSET(err[0], &rfds))
+ slotChildError(err[0]);
+
+ if (runs && FD_ISSET(notfd, &rfds)) {
+ runs = false; // hack: signal potential exit
+ return; // don't close anything, we will be called again
+ }
+ }
+ }
+#endif //Q_OS_UNIX
+
+ closeStdout();
+ closeStderr();
+
+ closePty();
+}
+
+
+void KProcess::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+
+///////////////////////////
+// CC: Class KShellProcess
+///////////////////////////
+
+KShellProcess::KShellProcess(const char *shellname):
+ KProcess()
+{
+ setUseShell( true, shellname ? shellname : getenv("SHELL") );
+}
+
+KShellProcess::~KShellProcess() {
+}
+
+QString KShellProcess::quote(const QString &arg)
+{
+ return KProcess::quote(arg);
+}
+
+bool KShellProcess::start(RunMode runmode, Communication comm)
+{
+ return KProcess::start(runmode, comm);
+}
+
+void KShellProcess::virtual_hook( int id, void* data )
+{ KProcess::virtual_hook( id, data ); }
+
+#include "kprocess.moc"
diff --git a/kdecore/kprocess.h b/kdecore/kprocess.h
new file mode 100644
index 000000000..4b3e88cd4
--- /dev/null
+++ b/kdecore/kprocess.h
@@ -0,0 +1,934 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kprocess_h__
+#define __kprocess_h__
+
+#include <sys/types.h> // for pid_t
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <qvaluelist.h>
+#include <qcstring.h>
+#include <qobject.h>
+#include "kdelibs_export.h"
+
+class QSocketNotifier;
+class KProcessPrivate;
+class KPty;
+
+/**
+ * Child process invocation, monitoring and control.
+ * This class works only in the application's main thread.
+ *
+ * <b>General usage and features:</b>\n
+ *
+ * This class allows a KDE application to start child processes without having
+ * to worry about UN*X signal handling issues and zombie process reaping.
+ *
+ * @see KProcIO
+ *
+ * Basically, this class distinguishes three different ways of running
+ * child processes:
+ *
+ * @li DontCare -- The child process is invoked and both the child
+ * process and the parent process continue concurrently.
+ *
+ * The process is started in an own session (see setsid(2)).
+ *
+ * @li NotifyOnExit -- The child process is invoked and both the
+ * child and the parent process run concurrently.
+ *
+ * When the child process exits, the KProcess instance
+ * corresponding to it emits the Qt signal processExited().
+ * Since this signal is @em not emitted from within a UN*X
+ * signal handler, arbitrary function calls can be made.
+ *
+ * Be aware: When the KProcess object gets destructed, the child
+ * process will be killed if it is still running!
+ * This means in particular, that it usually makes no sense to use
+ * a KProcess on the stack with NotifyOnExit.
+ *
+ * @li OwnGroup -- like NotifyOnExit, but the child process is started
+ * in an own process group (and an own session, FWIW). The behavior of
+ * kill() changes to killing the whole process group - this makes
+ * this mode useful for implementing primitive job management. It can be
+ * used to work around broken wrapper scripts that don't propagate signals
+ * to the "real" program. However, use this with care, as you disturb the
+ * shell's job management if your program is started from the command line.
+ *
+ * @li Block -- The child process starts and the parent process
+ * is suspended until the child process exits. (@em Really not recommended
+ * for programs with a GUI.)
+ * In this mode the parent can read the child's output, but can't send it any
+ * input.
+ *
+ * KProcess also provides several functions for determining the exit status
+ * and the pid of the child process it represents.
+ *
+ * Furthermore it is possible to supply command-line arguments to the process
+ * in a clean fashion (no null-terminated stringlists and such...)
+ *
+ * A small usage example:
+ * \code
+ * KProcess *proc = new KProcess;
+ *
+ * *proc << "my_executable";
+ * *proc << "These" << "are" << "the" << "command" << "line" << "args";
+ * QApplication::connect(proc, SIGNAL(processExited(KProcess *)),
+ * pointer_to_my_object, SLOT(my_objects_slot(KProcess *)));
+ * proc->start();
+ * \endcode
+ *
+ * This will start "my_executable" with the commandline arguments "These"...
+ *
+ * When the child process exits, the slot will be invoked.
+ *
+ * <b>Communication with the child process:</b>\n
+ *
+ * KProcess supports communication with the child process through
+ * stdin/stdout/stderr.
+ *
+ * The following functions are provided for getting data from the child
+ * process or sending data to the child's stdin (For more information,
+ * have a look at the documentation of each function):
+ *
+ * @li writeStdin()
+ * -- Transmit data to the child process' stdin. When all data was sent, the
+ * signal wroteStdin() is emitted.
+ *
+ * @li When data arrives at stdout or stderr, the signal receivedStdout()
+ * resp. receivedStderr() is emitted.
+ *
+ * @li You can shut down individual communication channels with
+ * closeStdin(), closeStdout(), and closeStderr(), resp.
+ *
+ * @author Christian Czezatke e9025461@student.tuwien.ac.at
+ *
+ **/
+class KDECORE_EXPORT KProcess : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Modes in which the communication channel can be opened.
+ *
+ * If communication for more than one channel is required,
+ * the values have to be or'ed together, for example to get
+ * communication with stdout as well as with stdin, you would
+ * specify @p Stdin | @p Stdout
+ *
+ * If @p NoRead is specified in conjunction with @p Stdout,
+ * no data is actually read from @p Stdout but only
+ * the signal receivedStdout(int fd, int &len) is emitted.
+ *
+ * @p CTtyOnly tells setUsePty() to create a PTY for the process
+ * and make it the process' controlling TTY, but does not redirect
+ * any I/O channel to the PTY.
+ *
+ * If @p MergedStderr is specified in conjunction with @p Stdout,
+ * Stderr will be redirected onto the same file handle as Stdout,
+ * i.e., all error output will be signalled with receivedStdout().
+ * Don't specify @p Stderr if you specify @p MergedStderr.
+ */
+ enum Communication {
+ NoCommunication = 0,
+ Stdin = 1, Stdout = 2, Stderr = 4,
+ AllOutput = 6, All = 7,
+ NoRead = 8,
+ CTtyOnly = NoRead,
+ MergedStderr = 16
+ };
+
+ /**
+ * Run-modes for a child process.
+ */
+ enum RunMode {
+ /**
+ * The application does not receive notifications from the subprocess when
+ * it is finished or aborted.
+ */
+ DontCare,
+ /**
+ * The application is notified when the subprocess dies.
+ */
+ NotifyOnExit,
+ /**
+ * The application is suspended until the started process is finished.
+ */
+ Block,
+ /**
+ * Same as NotifyOnExit, but the process is run in an own session,
+ * just like with DontCare.
+ */
+ OwnGroup
+ };
+
+ /**
+ * Constructor
+ * @since 3.2
+ */
+ KProcess( QObject* parent, const char *name = 0 );
+
+ /**
+ * Constructor
+ */ // KDE4 merge with the above
+ KProcess();
+
+ /**
+ *Destructor:
+ *
+ * If the process is running when the destructor for this class
+ * is called, the child process is killed with a SIGKILL, but
+ * only if the run mode is not of type @p DontCare.
+ * Processes started as @p DontCare keep running anyway.
+ */
+ virtual ~KProcess();
+
+ /**
+ @deprecated
+ Use operator<<() instead.
+
+ Sets the executable to be started with this KProcess object.
+ Returns false if the process is currently running (in that
+ case the executable remains unchanged).
+
+ @see operator<<()
+
+ */
+ bool setExecutable(const QString& proc) KDE_DEPRECATED;
+
+
+ /**
+ * Sets the executable and the command line argument list for this process.
+ *
+ * For example, doing an "ls -l /usr/local/bin" can be achieved by:
+ * \code
+ * KProcess p;
+ * ...
+ * p << "ls" << "-l" << "/usr/local/bin"
+ * \endcode
+ *
+ * @param arg the argument to add
+ * @return a reference to this KProcess
+ **/
+ KProcess &operator<<(const QString& arg);
+ /**
+ * Similar to previous method, takes a char *, supposed to be in locale 8 bit already.
+ */
+ KProcess &operator<<(const char * arg);
+ /**
+ * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already.
+ * @param arg the argument to add
+ * @return a reference to this KProcess
+ */
+ KProcess &operator<<(const QCString & arg);
+
+ /**
+ * Sets the executable and the command line argument list for this process,
+ * in a single method call, or add a list of arguments.
+ * @param args the arguments to add
+ * @return a reference to this KProcess
+ **/
+ KProcess &operator<<(const QStringList& args);
+
+ /**
+ * Clear a command line argument list that has been set by using
+ * operator<<.
+ */
+ void clearArguments();
+
+ /**
+ * Starts the process.
+ * For a detailed description of the
+ * various run modes and communication semantics, have a look at the
+ * general description of the KProcess class. Note that if you use
+ * setUsePty( Stdout | Stderr, \<bool\> ), you cannot use Stdout | Stderr
+ * here - instead, use Stdout only to receive the mixed output.
+ *
+ * The following problems could cause this function to
+ * return false:
+ *
+ * @li The process is already running.
+ * @li The command line argument list is empty.
+ * @li The the @p comm parameter is incompatible with the selected pty usage.
+ * @li The starting of the process failed (could not fork).
+ * @li The executable was not found.
+ *
+ * @param runmode The Run-mode for the process.
+ * @param comm Specifies which communication links should be
+ * established to the child process (stdin/stdout/stderr). By default,
+ * no communication takes place and the respective communication
+ * signals will never get emitted.
+ *
+ * @return true on success, false on error
+ * (see above for error conditions)
+ **/
+ virtual bool start(RunMode runmode = NotifyOnExit,
+ Communication comm = NoCommunication);
+
+ /**
+ * Stop the process (by sending it a signal).
+ *
+ * @param signo The signal to send. The default is SIGTERM.
+ * @return true if the signal was delivered successfully.
+ */
+ virtual bool kill(int signo = SIGTERM);
+
+ /**
+ * Checks whether the process is running.
+ * @return true if the process is (still) considered to be running
+ */
+ bool isRunning() const;
+
+ /** Returns the process id of the process.
+ *
+ * If it is called after
+ * the process has exited, it returns the process id of the last
+ * child process that was created by this instance of KProcess.
+ *
+ * Calling it before any child process has been started by this
+ * KProcess instance causes pid() to return 0.
+ * @return the pid of the process or 0 if no process has been started yet.
+ **/
+ pid_t pid() const;
+
+ /**
+ * @deprecated
+ * Use pid() instead.
+ */
+ KDE_DEPRECATED pid_t getPid() const { return pid(); }
+
+ /**
+ * Suspend processing of data from stdout of the child process.
+ */
+ void suspend();
+
+ /**
+ * Resume processing of data from stdout of the child process.
+ */
+ void resume();
+
+ /**
+ * Suspend execution of the current thread until the child process dies
+ * or the timeout hits. This function is not recommended for programs
+ * with a GUI.
+ * @param timeout timeout in seconds. -1 means wait indefinitely.
+ * @return true if the process exited, false if the timeout hit.
+ * @since 3.2
+ */
+ bool wait(int timeout = -1);
+
+ /**
+ * Checks whether the process exited cleanly.
+ *
+ * @return true if the process has already finished and has exited
+ * "voluntarily", ie: it has not been killed by a signal.
+ */
+ bool normalExit() const;
+
+ /**
+ * Checks whether the process was killed by a signal.
+ *
+ * @return true if the process has already finished and has not exited
+ * "voluntarily", ie: it has been killed by a signal.
+ *
+ * @since 3.2
+ */
+ bool signalled() const;
+
+ /**
+ * Checks whether a killed process dumped core.
+ *
+ * @return true if signalled() returns true and the process
+ * dumped core. Note that on systems that don't define the
+ * WCOREDUMP macro, the return value is always false.
+ *
+ * @since 3.2
+ */
+ bool coreDumped() const;
+
+ /**
+ * Returns the exit status of the process.
+ *
+ * @return the exit status of the process. Note that this value
+ * is not valid if normalExit() returns false.
+ */
+ int exitStatus() const;
+
+ /**
+ * Returns the signal the process was killed by.
+ *
+ * @return the signal number that caused the process to exit.
+ * Note that this value is not valid if signalled() returns false.
+ *
+ * @since 3.2
+ */
+ int exitSignal() const;
+
+ /**
+ * Transmit data to the child process' stdin.
+ *
+ * This function may return false in the following cases:
+ *
+ * @li The process is not currently running.
+ * This implies that you cannot use this function in Block mode.
+ *
+ * @li Communication to stdin has not been requested in the start() call.
+ *
+ * @li Transmission of data to the child process by a previous call to
+ * writeStdin() is still in progress.
+ *
+ * Please note that the data is sent to the client asynchronously,
+ * so when this function returns, the data might not have been
+ * processed by the child process.
+ * That means that you must not free @p buffer or call writeStdin()
+ * again until either a wroteStdin() signal indicates that the
+ * data has been sent or a processExited() signal shows that
+ * the child process is no longer alive.
+ *
+ * If all the data has been sent to the client, the signal
+ * wroteStdin() will be emitted.
+ *
+ * This function does not work when the process is start()ed in Block mode.
+ *
+ * @param buffer the buffer to write
+ * @param buflen the length of the buffer
+ * @return false if an error has occurred
+ **/
+ bool writeStdin(const char *buffer, int buflen);
+
+ /**
+ * Shuts down the Stdin communication link. If no pty is used, this
+ * causes "EOF" to be indicated on the child's stdin file descriptor.
+ *
+ * @return false if no Stdin communication link exists (any more).
+ */
+ bool closeStdin();
+
+ /**
+ * Shuts down the Stdout communication link. If no pty is used, any further
+ * attempts by the child to write to its stdout file descriptor will cause
+ * it to receive a SIGPIPE.
+ *
+ * @return false if no Stdout communication link exists (any more).
+ */
+ bool closeStdout();
+
+ /**
+ * Shuts down the Stderr communication link. If no pty is used, any further
+ * attempts by the child to write to its stderr file descriptor will cause
+ * it to receive a SIGPIPE.
+ *
+ * @return false if no Stderr communication link exists (any more).
+ */
+ bool closeStderr();
+
+ /**
+ * Deletes the optional utmp entry and closes the pty.
+ *
+ * Make sure to shut down any communication links that are using the pty
+ * before calling this function.
+ *
+ * @return false if the pty is not open (any more).
+ */
+ bool closePty();
+
+ /**
+ * @brief Close stdin, stdout, stderr and the pty
+ *
+ * This is the same that calling all close* functions in a row:
+ * @see closeStdin, @see closeStdout, @see closeStderr and @see closePty
+ */
+ void closeAll();
+
+ /**
+ * Lets you see what your arguments are for debugging.
+ * @return the list of arguments
+ */
+ const QValueList<QCString> &args() /* const */ { return arguments; }
+
+ /**
+ * Controls whether the started process should drop any
+ * setuid/setgid privileges or whether it should keep them.
+ * Note that this function is mostly a dummy, as the KDE libraries
+ * currently refuse to run with setuid/setgid privileges.
+ *
+ * The default is false: drop privileges
+ * @param keepPrivileges true to keep the privileges
+ */
+ void setRunPrivileged(bool keepPrivileges);
+
+ /**
+ * Returns whether the started process will drop any
+ * setuid/setgid privileges or whether it will keep them.
+ * @return true if the process runs privileged
+ */
+ bool runPrivileged() const;
+
+ /**
+ * Adds the variable @p name to the process' environment.
+ * This function must be called before starting the process.
+ * @param name the name of the environment variable
+ * @param value the new value for the environment variable
+ */
+ void setEnvironment(const QString &name, const QString &value);
+
+ /**
+ * Changes the current working directory (CWD) of the process
+ * to be started.
+ * This function must be called before starting the process.
+ * @param dir the new directory
+ */
+ void setWorkingDirectory(const QString &dir);
+
+ /**
+ * Specify whether to start the command via a shell or directly.
+ * The default is to start the command directly.
+ * If @p useShell is true @p shell will be used as shell, or
+ * if shell is empty, /bin/sh will be used.
+ *
+ * When using a shell, the caller should make sure that all filenames etc.
+ * are properly quoted when passed as argument.
+ * @see quote()
+ * @param useShell true if the command should be started via a shell
+ * @param shell the path to the shell that will execute the process, or
+ * 0 to use /bin/sh. Use getenv("SHELL") to use the user's
+ * default shell, but note that doing so is usually a bad idea
+ * for shell compatibility reasons.
+ * @since 3.1
+ */
+ void setUseShell(bool useShell, const char *shell = 0);
+
+ /**
+ * This function can be used to quote an argument string such that
+ * the shell processes it properly. This is e. g. necessary for
+ * user-provided file names which may contain spaces or quotes.
+ * It also prevents expansion of wild cards and environment variables.
+ * @param arg the argument to quote
+ * @return the quoted argument
+ * @since 3.1
+ */
+ static QString quote(const QString &arg);
+
+ /**
+ * Detaches KProcess from child process. All communication is closed.
+ * No exit notification is emitted any more for the child process.
+ * Deleting the KProcess will no longer kill the child process.
+ * Note that the current process remains the parent process of the
+ * child process.
+ */
+ void detach();
+
+#ifdef Q_OS_UNIX
+ /**
+ * Specify whether to create a pty (pseudo-terminal) for running the
+ * command.
+ * This function should be called before starting the process.
+ *
+ * @param comm for which stdio handles to use a pty. Note that it is not
+ * allowed to specify Stdout and Stderr at the same time both here and to
+ * start (there is only one pty, so they cannot be distinguished).
+ * @param addUtmp true if a utmp entry should be created for the pty
+ * @since 3.2
+ */
+ void setUsePty(Communication comm, bool addUtmp);
+
+ /**
+ * Obtains the pty object used by this process. The return value is
+ * valid only after setUsePty() was used with a non-zero argument.
+ * The pty is open only while the process is running.
+ * @return a pointer to the pty object
+ * @since 3.2
+ */
+ KPty *pty() const;
+#endif
+
+ /**
+ * More or less intuitive constants for use with setPriority().
+ */
+ enum { PrioLowest = 20, PrioLow = 10, PrioLower = 5, PrioNormal = 0,
+ PrioHigher = -5, PrioHigh = -10, PrioHighest = -19 };
+
+ /**
+ * Sets the scheduling priority of the process.
+ * @param prio the new priority in the range -20 (high) to 19 (low).
+ * @return false on error; see setpriority(2) for possible reasons.
+ * @since 3.2
+ */
+ bool setPriority(int prio);
+
+signals:
+ /**
+ * Emitted after the process has terminated when
+ * the process was run in the @p NotifyOnExit (==default option to
+ * start() ) or the Block mode.
+ * @param proc a pointer to the process that has exited
+ **/
+ void processExited(KProcess *proc);
+
+
+ /**
+ * Emitted, when output from the child process has
+ * been received on stdout.
+ *
+ * To actually get this signal, the Stdout communication link
+ * has to be turned on in start().
+ *
+ * @param proc a pointer to the process that has received the output
+ * @param buffer The data received.
+ * @param buflen The number of bytes that are available.
+ *
+ * You should copy the information contained in @p buffer to your private
+ * data structures before returning from the slot.
+ * Example:
+ * \code
+ * QString myBuf = QString::fromLatin1(buffer, buflen);
+ * \endcode
+ **/
+ void receivedStdout(KProcess *proc, char *buffer, int buflen);
+
+ /**
+ * Emitted when output from the child process has
+ * been received on stdout.
+ *
+ * To actually get this signal, the Stdout communication link
+ * has to be turned on in start() and the
+ * NoRead flag must have been passed.
+ *
+ * You will need to explicitly call resume() after your call to start()
+ * to begin processing data from the child process' stdout. This is
+ * to ensure that this signal is not emitted when no one is connected
+ * to it, otherwise this signal will not be emitted.
+ *
+ * The data still has to be read from file descriptor @p fd.
+ * @param fd the file descriptor that provides the data
+ * @param len the number of bytes that have been read from @p fd must
+ * be written here
+ **/
+ void receivedStdout(int fd, int &len); // KDE4: change, broken API
+
+
+ /**
+ * Emitted, when output from the child process has
+ * been received on stderr.
+ *
+ * To actually get this signal, the Stderr communication link
+ * has to be turned on in start().
+ *
+ * You should copy the information contained in @p buffer to your private
+ * data structures before returning from the slot.
+ *
+ * @param proc a pointer to the process that has received the data
+ * @param buffer The data received.
+ * @param buflen The number of bytes that are available.
+ **/
+ void receivedStderr(KProcess *proc, char *buffer, int buflen);
+
+ /**
+ * Emitted after all the data that has been
+ * specified by a prior call to writeStdin() has actually been
+ * written to the child process.
+ * @param proc a pointer to the process
+ **/
+ void wroteStdin(KProcess *proc);
+
+
+protected slots:
+
+ /**
+ * This slot gets activated when data from the child's stdout arrives.
+ * It usually calls childOutput().
+ * @param fdno the file descriptor for the output
+ */
+ void slotChildOutput(int fdno);
+
+ /**
+ * This slot gets activated when data from the child's stderr arrives.
+ * It usually calls childError().
+ * @param fdno the file descriptor for the output
+ */
+ void slotChildError(int fdno);
+
+ /**
+ * Called when another bulk of data can be sent to the child's
+ * stdin. If there is no more data to be sent to stdin currently
+ * available, this function must disable the QSocketNotifier innot.
+ * @param dummy ignore this argument
+ */
+ void slotSendData(int dummy); // KDE 4: remove dummy
+
+protected:
+
+ /**
+ * Sets up the environment according to the data passed via
+ * setEnvironment()
+ */
+ void setupEnvironment();
+
+ /**
+ * The list of the process' command line arguments. The first entry
+ * in this list is the executable itself.
+ */
+ QValueList<QCString> arguments;
+ /**
+ * How to run the process (Block, NotifyOnExit, DontCare). You should
+ * not modify this data member directly from derived classes.
+ */
+ RunMode run_mode;
+ /**
+ * true if the process is currently running. You should not
+ * modify this data member directly from derived classes. Please use
+ * isRunning() for reading the value of this data member since it
+ * will probably be made private in later versions of KProcess.
+ */
+ bool runs;
+
+ /**
+ * The PID of the currently running process.
+ * You should not modify this data member in derived classes.
+ * Please use pid() instead of directly accessing this
+ * member since it will probably be made private in
+ * later versions of KProcess.
+ */
+ pid_t pid_;
+
+ /**
+ * The process' exit status as returned by waitpid(). You should not
+ * modify the value of this data member from derived classes. You should
+ * rather use exitStatus() than accessing this data member directly
+ * since it will probably be made private in further versions of
+ * KProcess.
+ */
+ int status;
+
+
+ /**
+ * If false, the child process' effective uid & gid will be reset to the
+ * real values.
+ * @see setRunPrivileged()
+ */
+ bool keepPrivs;
+
+ /**
+ * This function is called from start() right before a fork() takes
+ * place. According to the @p comm parameter this function has to initialize
+ * the in, out and err data members of KProcess.
+ *
+ * This function should return 1 if setting the needed communication channels
+ * was successful.
+ *
+ * The default implementation is to create UNIX STREAM sockets for the
+ * communication, but you could reimplement this function to establish a
+ * TCP/IP communication for network communication, for example.
+ */
+ virtual int setupCommunication(Communication comm);
+
+ /**
+ * Called right after a (successful) fork() on the parent side. This function
+ * will usually do some communications cleanup, like closing in[0],
+ * out[1] and out[1].
+ *
+ * Furthermore, it must also create the QSocketNotifiers innot,
+ * outnot and errnot and connect their Qt signals to the respective
+ * KProcess slots.
+ *
+ * For a more detailed explanation, it is best to have a look at the default
+ * implementation in kprocess.cpp.
+ */
+ virtual int commSetupDoneP();
+
+ /**
+ * Called right after a (successful) fork(), but before an exec() on the child
+ * process' side. It usually duplicates the in[0], out[1] and
+ * err[1] file handles to the respective standard I/O handles.
+ */
+ virtual int commSetupDoneC();
+
+
+ /**
+ * Immediately called after a successfully started process in NotifyOnExit
+ * mode has exited. This function normally calls commClose()
+ * and emits the processExited() signal.
+ * @param state the exit code of the process as returned by waitpid()
+ */
+ virtual void processHasExited(int state);
+
+ /**
+ * Cleans up the communication links to the child after it has exited.
+ * This function should act upon the values of pid() and runs.
+ * See the kprocess.cpp source for details.
+ * @li If pid() returns zero, the communication links should be closed
+ * only.
+ * @li if pid() returns non-zero and runs is false, all data
+ * immediately available from the communication links should be processed
+ * before closing them.
+ * @li if pid() returns non-zero and runs is true, the communication
+ * links should be monitored for data until the file handle returned by
+ * KProcessController::theKProcessController->notifierFd() becomes ready
+ * for reading - when it triggers, runs should be reset to false, and
+ * the function should be immediately left without closing anything.
+ *
+ * The previous semantics of this function are forward-compatible, but should
+ * be avoided, as they are prone to race conditions and can cause KProcess
+ * (and thus the whole program) to lock up under certain circumstances. At the
+ * end the function closes the communication links in any case. Additionally
+ * @li if runs is true, the communication links are monitored for data
+ * until all of them have returned EOF. Note that if any system function is
+ * interrupted (errno == EINTR) the polling loop should be aborted.
+ * @li if runs is false, all data immediately available from the
+ * communication links is processed.
+ */
+ virtual void commClose();
+
+ /* KDE 4 - commClose will be changed to perform cleanup only in all cases *
+ * If @p notfd is -1, all data immediately available from the
+ * communication links should be processed.
+ * If @p notfd is not -1, the communication links should be monitored
+ * for data until the file handle @p notfd becomes ready for reading.
+ */
+// virtual void commDrain(int notfd);
+
+ /**
+ * Specify the actual executable that should be started (first argument to execve)
+ * Normally the the first argument is the executable but you can
+ * override that with this function.
+ */
+ void setBinaryExecutable(const char *filename);
+
+ /**
+ * The socket descriptors for stdout.
+ */
+ int out[2];
+ /**
+ * The socket descriptors for stdin.
+ */
+ int in[2];
+ /**
+ * The socket descriptors for stderr.
+ */
+ int err[2];
+
+ /**
+ * The socket notifier for in[1].
+ */
+ QSocketNotifier *innot;
+ /**
+ * The socket notifier for out[0].
+ */
+ QSocketNotifier *outnot;
+ /**
+ * The socket notifier for err[0].
+ */
+ QSocketNotifier *errnot;
+
+ /**
+ * Lists the communication links that are activated for the child
+ * process. Should not be modified from derived classes.
+ */
+ Communication communication;
+
+ /**
+ * Called by slotChildOutput() this function copies data arriving from
+ * the child process' stdout to the respective buffer and emits the signal
+ * receivedStdout().
+ */
+ int childOutput(int fdno);
+
+ /**
+ * Called by slotChildError() this function copies data arriving from
+ * the child process' stderr to the respective buffer and emits the signal
+ * receivedStderr().
+ */
+ int childError(int fdno);
+
+ /**
+ * The buffer holding the data that has to be sent to the child
+ */
+ const char *input_data;
+ /**
+ * The number of bytes already transmitted
+ */
+ int input_sent;
+ /**
+ * The total length of input_data
+ */
+ int input_total;
+
+ /**
+ * KProcessController is a friend of KProcess because it has to have
+ * access to various data members.
+ */
+ friend class KProcessController;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KProcessPrivate *d;
+};
+
+class KShellProcessPrivate;
+
+/**
+* @obsolete
+*
+* Use KProcess and KProcess::setUseShell(true) instead.
+*
+* @short A class derived from KProcess to start child
+* processes through a shell.
+* @author Christian Czezatke <e9025461@student.tuwien.ac.at>
+*/
+class KDECORE_EXPORT KShellProcess: public KProcess
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Constructor
+ *
+ * If no shellname is specified, the user's default shell is used.
+ */
+ KShellProcess(const char *shellname=0);
+
+ /**
+ * Destructor.
+ */
+ ~KShellProcess();
+
+ virtual bool start(RunMode runmode = NotifyOnExit,
+ Communication comm = NoCommunication);
+
+ static QString quote(const QString &arg);
+
+private:
+ QCString shell;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KShellProcessPrivate *d;
+};
+
+
+
+#endif
+
diff --git a/kdecore/kprocio.cpp b/kdecore/kprocio.cpp
new file mode 100644
index 000000000..d6fe33d89
--- /dev/null
+++ b/kdecore/kprocio.cpp
@@ -0,0 +1,276 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 David Sweet <dsweet@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "kprocio.h"
+
+#include <kdebug.h>
+#include <qtextcodec.h>
+
+class KProcIOPrivate {
+public:
+ KProcIOPrivate() : comm(KProcess::All) {}
+ KProcess::Communication comm;
+};
+
+KProcIO::KProcIO ( QTextCodec *_codec)
+ : codec(_codec), d(new KProcIOPrivate)
+{
+ rbi=0;
+ readsignalon=writeready=true;
+ outbuffer.setAutoDelete(true);
+
+ if (!codec)
+ {
+ codec = QTextCodec::codecForName("ISO 8859-1");
+ if (!codec)
+ {
+ kdError(174) << "Can't create ISO 8859-1 codec!" << endl;
+ }
+ }
+}
+
+KProcIO::~KProcIO()
+{
+ delete d;
+}
+
+void
+KProcIO::resetAll ()
+{
+ if (isRunning())
+ kill();
+
+ clearArguments();
+ rbi=0;
+ readsignalon=writeready=true;
+
+ disconnect (this, SIGNAL (receivedStdout (KProcess *, char *, int)),
+ this, SLOT (received (KProcess *, char *, int)));
+
+ disconnect (this, SIGNAL (receivedStderr (KProcess *, char *, int)),
+ this, SLOT (received (KProcess *, char *, int)));
+
+ disconnect (this, SIGNAL (wroteStdin(KProcess *)),
+ this, SLOT (sent (KProcess *)));
+
+ outbuffer.clear();
+
+}
+
+void KProcIO::setComm (Communication comm)
+{
+ d->comm = comm;
+}
+
+bool KProcIO::start (RunMode runmode, bool includeStderr)
+{
+ connect (this, SIGNAL (receivedStdout (KProcess *, char *, int)),
+ this, SLOT (received (KProcess *, char *, int)));
+
+ if (includeStderr)
+ {
+ connect (this, SIGNAL (receivedStderr (KProcess *, char *, int)),
+ this, SLOT (received (KProcess *, char *, int)));
+ }
+
+ connect (this, SIGNAL (wroteStdin(KProcess *)),
+ this, SLOT (sent (KProcess *)));
+
+ return KProcess::start (runmode, d->comm);
+}
+
+bool KProcIO::writeStdin (const QString &line, bool appendnewline)
+{
+ return writeStdin(codec->fromUnicode(line), appendnewline);
+}
+
+bool KProcIO::writeStdin (const QCString &line, bool appendnewline)
+{
+ QCString *qs = new QCString(line);
+
+ if (appendnewline)
+ {
+ *qs += '\n';
+ }
+
+ int l = qs->length();
+ if (!l)
+ {
+ delete qs;
+ return true;
+ }
+
+ QByteArray *b = (QByteArray *) qs;
+ b->truncate(l); // Strip trailing null
+
+ outbuffer.append(b);
+
+ if (writeready)
+ {
+ writeready=false;
+ return KProcess::writeStdin( b->data(), b->size() );
+ }
+ return true;
+}
+
+bool KProcIO::writeStdin(const QByteArray &data)
+{
+ if (!data.size())
+ return true;
+ QByteArray *b = new QByteArray(data);
+ outbuffer.append(b);
+
+ if (writeready)
+ {
+ writeready=false;
+ return KProcess::writeStdin( b->data(), b->size() );
+ }
+ return true;
+}
+
+void KProcIO::closeWhenDone()
+{
+ if (writeready)
+ {
+ closeStdin();
+ return;
+ }
+ outbuffer.append(0);
+
+ return;
+}
+
+void KProcIO::sent(KProcess *)
+{
+ outbuffer.removeFirst();
+
+ if (outbuffer.count()==0)
+ {
+ writeready=true;
+ }
+ else
+ {
+ QByteArray *b = outbuffer.first();
+ if (!b)
+ {
+ closeStdin();
+ }
+ else
+ {
+ KProcess::writeStdin(b->data(), b->size());
+ }
+ }
+
+}
+
+void KProcIO::received (KProcess *, char *buffer, int buflen)
+{
+ recvbuffer += QCString(buffer, buflen+1);
+
+ controlledEmission();
+}
+
+void KProcIO::ackRead ()
+{
+ readsignalon=true;
+ if (needreadsignal || recvbuffer.length()!=0)
+ controlledEmission();
+}
+
+void KProcIO::controlledEmission ()
+{
+ if (readsignalon)
+ {
+ needreadsignal=false;
+ readsignalon=false; //will stay off until read is acknowledged
+ emit readReady (this);
+ }
+ else
+ {
+ needreadsignal=true;
+ }
+}
+
+void KProcIO::enableReadSignals (bool enable)
+{
+ readsignalon=enable;
+
+ if (enable && needreadsignal)
+ emit readReady (this);
+}
+
+int KProcIO::readln (QString &line, bool autoAck, bool *partial)
+{
+ int len;
+
+ if (autoAck)
+ readsignalon=true;
+
+ //need to reduce the size of recvbuffer at some point...
+
+ len=recvbuffer.find ('\n',rbi)-rbi;
+
+ //kdDebug(174) << "KPIO::readln" << endl;
+
+ //in case there's no '\n' at the end of the buffer
+ if ((len<0) &&
+ ((unsigned int)rbi<recvbuffer.length()))
+ {
+ recvbuffer=recvbuffer.mid (rbi);
+ rbi=0;
+ if (partial)
+ {
+ len = recvbuffer.length();
+ line = recvbuffer;
+ recvbuffer = "";
+ *partial = true;
+ return len;
+ }
+ return -1;
+ }
+
+ if (len>=0)
+ {
+ line = codec->toUnicode(recvbuffer.mid(rbi,len), len);
+ rbi += len+1;
+ if (partial)
+ *partial = false;
+ return len;
+ }
+
+ recvbuffer="";
+ rbi=0;
+
+ //-1 on return signals "no more data" not error
+ return -1;
+
+}
+
+void KProcIO::virtual_hook( int id, void* data )
+{ KProcess::virtual_hook( id, data ); }
+
+#include "kprocio.moc"
+
diff --git a/kdecore/kprocio.h b/kdecore/kprocio.h
new file mode 100644
index 000000000..192c16fc1
--- /dev/null
+++ b/kdecore/kprocio.h
@@ -0,0 +1,217 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 David Sweet <dsweet@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KPROCIO_H_
+#define KPROCIO_H_
+
+#include <qstring.h>
+#include <kprocess.h>
+#include <qstrlist.h>
+#include "kdelibs_export.h"
+
+class KProcIOPrivate;
+class QTextCodec;
+
+/**
+ * KProcIO
+ *
+ * This class provides a slightly simpler interface to the communication
+ * functions provided by KProcess. The simplifications are:
+ * @li The buffer for a write is copied to an internal KProcIO
+ * buffer and maintained/freed appropriately. There is no need
+ * to be concerned with wroteStdin() signals _at_all_.
+ * @li readln() reads a line of data and buffers any leftovers.
+ * @li Conversion from/to unicode.
+ *
+ * Basically, KProcIO gives you buffered I/O similar to fgets()/fputs().
+ *
+ * Aside from these, and the fact that start() takes different
+ * parameters, use this class just like KProcess.
+ *
+ * @author David Sweet
+ * @short A slightly simpler interface to KProcess
+ **/
+
+
+class KDECORE_EXPORT KProcIO : public KProcess
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ */
+ KProcIO ( QTextCodec *codec = 0 );
+
+ /**
+ * Destructor
+ */
+ ~KProcIO();
+
+ /**
+ * Sets the communication mode to be passed to KProcess::start()
+ * by start(). The default communication mode is KProcess::All.
+ * You probably want to use this function in conjunction with
+ * KProcess::setUsePty().
+ * @param comm the communication mode
+ */
+ void setComm (Communication comm);
+
+ /**
+ * Starts the process. It will fail in the following cases:
+ * @li The process is already running.
+ * @li The command line argument list is empty.
+ * @li The starting of the process failed (could not fork).
+ * @li The executable was not found.
+ *
+ * @param runmode For a detailed description of the
+ * various run modes, have a look at the
+ * general description of the KProcess class.
+ * @param includeStderr If true, data from both stdout and stderr is
+ * listened to. If false, only stdout is listened to.
+ * @return true on success, false on error.
+ **/
+ bool start (RunMode runmode = NotifyOnExit, bool includeStderr = false);
+
+ /**
+ * Writes text to stdin of the process.
+ * @param line Text to write.
+ * @param appendnewline if true, a newline '\\n' is appended.
+ * @return true if successful, false otherwise
+ **/
+ bool writeStdin(const QString &line, bool appendnewline=true);
+
+ /**
+ * Writes text to stdin of the process.
+ * @param line Text to write.
+ * @param appendnewline if true, a newline '\\n' is appended.
+ * @return true if successful, false otherwise
+ **/
+ bool writeStdin(const QCString &line, bool appendnewline);
+
+ /**
+ * Writes data to stdin of the process.
+ * @param data Data to write.
+ * @return true if successful, false otherwise
+ **/
+ bool writeStdin(const QByteArray &data);
+
+ //I like fputs better -- it's the same as writeStdin
+ //inline
+ /**
+ * This function just calls writeStdin().
+ *
+ * @param line Text to write.
+ * @param AppendNewLine if true, a newline '\\n' is appended.
+ * @return true if successful, false otherwise
+ * @deprecated
+ **/
+ KDE_DEPRECATED bool fputs (const QString &line, bool AppendNewLine=true)
+ { return writeStdin(line, AppendNewLine); }
+
+ /**
+ * Closes stdin after all data has been send.
+ */
+ void closeWhenDone();
+
+ /**
+ * Reads a line of text (up to and including '\\n').
+ *
+ * Use readln() in response to a readReady() signal.
+ * You may use it multiple times if more than one line of data is
+ * available.
+ * Be sure to use ackRead() when you have finished processing the
+ * readReady() signal. This informs KProcIO that you are ready for
+ * another readReady() signal.
+ *
+ * readln() never blocks.
+ *
+ * autoAck==true makes these functions call ackRead() for you.
+ *
+ * @param line is used to store the line that was read.
+ * @param autoAck when true, ackRead() is called for you.
+ * @param partial when provided the line is returned
+ * even if it does not contain a '\\n'. *partial will be set to
+ * false if the line contains a '\\n' and false otherwise.
+ * @return the number of characters read, or -1 if no data is available.
+ **/
+ int readln (QString &line, bool autoAck=true, bool *partial=0);
+
+ /**
+ * This function calls readln().
+ * @param line is used to store the line that was read.
+ * @param autoAck when true, ackRead() is called for you.
+ * @return the number of characters read, or -1 if no data is available.
+ * @deprecated use readln. Note that it has an inverted autoAck default,
+ * though.
+ **/
+ KDE_DEPRECATED int fgets (QString &line, bool autoAck=false)
+ { return readln (line, autoAck); }
+
+ /**
+ * Reset the class. Doesn't kill the process.
+ **/
+ void resetAll ();
+
+ /**
+ * Call this after you have finished processing a readReady()
+ * signal. This call need not be made in the slot that was signalled
+ * by readReady(). You won't receive any more readReady() signals
+ * until you acknowledge with ackRead(). This prevents your slot
+ * from being reentered while you are still processing the current
+ * data. If this doesn't matter, then call ackRead() right away in
+ * your readReady()-processing slot.
+ **/
+ void ackRead ();
+
+ /**
+ * Turns readReady() signals on and off.
+ * You can turn this off at will and not worry about losing any data.
+ * (as long as you turn it back on at some point...)
+ * @param enable true to turn the signals on, false to turn them off
+ */
+ void enableReadSignals (bool enable);
+
+signals:
+ /**
+ * Emitted when the process is ready for reading.
+ * @param pio the process that emitted the signal
+ * @see enableReadSignals()
+ */
+ void readReady(KProcIO *pio);
+
+protected:
+ QPtrList<QByteArray> outbuffer;
+ QCString recvbuffer;
+ QTextCodec *codec;
+ int rbi;
+ bool needreadsignal, readsignalon, writeready;
+
+ void controlledEmission ();
+
+protected slots:
+ void received (KProcess *proc, char *buffer, int buflen);
+ void sent (KProcess *);
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KProcIOPrivate *d;
+};
+
+#endif // KPROCIO_H_
+
diff --git a/kdecore/kprotocolinfo_kdecore.cpp b/kdecore/kprotocolinfo_kdecore.cpp
new file mode 100644
index 000000000..0c40c36d3
--- /dev/null
+++ b/kdecore/kprotocolinfo_kdecore.cpp
@@ -0,0 +1,562 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifdef MAKE_KDECORE_LIB //needed for proper linkage (win32)
+#undef KIO_EXPORT
+#define KIO_EXPORT KDE_EXPORT
+#endif
+
+#define KPROTOCOLINFO_KDECORE
+#include "kprotocolinfo.h"
+#include "kprotocolinfofactory.h"
+
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <ksimpleconfig.h>
+#include <kconfig.h>
+#include <kstringhandler.h>
+
+class KProtocolInfo::KProtocolInfoPrivate
+{
+public:
+ QString docPath;
+ QString protClass;
+ KProtocolInfo::ExtraFieldList extraFields;
+ bool showPreviews;
+ bool canRenameFromFile;
+ bool canRenameToFile;
+ bool canDeleteRecursive;
+ bool fileNameUsedForCopying; // true if using UDS_NAME, false if using KURL::fileName() [default]
+ KURL::URIMode uriMode;
+ QStringList capabilities;
+ QString proxyProtocol;
+};
+
+//
+// Internal functions:
+//
+KProtocolInfo::KProtocolInfo(const QString &path)
+ : KSycocaEntry(path)
+{
+ d = new KProtocolInfoPrivate;
+ QString fullPath = locate("services", path);
+
+ KSimpleConfig config( fullPath, true );
+ config.setGroup( "Protocol" );
+
+ m_name = config.readEntry( "protocol" );
+ m_exec = config.readPathEntry( "exec" );
+ m_isSourceProtocol = config.readBoolEntry( "source", true );
+ m_isHelperProtocol = config.readBoolEntry( "helper", false );
+ m_supportsReading = config.readBoolEntry( "reading", false );
+ m_supportsWriting = config.readBoolEntry( "writing", false );
+ m_supportsMakeDir = config.readBoolEntry( "makedir", false );
+ m_supportsDeleting = config.readBoolEntry( "deleting", false );
+ m_supportsLinking = config.readBoolEntry( "linking", false );
+ m_supportsMoving = config.readBoolEntry( "moving", false );
+ m_canCopyFromFile = config.readBoolEntry( "copyFromFile", false );
+ m_canCopyToFile = config.readBoolEntry( "copyToFile", false );
+ d->canRenameFromFile = config.readBoolEntry( "renameFromFile", false );
+ d->canRenameToFile = config.readBoolEntry( "renameToFile", false );
+ d->canDeleteRecursive = config.readBoolEntry( "deleteRecursive", false );
+ d->fileNameUsedForCopying = config.readEntry( "fileNameUsedForCopying", "FromURL" ) == "Name";
+
+ m_listing = config.readListEntry( "listing" );
+ // Many .protocol files say "Listing=false" when they really mean "Listing=" (i.e. unsupported)
+ if ( m_listing.count() == 1 && m_listing.first() == "false" )
+ m_listing.clear();
+ m_supportsListing = ( m_listing.count() > 0 );
+ m_defaultMimetype = config.readEntry( "defaultMimetype" );
+ m_determineMimetypeFromExtension = config.readBoolEntry( "determineMimetypeFromExtension", true );
+ m_icon = config.readEntry( "Icon", "unknown" );
+ m_config = config.readEntry( "config", m_name );
+ m_maxSlaves = config.readNumEntry( "maxInstances", 1);
+
+ QString tmp = config.readEntry( "input" );
+ if ( tmp == "filesystem" )
+ m_inputType = KProtocolInfo::T_FILESYSTEM;
+ else if ( tmp == "stream" )
+ m_inputType = KProtocolInfo::T_STREAM;
+ else
+ m_inputType = KProtocolInfo::T_NONE;
+
+ tmp = config.readEntry( "output" );
+ if ( tmp == "filesystem" )
+ m_outputType = KProtocolInfo::T_FILESYSTEM;
+ else if ( tmp == "stream" )
+ m_outputType = KProtocolInfo::T_STREAM;
+ else
+ m_outputType = KProtocolInfo::T_NONE;
+
+ d->docPath = config.readPathEntry( "DocPath" );
+ d->protClass = config.readEntry( "Class" ).lower();
+ if (d->protClass[0] != ':')
+ d->protClass.prepend(':');
+
+ QStringList extraNames = config.readListEntry( "ExtraNames" );
+ QStringList extraTypes = config.readListEntry( "ExtraTypes" );
+ QStringList::Iterator it = extraNames.begin();
+ QStringList::Iterator typeit = extraTypes.begin();
+ for( ; it != extraNames.end() && typeit != extraTypes.end(); ++it, ++typeit ) {
+ d->extraFields.append( ExtraField( *it, *typeit ) );
+ }
+
+ d->showPreviews = config.readBoolEntry( "ShowPreviews", d->protClass == ":local" );
+
+ tmp = config.readEntry( "URIMode", QString::null ).lower();
+ if (tmp == "rawuri")
+ d->uriMode = KURL::RawURI;
+ else if (tmp == "mailto")
+ d->uriMode = KURL::Mailto;
+ else if (tmp == "url")
+ d->uriMode = KURL::URL;
+ else
+ d->uriMode = KURL::Auto;
+
+ d->capabilities = config.readListEntry( "Capabilities" );
+ d->proxyProtocol = config.readEntry( "ProxiedBy" );
+}
+
+KProtocolInfo::KProtocolInfo( QDataStream& _str, int offset) :
+ KSycocaEntry( _str, offset)
+{
+ d = new KProtocolInfoPrivate;
+ load( _str );
+}
+
+KProtocolInfo::~KProtocolInfo()
+{
+ delete d;
+}
+
+void
+KProtocolInfo::load( QDataStream& _str)
+{
+ // You may add new fields at the end. Make sure to update the version
+ // number in ksycoca.h
+ Q_INT32 i_inputType, i_outputType;
+ Q_INT8 i_isSourceProtocol, i_isHelperProtocol,
+ i_supportsListing, i_supportsReading,
+ i_supportsWriting, i_supportsMakeDir,
+ i_supportsDeleting, i_supportsLinking,
+ i_supportsMoving, i_determineMimetypeFromExtension,
+ i_canCopyFromFile, i_canCopyToFile, i_showPreviews,
+ i_uriMode, i_canRenameFromFile, i_canRenameToFile,
+ i_canDeleteRecursive, i_fileNameUsedForCopying;
+
+ _str >> m_name >> m_exec >> m_listing >> m_defaultMimetype
+ >> i_determineMimetypeFromExtension
+ >> m_icon
+ >> i_inputType >> i_outputType
+ >> i_isSourceProtocol >> i_isHelperProtocol
+ >> i_supportsListing >> i_supportsReading
+ >> i_supportsWriting >> i_supportsMakeDir
+ >> i_supportsDeleting >> i_supportsLinking
+ >> i_supportsMoving
+ >> i_canCopyFromFile >> i_canCopyToFile
+ >> m_config >> m_maxSlaves >> d->docPath >> d->protClass
+ >> d->extraFields >> i_showPreviews >> i_uriMode
+ >> d->capabilities >> d->proxyProtocol
+ >> i_canRenameFromFile >> i_canRenameToFile
+ >> i_canDeleteRecursive >> i_fileNameUsedForCopying;
+
+ m_inputType = (Type) i_inputType;
+ m_outputType = (Type) i_outputType;
+ m_isSourceProtocol = (i_isSourceProtocol != 0);
+ m_isHelperProtocol = (i_isHelperProtocol != 0);
+ m_supportsListing = (i_supportsListing != 0);
+ m_supportsReading = (i_supportsReading != 0);
+ m_supportsWriting = (i_supportsWriting != 0);
+ m_supportsMakeDir = (i_supportsMakeDir != 0);
+ m_supportsDeleting = (i_supportsDeleting != 0);
+ m_supportsLinking = (i_supportsLinking != 0);
+ m_supportsMoving = (i_supportsMoving != 0);
+ m_canCopyFromFile = (i_canCopyFromFile != 0);
+ m_canCopyToFile = (i_canCopyToFile != 0);
+ d->canRenameFromFile = (i_canRenameFromFile != 0);
+ d->canRenameToFile = (i_canRenameToFile != 0);
+ d->canDeleteRecursive = (i_canDeleteRecursive != 0);
+ d->fileNameUsedForCopying = (i_fileNameUsedForCopying != 0);
+ m_determineMimetypeFromExtension = (i_determineMimetypeFromExtension != 0);
+ d->showPreviews = (i_showPreviews != 0);
+ d->uriMode = (KURL::URIMode) i_uriMode;
+}
+
+void
+KProtocolInfo::save( QDataStream& _str)
+{
+ KSycocaEntry::save( _str );
+
+ // You may add new fields at the end. Make sure to update the version
+ // number in ksycoca.h
+ Q_INT32 i_inputType, i_outputType;
+ Q_INT8 i_isSourceProtocol, i_isHelperProtocol,
+ i_supportsListing, i_supportsReading,
+ i_supportsWriting, i_supportsMakeDir,
+ i_supportsDeleting, i_supportsLinking,
+ i_supportsMoving, i_determineMimetypeFromExtension,
+ i_canCopyFromFile, i_canCopyToFile, i_showPreviews,
+ i_uriMode, i_canRenameFromFile, i_canRenameToFile,
+ i_canDeleteRecursive, i_fileNameUsedForCopying;
+
+ i_inputType = (Q_INT32) m_inputType;
+ i_outputType = (Q_INT32) m_outputType;
+ i_isSourceProtocol = m_isSourceProtocol ? 1 : 0;
+ i_isHelperProtocol = m_isHelperProtocol ? 1 : 0;
+ i_supportsListing = m_supportsListing ? 1 : 0;
+ i_supportsReading = m_supportsReading ? 1 : 0;
+ i_supportsWriting = m_supportsWriting ? 1 : 0;
+ i_supportsMakeDir = m_supportsMakeDir ? 1 : 0;
+ i_supportsDeleting = m_supportsDeleting ? 1 : 0;
+ i_supportsLinking = m_supportsLinking ? 1 : 0;
+ i_supportsMoving = m_supportsMoving ? 1 : 0;
+ i_canCopyFromFile = m_canCopyFromFile ? 1 : 0;
+ i_canCopyToFile = m_canCopyToFile ? 1 : 0;
+ i_canRenameFromFile = d->canRenameFromFile ? 1 : 0;
+ i_canRenameToFile = d->canRenameToFile ? 1 : 0;
+ i_canDeleteRecursive = d->canDeleteRecursive ? 1 : 0;
+ i_fileNameUsedForCopying = d->fileNameUsedForCopying ? 1 : 0;
+ i_determineMimetypeFromExtension = m_determineMimetypeFromExtension ? 1 : 0;
+ i_showPreviews = d->showPreviews ? 1 : 0;
+ i_uriMode = d->uriMode;
+
+ _str << m_name << m_exec << m_listing << m_defaultMimetype
+ << i_determineMimetypeFromExtension
+ << m_icon
+ << i_inputType << i_outputType
+ << i_isSourceProtocol << i_isHelperProtocol
+ << i_supportsListing << i_supportsReading
+ << i_supportsWriting << i_supportsMakeDir
+ << i_supportsDeleting << i_supportsLinking
+ << i_supportsMoving
+ << i_canCopyFromFile << i_canCopyToFile
+ << m_config << m_maxSlaves << d->docPath << d->protClass
+ << d->extraFields << i_showPreviews << i_uriMode
+ << d->capabilities << d->proxyProtocol
+ << i_canRenameFromFile << i_canRenameToFile
+ << i_canDeleteRecursive << i_fileNameUsedForCopying;
+}
+
+
+//
+// Static functions:
+//
+
+QStringList KProtocolInfo::protocols()
+{
+ return KProtocolInfoFactory::self()->protocols();
+}
+
+bool KProtocolInfo::isSourceProtocol( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_isSourceProtocol;
+}
+
+bool KProtocolInfo::isFilterProtocol( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return !prot->m_isSourceProtocol;
+}
+
+bool KProtocolInfo::isHelperProtocol( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_isHelperProtocol;
+}
+
+bool KProtocolInfo::isKnownProtocol( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ return ( prot != 0);
+}
+
+bool KProtocolInfo::supportsListing( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsListing;
+}
+
+QStringList KProtocolInfo::listing( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QStringList();
+
+ return prot->m_listing;
+}
+
+bool KProtocolInfo::supportsReading( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsReading;
+}
+
+bool KProtocolInfo::supportsWriting( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsWriting;
+}
+
+bool KProtocolInfo::supportsMakeDir( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsMakeDir;
+}
+
+bool KProtocolInfo::supportsDeleting( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsDeleting;
+}
+
+bool KProtocolInfo::supportsLinking( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsLinking;
+}
+
+bool KProtocolInfo::supportsMoving( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsMoving;
+}
+
+bool KProtocolInfo::canCopyFromFile( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_canCopyFromFile;
+}
+
+
+bool KProtocolInfo::canCopyToFile( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_canCopyToFile;
+}
+
+QString KProtocolInfo::icon( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString::fromLatin1("unknown");
+
+ return prot->m_icon;
+}
+
+QString KProtocolInfo::config( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString::null;
+
+ return QString("kio_%1rc").arg(prot->m_config);
+}
+
+int KProtocolInfo::maxSlaves( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return 1;
+
+ return prot->m_maxSlaves;
+}
+
+QString KProtocolInfo::defaultMimetype( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString::null;
+
+ return prot->m_defaultMimetype;
+}
+
+bool KProtocolInfo::determineMimetypeFromExtension( const QString &_protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _protocol );
+ if ( !prot )
+ return true;
+
+ return prot->m_determineMimetypeFromExtension;
+}
+
+QString KProtocolInfo::exec( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString::null;
+
+ return prot->m_exec;
+}
+
+KProtocolInfo::Type KProtocolInfo::inputType( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return T_NONE;
+
+ return prot->m_inputType;
+}
+
+KProtocolInfo::Type KProtocolInfo::outputType( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return T_NONE;
+
+ return prot->m_outputType;
+}
+
+KProtocolInfo::ExtraFieldList KProtocolInfo::extraFields( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(url.protocol());
+ if ( !prot )
+ return ExtraFieldList();
+
+ return prot->d->extraFields;
+}
+
+QString KProtocolInfo::docPath( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString::null;
+
+ return prot->d->docPath;
+}
+
+QString KProtocolInfo::protocolClass( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString::null;
+
+ return prot->d->protClass;
+}
+
+bool KProtocolInfo::showFilePreview( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->d->showPreviews;
+}
+
+KURL::URIMode KProtocolInfo::uriParseMode( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return KURL::Auto;
+
+ return prot->d->uriMode;
+}
+
+QStringList KProtocolInfo::capabilities( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QStringList();
+
+ return prot->d->capabilities;
+}
+
+QString KProtocolInfo::proxiedBy( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString::null;
+
+ return prot->d->proxyProtocol;
+}
+
+bool KProtocolInfo::canRenameFromFile() const
+{
+ return d->canRenameFromFile;
+}
+
+bool KProtocolInfo::canRenameToFile() const
+{
+ return d->canRenameToFile;
+}
+
+bool KProtocolInfo::canDeleteRecursive() const
+{
+ return d->canDeleteRecursive;
+}
+
+KProtocolInfo::FileNameUsedForCopying KProtocolInfo::fileNameUsedForCopying() const
+{
+ return d->fileNameUsedForCopying ? Name : FromURL;
+}
+
+QDataStream& operator>>( QDataStream& s, KProtocolInfo::ExtraField& field ) {
+ s >> field.name;
+ s >> field.type;
+ return s;
+}
+
+QDataStream& operator<<( QDataStream& s, const KProtocolInfo::ExtraField& field ) {
+ s << field.name;
+ s << field.type;
+ return s;
+}
+
+// KURL based static functions are implemented in ../kio/kio/kprotocolinfo.cpp
+
+void KProtocolInfo::virtual_hook( int id, void* data )
+{ KSycocaEntry::virtual_hook( id, data ); }
+
diff --git a/kdecore/kprotocolinfofactory.cpp b/kdecore/kprotocolinfofactory.cpp
new file mode 100644
index 000000000..fc2544853
--- /dev/null
+++ b/kdecore/kprotocolinfofactory.cpp
@@ -0,0 +1,113 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <ksycoca.h>
+#include <ksycocadict.h>
+
+#include "kprotocolinfofactory.h"
+
+
+KProtocolInfoFactory* KProtocolInfoFactory::_self = 0;
+
+KProtocolInfoFactory::KProtocolInfoFactory() : KSycocaFactory( KST_KProtocolInfoFactory )
+{
+ _self = this;
+}
+
+KProtocolInfoFactory::~KProtocolInfoFactory()
+{
+ _self = 0;
+}
+
+
+KProtocolInfo*
+KProtocolInfoFactory::createEntry(int offset)
+{
+ KProtocolInfo *info = 0;
+ KSycocaType type;
+ QDataStream *str = KSycoca::self()->findEntry(offset, type);
+ switch (type)
+ {
+ case KST_KProtocolInfo:
+ info = new KProtocolInfo(*str, offset);
+ break;
+ default:
+ return 0;
+ }
+ if (!info->isValid())
+ {
+ delete info;
+ info = 0;
+ }
+ return info;
+}
+
+
+QStringList KProtocolInfoFactory::protocols()
+{
+ QStringList res;
+
+ KSycocaEntry::List list = allEntries();
+ for( KSycocaEntry::List::Iterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ KSycocaEntry *entry = (*it).data();
+ KProtocolInfo *info = static_cast<KProtocolInfo *>(entry);
+
+ res.append( info->name() );
+ }
+
+ return res;
+}
+
+KProtocolInfo *
+KProtocolInfoFactory::findProtocol(const QString &protocol)
+{
+ if (!m_sycocaDict) return 0; // Error!
+
+ QMap<QString,KProtocolInfo::Ptr>::iterator it = m_cache.find(protocol);
+ if (it != m_cache.end())
+ return (*it);
+
+ int offset;
+
+ offset = m_sycocaDict->find_string( protocol );
+
+ if (!offset) return 0; // Not found;
+
+ KProtocolInfo *info = createEntry(offset);
+
+ if (info && (info->name() != protocol))
+ {
+ // No it wasn't...
+ delete info;
+ info = 0; // Not found
+ }
+ m_cache.insert(protocol,info);
+ return info;
+}
+
+void KProtocolInfoFactory::virtual_hook( int id, void* data )
+{ KSycocaFactory::virtual_hook( id, data ); }
+
diff --git a/kdecore/kprotocolinfofactory.h b/kdecore/kprotocolinfofactory.h
new file mode 100644
index 000000000..822f5b455
--- /dev/null
+++ b/kdecore/kprotocolinfofactory.h
@@ -0,0 +1,91 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000,2003 Waldo Bastian <bastian@kde.org>
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __kprotocolinfofactory_h__
+#define __kprotocolinfofactory_h__
+
+#include "../kio/kio/kprotocolinfo.h"
+
+#include <qmap.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <kurl.h>
+#include <ksycocafactory.h>
+
+class KProtocolInfoPrivate;
+
+/**
+ * KProtocolInfoFactory is a factory for getting
+ * KProtocolInfo. The factory is a singleton
+ * (only one instance can exist).
+ *
+ * @short Factory for KProtocolInfo
+ */
+class KDECORE_EXPORT KProtocolInfoFactory : public KSycocaFactory
+{
+ K_SYCOCAFACTORY( KST_KProtocolInfoFactory )
+public:
+ /**
+ * The instance of the KProtocolInfoFactory.
+ * @return the factory instance
+ */
+ static KProtocolInfoFactory* self()
+ { if ( !_self) new KProtocolInfoFactory(); return _self; }
+ /** \internal */
+ KProtocolInfoFactory();
+ virtual ~KProtocolInfoFactory();
+
+ /*
+ * Returns protocol info for @p protocol.
+ *
+ * Does not take proxy settings into account.
+ * @param protocol the protocol to search for
+ * @return the pointer to the KProtocolInfo, or 0 if not found
+ */
+ KProtocolInfo *findProtocol(const QString &protocol);
+
+ /**
+ * Returns list of all known protocols.
+ * @return a list of all protocols
+ */
+ QStringList protocols();
+protected:
+
+ /**
+ * @internal Not used.
+ */
+ virtual KSycocaEntry *createEntry(const QString &, const char *)
+ { return 0; }
+
+ /**
+ * @internal
+ */
+ virtual KProtocolInfo *createEntry(int offset);
+
+protected:
+ static KProtocolInfoFactory *_self;
+
+ QMap<QString,KProtocolInfo::Ptr> m_cache;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KProtocolInfoFactoryPrivate* d;
+};
+
+#endif
diff --git a/kdecore/kpty.cpp b/kdecore/kpty.cpp
new file mode 100644
index 000000000..27cc3c51b
--- /dev/null
+++ b/kdecore/kpty.cpp
@@ -0,0 +1,541 @@
+/*
+
+ This file is part of the KDE libraries
+ Copyright (C) 1997-2002 The Konsole Developers
+ Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
+ Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include "kpty.h"
+#include "kprocess.h"
+
+#ifdef __sgi
+#define __svr4__
+#endif
+
+#ifdef __osf__
+#define _OSF_SOURCE
+#include <float.h>
+#endif
+
+#ifdef _AIX
+#define _ALL_SOURCE
+#endif
+
+// __USE_XOPEN isn't defined by default in ICC
+// (needed for ptsname(), grantpt() and unlockpt())
+#ifdef __INTEL_COMPILER
+# ifndef __USE_XOPEN
+# define __USE_XOPEN
+# endif
+#endif
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#ifdef HAVE_SYS_STROPTS_H
+# include <sys/stropts.h> // Defines I_PUSH
+# define _NEW_TTY_CTRL
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <grp.h>
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+# define USE_LOGIN
+#elif defined(HAVE_UTIL_H)
+# include <util.h>
+# define USE_LOGIN
+#endif
+
+#ifdef USE_LOGIN
+# include <utmp.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+/* for HP-UX (some versions) the extern C is needed, and for other
+ platforms it doesn't hurt */
+extern "C" {
+# include <termios.h>
+}
+#endif
+
+#if !defined(__osf__)
+# ifdef HAVE_TERMIO_H
+/* needed at least on AIX */
+# include <termio.h>
+# endif
+#endif
+
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
+# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
+#else
+# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
+# define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
+# else
+# define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
+# endif
+#endif
+
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
+# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
+#else
+# if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
+# define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
+# else
+# define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
+# endif
+#endif
+
+#if defined (_HPUX_SOURCE)
+# define _TERMIOS_INCLUDED
+# include <bsdtty.h>
+#endif
+
+#if defined(HAVE_PTY_H)
+# include <pty.h>
+#endif
+
+#include <kdebug.h>
+#include <kstandarddirs.h> // locate
+
+#ifndef CINTR
+#define CINTR 0x03
+#endif
+#ifndef CQUIT
+#define CQUIT 0x1c
+#endif
+#ifndef CERASE
+#define CERASE 0x7f
+#endif
+
+#define TTY_GROUP "tty"
+
+///////////////////////
+// private functions //
+///////////////////////
+
+#ifdef HAVE_UTEMPTER
+class KProcess_Utmp : public KProcess
+{
+public:
+ int commSetupDoneC()
+ {
+ dup2(cmdFd, 0);
+ dup2(cmdFd, 1);
+ dup2(cmdFd, 3);
+ return 1;
+ }
+ int cmdFd;
+};
+#endif
+
+#define BASE_CHOWN "kgrantpty"
+
+
+
+//////////////////
+// private data //
+//////////////////
+
+struct KPtyPrivate {
+ KPtyPrivate() :
+ xonXoff(false),
+ utf8(false),
+ masterFd(-1), slaveFd(-1)
+ {
+ memset(&winSize, 0, sizeof(winSize));
+ winSize.ws_row = 24;
+ winSize.ws_col = 80;
+ }
+
+ bool xonXoff : 1;
+ bool utf8 : 1;
+ int masterFd;
+ int slaveFd;
+ struct winsize winSize;
+
+ QCString ttyName;
+};
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KPty::KPty()
+{
+ d = new KPtyPrivate;
+}
+
+KPty::~KPty()
+{
+ close();
+ delete d;
+}
+
+bool KPty::open()
+{
+ if (d->masterFd >= 0)
+ return true;
+
+ QCString ptyName;
+
+ // Find a master pty that we can open ////////////////////////////////
+
+ // Because not all the pty animals are created equal, they want to
+ // be opened by several different methods.
+
+ // We try, as we know them, one by one.
+
+#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT)
+#ifdef _AIX
+ d->masterFd = ::open("/dev/ptc",O_RDWR);
+#else
+ d->masterFd = ::open("/dev/ptmx",O_RDWR);
+#endif
+ if (d->masterFd >= 0)
+ {
+ char *ptsn = ptsname(d->masterFd);
+ if (ptsn) {
+ grantpt(d->masterFd);
+ d->ttyName = ptsn;
+ goto gotpty;
+ } else {
+ ::close(d->masterFd);
+ d->masterFd = -1;
+ }
+ }
+#endif
+
+ // Linux device names, FIXME: Trouble on other systems?
+ for (const char* s3 = "pqrstuvwxyzabcdefghijklmno"; *s3; s3++)
+ {
+ for (const char* s4 = "0123456789abcdefghijklmnopqrstuvwxyz"; *s4; s4++)
+ {
+ ptyName.sprintf("/dev/pty%c%c", *s3, *s4);
+ d->ttyName.sprintf("/dev/tty%c%c", *s3, *s4);
+
+ d->masterFd = ::open(ptyName.data(), O_RDWR);
+ if (d->masterFd >= 0)
+ {
+#ifdef __sun
+ /* Need to check the process group of the pty.
+ * If it exists, then the slave pty is in use,
+ * and we need to get another one.
+ */
+ int pgrp_rtn;
+ if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
+ ::close(d->masterFd);
+ d->masterFd = -1;
+ continue;
+ }
+#endif /* sun */
+ if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
+ {
+ if (!geteuid())
+ {
+ struct group* p = getgrnam(TTY_GROUP);
+ if (!p)
+ p = getgrnam("wheel");
+ gid_t gid = p ? p->gr_gid : getgid ();
+
+ chown(d->ttyName.data(), getuid(), gid);
+ chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
+ }
+ goto gotpty;
+ }
+ ::close(d->masterFd);
+ d->masterFd = -1;
+ }
+ }
+ }
+
+ kdWarning(175) << "Can't open a pseudo teletype" << endl;
+ return false;
+
+ gotpty:
+ struct stat st;
+ if (stat(d->ttyName.data(), &st))
+ return false; // this just cannot happen ... *cough* Yeah right, I just
+ // had it happen when pty #349 was allocated. I guess
+ // there was some sort of leak? I only had a few open.
+ if (((st.st_uid != getuid()) ||
+ (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
+ !chownpty(true))
+ {
+ kdWarning(175)
+ << "chownpty failed for device " << ptyName << "::" << d->ttyName
+ << "\nThis means the communication can be eavesdropped." << endl;
+ }
+
+#ifdef BSD
+ revoke(d->ttyName.data());
+#endif
+
+#ifdef HAVE_UNLOCKPT
+ unlockpt(d->masterFd);
+#endif
+
+ d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
+ if (d->slaveFd < 0)
+ {
+ kdWarning(175) << "Can't open slave pseudo teletype" << endl;
+ ::close(d->masterFd);
+ d->masterFd = -1;
+ return false;
+ }
+
+#if (defined(__svr4__) || defined(__sgi__))
+ // Solaris
+ ioctl(d->slaveFd, I_PUSH, "ptem");
+ ioctl(d->slaveFd, I_PUSH, "ldterm");
+#endif
+
+ // set xon/xoff & control keystrokes
+ // without the '::' some version of HP-UX thinks, this declares
+ // the struct in this class, in this method, and fails to find
+ // the correct tc[gs]etattr
+ struct ::termios ttmode;
+
+ _tcgetattr(d->slaveFd, &ttmode);
+
+ if (!d->xonXoff)
+ ttmode.c_iflag &= ~(IXOFF | IXON);
+ else
+ ttmode.c_iflag |= (IXOFF | IXON);
+
+#ifdef IUTF8
+ if (!d->utf8)
+ ttmode.c_iflag &= ~IUTF8;
+ else
+ ttmode.c_iflag |= IUTF8;
+#endif
+
+ ttmode.c_cc[VINTR] = CINTR;
+ ttmode.c_cc[VQUIT] = CQUIT;
+ ttmode.c_cc[VERASE] = CERASE;
+
+ _tcsetattr(d->slaveFd, &ttmode);
+
+ // set screen size
+ ioctl(d->slaveFd, TIOCSWINSZ, (char *)&d->winSize);
+
+ fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
+ fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
+
+ return true;
+}
+
+void KPty::close()
+{
+ if (d->masterFd < 0)
+ return;
+ // don't bother resetting unix98 pty, it will go away after closing master anyway.
+ if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
+ if (!geteuid()) {
+ struct stat st;
+ if (!stat(d->ttyName.data(), &st)) {
+ chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
+ chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ }
+ } else {
+ fcntl(d->masterFd, F_SETFD, 0);
+ chownpty(false);
+ }
+ }
+ ::close(d->slaveFd);
+ ::close(d->masterFd);
+ d->masterFd = d->slaveFd = -1;
+}
+
+void KPty::setCTty()
+{
+ // Setup job control //////////////////////////////////
+
+ // Become session leader, process group leader,
+ // and get rid of the old controlling terminal.
+ setsid();
+
+ // make our slave pty the new controlling terminal.
+#ifdef TIOCSCTTY
+ ioctl(d->slaveFd, TIOCSCTTY, 0);
+#else
+ // SVR4 hack: the first tty opened after setsid() becomes controlling tty
+ ::close(::open(d->ttyName, O_WRONLY, 0));
+#endif
+
+ // make our new process group the foreground group on the pty
+ int pgrp = getpid();
+#if defined(_POSIX_VERSION) || defined(__svr4__)
+ tcsetpgrp (d->slaveFd, pgrp);
+#elif defined(TIOCSPGRP)
+ ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
+#endif
+}
+
+void KPty::login(const char *user, const char *remotehost)
+{
+#ifdef HAVE_UTEMPTER
+ KProcess_Utmp utmp;
+ utmp.cmdFd = d->masterFd;
+ utmp << "/usr/sbin/utempter" << "-a" << d->ttyName << "";
+ utmp.start(KProcess::Block);
+ Q_UNUSED(user);
+ Q_UNUSED(remotehost);
+#elif defined(USE_LOGIN)
+ const char *str_ptr;
+ struct utmp l_struct;
+ memset(&l_struct, 0, sizeof(struct utmp));
+ // note: strncpy without terminators _is_ correct here. man 4 utmp
+
+ if (user)
+ strncpy(l_struct.ut_name, user, UT_NAMESIZE);
+
+ if (remotehost)
+ strncpy(l_struct.ut_host, remotehost, UT_HOSTSIZE);
+
+# ifndef __GLIBC__
+ str_ptr = d->ttyName.data();
+ if (!memcmp(str_ptr, "/dev/", 5))
+ str_ptr += 5;
+ strncpy(l_struct.ut_line, str_ptr, UT_LINESIZE);
+# endif
+
+ // Handle 64-bit time_t properly, where it may be larger
+ // than the integral type of ut_time.
+ {
+ time_t ut_time_temp;
+ time(&ut_time_temp);
+ l_struct.ut_time=ut_time_temp;
+ }
+
+ ::login(&l_struct);
+#else
+ Q_UNUSED(user);
+ Q_UNUSED(remotehost);
+#endif
+}
+
+void KPty::logout()
+{
+#ifdef HAVE_UTEMPTER
+ KProcess_Utmp utmp;
+ utmp.cmdFd = d->masterFd;
+ utmp << "/usr/sbin/utempter" << "-d" << d->ttyName;
+ utmp.start(KProcess::Block);
+#elif defined(USE_LOGIN)
+ const char *str_ptr = d->ttyName.data();
+ if (!memcmp(str_ptr, "/dev/", 5))
+ str_ptr += 5;
+# ifdef __GLIBC__
+ else {
+ const char *sl_ptr = strrchr(str_ptr, '/');
+ if (sl_ptr)
+ str_ptr = sl_ptr + 1;
+ }
+# endif
+ ::logout(str_ptr);
+#endif
+}
+
+void KPty::setWinSize(int lines, int columns)
+{
+ d->winSize.ws_row = (unsigned short)lines;
+ d->winSize.ws_col = (unsigned short)columns;
+ if (d->masterFd >= 0)
+ ioctl( d->masterFd, TIOCSWINSZ, (char *)&d->winSize );
+}
+
+void KPty::setXonXoff(bool useXonXoff)
+{
+ d->xonXoff = useXonXoff;
+ if (d->masterFd >= 0) {
+ // without the '::' some version of HP-UX thinks, this declares
+ // the struct in this class, in this method, and fails to find
+ // the correct tc[gs]etattr
+ struct ::termios ttmode;
+
+ _tcgetattr(d->masterFd, &ttmode);
+
+ if (!useXonXoff)
+ ttmode.c_iflag &= ~(IXOFF | IXON);
+ else
+ ttmode.c_iflag |= (IXOFF | IXON);
+
+ _tcsetattr(d->masterFd, &ttmode);
+ }
+}
+
+void KPty::setUtf8Mode(bool useUtf8)
+{
+ d->utf8 = useUtf8;
+#ifdef IUTF8
+ if (d->masterFd >= 0) {
+ // without the '::' some version of HP-UX thinks, this declares
+ // the struct in this class, in this method, and fails to find
+ // the correct tc[gs]etattr
+ struct ::termios ttmode;
+
+ _tcgetattr(d->masterFd, &ttmode);
+
+ if (!useUtf8)
+ ttmode.c_iflag &= ~IUTF8;
+ else
+ ttmode.c_iflag |= IUTF8;
+
+ _tcsetattr(d->masterFd, &ttmode);
+ }
+#endif
+}
+
+const char *KPty::ttyName() const
+{
+ return d->ttyName.data();
+}
+
+int KPty::masterFd() const
+{
+ return d->masterFd;
+}
+
+int KPty::slaveFd() const
+{
+ return d->slaveFd;
+}
+
+// private
+bool KPty::chownpty(bool grant)
+{
+ KProcess proc;
+ proc << locate("exe", BASE_CHOWN) << (grant?"--grant":"--revoke") << QString::number(d->masterFd);
+ return proc.start(KProcess::Block) && proc.normalExit() && !proc.exitStatus();
+}
+
diff --git a/kdecore/kpty.h b/kdecore/kpty.h
new file mode 100644
index 000000000..51d069ac0
--- /dev/null
+++ b/kdecore/kpty.h
@@ -0,0 +1,149 @@
+/* This file is part of the KDE libraries
+
+ Copyright (C) 1997-2002 The Konsole Developers
+ Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
+ Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kpty_h__
+#define __kpty_h__
+
+#include <qglobal.h>
+#include <kdelibs_export.h>
+
+#ifdef Q_OS_UNIX
+
+struct KPtyPrivate;
+
+/**
+ * Provides a high level representation of a pseudo tty pair, including
+ * utmp support.
+ * ...
+ *
+ * @since 3.2
+ **/
+class KDECORE_EXPORT KPty {
+
+public:
+
+ /**
+ * Constructor
+ */
+ KPty();
+
+ /**
+ * Destructor:
+ *
+ * If the pty is still open, it will be closed. Note, however, that
+ * an utmp registration is @em not undone.
+ */
+ ~KPty();
+
+ /**
+ * Create a pty master/slave pair.
+ *
+ * @return true if a pty pair was successfully opened
+ */
+ bool open();
+
+ /**
+ * Close the pty master/slave pair.
+ */
+ void close();
+
+ /**
+ * Creates a new session and process group and makes this pty the
+ * controlling tty.
+ */
+ void setCTty();
+
+ /**
+ * Creates an utmp entry for the tty.
+ * This function must be called after calling setCTty and
+ * making this pty the stdin.
+ * @param user the user to be logged on
+ * @param remotehost the host from which the login is coming. This is
+ * @em not the local host. For remote logins it should be the hostname
+ * of the client. For local logins from inside an X session it should
+ * be the name of the X display. Otherwise it should be empty.
+ */
+ void login(const char *user = 0, const char *remotehost = 0);
+
+ /**
+ * Removes the utmp entry for this tty.
+ */
+ void logout();
+
+ /**
+ * Change the logical (screen) size of the pty.
+ * The default is 24 lines by 80 columns.
+ *
+ * @param lines the number of rows
+ * @param columns the number of columns
+ */
+ void setWinSize(int lines, int columns);
+
+ /**
+ * Set whether the pty should honor Xon/Xoff flow control.
+ *
+ * Xon/Xoff flow control is off by default.
+ *
+ * @param useXonXoff true if Xon/Xoff flow control should be used.
+ */
+ void setXonXoff(bool useXonXoff);
+
+ /**
+ * Set the pty in utf8 mode on systems that support it.
+ *
+ * See the man page of "stty iutf8" for more info.
+ *
+ * @since 3.4
+ */
+ void setUtf8Mode(bool useUtf8);
+
+
+ /**
+ * @return the name of the slave pty device.
+ *
+ * This function should be called only while the pty is open.
+ */
+ const char *ttyName() const;
+
+ /**
+ * @return the file descriptor of the master pty
+ *
+ * This function should be called only while the pty is open.
+ */
+ int masterFd() const;
+
+ /**
+ * @return the file descriptor of the slave pty
+ *
+ * This function should be called only while the pty is open.
+ */
+ int slaveFd() const;
+
+private:
+ bool chownpty(bool grant);
+
+ KPtyPrivate *d;
+};
+
+#endif //Q_OS_UNIX
+#endif
+
diff --git a/kdecore/kqiodevicegzip_p.cpp b/kdecore/kqiodevicegzip_p.cpp
new file mode 100644
index 000000000..cb0cd2fe6
--- /dev/null
+++ b/kdecore/kqiodevicegzip_p.cpp
@@ -0,0 +1,159 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2005 Nicolas GOUTTE <nicog@snafu.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// TODO: more error report and control
+
+#include <qstring.h>
+#include "kqiodevicegzip_p.h"
+
+KQIODeviceGZip::KQIODeviceGZip(const QString& filename)
+{
+ m_gzfile=0;
+ m_ungetchar=-1;
+ m_filename=filename;
+ setFlags(IO_Sequential); // We have no direct access, so it is sequential!
+ // NOTE: "sequential" also means that you cannot use size()
+}
+
+KQIODeviceGZip::~KQIODeviceGZip(void)
+{
+ if (m_gzfile)
+ close();
+}
+
+bool KQIODeviceGZip::open(int mode)
+{
+ if (m_gzfile)
+ close(); // One file is already open, so close it first.
+ if (m_filename.isEmpty())
+ return false; // No file name, cannot open!
+
+ if (IO_ReadOnly==mode)
+ {
+ m_gzfile=gzopen(QFile::encodeName(m_filename),"rb");
+ }
+ else if (IO_WriteOnly==mode)
+ {
+ m_gzfile=gzopen(QFile::encodeName(m_filename),"wb9"); // Always set best compression
+ }
+ else
+ {
+ // We only support read only or write only, nothing else!
+ return false;
+ }
+ return (m_gzfile!=0);
+}
+
+void KQIODeviceGZip::close(void)
+{
+ if (m_gzfile)
+ {
+ gzclose(m_gzfile);
+ m_gzfile=0;
+ }
+}
+
+void KQIODeviceGZip::flush(void)
+{
+ // Always try to flush, do not return any error!
+ if (m_gzfile)
+ {
+ gzflush(m_gzfile,Z_SYNC_FLUSH);
+ }
+}
+
+QIODevice::Offset KQIODeviceGZip::size(void) const
+{
+ return 0; // You cannot determine size!
+}
+
+QIODevice::Offset KQIODeviceGZip::at() const
+{
+ if (!m_gzfile)
+ return 0;
+ return gztell(m_gzfile);
+}
+
+bool KQIODeviceGZip::at(QIODevice::Offset pos)
+{
+ if (!m_gzfile)
+ return false;
+ return (gzseek(m_gzfile,pos,SEEK_SET)>=0);
+}
+
+bool KQIODeviceGZip::atEnd() const
+{
+ if (!m_gzfile)
+ return true;
+ return gzeof(m_gzfile);
+}
+
+bool KQIODeviceGZip::reset(void)
+{
+ if (!m_gzfile)
+ return false; //Say we arew at end of file
+ return (gzrewind(m_gzfile)>=0);
+}
+
+Q_LONG KQIODeviceGZip::readBlock( char *data, Q_ULONG maxlen )
+{
+ Q_LONG result=0;
+ if (m_gzfile)
+ {
+ result=gzread(m_gzfile,data,maxlen);
+ if (result<0) result=0;
+ }
+ return result;
+}
+
+Q_LONG KQIODeviceGZip::writeBlock( const char *data, Q_ULONG len )
+{
+ Q_ULONG result=0;
+ if (m_gzfile)
+ {
+ result=gzwrite(m_gzfile,(char*)data,len);
+ }
+ return result;
+}
+
+int KQIODeviceGZip::getch()
+{
+ if (m_ungetchar>0)
+ {
+ const int ch=m_ungetchar;
+ m_ungetchar=-1;
+ return ch;
+ }
+ if (!m_gzfile)
+ return -1;
+ return gzgetc(m_gzfile);
+}
+
+int KQIODeviceGZip::putch( int ch)
+{
+ if (!m_gzfile)
+ return -1;
+ return gzputc(m_gzfile,ch);
+}
+
+int KQIODeviceGZip::ungetch(int ch)
+{
+ m_ungetchar=ch;
+ return ch;
+}
diff --git a/kdecore/kqiodevicegzip_p.h b/kdecore/kqiodevicegzip_p.h
new file mode 100644
index 000000000..c8ebe9be9
--- /dev/null
+++ b/kdecore/kqiodevicegzip_p.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2005 Nicolas GOUTTE <nicog@snafu.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KDELIBS_KQIODEVICEGZIP_H
+#define KDELIBS_KQIODEVICEGZIP_H
+
+#include <qiodevice.h>
+#include <qstring.h>
+#include <qfile.h>
+
+#include <zlib.h>
+
+
+/**
+ * \brief QIODevice class for a gzipped file
+ * \internal This class is internal to KDE.
+ * The class KFilterDev should be used instead.
+ */
+class KQIODeviceGZip : public QIODevice
+{
+public:
+ KQIODeviceGZip(const QString& filename);
+ ~KQIODeviceGZip(void);
+
+ bool open(int mode);
+ void close(void);
+ void flush(void);
+
+ Offset size(void) const;
+ Offset at(void) const;
+ bool at(Offset pos);
+ bool atEnd(void) const;
+ bool reset (void);
+
+ Q_LONG readBlock( char *data, Q_ULONG maxlen );
+ Q_LONG writeBlock( const char *data, Q_ULONG len );
+
+ int getch(void);
+ int putch(int ch);
+ int ungetch(int ch);
+private:
+ gzFile m_gzfile;
+ int m_ungetchar;
+ QString m_filename;
+};
+
+
+#endif // KDELIBS_KQIODEVICEGZIP_H
diff --git a/kdecore/krandomsequence.cpp b/kdecore/krandomsequence.cpp
new file mode 100644
index 000000000..415329e60
--- /dev/null
+++ b/kdecore/krandomsequence.cpp
@@ -0,0 +1,239 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Sean Harmer <sh@astro.keele.ac.uk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qptrlist.h>
+
+#include "krandomsequence.h"
+#include "kapplication.h"
+
+const int KRandomSequence::m_nShuffleTableSize = 32;
+
+//////////////////////////////////////////////////////////////////////////////
+// Construction / Destruction
+//////////////////////////////////////////////////////////////////////////////
+
+KRandomSequence::KRandomSequence( long lngSeed1 )
+{
+ // Seed the generator
+ setSeed( lngSeed1 );
+
+
+ // Set the size of the shuffle table
+ m_ShuffleArray = new long [m_nShuffleTableSize];
+}
+
+KRandomSequence::~KRandomSequence()
+{
+ delete [] m_ShuffleArray;
+}
+
+KRandomSequence::KRandomSequence(const KRandomSequence &a)
+{
+ // Set the size of the shuffle table
+ m_ShuffleArray = new long [m_nShuffleTableSize];
+ *this = a;
+}
+
+KRandomSequence &
+KRandomSequence::operator=(const KRandomSequence &a)
+{
+ m_lngSeed1 = a.m_lngSeed1;
+ m_lngSeed2 = a.m_lngSeed2;
+ m_lngShufflePos = a.m_lngShufflePos;
+ memcpy(m_ShuffleArray, a.m_ShuffleArray, sizeof(long)*m_nShuffleTableSize);
+ return *this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Member Functions
+//////////////////////////////////////////////////////////////////////////////
+
+void KRandomSequence::setSeed( long lngSeed1 )
+{
+ // Convert the positive seed number to a negative one so that the Draw()
+ // function can intialise itself the first time it is called. We just have
+ // to make sure that the seed used != 0 as zero perpetuates itself in a
+ // sequence of random numbers.
+ if ( lngSeed1 < 0 )
+ {
+ m_lngSeed1 = -1;
+ }
+ else if (lngSeed1 == 0)
+ {
+ m_lngSeed1 = -((KApplication::random() & ~1)+1);
+ }
+ else
+ {
+ m_lngSeed1 = -lngSeed1;
+ }
+}
+
+static const long sMod1 = 2147483563;
+static const long sMod2 = 2147483399;
+
+void KRandomSequence::Draw()
+{
+ static const long sMM1 = sMod1 - 1;
+ static const long sA1 = 40014;
+ static const long sA2 = 40692;
+ static const long sQ1 = 53668;
+ static const long sQ2 = 52774;
+ static const long sR1 = 12211;
+ static const long sR2 = 3791;
+ static const long sDiv = 1 + sMM1 / m_nShuffleTableSize;
+
+ // Long period (>2 * 10^18) random number generator of L'Ecuyer with
+ // Bayes-Durham shuffle and added safeguards. Returns a uniform random
+ // deviate between 0.0 and 1.0 (exclusive of the endpoint values). Call
+ // with a negative number to initialize; thereafter, do not alter idum
+ // between successive deviates in a sequence. RNMX should approximate
+ // the largest floating point value that is less than 1.
+
+ int j; // Index for the shuffle table
+ long k;
+
+ // Initialise
+ if ( m_lngSeed1 <= 0 )
+ {
+ m_lngSeed2 = m_lngSeed1;
+
+ // Load the shuffle table after 8 warm-ups
+ for ( j = m_nShuffleTableSize + 7; j >= 0; j-- )
+ {
+ k = m_lngSeed1 / sQ1;
+ m_lngSeed1 = sA1 * ( m_lngSeed1 - k*sQ1) - k*sR1;
+ if ( m_lngSeed1 < 0 )
+ {
+ m_lngSeed1 += sMod1;
+ }
+
+ if ( j < m_nShuffleTableSize )
+ {
+ m_ShuffleArray[j] = m_lngSeed1;
+ }
+ }
+
+ m_lngShufflePos = m_ShuffleArray[0];
+ }
+
+ // Start here when not initializing
+
+ // Compute m_lngSeed1 = ( lngIA1*m_lngSeed1 ) % lngIM1 without overflows
+ // by Schrage's method
+ k = m_lngSeed1 / sQ1;
+ m_lngSeed1 = sA1 * ( m_lngSeed1 - k*sQ1 ) - k*sR1;
+ if ( m_lngSeed1 < 0 )
+ {
+ m_lngSeed1 += sMod1;
+ }
+
+ // Compute m_lngSeed2 = ( lngIA2*m_lngSeed2 ) % lngIM2 without overflows
+ // by Schrage's method
+ k = m_lngSeed2 / sQ2;
+ m_lngSeed2 = sA2 * ( m_lngSeed2 - k*sQ2 ) - k*sR2;
+ if ( m_lngSeed2 < 0 )
+ {
+ m_lngSeed2 += sMod2;
+ }
+
+ j = m_lngShufflePos / sDiv;
+ m_lngShufflePos = m_ShuffleArray[j] - m_lngSeed2;
+ m_ShuffleArray[j] = m_lngSeed1;
+
+ if ( m_lngShufflePos < 1 )
+ {
+ m_lngShufflePos += sMM1;
+ }
+}
+
+void
+KRandomSequence::modulate(int i)
+{
+ m_lngSeed2 -= i;
+ if ( m_lngSeed2 < 0 )
+ {
+ m_lngShufflePos += sMod2;
+ }
+ Draw();
+ m_lngSeed1 -= i;
+ if ( m_lngSeed1 < 0 )
+ {
+ m_lngSeed1 += sMod1;
+ }
+ Draw();
+}
+
+double
+KRandomSequence::getDouble()
+{
+ static const double finalAmp = 1.0 / double( sMod1 );
+ static const double epsilon = 1.2E-7;
+ static const double maxRand = 1.0 - epsilon;
+ double temp;
+ Draw();
+ // Return a value that is not one of the endpoints
+ if ( ( temp = finalAmp * m_lngShufflePos ) > maxRand )
+ {
+ // We don't want to return 1.0
+ return maxRand;
+ }
+ else
+ {
+ return temp;
+ }
+}
+
+unsigned long
+KRandomSequence::getLong(unsigned long max)
+{
+ Draw();
+
+ return max ? (((unsigned long) m_lngShufflePos) % max) : 0;
+}
+
+bool
+KRandomSequence::getBool()
+{
+ Draw();
+
+ return (((unsigned long) m_lngShufflePos) & 1);
+}
+
+class KRandomSequenceList : public QGList
+{
+ friend class KRandomSequence;
+public:
+ KRandomSequenceList() : QGList() { }
+ virtual void deleteItem( QPtrCollection::Item ) {}
+};
+
+void
+KRandomSequence::randomize(QGList *_list)
+{
+ KRandomSequenceList *list = (KRandomSequenceList *)_list;
+ KRandomSequenceList l;
+ while(list->count())
+ l.append(list->takeFirst());
+
+ list->append(l.takeFirst()); // Start with 1
+ while(l.count())
+ list->insertAt(getLong(list->count()+1), l.takeFirst());
+}
diff --git a/kdecore/krandomsequence.h b/kdecore/krandomsequence.h
new file mode 100644
index 000000000..7d18f732d
--- /dev/null
+++ b/kdecore/krandomsequence.h
@@ -0,0 +1,145 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Sean Harmer <sh@astro.keele.ac.uk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef K_RANDOM_SEQUENCE_H
+#define K_RANDOM_SEQUENCE_H
+
+#include "kdelibs_export.h"
+
+class KRandomSequencePrivate;
+class QGList;
+/**
+ * A class to create a pseudo-random sequence
+ *
+ * Given a seed number, this class will produce a sequence of
+ * pseudo-random numbers. This would typically be used in
+ * applications like games.
+ *
+ * In general, you should instantiate a KRandomSequence object and
+ * pass along your seed number in the constructor. From then on,
+ * simply call getDouble() or getLong() to obtain the next
+ * number in the sequence.
+ *
+ * @author Sean Harmer <sh@astro.keele.ac.uk>
+ */
+class KDECORE_EXPORT KRandomSequence
+{
+public:
+ /**
+ * Creates a pseudo-random sequence based on the seed lngSeed.
+ *
+ * A Pseudo-random sequence is different for each seed but can be
+ * reproduced by starting the sequence with the same seed.
+ *
+ * If you need a single value which needs to be unpredictable,
+ * you need to use kapp->random() instead.
+ *
+ * @param lngSeed Seed to initialize the sequence with.
+ * If lngSeed is 0, the sequence is initialized with a value from
+ * KApplication::random().
+ */
+ KRandomSequence( long lngSeed = 0 );
+
+ /**
+ * Standard destructor
+ */
+ virtual ~KRandomSequence();
+
+ /**
+ * Copy constructor
+ */
+ KRandomSequence(const KRandomSequence &a);
+
+ /**
+ * Assignment
+ */
+ KRandomSequence &operator=(const KRandomSequence &a);
+
+ /**
+ * Restart the sequence based on lngSeed.
+ * @param lngSeed Seed to initialize the sequence with.
+ * If lngSeed is 0, the sequence is initialized with a value from
+ * KApplication::random().
+ */
+ void setSeed( long lngSeed = 0 );
+
+ /**
+ * Get the next number from the pseudo-random sequence.
+ *
+ * @return a pseudo-random double value between [0,1[
+ */
+ double getDouble();
+
+ /**
+ * Get the next number from the pseudo-random sequence.
+ *
+ * @return a pseudo-random integer value between [0, max[
+ * with 0 <= max < 1.000.000
+ */
+ unsigned long getLong(unsigned long max);
+
+ /**
+ * Get a boolean from the pseudo-random sequence.
+ *
+ * @return a boolean which is either true or false
+ */
+ bool getBool();
+
+ /**
+ * Put a list in random order.
+ *
+ * @param list the list whose order will be modified
+ */
+ void randomize(QGList *list);
+
+ /**
+ * Modulate the random sequence.
+ *
+ * If S(i) is the sequence of numbers that will follow
+ * given the current state after calling modulate(i),
+ * then S(i) != S(j) for i != j and
+ * S(i) == S(j) for i == j.
+ *
+ * This can be useful in game situation where "undo" restores
+ * the state of the random sequence. If the game modulates the
+ * random sequence with the move chosen by the player, the
+ * random sequence will be identical whenever the player "redo"-s
+ * his or hers original move, but different when the player
+ * chooses another move.
+ *
+ * With this scenario "undo" can no longer be used to repeat a
+ * certain move over and over again until the computer reacts
+ * with a favorable response or to predict the response for a
+ * certain move based on the response to another move.
+ * @param i the sequence identified
+ */
+ void modulate(int i);
+
+private:
+ void Draw(); // Generate the random number
+ long m_lngSeed1;
+ long m_lngSeed2;
+ long m_lngShufflePos;
+
+ static const int m_nShuffleTableSize;
+ long *m_ShuffleArray;
+
+ KRandomSequencePrivate *d;
+};
+
+#endif
+
diff --git a/kdecore/kregexp.cpp b/kdecore/kregexp.cpp
new file mode 100644
index 000000000..22db51dfa
--- /dev/null
+++ b/kdecore/kregexp.cpp
@@ -0,0 +1,210 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "kregexp.h"
+#include "kregpriv.h"
+#include "kdebug.h"
+
+KRegExpPrivate::KRegExpPrivate()
+{
+ m_bInit = false;
+
+ for ( int i = 0; i < 10; i++ )
+ m_strMatches[i] = 0L;
+}
+
+KRegExpPrivate::KRegExpPrivate( const char *_pattern, const char *_mode )
+{
+ m_bInit = false;
+
+ for ( int i = 0; i < 10; i++ )
+ m_strMatches[i] = 0L;
+
+ compile( _pattern, _mode );
+}
+
+KRegExpPrivate::~KRegExpPrivate()
+{
+ for ( int i = 0; i < 10; i++ )
+ if ( m_strMatches[i] )
+ free( m_strMatches[i] );
+
+ if ( m_bInit )
+ regfree( &m_pattern );
+}
+
+bool KRegExpPrivate::compile( const char *_pattern, const char *_mode )
+{
+ if ( m_bInit )
+ regfree( &m_pattern );
+
+ int res = regcomp( &m_pattern, _pattern, ( strchr( _mode, 'i' ) != 0L ? REG_ICASE : 0 ) | REG_EXTENDED );
+ if ( res == 0 )
+ m_bInit = true;
+
+ return ( res == 0 );
+}
+
+bool KRegExpPrivate::match( const char *_string )
+{
+ if ( !m_bInit )
+ {
+ kdDebug(128) << "You must compile a pattern before you can try to match it" << endl;
+ assert( 0 );
+ }
+
+ for ( int i = 0; i < 10; i++ )
+ {
+ m_matches[i].rm_so = -1;
+ m_matches[i].rm_eo = -1;
+ if ( m_strMatches[i] )
+ {
+ free( m_strMatches[i] );
+ m_strMatches[i] = 0L;
+ }
+ }
+
+ int res = regexec( &m_pattern, _string, 10, m_matches, 0 );
+ if ( res != 0 )
+ return false;
+
+ int slen = strlen( _string );
+
+ for ( int j = 0; j < 10; j++ )
+ {
+ if ( m_matches[j].rm_so >= 0 && m_matches[j].rm_eo >= 0 &&
+ m_matches[j].rm_so <= slen && m_matches[j].rm_eo <= slen &&
+ m_matches[j].rm_so <= m_matches[j].rm_eo )
+ {
+ int len = m_matches[j].rm_eo - m_matches[j].rm_so;
+ m_strMatches[j] = ( char* )malloc( len + 1 );
+ memcpy( m_strMatches[j], _string + m_matches[j].rm_so, len );
+ m_strMatches[j][ len ] = 0;
+ }
+ }
+
+ return true;
+}
+
+const char* KRegExpPrivate::group( int _grp )
+{
+ if ( _grp < 0 || _grp >= 10 )
+ {
+ kdDebug(128) << "You may only use a group in the range of 0..9" << endl;
+ assert( 0 );
+ }
+
+ return m_strMatches[ _grp ];
+}
+
+int KRegExpPrivate::groupStart( int _grp )
+{
+ if ( _grp < 0 || _grp >= 10 )
+ {
+ kdDebug(128) << "You may only use a group in the range of 0..9" << endl;
+ assert( 0 );
+ }
+
+ return m_matches[ _grp ].rm_so;
+}
+
+int KRegExpPrivate::groupEnd( int _grp )
+{
+ if ( _grp < 0 || _grp >= 10 )
+ {
+ kdDebug(128) << "You may only use a group in the range of 0..9" << endl;
+ assert( 0 );
+ }
+
+ return m_matches[ _grp ].rm_eo;
+}
+
+KRegExp::KRegExp()
+{
+ m_pPrivate = new KRegExpPrivate;
+}
+
+KRegExp::KRegExp( const char *_pattern, const char *_mode)
+{
+ m_pPrivate = new KRegExpPrivate( _pattern, _mode );
+}
+
+KRegExp::~KRegExp()
+{
+ delete m_pPrivate;
+}
+
+bool KRegExp::compile( const char *_pattern, const char *_mode)
+{
+ return m_pPrivate->compile( _pattern, _mode );
+}
+
+bool KRegExp::match( const char *_string )
+{
+ return m_pPrivate->match( _string );
+}
+
+const char* KRegExp::group( int _grp )
+{
+ return m_pPrivate->group( _grp );
+}
+
+int KRegExp::groupStart( int _grp )
+{
+ return m_pPrivate->groupStart( _grp );
+}
+
+int KRegExp::groupEnd( int _grp )
+{
+ return m_pPrivate->groupEnd( _grp );
+}
+
+/*
+int main( int argc, char **argv )
+{
+ if ( argc != 3 )
+ assert( 0 );
+
+ KRegExp r( argv[1], "" );
+ cout << "Compiled" << endl;
+
+ if ( !r.match( argv[2] ) )
+ {
+ cerr << "Does not match" << endl;
+ return 0;
+ }
+
+ cout << "Match" << endl;
+
+ for( int i = 0; i < 10; i++ )
+ {
+ const char *c = r.group( i );
+ if ( !c )
+ return 0;
+ cout << "Group #" << i << ":" << c << endl;
+ }
+
+ return 0;
+}
+*/
diff --git a/kdecore/kregexp.h b/kdecore/kregexp.h
new file mode 100644
index 000000000..74489fa3f
--- /dev/null
+++ b/kdecore/kregexp.h
@@ -0,0 +1,129 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __kregexp_h__
+#define __kregexp_h__
+
+#include "kdelibs_export.h"
+
+class KRegExpPrivate;
+
+/**
+ * @deprecated
+ * Please use QRegExp instead.
+ *
+ * Regular expression (regexp) matching with back-references.
+ *
+ * This was implemented
+ * because QRegExp did not support back-references. It now does and
+ * is recommended over KRegExp because of the unicode support and the
+ * more powerful API.
+ *
+ * Back-references are parts of a regexp grouped with parentheses. If a
+ * string matches the regexp, you can access the text that matched each
+ * group with the group method. This is similar to regular expressions
+ * in Perl.
+ *
+ * Example:
+ * \code
+ * KRegExp ex( "([A-Za-z]+) (.+)" );
+ * ex.match( "42 Torben Weis" );
+ * kdDebug() << ex.group(0) << endl;
+ * kdDebug() << ex.group(1) << endl;
+ * kdDebug() << ex.group(2) << endl;
+ * \endcode
+ * Output:
+ * \code
+ * Torben Weis
+ * Torben
+ * Weis
+ * \endcode
+ *
+ * Please notice that KRegExp does @em not support unicode.
+ *
+ * @author Torben Weis <weis@kde.org>
+ */
+class KDECORE_EXPORT KDE_DEPRECATED KRegExp
+{
+public:
+
+ /**
+ * Creates a KRegExp object without a default pattern.
+ */
+ KRegExp();
+
+ /**
+ * Creates a KRegExp object.
+ * @param _pattern The regular expression to use for matches.
+ * @param _mode If this is "i", case-insensitive matches will be
+ * performed.
+ */
+ KRegExp( const char *_pattern, const char *_mode = "" );
+ ~KRegExp();
+
+ /**
+ * Prepare a regular expression for subsequent matches.
+ * @param _pattern The regular expression to use for matches.
+ * @param _mode If this is "i", case-insensitive matches will be
+ * performed.
+ * @return bool if successful.
+ */
+ bool compile( const char *_pattern, const char *_mode = "" );
+
+ /**
+ * Match a string to the last supplied regexp.
+ * @param _string the string to match
+ * @return @p true on match, false otherwise.
+ */
+ bool match( const char *_string );
+
+
+ /**
+ * Returns a group from the match.
+ *
+ * @param _grp May be in the range [0..9]. If @p _grp is 0 then the complete
+ * matched string is returned.
+ * @return a grouped substring. A substring may be empty.
+ * In this case 0 is returned. Otherwise you may @em not
+ * delete or modify the returned value. In addition the
+ * returned value becomes invalid after the KRegExp instance
+ * is deleted or after match() was called again.
+ */
+ const char *group( int _grp );
+
+ /**
+ * The offset of the given group in the string.
+ * @param _grp May be in the range [0..9]. If @p _grp is 0 then the start offset
+ * of the complete matched string is returned.
+ * @return The start offset of the grouped substring.
+ */
+ int groupStart( int _grp );
+ /**
+ * The offset of the given group's end in the string.
+ * @param _grp May be in the range [0..9]. If @p _grp is 0 then the end offset
+ * of the complete matched string is returned.
+ * @return The end offset of the grouped substring. The "end offset" is the first
+ * character after the string.
+ */
+ int groupEnd( int _grp );
+
+private:
+ KRegExpPrivate *m_pPrivate;
+};
+
+
+#endif
diff --git a/kdecore/kregpriv.h b/kdecore/kregpriv.h
new file mode 100644
index 000000000..2aa34bba5
--- /dev/null
+++ b/kdecore/kregpriv.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __kreg_private_h__
+#define __kreg_private_h__
+
+extern "C" { // bug with some libc5 distributions
+#include <regex.h>
+}
+
+class KRegExpDataPtr;
+
+/**
+ * Used internally by KRegExp.
+ * @internal
+ *
+ * @author Torben Weis <weis@kde.org>
+ */
+class KRegExpPrivate
+{
+public:
+ KRegExpPrivate();
+ KRegExpPrivate( const char *_pattern, const char *_mode = "" );
+ ~KRegExpPrivate();
+
+ bool compile( const char *_pattern, const char *_mode = "" );
+
+ bool match( const char *_string );
+ const char *group( int _grp );
+ int groupStart( int _grp );
+ int groupEnd( int _grp );
+
+protected:
+ regex_t m_pattern;
+ regmatch_t m_matches[ 10 ];
+ char* m_strMatches[10];
+ bool m_bInit;
+
+private:
+ KRegExpDataPtr *d;
+};
+
+#endif
diff --git a/kdecore/krfcdate.cpp b/kdecore/krfcdate.cpp
new file mode 100644
index 000000000..4e214a81f
--- /dev/null
+++ b/kdecore/krfcdate.cpp
@@ -0,0 +1,505 @@
+/*
+ *
+ * This file is part of the KDE libraries
+ * Copyright (c) 2000-2002 Waldo Bastian <bastian@kde.org>
+ * 2002 Rik Hemsley <rik@kde.org>
+ *
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <qstringlist.h>
+
+#include <krfcdate.h>
+
+static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
+{
+ if (sizeof(time_t) == 4)
+ {
+ if ((time_t)-1 < 0)
+ {
+ if (year >= 2038)
+ {
+ year = 2038;
+ mon = 0;
+ day = 1;
+ hour = 0;
+ minute = 0;
+ second = 0;
+ }
+ }
+ else
+ {
+ if (year >= 2115)
+ {
+ year = 2115;
+ mon = 0;
+ day = 1;
+ hour = 0;
+ minute = 0;
+ second = 0;
+ }
+ }
+ }
+
+ unsigned int ret = (day - 32075) /* days */
+ + 1461L * (year + 4800L + (mon - 14) / 12) / 4
+ + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
+ - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
+ - 2440588;
+ ret = 24*ret + hour; /* hours */
+ ret = 60*ret + minute; /* minutes */
+ ret = 60*ret + second; /* seconds */
+
+ return ret;
+}
+
+static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
+
+// we follow the recommendation of rfc2822 to consider all
+// obsolete time zones not listed here equivalent to "-0000"
+static const struct {
+ const char tzName[4];
+ int tzOffset;
+} known_zones[] = {
+ { "UT", 0 },
+ { "GMT", 0 },
+ { "EST", -300 },
+ { "EDT", -240 },
+ { "CST", -360 },
+ { "CDT", -300 },
+ { "MST", -420 },
+ { "MDT", -360 },
+ { "PST", -480 },
+ { "PDT", -420 },
+ { { 0,0,0,0 }, 0 }
+};
+
+time_t
+KRFCDate::parseDate(const QString &_date)
+{
+ if (_date.isEmpty())
+ return 0;
+
+ // This parse a date in the form:
+ // Wednesday, 09-Nov-99 23:12:40 GMT
+ // or
+ // Sat, 01-Jan-2000 08:00:00 GMT
+ // or
+ // Sat, 01 Jan 2000 08:00:00 GMT
+ // or
+ // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822)
+ //
+ // We ignore the weekday
+ //
+ time_t result = 0;
+ int offset = 0;
+ char *newPosStr;
+ const char *dateString = _date.latin1();
+ int day = 0;
+ char monthStr[4];
+ int month = -1;
+ int year = 0;
+ int hour = 0;
+ int minute = 0;
+ int second = 0;
+
+ // Strip leading space
+ while(*dateString && isspace(*dateString))
+ dateString++;
+
+ // Strip weekday
+ while(*dateString && !isdigit(*dateString) && !isspace(*dateString))
+ dateString++;
+
+ // Strip trailing space
+ while(*dateString && isspace(*dateString))
+ dateString++;
+
+ if (!*dateString)
+ return result; // Invalid date
+
+ if (isalpha(*dateString))
+ {
+ // ' Nov 5 1994 18:15:30 GMT'
+ // Strip leading space
+ while(*dateString && isspace(*dateString))
+ dateString++;
+
+ for(int i=0; i < 3;i++)
+ {
+ if (!*dateString || (*dateString == '-') || isspace(*dateString))
+ return result; // Invalid date
+ monthStr[i] = tolower(*dateString++);
+ }
+ monthStr[3] = '\0';
+
+ newPosStr = (char*)strstr(haystack, monthStr);
+
+ if (!newPosStr)
+ return result; // Invalid date
+
+ month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
+
+ if ((month < 0) || (month > 11))
+ return result; // Invalid date
+
+ while (*dateString && isalpha(*dateString))
+ dateString++; // Skip rest of month-name
+ }
+
+ // ' 09-Nov-99 23:12:40 GMT'
+ // ' 5 1994 18:15:30 GMT'
+ day = strtol(dateString, &newPosStr, 10);
+ dateString = newPosStr;
+
+ if ((day < 1) || (day > 31))
+ return result; // Invalid date;
+
+ if (!*dateString)
+ return result; // Invalid date
+
+ while(*dateString && (isspace(*dateString) || (*dateString == '-')))
+ dateString++;
+
+ if (month == -1)
+ {
+ for(int i=0; i < 3;i++)
+ {
+ if (!*dateString || (*dateString == '-') || isspace(*dateString))
+ return result; // Invalid date
+ monthStr[i] = tolower(*dateString++);
+ }
+ monthStr[3] = '\0';
+
+ newPosStr = (char*)strstr(haystack, monthStr);
+
+ if (!newPosStr)
+ return result; // Invalid date
+
+ month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
+
+ if ((month < 0) || (month > 11))
+ return result; // Invalid date
+
+ while (*dateString && isalpha(*dateString))
+ dateString++; // Skip rest of month-name
+
+ }
+
+ // '-99 23:12:40 GMT'
+ while(*dateString && (isspace(*dateString) || (*dateString == '-')))
+ dateString++;
+
+ if (!*dateString || !isdigit(*dateString))
+ return result; // Invalid date
+
+ // '99 23:12:40 GMT'
+ year = strtol(dateString, &newPosStr, 10);
+ dateString = newPosStr;
+
+ // Y2K: Solve 2 digit years
+ if ((year >= 0) && (year < 50))
+ year += 2000;
+
+ if ((year >= 50) && (year < 100))
+ year += 1900; // Y2K
+
+ if ((year < 1900) || (year > 2500))
+ return result; // Invalid date
+
+ // Don't fail if the time is missing.
+ if (*dateString)
+ {
+ // ' 23:12:40 GMT'
+ if (!isspace(*dateString++))
+ return result; // Invalid date
+
+ hour = strtol(dateString, &newPosStr, 10);
+ dateString = newPosStr;
+
+ if ((hour < 0) || (hour > 23))
+ return result; // Invalid date
+
+ if (!*dateString)
+ return result; // Invalid date
+
+ // ':12:40 GMT'
+ if (*dateString++ != ':')
+ return result; // Invalid date
+
+ minute = strtol(dateString, &newPosStr, 10);
+ dateString = newPosStr;
+
+ if ((minute < 0) || (minute > 59))
+ return result; // Invalid date
+
+ if (!*dateString)
+ return result; // Invalid date
+
+ // ':40 GMT'
+ if (*dateString != ':' && !isspace(*dateString))
+ return result; // Invalid date
+
+ // seconds are optional in rfc822 + rfc2822
+ if (*dateString ==':') {
+ dateString++;
+
+ second = strtol(dateString, &newPosStr, 10);
+ dateString = newPosStr;
+
+ if ((second < 0) || (second > 59))
+ return result; // Invalid date
+ } else {
+ dateString++;
+ }
+
+ while(*dateString && isspace(*dateString))
+ dateString++;
+ }
+
+ // don't fail if the time zone is missing, some
+ // broken mail-/news-clients omit the time zone
+ if (*dateString) {
+ if ((strncasecmp(dateString, "gmt", 3) == 0) ||
+ (strncasecmp(dateString, "utc", 3) == 0))
+ {
+ dateString += 3;
+ while(*dateString && isspace(*dateString))
+ dateString++;
+ }
+
+ if ((*dateString == '+') || (*dateString == '-')) {
+ offset = strtol(dateString, &newPosStr, 10);
+ if (abs(offset) < 30)
+ {
+ dateString = newPosStr;
+
+ offset = offset * 100;
+
+ if (*dateString && *(dateString+1))
+ {
+ dateString++;
+ int minutes = strtol(dateString, &newPosStr, 10);
+ if (offset > 0)
+ offset += minutes;
+ else
+ offset -= minutes;
+ }
+ }
+
+ if ((offset < -9959) || (offset > 9959))
+ return result; // Invalid date
+
+ int sgn = (offset < 0)? -1:1;
+ offset = abs(offset);
+ offset = ((offset / 100)*60 + (offset % 100))*sgn;
+ } else {
+ for (int i=0; known_zones[i].tzName != 0; i++) {
+ if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
+ offset = known_zones[i].tzOffset;
+ break;
+ }
+ }
+ }
+ }
+
+ result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
+
+ // avoid negative time values
+ if ((offset > 0) && (offset > result))
+ offset = 0;
+
+ result -= offset*60;
+
+ // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
+ // This is so that parse error and valid epoch 0 return values won't
+ // be the same for sensitive applications...
+ if (result < 1) result = 1;
+
+ return result;
+}
+
+time_t
+KRFCDate::parseDateISO8601( const QString& input_ )
+{
+ if (input_.isEmpty())
+ return 0;
+
+ // These dates look like this:
+ // YYYY-MM-DDTHH:MM:SS
+ // But they may also have 0, 1 or 2 suffixes.
+ // Suffix 1: .secfrac (fraction of second)
+ // Suffix 2: Either 'Z' or +zone or -zone, where zone is HHMM
+
+ unsigned int year = 0;
+ unsigned int month = 0;
+ unsigned int mday = 0;
+ unsigned int hour = 0;
+ unsigned int min = 0;
+ unsigned int sec = 0;
+
+ int offset = 0;
+
+ QString input = input_;
+
+ // First find the 'T' separator, if any.
+ int tPos = input.find('T');
+
+ // If there is no time, no month or no day specified, fill those missing
+ // fields so that 'input' matches YYYY-MM-DDTHH:MM:SS
+ if (-1 == tPos) {
+ const int dashes = input.contains('-');
+ if (0 == dashes) {
+ input += "-01-01";
+ } else if (1 == dashes) {
+ input += "-01";
+ }
+ tPos = input.length();
+ input += "T12:00:00";
+ }
+
+ // Now parse the date part.
+
+ QString dateString = input.left(tPos).stripWhiteSpace();
+
+ QString timeString = input.mid(tPos + 1).stripWhiteSpace();
+
+ QStringList l = QStringList::split('-', dateString);
+
+ if (l.size() < 3)
+ return 0;
+
+ year = l[0].toUInt();
+ month = l[1].toUInt();
+ mday = l[2].toUInt();
+
+ // Z suffix means UTC.
+ if ('Z' == timeString.at(timeString.length() - 1)) {
+ timeString.remove(timeString.length() - 1, 1);
+ }
+
+ // +zone or -zone suffix (offset from UTC).
+
+ int plusPos = timeString.findRev('+');
+
+ if (-1 != plusPos) {
+ QString offsetString = timeString.mid(plusPos + 1);
+
+ offset = offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt();
+
+ timeString = timeString.left(plusPos);
+ } else {
+ int minusPos = timeString.findRev('-');
+
+ if (-1 != minusPos) {
+ QString offsetString = timeString.mid(minusPos + 1);
+
+ offset = - int(offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt());
+
+ timeString = timeString.left(minusPos);
+ }
+ }
+
+ // secfrac suffix.
+ int dotPos = timeString.findRev('.');
+
+ if (-1 != dotPos) {
+ timeString = timeString.left(dotPos);
+ }
+
+ // Now parse the time part.
+
+ l = QStringList::split(':', timeString);
+
+ if (l.size() < 3)
+ return 0;
+
+ hour = l[0].toUInt();
+ min = l[1].toUInt();
+ sec = l[2].toUInt();
+
+ time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
+
+ // avoid negative time values
+ if ((offset > 0) && (offset > result))
+ offset = 0;
+
+ result -= offset*60;
+
+ // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
+ // This is so that parse error and valid epoch 0 return values won't
+ // be the same for sensitive applications...
+ if (result < 1) result = 1;
+
+ return result;
+}
+
+
+int KRFCDate::localUTCOffset()
+{
+ time_t timeNow = time((time_t*) 0);
+
+ tm *tM = gmtime(&timeNow);
+ unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
+ tM->tm_hour, tM->tm_min, tM->tm_sec);
+
+ tM = localtime(&timeNow);
+ unsigned int timeLocal = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
+ tM->tm_hour, tM->tm_min, tM->tm_sec);
+
+ return ((int)(timeLocal-timeUTC))/60;
+}
+
+
+static const char * const day_names[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+static const char * const month_names[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+
+QCString KRFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
+{
+ utcTime += utcOffset * 60;
+ tm *tM = gmtime(&utcTime);
+ char sgn = (utcOffset < 0) ? '-' : '+';
+ int z = (utcOffset < 0) ? -utcOffset : utcOffset;
+ QCString dateStr;
+
+ dateStr.sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
+ day_names[tM->tm_wday], tM->tm_mday,
+ month_names[tM->tm_mon], tM->tm_year+1900,
+ tM->tm_hour, tM->tm_min, tM->tm_sec,
+ sgn, z/60%24, z%60);
+
+ return dateStr;
+}
+
+
+QCString KRFCDate::rfc2822DateString(time_t utcTime)
+{
+ return rfc2822DateString(utcTime, localUTCOffset());
+}
diff --git a/kdecore/krfcdate.h b/kdecore/krfcdate.h
new file mode 100644
index 000000000..b8884eb0f
--- /dev/null
+++ b/kdecore/krfcdate.h
@@ -0,0 +1,100 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KRFCDATE_H_
+#define _KRFCDATE_H_
+
+#include <qstring.h>
+#include <time.h>
+#include "kdelibs_export.h"
+
+/**
+ * The KRFCDate class contains functions related to the parsing of dates.
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ */
+class KDECORE_EXPORT KRFCDate
+{
+public:
+ /**
+ * This function tries to parse a string containing a date/time in any
+ * of the formats specified by RFC822, RFC850, RFC1036, RFC1123 and RFC2822.
+ *
+ * If the date/time could not be parsed, 0 is returned. If the
+ * parsed date is epoch, then epoch+1 is returned so that a valid
+ * date will not be confused with an improper date string.
+ *
+ * The date/time returned is converted to UTC.
+ * @param date the date to parse
+ * @return the date, or 0 if not possible
+ */
+ static time_t parseDate(const QString &date);
+
+ /**
+ * This function tries to parse a string containing a date/time in
+ * any of the formats specified by http://www.w3.org/TR/NOTE-datetime
+ *
+ * This is a subset of the formats specified in ISO8601.
+ *
+ * If the date/time could not be parsed, 0 is returned. If the
+ * parsed date is epoch, then epoch+1 is returned so that a valid
+ * date will not be confused with an improper date string.
+ *
+ * The date/time returned is converted to UTC.
+ *
+ * @param date the date to parse
+ * @return the date, or 0 if not possible
+ */
+ static time_t parseDateISO8601(const QString &date);
+
+ /**
+ * Returns the local timezone offset to UTC in minutes
+ * @return the local timezone offset in minutes
+ */
+ static int localUTCOffset();
+
+
+ /**
+ * Returns a string representation of the given date and time formated
+ * in conformance to RFC2822.
+ *
+ * @param utcTime a date and time in UTC
+ * @param utcOffset the offset to UTC in minutes
+ * @return the string representation of the date
+ */
+
+ static QCString rfc2822DateString(time_t utcTime, int utcOffset);
+
+
+ /**
+ * Returns a string representation of the given date and time formated
+ * in conformance to RFC2822.
+ *
+ * Provided for convenience, the function is equivalent to
+ * rfc2822DateString(t, localUTCOffset()).
+ *
+ * @param utcTime a date and time in UTC
+ * @return the string representation of the date
+ */
+
+ static QCString rfc2822DateString(time_t utcTime);
+
+};
+
+#endif
diff --git a/kdecore/krootprop.cpp b/kdecore/krootprop.cpp
new file mode 100644
index 000000000..aca5b8255
--- /dev/null
+++ b/kdecore/krootprop.cpp
@@ -0,0 +1,303 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Mark Donohoe (donohoe@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qwidget.h>
+
+#include "config.h"
+#ifdef Q_WS_X11 // not needed anyway :-)
+
+#include "krootprop.h"
+#include "kglobal.h"
+#include "klocale.h"
+#include "kcharsets.h"
+#include "kapplication.h"
+#include <qtextstream.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+KRootProp::KRootProp(const QString& rProp )
+{
+ atom = 0;
+ dirty = false;
+ setProp( rProp );
+}
+
+KRootProp::~KRootProp()
+{
+ sync();
+ propDict.clear();
+}
+
+void KRootProp::sync()
+{
+ if ( !dirty )
+ return;
+
+ QString propString;
+ if ( !propDict.isEmpty() )
+ {
+ QMap<QString,QString>::Iterator it = propDict.begin();
+ QString keyvalue;
+
+ while ( it != propDict.end() )
+ {
+ keyvalue = QString( "%1=%2\n").arg(it.key()).arg(it.data());
+ propString += keyvalue;
+ ++it;
+ }
+ }
+
+ XChangeProperty( qt_xdisplay(), qt_xrootwin(), atom,
+ XA_STRING, 8, PropModeReplace,
+ (const unsigned char *)propString.utf8().data(),
+ propString.length());
+ XFlush( qt_xdisplay() );
+}
+
+void KRootProp::setProp( const QString& rProp )
+{
+ Atom type;
+ int format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ long offset;
+
+ // If a property has already been opened write
+ // the dictionary back to the root window
+
+ if( atom )
+ sync();
+
+ property_ = rProp;
+ if( rProp.isEmpty() )
+ return;
+
+ atom = XInternAtom( qt_xdisplay(), rProp.utf8(), False);
+
+ QString s;
+ offset = 0; bytes_after = 1;
+ while (bytes_after != 0)
+ {
+ unsigned char *buf = 0;
+ if (XGetWindowProperty( qt_xdisplay(), qt_xrootwin(), atom, offset, 256,
+ False, XA_STRING, &type, &format, &nitems, &bytes_after,
+ &buf) == Success && buf)
+ {
+ s += QString::fromUtf8((const char*)buf);
+ offset += nitems/4;
+ XFree(buf);
+ }
+ }
+
+ // Parse through the property string stripping out key value pairs
+ // and putting them in the dictionary
+
+ QString keypair;
+ int i=0;
+ QString key;
+ QString value;
+
+ while(s.length() >0 )
+ {
+ // parse the string for first key-value pair separator '\n'
+
+ i = s.find("\n");
+ if(i == -1)
+ i = s.length();
+
+ // extract the key-values pair and remove from string
+
+ keypair = s.left(i);
+ s.remove(0,i+1);
+
+ // split key and value and add to dictionary
+
+ keypair.simplifyWhiteSpace();
+
+ i = keypair.find( "=" );
+ if( i != -1 )
+ {
+ key = keypair.left( i );
+ value = keypair.mid( i+1 );
+ propDict.insert( key, value );
+ }
+ }
+}
+
+
+QString KRootProp::prop() const
+{
+ return property_;
+}
+
+void KRootProp::destroy()
+{
+ dirty = false;
+ propDict.clear();
+ if( atom ) {
+ XDeleteProperty( qt_xdisplay(), qt_xrootwin(), atom );
+ atom = 0;
+ }
+}
+
+QString KRootProp::readEntry( const QString& rKey,
+ const QString& pDefault ) const
+{
+ if( propDict.contains( rKey ) )
+ return propDict[ rKey ];
+ else
+ return pDefault;
+}
+
+int KRootProp::readNumEntry( const QString& rKey, int nDefault ) const
+{
+
+ QString aValue = readEntry( rKey );
+ if( !aValue.isNull() )
+ {
+ bool ok;
+
+ int rc = aValue.toInt( &ok );
+ if (ok)
+ return rc;
+ }
+ return nDefault;
+}
+
+
+QFont KRootProp::readFontEntry( const QString& rKey,
+ const QFont* pDefault ) const
+{
+ QFont aRetFont;
+ QFont aDefFont;
+
+ if (pDefault)
+ aDefFont = *pDefault;
+
+ QString aValue = readEntry( rKey );
+ if( aValue.isNull() )
+ return aDefFont; // Return default font
+
+ if ( !aRetFont.fromString( aValue ) && pDefault )
+ aRetFont = aDefFont;
+
+ return aRetFont;
+}
+
+
+QColor KRootProp::readColorEntry( const QString& rKey,
+ const QColor* pDefault ) const
+{
+ QColor aRetColor;
+ int nRed = 0, nGreen = 0, nBlue = 0;
+
+ if( pDefault )
+ aRetColor = *pDefault;
+
+ QString aValue = readEntry( rKey );
+ if( aValue.isNull() )
+ return aRetColor;
+
+ // Support #ffffff style color naming.
+ // Help ease transistion from legacy KDE setups
+ if( aValue.find("#") == 0 ) {
+ aRetColor.setNamedColor( aValue );
+ return aRetColor;
+ }
+
+ // Parse "red,green,blue"
+ // find first comma
+ int nIndex1 = aValue.find( ',' );
+ if( nIndex1 == -1 )
+ return aRetColor;
+ // find second comma
+ int nIndex2 = aValue.find( ',', nIndex1+1 );
+ if( nIndex2 == -1 )
+ return aRetColor;
+
+ bool bOK;
+ nRed = aValue.left( nIndex1 ).toInt( &bOK );
+ nGreen = aValue.mid( nIndex1+1,
+ nIndex2-nIndex1-1 ).toInt( &bOK );
+ nBlue = aValue.mid( nIndex2+1 ).toInt( &bOK );
+
+ aRetColor.setRgb( nRed, nGreen, nBlue );
+
+ return aRetColor;
+}
+
+QString KRootProp::writeEntry( const QString& rKey, const QString& rValue )
+{
+ dirty = true;
+ if ( propDict.contains( rKey ) ) {
+ QString aValue = propDict[ rKey ];
+ propDict.replace( rKey, rValue );
+ return aValue;
+ }
+ else {
+ propDict.insert( rKey, rValue );
+ return QString::null;
+ }
+}
+
+QString KRootProp::writeEntry( const QString& rKey, int nValue )
+{
+ QString aValue;
+
+ aValue.setNum( nValue );
+
+ return writeEntry( rKey, aValue );
+}
+
+QString KRootProp::writeEntry( const QString& rKey, const QFont& rFont )
+{
+ return writeEntry( rKey, rFont.toString() );
+}
+
+QString KRootProp::writeEntry( const QString& rKey, const QColor& rColor )
+{
+ QString aValue = QString( "%1,%2,%3").arg(rColor.red()).arg(rColor.green()).arg(rColor.blue() );
+
+ return writeEntry( rKey, aValue );
+}
+
+QString KRootProp::removeEntry(const QString& rKey)
+{
+ if (propDict.contains(rKey)) {
+ dirty = true;
+ QString aValue = propDict[rKey];
+ propDict.remove(rKey);
+ return aValue;
+ } else
+ return QString::null;
+}
+
+QStringList KRootProp::listEntries() const
+{
+ QMap<QString,QString>::ConstIterator it;
+ QStringList list;
+
+ QMap<QString,QString>::ConstIterator end(propDict.end());
+ for (it=propDict.begin(); it!=end; ++it)
+ list += it.key();
+
+ return list;
+}
+#endif
diff --git a/kdecore/krootprop.h b/kdecore/krootprop.h
new file mode 100644
index 000000000..1234f143e
--- /dev/null
+++ b/kdecore/krootprop.h
@@ -0,0 +1,206 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Mark Donohoe (donohoe@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KROOTPROP_H
+#define _KROOTPROP_H
+
+typedef unsigned long Atom;
+
+#include <qcolor.h>
+#include <qfont.h>
+#include <qmap.h>
+#include <qstringlist.h>
+
+#include <kdelibs_export.h>
+
+class KRootPropPrivate;
+
+/**
+* Access KDE desktop resources stored on the root window.
+*
+* A companion to the KConfig class.
+*
+* The KRootProp class is used for reading and writing configuration entries
+* to properties on the root window.
+*
+* All configuration entries are of the form "key=value".
+*
+* @see KConfig::KConfig
+* @author Mark Donohoe (donohe@kde.org)
+*/
+class KDECORE_EXPORT KRootProp
+{
+private:
+ Atom atom;
+ QMap<QString,QString> propDict;
+ QString property_;
+ bool dirty;
+ KRootPropPrivate *d;
+
+public:
+ /**
+ * Constructs a KRootProp object for the property @p rProp.
+ * @param rProp the property that will be searched, null to
+ * do nothing
+ * @see setProp()
+ **/
+ KRootProp( const QString& rProp = QString::null );
+ /**
+ * Destructs the KRootProp object.
+ *
+ * Writes back any dirty configuration entries.
+ **/
+ ~KRootProp();
+
+ /**
+ * Sets the property in which keys will be searched.
+ * @param rProp the property that will be searched
+ **/
+ void setProp(const QString& rProp=QString());
+ /**
+ * Returns the name of the property under which keys are searched.
+ * @return the property that will be searched
+ **/
+ QString prop() const;
+
+ /**
+ * Destroys the property completely.
+ *
+ * I.e. all entries will be cleared
+ * and the property will be removed from the root window.
+ **/
+ void destroy();
+
+ /**
+ * Reads the value of an entry specified by @p rKey in the current property.
+ *
+ * @param rKey The key to search for.
+ * @param pDefault A default value returned if the key was not found.
+ * @return The value for this key or the default if no value
+ * was found.
+ **/
+ QString readEntry( const QString& rKey,
+ const QString& pDefault = QString::null ) const ;
+
+ /**
+ * Reads a numerical value.
+ *
+ * Reads the value of an entry specified by @p rKey in the current property
+ * and interprets it numerically.
+ *
+ * @param rKey The key to search for.
+ * @param nDefault A default value returned if the key was not found.
+ * @return The value for this key or the default if no value was found.
+ */
+ int readNumEntry( const QString& rKey, int nDefault = 0 ) const;
+
+ /**
+ * Reads a QFont value.
+ *
+ * Reads the value of an entry specified by @p rKey in the current property
+ * and interpret it as a font object.
+ *
+ * @param rKey The key to search for.
+ * @param pDefault A default value returned if the key was not found.
+ * @return The value for this key or a default font if no value was found.
+ */
+ QFont readFontEntry( const QString& rKey,
+ const QFont* pDefault = 0 ) const;
+
+ /**
+ * Reads a QColor.
+ *
+ * Reads the value of an entry specified by @p rKey in the current property
+ * and interprets it as a color.
+ *
+ * @param rKey The key to search for.
+ * @param pDefault A default value returned if the key was not found.
+ * @return The value for this key or a default color if no value
+ * was found.
+ */
+ QColor readColorEntry( const QString& rKey,
+ const QColor* pDefault = 0 ) const;
+
+
+ /**
+ * Writes a (key/value) pair.
+ *
+ * This is stored to the current property when destroying the
+ * config object or when calling sync().
+ *
+ * @param rKey The key to write.
+ * @param rValue The value to write.
+ * @return The old value for this key. If this key did not exist,
+ * a null string is returned.
+ *
+ **/
+ QString writeEntry( const QString& rKey, const QString& rValue );
+
+ /**
+ * Writes the (key/value) pair.
+ * Same as above, but writes a numerical value.
+ * @param rKey The key to write.
+ * @param nValue The value to write.
+ * @return The old value for this key. If this key did not
+ * exist, a null string is returned.
+ **/
+ QString writeEntry( const QString& rKey, int nValue );
+
+ /**
+ * Writes the (key/value) pair.
+ * Same as above, but writes a font.
+ * @param rKey The key to write.
+ * @param rFont The font to write.
+ * @return The old value for this key. If this key did not
+ * exist, a null string is returned.
+ **/
+ QString writeEntry( const QString& rKey, const QFont& rFont );
+
+ /**
+ * Writes the (key/value) pair.
+ * Same as above, but writes a color.
+ * @param rKey The key to write.
+ * @param rColor The color to write.
+ * @return The old value for this key. If this key did not
+ * exist, a null string is returned.
+ **/
+ QString writeEntry( const QString& rKey, const QColor& rColor );
+
+ /**
+ * Removes an entry.
+ * @param rKey The key to remove.
+ * @return The old value for this key. If this key did not
+ * exist, a null string is returned.
+ **/
+ QString removeEntry(const QString& rKey);
+
+ /**
+ * Returns a list of all keys.
+ * @return A QStringList containing all the keys.
+ **/
+ QStringList listEntries() const;
+
+ /**
+ * Flushes the entry cache.
+ * Writes back dirty configuration entries to the current property,
+ * This is called automatically from the destructor.
+ **/
+ void sync();
+};
+
+#endif
diff --git a/kdecore/ksavefile.cpp b/kdecore/ksavefile.cpp
new file mode 100644
index 000000000..35ec51da1
--- /dev/null
+++ b/kdecore/ksavefile.cpp
@@ -0,0 +1,230 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_TEST
+#include <test.h>
+#endif
+
+#include <qdatetime.h>
+#include <qdir.h>
+
+#include <kde_file.h>
+#include "kapplication.h"
+#include "ksavefile.h"
+#include "kstandarddirs.h"
+
+KSaveFile::KSaveFile(const QString &filename, int mode)
+ : mTempFile(true)
+{
+ // follow symbolic link, if any
+ QString real_filename = KStandardDirs::realFilePath(filename);
+
+ // we only check here if the directory can be written to
+ // the actual filename isn't written to, but replaced later
+ // with the contents of our tempfile
+ if (!checkAccess(real_filename, W_OK))
+ {
+ mTempFile.setError(EACCES);
+ return;
+ }
+
+ if (mTempFile.create(real_filename, QString::fromLatin1(".new"), mode))
+ {
+ mFileName = real_filename; // Set filename upon success
+
+ // if we're overwriting an existing file, ensure temp file's
+ // permissions are the same as existing file so the existing
+ // file's permissions are preserved
+ KDE_struct_stat stat_buf;
+ if (KDE_stat(QFile::encodeName(real_filename), &stat_buf)==0)
+ {
+ // But only if we own the existing file
+ if (stat_buf.st_uid == getuid())
+ {
+ bool changePermission = true;
+ if (stat_buf.st_gid != getgid())
+ {
+ if (fchown(mTempFile.handle(), (uid_t) -1, stat_buf.st_gid) != 0)
+ {
+ // Use standard permission if we can't set the group
+ changePermission = false;
+ }
+ }
+ if (changePermission)
+ fchmod(mTempFile.handle(), stat_buf.st_mode);
+ }
+ }
+ }
+}
+
+KSaveFile::~KSaveFile()
+{
+ if (mTempFile.bOpen)
+ close(); // Close if we were still open
+}
+
+QString
+KSaveFile::name() const
+{
+ return mFileName;
+}
+
+void
+KSaveFile::abort()
+{
+ mTempFile.close();
+ mTempFile.unlink();
+}
+
+bool
+KSaveFile::close()
+{
+ if (mTempFile.name().isEmpty() || mTempFile.handle()==-1)
+ return false; // Save was aborted already
+ if (!mTempFile.sync())
+ {
+ abort();
+ return false;
+ }
+ if (mTempFile.close())
+ {
+ if (0==KDE_rename(QFile::encodeName(mTempFile.name()), QFile::encodeName(mFileName)))
+ return true; // Success!
+ mTempFile.setError(errno);
+ }
+ // Something went wrong, make sure to delete the interim file.
+ mTempFile.unlink();
+ return false;
+}
+
+static int
+write_all(int fd, const char *buf, size_t len)
+{
+ while (len > 0)
+ {
+ int written = write(fd, buf, len);
+ if (written < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ buf += written;
+ len -= written;
+ }
+ return 0;
+}
+
+bool KSaveFile::backupFile( const QString& qFilename, const QString& backupDir,
+ const QString& backupExtension)
+{
+ QCString cFilename = QFile::encodeName(qFilename);
+ const char *filename = cFilename.data();
+
+ int fd = KDE_open( filename, O_RDONLY );
+ if (fd < 0)
+ return false;
+
+ KDE_struct_stat buff;
+ if ( KDE_fstat( fd, &buff) < 0 )
+ {
+ ::close( fd );
+ return false;
+ }
+
+ QCString cBackup;
+ if ( backupDir.isEmpty() )
+ cBackup = cFilename;
+ else
+ {
+ QCString nameOnly;
+ int slash = cFilename.findRev('/');
+ if (slash < 0)
+ nameOnly = cFilename;
+ else
+ nameOnly = cFilename.mid(slash + 1);
+ cBackup = QFile::encodeName(backupDir);
+ if ( backupDir[backupDir.length()-1] != '/' )
+ cBackup += '/';
+ cBackup += nameOnly;
+ }
+ cBackup += QFile::encodeName(backupExtension);
+ const char *backup = cBackup.data();
+ int permissions = buff.st_mode & 07777;
+
+ if ( KDE_stat( backup, &buff) == 0)
+ {
+ if ( unlink( backup ) != 0 )
+ {
+ ::close(fd);
+ return false;
+ }
+ }
+
+ mode_t old_umask = umask(0);
+ int fd2 = KDE_open( backup, O_WRONLY | O_CREAT | O_EXCL, permissions | S_IWUSR);
+ umask(old_umask);
+
+ if ( fd2 < 0 )
+ {
+ ::close(fd);
+ return false;
+ }
+
+ char buffer[ 32*1024 ];
+
+ while( 1 )
+ {
+ int n = ::read( fd, buffer, 32*1024 );
+ if (n == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ ::close(fd);
+ ::close(fd2);
+ return false;
+ }
+ if (n == 0)
+ break; // Finished
+
+ if (write_all( fd2, buffer, n))
+ {
+ ::close(fd);
+ ::close(fd2);
+ return false;
+ }
+ }
+
+ ::close( fd );
+
+ if (::close(fd2))
+ return false;
+ return true;
+}
diff --git a/kdecore/ksavefile.h b/kdecore/ksavefile.h
new file mode 100644
index 000000000..7e05aaa81
--- /dev/null
+++ b/kdecore/ksavefile.h
@@ -0,0 +1,152 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KSAVEFILE_H_
+#define _KSAVEFILE_H_
+
+#include <qstring.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ktempfile.h>
+
+class KSaveFilePrivate;
+
+/**
+ * The KSaveFile class has been made to write out changes to an existing
+ * file atomically.
+ * This means that EITHER:
+ * a)
+ * All changes have been written successfully to the file.
+ *
+ * b)
+ * Some error occurred, no changes have been written whatsoever and the
+ * old file is still in place.
+ */
+class KDECORE_EXPORT KSaveFile
+{
+public:
+ /**
+ * Creates a new KSaveFile with the given file name.
+ * @param filename the path of the file
+ * @param mode the mode of the file (see chmod(1))
+ */
+ KSaveFile(const QString &filename, int mode = 0666 );
+
+ /**
+ * The destructor closes the file.
+ * You might want to call close() explicitely though, to test whether it worked.
+ **/
+ ~KSaveFile();
+
+ /**
+ * Returns the status of the file based on errno. (see errno.h)
+ * 0 means OK.
+ *
+ * You should check the status after object creation to check
+ * whether a file could be created in the first place.
+ *
+ * You may check the status after closing the file to verify that
+ * the file has indeed been written correctly.
+ * @return the errno status, 0 means ok
+ **/
+ int status() const
+ { return mTempFile.status(); }
+
+ /**
+ * The name of the file as passed to the constructor.
+ * @return The name of the file, or QString::null if opening the
+ * file has failed
+ **/
+ QString name() const;
+
+ /**
+ * An integer file descriptor open for writing to the file.
+ * @return The file descriptor, or a negative number if opening
+ * the temporary file failed
+ **/
+ int handle() const
+ { return mTempFile.handle(); }
+
+ /**
+ * A FILE* stream open for writing to the file.
+ * @return FILE* stream open for writing to the file, or 0
+ * if opening the temporary file failed
+ **/
+ FILE *fstream()
+ { return mTempFile.fstream(); }
+
+ /**
+ * A QFile* open for writing to the file.
+ * @return A QFile open for writing to the file, or 0 if
+ * opening the temporary file failed.
+ **/
+ QFile *file()
+ { return mTempFile.file(); }
+
+ /**
+ * A QTextStream* open for writing to the file.
+ * @return A QTextStream that is open for writing to the file, or 0
+ * if opening the temporary file failed
+ **/
+ QTextStream *textStream()
+ { return mTempFile.textStream(); }
+
+ /**
+ * A QDataStream* open for writing to the file.
+ * @return A QDataStream that is open for writing to the file, or 0
+ * if opening the file failed
+ **/
+ QDataStream *dataStream()
+ { return mTempFile.dataStream(); }
+
+ /**
+ * Aborts the write operation and removes any intermediate files
+ * This implies a close.
+ **/
+ void abort();
+
+ /**
+ * Closes the file and makes the changes definitive.
+ * Returns 'true' is successful, or 'false' if an error has occurred.
+ * See status() for details about errors.
+ * @return true if successful, or false if an error has occurred.
+ **/
+ bool close();
+
+ /**
+ * Static method to create a backup file before saving.
+ * You can use this method even if you don't use KSaveFile.
+ * @param filename the file to backup
+ * @param backupDir optional directory where to save the backup file in.
+ * If empty (the default), the backup will be in the same directory as @p filename.
+ * @param backupExtension the extension to append to @p filename, "~" by default.
+ * @since 3.2
+ */
+ static bool backupFile( const QString& filename,
+ const QString& backupDir = QString::null,
+ const QString& backupExtension = QString::fromLatin1( "~" ) );
+
+private:
+ QString mFileName;
+ KTempFile mTempFile;
+
+ KSaveFilePrivate *d;
+};
+
+#endif
diff --git a/kdecore/ksharedptr.h b/kdecore/ksharedptr.h
new file mode 100644
index 000000000..ada08413b
--- /dev/null
+++ b/kdecore/ksharedptr.h
@@ -0,0 +1,175 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KSharedPTR_H
+#define KSharedPTR_H
+
+#include "kdelibs_export.h"
+
+/**
+ * Reference counting for shared objects. If you derive your object
+ * from this class, then you may use it in conjunction with
+ * KSharedPtr to control the lifetime of your object.
+ *
+ * Specifically, all classes that derive from KShared have an internal
+ * counter keeping track of how many other objects have a reference to
+ * their object. If used with KSharedPtr, then your object will
+ * not be deleted until all references to the object have been
+ * released.
+ *
+ * You should probably not ever use any of the methods in this class
+ * directly -- let the KSharedPtr take care of that. Just derive
+ * your class from KShared and forget about it.
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ */
+class KDECORE_EXPORT KShared {
+public:
+ /**
+ * Standard constructor. This will initialize the reference count
+ * on this object to 0.
+ */
+ KShared() : count(0) { }
+
+ /**
+ * Copy constructor. This will @em not actually copy the objects
+ * but it will initialize the reference count on this object to 0.
+ */
+ KShared( const KShared & ) : count(0) { }
+
+ /**
+ * Overloaded assignment operator.
+ */
+ KShared &operator=(const KShared & ) { return *this; }
+
+ /**
+ * Increases the reference count by one.
+ */
+ void _KShared_ref() const { count++; }
+
+ /**
+ * Releases a reference (decreases the reference count by one). If
+ * the count goes to 0, this object will delete itself.
+ */
+ void _KShared_unref() const { if (!--count) delete this; }
+
+ /**
+ * Return the current number of references held.
+ *
+ * @return Number of references
+ */
+ int _KShared_count() const { return count; }
+
+protected:
+ virtual ~KShared() { }
+private:
+ mutable int count;
+};
+
+/**
+ * Can be used to control the lifetime of an object that has derived
+ * KShared. As long a someone holds a KSharedPtr on some KShared
+ * object it won't become deleted but is deleted once its reference
+ * count is 0. This struct emulates C++ pointers virtually perfectly.
+ * So just use it like a simple C++ pointer.
+ *
+ * KShared and KSharedPtr are preferred over QShared / QSharedPtr
+ * since they are more safe.
+ *
+ * WARNING: Please note that this class template provides an implicit
+ * conversion to T*. Do *not* change this pointer or the pointee (don't
+ * call delete on it, for instance) behind KSharedPtr's back.
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ */
+template< class T >
+class KSharedPtr
+{
+public:
+/**
+ * Creates a null pointer.
+ */
+ KSharedPtr()
+ : ptr(0) { }
+ /**
+ * Creates a new pointer.
+ * @param t the pointer
+ */
+ KSharedPtr( T* t )
+ : ptr(t) { if ( ptr ) ptr->_KShared_ref(); }
+
+ /**
+ * Copies a pointer.
+ * @param p the pointer to copy
+ */
+ KSharedPtr( const KSharedPtr& p )
+ : ptr(p.ptr) { if ( ptr ) ptr->_KShared_ref(); }
+
+ /**
+ * Unreferences the object that this pointer points to. If it was
+ * the last reference, the object will be deleted.
+ */
+ ~KSharedPtr() { if ( ptr ) ptr->_KShared_unref(); }
+
+ KSharedPtr<T>& operator= ( const KSharedPtr<T>& p ) {
+ if ( ptr == p.ptr ) return *this;
+ if ( ptr ) ptr->_KShared_unref();
+ ptr = p.ptr;
+ if ( ptr ) ptr->_KShared_ref();
+ return *this;
+ }
+ KSharedPtr<T>& operator= ( T* p ) {
+ if ( ptr == p ) return *this;
+ if ( ptr ) ptr->_KShared_unref();
+ ptr = p;
+ if ( ptr ) ptr->_KShared_ref();
+ return *this;
+ }
+ bool operator== ( const KSharedPtr<T>& p ) const { return ( ptr == p.ptr ); }
+ bool operator!= ( const KSharedPtr<T>& p ) const { return ( ptr != p.ptr ); }
+ bool operator== ( const T* p ) const { return ( ptr == p ); }
+ bool operator!= ( const T* p ) const { return ( ptr != p ); }
+ bool operator!() const { return ( ptr == 0 ); }
+ operator T*() const { return ptr; }
+
+ /**
+ * Returns the pointer.
+ * @return the pointer
+ */
+ T* data() { return ptr; }
+
+ /**
+ * Returns the pointer.
+ * @return the pointer
+ */
+ const T* data() const { return ptr; }
+
+ const T& operator*() const { return *ptr; }
+ T& operator*() { return *ptr; }
+ const T* operator->() const { return ptr; }
+ T* operator->() { return ptr; }
+
+ /**
+ * Returns the number of references.
+ * @return the number of references
+ */
+ int count() const { return ptr->_KShared_count(); } // for debugging purposes
+private:
+ T* ptr;
+};
+
+#endif
diff --git a/kdecore/kshell.cpp b/kdecore/kshell.cpp
new file mode 100644
index 000000000..2d688a85f
--- /dev/null
+++ b/kdecore/kshell.cpp
@@ -0,0 +1,377 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kshell.h>
+
+#include <qfile.h>
+
+#include <stdlib.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+static int fromHex( QChar c )
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+inline static bool isQuoteMeta( uint c )
+{
+#if 0 // it's not worth it, especially after seeing gcc's asm output ...
+ static const uchar iqm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00
+ }; // \'"$
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+#else
+ return c == '\\' || c == '\'' || c == '"' || c == '$';
+#endif
+}
+
+inline static bool isMeta( uint c )
+{
+ static const uchar iqm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8,
+ 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38
+ }; // \'"$`<>|;&(){}*?#
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+}
+
+QStringList KShell::splitArgs( const QString &args, int flags, int *err )
+{
+ QStringList ret;
+ bool firstword = flags & AbortOnMeta;
+
+ for (uint pos = 0; ; ) {
+ QChar c;
+ do {
+ if (pos >= args.length())
+ goto okret;
+ c = args.unicode()[pos++];
+ } while (c.isSpace());
+ QString cret;
+ if ((flags & TildeExpand) && c == '~') {
+ uint opos = pos;
+ for (; ; pos++) {
+ if (pos >= args.length())
+ break;
+ c = args.unicode()[pos];
+ if (c == '/' || c.isSpace())
+ break;
+ if (isQuoteMeta( c )) {
+ pos = opos;
+ c = '~';
+ goto notilde;
+ }
+ if ((flags & AbortOnMeta) && isMeta( c ))
+ goto metaerr;
+ }
+ QString ccret = homeDir( QConstString( args.unicode() + opos, pos - opos ).string() );
+ if (ccret.isEmpty()) {
+ pos = opos;
+ c = '~';
+ goto notilde;
+ }
+ if (pos >= args.length()) {
+ ret += ccret;
+ goto okret;
+ }
+ pos++;
+ if (c.isSpace()) {
+ ret += ccret;
+ firstword = false;
+ continue;
+ }
+ cret = ccret;
+ }
+ // before the notilde label, as a tilde does not match anyway
+ if (firstword) {
+ if (c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ uint pos2 = pos;
+ QChar cc;
+ do
+ cc = args[pos2++];
+ while (cc == '_' || (cc >= 'A' && cc <= 'Z') ||
+ (cc >= 'a' && cc <= 'z') || (cc >= '0' && cc <= '9'));
+ if (cc == '=')
+ goto metaerr;
+ }
+ }
+ notilde:
+ do {
+ if (c == '\'') {
+ uint spos = pos;
+ do {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ } while (c != '\'');
+ cret += QConstString( args.unicode() + spos, pos - spos - 1 ).string();
+ } else if (c == '"') {
+ for (;;) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ if (c == '"')
+ break;
+ if (c == '\\') {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ if (c != '"' && c != '\\' &&
+ !((flags & AbortOnMeta) && (c == '$' || c == '`')))
+ cret += '\\';
+ } else if ((flags & AbortOnMeta) && (c == '$' || c == '`'))
+ goto metaerr;
+ cret += c;
+ }
+ } else if (c == '$' && args[pos] == '\'') {
+ pos++;
+ for (;;) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ if (c == '\'')
+ break;
+ if (c == '\\') {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ switch (c) {
+ case 'a': cret += '\a'; break;
+ case 'b': cret += '\b'; break;
+ case 'e': cret += '\033'; break;
+ case 'f': cret += '\f'; break;
+ case 'n': cret += '\n'; break;
+ case 'r': cret += '\r'; break;
+ case 't': cret += '\t'; break;
+ case '\\': cret += '\\'; break;
+ case '\'': cret += '\''; break;
+ case 'c': cret += args[pos++] & 31; break;
+ case 'x':
+ {
+ int hv = fromHex( args[pos] );
+ if (hv < 0) {
+ cret += "\\x";
+ } else {
+ int hhv = fromHex( args[++pos] );
+ if (hhv > 0) {
+ hv = hv * 16 + hhv;
+ pos++;
+ }
+ cret += QChar( hv );
+ }
+ break;
+ }
+ default:
+ if (c >= '0' && c <= '7') {
+ int hv = c - '0';
+ for (int i = 0; i < 2; i++) {
+ c = args[pos];
+ if (c < '0' || c > '7')
+ break;
+ hv = hv * 8 + (c - '0');
+ pos++;
+ }
+ cret += QChar( hv );
+ } else {
+ cret += '\\';
+ cret += c;
+ }
+ break;
+ }
+ } else
+ cret += c;
+ }
+ } else {
+ if (c == '\\') {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ if (!c.isSpace() &&
+ !((flags & AbortOnMeta) ? isMeta( c ) : isQuoteMeta( c )))
+ cret += '\\';
+ } else if ((flags & AbortOnMeta) && isMeta( c ))
+ goto metaerr;
+ cret += c;
+ }
+ if (pos >= args.length())
+ break;
+ c = args.unicode()[pos++];
+ } while (!c.isSpace());
+ ret += cret;
+ firstword = false;
+ }
+
+ okret:
+ if (err)
+ *err = NoError;
+ return ret;
+
+ quoteerr:
+ if (err)
+ *err = BadQuoting;
+ return QStringList();
+
+ metaerr:
+ if (err)
+ *err = FoundMeta;
+ return QStringList();
+}
+
+inline static bool isSpecial( uint c )
+{
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xdd, 0x07, 0x00, 0xd8,
+ 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38
+ }; // 0-32 \'"$`<>|;&(){}*?#
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+}
+
+QString KShell::joinArgs( const QStringList &args )
+{
+ QChar q( '\'' );
+ QString ret;
+ for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) {
+ if (!ret.isEmpty())
+ ret += ' ';
+ if (!(*it).length())
+ ret.append( q ).append( q );
+ else {
+ for (uint i = 0; i < (*it).length(); i++)
+ if (isSpecial((*it).unicode()[i])) {
+ QString tmp(*it);
+ tmp.replace( q, "'\\''" );
+ ret += q;
+ tmp += q;
+ ret += tmp;
+ goto ex;
+ }
+ ret += *it;
+ ex: ;
+ }
+ }
+ return ret;
+}
+
+QString KShell::joinArgs( const char * const *args, int nargs )
+{
+ if (!args)
+ return QString::null; // well, QString::empty, in fact. qt sucks ;)
+ QChar q( '\'' );
+ QString ret;
+ for (const char * const *argp = args; nargs && *argp; argp++, nargs--) {
+ if (!ret.isEmpty())
+ ret += ' ';
+ if (!**argp)
+ ret.append( q ).append( q );
+ else {
+ QString tmp( QFile::decodeName( *argp ) );
+ for (uint i = 0; i < tmp.length(); i++)
+ if (isSpecial(tmp.unicode()[i])) {
+ tmp.replace( q, "'\\''" );
+ ret += q;
+ tmp += q;
+ ret += tmp;
+ goto ex;
+ }
+ ret += tmp;
+ ex: ;
+ }
+ }
+ return ret;
+}
+
+QString KShell::joinArgsDQ( const QStringList &args )
+{
+ QChar q( '\'' ), sp( ' ' ), bs( '\\' );
+ QString ret;
+ for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) {
+ if (!ret.isEmpty())
+ ret += sp;
+ if (!(*it).length())
+ ret.append( q ).append( q );
+ else {
+ for (uint i = 0; i < (*it).length(); i++)
+ if (isSpecial((*it).unicode()[i])) {
+ ret.append( '$' ).append( q );
+ for (uint pos = 0; pos < (*it).length(); pos++) {
+ int c = (*it).unicode()[pos];
+ if (c < 32) {
+ ret += bs;
+ switch (c) {
+ case '\a': ret += 'a'; break;
+ case '\b': ret += 'b'; break;
+ case '\033': ret += 'e'; break;
+ case '\f': ret += 'f'; break;
+ case '\n': ret += 'n'; break;
+ case '\r': ret += 'r'; break;
+ case '\t': ret += 't'; break;
+ case '\034': ret += 'c'; ret += '|'; break;
+ default: ret += 'c'; ret += c + '@'; break;
+ }
+ } else {
+ if (c == '\'' || c == '\\')
+ ret += bs;
+ ret += c;
+ }
+ }
+ ret.append( q );
+ goto ex;
+ }
+ ret += *it;
+ ex: ;
+ }
+ }
+ return ret;
+}
+
+QString KShell::tildeExpand( const QString &fname )
+{
+ if (fname[0] == '~') {
+ int pos = fname.find( '/' );
+ if (pos < 0)
+ return homeDir( QConstString( fname.unicode() + 1, fname.length() - 1 ).string() );
+ QString ret = homeDir( QConstString( fname.unicode() + 1, pos - 1 ).string() );
+ if (!ret.isNull())
+ ret += QConstString( fname.unicode() + pos, fname.length() - pos ).string();
+ return ret;
+ }
+ return fname;
+}
+
+QString KShell::homeDir( const QString &user )
+{
+ if (user.isEmpty())
+ return QFile::decodeName( getenv( "HOME" ) );
+ struct passwd *pw = getpwnam( QFile::encodeName( user ).data() );
+ if (!pw)
+ return QString::null;
+ return QFile::decodeName( pw->pw_dir );
+}
diff --git a/kdecore/kshell.h b/kdecore/kshell.h
new file mode 100644
index 000000000..1b52de099
--- /dev/null
+++ b/kdecore/kshell.h
@@ -0,0 +1,147 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KSHELL_H
+#define _KSHELL_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include "kdelibs_export.h"
+
+/**
+ * \namespace KShell
+ * Provides some basic POSIX shell and bash functionality.
+ * @see KStringHandler
+ *
+ * @since 3.2
+ */
+namespace KShell {
+
+ /**
+ * Flags for splitArgs().
+ */
+ enum Options {
+ NoOptions = 0,
+
+ /**
+ * Perform tilde expansion.
+ */
+ TildeExpand = 1,
+
+ /**
+ * Bail out if a non-quoting and not quoted shell meta character is encoutered.
+ * Meta characters are the command separators @p semicolon and @p ampersand,
+ * the redirection symbols @p less-than, @p greater-than and the @p pipe @p symbol,
+ * the grouping symbols opening and closing @p parens and @p braces, the command
+ * substitution symbol @p backquote, the generic substitution symbol @p dollar
+ * (if not followed by an apostrophe), the wildcards @p asterisk and
+ * @p question @p mark, and the comment symbol @p hash @p mark. Additionally,
+ * a variable assignment in the first word is recognized.
+ */
+ AbortOnMeta = 2
+ };
+
+ /**
+ * Status codes from splitArgs()
+ */
+ enum Errors {
+ /**
+ * Success.
+ */
+ NoError = 0,
+
+ /**
+ * Indicates a parsing error, like an unterminated quoted string.
+ */
+ BadQuoting,
+
+ /**
+ * The AbortOnMeta flag was set and a shell meta character
+ * was encoutered.
+ */
+ FoundMeta
+ };
+
+ /**
+ * Splits @p cmd according to POSIX shell word splitting and quoting rules.
+ * Can optionally perform tilde expansion and/or abort if it finds shell
+ * meta characters it cannot process.
+ *
+ * @param cmd the command to split
+ * @param flags operation flags, see Options
+ * @param err if not NULL, a status code will be stored at the pointer
+ * target, see Errors
+ * @return a list of unquoted words or an empty list if an error occurred
+ */
+ KDECORE_EXPORT QStringList splitArgs( const QString &cmd, int flags = 0, int *err = 0 );
+
+ /**
+ * Quotes and joins @p args together according to POSIX shell rules.
+ *
+ * @param args a list of strings to quote and join
+ * @return a command suitable for shell execution
+ */
+ KDECORE_EXPORT QString joinArgs( const QStringList &args );
+
+ /**
+ * Same as above, but $'' is used instead of '' for the quoting.
+ * The output is suitable for splitArgs(), bash, zsh and possibly
+ * other bourne-compatible shells, but not for plain sh. The advantage
+ * is, that control characters (ASCII less than 32) are escaped into
+ * human-readable strings.
+ *
+ * @param args a list of strings to quote and join
+ * @return a command suitable for shell execution
+ */
+ KDECORE_EXPORT QString joinArgsDQ( const QStringList &args );
+
+ /**
+ * Quotes and joins @p argv together according to POSIX shell rules.
+ *
+ * @param argv an array of c strings to quote and join.
+ * The strings are expected to be in local-8-bit encoding.
+ * @param argc maximal number of strings in @p argv. if not supplied,
+ * @p argv must be null-terminated.
+ * @return a command suitable for shell execution
+ */
+ KDECORE_EXPORT QString joinArgs( const char * const *argv, int argc = -1 );
+
+ /**
+ * Performs tilde expansion on @p path. Interprets "~/path" and
+ * "~user/path".
+ *
+ * @param path the path to tilde-expand
+ * @return the expanded path
+ */
+ KDECORE_EXPORT QString tildeExpand( const QString &path );
+
+ /**
+ * Obtain a @p user's home directory.
+ *
+ * @param user The name of the user whose home dir should be obtained.
+ * An empty string denotes the current user.
+ * @return The user's home directory.
+ */
+ KDECORE_EXPORT QString homeDir( const QString &user );
+
+}
+
+
+#endif /* _KSHELL_H */
diff --git a/kdecore/kshortcut.cpp b/kdecore/kshortcut.cpp
new file mode 100644
index 000000000..4e03b1a2a
--- /dev/null
+++ b/kdecore/kshortcut.cpp
@@ -0,0 +1,671 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kshortcut.h"
+#include "kkeynative.h"
+#include "kkeyserver.h"
+
+#include <qevent.h>
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <ksimpleconfig.h>
+
+//----------------------------------------------------
+
+static KKey* g_pspec = 0;
+static KKeySequence* g_pseq = 0;
+static KShortcut* g_pcut = 0;
+
+//----------------------------------------------------
+// KKey
+//----------------------------------------------------
+
+KKey::KKey() { clear(); }
+KKey::KKey( uint key, uint modFlags ) { init( key, modFlags ); }
+KKey::KKey( int keyQt ) { init( keyQt ); }
+KKey::KKey( const QKeySequence& seq ) { init( seq ); }
+KKey::KKey( const QKeyEvent* pEvent ) { init( pEvent ); }
+KKey::KKey( const KKey& key ) { init( key ); }
+KKey::KKey( const QString& sKey ) { init( sKey ); }
+
+KKey::~KKey()
+{
+}
+
+void KKey::clear()
+{
+ m_sym = 0;
+ m_mod = 0;
+}
+
+bool KKey::init( uint key, uint modFlags )
+{
+ m_sym = key;
+ m_mod = modFlags;
+ return true;
+}
+
+bool KKey::init( int keyQt )
+{
+ //KKeyServer::Sym sym;
+
+ //if( sym.initQt( keyQt )
+ if( KKeyServer::keyQtToSym( keyQt, m_sym )
+ && KKeyServer::keyQtToMod( keyQt, m_mod ) )
+ return true;
+ else {
+ m_sym = 0;
+ m_mod = 0;
+ return false;
+ }
+}
+
+bool KKey::init( const QKeySequence& key )
+{
+ // TODO: if key.count() > 1, should we return failure?
+ return init( (int) key );
+}
+
+bool KKey::init( const QKeyEvent* pEvent )
+{
+ int keyQt = pEvent->key();
+ if( pEvent->state() & Qt::ShiftButton ) keyQt |= Qt::SHIFT;
+ if( pEvent->state() & Qt::ControlButton ) keyQt |= Qt::CTRL;
+ if( pEvent->state() & Qt::AltButton ) keyQt |= Qt::ALT;
+ if( pEvent->state() & Qt::MetaButton ) keyQt |= Qt::META;
+ return init( keyQt );
+}
+
+bool KKey::init( const KKey& key )
+{
+ m_sym = key.m_sym;
+ m_mod = key.m_mod;
+ return true;
+}
+
+bool KKey::init( const QString& sSpec )
+{
+ clear();
+
+ QString sKey = sSpec.stripWhiteSpace();
+ if( sKey.startsWith( "default(" ) && sKey.endsWith( ")" ) )
+ sKey = sKey.mid( 8, sKey.length() - 9 );
+ // i.e., "Ctrl++" = "Ctrl+Plus"
+ if( sKey.endsWith( "++" ) )
+ sKey = sKey.left( sKey.length() - 1 ) + "plus";
+ QStringList rgs = QStringList::split( '+', sKey, true );
+
+ uint i;
+ // Check for modifier keys first.
+ for( i = 0; i < rgs.size(); i++ ) {
+ QString s = rgs[i].lower();
+ if( s == "shift" ) m_mod |= KKey::SHIFT;
+ else if( s == "ctrl" ) m_mod |= KKey::CTRL;
+ else if( s == "alt" ) m_mod |= KKey::ALT;
+ else if( s == "win" ) m_mod |= KKey::WIN;
+ else if( s == "meta" ) m_mod |= KKey::WIN;
+ else {
+ uint m = KKeyServer::stringUserToMod( s );
+ if( m != 0 ) m_mod |= m;
+ else break;
+ }
+ }
+ // If there is one non-blank key left:
+ if( (i == rgs.size() - 1 && !rgs[i].isEmpty()) ) {
+ KKeyServer::Sym sym( rgs[i] );
+ m_sym = sym.m_sym;
+ }
+
+ if( m_sym == 0 )
+ m_mod = 0;
+
+ kdDebug(125) << "KKey::init( \"" << sSpec << "\" ):"
+ << " m_sym = " << QString::number(m_sym, 16)
+ << ", m_mod = " << QString::number(m_mod, 16) << endl;
+
+ return m_sym != 0;
+}
+
+bool KKey::isNull() const { return m_sym == 0; }
+uint KKey::sym() const { return m_sym; }
+uint KKey::modFlags() const { return m_mod; }
+
+int KKey::compare( const KKey& spec ) const
+{
+ if( m_sym != spec.m_sym )
+ return m_sym - spec.m_sym;
+ if( m_mod != spec.m_mod )
+ return m_mod - spec.m_mod;
+ return 0;
+}
+
+int KKey::keyCodeQt() const
+{
+ return KKeyNative( *this ).keyCodeQt();
+}
+
+QString KKey::toString() const
+{
+ QString s;
+
+ s = KKeyServer::modToStringUser( m_mod );
+ if( !s.isEmpty() )
+ s += '+';
+ s += KKeyServer::Sym(m_sym).toString();
+
+ return s;
+}
+
+QString KKey::toStringInternal() const
+{
+ //kdDebug(125) << "KKey::toStringInternal(): this = " << this
+ // << " mod = " << QString::number(m_mod, 16)
+ // << " key = " << QString::number(m_sym, 16) << endl;
+ QString s;
+
+ s = KKeyServer::modToStringInternal( m_mod );
+ if( !s.isEmpty() )
+ s += '+';
+ s += KKeyServer::Sym(m_sym).toStringInternal();
+ return s;
+}
+
+KKey& KKey::null()
+{
+ if( !g_pspec )
+ g_pspec = new KKey;
+ if( !g_pspec->isNull() )
+ g_pspec->clear();
+ return *g_pspec;
+}
+
+QString KKey::modFlagLabel( ModFlag modFlag )
+{
+ return KKeyServer::modToStringUser( modFlag );
+}
+
+//---------------------------------------------------------------------
+// KKeySequence
+//---------------------------------------------------------------------
+
+KKeySequence::KKeySequence() { clear(); }
+KKeySequence::KKeySequence( const QKeySequence& seq ) { init( seq ); }
+KKeySequence::KKeySequence( const KKey& key ) { init( key ); }
+KKeySequence::KKeySequence( const KKeySequence& seq ) { init( seq ); }
+KKeySequence::KKeySequence( const QString& s ) { init( s ); }
+
+KKeySequence::~KKeySequence()
+{
+}
+
+void KKeySequence::clear()
+{
+ m_nKeys = 0;
+ m_bTriggerOnRelease = false;
+}
+
+bool KKeySequence::init( const QKeySequence& seq )
+{
+ clear();
+ if( !seq.isEmpty() ) {
+ for( uint i = 0; i < seq.count(); i++ ) {
+ m_rgvar[i].init( seq[i] );
+ if( m_rgvar[i].isNull() )
+ return false;
+ }
+ m_nKeys = seq.count();
+ m_bTriggerOnRelease = false;
+ }
+ return true;
+}
+
+bool KKeySequence::init( const KKey& key )
+{
+ if( !key.isNull() ) {
+ m_nKeys = 1;
+ m_rgvar[0].init( key );
+ m_bTriggerOnRelease = false;
+ } else
+ clear();
+ return true;
+}
+
+bool KKeySequence::init( const KKeySequence& seq )
+{
+ m_bTriggerOnRelease = false;
+ m_nKeys = seq.m_nKeys;
+ for( uint i = 0; i < m_nKeys; i++ ) {
+ if( seq.m_rgvar[i].isNull() ) {
+ kdDebug(125) << "KKeySequence::init( seq ): key[" << i << "] is null." << endl;
+ m_nKeys = 0;
+ return false;
+ }
+ m_rgvar[i] = seq.m_rgvar[i];
+ }
+ return true;
+}
+
+bool KKeySequence::init( const QString& s )
+{
+ m_bTriggerOnRelease = false;
+ //kdDebug(125) << "KKeySequence::init( " << s << " )" << endl;
+ QStringList rgs = QStringList::split( ',', s );
+ if( s == "none" || rgs.size() == 0 ) {
+ clear();
+ return true;
+ } else if( rgs.size() <= MAX_KEYS ) {
+ m_nKeys = rgs.size();
+ for( uint i = 0; i < m_nKeys; i++ ) {
+ m_rgvar[i].init( KKey(rgs[i]) );
+ //kdDebug(125) << "\t'" << rgs[i] << "' => " << m_rgvar[i].toStringInternal() << endl;
+ }
+ return true;
+ } else {
+ clear();
+ return false;
+ }
+}
+
+uint KKeySequence::count() const
+{
+ return m_nKeys;
+}
+
+const KKey& KKeySequence::key( uint i ) const
+{
+ if( i < m_nKeys )
+ return m_rgvar[i];
+ else
+ return KKey::null();
+}
+
+bool KKeySequence::isTriggerOnRelease() const
+ { return m_bTriggerOnRelease; }
+
+bool KKeySequence::setKey( uint iKey, const KKey& key )
+{
+ if( iKey <= m_nKeys && iKey < MAX_KEYS ) {
+ m_rgvar[iKey].init( key );
+ if( iKey == m_nKeys )
+ m_nKeys++;
+ return true;
+ } else
+ return false;
+}
+
+bool KKeySequence::isNull() const
+{
+ return m_nKeys == 0;
+}
+
+bool KKeySequence::startsWith( const KKeySequence& seq ) const
+{
+ if( m_nKeys < seq.m_nKeys )
+ return false;
+
+ for( uint i = 0; i < seq.m_nKeys; i++ ) {
+ if( m_rgvar[i] != seq.m_rgvar[i] )
+ return false;
+ }
+
+ return true;
+}
+
+int KKeySequence::compare( const KKeySequence& seq ) const
+{
+ for( uint i = 0; i < m_nKeys && i < seq.m_nKeys; i++ ) {
+ int ret = m_rgvar[i].compare( seq.m_rgvar[i] );
+ if( ret != 0 )
+ return ret;
+ }
+ if( m_nKeys != seq.m_nKeys )
+ return m_nKeys - seq.m_nKeys;
+ else
+ return 0;
+}
+
+QKeySequence KKeySequence::qt() const
+{
+ int k[4] = { 0, 0, 0, 0 };
+
+ for( uint i = 0; i < count(); i++ )
+ k[i] = KKeyNative(key(i)).keyCodeQt();
+ QKeySequence seq( k[0], k[1], k[2], k[3] );
+ return seq;
+}
+
+int KKeySequence::keyCodeQt() const
+{
+ return (count() == 1) ? KKeyNative(key(0)).keyCodeQt() : 0;
+}
+
+QString KKeySequence::toString() const
+{
+ if( m_nKeys < 1 ) return QString::null;
+
+ QString s;
+ s = m_rgvar[0].toString();
+ for( uint i = 1; i < m_nKeys; i++ ) {
+ s += ",";
+ s += m_rgvar[i].toString();
+ }
+
+ return s;
+}
+
+QString KKeySequence::toStringInternal() const
+{
+ if( m_nKeys < 1 ) return QString::null;
+
+ QString s;
+ s = m_rgvar[0].toStringInternal();
+ for( uint i = 1; i < m_nKeys; i++ ) {
+ s += ",";
+ s += m_rgvar[i].toStringInternal();
+ }
+
+ return s;
+}
+
+KKeySequence& KKeySequence::null()
+{
+ if( !g_pseq )
+ g_pseq = new KKeySequence;
+ if( !g_pseq->isNull() )
+ g_pseq->clear();
+ return *g_pseq;
+}
+
+//---------------------------------------------------------------------
+// KShortcut
+//---------------------------------------------------------------------
+
+KShortcut::KShortcut() { clear(); }
+KShortcut::KShortcut( int keyQt ) { init( keyQt ); }
+KShortcut::KShortcut( const QKeySequence& key ) { init( key ); }
+KShortcut::KShortcut( const KKey& key ) { init( key ); }
+KShortcut::KShortcut( const KKeySequence& seq ) { init( seq ); }
+KShortcut::KShortcut( const KShortcut& cut ) { init( cut ); }
+KShortcut::KShortcut( const char* ps ) { init( QString(ps) ); }
+KShortcut::KShortcut( const QString& s ) { init( s ); }
+
+KShortcut::~KShortcut()
+{
+}
+
+void KShortcut::clear()
+{
+ m_nSeqs = 0;
+}
+
+bool KShortcut::init( int keyQt )
+{
+ if( keyQt ) {
+ m_nSeqs = 1;
+ m_rgseq[0].init( QKeySequence(keyQt) );
+ } else
+ clear();
+ return true;
+}
+
+bool KShortcut::init( const QKeySequence& key )
+{
+ m_nSeqs = 1;
+ m_rgseq[0].init( key );
+ return true;
+}
+
+bool KShortcut::init( const KKey& spec )
+{
+ m_nSeqs = 1;
+ m_rgseq[0].init( spec );
+ return true;
+}
+
+bool KShortcut::init( const KKeySequence& seq )
+{
+ m_nSeqs = 1;
+ m_rgseq[0] = seq;
+ return true;
+}
+
+bool KShortcut::init( const KShortcut& cut )
+{
+ m_nSeqs = cut.m_nSeqs;
+ for( uint i = 0; i < m_nSeqs; i++ )
+ m_rgseq[i] = cut.m_rgseq[i];
+ return true;
+}
+
+bool KShortcut::init( const QString& s )
+{
+ bool bRet = true;
+ QStringList rgs = QStringList::split( ';', s );
+
+ if( s == "none" || rgs.size() == 0 )
+ clear();
+ else if( rgs.size() <= MAX_SEQUENCES ) {
+ m_nSeqs = rgs.size();
+ for( uint i = 0; i < m_nSeqs; i++ ) {
+ QString& sSeq = rgs[i];
+ if( sSeq.startsWith( "default(" ) )
+ sSeq = sSeq.mid( 8, sSeq.length() - 9 );
+ m_rgseq[i].init( sSeq );
+ //kdDebug(125) << "*\t'" << sSeq << "' => " << m_rgseq[i].toStringInternal() << endl;
+ }
+ } else {
+ clear();
+ bRet = false;
+ }
+
+ if( !s.isEmpty() ) {
+ QString sDebug;
+ QTextStream os( &sDebug, IO_WriteOnly );
+ os << "KShortcut::init( \"" << s << "\" ): ";
+ for( uint i = 0; i < m_nSeqs; i++ ) {
+ os << " m_rgseq[" << i << "]: ";
+ KKeyServer::Variations vars;
+ vars.init( m_rgseq[i].key(0), true );
+ for( uint j = 0; j < vars.count(); j++ )
+ os << QString::number(vars.m_rgkey[j].keyCodeQt(),16) << ',';
+ }
+ kdDebug(125) << sDebug << endl;
+ }
+
+ return bRet;
+}
+
+uint KShortcut::count() const
+{
+ return m_nSeqs;
+}
+
+const KKeySequence& KShortcut::seq( uint i ) const
+{
+ return (i < m_nSeqs) ? m_rgseq[i] : KKeySequence::null();
+}
+
+int KShortcut::keyCodeQt() const
+{
+ if( m_nSeqs >= 1 )
+ return m_rgseq[0].keyCodeQt();
+ return QKeySequence();
+}
+
+bool KShortcut::isNull() const
+{
+ return m_nSeqs == 0;
+}
+
+int KShortcut::compare( const KShortcut& cut ) const
+{
+ for( uint i = 0; i < m_nSeqs && i < cut.m_nSeqs; i++ ) {
+ int ret = m_rgseq[i].compare( cut.m_rgseq[i] );
+ if( ret != 0 )
+ return ret;
+ }
+ return m_nSeqs - cut.m_nSeqs;
+}
+
+bool KShortcut::contains( const KKey& key ) const
+{
+ return contains( KKeySequence(key) );
+}
+
+bool KShortcut::contains( const KKeyNative& keyNative ) const
+{
+ KKey key = keyNative.key();
+ key.simplify();
+
+ for( uint i = 0; i < count(); i++ ) {
+ if( !m_rgseq[i].isNull()
+ && m_rgseq[i].count() == 1
+ && m_rgseq[i].key(0) == key )
+ return true;
+ }
+ return false;
+}
+
+bool KShortcut::contains( const KKeySequence& seq ) const
+{
+ for( uint i = 0; i < count(); i++ ) {
+ if( !m_rgseq[i].isNull() && m_rgseq[i] == seq )
+ return true;
+ }
+ return false;
+}
+
+bool KShortcut::setSeq( uint iSeq, const KKeySequence& seq )
+{
+ // TODO: check if seq is null, and act accordingly.
+ if( iSeq <= m_nSeqs && iSeq < MAX_SEQUENCES ) {
+ m_rgseq[iSeq] = seq;
+ if( iSeq == m_nSeqs )
+ m_nSeqs++;
+ return true;
+ } else
+ return false;
+}
+
+void KShortcut::remove( const KKeySequence& seq )
+{
+ if (seq.isNull()) return;
+
+ for( uint iSeq = 0; iSeq < m_nSeqs; iSeq++ )
+ {
+ if (m_rgseq[iSeq] == seq)
+ {
+ for( uint jSeq = iSeq + 1; jSeq < m_nSeqs; jSeq++)
+ m_rgseq[jSeq-1] = m_rgseq[jSeq];
+ m_nSeqs--;
+ }
+ }
+}
+
+bool KShortcut::append( const KKeySequence& seq )
+{
+ if( m_nSeqs < MAX_SEQUENCES ) {
+ if( !seq.isNull() ) {
+ m_rgseq[m_nSeqs] = seq;
+ m_nSeqs++;
+ }
+ return true;
+ } else
+ return false;
+}
+
+bool KShortcut::append( const KKey& spec )
+{
+ if( m_nSeqs < MAX_SEQUENCES ) {
+ m_rgseq[m_nSeqs].init( spec );
+ m_nSeqs++;
+ return true;
+ } else
+ return false;
+}
+
+bool KShortcut::append( const KShortcut& cut )
+{
+ uint seqs = m_nSeqs, co = cut.count();
+ for( uint i=0; i<co; i++ ) {
+ if (!contains(cut.seq(i))) seqs++;
+ }
+ if( seqs > MAX_SEQUENCES ) return false;
+
+ for( uint i=0; i<co; i++ ) {
+ const KKeySequence& seq = cut.seq(i);
+ if(!contains(seq)) {
+ m_rgseq[m_nSeqs] = seq;
+ m_nSeqs++;
+ }
+ }
+ return true;
+}
+
+KShortcut::operator QKeySequence () const
+{
+ if( count() >= 1 )
+ return m_rgseq[0].qt();
+ else
+ return QKeySequence();
+}
+
+QString KShortcut::toString() const
+{
+ QString s;
+
+ for( uint i = 0; i < count(); i++ ) {
+ s += m_rgseq[i].toString();
+ if( i < count() - 1 )
+ s += ';';
+ }
+
+ return s;
+}
+
+QString KShortcut::toStringInternal( const KShortcut* pcutDefault ) const
+{
+ QString s;
+
+ for( uint i = 0; i < count(); i++ ) {
+ const KKeySequence& seq = m_rgseq[i];
+ if( pcutDefault && i < pcutDefault->count() && seq == (*pcutDefault).seq(i) ) {
+ s += "default(";
+ s += seq.toStringInternal();
+ s += ")";
+ } else
+ s += seq.toStringInternal();
+ if( i < count() - 1 )
+ s += ';';
+ }
+
+ return s;
+}
+
+KShortcut& KShortcut::null()
+{
+ if( !g_pcut )
+ g_pcut = new KShortcut;
+ if( !g_pcut->isNull() )
+ g_pcut->clear();
+ return *g_pcut;
+}
diff --git a/kdecore/kshortcut.h b/kdecore/kshortcut.h
new file mode 100644
index 000000000..b06e19f23
--- /dev/null
+++ b/kdecore/kshortcut.h
@@ -0,0 +1,851 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KSHORTCUT_H
+#define __KSHORTCUT_H
+
+#include <qkeysequence.h>
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+class QKeyEvent;
+class KKeyNative;
+
+/**
+* A KKey object represents a single key with possible modifiers
+* (Shift, Ctrl, Alt, Win). It can represent both keys which are
+* understood by Qt as well as those which are additionally supported
+* by the underlying system (e.g. X11).
+* @see KKeyNative
+* @see KKeySequence
+* @see KShortcut
+*/
+
+class KDECORE_EXPORT KKey
+{
+ public:
+ /**
+ * The number of flags.
+ * @see ModFlag
+ */
+ enum { MOD_FLAG_COUNT = 4 };
+ enum { QtWIN = (Qt::META) };
+ /**
+ * Flags to represent the modifiers. You can combine modifiers
+ * by ORing them.
+ */
+ enum ModFlag {
+ SHIFT = 0x01,
+ CTRL = 0x02,
+ ALT = 0x04,
+ WIN = 0x08
+ };
+
+ /**
+ * Creates a new null KKey.
+ * @see clear()
+ * @see isNull()
+ * @see null()
+ */
+ KKey();
+
+ /**
+ * Creates a new key for the given Qt key code.
+ * @param keyQt the qt keycode
+ * @see Qt::Key
+ */
+ KKey( int keyQt );
+
+ /**
+ * Creates a new key from the first key code of the given key sequence.
+ * @param keySeq the key sequence that contains the key
+ */
+ KKey( const QKeySequence& keySeq );
+
+ /**
+ * Extracts the key from the given key event.
+ * @param keyEvent the key event to get the key from
+ */
+ KKey( const QKeyEvent* keyEvent );
+
+ /**
+ * Copy constructor.
+ */
+ KKey( const KKey& key );
+
+ /**
+ * Creates a new key from the given description. The form of the description
+ * is "[modifier+[modifier+]]+key", for example "e", "CTRL+q" or
+ * "CTRL+ALT+DEL". Allowed modifiers are "SHIFT", "CTRL", "ALT", "WIN" and
+ * "META". "WIN" and "META" are equivalent. Modifiers are not case-sensitive.
+ * @param key the description of the key
+ * @see KKeyServer::Sym::init()
+ */
+ KKey( const QString& key );
+ /**
+ * @internal
+ */
+ KKey( uint key, uint mod );
+ ~KKey();
+
+ // Initialization methods
+ /**
+ * Clears the key. The key is null after calling this function.
+ * @see isNull()
+ */
+ void clear();
+
+ /**
+ * Initializes the key with the given Qt key code.
+ * @param keyQt the qt keycode
+ * @return true if successful, false otherwise
+ * @see Qt::Key
+ */
+ bool init( int keyQt );
+
+ /**
+ * Initializes the key with the first key code of the given key sequence.
+ * @param keySeq the key sequence that contains the key
+ * @return true if successful, false otherwise
+ */
+ bool init( const QKeySequence& keySeq );
+
+ /**
+ * Initializes the key by extracting the code from the given key event.
+ * @param keyEvent the key event to get the key from
+ * @return true if successful, false otherwise
+ */
+ bool init( const QKeyEvent* keyEvent );
+
+ /**
+ * Copies the given key.
+ * @param key the key to copy
+ * @return true if successful, false otherwise
+ */
+ bool init( const KKey& key );
+
+ /**
+ * Initializes the key with the given description. The form of the description
+ * is "[modifier+[modifier+]]+key", for example "e", "CTRL+q" or
+ * "CTRL+ALT+DEL". Allowed modifiers are "SHIFT", "CTRL", "ALT", "WIN" and
+ * "META". "WIN" and "META" are equivalent. Modifiers are not case-sensitive.
+ * @param key the description of the key
+ * @return true if successful, false otherwise
+ * @see KKeyServer::Sym::init()
+ */
+ bool init( const QString& key);
+
+ /**
+ * @internal
+ */
+ bool init( uint key, uint mod );
+
+ /**
+ * Copies the key.
+ */
+ KKey& operator =( const KKey& key )
+ { init( key ); return *this; }
+
+ // Query methods.
+ /**
+ * Returns true if the key is null (after clear() or empty
+ * constructor).
+ * @return true if the key is null
+ * @see clear()
+ * @see null()
+ */
+ bool isNull() const;
+
+ /**
+ * @internal
+ */
+ uint sym() const;
+ /**
+ * @internal
+ */
+ uint modFlags() const;
+
+ // Comparison Methods
+ /**
+ * Compares this key with the given KKey object. Returns a negative
+ * number if the given KKey is larger, 0 if they are equal and
+ * a positive number this KKey is larger. The returned value
+ * is the difference between the symbol or, if the symbols
+ * are equal, the difference between the encoded modifiers.
+ * @param key the key to compare with this key
+ * @return a negative number if the given KKey is larger, 0 if
+ * they are equal and a positive number this KKey is larger
+ */
+ int compare( const KKey& key ) const;
+
+ /**
+ * Compares the symbol and modifiers of both keys.
+ * @see compare()
+ */
+ bool operator == ( const KKey& key ) const
+ { return compare( key ) == 0; }
+ /**
+ * Compares the symbol and modifiers of both keys.
+ * @see compare()
+ */
+ bool operator != ( const KKey& key ) const
+ { return compare( key ) != 0; }
+ /**
+ * Compares the symbol and modifiers of both keys.
+ * @see compare()
+ */
+ bool operator < ( const KKey& key ) const
+ { return compare( key ) < 0; }
+
+ // Conversion methods.
+ /**
+ * Returns the qt key code.
+ * @return the qt key code or 0 if there is no key set.
+ * @see Qt::Key
+ */
+ int keyCodeQt() const;
+
+ /**
+ * Returns a human-readable representation of the key in the form
+ * "modifier+key". Note that the representation is localised,
+ * use toStringInternal() for cases like saving to configuration files.
+ * @return the string representation of the key
+ * @see toStringInternal()
+ */
+ QString toString() const;
+
+ /**
+ * Returns an untranslated text representation of the key in the form
+ * "modifier+key", suitable e.g. for saving in configuration files.
+ */
+ QString toStringInternal() const;
+
+ // Operation methods
+ /**
+ * @internal
+ */
+ void simplify();
+
+ /**
+ * Returns a null key.
+ * @return the null key
+ * @see isNull()
+ * @see clear()
+ */
+ static KKey& null();
+
+ /**
+ * Returns a user-readable representation of the given modifiers.
+ * @param f the modifiers to convert
+ * @return the string representation of the modifiers
+ */
+ static QString modFlagLabel( ModFlag f );
+
+ private:
+ /*
+ * Under X11, m_key will hold an X11 key symbol.
+ * For Qt/Embedded, it will hold the Qt key code.
+ */
+ /**
+ * Returns the native key symbol value key. Under X11, this is the X
+ * keycode. Under Qt/Embedded, this is the Qt keycode.
+ * @see /usr/include/X11/keysymdef.h
+ * @see qnamespace.h
+ */
+ uint m_sym;
+ /**
+ * m_mod holds the
+ */
+ uint m_mod;
+
+ private:
+ friend class KKeyNative;
+};
+
+/**
+* A KKeySequence object holds a sequence of up to 4 keys.
+* Ex: Ctrl+X,I
+* @see KKey
+* @see KShortcut
+*/
+
+class KDECORE_EXPORT KKeySequence
+{
+ public:
+ /// Defines the maximum length of the key sequence
+ enum { MAX_KEYS = 4 };
+
+ /**
+ * Create a new null key sequence.
+ * @see isNull()
+ * @see null()
+ * @see clear()
+ */
+ KKeySequence();
+
+ /**
+ * Copies the given qt key sequence.
+ * @param keySeq the qt key sequence to copy
+ */
+ KKeySequence( const QKeySequence& keySeq );
+
+ /**
+ * Create a new key sequence that only contains the given key.
+ * @param key the key to add
+ */
+ KKeySequence( const KKey& key );
+
+ /**
+ * Create a new key sequence that only contains the given key.
+ * @param key the key to add
+ */
+ KKeySequence( const KKeyNative& key );
+
+ /**
+ * Copies the given key sequence.
+ * @param keySeq the key sequence to copy
+ */
+ KKeySequence( const KKeySequence& keySeq );
+
+ /**
+ * Creates a new key sequence that contains the given key sequence.
+ * The description consists of comma-separated keys as
+ * required by KKey::KKey(const QString&).
+ * @param keySeq the description of the key
+ * @see KKeyServer::Sym::init()
+ * @see KKey::KKey(const QString&)
+ */
+ KKeySequence( const QString& keySeq );
+
+ ~KKeySequence();
+
+ /**
+ * Clears the key sequence. The key sequence is null after calling this
+ * function.
+ * @see isNull()
+ */
+ void clear();
+
+ /**
+ * Copies the given qt key sequence over this key sequence.
+ * @param keySeq the qt key sequence to copy
+ * @return true if successful, false otherwise
+ */
+ bool init( const QKeySequence& keySeq );
+
+ /**
+ * Initializes the key sequence to only contain the given key.
+ * @param key the key to set
+ * @return true if successful, false otherwise
+ */
+ bool init( const KKey& key );
+
+ /**
+ * Initializes the key sequence to only contain the given key.
+ * @param key the key to set
+ * @return true if successful, false otherwise
+ */
+ bool init( const KKeyNative& key );
+
+ /**
+ * Copies the given key sequence over this key sequence.
+ * @param keySeq the key sequence to copy
+ * @return true if successful, false otherwise
+ */
+ bool init( const KKeySequence& keySeq );
+
+ /**
+ * Initializes this key sequence to contain the given key sequence.
+ * The description consists of comma-separated keys as
+ * required by KKey::KKey(const QString&).
+ * @param key the description of the key
+ * @return true if successful, false otherwise
+ * @see KKeyServer::Sym::init()
+ * @see KKey::KKey(const QString&)
+ */
+ bool init( const QString& key );
+
+ /**
+ * Copy the given key sequence into this sequence.
+ */
+ KKeySequence& operator =( const KKeySequence& seq )
+ { init( seq ); return *this; }
+
+ /**
+ * Returns the number of key strokes of this sequence.
+ * @return the number of key strokes
+ * @see MAX_KEYS
+ */
+ uint count() const;
+
+ /**
+ * Return the @p i'th key of this sequence, or a null key if there
+ * are less then i keys.
+ * @param i the key to retrieve
+ * @return the @p i'th key, or KKey::null() if there are less
+ * than i keys
+ * @see MAX_KEYS
+ */
+ const KKey& key( uint i ) const;
+
+ /**
+ * @internal
+ */
+ bool isTriggerOnRelease() const;
+
+ /**
+ * Sets the @p i'th key of the sequence. You can not introduce gaps
+ * in a sequence, so you must use an @p i <= count(). Also note that
+ * the maximum length of a key sequence is MAX_KEYS.
+ * @param i the position of the new key (<= count(), <= MAX_KEYS)
+ * @param key the key to set
+ * @return true if successful, false otherwise
+ */
+ bool setKey( uint i, const KKey& key );
+
+ /**
+ * Returns true if the key sequence is null (after clear() or empty
+ * constructor).
+ * @return true if the key sequence is null
+ * @see clear()
+ * @see null()
+ */
+ bool isNull() const;
+
+ /**
+ * Returns true if this key sequence begins with the given sequence.
+ * @param keySeq the key sequence to search
+ * @return true if this key sequence begins with the given sequence
+ */
+ bool startsWith( const KKeySequence& keySeq ) const;
+
+ /**
+ * Compares this object with the given key sequence. Returns a negative
+ * number if the given KKeySequence is larger, 0 if they are equal and
+ * a positive number this KKeySequence is larger. Key sequences are
+ * compared by comparing the individual keys, starting from the beginning
+ * until an unequal key has been found. If a sequence contains more
+ * keys, it is considered larger.
+ * @param keySeq the key sequence to compare to
+ * @return a negative number if the given KKeySequence is larger, 0 if
+ * they are equal and a positive number this KKeySequence is larger
+ * @see KKey::sequence
+ */
+ int compare( const KKeySequence& keySeq ) const;
+
+ /**
+ * Compares the keys of both sequences.
+ * @see compare()
+ */
+ bool operator == ( const KKeySequence& seq ) const
+ { return compare( seq ) == 0; }
+
+ /**
+ * Compares the keys of both sequences.
+ * @see compare()
+ */
+ bool operator != ( const KKeySequence& seq ) const
+ { return compare( seq ) != 0; }
+
+ /**
+ * Compares the keys of both sequences.
+ * @see compare()
+ */
+ bool operator < ( const KKeySequence& seq ) const
+ { return compare( seq ) < 0; }
+ // TODO: consider adding Qt::SequenceMatch matches(...) methods for QKeySequence equivalence
+
+ /**
+ * Converts this key sequence to a QKeySequence.
+ * @return the QKeySequence
+ */
+ QKeySequence qt() const;
+
+ /**
+ * Returns the qt key code of the first key.
+ * @return the qt key code of the first key
+ * @see Qt::Key
+ * @see KKey::keyCodeQt()
+ */
+ int keyCodeQt() const;
+
+ /**
+ * Returns the key sequence as a number of key presses as
+ * returned by KKey::toString(), separated by commas.
+ * @return the string represenation of this key sequence
+ * @see KKey::toString()
+ */
+ QString toString() const;
+
+ /**
+ * @internal
+ */
+ QString toStringInternal() const;
+
+ /**
+ * Returns a null key sequence.
+ * @return the null key sequence
+ * @see isNull()
+ * @see clear()
+ */
+ static KKeySequence& null();
+
+ protected:
+ uchar m_nKeys;
+ uchar m_bTriggerOnRelease;
+ // BCI: m_rgvar should be renamed to m_rgkey for KDE 4.0
+ KKey m_rgvar[MAX_KEYS];
+
+ private:
+ class KKeySequencePrivate* d;
+ friend class KKeyNative;
+};
+
+/**
+* The KShortcut class is used to represent a keyboard shortcut to an action.
+* A shortcut is normally a single key with modifiers, such as Ctrl+V.
+* A KShortcut object may also contain an alternate key which will also
+* activate the action it's associated to, as long as no other actions have
+* defined that key as their primary key. Ex: Ctrl+V;Shift+Insert.
+*
+* This can be used to add additional accelerators to a KAction. For example,
+* the below code binds the escape key to the close action.
+*
+* \code
+* KAction *closeAction = KStdAction::close( this, SLOT( close() ), actionCollection() );
+* KShortcut closeShortcut = closeAction->shortcut();
+* closeShortcut.append( KKey(Key_Escape));
+* closeAction->setShortcut(closeShortcut);
+* \endcode
+*
+* Note that a shortcut cannot have more than 2 key combinations associated with it, so the above
+* code would not do anything (and append() would return false) if the closeAction already had
+* an key and alternate key.
+*
+*/
+
+class KDECORE_EXPORT KShortcut
+{
+ public:
+ /**
+ * The maximum number of key sequences that can be contained in
+ * a KShortcut.
+ */
+ enum { MAX_SEQUENCES = 2 };
+
+ /**
+ * Creates a new null shortcut.
+ * @see null()
+ * @see isNull()
+ * @see clear()
+ */
+ KShortcut();
+
+ /**
+ * Creates a new shortcut with the given Qt key code
+ * as the only key sequence.
+ * @param keyQt the qt keycode
+ * @see Qt::Key
+ */
+ KShortcut( int keyQt );
+
+ /**
+ * Creates a new shortcut that contains only the given qt key
+ * sequence.
+ * @param keySeq the qt key sequence to add
+ */
+ KShortcut( const QKeySequence& keySeq );
+
+ /**
+ * Creates a new shortcut that contains only the given key
+ * in its only sequence.
+ * @param key the key to add
+ */
+ KShortcut( const KKey& key );
+
+ /**
+ * Creates a new shortcut that contains only the given key
+ * sequence.
+ * @param keySeq the key sequence to add
+ */
+ KShortcut( const KKeySequence& keySeq );
+
+ /**
+ * Copies the given shortcut.
+ * @param shortcut the shortcut to add
+ */
+ KShortcut( const KShortcut& shortcut );
+
+ /**
+ * Creates a new key sequence that contains the given key sequence.
+ * The description consists of semicolon-separated keys as
+ * used in KKeySequence::KKeySequence(const QString&).
+ * @param shortcut the description of the key
+ * @see KKeySequence::KKeySequence(const QString&)
+ */
+ KShortcut( const char* shortcut );
+
+ /**
+ * Creates a new key sequence that contains the given key sequence.
+ * The description consists of semicolon-separated keys as
+ * used in KKeySequence::KKeySequence(const QString&).
+ * @param shortcut the description of the key
+ * @see KKeySequence::KKeySequence(const QString&)
+ */
+ KShortcut( const QString& shortcut );
+ ~KShortcut();
+
+ /**
+ * Clears the shortcut. The shortcut is null after calling this
+ * function.
+ * @see isNull()
+ */
+ void clear();
+
+ /**
+ * Initializes the shortcut with the given Qt key code
+ * as the only key sequence.
+ * @param keyQt the qt keycode
+ * @see Qt::Key
+ */
+ bool init( int keyQt );
+
+ /**
+ * Initializes the shortcut with the given qt key sequence.
+ * @param keySeq the qt key sequence to add
+ */
+ bool init( const QKeySequence& keySeq );
+
+ /**
+ * Initializes the shortcut with the given key as its only sequence.
+ * @param key the key to add
+ */
+ bool init( const KKey& key );
+
+ /**
+ * Initializes the shortcut with the given qt key sequence.
+ * @param keySeq the qt key sequence to add
+ */
+ bool init( const KKeySequence& keySeq );
+
+ /**
+ * Copies the given shortcut.
+ * @param shortcut the shortcut to add
+ */
+ bool init( const KShortcut& shortcut );
+
+ /**
+ * Initializes the key sequence with the given key sequence.
+ * The description consists of semicolon-separated keys as
+ * used in KKeySequence::KKeySequence(const QString&).
+ * @param shortcut the description of the key
+ * @see KKeySequence::KKeySequence(const QString&)
+ */
+ bool init( const QString& shortcut );
+
+ /**
+ * Copies the given shortcut over this shortcut.
+ */
+ KShortcut& operator =( const KShortcut& cut )
+ { init( cut ); return *this; }
+
+ /**
+ * Returns the number of sequences that are in this
+ * shortcut.
+ * @return the number of sequences
+ * MAX_SEQUENCES
+ */
+ uint count() const;
+
+ /**
+ * Returns the @p i'th key sequence of this shortcut.
+ * @param i the number of the key sequence to retrieve
+ * @return the @p i'th sequence or KKeySequence::null() if
+ * there are less than @p i key sequences
+ * MAX_SEQUENCES
+ */
+ const KKeySequence& seq( uint i ) const;
+
+ /**
+ * Returns the key code of the first key sequence, or
+ * null if there is no first key sequence.
+ * @return the key code of the first sequence's first key
+ * @see Qt::Key
+ * @see KKeySequence::keyCodeQt()
+ */
+ int keyCodeQt() const;
+
+ /**
+ * Returns true if the shortcut is null (after clear() or empty
+ * constructor).
+ * @return true if the shortcut is null
+ * @see clear()
+ * @see null()
+ */
+ bool isNull() const;
+
+ /**
+ * Compares this object with the given shortcut. Returns a negative
+ * number if the given shortcut is larger, 0 if they are equal and
+ * a positive number this shortcut is larger. Shortcuts are
+ * compared by comparing the individual key sequences, starting from the
+ * beginning until an unequal key sequences has been found. If a shortcut
+ * contains more key sequences, it is considered larger.
+ * @param shortcut the shortcut to compare to
+ * @return a negative number if the given KShortcut is larger, 0 if
+ * they are equal and a positive number this KShortcut is larger
+ * @see KKey::compare()
+ * @see KKeyShortcut::compare()
+ */
+ int compare( const KShortcut& shortcut ) const;
+
+ /**
+ * Compares the sequences of both shortcuts.
+ * @see compare()
+ */
+ bool operator == ( const KShortcut& cut ) const
+ { return compare( cut ) == 0; }
+
+ /**
+ * Compares the sequences of both shortcuts.
+ * @see compare()
+ */
+ bool operator != ( const KShortcut& cut ) const
+ { return compare( cut ) != 0; }
+
+ /**
+ * Compares the sequences of both shortcuts.
+ * @see compare()
+ */
+ bool operator < ( const KShortcut& cut ) const
+ { return compare( cut ) < 0; }
+
+ /**
+ * Checks whether this shortcut contains a sequence that starts
+ * with the given key.
+ * @param key the key to check
+ * @return true if a key sequence starts with the key
+ */
+ bool contains( const KKey& key ) const;
+
+ /**
+ * Checks whether this shortcut contains a sequence that starts
+ * with the given key.
+ * @param key the key to check
+ * @return true if a key sequence starts with the key
+ */
+ bool contains( const KKeyNative& key ) const;
+
+ /**
+ * Checks whether this shortcut contains the given sequence.
+ * @param keySeq the key sequence to check
+ * @return true if the shortcut has the given key sequence
+ */
+ bool contains( const KKeySequence& keySeq ) const;
+
+ /**
+ * Sets the @p i 'th key sequence of the shortcut. You can not introduce
+ * gaps in the list of sequences, so you must use an @p i <= count().
+ * Also note that the maximum number of key sequences is MAX_SEQUENCES.
+ * @param i the position of the new key sequence(0 <= i <= count(), 0 <= i < MAX_SEQUENCES)
+ * @param keySeq the key sequence to set
+ * @return true if successful, false otherwise
+ */
+ bool setSeq( uint i, const KKeySequence& keySeq );
+
+ /**
+ * Appends the given key sequence. This sets it as either the keysequence or
+ * the alternate keysequence. If the shortcut already has MAX_SEQUENCES
+ * sequences then this call does nothing, and returns false.
+ *
+ * @param keySeq the key sequence to add
+ * @return true if successful, false otherwise
+ * @see setSeq()
+ */
+ bool append( const KKeySequence& keySeq );
+
+ /**
+ * Removes the given key sequence from this shortcut
+ * @param keySeq the key sequence to remove
+ * @since 3.3
+ */
+ void remove( const KKeySequence& keySeq );
+
+ /**
+ * Appends the given key
+ * @param spec the key to add
+ * @return true if successful, false otherwise
+ * @see setSeq()
+ * @see MAX_SEQUENCES
+ * @since 3.2
+ */
+ bool append( const KKey& spec );
+
+ /**
+ * Appends the sequences from the given shortcut.
+ * @param cut the shortcut to append
+ * @return true if successful, false otherwise
+ * @see MAX_SEQUENCES
+ * @since 3.2
+ */
+ bool append( const KShortcut& cut );
+
+ /**
+ * Converts this shortcut to a key sequence. The first key sequence
+ * will be taken.
+ */
+ operator QKeySequence () const;
+
+ /**
+ * Returns a description of the shortcut as semicolon-separated
+ * ket sequences, as returned by KKeySequence::toString().
+ * @return the string represenation of this shortcut
+ * @see KKey::toString()
+ * @see KKeySequence::toString()
+ */
+ QString toString() const;
+
+ /**
+ * @internal
+ */
+ QString toStringInternal( const KShortcut* pcutDefault = 0 ) const;
+
+ /**
+ * Returns a null shortcut.
+ * @return the null shortcut
+ * @see isNull()
+ * @see clear()
+ */
+ static KShortcut& null();
+
+ protected:
+ uint m_nSeqs;
+ KKeySequence m_rgseq[MAX_SEQUENCES];
+
+ private:
+ class KShortcutPrivate* d;
+ friend class KKeyNative;
+
+#ifndef KDE_NO_COMPAT
+ public:
+ operator int () const { return keyCodeQt(); }
+#endif
+};
+
+#endif // __KSHORTCUT_H
diff --git a/kdecore/kshortcutlist.cpp b/kdecore/kshortcutlist.cpp
new file mode 100644
index 000000000..327153ce8
--- /dev/null
+++ b/kdecore/kshortcutlist.cpp
@@ -0,0 +1,220 @@
+#include <qstring.h>
+#include <qvariant.h>
+
+#include <kaccel.h>
+#include "kaccelaction.h"
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalaccel.h>
+#include <kinstance.h>
+#include <kshortcut.h>
+#include "kshortcutlist.h"
+
+//---------------------------------------------------------------------
+// KShortcutList
+//---------------------------------------------------------------------
+
+KShortcutList::KShortcutList()
+{
+}
+
+KShortcutList::~KShortcutList()
+{
+}
+
+bool KShortcutList::isGlobal( uint ) const
+{
+ return false;
+}
+
+int KShortcutList::index( const QString& sName ) const
+{
+ uint nSize = count();
+ for( uint i = 0;
+ i < nSize;
+ ++i )
+ if( name( i ) == sName )
+ return i;
+ return -1;
+}
+
+int KShortcutList::index( const KKeySequence& seq ) const
+{
+ if( seq.isNull() )
+ return -1;
+
+ uint nSize = count();
+ for( uint i = 0; i < nSize; i++ ) {
+ if( shortcut(i).contains( seq ) )
+ return i;
+ }
+
+ return -1;
+}
+
+const KInstance* KShortcutList::instance() const
+{
+ return 0;
+}
+
+QVariant KShortcutList::getOther( Other, uint ) const
+{
+ return QVariant();
+}
+
+bool KShortcutList::setOther( Other, uint, QVariant )
+{
+ return false;
+}
+
+bool KShortcutList::readSettings( const QString& sConfigGroup, KConfigBase* pConfig )
+{
+ kdDebug(125) << "KShortcutList::readSettings( \"" << sConfigGroup << "\", " << pConfig << " ) start" << endl;
+ if( !pConfig )
+ pConfig = KGlobal::config();
+ QString sGroup = (!sConfigGroup.isEmpty()) ? sConfigGroup : QString("Shortcuts");
+
+ // If the config file still has the old group name:
+ // FIXME: need to rename instead? -- and don't do this if hasGroup( "Shortcuts" ).
+ if( sGroup == "Shortcuts" && pConfig->hasGroup( "Keys" ) ) {
+ readSettings( "Keys", pConfig );
+ }
+
+ kdDebug(125) << "\treadSettings( \"" << sGroup << "\", " << pConfig << " )" << endl;
+ if( !pConfig->hasGroup( sGroup ) )
+ return true;
+ KConfigGroupSaver cgs( pConfig, sGroup );
+
+ uint nSize = count();
+ for( uint i = 0; i < nSize; i++ ) {
+ if( isConfigurable(i) ) {
+ QString sEntry = pConfig->readEntry( name(i) );
+ if( !sEntry.isEmpty() ) {
+ if( sEntry == "none" )
+ setShortcut( i, KShortcut() );
+ else
+ setShortcut( i, KShortcut(sEntry) );
+ }
+ else // default shortcut
+ setShortcut( i, shortcutDefault(i) );
+ kdDebug(125) << "\t" << name(i) << " = '" << sEntry << "'" << endl;
+ }
+ }
+
+ kdDebug(125) << "KShortcutList::readSettings done" << endl;
+ return true;
+}
+
+bool KShortcutList::writeSettings( const QString &sConfigGroup, KConfigBase* pConfig, bool bWriteAll, bool bGlobal ) const
+{
+ kdDebug(125) << "KShortcutList::writeSettings( " << sConfigGroup << ", " << pConfig << ", " << bWriteAll << ", " << bGlobal << " )" << endl;
+ if( !pConfig )
+ pConfig = KGlobal::config();
+
+ QString sGroup = (!sConfigGroup.isEmpty()) ? sConfigGroup : QString("Shortcuts");
+
+ // If it has the deprecated group [Keys], remove it
+ if( pConfig->hasGroup( "Keys" ) )
+ pConfig->deleteGroup( "Keys", true );
+
+ KConfigGroupSaver cs( pConfig, sGroup );
+
+ uint nSize = count();
+ for( uint i = 0; i < nSize; i++ ) {
+ if( isConfigurable(i) ) {
+ const QString& sName = name(i);
+ bool bConfigHasAction = !pConfig->readEntry( sName ).isEmpty();
+ bool bSameAsDefault = (shortcut(i) == shortcutDefault(i));
+ // If we're using a global config or this setting
+ // differs from the default, then we want to write.
+ if( bWriteAll || !bSameAsDefault ) {
+ QString s = shortcut(i).toStringInternal();
+ if( s.isEmpty() )
+ s = "none";
+ kdDebug(125) << "\twriting " << sName << " = " << s << endl;
+ pConfig->writeEntry( sName, s, true, bGlobal );
+ }
+ // Otherwise, this key is the same as default
+ // but exists in config file. Remove it.
+ else if( bConfigHasAction ) {
+ kdDebug(125) << "\tremoving " << sName << " because == default" << endl;
+ pConfig->deleteEntry( sName, false, bGlobal );
+ }
+ }
+ }
+
+ pConfig->sync();
+ return true;
+}
+
+//---------------------------------------------------------------------
+// KAccelShortcutList
+//---------------------------------------------------------------------
+
+class KAccelShortcutListPrivate
+{
+ public:
+ QString m_configGroup;
+};
+
+KAccelShortcutList::KAccelShortcutList( KAccel* pAccel )
+: m_actions( pAccel->actions() )
+{
+ d=new KAccelShortcutListPrivate;
+ m_bGlobal = false;
+ d->m_configGroup=pAccel->configGroup();
+}
+
+KAccelShortcutList::KAccelShortcutList( KGlobalAccel* pAccel )
+: m_actions( pAccel->actions() )
+{
+ d=new KAccelShortcutListPrivate;
+ m_bGlobal = true;
+ d->m_configGroup=pAccel->configGroup();
+}
+
+KAccelShortcutList::KAccelShortcutList( KAccelActions& actions, bool bGlobal )
+: m_actions( actions )
+{
+ d=new KAccelShortcutListPrivate;
+ m_bGlobal = bGlobal;
+}
+
+
+KAccelShortcutList::~KAccelShortcutList()
+ { delete d;}
+uint KAccelShortcutList::count() const
+ { return m_actions.count(); }
+QString KAccelShortcutList::name( uint i ) const
+ { return m_actions.actionPtr(i)->name(); }
+QString KAccelShortcutList::label( uint i ) const
+ { return m_actions.actionPtr(i)->label(); }
+QString KAccelShortcutList::whatsThis( uint i ) const
+ { return m_actions.actionPtr(i)->whatsThis(); }
+const KShortcut& KAccelShortcutList::shortcut( uint i ) const
+ { return m_actions.actionPtr(i)->shortcut(); }
+const KShortcut& KAccelShortcutList::shortcutDefault( uint i ) const
+ { return m_actions.actionPtr(i)->shortcutDefault(); }
+bool KAccelShortcutList::isConfigurable( uint i ) const
+ { return m_actions.actionPtr(i)->isConfigurable(); }
+bool KAccelShortcutList::setShortcut( uint i, const KShortcut& cut )
+ { return m_actions.actionPtr(i)->setShortcut( cut ); }
+QVariant KAccelShortcutList::getOther( Other, uint ) const
+ { return QVariant(); }
+bool KAccelShortcutList::isGlobal( uint ) const
+ { return m_bGlobal; }
+bool KAccelShortcutList::setOther( Other, uint, QVariant )
+ { return false; }
+bool KAccelShortcutList::save() const
+ { return writeSettings( d->m_configGroup ); }
+
+void KShortcutList::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KAccelShortcutList::virtual_hook( int id, void* data )
+{ KShortcutList::virtual_hook( id, data ); }
+
+void KStdAccel::ShortcutList::virtual_hook( int id, void* data )
+{ KShortcutList::virtual_hook( id, data ); }
+
diff --git a/kdecore/kshortcutlist.h b/kdecore/kshortcutlist.h
new file mode 100644
index 000000000..f20808962
--- /dev/null
+++ b/kdecore/kshortcutlist.h
@@ -0,0 +1,295 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KSHORTCUTLIST_H
+#define __KSHORTCUTLIST_H
+
+#include <qglobal.h> // For uint
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+class QVariant;
+class KConfigBase;
+class KInstance;
+class KKeySequence;
+class KShortcut;
+
+/**********************************************************************
+* This is a wrapper class which allows a function to use one interface
+* to KActionCollection, KAccelActions, and KActionPtrList.
+**********************************************************************/
+
+/**
+ * KShortcutList is an abstract base class for
+ * KAccelShortcutList and KStdAccel::ShortcutList. It gives
+ * you an unified interface for accessing the accelerator lists
+ * of KAccel (using KAccelShortcutList),
+ * KGlobalAccel (using KAccelShortcutList), and
+ * KStdAccel (using KStdAccel::ShortcutList).
+ *
+ * @short Base class for accessing accelerator lists
+ */
+class KDECORE_EXPORT KShortcutList
+{
+ public:
+ /**
+ * Default constructor.
+ */
+ KShortcutList();
+ virtual ~KShortcutList();
+
+ /**
+ * Returns the number of entries.
+ * @return the number of entries
+ */
+ virtual uint count() const = 0;
+
+ /**
+ * Returns the name of the shortcut with the given @p index.
+ * @param index the index of the shortcut (must be < count())
+ * @return the name of the shortcut
+ */
+ virtual QString name( uint index ) const = 0;
+
+ /**
+ * Returns the (i18n'd) label of the shortcut with the given @p index.
+ * @param index the index of the shortcut (must be < count())
+ * @return the label (i18n'd) of the shortcut
+ */
+ virtual QString label( uint index ) const = 0;
+
+ /**
+ * Returns the (i18n'd) What's This text of the shortcut with the given @p index.
+ * @param index the index of the shortcut (must be < count())
+ * @return the What's This text (i18n'd) of the shortcut
+ */
+ virtual QString whatsThis( uint index ) const = 0;
+
+ // TODO KDE4: add virtual QString toolTip( uint index ) const = 0
+ // Will then be used by the listview in kkeydialog
+
+ /**
+ * Returns the shortcut with the given @p index.
+ * @param index the index of the shortcut (must be < count())
+ * @return the shortcut
+ * @see shortcutDefault()
+ */
+ virtual const KShortcut& shortcut( uint index ) const = 0;
+
+ /**
+ * Returns default shortcut with the given @p index.
+ * @param index the index of the shortcut (must be < count())
+ * @return the default shortcut
+ * @see shortcut()
+ */
+ virtual const KShortcut& shortcutDefault( uint index ) const = 0;
+
+ /**
+ * Checks whether the shortcut with the given @p index is configurable.
+ * @param index the index of the shortcut (must be < count())
+ * @return true if configurable, false otherwise
+ */
+ virtual bool isConfigurable( uint index ) const = 0;
+
+ /**
+ * Sets the shortcut of the given entry
+ * @param index the index of the shortcut (must be < count())
+ * @param shortcut the shortcut
+ */
+ virtual bool setShortcut( uint index, const KShortcut &shortcut ) = 0;
+
+ /**
+ * Checks whether the shortcut with the given @p index is saved in the
+ * global configuration.
+ * @param index the index of the shortcut (must be < count())
+ * @return true if global, false otherwise
+ */
+ virtual bool isGlobal( uint index ) const;
+
+ /**
+ * Returns the index of the shortcut with he given name.
+ * @param sName the name of the shortcut to search
+ * @return the index of the shortcut, of -1 if not found
+ */
+ virtual int index( const QString& sName ) const;
+
+ /**
+ * Returns the index of the shortcut with he given key sequence.
+ * @param keySeq the key sequence to search for
+ * @return the index of the shortcut, of -1 if not found
+ */
+ virtual int index( const KKeySequence& keySeq ) const;
+
+ /**
+ * The KInstance.
+ * @return the KInstance of the list, can be 0 if not available
+ */
+ virtual const KInstance* instance() const;
+
+ // These are here in order to handle expansion.
+ enum Other { };
+ /** \internal */
+ virtual QVariant getOther( Other, uint index ) const = 0;
+ /** \internal */
+ virtual bool setOther( Other, uint index, QVariant ) = 0;
+
+ /**
+ * Save the shortcut list.
+ * @return true if successful, false otherwise
+ */
+ virtual bool save() const = 0;
+
+ /**
+ * Loads the shortcuts from the given configuration file.
+ *
+ * @param sConfigGroup the group in the configuration file
+ * @param pConfig the configuration file to load from
+ * @return true if successful, false otherwise
+ */
+ virtual bool readSettings( const QString& sConfigGroup = QString::null, KConfigBase* pConfig = 0 );
+
+ /**
+ * Writes the shortcuts to the given configuration file.
+ *
+ * @param sConfigGroup the group in the configuration file
+ * @param pConfig the configuration file to save to
+ * @param bWriteAll true to write all actions
+ * @param bGlobal true to write to the global configuration file
+ * @return true if successful, false otherwise
+ */
+ virtual bool writeSettings( const QString& sConfigGroup = QString::null, KConfigBase* pConfig = 0,
+ bool bWriteAll = false, bool bGlobal = false ) const;
+
+ protected:
+ /// used to extend the interface with virtuals without breaking binary compatibility
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class KShortcutListPrivate* d;
+};
+
+//---------------------------------------------------------------------
+// KAccelShortcutList
+//---------------------------------------------------------------------
+
+class KAccel;
+class KAccelActions;
+class KGlobalAccel;
+
+/**
+ * KShortcutList implementation to access KAccel and
+ * KGlobalAccel lists.
+ */
+class KDECORE_EXPORT KAccelShortcutList : public KShortcutList
+{
+ public:
+ /**
+ * Creates a new KShortcutList that accesses the given KAccel.
+ * @param accel the accelerators to access
+ */
+ KAccelShortcutList( KAccel* accel );
+
+ /**
+ * Creates a new KShortcutList that accesses the given
+ * KGlobalAccel.
+ * @param accel the accelerators to access
+ */
+ KAccelShortcutList( KGlobalAccel* accel );
+
+ /**
+ * @internal
+ * Creates a new KShortcutList that accesses the given
+ * KAccelActions collection.
+ * @param actions the actions to access
+ * @param bGlobal true to save the actions in the global
+ * configuration file
+ */
+ KAccelShortcutList( KAccelActions &actions, bool bGlobal );
+ virtual ~KAccelShortcutList();
+
+ virtual uint count() const;
+ virtual QString name( uint index ) const;
+ virtual QString label( uint index ) const;
+ virtual QString whatsThis( uint index ) const;
+ virtual const KShortcut& shortcut( uint index ) const;
+ virtual const KShortcut& shortcutDefault( uint index ) const;
+ virtual bool isConfigurable( uint index ) const;
+ virtual bool setShortcut( uint index , const KShortcut& shortcut );
+ virtual bool isGlobal( uint index ) const;
+
+ /** \internal */
+ virtual QVariant getOther( Other, uint index ) const;
+ /** \internal */
+ virtual bool setOther( Other, uint index, QVariant );
+
+ virtual bool save() const;
+
+ protected:
+ /** Actions (collection) for this shortcut list. Set by constructor. */
+ KAccelActions& m_actions;
+ /** Is this shortcut list global? Access through isGlobal() */
+ bool m_bGlobal;
+
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class KAccelShortcutListPrivate* d;
+};
+
+namespace KStdAccel {
+//---------------------------------------------------------------------
+// ShortcutList
+//---------------------------------------------------------------------
+
+/**
+ * KShortcutList implementation that accesses KStdAccel
+ * actions.
+ */
+class KDECORE_EXPORT ShortcutList : public KShortcutList
+{
+ public:
+ /**
+ * Creates a new ShortcutList.
+ */
+ ShortcutList();
+ virtual ~ShortcutList();
+
+ virtual uint count() const;
+ virtual QString name( uint index ) const;
+ virtual QString label( uint index ) const;
+ virtual QString whatsThis( uint index ) const;
+ virtual const KShortcut& shortcut( uint index ) const;
+ virtual const KShortcut& shortcutDefault( uint index ) const;
+ virtual bool isConfigurable( uint index ) const;
+ virtual bool setShortcut( uint index , const KShortcut& shortcut );
+
+ /** \internal */
+ virtual QVariant getOther( Other, uint index ) const;
+ /** \internal */
+ virtual bool setOther( Other, uint index, QVariant );
+
+ virtual bool save() const;
+
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class ShortcutListPrivate* d;
+};
+}
+
+#endif // __KSHORTCUTLIST_H
diff --git a/kdecore/kshortcutmenu.cpp b/kdecore/kshortcutmenu.cpp
new file mode 100644
index 000000000..5d7fea1f8
--- /dev/null
+++ b/kdecore/kshortcutmenu.cpp
@@ -0,0 +1,161 @@
+/*
+ Copyright (c) 2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qkeysequence.h>
+#include <qlabel.h>
+#include <qpopupmenu.h>
+
+#include "kaccelaction.h"
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include "kshortcutmenu.h"
+//#include <kkeynative.h>
+
+KShortcutMenu::KShortcutMenu( QWidget* pParent, KAccelActions* pActions, KKeySequence seq )
+: QPopupMenu( pParent ),
+ m_pActions( pActions ),
+ m_seq( seq )
+{
+ kdDebug() << seq.toStringInternal() << endl;
+
+ QFont fontTitle = KGlobalSettings::menuFont();
+ fontTitle.setBold( true );
+
+ pTitle = new QLabel( "", (QWidget*)0 );
+ pTitle->setFont( fontTitle );
+ pTitle->setFrameShape( QFrame::Panel );
+
+ insertItem( pTitle );
+}
+
+bool KShortcutMenu::insertAction( uint iAction, KKeySequence seq )
+{
+ KAccelAction* pAction = m_pActions->actionPtr( iAction );
+
+ if( pAction ) {
+ insertItem( "", iAction );
+ m_seqs[indexOf(iAction)] = seq;
+ return true;
+ } else
+ return false;
+}
+
+
+void KShortcutMenu::updateShortcuts()
+{
+ pTitle->setText( m_seq.toString() + ",..." );
+
+ for( uint iItem = 1; iItem < count(); iItem++ ) {
+ int iAction = idAt( iItem );
+ if( iAction >= 0 ) {
+ KAccelAction* pAction = m_pActions->actionPtr( iAction );
+ if( pAction ) {
+ KKeySequence seq = m_seqs[iItem];
+ QString sSeq = seq.key(m_seq.count()).toString();
+ for( uint iKey = m_seq.count() + 1; iKey < seq.count(); iKey++ )
+ sSeq += QString(",") + seq.key(iKey).toString();
+
+ kdDebug(125) << "seq = " << seq.toStringInternal() << " sSeq = " << sSeq << endl;
+ changeItem( iAction, pAction->label() + "\t" + sSeq );
+ }
+ }
+ }
+}
+
+void KShortcutMenu::keyPressEvent( QKeyEvent* pEvent )
+{
+ kdDebug() << "keypress; " << pEvent->key() << endl;
+ KKey key( pEvent );
+
+ switch( pEvent->key() ) {
+ case Key_Shift:
+ case Key_Control:
+ case Key_Alt:
+ case Key_Meta:
+ case Key_Super_L:
+ case Key_Super_R:
+ case Key_Hyper_L:
+ case Key_Hyper_R:
+ break;
+ default:
+ int iItem = searchForKey( key );
+ // If key not found, look for unmodified version.
+ if( iItem == -1 ) {
+ key = pEvent->key();
+ iItem = searchForKey( key );
+ }
+
+ if( iItem == -1 ) {
+ // Let Up and Down keys navigate menu,
+ // And permit Enter, Return to select the item.
+ if( pEvent->key() == Qt::Key_Up || pEvent->key() == Qt::Key_Down ||
+ pEvent->key() == Qt::Key_Enter || pEvent->key() == Qt::Key_Return )
+ QPopupMenu::keyPressEvent( pEvent );
+ else
+ close();
+ }
+ else if( iItem == 0 )
+ keepItemsMatching( key );
+ else
+ activateItemAt( iItem );
+ }
+}
+
+int KShortcutMenu::searchForKey( KKey key )
+{
+ int iItemFound = -1; // -1 indicates no match
+ uint iKey = m_seq.count();
+
+ for( uint iItem = 1; iItem < count(); iItem++ ) {
+ if( m_seqs.contains( iItem ) ) {
+ KKey keyItem = m_seqs[iItem].key( iKey );
+ //kdDebug(125) << "iItem = " << iItem << " key = " << key.toStringInternal() << " keyItem = " << keyItem.toStringInternal() << endl;
+ if( key == keyItem ) {
+ if( iItemFound == -1 )
+ iItemFound = iItem;
+ else
+ return 0; // 0 indicates duplicate matches
+ }
+ }
+ }
+
+ return iItemFound;
+}
+
+void KShortcutMenu::keepItemsMatching( KKey key )
+{
+ kdDebug(125) << "MyAccel::keepItemsMatching( " << key.toStringInternal() << " )" << endl;
+
+ uint iKey = m_seq.count();
+ m_seq.setKey( iKey, key );
+
+ for( uint iItem = 1; iItem < count(); iItem++ ) {
+ if( m_seqs.contains( iItem ) ) {
+ KKey keyItem = m_seqs[iItem].key( iKey );
+ if( key != keyItem ) {
+ m_seqs.remove( iItem );
+ removeItemAt( iItem-- );
+ }
+ }
+ }
+
+ updateShortcuts();
+}
+
+#include "kshortcutmenu.moc"
diff --git a/kdecore/kshortcutmenu.h b/kdecore/kshortcutmenu.h
new file mode 100644
index 000000000..1a8bb7921
--- /dev/null
+++ b/kdecore/kshortcutmenu.h
@@ -0,0 +1,61 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Ellis Whitehead <ellis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KSHORTCUTMENU_H
+#define __KSHORTCUTMENU_H
+
+#include <qmap.h>
+#include <qpopupmenu.h>
+
+#include "kshortcut.h"
+
+class QLabel;
+
+class KAccelActions;
+
+/**
+ * @internal
+ */
+class KDECORE_EXPORT KShortcutMenu : public QPopupMenu
+{
+ Q_OBJECT
+ public:
+ KShortcutMenu( QWidget* pParent, KAccelActions* pActions, KKeySequence seq );
+
+ bool insertAction( uint iAction, KKeySequence seq );
+
+ void updateShortcuts();
+
+ protected:
+ void keyPressEvent( QKeyEvent* pEvent );
+
+ private:
+ int searchForKey( KKey key );
+ void keepItemsMatching( KKey key );
+
+ private:
+ typedef QMap<uint, KKeySequence> IndexToKKeySequence;
+
+ KAccelActions* m_pActions;
+ KKeySequence m_seq;
+ QLabel* pTitle;
+ IndexToKKeySequence m_seqs;
+};
+
+#endif // __KSHORTCUTMENU_H
diff --git a/kdecore/ksimpleconfig.cpp b/kdecore/ksimpleconfig.cpp
new file mode 100644
index 000000000..b23236be9
--- /dev/null
+++ b/kdecore/ksimpleconfig.cpp
@@ -0,0 +1,81 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+// $Id$
+
+#include <config.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+
+#include "kglobal.h"
+#include "kstandarddirs.h"
+#include "kconfigbackend.h"
+
+#include "ksimpleconfig.h"
+
+KSimpleConfig::KSimpleConfig(const QString &fileName, bool bReadOnly)
+ : KConfig(QString::fromLatin1(""), bReadOnly, false)
+{
+ // the difference between KConfig and KSimpleConfig is just that
+ // for KSimpleConfig an absolute filename is guaranteed
+ if (!fileName.isNull() && QDir::isRelativePath(fileName)) {
+ backEnd->changeFileName( KGlobal::dirs()->
+ saveLocation("config", QString::null, !bReadOnly)+fileName, "config", false);
+ } else {
+ backEnd->changeFileName(fileName, "config", false);
+ }
+ setReadOnly( bReadOnly );
+ reparseConfiguration();
+}
+
+KSimpleConfig::KSimpleConfig(KConfigBackEnd *backEnd, bool bReadOnly)
+ : KConfig(backEnd, bReadOnly)
+{}
+
+KSimpleConfig::~KSimpleConfig()
+{
+ // we need to call the KSimpleConfig version of sync. Relying on the
+ // regular KConfig sync is bad, because the KSimpleConfig sync has
+ // different behavior. Syncing here will insure that the sync() call
+ // in the KConfig destructor doesn't actually do anything.
+ sync();
+}
+
+void KSimpleConfig::sync()
+{
+ if (isReadOnly())
+ return;
+ backEnd->sync(false);
+
+ if (isDirty())
+ rollback();
+}
+
+void KSimpleConfig::virtual_hook( int id, void* data )
+{ KConfig::virtual_hook( id, data ); }
+
+#include "ksimpleconfig.moc"
diff --git a/kdecore/ksimpleconfig.h b/kdecore/ksimpleconfig.h
new file mode 100644
index 000000000..6d556d456
--- /dev/null
+++ b/kdecore/ksimpleconfig.h
@@ -0,0 +1,81 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KSIMPLECONFIG_H
+#define _KSIMPLECONFIG_H
+
+#include "kconfig.h"
+
+class KSimpleConfigPrivate;
+
+/**
+ * KDE Configuration entries
+ *
+ * This is a trivial extension of KConfig for applications that need
+ * only one configuration file and no default system.
+ * A difference with KConfig is that when the data in memory is written back
+ * it is not merged with what is on disk.
+ * Whatever is in memory simply replaces what is on disk entirely.
+ *
+ * @author Kalle Dalheimer <kalle@kde.org>, Preston Brown <pbrown@kde.org>
+ * @see KConfigBase KConfig
+ * @short KDE Configuration Management class with deletion ability
+ */
+class KDECORE_EXPORT KSimpleConfig : public KConfig
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Construct a KSimpleConfig object and make it either read-write
+ * or read-only.
+ *
+ * @param fileName The file used for saving the config data. Either
+ * a full path can be specified or just the filename.
+ * If only a filename is specified, the default
+ * directory for "config" files is used.
+ * @param bReadOnly Whether the object should be read-only.
+ */
+ KSimpleConfig( const QString &fileName, bool bReadOnly = false);
+
+ KSimpleConfig(KConfigBackEnd *backEnd, bool bReadOnly = false);
+
+ /**
+ * Destructor.
+ *
+ * Writes back any dirty configuration entries.
+ */
+ virtual ~KSimpleConfig();
+
+ virtual void sync();
+
+private:
+
+ // copy-construction and assignment are not allowed
+ KSimpleConfig( const KSimpleConfig& );
+ KSimpleConfig& operator= ( const KSimpleConfig& rConfig );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KSimpleConfigPrivate *d;
+};
+
+#endif
diff --git a/kdecore/ksock.cpp b/kdecore/ksock.cpp
new file mode 100644
index 000000000..da28a64d5
--- /dev/null
+++ b/kdecore/ksock.cpp
@@ -0,0 +1,435 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1997 Torben Weis (weis@kde.org)
+ *
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+// on Linux/libc5, this includes linux/socket.h where SOMAXCONN is defined
+#include <sys/socket.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+extern "C" {
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+}
+
+#define KSOCK_NO_BROKEN
+#include "kdebug.h"
+#include "ksock.h"
+#include "kextsock.h"
+#include "ksockaddr.h"
+
+#include "ksocks.h"
+
+extern "C" {
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_GETADDRINFO
+#include <netdb.h>
+#endif
+
+// defines MAXDNAME under Solaris
+#include <arpa/nameser.h>
+#include <resolv.h>
+}
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <assert.h>
+
+#ifdef HAVE_SYSENT_H
+#include <sysent.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+
+
+// Play it safe, use a reasonable default, if SOMAXCONN was nowhere defined.
+#ifndef SOMAXCONN
+#warning Your header files do not seem to support SOMAXCONN
+#define SOMAXCONN 5
+#endif
+
+#include <qapplication.h>
+#include <qsocketnotifier.h>
+
+#include "netsupp.h" // leave this last
+
+#ifdef __CYGWIN__
+#include "qwindowdefs.h"
+#endif
+
+class KSocketPrivate
+{
+public:
+ QSocketNotifier *readNotifier;
+ QSocketNotifier *writeNotifier;
+
+ KSocketPrivate() :
+ readNotifier(0), writeNotifier(0)
+ { }
+};
+
+// I moved this into here so we could accurately detect the domain, for
+// posterity. Really.
+KSocket::KSocket( int _sock)
+ : sock(_sock), d(new KSocketPrivate)
+{
+ struct sockaddr_in sin;
+ ksocklen_t len = sizeof(sin);
+
+ memset(&sin, 0, len);
+
+ // getsockname will fill in all the appropriate details, and
+ // since sockaddr_in will exist everywhere and is somewhat compatible
+ // with sockaddr_in6, we can use it to avoid needless ifdefs.
+ KSocks::self()->getsockname(_sock, (struct sockaddr *)&sin, &len);
+}
+
+KSocket::KSocket( const char *_host, unsigned short int _port, int _timeout ) :
+ sock( -1 ), d(new KSocketPrivate)
+{
+ connect( _host, _port, _timeout );
+}
+
+KSocket::KSocket( const char *_path ) :
+ sock( -1 ), d(new KSocketPrivate)
+{
+ connect( _path );
+}
+
+void KSocket::enableRead( bool _state )
+{
+ if ( _state )
+ {
+ if ( !d->readNotifier )
+ {
+ d->readNotifier = new QSocketNotifier( sock, QSocketNotifier::Read );
+ QObject::connect( d->readNotifier, SIGNAL( activated(int) ), this, SLOT( slotRead(int) ) );
+ }
+ else
+ d->readNotifier->setEnabled( true );
+ }
+ else if ( d->readNotifier )
+ d->readNotifier->setEnabled( false );
+}
+
+void KSocket::enableWrite( bool _state )
+{
+ if ( _state )
+ {
+ if ( !d->writeNotifier )
+ {
+ d->writeNotifier = new QSocketNotifier( sock, QSocketNotifier::Write );
+ QObject::connect( d->writeNotifier, SIGNAL( activated(int) ), this,
+ SLOT( slotWrite(int) ) );
+ }
+ else
+ d->writeNotifier->setEnabled( true );
+ }
+ else if ( d->writeNotifier )
+ d->writeNotifier->setEnabled( false );
+}
+
+void KSocket::slotRead( int )
+{
+ char buffer[2];
+
+ int n = recv( sock, buffer, 1, MSG_PEEK );
+ if ( n <= 0 )
+ emit closeEvent( this );
+ else
+ emit readEvent( this );
+}
+
+void KSocket::slotWrite( int )
+{
+ emit writeEvent( this );
+}
+
+/*
+ * Connects the PF_UNIX domain socket to _path.
+ */
+bool KSocket::connect( const char *_path )
+{
+ KExtendedSocket ks(QString::null, _path, KExtendedSocket::unixSocket);
+
+ ks.connect();
+ sock = ks.fd();
+ ks.release();
+
+ return sock >= 0;
+}
+
+/*
+ * Connects the socket to _host, _port.
+ */
+bool KSocket::connect( const QString& _host, unsigned short int _port, int _timeout )
+{
+ KExtendedSocket ks(_host, _port, KExtendedSocket::inetSocket);
+ ks.setTimeout(_timeout, 0);
+
+ ks.connect();
+ sock = ks.fd();
+ ks.release();
+
+ return sock >= 0;
+}
+
+// only for doxygen - the define is always true as defined above
+#ifdef KSOCK_NO_BROKEN
+unsigned long KSocket::ipv4_addr()
+{
+ unsigned long retval = 0;
+ KSocketAddress *sa = KExtendedSocket::peerAddress(sock);
+ if (sa == NULL)
+ return 0;
+
+ if (sa->address() != NULL && (sa->address()->sa_family == PF_INET
+#ifdef PF_INET6
+ || sa->address()->sa_family == PF_INET6
+#endif
+ ))
+ {
+ KInetSocketAddress *ksin = (KInetSocketAddress*)sa;
+ const sockaddr_in *sin = ksin->addressV4();
+ if (sin != NULL)
+ retval = sin->sin_addr.s_addr;
+ }
+ delete sa;
+ return retval;
+}
+
+bool KSocket::initSockaddr (ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain)
+{
+ // This function is now IPv4 only
+ // if you want something better, you should use KExtendedSocket::lookup yourself
+
+ kdWarning(170) << "deprecated KSocket::initSockaddr called" << endl;
+
+ if (domain != PF_INET)
+ return false;
+
+ QPtrList<KAddressInfo> list = KExtendedSocket::lookup(hostname, QString::number(port),
+ KExtendedSocket::ipv4Socket);
+ list.setAutoDelete(true);
+
+ if (list.isEmpty())
+ return false;
+
+ memset(server_name, 0, sizeof(*server_name));
+
+ // We are sure that only KInetSocketAddress objects are in the list
+ KInetSocketAddress *sin = (KInetSocketAddress*)list.getFirst()->address();
+ if (sin == NULL)
+ return false;
+
+ memcpy(server_name, sin->addressV4(), sizeof(*server_name));
+ kdDebug(170) << "KSocket::initSockaddr: returning " << sin->pretty() << endl;
+ return true;
+}
+
+#endif
+
+KSocket::~KSocket()
+{
+ // Coolo says delete 0 is ok :) -thiago
+ delete d->readNotifier;
+ delete d->writeNotifier;
+
+ delete d;
+
+ if (sock != -1) {
+ ::close( sock );
+ }
+}
+
+class KServerSocketPrivate
+{
+public:
+ bool bind;
+ QCString path;
+ unsigned short int port;
+ KExtendedSocket *ks;
+};
+
+
+KServerSocket::KServerSocket( const char *_path, bool _bind ) :
+ sock( -1 )
+{
+ d = new KServerSocketPrivate();
+ d->bind = _bind;
+
+ init ( _path );
+}
+
+KServerSocket::KServerSocket( unsigned short int _port, bool _bind ) :
+ sock( -1 )
+{
+ d = new KServerSocketPrivate();
+ d->bind = _bind;
+
+ init ( _port );
+}
+
+bool KServerSocket::init( const char *_path )
+{
+ unlink(_path );
+ d->path = _path;
+
+ KExtendedSocket *ks = new KExtendedSocket(QString::null, _path, KExtendedSocket::passiveSocket |
+ KExtendedSocket::unixSocket);
+ d->ks = ks;
+
+ if (d->bind)
+ return bindAndListen();
+ return true;
+}
+
+
+bool KServerSocket::init( unsigned short int _port )
+{
+ d->port = _port;
+ KExtendedSocket *ks;
+ ks = new KExtendedSocket(QString::null, _port, KExtendedSocket::passiveSocket |
+ KExtendedSocket::inetSocket);
+ d->ks = ks;
+
+ if (d->bind)
+ return bindAndListen();
+ return true;
+}
+
+bool KServerSocket::bindAndListen()
+{
+ if (d == NULL || d->ks == NULL)
+ return false;
+
+
+ int ret = d->ks->listen( SOMAXCONN );
+ if (ret < 0)
+ {
+ kdWarning(170) << "Error listening on socket: " << ret << "\n";
+ delete d->ks;
+ d->ks = NULL;
+ sock = -1;
+ return false;
+ }
+
+
+ sock = d->ks->fd();
+
+ connect( d->ks->readNotifier(), SIGNAL( activated(int) ), this, SLOT( slotAccept(int) ) );
+ return true;
+}
+
+
+unsigned short int KServerSocket::port()
+{
+ if (d == NULL || d->ks == NULL || sock == -1)
+ return 0;
+ const KSocketAddress *sa = d->ks->localAddress();
+ if (sa == NULL)
+ return 0;
+
+ // we can use sockaddr_in here even if it isn't IPv4
+ sockaddr_in *sin = (sockaddr_in*)sa->address();
+
+ if (sin->sin_family == PF_INET)
+ // correct family
+ return sin->sin_port;
+#ifdef PF_INET6
+ else if (sin->sin_family == PF_INET6)
+ {
+ kde_sockaddr_in6 *sin6 = (kde_sockaddr_in6*)sin;
+ return sin6->sin6_port;
+ }
+#endif
+ return 0; // not a port we know
+}
+
+unsigned long KServerSocket::ipv4_addr()
+{
+ if (d == NULL || d->ks == NULL || sock == -1)
+ return 0;
+ const KSocketAddress *sa = d->ks->localAddress();
+
+ const sockaddr_in *sin = (sockaddr_in*)sa->address();
+
+ if (sin->sin_family == PF_INET)
+ // correct family
+ return ntohl(sin->sin_addr.s_addr);
+#ifdef PF_INET6
+ else if (sin->sin_family == PF_INET6)
+ {
+ KInetSocketAddress *ksin = (KInetSocketAddress*)sa;
+ sin = ksin->addressV4();
+ if (sin != NULL)
+ return sin->sin_addr.s_addr;
+ }
+#endif
+ return 0; // this is dumb, isn't it?
+}
+
+void KServerSocket::slotAccept( int )
+{
+ if (d == NULL || d->ks == NULL || sock == -1)
+ return; // nothing!
+
+ KExtendedSocket *s;
+ if (d->ks->accept(s) < 0)
+ {
+ kdWarning(170) << "Error accepting\n";
+ return;
+ }
+
+ int new_sock = s->fd();
+ s->release(); // we're getting rid of the KExtendedSocket
+ delete s;
+
+ emit accepted( new KSocket( new_sock ) );
+}
+
+KServerSocket::~KServerSocket()
+{
+ if (d != NULL)
+ {
+ if (d->ks != NULL)
+ delete d->ks;
+ delete d;
+ }
+ // deleting d->ks closes the socket
+ // ::close( sock );
+}
+
+#include "ksock.moc"
diff --git a/kdecore/ksock.h b/kdecore/ksock.h
new file mode 100644
index 000000000..566d23236
--- /dev/null
+++ b/kdecore/ksock.h
@@ -0,0 +1,346 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1997 Torben Weis (weis@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KSOCK_H
+#define KSOCK_H
+
+#include "kdelibs_export.h"
+
+#ifdef Q_OS_UNIX
+
+#include <qobject.h>
+#include <sys/types.h>
+// we define STRICT_ANSI to get rid of some warnings in glibc
+#ifndef __STRICT_ANSI__
+#define __STRICT_ANSI__
+#define _WE_DEFINED_IT_
+#endif
+#include <sys/socket.h>
+#ifdef _WE_DEFINED_IT_
+#undef __STRICT_ANSI__
+#undef _WE_DEFINED_IT_
+#endif
+
+#include <sys/un.h>
+
+#include <netinet/in.h>
+class QSocketNotifier;
+
+#ifdef KSOCK_NO_BROKEN
+// This is here for compatibility with old applications still using the constants
+// Never use them in new programs
+
+// Here are a whole bunch of hackish macros that allow one to
+// get at the correct member of ksockaddr_in
+// But since ksockaddr_in is IPv4-only, and deprecated...
+
+typedef sockaddr_in ksockaddr_in;
+#define get_sin_addr(x) x.sin_addr
+#define get_sin_port(x) x.sin_port
+#define get_sin_family(x) x.sin_family
+#define get_sin_paddr(x) x->sin_addr
+#define get_sin_pport(x) x->sin_port
+#define get_sin_pfamily(x) x->sin_family
+#endif
+
+#define KSOCK_DEFAULT_DOMAIN PF_INET
+
+class KSocketPrivate;
+class KServerSocketPrivate;
+
+/** @deprecated
+ * You can connect this socket to any Internet address.
+ *
+ * This class is deprecated and will be removed in the future. For new
+ * programs, please use KExtendedSocket class.
+ *
+ * The socket gives you three signals: When ready for reading,
+ * ready for writing or if the connection is broken.
+ * Using socket() you get a file descriptor
+ * which you can use with the usual UNIX function like write() or
+ * read().
+ * If you have already such a socket identifier you can construct a KSocket
+ * on this identifier.
+ *
+ * If socket() delivers a value of -1 or less, the connection
+ * was not successful.
+ *
+ * @author Torben Weis <weis@uni-frankfurt.de>
+ * @short A TCP/IP client socket.
+ */
+class KDECORE_EXPORT KSocket : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructs a KSocket with the provided file descriptor.
+ * @param _sock The file descriptor to use.
+ */
+ KSocket( int _sock ) KDE_DEPRECATED;
+ /**
+ * Creates a socket and connects to a host.
+ * @param _host The remote host to which to connect.
+ * @param _port The port on the remote host.
+ * @param timeOut The number of seconds waiting for connect (default 30).
+ */
+ KSocket( const char *_host, unsigned short int _port, int timeOut = 30) KDE_DEPRECATED;
+
+ /**
+ * Connects to a UNIX domain socket.
+ * @param _path The filename of the socket.
+ */
+ KSocket( const char * _path ) KDE_DEPRECATED;
+
+ /**
+ * Destructor. Closes the socket if it is still open.
+ */
+ virtual ~KSocket();
+
+ /**
+ * Returns a file descriptor for this socket.
+ * @return the file descriptor, or -1 when an error occurred.
+ */
+ int socket() const { return sock; }
+
+ /**
+ * Enables the socket for reading.
+ *
+ * If you enable read mode, the socket will emit the signal
+ * readEvent() whenever there is something to read out of this
+ * socket.
+ * @param enable true to enable reading signals
+ */
+ void enableRead( bool enable );
+
+ /**
+ * Enables the socket for writing.
+ *
+ * If you enable write mode, the socket will emit the signal
+ * writeEvent() whenever the socket is ready for writing.
+ *
+ * Warning: If you forget to call enableWrite(false) when you are
+ * not ready to send data, you will get lots of writeEvent() signals,
+ * in the order of thousands a second !
+ * @param enable true to enable writing signals
+ */
+ void enableWrite( bool enable );
+
+#ifdef KSOCK_NO_BROKEN
+ // BCI: remove in libkdecore.so.4
+ /**
+ * Return address.
+ * This function is dumb. Don't ever use it
+ * if you need the peer address of this socket, use KExtendedSocket::peerAddress(int)
+ * instead
+ * @deprecated
+ */
+ unsigned long ipv4_addr() KDE_DEPRECATED;
+
+ // BCI: remove in libkdecore.so.4
+ /**
+ * A small wrapper around gethostbyname() and such.
+ * Don't use this in new programs. Use KExtendedSocket::lookup
+ * @deprecated
+ */
+ static bool initSockaddr(ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain = PF_INET) KDE_DEPRECATED;
+#endif
+
+signals:
+ /**
+ * Data has arrived for reading.
+ *
+ * This signal will only be raised if enableRead( @p true ) was called
+ * first.
+ * @param s the KSocket that triggered the event
+ */
+ void readEvent( KSocket *s );
+
+ /**
+ * Socket is ready for writing.
+ *
+ * This signal will only be raised if enableWrite( @p true ) was
+ * called first.
+ *
+ * Warning: If you forget to call enableWrite(false) when you are
+ * not ready to send data, you will get lots of writeEvent() signals,
+ * in the order of thousands a second !
+ * @param s the KSocket that triggered the event
+ */
+ void writeEvent( KSocket *s );
+
+ /**
+ * Raised when the connection is broken.
+ * @param s the KSocket that triggered the event
+ */
+ void closeEvent( KSocket *s );
+
+public slots:
+ /**
+ * Connected to the writeNotifier.
+ *
+ * Called when
+ * the socket is ready for writing.
+ * @param x ignored
+ */
+ void slotWrite( int x);
+
+ /**
+ * Connected to the readNotifier.
+ *
+ * Called when
+ * the socket is ready for reading.
+ * @param x ignored
+ */
+ void slotRead( int x );
+
+protected:
+ bool connect( const QString& _host, unsigned short int _port, int timeout = 0 );
+ bool connect( const char *_path );
+
+ /******************************************************
+ * The file descriptor for this socket. sock may be -1.
+ * This indicates that it is not connected.
+ */
+ int sock;
+
+private:
+ KSocket(const KSocket&);
+ KSocket& operator=(const KSocket&);
+
+ KSocketPrivate *d;
+
+};
+
+
+/**
+ * @short Monitors a port for incoming TCP/IP connections.
+ *
+ * @deprecated
+ * This class is deprecated and will be removed in the future.
+ * Please use the classes in KNetwork for new programs.
+ * In special, this class is replaced by KNetwork::KStreamSocket
+ * and KNetwork::KServerSocket.
+ *
+ * You can use a KServerSocket to listen on a port for incoming
+ * connections. When a connection arrived in the port, a KSocket
+ * is created and the signal accepted is raised. Make sure you
+ * always connect to this signal. If you don't the ServerSocket will
+ * create new KSocket's and no one will delete them!
+ *
+ * If socket() is -1 or less the socket was not created properly.
+ *
+ * @author Torben Weis <weis@stud.uni-frankfurt.de>
+*/
+class KDECORE_EXPORT KServerSocket : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor.
+ * @param _port the port number to monitor for incoming connections.
+ * @param _bind if false you need to call bindAndListen yourself.
+ * This gives you the opportunity to set options on the
+ * socket.
+ */
+ KServerSocket( unsigned short int _port, bool _bind = true );
+
+ /**
+ * Creates a UNIX domain server socket.
+ * @param _path path used for the socket.
+ * @param _bind if false you need to call bindAndListen yourself.
+ * This gives you the opportunity to set options on the
+ * socket.
+ */
+ KServerSocket( const char *_path, bool _bind = true);
+
+ /**
+ * Destructor. Closes the socket if it was not already closed.
+ */
+ virtual ~KServerSocket();
+
+ /**
+ * Binds the socket and start listening. This should only be called
+ * once when the constructor was called with _bind false.
+ * On error the socket will be closed.
+ * @return true on success. false on error.
+ */
+ bool bindAndListen();
+
+ /**
+ * Returns the file descriptor associated with the socket.
+ * @return the file descriptor, -1 when an error occurred during
+ * construction or bindAndListen
+ */
+ int socket() const { return sock; }
+
+ /**
+ * Returns the port number which is being monitored.
+ * @return the port number
+ */
+ unsigned short int port();
+
+#ifdef KSOCK_NO_BROKEN
+ // BCI: remove in libkdecore.so.4
+ /**
+ * The address.
+ * This is dumb. Don't use it
+ * Refer to KExtendedSocket::localAddress(int)
+ * @deprecated
+ */
+ unsigned long ipv4_addr();
+#endif
+
+public slots:
+ /**
+ * Called when someone connected to our port.
+ */
+ virtual void slotAccept( int ); // why is this virtual?
+
+signals:
+ /**
+ * A connection has been accepted.
+ * It is your task to delete the KSocket if it is no longer needed.
+ *
+ * WARNING: this signal is always emitted, even if you don't connect
+ * anything to it. That would mean memory loss, because the KSockets
+ * created go to oblivion.
+ * @param s the socket that accepted
+ */
+ void accepted( KSocket*s );
+
+protected:
+ bool init( unsigned short int );
+ bool init( const char *_path );
+
+ /**
+ * The file descriptor for this socket. sock may be -1.
+ * This indicates that it is not connected.
+ */
+ int sock;
+
+private:
+ KServerSocket(const KServerSocket&);
+ KServerSocket& operator=(const KServerSocket&);
+
+ KServerSocketPrivate *d;
+};
+
+#endif //Q_OS_UNIX
+
+#endif
diff --git a/kdecore/ksockaddr.cpp b/kdecore/ksockaddr.cpp
new file mode 100644
index 000000000..be3e08b58
--- /dev/null
+++ b/kdecore/ksockaddr.cpp
@@ -0,0 +1,894 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2002 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "ksockaddr.h"
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifdef Q_OS_UNIX
+#include <arpa/inet.h>
+#endif
+#include <netinet/in.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <qglobal.h>
+#include <qfile.h>
+
+#include "kdebug.h"
+#include "klocale.h"
+//#include "kextsock.h"
+
+#ifndef HAVE_STRUCT_SOCKADDR_IN6
+// The system doesn't have sockaddr_in6
+// But we can tell netsupp.h to define it for us, according to the RFC
+#define CLOBBER_IN6
+#endif
+
+#include "netsupp.h"
+
+#define V6_CAN_CONVERT_TO_V4(addr) (KDE_IN6_IS_ADDR_V4MAPPED(addr) || KDE_IN6_IS_ADDR_V4COMPAT(addr))
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+# define MY_MAX(a, b) ((a) > (b) ? (a) : (b))
+# define MIN_SOCKADDR_LEN MY_MAX(offsetof(sockaddr, sa_family) + sizeof(((sockaddr*)0)->sa_family), \
+ offsetof(sockaddr, sa_len) + sizeof(((sockaddr*)0)->sa_len))
+#else
+# define MIN_SOCKADDR_LEN (offsetof(sockaddr, sa_family) + sizeof(((sockaddr*)0)->sa_family))
+#endif
+
+// Minimum size accepted for sockaddr_in6 sockets.
+// The scopeid field is missing from some implementations
+// that conform to the obsoleted RFC 2133, e.g. Linux glibc 2.1
+#define MIN_SOCKADDR_IN6_LEN (offsetof(sockaddr_in6, sin6_addr) + sizeof(((sockaddr_in6*)0)->sin6_addr))
+
+#ifdef offsetof
+#undef offsetof
+#endif
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+// This is how it is
+// 46 == strlen("1234:5678:9abc:def0:1234:5678:255.255.255.255")
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+
+/**
+ * Class KSocketAddress
+ */
+
+KSocketAddress::KSocketAddress(const sockaddr* sa, ksocklen_t size)
+{
+ if ( !sa )
+ init();
+ else {
+ data = (sockaddr*)malloc(size);
+ if (data == NULL)
+ return;
+ memcpy(data, sa, size);
+ datasize = size;
+ owndata = true;
+ }
+}
+
+void KSocketAddress::init()
+{
+ data = NULL;
+ datasize = 0;
+ owndata = false;
+}
+
+KSocketAddress::~KSocketAddress()
+{
+ if (owndata && data != NULL)
+ free(data);
+}
+
+QString KSocketAddress::pretty() const
+{
+ return i18n("<unknown socket>");
+}
+
+int KSocketAddress::family() const
+{
+ if (data != NULL)
+ return data->sa_family;
+ return AF_UNSPEC;
+}
+
+// This creates a new KSocketAddress with given sockaddr
+KSocketAddress* KSocketAddress::newAddress(const struct sockaddr* sa, ksocklen_t size)
+{
+ if (size == 0)
+ {
+ kdWarning() << "KSocketAddress::newAddress called with size = 0!\n";
+ return NULL;
+ }
+
+ // make sure we have the right stuff
+ if (size < MIN_SOCKADDR_LEN)
+ {
+ kdWarning() << "KSocketAddress::newAddress called with invalid size\n";
+ return NULL;
+ }
+
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (size >= sizeof(sockaddr_in))
+ return new KInetSocketAddress((const sockaddr_in*)sa, size);
+ return NULL;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ if (size >= MIN_SOCKADDR_IN6_LEN)
+ return new KInetSocketAddress((const sockaddr_in6*)sa, size);
+ return NULL;
+#endif
+
+ case AF_UNIX: // AF_LOCAL
+ return new KUnixSocketAddress((const sockaddr_un*)sa, size);
+ }
+
+ return new KSocketAddress(sa, size);
+}
+
+bool KSocketAddress::isEqual(const KSocketAddress& other) const
+{
+ switch(family())
+ {
+ case AF_INET:
+ return KInetSocketAddress::areEqualInet(*this, other, false);
+#ifdef AF_INET6
+ case AF_INET6:
+ return KInetSocketAddress::areEqualInet6(*this, other, false);
+#endif
+ case AF_UNIX: // AF_LOCAL
+ return KUnixSocketAddress::areEqualUnix(*this, other, false);
+ }
+
+ // This is not a known socket type
+ if (other.datasize != datasize)
+ return false; // can't be equal
+ return memcmp(data, other.data, datasize) == 0;
+}
+
+bool KSocketAddress::isCoreEqual(const KSocketAddress& other) const
+{
+ switch(family())
+ {
+ case AF_INET:
+ return KInetSocketAddress::areEqualInet(*this, other, true);
+#ifdef AF_INET6
+ case AF_INET6:
+ return KInetSocketAddress::areEqualInet6(*this, other, true);
+#endif
+ case AF_UNIX: // AF_LOCAL
+ return KUnixSocketAddress::areEqualUnix(*this, other, true);
+ }
+
+ return false;
+}
+
+QString KSocketAddress::nodeName() const
+{
+ return QString::null;
+}
+
+QString KSocketAddress::serviceName() const
+{
+ return QString::null;
+}
+
+int KSocketAddress::ianaFamily(int af)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return 1;
+#ifdef AF_INET6
+ case AF_INET6:
+ return 2;
+#endif
+ default:
+ return 0;
+ }
+}
+
+int KSocketAddress::fromIanaFamily(int iana)
+{
+ switch (iana)
+ {
+ case 1:
+ return AF_INET;
+#ifdef AF_INET6
+ case 2:
+ return AF_INET6;
+#endif
+ default:
+ return AF_UNSPEC;
+ }
+}
+
+/**
+ * class KInetSocketAddress
+ */
+class KInetSocketAddressPrivate
+{
+public:
+ int sockfamily;
+ sockaddr_in sin;
+#ifdef AF_INET6
+ sockaddr_in6 sin6;
+#endif
+
+ KInetSocketAddressPrivate() :
+ sockfamily(AF_UNSPEC)
+ {
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin.sin_len = sizeof(sin);
+#endif
+#ifdef AF_INET6
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = 0;
+ sin6.sin6_flowinfo = 0;
+# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ sin6.sin6_scope_id = 0;
+# endif
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6.sin6_len = sizeof(sin6);
+# endif
+#endif
+ }
+
+};
+
+KInetSocketAddress::KInetSocketAddress() :
+ d(new KInetSocketAddressPrivate)
+{
+}
+
+KInetSocketAddress::KInetSocketAddress(const KInetSocketAddress &other) :
+ KSocketAddress(), d(new KInetSocketAddressPrivate)
+{
+ setAddress(other);
+}
+
+KInetSocketAddress::KInetSocketAddress(const sockaddr_in* sin, ksocklen_t len) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(sin, len);
+}
+
+KInetSocketAddress::KInetSocketAddress(const sockaddr_in6* sin6, ksocklen_t len) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(sin6, len);
+}
+
+KInetSocketAddress::KInetSocketAddress(const in_addr& addr, unsigned short port) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(addr, port);
+}
+
+KInetSocketAddress::KInetSocketAddress(const in6_addr& addr, unsigned short port) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(addr, port);
+}
+
+KInetSocketAddress::KInetSocketAddress(const QString& addr, unsigned short port, int family) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(addr, port, family);
+}
+
+KInetSocketAddress::~KInetSocketAddress()
+{
+ delete d;
+
+ // KSocketAddress::~KSocketAddress();
+}
+
+bool KInetSocketAddress::setAddress(const KInetSocketAddress &other)
+{
+ if (other.family() == AF_INET)
+ return setAddress(other.addressV4(), other.size());
+#ifdef AF_INET6
+ else if (other.family() == AF_INET6)
+ return setAddress(other.addressV6(), other.size());
+#endif
+ return false;
+}
+
+bool KInetSocketAddress::setAddress(const sockaddr_in* sin, ksocklen_t len)
+{
+ // This is supposed to be a AF_INET socket
+ if ((len < sizeof(sockaddr_in)) || (sin->sin_family != AF_INET))
+ {
+ kdWarning() << "KInetSocketAddress::setAddress(sockaddr_in*) called with invalid sockaddr_in\n";
+ return false;
+ }
+
+ return setHost(sin->sin_addr) && setPort(ntohs(sin->sin_port));
+}
+
+bool KInetSocketAddress::setAddress(const sockaddr_in6* sin6, ksocklen_t len)
+{
+#ifdef AF_INET6
+ // should be family AF_INET6
+ if ((len < MIN_SOCKADDR_IN6_LEN) || (sin6->sin6_family != AF_INET6))
+ {
+ kdWarning() << "KInetSocketAddress::setAddress(sockaddr_in6*) called with invalid sockaddr_in6\n";
+ return 0;
+ }
+
+ memset(&d->sin6, 0, sizeof(d->sin6));
+ if (len > sizeof(d->sin6))
+ len = sizeof(d->sin6);
+ memcpy(&d->sin6, sin6, len);
+
+ /* Now make a sanity check */
+ d->sockfamily = d->sin6.sin6_family = AF_INET6;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ d->sin6.sin6_len = sizeof(d->sin6);
+# endif
+
+ fromV6();
+ return true;
+#else // !AF_INET6
+ return false;
+#endif
+}
+
+bool KInetSocketAddress::setAddress(const in_addr& addr, unsigned short port)
+{
+ return setHost(addr) && setPort(port);
+}
+
+bool KInetSocketAddress::setAddress(const in6_addr& addr, unsigned short port)
+{
+ return setHost(addr) && setPort(port);
+}
+
+bool KInetSocketAddress::setAddress(const QString& addr, unsigned short port, int family)
+{
+ return setHost(addr, family) && setPort(port);
+}
+
+bool KInetSocketAddress::setHost(const in_addr& addr)
+{
+ d->sockfamily = AF_INET; // set address to IPv4 type
+ d->sin.sin_addr = addr;
+ fromV4();
+ return true;
+}
+
+bool KInetSocketAddress::setHost(const in6_addr& addr)
+{
+#ifdef AF_INET6
+ d->sockfamily = AF_INET6; // set address to IPv6 type
+ d->sin6.sin6_addr = addr;
+ fromV6();
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool KInetSocketAddress::setHost(const QString& addr, int family)
+{
+ // if family == -1, we'll try to guess the host name
+ if ((family != -1) && (family != AF_INET)
+#ifdef AF_INET6
+ && (family != AF_INET6)
+#endif
+ )
+ {
+ kdWarning() << "KInetSocketAddress::setHost(QString, int) called with unknown family address\n";
+ return false;
+ }
+
+ if (family == -1)
+ {
+ // guess the family type
+
+#ifdef AF_INET6
+ // IPv6 addresses MUST contain colons (:) and IPv4 addresses must not
+ if (addr.find(':') != -1)
+ family = AF_INET6;
+ else
+ family = AF_INET;
+#else
+
+ // There's only one guess:
+ family = AF_INET;
+#endif
+ }
+
+ /*
+ * FIXME! What is the decoding process for hostnames?
+ */
+ if (family == AF_INET)
+ {
+ inet_pton(family, addr.latin1(), (void*)&(d->sin.sin_addr));
+ fromV4();
+ }
+#ifdef AF_INET6
+ else
+ {
+ inet_pton(family, addr.latin1(), (void*)&(d->sin6.sin6_addr));
+ fromV6();
+ }
+#endif
+ d->sockfamily = family;
+ return true;
+}
+
+bool KInetSocketAddress::setPort(unsigned short port)
+{
+ // set port on all socket types
+ d->sin.sin_port = htons(port);
+#ifdef AF_INET6
+ d->sin6.sin6_port = htons(port);
+#endif
+
+ return true;
+}
+
+bool KInetSocketAddress::setFamily(int _family)
+{
+ if (_family != AF_INET
+#ifdef AF_INET6
+ && _family != AF_INET6
+#endif
+ )
+ {
+ kdWarning() << "KInetSocketAddress::setFamily(int) called with unknown family\n";
+ return false;
+ }
+
+ d->sockfamily = _family;
+ if (_family == AF_INET)
+ fromV4();
+#ifdef AF_INET6
+ else if (_family == AF_INET6)
+ fromV6();
+#endif
+
+ return true;
+}
+
+bool KInetSocketAddress::setFlowinfo(Q_UINT32 flowinfo)
+{
+#ifdef AF_INET6
+ if (d->sockfamily == AF_INET6)
+ {
+ d->sin6.sin6_flowinfo = flowinfo;
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool KInetSocketAddress::setScopeId(int scopeid)
+{
+#if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ if (d->sockfamily == AF_INET6)
+ {
+ d->sin6.sin6_scope_id = scopeid;
+ return true;
+ }
+#endif
+ (void)scopeid;
+ return false;
+}
+
+const sockaddr_in* KInetSocketAddress::addressV4() const
+{
+ if (d->sockfamily == AF_INET)
+ return &d->sin;
+#ifdef AF_INET6
+ else if (d->sockfamily == AF_INET6)
+ {
+ // check if this IPv6 address was converted without loss
+ if (V6_CAN_CONVERT_TO_V4(&d->sin6.sin6_addr))
+ return &d->sin;
+ else
+ return NULL; // there was loss, so return nothing
+ }
+#endif
+
+ kdWarning() << "KInetSocketAddress::addressV4() called on uninitialized socket\n";
+ return NULL;
+}
+
+const sockaddr_in6* KInetSocketAddress::addressV6() const
+{
+#ifdef AF_INET6
+ return &d->sin6;
+#else
+ return NULL;
+#endif
+}
+
+in_addr KInetSocketAddress::hostV4() const
+{
+ // this might be empty
+ return d->sin.sin_addr;
+}
+
+/*
+ * ATTENTION
+ * This function is left undefined if no IPv6 support exists
+ * This is intentional
+ */
+#ifdef AF_INET6
+in6_addr KInetSocketAddress::hostV6() const
+{
+ return d->sin6.sin6_addr;
+}
+#endif
+
+QString KInetSocketAddress::pretty() const
+{
+ if (d->sockfamily != AF_INET
+#ifdef AF_INET6
+ && d->sockfamily != AF_INET6
+#endif
+ )
+ {
+ kdWarning() << "KInetSocketAddress::pretty() called on uninitialized class\n";
+ return i18n("<empty>");
+ }
+
+ return i18n("1: hostname, 2: port number", "%1 port %2").arg(nodeName()).arg(serviceName());
+}
+
+QString KInetSocketAddress::nodeName() const
+{
+ char buf[INET6_ADDRSTRLEN]; // INET6_ADDRSTRLEN > INET_ADDRSTRLEN
+
+ if (d->sockfamily == AF_INET)
+ inet_ntop(d->sockfamily, (void*)&d->sin.sin_addr, buf, sizeof(buf));
+#ifdef AF_INET6
+ else if (d->sockfamily == AF_INET6)
+ inet_ntop(d->sockfamily, (void*)&d->sin6.sin6_addr, buf, sizeof(buf));
+#endif
+ else
+ {
+ kdWarning() << "KInetSocketAddress::nodeName() called on uninitialized class\n";
+ return i18n("<empty>");
+ }
+
+ return QString::fromLatin1(buf); // FIXME! What's the encoding?
+}
+
+QString KInetSocketAddress::serviceName() const
+{
+ return QString::number(port());
+}
+
+unsigned short KInetSocketAddress::port() const
+{
+#ifdef AF_INET6
+ // we prefer sin6 here because fromV6() might make sin.sin_port be 0
+ return ntohs(d->sin6.sin6_port);
+#else
+ return ntohs(d->sin.sin_port);
+#endif
+}
+
+Q_UINT32 KInetSocketAddress::flowinfo() const
+{
+#ifdef AF_INET6
+ if (d->sockfamily == AF_INET6)
+ return (Q_UINT32)d->sin6.sin6_flowinfo;
+#endif
+ return 0;
+}
+
+ksocklen_t KInetSocketAddress::size() const
+{
+ if (d->sockfamily == AF_INET)
+ return sizeof(d->sin);
+#ifdef AF_INET6
+ else if (d->sockfamily == AF_INET6)
+ return sizeof(d->sin6);
+#endif
+ else
+ return 0;
+}
+
+bool KInetSocketAddress::areEqualInet(const KSocketAddress &s1, const KSocketAddress &s2, bool coreOnly)
+{
+ if (s1.family() != s2.family())
+ return false;
+ if ((s1.size() < sizeof(sockaddr_in)) || (s2.size() < sizeof(sockaddr_in)))
+ return false;
+
+ struct sockaddr_in *sin1 = (sockaddr_in *) s1.address();
+ struct sockaddr_in *sin2 = (sockaddr_in *) s2.address();
+
+ if (coreOnly)
+ return (memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof(struct in_addr)) == 0);
+ else
+ return (sin1->sin_port == sin2->sin_port) &&
+ (memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof(struct in_addr)) == 0);
+}
+
+bool KInetSocketAddress::areEqualInet6(const KSocketAddress &s1, const KSocketAddress &s2, bool coreOnly)
+{
+#ifdef AF_INET6
+ if (s1.family() != s2.family())
+ return false;
+
+ if ((s1.size() < sizeof(sockaddr_in6)) || (s2.size() < sizeof(sockaddr_in6)))
+ return false;
+
+ struct sockaddr_in6 *sin1 = (sockaddr_in6 *) s1.address();
+ struct sockaddr_in6 *sin2 = (sockaddr_in6 *) s2.address();
+
+ if (coreOnly)
+ return (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof(struct in6_addr)) == 0);
+ else
+ return (sin1->sin6_port == sin2->sin6_port) &&
+ (sin1->sin6_flowinfo == sin2->sin6_flowinfo) &&
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ (sin1->sin6_scope_id == sin2->sin6_scope_id) &&
+#endif
+ (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof(struct in6_addr)) == 0);
+#else
+ return false;
+#endif
+}
+
+void KInetSocketAddress::fromV4()
+{
+ // converts an address from v4
+
+#ifdef AF_INET6
+ d->sin6.sin6_port = d->sin.sin_port;
+
+ // Make this a v4-mapped address
+ ((Q_UINT32*)&d->sin6.sin6_addr)[0] = ((Q_UINT32*)&d->sin6.sin6_addr)[1] = 0;
+ ((Q_UINT32*)&d->sin6.sin6_addr)[2] = htonl(0xffff);
+ ((Q_UINT32*)&d->sin6.sin6_addr)[3] = *(Q_UINT32*)&d->sin.sin_addr;
+
+ // Clear flowinfo and scopeid
+ d->sin6.sin6_flowinfo = 0;
+# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ d->sin6.sin6_scope_id = 0;
+# endif
+#endif
+
+ // data == KSocketAddress::data
+ data = (sockaddr*)&d->sin;
+ datasize = sizeof( sockaddr_in );
+}
+
+void KInetSocketAddress::fromV6()
+{
+#ifdef AF_INET6
+ // convert to v4 only if this is a v4-mapped or v4-compat address
+ if (V6_CAN_CONVERT_TO_V4(&d->sin6.sin6_addr))
+ {
+ d->sin.sin_port = d->sin6.sin6_port;
+ *(Q_UINT32*)&d->sin.sin_addr = ((Q_UINT32*)&d->sin6.sin6_addr)[3];
+ }
+ else
+ {
+ d->sin.sin_port = 0;
+ memset(&d->sin.sin_addr, 0, sizeof(d->sin.sin_addr));
+ }
+
+ data = (sockaddr*)&d->sin6;
+ datasize = sizeof( d->sin6 );
+#endif
+}
+
+QString KInetSocketAddress::addrToString(int family, const void* addr)
+{
+ char buf[INET6_ADDRSTRLEN+1];
+
+ return QString::fromLatin1(inet_ntop(family, addr, buf, INET6_ADDRSTRLEN));
+}
+
+bool KInetSocketAddress::stringToAddr(int family, const char *text, void *dest)
+{
+ return inet_pton(family, text, dest) != 0;
+}
+
+/**
+ * class KUnixSocketAddress
+ */
+
+class KUnixSocketAddressPrivate
+{
+public:
+ sockaddr_un *m_sun;
+
+ KUnixSocketAddressPrivate() : m_sun(NULL)
+ { }
+};
+
+KUnixSocketAddress::KUnixSocketAddress() :
+ d(new KUnixSocketAddressPrivate)
+{
+}
+
+KUnixSocketAddress::KUnixSocketAddress(const sockaddr_un* _sun, ksocklen_t size) :
+ d(new KUnixSocketAddressPrivate)
+{
+ setAddress(_sun, size);
+}
+
+KUnixSocketAddress::KUnixSocketAddress(QCString pathname) :
+ d(new KUnixSocketAddressPrivate)
+{
+ setAddress(pathname);
+}
+
+KUnixSocketAddress::~KUnixSocketAddress()
+{
+ delete d;
+}
+
+bool KUnixSocketAddress::setAddress(const sockaddr_un* _sun, ksocklen_t _size)
+{
+ if (_sun->sun_family != AF_UNIX)
+ {
+ kdWarning() << "KUnixSocketAddress::setAddress called with invalid socket\n";
+ return false;
+ }
+
+ if (owndata && (d->m_sun != NULL) && (datasize >= _size))
+ {
+ // reuse this without reallocating
+ memcpy(d->m_sun, _sun, _size);
+ }
+ else
+ {
+ if (owndata && (d->m_sun != NULL))
+ free(d->m_sun);
+
+ d->m_sun = (sockaddr_un*)malloc(_size);
+
+ if (d->m_sun == NULL)
+ {
+ // problems
+ owndata = false;
+ return false;
+ }
+
+ memcpy(d->m_sun, _sun, _size);
+ }
+
+ datasize = _size;
+ data = (sockaddr*)d->m_sun;
+ owndata = true;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ data->sa_len = _size;
+#endif
+ return 1;
+}
+
+bool KUnixSocketAddress::setAddress(QCString path)
+{
+ // the +1 is necessary for the ending zero
+ ksocklen_t newsize = offsetof(sockaddr_un, sun_path) + path.length() + 1;
+
+ if (owndata && (d->m_sun != NULL) && (datasize >= newsize))
+ {
+ // we can reuse this
+ strcpy(d->m_sun->sun_path, path);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ data->sa_len = newsize;
+#endif
+ return true;
+ }
+
+ // nah, we have to do better
+ if (owndata && (d->m_sun != NULL))
+ free(d->m_sun);
+
+ d->m_sun = (sockaddr_un*) malloc(newsize);
+ if (d->m_sun == NULL)
+ {
+ owndata = false;
+ return false;
+ }
+
+ d->m_sun->sun_family = AF_UNIX;
+ strcpy(d->m_sun->sun_path, path);
+ data = (sockaddr*)d->m_sun;
+ datasize = newsize;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ data->sa_len = newsize;
+#endif
+ return 1;
+}
+
+QCString KUnixSocketAddress::pathname() const
+{
+ if (d->m_sun != NULL)
+ {
+ if (datasize > offsetof(sockaddr_un, sun_path))
+ return d->m_sun->sun_path;
+ return "";
+ }
+ return QCString(0);
+}
+
+QString KUnixSocketAddress::pretty() const
+{
+ QCString pname = pathname();
+ if (pname.isEmpty())
+ return i18n("<empty UNIX socket>");
+ return QFile::decodeName(pathname());
+}
+
+QString KUnixSocketAddress::serviceName() const
+{
+ return QString::fromUtf8(pathname());
+}
+
+const sockaddr_un* KUnixSocketAddress::address() const
+{
+ return d->m_sun;
+}
+
+bool KUnixSocketAddress::areEqualUnix(const KSocketAddress &s1, const KSocketAddress &s2, bool /* coreOnly */)
+{
+ if (s1.family() != s2.family())
+ return false;
+
+ if ((s1.size() < MIN_SOCKADDR_LEN) || (s2.size() < MIN_SOCKADDR_LEN))
+ return false;
+
+ struct sockaddr_un *sun1 = (sockaddr_un *) s1.address();
+ struct sockaddr_un *sun2 = (sockaddr_un *) s2.address();
+
+ if (s1.size() == MIN_SOCKADDR_LEN && s2.size() == MIN_SOCKADDR_LEN)
+ return true; // unnamed Unix sockets
+
+ return (strcmp(sun1->sun_path, sun2->sun_path) == 0);
+}
+
+void KSocketAddress::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KInetSocketAddress::virtual_hook( int id, void* data )
+{ KSocketAddress::virtual_hook( id, data ); }
+
+void KUnixSocketAddress::virtual_hook( int id, void* data )
+{ KSocketAddress::virtual_hook( id, data ); }
+
+
+#include "ksockaddr.moc"
diff --git a/kdecore/ksockaddr.h b/kdecore/ksockaddr.h
new file mode 100644
index 000000000..be522f72b
--- /dev/null
+++ b/kdecore/ksockaddr.h
@@ -0,0 +1,683 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KSOCKADDR_H
+#define KSOCKADDR_H
+
+#include <qobject.h>
+#include <qcstring.h>
+#include <qstring.h>
+#include "kdelibs_export.h"
+
+/*
+ * This file defines a class that envelopes most, if not all, socket addresses
+ */
+typedef unsigned ksocklen_t;
+
+struct sockaddr;
+
+class KExtendedSocket; // No need to define it fully
+
+class KSocketAddressPrivate;
+/**
+ * A socket address.
+ *
+ * This class envelopes almost if not all socket addresses.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ * @short a socket address.
+ */
+class KDECORE_EXPORT KSocketAddress: public QObject
+{
+ Q_OBJECT
+protected:
+ /**
+ * Creates an empty class
+ */
+ KSocketAddress() { init(); }
+
+ /**
+ * Creates with given data
+ * @param sa a sockaddr structure
+ * @param size the size of @p sa
+ */
+ KSocketAddress(const sockaddr* sa, ksocklen_t size);
+
+public:
+ /**
+ * Destructor.
+ */
+ virtual ~KSocketAddress();
+
+ /**
+ * Returns a string representation of this socket.
+ * @return a pretty string representation
+ */
+ virtual QString pretty() const;
+
+ /**
+ * Returns a sockaddr structure, for passing down to library functions.
+ * @return the sockaddr structure, can be 0
+ */
+ const sockaddr* address() const
+ { return data; }
+
+ /**
+ * Returns sockaddr structure size.
+ * @return the size of the sockaddr structre, 0 if there is none.
+ */
+ virtual ksocklen_t size() const
+ { return datasize; }
+
+ /**
+ * Returns a sockaddr structure, for passing down to library functions.
+ * @return the sockaddr structure, can be 0.
+ * @see address()
+ */
+ operator const sockaddr*() const
+ { return data; }
+
+ /**
+ * Returns the family of this address.
+ * @return the family of this address, AF_UNSPEC if it's undefined
+ */
+ int family() const;
+
+ /**
+ * Returns the IANA family number of this address.
+ * @return the IANA family number of this address (1 for AF_INET.
+ * 2 for AF_INET6, otherwise 0)
+ */
+ inline int ianaFamily() const
+ { return ianaFamily(family()); }
+
+ /**
+ * Returns true if this equals the other socket.
+ * @param other the other socket
+ * @return true if both sockets are equal
+ */
+ virtual bool isEqual(const KSocketAddress& other) const;
+ bool isEqual(const KSocketAddress* other) const
+ { return isEqual(*other); }
+
+ /**
+ * Overloaded == operator.
+ * @see isEqual()
+ */
+ bool operator==(const KSocketAddress& other) const
+ { return isEqual(other); }
+
+ /**
+ * Some sockets may differ in such things as services or port numbers,
+ * like Internet sockets. This function compares only the core part
+ * of that, if possible.
+ *
+ * If not possible, like the default implementation, this returns
+ * the same as isEqual.
+ * @param other the other socket
+ * @return true if the code part is equal
+ */
+ bool isCoreEqual(const KSocketAddress& other) const;
+
+ /**
+ * Some sockets may differ in such things as services or port numbers,
+ * like Internet sockets. This function compares only the core part
+ * of that, if possible.
+ *
+ * If not possible, like the default implementation, this returns
+ * the same as isEqual.
+ * @param other the other socket
+ * @return true if the code part is equal
+ */
+ bool isCoreEqual(const KSocketAddress* other) const
+ { return isCoreEqual(*other); }
+
+ /**
+ * Returns the node name of this socket, as KExtendedSocket::lookup expects
+ * as the first argument.
+ * In the case of Internet sockets, this is the hostname.
+ * The default implementation returns QString::null.
+ * @return the node name, can be QString::null
+ */
+ virtual QString nodeName() const;
+
+ /**
+ * Returns the service name for this socket, as KExtendedSocket::lookup expects
+ * as the service argument.
+ * In the case of Internet sockets, this is the port number.
+ * The default implementation returns QString::null.
+ * @return the service name, can be QString::null
+ */
+ virtual QString serviceName() const;
+
+protected:
+ sockaddr* data;
+ ksocklen_t datasize;
+ bool owndata;
+
+private:
+ void init();
+ /* No copy constructor */
+ KSocketAddress(KSocketAddress&);
+ KSocketAddress& operator=(KSocketAddress&);
+
+public:
+ /**
+ * Creates a new KSocketAddress or descendant class from given
+ * raw socket address.
+ * @param sa new socket address
+ * @param size new socket address's length
+ * @return the new KSocketAddress, or 0 if the function failed
+ */
+ static KSocketAddress* newAddress(const struct sockaddr *sa, ksocklen_t size);
+
+ /**
+ * Returns the IANA family number of the given address family.
+ * Returns 0 if there is no corresponding IANA family number.
+ * @param af the address family, in AF_* constants
+ * @return the IANA family number of this address (1 for AF_INET.
+ * 2 for AF_INET6, otherwise 0)
+ */
+ static int ianaFamily(int af);
+
+ /**
+ * Returns the address family of the given IANA family number.
+ * @return the address family, AF_UNSPEC for unknown IANA family numbers
+ */
+ static int fromIanaFamily(int iana);
+
+ friend class KExtendedSocket;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KSocketAddressPrivate* d;
+};
+
+/*
+ * External definitions
+ * We need these for KInetSocketAddress
+ */
+struct sockaddr_in;
+struct sockaddr_in6;
+struct in_addr;
+struct in6_addr;
+
+class KInetSocketAddressPrivate;
+/**
+ * An Inet (IPv4 or IPv6) socket address
+ *
+ * This is an IPv4 or IPv6 address of the Internet
+ *
+ * This class inherits most of the functionality from KSocketAddress, but
+ * is targeted specifically to Internet addresses
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ * @short an Internet socket address
+ */
+class KDECORE_EXPORT KInetSocketAddress: public ::KSocketAddress
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor. Does nothing
+ */
+ KInetSocketAddress();
+
+ /**
+ * Copy constructor
+ */
+ KInetSocketAddress(const KInetSocketAddress&);
+
+ /**
+ * Creates an IPv4 socket from raw sockaddr_in.
+ * @param sin a sockaddr_in structure to copy from
+ * @param len the socket address length
+ */
+ KInetSocketAddress(const sockaddr_in* sin, ksocklen_t len);
+
+ /**
+ * Creates an IPv6 socket from raw sockaddr_in6.
+ * @param sin6 a sockaddr_in6 structure to copy from
+ * @param len the socket address length
+ */
+ KInetSocketAddress(const sockaddr_in6* sin6, ksocklen_t len);
+
+ /**
+ * Creates a socket from information.
+ * @param addr a binary address
+ * @param port a port number
+ */
+ KInetSocketAddress(const in_addr& addr, unsigned short port);
+
+ /**
+ * Creates a socket from information.
+ * @param addr a binary address
+ * @param port a port number
+ */
+ KInetSocketAddress(const in6_addr& addr, unsigned short port);
+
+ /**
+ * Creates a socket from text representation.
+ *
+ * @param addr a text representation of the address
+ * @param port a port number
+ * @param family the family for this address. Use -1 to guess the
+ * family type
+ * @see setAddress
+ */
+ KInetSocketAddress(const QString& addr, unsigned short port, int family = -1);
+
+ /**
+ * Destructor
+ */
+ virtual ~KInetSocketAddress();
+
+ /**
+ * Sets this socket to given socket.
+ * @param ksa the other socket
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(const KInetSocketAddress& ksa);
+
+ /**
+ * Sets this socket to given raw socket.
+ * @param sin the raw socket
+ * @param len the socket address length
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(const sockaddr_in* sin, ksocklen_t len);
+
+ /**
+ * Sets this socket to given raw socket.
+ *
+ * Note: this function does not clear the scope ID and flow info values
+ * @param sin6 the raw socket
+ * @param len the socket address length
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(const sockaddr_in6* sin6, ksocklen_t len);
+
+ /**
+ * Sets this socket to raw address and port.
+ * @param addr the address
+ * @param port the port number
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(const in_addr& addr, unsigned short port);
+
+ /**
+ * Sets this socket to raw address and port.
+ * @param addr the address
+ * @param port the port number
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(const in6_addr& addr, unsigned short port);
+
+ /**
+ * Sets this socket to text address and port
+ *
+ * You can use the @p family parameter to specify what kind of socket
+ * you want this to be. It could be AF_INET or AF_INET6 or -1.
+ *
+ * If the value is -1 (default), this function will make an effort to
+ * discover what is the family. That isn't too hard, actually, and it
+ * works in all cases. But, if you want to be sure that your socket
+ * is of the type you want, use this parameter.
+ *
+ * This function returns false if the socket address was not valid.
+ * @param addr the address
+ * @param port the port number
+ * @param family the address family, -1 for any
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(const QString& addr, unsigned short port, int family = -1);
+
+ /**
+ * Sets this socket's host address to given raw address.
+ * @param addr the address
+ * @return true if successful, false otherwise
+ */
+ bool setHost(const in_addr& addr);
+
+ /**
+ * Sets this socket's host address to given raw address.
+ * @param addr the address
+ * @return true if successful, false otherwise
+ */
+ bool setHost(const in6_addr& addr);
+
+ /**
+ * Sets this socket's host address to given text representation.
+ * @param addr the address
+ * @param family the address family, -1 to guess the family
+ * @return true if successful, false otherwise
+ */
+ bool setHost(const QString& addr, int family = -1);
+
+ /**
+ * Sets this socket's port number to given port number.
+ * @param port the port number
+ * @return true if successful, false otherwise
+ */
+ bool setPort(unsigned short port);
+
+ /**
+ * Turns this into an IPv4 or IPv6 address.
+ *
+ * @param family the new address family
+ * @return false if this is v6 and information was lost. That doesn't
+ * mean the conversion was unsuccessful.
+ */
+ bool setFamily(int family);
+
+ /**
+ * Sets flowinfo information for this socket address if this is IPv6.
+ * @param flowinfo flowinfo
+ * @return true if successful, false otherwise
+ */
+ bool setFlowinfo(Q_UINT32 flowinfo);
+
+ /**
+ * Sets the scope id for this socket if this is IPv6.
+ * @param scopeid the scope id
+ * @return true if successful, false otherwise
+ */
+ bool setScopeId(int scopeid);
+
+ /**
+ * Returns a pretty representation of this address.
+ * @return a pretty representation
+ */
+ virtual QString pretty() const;
+
+ /**
+ * Returns the text representation of the host address.
+ * @return a text representation of the host address
+ */
+ virtual QString nodeName() const;
+ // QString prettyHost() const;
+
+ /**
+ * Returns the text representation of the port number.
+ * @return the name of the service (a number)
+ */
+ virtual QString serviceName() const;
+
+ /**
+ * Returns the socket address.
+ *
+ * This will be NULL if this is a non-convertible v6.
+ * This function will return an IPv4 socket if this IPv6
+ * socket is a v4-mapped address. That is, if it's really
+ * an IPv4 address, but in v6 disguise.
+ * @return the sockaddr_in struct, can be 0.
+ */
+ const sockaddr_in* addressV4() const;
+
+ /**
+ * Returns the socket address in IPv6
+ * @return the sockaddr_in struct, can be 0 if IPv6 is unsupported.
+ */
+ const sockaddr_in6* addressV6() const;
+
+ /**
+ * Returns the host address.
+ * Might be empty.
+ * @return the host address
+ */
+ in_addr hostV4() const;
+
+ /**
+ * Returns the host address.
+ *
+ * WARNING: this function is not defined if there is no IPv6 support
+ * @return the host address
+ */
+ in6_addr hostV6() const;
+
+ /**
+ * Returns the port number.
+ * @return the port number
+ */
+ unsigned short port() const;
+
+ /**
+ * Returns flowinfo for IPv6 socket.
+ * @return the flowinfo, 0 if unsupported
+ */
+ Q_UINT32 flowinfo() const;
+
+ /**
+ * Returns the scope id for this IPv6 socket.
+ * @return the scope id
+ */
+ int scopeId() const;
+
+ /**
+ * Returns the socket length.
+ * Will be either sizeof(sockaddr_in) or sizeof(sockaddr_in6)
+ * @return the length of the socket
+ */
+ virtual ksocklen_t size() const; // should be socklen_t
+
+ /* comparation */
+ /**
+ * Compares two IPv4 addresses.
+ * @param s1 the first address to compare
+ * @param s2 the second address to compare
+ * @param coreOnly true if only core parts should be compared (only
+ * the address)
+ * @return true if the given addresses are equal.
+ * @see areEqualInet6()
+ * @see KSocketAddress::isEqual()
+ * @see KSocketAddress::isCoreEqual()
+ */
+ static bool areEqualInet(const KSocketAddress &s1, const KSocketAddress &s2, bool coreOnly);
+
+ /**
+ * Compares two IPv6 addresses.
+ * @param s1 the first address to compare
+ * @param s2 the second address to compare
+ * @param coreOnly true if only core parts should be compared (only
+ * the address)
+ * @return true if the given addresses are equal.
+ * @see areEqualInet()
+ * @see KSocketAddress::isEqual()
+ * @see KSocketAddress::isCoreEqual()
+ */
+ static bool areEqualInet6(const KSocketAddress &s1, const KSocketAddress &s2, bool coreOnly);
+
+ /* operators */
+
+ /**
+ * Returns the socket address.
+ * This will be NULL if this is a non-convertible v6.
+ * @return the sockaddr_in structure, can be 0 if v6.
+ * @see addressV4()
+ */
+ operator const sockaddr_in*() const
+ { return addressV4(); }
+
+ /**
+ * Returns the socket address.
+ * @return the sockaddr_in structure, can be 0 if v6 is unsupported.
+ * @see addressV6()
+ */
+ operator const sockaddr_in6*() const
+ { return addressV6(); }
+
+ /**
+ * Sets this object to be the same as the other.
+ */
+ KInetSocketAddress& operator=(const KInetSocketAddress &other)
+ { setAddress(other); return *this; }
+
+private:
+
+ void fromV4();
+ void fromV6();
+
+public:
+ /**
+ * Convert s the given raw address into text form.
+ * This function returns QString::null if the address cannot be converted.
+ * @param family the family of the address
+ * @param addr the address, in raw form
+ * @return the converted address, or QString::null if not possible.
+ */
+ static QString addrToString(int family, const void *addr);
+
+ /**
+ * Converts the address given in text form into raw form.
+ * The size of the destination buffer @p dest is supposed to be
+ * large enough to hold the address of the given family.
+ * @param family the family of the address
+ * @param text the text representation of the address
+ * @param dest the destination buffer of the address
+ * @return true if convertion was successful.
+ */
+ static bool stringToAddr(int family, const char *text, void *dest);
+
+ friend class KExtendedSocket;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KInetSocketAddressPrivate* d;
+};
+
+extern const ::KInetSocketAddress addressAny, addressLoopback;
+
+/*
+ * External definition KUnixSocketAddress
+ */
+struct sockaddr_un;
+
+class KUnixSocketAddressPrivate;
+/**
+ * A Unix socket address
+ *
+ * This is a Unix socket address.
+ *
+ * This class expects QCString instead of QString values, which means the
+ * filenames should be encoded in whatever form locale/system deems necessary
+ * before passing down to the function
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ * @short a Unix socket address
+ */
+class KDECORE_EXPORT KUnixSocketAddress: public ::KSocketAddress
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ KUnixSocketAddress();
+
+ /**
+ * Constructor from raw data.
+ * @param raw_data raw data
+ * @param size data length
+ */
+ KUnixSocketAddress(const sockaddr_un* raw_data, ksocklen_t size);
+
+ /**
+ * Constructor from pathname.
+ * @param pathname pathname
+ */
+ KUnixSocketAddress(QCString pathname);
+
+ /**
+ * Destructor
+ */
+ virtual ~KUnixSocketAddress();
+
+ /**
+ * Sets this to given sockaddr_un.
+ * @param socket_address socket address
+ * @param size the socket length
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(const sockaddr_un* socket_address, ksocklen_t size);
+
+ /**
+ * Sets this to given pathname.
+ * @param path pathname
+ * @return true if successful, false otherwise
+ */
+ bool setAddress(QCString path);
+
+ /**
+ * Returns the pathname.
+ * @return the pathname, can be QCString::null if uninitialized, or
+ * "" if unknown
+ */
+ QCString pathname() const;
+
+ /**
+ * Returns pretty representation of this socket.
+ * @return a pretty text representation of the socket.
+ */
+ virtual QString pretty() const;
+
+ /*
+ * Returns the path in the form of a QString.
+ * This can be fed into KExtendedSocket.
+ * @return the path (can be QString::null).
+ * @see pathname()
+ */
+ virtual QString serviceName() const;
+
+ /**
+ * Returns raw socket address.
+ * @return the raw socket address (can be 0 if uninitialized)
+ */
+ const sockaddr_un* address() const;
+
+ /**
+ * Returns raw socket address.
+ * @return the raw socket address (can be 0 if uninitialized)
+ * @see address()
+ */
+ operator const sockaddr_un*() const
+ { return address(); }
+
+ /**
+ * Compares two unix socket addresses.
+ * @param s1 the first address to compare
+ * @param s2 the second address to compare
+ * @param coreOnly true if only core parts should be compared (currently
+ * unused)
+ * @return true if the given addresses are equal.
+ * @see KSocketAddress::isEqual()
+ * @see KSocketAddress::isCoreEqual()
+ */
+ static bool areEqualUnix(const KSocketAddress &s1, const KSocketAddress &s2, bool coreOnly);
+
+private:
+ void init();
+
+ friend class KExtendedSocket;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KUnixSocketAddressPrivate* d;
+};
+
+#endif // KSOCKADDR_H
diff --git a/kdecore/ksocks.cpp b/kdecore/ksocks.cpp
new file mode 100644
index 000000000..be9331548
--- /dev/null
+++ b/kdecore/ksocks.cpp
@@ -0,0 +1,600 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001-2003 George Staikos <staikos@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <qfile.h>
+#include <qstring.h>
+#include <qmap.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include "klibloader.h"
+#include <kconfig.h>
+#include <kapplication.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <unistd.h>
+
+#include "ksocks.h"
+
+// DO NOT RE-ORDER THESE.
+enum SymbolKeys {
+ S_SOCKSinit = 0,
+ S_connect = 1,
+ S_read = 2,
+ S_write = 3,
+ S_recvfrom = 4,
+ S_sendto = 5,
+ S_recv = 6,
+ S_send = 7,
+ S_getsockname = 8,
+ S_getpeername = 9,
+ S_accept = 10,
+ S_select = 11,
+ S_listen = 12,
+ S_bind = 13
+ };
+
+
+extern "C" {
+// Function pointer table
+static int (*F_SOCKSinit) (char *) = 0L;
+static int (*F_connect) (int, const struct sockaddr *, ksocklen_t) = 0L;
+static signed long int (*F_read) (int, void *, unsigned long int) = 0L;
+static signed long int (*F_write) (int, const void *, unsigned long int) = 0L;
+static int (*F_recvfrom) (int, void *, unsigned long int, int, struct sockaddr *,
+ ksocklen_t *) = 0L;
+static int (*F_sendto) (int, const void *, unsigned long int, int,
+ const struct sockaddr *, ksocklen_t) = 0L;
+static int (*F_recv) (int, void *, unsigned long int, int) = 0L;
+static int (*F_send) (int, const void *, unsigned long int, int) = 0L;
+static int (*F_getsockname) (int, struct sockaddr *, ksocklen_t *) = 0L;
+static int (*F_getpeername) (int, struct sockaddr *, ksocklen_t *) = 0L;
+static int (*F_accept) (int, struct sockaddr *, ksocklen_t *) = 0L;
+static int (*F_select) (int, fd_set *, fd_set *, fd_set *,
+ struct timeval *) = 0L;
+static int (*F_listen) (int, int) = 0L;
+static int (*F_bind) (int, const struct sockaddr *, ksocklen_t) = 0L;
+}
+
+
+class KSocksTable {
+ public:
+ KSocksTable();
+ virtual ~KSocksTable();
+
+ // The name of each symbol and it's SOCKS replacement
+ QMap<SymbolKeys,QString> symbols;
+ // The name of this library
+ QString myname;
+ bool hasWorkingAsyncConnect;
+};
+
+
+KSocksTable::KSocksTable() : myname("Unknown"), hasWorkingAsyncConnect(true) {
+}
+
+KSocksTable::~KSocksTable() {
+}
+
+
+/*
+ * How to add support for a new SOCKS package.
+ *
+ * 1) Subclass KSocksTable as is done below and write out all the symbols
+ * 1.b) Give the class a "myname"
+ * 2) Make sure that all possible library names are written into the
+ * _libNames string list. Don't forget that different OSes name shared
+ * libraries differently. Expect .so, .sl, .a (!) (AIX does this).
+ * 3) Find a unique symbol in the library that we can use to identify that
+ * library and write out the test case in the constructor
+ * 4) Make necessary changes to the KControl module in kdebase/kcontrol/....
+ * 5) TEST!
+ *
+ */
+
+//////////////////////////////////////////////////////////////////
+/////// Define each library symbol table here ///////
+//////////////////////////////////////////////////////////////////
+
+
+//
+// Support for NEC SOCKS client
+//
+
+class KNECSocksTable : public KSocksTable {
+ public:
+ KNECSocksTable();
+ virtual ~KNECSocksTable();
+};
+
+
+KNECSocksTable::KNECSocksTable() : KSocksTable() {
+ myname = i18n("NEC SOCKS client");
+ symbols.insert(S_SOCKSinit, "SOCKSinit");
+ symbols.insert(S_connect, "connect");
+ symbols.insert(S_read, "read");
+ symbols.insert(S_write, "write");
+ symbols.insert(S_recvfrom, "recvfrom");
+ symbols.insert(S_sendto, "sendto");
+ symbols.insert(S_recv, "recv");
+ symbols.insert(S_send, "send");
+ symbols.insert(S_getsockname, "getsockname");
+ symbols.insert(S_getpeername, "getpeername");
+ symbols.insert(S_accept, "accept");
+ symbols.insert(S_select, "select");
+ symbols.insert(S_listen, "listen");
+ symbols.insert(S_bind, "bind");
+}
+
+KNECSocksTable::~KNECSocksTable() {
+}
+
+
+
+
+//
+// Support for Dante SOCKS client
+//
+
+class KDanteSocksTable : public KSocksTable {
+ public:
+ KDanteSocksTable();
+ virtual ~KDanteSocksTable();
+};
+
+KDanteSocksTable::KDanteSocksTable() : KSocksTable() {
+ hasWorkingAsyncConnect = false;
+ myname = i18n("Dante SOCKS client");
+ symbols.insert(S_SOCKSinit, "SOCKSinit");
+ symbols.insert(S_connect, "Rconnect");
+ symbols.insert(S_read, "Rread");
+ symbols.insert(S_write, "Rwrite");
+ symbols.insert(S_recvfrom, "Rrecvfrom");
+ symbols.insert(S_sendto, "Rsendto");
+ symbols.insert(S_recv, "Rrecv");
+ symbols.insert(S_send, "Rsend");
+ symbols.insert(S_getsockname, "Rgetsockname");
+ symbols.insert(S_getpeername, "Rgetpeername");
+ symbols.insert(S_accept, "Raccept");
+ symbols.insert(S_select, "Rselect");
+ symbols.insert(S_listen, "Rlisten");
+ symbols.insert(S_bind, "Rbind");
+}
+
+
+KDanteSocksTable::~KDanteSocksTable() {
+}
+
+
+
+//////////////////////////////////////////////////////////////////
+/////// End of all symbol table definitions ///////
+//////////////////////////////////////////////////////////////////
+
+
+KSocks *KSocks::_me = 0;
+#ifdef __CYGWIN__
+bool KSocks::_disabled = true;
+#else
+bool KSocks::_disabled = false;
+#endif
+static KStaticDeleter<KSocks> med;
+
+void KSocks::disable()
+{
+ if (!_me)
+ _disabled = true;
+}
+
+KSocks *KSocks::self() {
+ // Note that we don't use a static deleter here. It makes no sense and tends to cause crashes.
+ if (!_me) {
+ if (kapp) {
+ KConfigGroup cfg(kapp->config(), "Socks");
+ _me = new KSocks(&cfg);
+ } else {
+ _disabled = true;
+ _me = new KSocks(0);
+ }
+ }
+ return _me;
+}
+
+void KSocks::setConfig(KConfigBase *config)
+{
+ // We can change the config from disabled to enabled
+ // but not the other way around.
+ if (_me && _disabled) {
+ delete _me;
+ _me = 0;
+ _disabled = false;
+ }
+ if (!_me)
+ _me = new KSocks(config);
+}
+
+bool KSocks::activated() { return (_me != 0L); }
+
+
+KSocks::KSocks(KConfigBase *config) : _socksLib(0L), _st(0L) {
+ _hasSocks = false;
+ _useSocks = false;
+
+ if (!config)
+ return;
+
+ if (!(config->readBoolEntry("SOCKS_enable", false))) {
+ _disabled = true;
+ }
+
+ if (_disabled)
+ return;
+
+ _libPaths << ""
+ << "/usr/lib" KDELIBSUFF "/"
+ << "/usr/lib/"
+ << "/usr/local/lib" KDELIBSUFF "/"
+ << "/usr/local/lib/"
+ << "/usr/local/socks5/lib" KDELIBSUFF "/"
+ << "/usr/local/socks5/lib/"
+ << "/opt/socks5/lib" KDELIBSUFF "/"
+ << "/opt/socks5/lib/";
+ _libNames << "libsocks.so" // Dante
+ << "libdsocksd.so.0" // Dante 1.1.14-2 on
+ // Debian unstable 17-12-2003
+ << "libsocks5.so" // ?
+ << "libsocks5_sh.so"; // NEC
+
+ // Add the custom library paths here
+ QStringList newlibs = config->readListEntry("SOCKS_lib_path");
+
+ for (QStringList::Iterator it = newlibs.begin();
+ it != newlibs.end();
+ ++it) {
+ QString thisone = *it;
+ if (thisone[thisone.length()-1] != '/') thisone += "/";
+ _libPaths << thisone;
+ kdDebug(171) << "KSocks added a new library path: " << thisone << endl;
+ }
+
+ // Load the proper libsocks and KSocksTable
+ KLibLoader *ll = KLibLoader::self();
+
+
+ int _meth = config->readNumEntry("SOCKS_method", 1);
+ /**** Current methods
+ * 1) Autodetect (read: any) 2) NEC
+ * 3) Dante 4) Custom
+ */
+
+ if (_meth == 4) { // try to load^H^H^H^Hguess at a custom library
+ _socksLib = ll->library(config->readPathEntry("SOCKS_lib").latin1());
+ if (_socksLib && _socksLib->symbol("Rconnect")) { // Dante compatible?
+ _st = new KDanteSocksTable;
+ _useSocks = true;
+ _hasSocks = true;
+ } else if (_socksLib && _socksLib->symbol("connect")) { // NEC compatible?
+ _st = new KNECSocksTable;
+ _useSocks = true;
+ _hasSocks = true;
+ } else if (_socksLib) {
+ _socksLib->unload();
+ _socksLib = 0L;
+ }
+ } else // leave this here "else for {}"
+ for (QStringList::Iterator pit = _libPaths.begin();
+ !_hasSocks && pit != _libPaths.end();
+ ++pit)
+ for (QStringList::Iterator it = _libNames.begin();
+ it != _libNames.end();
+ ++it) {
+ _socksLib = ll->library((*pit + *it).latin1());
+ if (_socksLib) {
+ if ((_meth == 1 || _meth == 2) &&
+ _socksLib->symbol("S5LogShowThreadIDS") != 0L) { // NEC SOCKS
+ kdDebug(171) << "Found NEC SOCKS" << endl;
+ _st = new KNECSocksTable;
+ _useSocks = true;
+ _hasSocks = true;
+ break;
+ } else if ((_meth == 1 || _meth == 3) &&
+ _socksLib->symbol("sockaddr2ruleaddress") != 0L) { //Dante
+ kdDebug(171) << "Found Dante SOCKS" << endl;
+ _st = new KDanteSocksTable;
+ _useSocks = true;
+ _hasSocks = true;
+ break;
+ } else {
+ _socksLib->unload();
+ _socksLib = 0L;
+ }
+ }
+ }
+
+ // Load in all the symbols
+ if (_st) {
+ for (QMap<SymbolKeys,QString>::Iterator it = _st->symbols.begin();
+ it != _st->symbols.end();
+ ++it) {
+ switch(it.key()) {
+ case S_SOCKSinit:
+ F_SOCKSinit = (int (*)(char *))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_connect:
+ F_connect = (int (*)(int, const struct sockaddr *, ksocklen_t))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_read:
+ F_read = (signed long int (*)(int, void *, unsigned long int))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_write:
+ F_write = (signed long int (*)(int, const void *, unsigned long int))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_recvfrom:
+ F_recvfrom = (int (*)(int, void *, unsigned long int, int,
+ struct sockaddr *, ksocklen_t *))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_sendto:
+ F_sendto = (int (*)(int, const void *, unsigned long int, int,
+ const struct sockaddr *, ksocklen_t))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_recv:
+ F_recv = (int (*)(int, void *, unsigned long int, int))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_send:
+ F_send = (int (*)(int, const void *, unsigned long int, int))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_getsockname:
+ F_getsockname = (int (*)(int, struct sockaddr *, ksocklen_t *))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_getpeername:
+ F_getpeername = (int (*)(int, struct sockaddr *, ksocklen_t *))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_accept:
+ F_accept = (int (*)(int, struct sockaddr *, ksocklen_t *))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_select:
+ F_select = (int (*)(int, fd_set *, fd_set *, fd_set *, struct timeval *))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_listen:
+ F_listen = (int (*)(int, int))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ case S_bind:
+ F_bind = (int (*)(int, const struct sockaddr *, ksocklen_t))
+ _socksLib->symbol(it.data().latin1());
+ break;
+ default:
+ kdDebug(171) << "KSocks got a symbol it doesn't know about!" << endl;
+ break;
+ }
+ }
+
+ // Now we check for the critical stuff.
+ if (F_SOCKSinit) {
+ int rc = (*F_SOCKSinit)((char *)"KDE");
+ if (rc != 0)
+ stopSocks();
+ else kdDebug(171) << "SOCKS has been activated!" << endl;
+ } else {
+ stopSocks();
+ }
+ }
+}
+
+
+KSocks::~KSocks() {
+ stopSocks();
+ _me = 0;
+}
+
+void KSocks::die() {
+ if (_me == this) {
+ _me = 0;
+ delete this;
+ }
+}
+
+void KSocks::stopSocks() {
+ if (_hasSocks) {
+ // This library doesn't even provide the basics.
+ // It's probably broken. Let's abort.
+ _useSocks = false;
+ _hasSocks = false;
+ if (_socksLib) {
+ _socksLib->unload();
+ _socksLib = 0L;
+ }
+ delete _st;
+ _st = 0L;
+ }
+}
+
+
+bool KSocks::usingSocks() {
+ return _useSocks;
+}
+
+
+bool KSocks::hasSocks() {
+ return _hasSocks;
+}
+
+
+void KSocks::disableSocks() {
+ _useSocks = false;
+}
+
+
+void KSocks::enableSocks() {
+ if (_hasSocks)
+ _useSocks = true;
+}
+
+bool KSocks::hasWorkingAsyncConnect()
+{
+ return (_useSocks && _st) ? _st->hasWorkingAsyncConnect : true;
+}
+
+
+/*
+ * REIMPLEMENTED FUNCTIONS FROM LIBC
+ *
+ */
+
+int KSocks::connect (int sockfd, const sockaddr *serv_addr,
+ ksocklen_t addrlen) {
+ if (_useSocks && F_connect)
+ return (*F_connect)(sockfd, serv_addr, addrlen);
+ else return ::connect(sockfd, (sockaddr*) serv_addr, (socklen_t)addrlen);
+}
+
+
+signed long int KSocks::read (int fd, void *buf, unsigned long int count) {
+ if (_useSocks && F_read)
+ return (*F_read)(fd, buf, count);
+ else return ::read(fd, buf, count);
+}
+
+
+signed long int KSocks::write (int fd, const void *buf, unsigned long int count) {
+ if (_useSocks && F_write)
+ return (*F_write)(fd, buf, count);
+ else return ::write(fd, buf, count);
+}
+
+
+int KSocks::recvfrom (int s, void *buf, unsigned long int len, int flags,
+ sockaddr *from, ksocklen_t *fromlen) {
+ if (_useSocks && F_recvfrom) {
+ return (*F_recvfrom)(s, buf, len, flags, from, fromlen);
+ } else {
+ socklen_t casted_len = (socklen_t) *fromlen;
+ int rc = ::recvfrom(s, (char*) buf, len, flags, from, &casted_len);
+ *fromlen = casted_len;
+ return rc;
+ }
+}
+
+
+int KSocks::sendto (int s, const void *msg, unsigned long int len, int flags,
+ const sockaddr *to, ksocklen_t tolen) {
+ if (_useSocks && F_sendto)
+ return (*F_sendto)(s, msg, len, flags, to, tolen);
+ else return ::sendto(s, (char*) msg, len, flags, to, (socklen_t)tolen);
+}
+
+
+int KSocks::recv (int s, void *buf, unsigned long int len, int flags) {
+ if (_useSocks && F_recv)
+ return (*F_recv)(s, buf, len, flags);
+ else return ::recv(s, (char*) buf, len, flags);
+}
+
+
+int KSocks::send (int s, const void *msg, unsigned long int len, int flags) {
+ if (_useSocks && F_send)
+ return (*F_send)(s, msg, len, flags);
+ else return ::send(s, (char*) msg, len, flags);
+}
+
+
+int KSocks::getsockname (int s, sockaddr *name, ksocklen_t *namelen) {
+ if (_useSocks && F_getsockname) {
+ return (*F_getsockname)(s, name, namelen);
+ } else {
+ socklen_t casted_len = *namelen;
+ int rc = ::getsockname(s, name, &casted_len);
+ *namelen = casted_len;
+ return rc;
+ }
+}
+
+
+int KSocks::getpeername (int s, sockaddr *name, ksocklen_t *namelen) {
+ if (_useSocks && F_getpeername) {
+ return (*F_getpeername)(s, name, namelen);
+ } else {
+ socklen_t casted_len = *namelen;
+ int rc = ::getpeername(s, name, &casted_len);
+ *namelen = casted_len;
+ return rc;
+ }
+}
+
+
+int KSocks::accept (int s, sockaddr *addr, ksocklen_t *addrlen) {
+ if (_useSocks && F_accept) {
+ return (*F_accept)(s, addr, addrlen);
+ } else {
+ socklen_t casted_len = *addrlen;
+ int rc = ::accept(s, addr, &casted_len);
+ *addrlen = casted_len;
+ return rc;
+ }
+}
+
+
+int KSocks::select (int n, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout) {
+ if (_useSocks && F_select)
+ return (*F_select)(n, readfds, writefds, exceptfds, timeout);
+ else return ::select(n, readfds, writefds, exceptfds, timeout);
+}
+
+
+int KSocks::listen (int s, int backlog) {
+ if (_useSocks && F_listen)
+ return (*F_listen)(s, backlog);
+ else return ::listen(s, backlog);
+}
+
+
+int KSocks::bind (int sockfd, const sockaddr *my_addr, ksocklen_t addrlen) {
+ if (_useSocks && F_bind)
+ return (*F_bind)(sockfd, my_addr, addrlen);
+ else return ::bind(sockfd, my_addr, (socklen_t)addrlen);
+}
+
+int KSocks::bind (int sockfd, sockaddr *my_addr, ksocklen_t addrlen) {
+ if (_useSocks && F_bind)
+ return (*F_bind)(sockfd, my_addr, addrlen);
+ else return ::bind(sockfd, my_addr, (socklen_t)addrlen);
+}
+
+
+
diff --git a/kdecore/ksocks.h b/kdecore/ksocks.h
new file mode 100644
index 000000000..04fb4f79a
--- /dev/null
+++ b/kdecore/ksocks.h
@@ -0,0 +1,210 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 George Staikos <staikos@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KSOCKS_H_
+#define _KSOCKS_H_
+
+#include <qstringlist.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <kstaticdeleter.h>
+#include <kdelibs_export.h>
+
+#ifdef Q_OS_UNIX
+
+class KSocksTable;
+class KSocksPrivate;
+class KLibrary;
+class KConfigBase;
+struct sockaddr;
+
+typedef unsigned ksocklen_t;
+
+
+/**
+ * This class provides you with an interface to a
+ * <a href="http://www.socks.nec.com/">SOCKS</a> Proxy server. A SOCKS server
+ * is able to provide full internet access behind a firewall.
+ * KSocks is a singleton; there can only be one instance at any
+ * given time. To obtain a reference to that instance, use
+ * self().
+ *
+ * @short Access to a SOCKS Proxy.
+ */
+class KDECORE_EXPORT KSocks {
+ friend class KStaticDeleter<KSocks>;
+
+public:
+
+ /**
+ * Return an instance of class KSocks *.
+ * You cannot delete this object. It is a singleton class.
+ * @return the KSock instance
+ */
+ static KSocks *self();
+
+ /**
+ * Checks whether KSocks has been started (ie someone called self())
+ * @return true if activated
+ */
+ static bool activated();
+
+ /**
+ * Disable the use of SOCKS immediately
+ */
+ void disableSocks();
+
+ /**
+ * Enable the use of SOCKS immediately if hasSocks() is true.
+ */
+ void enableSocks();
+
+ /**
+ * Checks whether SOCKS is currently being used.
+ * @return true if SOCKS is currently being used.
+ */
+ bool usingSocks();
+
+ /**
+ * Checks whether SOCKS is available for use.
+ * @return true if SOCKS is available for use.
+ */
+ bool hasSocks();
+
+ /**
+ * Returns whether asynchronous connects work with the
+ * selected SOCKS impementation
+ */
+ bool hasWorkingAsyncConnect();
+
+ /*
+ ** REIMPLEMENTATIONS OF LIBC SOCKET FUNCTIONS
+ **/
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int connect (int sockfd, const sockaddr *serv_addr,
+ ksocklen_t addrlen);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ signed long int read (int fd, void *buf, unsigned long int count);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ signed long int write (int fd, const void *buf, unsigned long int count);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int recvfrom (int s, void *buf, unsigned long int len, int flags,
+ sockaddr *from, ksocklen_t *fromlen);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int sendto (int s, const void *msg, unsigned long int len, int flags,
+ const sockaddr *to, ksocklen_t tolen);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int recv (int s, void *buf, unsigned long int len, int flags);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int send (int s, const void *msg, unsigned long int len, int flags);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int getsockname (int s, sockaddr *name, ksocklen_t *namelen);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int getpeername (int s, sockaddr *name, ksocklen_t *namelen);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int accept (int s, sockaddr *addr, ksocklen_t *addrlen);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int select (int n, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout);
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int listen (int s, int backlog);
+
+ /**
+ * This is the re-implementation of libc's function of the same
+ * name. Read the appropriate man page.
+ */
+ int bind (int sockfd, sockaddr *my_addr,
+ ksocklen_t addrlen);
+ int bind (int sockfd, const sockaddr *my_addr,
+ ksocklen_t addrlen);
+
+ /**
+ * If you're using this, you're probably doing something wrong.
+ * Please don't use it.
+ * @internal
+ */
+ void die();
+
+ /**
+ * Set this before the first call to KSocks::self() and it will fail
+ * to initialize SOCKS.
+ */
+ static void disable();
+
+ /**
+ * Set this before the first call to KSocks::self() and it will use
+ * @p config to read its configuration from.
+ */
+ static void setConfig(KConfigBase *config);
+
+private:
+ KSocks(KConfigBase *config);
+ ~KSocks();
+
+ void stopSocks();
+
+ static KSocks *_me;
+ static bool _disabled;
+ QStringList _libNames;
+ QStringList _libPaths;
+ bool _useSocks, _hasSocks;
+ KLibrary* _socksLib;
+
+
+ KSocksTable *_st;
+ KSocksPrivate *d;
+};
+
+#endif //Q_OS_UNIX
+
+#endif //_KSOCKS_H_
diff --git a/kdecore/ksortablevaluelist.h b/kdecore/ksortablevaluelist.h
new file mode 100644
index 000000000..e83bdf4ab
--- /dev/null
+++ b/kdecore/ksortablevaluelist.h
@@ -0,0 +1,171 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSORTABLEVALUELIST_H
+#define KSORTABLEVALUELIST_H
+
+#include <qpair.h>
+#include <qvaluelist.h>
+#include "kdelibs_export.h"
+
+/**
+ * KSortableItem is a QPair that provides several operators
+ * for sorting.
+ * @see KSortableValueList
+ */
+template<class T, class Key = int> class KSortableItem : public QPair<Key,T>
+{
+public:
+ /**
+ * Creates a new KSortableItem with the given values.
+ * @param i the first value
+ * @param t the second value
+ */
+ KSortableItem( Key i, const T& t ) : QPair<Key, T>( i, t ) {}
+ /**
+ * Creates a new KSortableItem that copies another one.
+ * @param rhs the other item to copy
+ */
+ KSortableItem( const KSortableItem<T, Key> &rhs )
+ : QPair<Key,T>( rhs.first, rhs.second ) {}
+
+ /**
+ * Creates a new KSortableItem with uninitialized values.
+ */
+ KSortableItem() {}
+
+ /**
+ * Assignment operator, just copies the item.
+ */
+ KSortableItem<T, Key> &operator=( const KSortableItem<T, Key>& i ) {
+ this->first = i.first;
+ this->second = i.second;
+ return *this;
+ }
+
+ // operators for sorting
+ /**
+ * Compares the two items. This implementation only compares
+ * the first value.
+ */
+ bool operator> ( const KSortableItem<T, Key>& i2 ) const {
+ return (i2.first < this->first);
+ }
+ /**
+ * Compares the two items. This implementation only compares
+ * the first value.
+ */
+ bool operator< ( const KSortableItem<T, Key>& i2 ) const {
+ return (this->first < i2.first);
+ }
+ /**
+ * Compares the two items. This implementation only compares
+ * the first value.
+ */
+ bool operator>= ( const KSortableItem<T, Key>& i2 ) const {
+ return (this->first >= i2.first);
+ }
+ /**
+ * Compares the two items. This implementation only compares
+ * the first value.
+ */
+ bool operator<= ( const KSortableItem<T, Key>& i2 ) const {
+ return !(i2.first < this->first);
+ }
+ /**
+ * Compares the two items. This implementation only compares
+ * the first value.
+ */
+ bool operator== ( const KSortableItem<T, Key>& i2 ) const {
+ return (this->first == i2.first);
+ }
+ /**
+ * Compares the two items. This implementation only compares
+ * the first value.
+ */
+ bool operator!= ( const KSortableItem<T, Key>& i2 ) const {
+ return (this->first != i2.first);
+ }
+
+ /**
+ * @return the second value
+ */
+ T& value() { return this->second; }
+
+ /**
+ * Returns the second value.
+ */
+ const T& value() const { return this->second; }
+
+ /**
+ * @return the first value.
+ */
+ Key index() const { return this->first; }
+};
+
+
+/**
+ * KSortableValueList is a special QValueList for
+ * KSortableItem. It includes convenience operators
+ * to get the first value of the KSortableItem and a method
+ * to sort all items.
+ */
+template <class T, class Key = int>
+class KSortableValueList : public QValueList<KSortableItem<T, Key> >
+{
+public:
+ /**
+ * Insert a KSortableItem with the given values.
+ * @param i the first value
+ * @param t the second value
+ */
+ void insert( Key i, const T& t ) {
+ QValueList<KSortableItem<T, Key> >::append( KSortableItem<T, Key>( i, t ) );
+ }
+ // add more as you please...
+
+ /**
+ * Returns the first value of the KSortableItem at the given position.
+ * @return the first value of the KSortableItem
+ */
+ T& operator[]( Key i ) {
+ return QValueList<KSortableItem<T, Key> >::operator[]( i ).value();
+ }
+
+ /**
+ * Returns the first value of the KSortableItem at the given position.
+ * @return the first value of the KSortableItem
+ */
+ const T& operator[]( Key i ) const {
+ return QValueList<KSortableItem<T, Key> >::operator[]( i ).value();
+ }
+
+ /**
+ * Sorts the KSortableItems.
+ */
+ void sort() {
+ qHeapSort( *this );
+ }
+};
+
+// template <class T> class KSortableValueListIterator : public QValueListIterator<KSortableItem<T> >
+// {
+// };
+
+#endif // KSORTABLEVALUELIST_H
diff --git a/kdecore/kstandarddirs.cpp b/kdecore/kstandarddirs.cpp
new file mode 100644
index 000000000..015590c2d
--- /dev/null
+++ b/kdecore/kstandarddirs.cpp
@@ -0,0 +1,1682 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
+ Copyright (C) 1999 Stephan Kulow <coolo@kde.org>
+ Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ * Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
+ * Version: $Id$
+ * Generated: Thu Mar 5 16:05:28 EST 1998
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <qregexp.h>
+#include <qasciidict.h>
+#include <qdict.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "kstandarddirs.h"
+#include "kconfig.h"
+#include "kdebug.h"
+#include "kinstance.h"
+#include "kshell.h"
+#include "ksimpleconfig.h"
+#include "kuser.h"
+#include "kstaticdeleter.h"
+#include <kde_file.h>
+
+template class QDict<QStringList>;
+
+class KStandardDirs::KStandardDirsPrivate
+{
+public:
+ KStandardDirsPrivate()
+ : restrictionsActive(false),
+ dataRestrictionActive(false),
+ checkRestrictions(true)
+ { }
+
+ bool restrictionsActive;
+ bool dataRestrictionActive;
+ bool checkRestrictions;
+ QAsciiDict<bool> restrictions;
+ QStringList xdgdata_prefixes;
+ QStringList xdgconf_prefixes;
+};
+
+// Singleton, with data shared by all kstandarddirs instances.
+// Used in static methods like findExe()
+class KStandardDirsSingleton
+{
+public:
+ QString defaultprefix;
+ QString defaultbindir;
+ static KStandardDirsSingleton* self();
+private:
+ static KStandardDirsSingleton* s_self;
+};
+static KStaticDeleter<KStandardDirsSingleton> kstds_sd;
+KStandardDirsSingleton* KStandardDirsSingleton::s_self = 0;
+KStandardDirsSingleton* KStandardDirsSingleton::self() {
+ if ( !s_self )
+ kstds_sd.setObject( s_self, new KStandardDirsSingleton );
+ return s_self;
+}
+
+static const char* const types[] = {"html", "icon", "apps", "sound",
+ "data", "locale", "services", "mime",
+ "servicetypes", "config", "exe",
+ "wallpaper", "lib", "pixmap", "templates",
+ "module", "qtplugins",
+ "xdgdata-apps", "xdgdata-dirs", "xdgconf-menu",
+ "xdgdata-icon", "xdgdata-pixmap",
+ "kcfg", "emoticons", 0 };
+
+static int tokenize( QStringList& token, const QString& str,
+ const QString& delim );
+
+KStandardDirs::KStandardDirs( ) : addedCustoms(false)
+{
+ d = new KStandardDirsPrivate;
+ dircache.setAutoDelete(true);
+ relatives.setAutoDelete(true);
+ absolutes.setAutoDelete(true);
+ savelocations.setAutoDelete(true);
+ addKDEDefaults();
+}
+
+KStandardDirs::~KStandardDirs()
+{
+ delete d;
+}
+
+bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
+{
+ if (!d || !d->restrictionsActive)
+ return false;
+
+ if (d->restrictions[type])
+ return true;
+
+ if (strcmp(type, "data")==0)
+ {
+ applyDataRestrictions(relPath);
+ if (d->dataRestrictionActive)
+ {
+ d->dataRestrictionActive = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+void KStandardDirs::applyDataRestrictions(const QString &relPath) const
+{
+ QString key;
+ int i = relPath.find('/');
+ if (i != -1)
+ key = "data_"+relPath.left(i);
+ else
+ key = "data_"+relPath;
+
+ if (d && d->restrictions[key.latin1()])
+ d->dataRestrictionActive = true;
+}
+
+
+QStringList KStandardDirs::allTypes() const
+{
+ QStringList list;
+ for (int i = 0; types[i] != 0; ++i)
+ list.append(QString::fromLatin1(types[i]));
+ return list;
+}
+
+static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
+{
+ if (priority && !prefixes.isEmpty())
+ {
+ // Add in front but behind $KDEHOME
+ QStringList::iterator it = prefixes.begin();
+ it++;
+ prefixes.insert(it, 1, dir);
+ }
+ else
+ {
+ prefixes.append(dir);
+ }
+}
+
+void KStandardDirs::addPrefix( const QString& _dir )
+{
+ addPrefix(_dir, false);
+}
+
+void KStandardDirs::addPrefix( const QString& _dir, bool priority )
+{
+ if (_dir.isEmpty())
+ return;
+
+ QString dir = _dir;
+ if (dir.at(dir.length() - 1) != '/')
+ dir += '/';
+
+ if (!prefixes.contains(dir)) {
+ priorityAdd(prefixes, dir, priority);
+ dircache.clear();
+ }
+}
+
+void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
+{
+ addXdgConfigPrefix(_dir, false);
+}
+
+void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
+{
+ if (_dir.isEmpty())
+ return;
+
+ QString dir = _dir;
+ if (dir.at(dir.length() - 1) != '/')
+ dir += '/';
+
+ if (!d->xdgconf_prefixes.contains(dir)) {
+ priorityAdd(d->xdgconf_prefixes, dir, priority);
+ dircache.clear();
+ }
+}
+
+void KStandardDirs::addXdgDataPrefix( const QString& _dir )
+{
+ addXdgDataPrefix(_dir, false);
+}
+
+void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
+{
+ if (_dir.isEmpty())
+ return;
+
+ QString dir = _dir;
+ if (dir.at(dir.length() - 1) != '/')
+ dir += '/';
+
+ if (!d->xdgdata_prefixes.contains(dir)) {
+ priorityAdd(d->xdgdata_prefixes, dir, priority);
+ dircache.clear();
+ }
+}
+
+QString KStandardDirs::kfsstnd_prefixes()
+{
+ return prefixes.join(QChar(KPATH_SEPARATOR));
+}
+
+QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
+{
+ return d->xdgconf_prefixes.join(QChar(KPATH_SEPARATOR));
+}
+
+QString KStandardDirs::kfsstnd_xdg_data_prefixes()
+{
+ return d->xdgdata_prefixes.join(QChar(KPATH_SEPARATOR));
+}
+
+bool KStandardDirs::addResourceType( const char *type,
+ const QString& relativename )
+{
+ return addResourceType(type, relativename, true);
+}
+bool KStandardDirs::addResourceType( const char *type,
+ const QString& relativename,
+ bool priority )
+{
+ if (relativename.isEmpty())
+ return false;
+
+ QStringList *rels = relatives.find(type);
+ if (!rels) {
+ rels = new QStringList();
+ relatives.insert(type, rels);
+ }
+ QString copy = relativename;
+ if (copy.at(copy.length() - 1) != '/')
+ copy += '/';
+ if (!rels->contains(copy)) {
+ if (priority)
+ rels->prepend(copy);
+ else
+ rels->append(copy);
+ dircache.remove(type); // clean the cache
+ return true;
+ }
+ return false;
+}
+
+bool KStandardDirs::addResourceDir( const char *type,
+ const QString& absdir)
+{
+ // KDE4: change priority to bring in line with addResourceType
+ return addResourceDir(type, absdir, false);
+}
+
+bool KStandardDirs::addResourceDir( const char *type,
+ const QString& absdir,
+ bool priority)
+{
+ QStringList *paths = absolutes.find(type);
+ if (!paths) {
+ paths = new QStringList();
+ absolutes.insert(type, paths);
+ }
+ QString copy = absdir;
+ if (copy.at(copy.length() - 1) != '/')
+ copy += '/';
+
+ if (!paths->contains(copy)) {
+ if (priority)
+ paths->prepend(copy);
+ else
+ paths->append(copy);
+ dircache.remove(type); // clean the cache
+ return true;
+ }
+ return false;
+}
+
+QString KStandardDirs::findResource( const char *type,
+ const QString& filename ) const
+{
+ if (!QDir::isRelativePath(filename))
+ return filename; // absolute dirs are absolute dirs, right? :-/
+
+#if 0
+kdDebug() << "Find resource: " << type << endl;
+for (QStringList::ConstIterator pit = prefixes.begin();
+ pit != prefixes.end();
+ pit++)
+{
+ kdDebug() << "Prefix: " << *pit << endl;
+}
+#endif
+
+ QString dir = findResourceDir(type, filename);
+ if (dir.isEmpty())
+ return dir;
+ else return dir + filename;
+}
+
+static Q_UINT32 updateHash(const QString &file, Q_UINT32 hash)
+{
+ QCString cFile = QFile::encodeName(file);
+ KDE_struct_stat buff;
+ if ((access(cFile, R_OK) == 0) &&
+ (KDE_stat( cFile, &buff ) == 0) &&
+ (S_ISREG( buff.st_mode )))
+ {
+ hash = hash + (Q_UINT32) buff.st_ctime;
+ }
+ return hash;
+}
+
+Q_UINT32 KStandardDirs::calcResourceHash( const char *type,
+ const QString& filename, bool deep) const
+{
+ Q_UINT32 hash = 0;
+
+ if (!QDir::isRelativePath(filename))
+ {
+ // absolute dirs are absolute dirs, right? :-/
+ return updateHash(filename, hash);
+ }
+ if (d && d->restrictionsActive && (strcmp(type, "data")==0))
+ applyDataRestrictions(filename);
+ QStringList candidates = resourceDirs(type);
+ QString fullPath;
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it)
+ {
+ hash = updateHash(*it + filename, hash);
+ if (!deep && hash)
+ return hash;
+ }
+ return hash;
+}
+
+
+QStringList KStandardDirs::findDirs( const char *type,
+ const QString& reldir ) const
+{
+ QDir testdir;
+ QStringList list;
+ if (!QDir::isRelativePath(reldir))
+ {
+ testdir.setPath(reldir);
+ if (testdir.exists())
+ {
+ if (reldir.endsWith("/"))
+ list.append(reldir);
+ else
+ list.append(reldir+'/');
+ }
+ return list;
+ }
+
+ checkConfig();
+
+ if (d && d->restrictionsActive && (strcmp(type, "data")==0))
+ applyDataRestrictions(reldir);
+ QStringList candidates = resourceDirs(type);
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it) {
+ testdir.setPath(*it + reldir);
+ if (testdir.exists())
+ list.append(testdir.absPath() + '/');
+ }
+
+ return list;
+}
+
+QString KStandardDirs::findResourceDir( const char *type,
+ const QString& filename) const
+{
+#ifndef NDEBUG
+ if (filename.isEmpty()) {
+ kdWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!" << endl;
+ return QString::null;
+ }
+#endif
+
+ if (d && d->restrictionsActive && (strcmp(type, "data")==0))
+ applyDataRestrictions(filename);
+ QStringList candidates = resourceDirs(type);
+ QString fullPath;
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it) {
+ if (exists(*it + filename)) {
+#ifdef Q_WS_WIN //this ensures we're using installed .la files
+ if ((*it).isEmpty() && filename.right(3)==".la") {
+#ifndef NDEBUG
+ kdDebug() << "KStandardDirs::findResourceDir() found .la in cwd: skipping. (fname=" << filename << ")" << endl;
+#endif
+ continue;
+ }
+#endif //Q_WS_WIN
+ return *it;
+ }
+ }
+
+#ifndef NDEBUG
+ if(false && strcmp(type, "locale"))
+ kdDebug() << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\"." << endl;
+#endif
+
+ return QString::null;
+}
+
+bool KStandardDirs::exists(const QString &fullPath)
+{
+ KDE_struct_stat buff;
+ if (access(QFile::encodeName(fullPath), R_OK) == 0 && KDE_stat( QFile::encodeName(fullPath), &buff ) == 0)
+ if (fullPath.at(fullPath.length() - 1) != '/') {
+ if (S_ISREG( buff.st_mode ))
+ return true;
+ } else
+ if (S_ISDIR( buff.st_mode ))
+ return true;
+ return false;
+}
+
+static void lookupDirectory(const QString& path, const QString &relPart,
+ const QRegExp &regexp,
+ QStringList& list,
+ QStringList& relList,
+ bool recursive, bool unique)
+{
+ QString pattern = regexp.pattern();
+ if (recursive || pattern.contains('?') || pattern.contains('*'))
+ {
+ if (path.isEmpty()) //for sanity
+ return;
+ // We look for a set of files.
+ DIR *dp = opendir( QFile::encodeName(path));
+ if (!dp)
+ return;
+
+#ifdef Q_WS_WIN
+ assert(path.at(path.length() - 1) == '/' || path.at(path.length() - 1) == '\\');
+#else
+ assert(path.at(path.length() - 1) == '/');
+#endif
+
+ struct dirent *ep;
+ KDE_struct_stat buff;
+
+ QString _dot(".");
+ QString _dotdot("..");
+
+ while( ( ep = readdir( dp ) ) != 0L )
+ {
+ QString fn( QFile::decodeName(ep->d_name));
+ if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() == '~')
+ continue;
+
+ if (!recursive && !regexp.exactMatch(fn))
+ continue; // No match
+
+ QString pathfn = path + fn;
+ if ( KDE_stat( QFile::encodeName(pathfn), &buff ) != 0 ) {
+ kdDebug() << "Error stat'ing " << pathfn << " : " << perror << endl;
+ continue; // Couldn't stat (e.g. no read permissions)
+ }
+ if ( recursive ) {
+ if ( S_ISDIR( buff.st_mode )) {
+ lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, unique);
+ }
+ if (!regexp.exactMatch(fn))
+ continue; // No match
+ }
+ if ( S_ISREG( buff.st_mode))
+ {
+ if (!unique || !relList.contains(relPart + fn))
+ {
+ list.append( pathfn );
+ relList.append( relPart + fn );
+ }
+ }
+ }
+ closedir( dp );
+ }
+ else
+ {
+ // We look for a single file.
+ QString fn = pattern;
+ QString pathfn = path + fn;
+ KDE_struct_stat buff;
+ if ( KDE_stat( QFile::encodeName(pathfn), &buff ) != 0 )
+ return; // File not found
+ if ( S_ISREG( buff.st_mode))
+ {
+ if (!unique || !relList.contains(relPart + fn))
+ {
+ list.append( pathfn );
+ relList.append( relPart + fn );
+ }
+ }
+ }
+}
+
+static void lookupPrefix(const QString& prefix, const QString& relpath,
+ const QString& relPart,
+ const QRegExp &regexp,
+ QStringList& list,
+ QStringList& relList,
+ bool recursive, bool unique)
+{
+ if (relpath.isEmpty()) {
+ lookupDirectory(prefix, relPart, regexp, list,
+ relList, recursive, unique);
+ return;
+ }
+ QString path;
+ QString rest;
+
+ if (relpath.length())
+ {
+ int slash = relpath.find('/');
+ if (slash < 0)
+ rest = relpath.left(relpath.length() - 1);
+ else {
+ path = relpath.left(slash);
+ rest = relpath.mid(slash + 1);
+ }
+ }
+
+ if (prefix.isEmpty()) //for sanity
+ return;
+#ifdef Q_WS_WIN
+ assert(prefix.at(prefix.length() - 1) == '/' || prefix.at(prefix.length() - 1) == '\\');
+#else
+ assert(prefix.at(prefix.length() - 1) == '/');
+#endif
+ KDE_struct_stat buff;
+
+ if (path.contains('*') || path.contains('?')) {
+
+ QRegExp pathExp(path, true, true);
+ DIR *dp = opendir( QFile::encodeName(prefix) );
+ if (!dp) {
+ return;
+ }
+
+ struct dirent *ep;
+
+ QString _dot(".");
+ QString _dotdot("..");
+
+ while( ( ep = readdir( dp ) ) != 0L )
+ {
+ QString fn( QFile::decodeName(ep->d_name));
+ if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1) == '~')
+ continue;
+
+ if ( !pathExp.exactMatch(fn) )
+ continue; // No match
+ QString rfn = relPart+fn;
+ fn = prefix + fn;
+ if ( KDE_stat( QFile::encodeName(fn), &buff ) != 0 ) {
+ kdDebug() << "Error statting " << fn << " : " << perror << endl;
+ continue; // Couldn't stat (e.g. no permissions)
+ }
+ if ( S_ISDIR( buff.st_mode ))
+ lookupPrefix(fn + '/', rest, rfn + '/', regexp, list, relList, recursive, unique);
+ }
+
+ closedir( dp );
+ } else {
+ // Don't stat, if the dir doesn't exist we will find out
+ // when we try to open it.
+ lookupPrefix(prefix + path + '/', rest,
+ relPart + path + '/', regexp, list,
+ relList, recursive, unique);
+ }
+}
+
+QStringList
+KStandardDirs::findAllResources( const char *type,
+ const QString& filter,
+ bool recursive,
+ bool unique,
+ QStringList &relList) const
+{
+ QStringList list;
+ QString filterPath;
+ QString filterFile;
+
+ if (filter.length())
+ {
+ int slash = filter.findRev('/');
+ if (slash < 0)
+ filterFile = filter;
+ else {
+ filterPath = filter.left(slash + 1);
+ filterFile = filter.mid(slash + 1);
+ }
+ }
+
+ checkConfig();
+
+ QStringList candidates;
+ if (!QDir::isRelativePath(filter)) // absolute path
+ {
+#ifdef Q_OS_WIN
+ candidates << filterPath.left(3); //e.g. "C:\"
+ filterPath = filterPath.mid(3);
+#else
+ candidates << "/";
+ filterPath = filterPath.mid(1);
+#endif
+ }
+ else
+ {
+ if (d && d->restrictionsActive && (strcmp(type, "data")==0))
+ applyDataRestrictions(filter);
+ candidates = resourceDirs(type);
+ }
+ if (filterFile.isEmpty())
+ filterFile = "*";
+
+ QRegExp regExp(filterFile, true, true);
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it)
+ {
+ lookupPrefix(*it, filterPath, "", regExp, list,
+ relList, recursive, unique);
+ }
+
+ return list;
+}
+
+QStringList
+KStandardDirs::findAllResources( const char *type,
+ const QString& filter,
+ bool recursive,
+ bool unique) const
+{
+ QStringList relList;
+ return findAllResources(type, filter, recursive, unique, relList);
+}
+
+QString
+KStandardDirs::realPath(const QString &dirname)
+{
+ char realpath_buffer[MAXPATHLEN + 1];
+ memset(realpath_buffer, 0, MAXPATHLEN + 1);
+
+ /* If the path contains symlinks, get the real name */
+ if (realpath( QFile::encodeName(dirname).data(), realpath_buffer) != 0) {
+ // success, use result from realpath
+ int len = strlen(realpath_buffer);
+ realpath_buffer[len] = '/';
+ realpath_buffer[len+1] = 0;
+ return QFile::decodeName(realpath_buffer);
+ }
+
+ return dirname;
+}
+
+QString
+KStandardDirs::realFilePath(const QString &filename)
+{
+ char realpath_buffer[MAXPATHLEN + 1];
+ memset(realpath_buffer, 0, MAXPATHLEN + 1);
+
+ /* If the path contains symlinks, get the real name */
+ if (realpath( QFile::encodeName(filename).data(), realpath_buffer) != 0) {
+ // success, use result from realpath
+ return QFile::decodeName(realpath_buffer);
+ }
+
+ return filename;
+}
+
+void KStandardDirs::createSpecialResource(const char *type)
+{
+ char hostname[256];
+ hostname[0] = 0;
+ gethostname(hostname, 255);
+ QString dir = QString("%1%2-%3").arg(localkdedir()).arg(type).arg(hostname);
+ char link[1024];
+ link[1023] = 0;
+ int result = readlink(QFile::encodeName(dir).data(), link, 1023);
+ bool relink = (result == -1) && (errno == ENOENT);
+ if (result > 0)
+ {
+ link[result] = 0;
+ if (!QDir::isRelativePath(link))
+ {
+ KDE_struct_stat stat_buf;
+ int res = KDE_lstat(link, &stat_buf);
+ if ((res == -1) && (errno == ENOENT))
+ {
+ relink = true;
+ }
+ else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
+ {
+ fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
+ relink = true;
+ }
+ else if (stat_buf.st_uid != getuid())
+ {
+ fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
+ relink = true;
+ }
+ }
+ }
+#ifdef Q_WS_WIN
+ if (relink)
+ {
+ if (!makeDir(dir, 0700))
+ fprintf(stderr, "failed to create \"%s\"", dir.latin1());
+ else
+ result = readlink(QFile::encodeName(dir).data(), link, 1023);
+ }
+#else //UNIX
+ if (relink)
+ {
+ QString srv = findExe(QString::fromLatin1("lnusertemp"), kfsstnd_defaultbindir());
+ if (srv.isEmpty())
+ srv = findExe(QString::fromLatin1("lnusertemp"));
+ if (!srv.isEmpty())
+ {
+ system(QFile::encodeName(srv)+" "+type);
+ result = readlink(QFile::encodeName(dir).data(), link, 1023);
+ }
+ }
+ if (result > 0)
+ {
+ link[result] = 0;
+ if (link[0] == '/')
+ dir = QFile::decodeName(link);
+ else
+ dir = QDir::cleanDirPath(dir+QFile::decodeName(link));
+ }
+#endif
+ addResourceDir(type, dir+'/');
+}
+
+QStringList KStandardDirs::resourceDirs(const char *type) const
+{
+ QStringList *candidates = dircache.find(type);
+
+ if (!candidates) { // filling cache
+ if (strcmp(type, "socket") == 0)
+ const_cast<KStandardDirs *>(this)->createSpecialResource(type);
+ else if (strcmp(type, "tmp") == 0)
+ const_cast<KStandardDirs *>(this)->createSpecialResource(type);
+ else if (strcmp(type, "cache") == 0)
+ const_cast<KStandardDirs *>(this)->createSpecialResource(type);
+
+ QDir testdir;
+
+ candidates = new QStringList();
+ QStringList *dirs;
+
+ bool restrictionActive = false;
+ if (d && d->restrictionsActive)
+ {
+ if (d->dataRestrictionActive)
+ restrictionActive = true;
+ else if (d->restrictions["all"])
+ restrictionActive = true;
+ else if (d->restrictions[type])
+ restrictionActive = true;
+ d->dataRestrictionActive = false; // Reset
+ }
+
+ dirs = relatives.find(type);
+ if (dirs)
+ {
+ bool local = true;
+ const QStringList *prefixList = 0;
+ if (strncmp(type, "xdgdata-", 8) == 0)
+ prefixList = &(d->xdgdata_prefixes);
+ else if (strncmp(type, "xdgconf-", 8) == 0)
+ prefixList = &(d->xdgconf_prefixes);
+ else
+ prefixList = &prefixes;
+
+ for (QStringList::ConstIterator pit = prefixList->begin();
+ pit != prefixList->end();
+ ++pit)
+ {
+ for (QStringList::ConstIterator it = dirs->begin();
+ it != dirs->end(); ++it) {
+ QString path = realPath(*pit + *it);
+ testdir.setPath(path);
+ if (local && restrictionActive)
+ continue;
+ if ((local || testdir.exists()) && !candidates->contains(path))
+ candidates->append(path);
+ }
+ local = false;
+ }
+ }
+ dirs = absolutes.find(type);
+ if (dirs)
+ for (QStringList::ConstIterator it = dirs->begin();
+ it != dirs->end(); ++it)
+ {
+ testdir.setPath(*it);
+ if (testdir.exists())
+ {
+ QString filename = realPath(*it);
+ if (!candidates->contains(filename))
+ candidates->append(filename);
+ }
+ }
+ dircache.insert(type, candidates);
+ }
+
+#if 0
+ kdDebug() << "found dirs for resource " << type << ":" << endl;
+ for (QStringList::ConstIterator pit = candidates->begin();
+ pit != candidates->end();
+ pit++)
+ {
+ fprintf(stderr, "%s\n", (*pit).latin1());
+ }
+#endif
+
+
+ return *candidates;
+}
+
+QStringList KStandardDirs::systemPaths( const QString& pstr )
+{
+ QStringList tokens;
+ QString p = pstr;
+
+ if( p.isNull() )
+ {
+ p = getenv( "PATH" );
+ }
+
+ QString delimiters(QChar(KPATH_SEPARATOR));
+ delimiters += "\b";
+ tokenize( tokens, p, delimiters );
+
+ QStringList exePaths;
+
+ // split path using : or \b as delimiters
+ for( unsigned i = 0; i < tokens.count(); i++ )
+ {
+ p = tokens[ i ];
+
+ if ( p[ 0 ] == '~' )
+ {
+ int len = p.find( '/' );
+ if ( len == -1 )
+ len = p.length();
+ if ( len == 1 )
+ {
+ p.replace( 0, 1, QDir::homeDirPath() );
+ }
+ else
+ {
+ QString user = p.mid( 1, len - 1 );
+ struct passwd *dir = getpwnam( user.local8Bit().data() );
+ if ( dir && strlen( dir->pw_dir ) )
+ p.replace( 0, len, QString::fromLocal8Bit( dir->pw_dir ) );
+ }
+ }
+
+ exePaths << p;
+ }
+
+ return exePaths;
+}
+
+
+QString KStandardDirs::findExe( const QString& appname,
+ const QString& pstr, bool ignore)
+{
+#ifdef Q_WS_WIN
+ QString real_appname = appname + ".exe";
+#else
+ QString real_appname = appname;
+#endif
+ QFileInfo info;
+
+ // absolute or relative path given
+ if (real_appname.find(QDir::separator()) >= 0)
+ {
+ info.setFile( real_appname );
+ if( info.exists() && ( ignore || info.isExecutable() )
+ && info.isFile() ) {
+ return info.absFilePath();
+ }
+ return QString::null;
+ }
+
+ QString p = QString("%1/%2").arg(kfsstnd_defaultbindir()).arg(real_appname);
+ info.setFile( p );
+ if( info.exists() && ( ignore || info.isExecutable() )
+ && ( info.isFile() || info.isSymLink() ) ) {
+ return p;
+ }
+
+ QStringList exePaths = systemPaths( pstr );
+ for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
+ {
+ p = (*it) + "/";
+ p += real_appname;
+
+ // Check for executable in this tokenized path
+ info.setFile( p );
+
+ if( info.exists() && ( ignore || info.isExecutable() )
+ && ( info.isFile() || info.isSymLink() ) ) {
+ return p;
+ }
+ }
+
+ // If we reach here, the executable wasn't found.
+ // So return empty string.
+
+ return QString::null;
+}
+
+int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
+ const QString& pstr, bool ignore )
+{
+#ifdef Q_WS_WIN
+ QString real_appname = appname + ".exe";
+#else
+ QString real_appname = appname;
+#endif
+ QFileInfo info;
+ QString p;
+ list.clear();
+
+ QStringList exePaths = systemPaths( pstr );
+ for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
+ {
+ p = (*it) + "/";
+ p += real_appname;
+
+ info.setFile( p );
+
+ if( info.exists() && (ignore || info.isExecutable())
+ && info.isFile() ) {
+ list.append( p );
+ }
+ }
+
+ return list.count();
+}
+
+static int tokenize( QStringList& tokens, const QString& str,
+ const QString& delim )
+{
+ int len = str.length();
+ QString token = "";
+
+ for( int index = 0; index < len; index++)
+ {
+ if ( delim.find( str[ index ] ) >= 0 )
+ {
+ tokens.append( token );
+ token = "";
+ }
+ else
+ {
+ token += str[ index ];
+ }
+ }
+ if ( token.length() > 0 )
+ {
+ tokens.append( token );
+ }
+
+ return tokens.count();
+}
+
+QString KStandardDirs::kde_default(const char *type) {
+ if (!strcmp(type, "data"))
+ return "share/apps/";
+ if (!strcmp(type, "html"))
+ return "share/doc/HTML/";
+ if (!strcmp(type, "icon"))
+ return "share/icons/";
+ if (!strcmp(type, "config"))
+ return "share/config/";
+ if (!strcmp(type, "pixmap"))
+ return "share/pixmaps/";
+ if (!strcmp(type, "apps"))
+ return "share/applnk/";
+ if (!strcmp(type, "sound"))
+ return "share/sounds/";
+ if (!strcmp(type, "locale"))
+ return "share/locale/";
+ if (!strcmp(type, "services"))
+ return "share/services/";
+ if (!strcmp(type, "servicetypes"))
+ return "share/servicetypes/";
+ if (!strcmp(type, "mime"))
+ return "share/mimelnk/";
+ if (!strcmp(type, "cgi"))
+ return "cgi-bin/";
+ if (!strcmp(type, "wallpaper"))
+ return "share/wallpapers/";
+ if (!strcmp(type, "templates"))
+ return "share/templates/";
+ if (!strcmp(type, "exe"))
+ return "bin/";
+ if (!strcmp(type, "lib"))
+ return "lib" KDELIBSUFF "/";
+ if (!strcmp(type, "module"))
+ return "lib" KDELIBSUFF "/kde3/";
+ if (!strcmp(type, "qtplugins"))
+ return "lib" KDELIBSUFF "/kde3/plugins";
+ if (!strcmp(type, "xdgdata-apps"))
+ return "applications/";
+ if (!strcmp(type, "xdgdata-icon"))
+ return "icons/";
+ if (!strcmp(type, "xdgdata-pixmap"))
+ return "pixmaps/";
+ if (!strcmp(type, "xdgdata-dirs"))
+ return "desktop-directories/";
+ if (!strcmp(type, "xdgconf-menu"))
+ return "menus/";
+ if (!strcmp(type, "kcfg"))
+ return "share/config.kcfg";
+ if (!strcmp(type, "emoticons"))
+ return "share/emoticons";
+
+
+ qFatal("unknown resource type %s", type);
+ return QString::null;
+}
+
+QString KStandardDirs::saveLocation(const char *type,
+ const QString& suffix,
+ bool create) const
+{
+ checkConfig();
+
+ QString *pPath = savelocations.find(type);
+ if (!pPath)
+ {
+ QStringList *dirs = relatives.find(type);
+ if (!dirs && (
+ (strcmp(type, "socket") == 0) ||
+ (strcmp(type, "tmp") == 0) ||
+ (strcmp(type, "cache") == 0) ))
+ {
+ (void) resourceDirs(type); // Generate socket|tmp|cache resource.
+ dirs = relatives.find(type); // Search again.
+ }
+ if (dirs)
+ {
+ // Check for existence of typed directory + suffix
+ if (strncmp(type, "xdgdata-", 8) == 0)
+ pPath = new QString(realPath(localxdgdatadir() + dirs->last()));
+ else if (strncmp(type, "xdgconf-", 8) == 0)
+ pPath = new QString(realPath(localxdgconfdir() + dirs->last()));
+ else
+ pPath = new QString(realPath(localkdedir() + dirs->last()));
+ }
+ else {
+ dirs = absolutes.find(type);
+ if (!dirs)
+ qFatal("KStandardDirs: The resource type %s is not registered", type);
+ pPath = new QString(realPath(dirs->last()));
+ }
+
+ savelocations.insert(type, pPath);
+ }
+ QString fullPath = *pPath + (pPath->endsWith("/") ? "" : "/") + suffix;
+
+ KDE_struct_stat st;
+ if (KDE_stat(QFile::encodeName(fullPath), &st) != 0 || !(S_ISDIR(st.st_mode))) {
+ if(!create) {
+#ifndef NDEBUG
+ kdDebug() << QString("save location %1 doesn't exist").arg(fullPath) << endl;
+#endif
+ return fullPath;
+ }
+ if(!makeDir(fullPath, 0700)) {
+ return fullPath;
+ }
+ dircache.remove(type);
+ }
+ if (!fullPath.endsWith("/"))
+ fullPath += "/";
+ return fullPath;
+}
+
+QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
+{
+ QString fullPath = absPath;
+ int i = absPath.findRev('/');
+ if (i != -1)
+ {
+ fullPath = realPath(absPath.left(i+1))+absPath.mid(i+1); // Normalize
+ }
+
+ QStringList candidates = resourceDirs(type);
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it)
+ if (fullPath.startsWith(*it))
+ {
+ return fullPath.mid((*it).length());
+ }
+
+ return absPath;
+}
+
+
+bool KStandardDirs::makeDir(const QString& dir, int mode)
+{
+ // we want an absolute path
+ if (QDir::isRelativePath(dir))
+ return false;
+
+ QString target = dir;
+ uint len = target.length();
+
+ // append trailing slash if missing
+ if (dir.at(len - 1) != '/')
+ target += '/';
+
+ QString base("");
+ uint i = 1;
+
+ while( i < len )
+ {
+ KDE_struct_stat st;
+ int pos = target.find('/', i);
+ base += target.mid(i - 1, pos - i + 1);
+ QCString baseEncoded = QFile::encodeName(base);
+ // bail out if we encountered a problem
+ if (KDE_stat(baseEncoded, &st) != 0)
+ {
+ // Directory does not exist....
+ // Or maybe a dangling symlink ?
+ if (KDE_lstat(baseEncoded, &st) == 0)
+ (void)unlink(baseEncoded); // try removing
+
+ if ( KDE_mkdir(baseEncoded, (mode_t) mode) != 0) {
+ baseEncoded.prepend( "trying to create local folder " );
+ perror(baseEncoded.data());
+ return false; // Couldn't create it :-(
+ }
+ }
+ i = pos + 1;
+ }
+ return true;
+}
+
+static QString readEnvPath(const char *env)
+{
+ QCString c_path = getenv(env);
+ if (c_path.isEmpty())
+ return QString::null;
+#ifdef Q_OS_WIN
+ //win32 paths are case-insensitive: avoid duplicates on various dir lists
+ return QFile::decodeName(c_path).lower();
+#else
+ return QFile::decodeName(c_path);
+#endif
+}
+
+#ifdef __linux__
+static QString executablePrefix()
+{
+ char path_buffer[MAXPATHLEN + 1];
+ path_buffer[MAXPATHLEN] = 0;
+ int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
+ if (length == -1)
+ return QString::null;
+
+ path_buffer[length] = '\0';
+
+ QString path = QFile::decodeName(path_buffer);
+
+ if(path.isEmpty())
+ return QString::null;
+
+ int pos = path.findRev('/'); // Skip filename
+ if(pos <= 0)
+ return QString::null;
+ pos = path.findRev('/', pos - 1); // Skip last directory
+ if(pos <= 0)
+ return QString::null;
+
+ return path.left(pos);
+}
+#endif
+
+QString KStandardDirs::kfsstnd_defaultprefix()
+{
+ KStandardDirsSingleton* s = KStandardDirsSingleton::self();
+ if (!s->defaultprefix.isEmpty())
+ return s->defaultprefix;
+#ifdef Q_WS_WIN
+ s->defaultprefix = readEnvPath("KDEDIR");
+ if (s->defaultprefix.isEmpty()) {
+ s->defaultprefix = QFile::decodeName("c:\\kde");
+ //TODO: find other location (the Registry?)
+ }
+#else //UNIX
+ s->defaultprefix = KDEDIR;
+#endif
+ if (s->defaultprefix.isEmpty())
+ kdWarning() << "KStandardDirs::kfsstnd_defaultprefix(): default KDE prefix not found!" << endl;
+ return s->defaultprefix;
+}
+
+QString KStandardDirs::kfsstnd_defaultbindir()
+{
+ KStandardDirsSingleton* s = KStandardDirsSingleton::self();
+ if (!s->defaultbindir.isEmpty())
+ return s->defaultbindir;
+#ifdef Q_WS_WIN
+ s->defaultbindir = kfsstnd_defaultprefix() + QString::fromLatin1("/bin");
+#else //UNIX
+ s->defaultbindir = __KDE_BINDIR;
+ if (s->defaultbindir.isEmpty())
+ s->defaultbindir = kfsstnd_defaultprefix() + QString::fromLatin1("/bin");
+#endif
+ if (s->defaultbindir.isEmpty())
+ kdWarning() << "KStandardDirs::kfsstnd_defaultbindir(): default binary KDE dir not found!" << endl;
+ return s->defaultbindir;
+}
+
+void KStandardDirs::addKDEDefaults()
+{
+ QStringList kdedirList;
+
+ // begin KDEDIRS
+ QString kdedirs = readEnvPath("KDEDIRS");
+ if (!kdedirs.isEmpty())
+ {
+ tokenize(kdedirList, kdedirs, QChar(KPATH_SEPARATOR));
+ }
+ else
+ {
+ QString kdedir = readEnvPath("KDEDIR");
+ if (!kdedir.isEmpty())
+ {
+ kdedir = KShell::tildeExpand(kdedir);
+ kdedirList.append(kdedir);
+ }
+ }
+
+#ifndef Q_OS_WIN //no default KDEDIR on win32 defined
+ kdedirList.append(KDEDIR);
+#endif
+
+#ifdef __KDE_EXECPREFIX
+ QString execPrefix(__KDE_EXECPREFIX);
+ if (execPrefix!="NONE")
+ kdedirList.append(execPrefix);
+#endif
+#ifdef __linux__
+ const QString linuxExecPrefix = executablePrefix();
+ if ( !linuxExecPrefix.isEmpty() )
+ kdedirList.append( linuxExecPrefix );
+#endif
+
+ // We treat root differently to prevent a "su" shell messing up the
+ // file permissions in the user's home directory.
+ QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
+ if (!localKdeDir.isEmpty())
+ {
+ if (localKdeDir[localKdeDir.length()-1] != '/')
+ localKdeDir += '/';
+ }
+ else
+ {
+ localKdeDir = QDir::homeDirPath() + "/.kde/";
+ }
+
+ if (localKdeDir != "-/")
+ {
+ localKdeDir = KShell::tildeExpand(localKdeDir);
+ addPrefix(localKdeDir);
+ }
+
+ QStringList::ConstIterator end(kdedirList.end());
+ for (QStringList::ConstIterator it = kdedirList.begin();
+ it != end; ++it)
+ {
+ QString dir = KShell::tildeExpand(*it);
+ addPrefix(dir);
+ }
+ // end KDEDIRS
+
+ // begin XDG_CONFIG_XXX
+ QStringList xdgdirList;
+ QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
+ if (!xdgdirs.isEmpty())
+ {
+ tokenize(xdgdirList, xdgdirs, QChar(KPATH_SEPARATOR));
+ }
+ else
+ {
+ xdgdirList.clear();
+ xdgdirList.append("/etc/xdg");
+#ifdef Q_WS_WIN
+ xdgdirList.append(kfsstnd_defaultprefix() + "/etc/xdg");
+#else
+ xdgdirList.append(KDESYSCONFDIR "/xdg");
+#endif
+ }
+
+ QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
+ if (!localXdgDir.isEmpty())
+ {
+ if (localXdgDir[localXdgDir.length()-1] != '/')
+ localXdgDir += '/';
+ }
+ else
+ {
+ localXdgDir = QDir::homeDirPath() + "/.config/";
+ }
+
+ localXdgDir = KShell::tildeExpand(localXdgDir);
+ addXdgConfigPrefix(localXdgDir);
+
+ for (QStringList::ConstIterator it = xdgdirList.begin();
+ it != xdgdirList.end(); ++it)
+ {
+ QString dir = KShell::tildeExpand(*it);
+ addXdgConfigPrefix(dir);
+ }
+ // end XDG_CONFIG_XXX
+
+ // begin XDG_DATA_XXX
+ xdgdirs = readEnvPath("XDG_DATA_DIRS");
+ if (!xdgdirs.isEmpty())
+ {
+ tokenize(xdgdirList, xdgdirs, QChar(KPATH_SEPARATOR));
+ }
+ else
+ {
+ xdgdirList.clear();
+ for (QStringList::ConstIterator it = kdedirList.begin();
+ it != kdedirList.end(); ++it)
+ {
+ QString dir = *it;
+ if (dir[dir.length()-1] != '/')
+ dir += '/';
+ xdgdirList.append(dir+"share/");
+ }
+
+ xdgdirList.append("/usr/local/share/");
+ xdgdirList.append("/usr/share/");
+ }
+
+ localXdgDir = readEnvPath("XDG_DATA_HOME");
+ if (!localXdgDir.isEmpty())
+ {
+ if (localXdgDir[localXdgDir.length()-1] != '/')
+ localXdgDir += '/';
+ }
+ else
+ {
+ localXdgDir = QDir::homeDirPath() + "/.local/share/";
+ }
+
+ localXdgDir = KShell::tildeExpand(localXdgDir);
+ addXdgDataPrefix(localXdgDir);
+
+ for (QStringList::ConstIterator it = xdgdirList.begin();
+ it != xdgdirList.end(); ++it)
+ {
+ QString dir = KShell::tildeExpand(*it);
+ addXdgDataPrefix(dir);
+ }
+ // end XDG_DATA_XXX
+
+
+ uint index = 0;
+ while (types[index] != 0) {
+ addResourceType(types[index], kde_default(types[index]));
+ index++;
+ }
+
+ addResourceDir("home", QDir::homeDirPath());
+}
+
+void KStandardDirs::checkConfig() const
+{
+ if (!addedCustoms && KGlobal::_instance && KGlobal::_instance->_config)
+ const_cast<KStandardDirs*>(this)->addCustomized(KGlobal::_instance->_config);
+}
+
+static QStringList lookupProfiles(const QString &mapFile)
+{
+ QStringList profiles;
+
+ if (mapFile.isEmpty() || !QFile::exists(mapFile))
+ {
+ profiles << "default";
+ return profiles;
+ }
+
+ struct passwd *pw = getpwuid(geteuid());
+ if (!pw)
+ {
+ profiles << "default";
+ return profiles; // Not good
+ }
+
+ QCString user = pw->pw_name;
+
+ gid_t sup_gids[512];
+ int sup_gids_nr = getgroups(512, sup_gids);
+
+ KSimpleConfig mapCfg(mapFile, true);
+ mapCfg.setGroup("Users");
+ if (mapCfg.hasKey(user.data()))
+ {
+ profiles = mapCfg.readListEntry(user.data());
+ return profiles;
+ }
+
+ mapCfg.setGroup("General");
+ QStringList groups = mapCfg.readListEntry("groups");
+
+ mapCfg.setGroup("Groups");
+
+ for( QStringList::ConstIterator it = groups.begin();
+ it != groups.end(); ++it )
+ {
+ QCString grp = (*it).utf8();
+ // Check if user is in this group
+ struct group *grp_ent = getgrnam(grp);
+ if (!grp_ent) continue;
+ gid_t gid = grp_ent->gr_gid;
+ if (pw->pw_gid == gid)
+ {
+ // User is in this group --> add profiles
+ profiles += mapCfg.readListEntry(*it);
+ }
+ else
+ {
+ for(int i = 0; i < sup_gids_nr; i++)
+ {
+ if (sup_gids[i] == gid)
+ {
+ // User is in this group --> add profiles
+ profiles += mapCfg.readListEntry(*it);
+ break;
+ }
+ }
+ }
+ }
+
+ if (profiles.isEmpty())
+ profiles << "default";
+ return profiles;
+}
+
+extern bool kde_kiosk_admin;
+
+bool KStandardDirs::addCustomized(KConfig *config)
+{
+ if (addedCustoms && !d->checkRestrictions) // there are already customized entries
+ return false; // we just quit and hope they are the right ones
+
+ // save the numbers of config directories. If this changes,
+ // we will return true to give KConfig a chance to reparse
+ uint configdirs = resourceDirs("config").count();
+
+ // Remember original group
+ QString oldGroup = config->group();
+
+ if (!addedCustoms)
+ {
+ // We only add custom entries once
+ addedCustoms = true;
+
+ // reading the prefixes in
+ QString group = QString::fromLatin1("Directories");
+ config->setGroup(group);
+
+ QString kioskAdmin = config->readEntry("kioskAdmin");
+ if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
+ {
+ int i = kioskAdmin.find(':');
+ QString user = kioskAdmin.left(i);
+ QString host = kioskAdmin.mid(i+1);
+
+ KUser thisUser;
+ char hostname[ 256 ];
+ hostname[ 0 ] = '\0';
+ if (!gethostname( hostname, 255 ))
+ hostname[sizeof(hostname)-1] = '\0';
+
+ if ((user == thisUser.loginName()) &&
+ (host.isEmpty() || (host == hostname)))
+ {
+ kde_kiosk_admin = true;
+ }
+ }
+
+ bool readProfiles = true;
+
+ if (kde_kiosk_admin && !QCString(getenv("KDE_KIOSK_NO_PROFILES")).isEmpty())
+ readProfiles = false;
+
+ QString userMapFile = config->readEntry("userProfileMapFile");
+ QString profileDirsPrefix = config->readEntry("profileDirsPrefix");
+ if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith("/"))
+ profileDirsPrefix.append('/');
+
+ QStringList profiles;
+ if (readProfiles)
+ profiles = lookupProfiles(userMapFile);
+ QString profile;
+
+ bool priority = false;
+ while(true)
+ {
+ config->setGroup(group);
+ QStringList list = config->readListEntry("prefixes");
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ {
+ addPrefix(*it, priority);
+ addXdgConfigPrefix(*it+"/etc/xdg", priority);
+ addXdgDataPrefix(*it+"/share", priority);
+ }
+ // If there are no prefixes defined, check if there is a directory
+ // for this profile under <profileDirsPrefix>
+ if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
+ {
+ QString dir = profileDirsPrefix + profile;
+ addPrefix(dir, priority);
+ addXdgConfigPrefix(dir+"/etc/xdg", priority);
+ addXdgDataPrefix(dir+"/share", priority);
+ }
+
+ // iterating over all entries in the group Directories
+ // to find entries that start with dir_$type
+ QMap<QString, QString> entries = config->entryMap(group);
+ for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
+ it2 != entries.end(); it2++)
+ {
+ QString key = it2.key();
+ if (key.startsWith("dir_")) {
+ // generate directory list, there may be more than 1.
+ QStringList dirs = QStringList::split(',', *it2);
+ QStringList::Iterator sIt(dirs.begin());
+ QString resType = key.mid(4, key.length());
+ for (; sIt != dirs.end(); ++sIt)
+ {
+ addResourceDir(resType.latin1(), *sIt, priority);
+ }
+ }
+ }
+ if (profiles.isEmpty())
+ break;
+ profile = profiles.back();
+ group = QString::fromLatin1("Directories-%1").arg(profile);
+ profiles.pop_back();
+ priority = true;
+ }
+ }
+
+ // Process KIOSK restrictions.
+ if (!kde_kiosk_admin || QCString(getenv("KDE_KIOSK_NO_RESTRICTIONS")).isEmpty())
+ {
+ config->setGroup("KDE Resource Restrictions");
+ QMap<QString, QString> entries = config->entryMap("KDE Resource Restrictions");
+ for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
+ it2 != entries.end(); it2++)
+ {
+ QString key = it2.key();
+ if (!config->readBoolEntry(key, true))
+ {
+ d->restrictionsActive = true;
+ d->restrictions.insert(key.latin1(), &d->restrictionsActive); // Anything will do
+ dircache.remove(key.latin1());
+ }
+ }
+ }
+
+ config->setGroup(oldGroup);
+
+ // check if the number of config dirs changed
+ bool configDirsChanged = (resourceDirs("config").count() != configdirs);
+ // If the config dirs changed, we check kiosk restrictions again.
+ d->checkRestrictions = configDirsChanged;
+ // return true if the number of config dirs changed: reparse config file
+ return configDirsChanged;
+}
+
+QString KStandardDirs::localkdedir() const
+{
+ // Return the prefix to use for saving
+ return prefixes.first();
+}
+
+QString KStandardDirs::localxdgdatadir() const
+{
+ // Return the prefix to use for saving
+ return d->xdgdata_prefixes.first();
+}
+
+QString KStandardDirs::localxdgconfdir() const
+{
+ // Return the prefix to use for saving
+ return d->xdgconf_prefixes.first();
+}
+
+
+// just to make code more readable without macros
+QString locate( const char *type,
+ const QString& filename, const KInstance* inst )
+{
+ return inst->dirs()->findResource(type, filename);
+}
+
+QString locateLocal( const char *type,
+ const QString& filename, const KInstance* inst )
+{
+ return locateLocal(type, filename, true, inst);
+}
+
+QString locateLocal( const char *type,
+ const QString& filename, bool createDir, const KInstance* inst )
+{
+ // try to find slashes. If there are some, we have to
+ // create the subdir first
+ int slash = filename.findRev('/')+1;
+ if (!slash) // only one filename
+ return inst->dirs()->saveLocation(type, QString::null, createDir) + filename;
+
+ // split path from filename
+ QString dir = filename.left(slash);
+ QString file = filename.mid(slash);
+ return inst->dirs()->saveLocation(type, dir, createDir) + file;
+}
diff --git a/kdecore/kstandarddirs.h b/kdecore/kstandarddirs.h
new file mode 100644
index 000000000..ca9b2870b
--- /dev/null
+++ b/kdecore/kstandarddirs.h
@@ -0,0 +1,729 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
+ Copyright (C) 1999 Stephan Kulow <coolo@kde.org>
+ Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SSK_KSTDDIRS_H
+#define SSK_KSTDDIRS_H
+
+#include <qstring.h>
+#include <qdict.h>
+#include <qstringlist.h>
+#include <kglobal.h>
+
+class KConfig;
+class KStandardDirsPrivate;
+
+/**
+ * @short Site-independent access to standard KDE directories.
+ * @author Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
+ *
+ * This is one of the most central classes in kdelibs as
+ * it provides a basic service: It knows where the files
+ * reside on the user's hard disk. And it's meant to be the
+ * only one that knows -- to make the real location as
+ * transparent as possible to both the user and the applications.
+ *
+ * To this end it insulates the application from all information
+ * and applications always refer to a file with a resource type
+ * (e.g. icon) and a filename (e.g. khexdit.xpm). In an ideal world
+ * the application would make no assumption where this file is and
+ * leave it up to KStandardDirs::findResource("apps", "Home.desktop")
+ * to apply this knowledge to return /opt/kde/share/applnk/Home.desktop
+ * or ::locate("data", "kgame/background.jpg") to return
+ * /opt/kde/share/apps/kgame/background.jpg
+ *
+ * The main idea behind KStandardDirs is that there are several
+ * toplevel prefixes below which the files lie. One of these prefixes is
+ * the one where the user installed kdelibs, one is where the
+ * application was installed, and one is $HOME/.kde, but there
+ * may be even more. Under these prefixes there are several well
+ * defined suffixes where specific resource types are to be found.
+ * For example, for the resource type "html" the suffixes could be
+ * share/doc/HTML and share/doc/kde/HTML.
+ * So the search algorithm basically appends to each prefix each registered
+ * suffix and tries to locate the file there.
+ * To make the thing even more complex, it's also possible to register
+ * absolute paths that KStandardDirs looks up after not finding anything
+ * in the former steps. They can be useful if the user wants to provide
+ * specific directories that aren't in his $HOME/.kde directory for,
+ * for example, icons.
+ *
+ * <b>Standard resources that kdelibs allocates are:</b>\n
+ *
+ * @li apps - Applications menu (.desktop files).
+ * @li cache - Cached information (e.g. favicons, web-pages)
+ * @li cgi - CGIs to run from kdehelp.
+ * @li config - Configuration files.
+ * @li data - Where applications store data.
+ * @li exe - Executables in $prefix/bin. findExe() for a function that takes $PATH into account.
+ * @li html - HTML documentation.
+ * @li icon - Icons, see KIconLoader.
+ * @li lib - Libraries.
+ * @li locale - Translation files for KLocale.
+ * @li mime - Mime types.
+ * @li module - Module (dynamically loaded library).
+ * @li qtplugins - Qt plugins (dynamically loaded objects for Qt)
+ * @li services - Services.
+ * @li servicetypes - Service types.
+ * @li scripts - Application scripting additions.
+ * @li sound - Application sounds.
+ * @li templates - Templates
+ * @li wallpaper - Wallpapers.
+ * @li tmp - Temporary files (specific for both current host and current user)
+ * @li socket - UNIX Sockets (specific for both current host and current user)
+ * @li emoticons - Emoticons themes (Since KDE 3.4)
+ *
+ * A type that is added by the class KApplication if you use it, is
+ * appdata. This one makes the use of the type data a bit easier as it
+ * appends the name of the application.
+ * So while you had to ::locate("data", "appname/filename") so you can
+ * also write ::locate("appdata", "filename") if your KApplication instance
+ * is called "appname" (as set via KApplication's constructor or KAboutData, if
+ * you use the global KStandardDirs object KGlobal::dirs()).
+ * Please note though that you cannot use the "appdata"
+ * type if you intend to use it in an applet for Kicker because 'appname' would
+ * be "Kicker" instead of the applet's name. Therefore, for applets, you've got
+ * to work around this by using ::locate("data", "appletname/filename").
+ *
+ * <b>KStandardDirs supports the following environment variables:</b>
+ *
+ * @li KDEDIRS: This may set an additional number of directory prefixes to
+ * search for resources. The directories should be separated
+ * by ':'. The directories are searched in the order they are
+ * specified.
+ * @li KDEDIR: Used for backwards compatibility. As KDEDIRS but only a single
+ * directory may be specified. If KDEDIRS is set KDEDIR is
+ * ignored.
+ * @li KDEHOME: The directory where changes are saved to. This directory is
+ * used to search for resources first. If KDEHOME is not
+ * specified it defaults to "$HOME/.kde"
+ * @li KDEROOTHOME: Like KDEHOME, but used for the root user.
+ * If KDEROOTHOME is not set it defaults to the .kde directory in the
+ * home directory of root, usually "/root/.kde".
+ * Note that the setting of $HOME is ignored in this case.
+ *
+ * @see KGlobalSettings
+ */
+class KDECORE_EXPORT KStandardDirs
+{
+public:
+ /**
+ * KStandardDirs' constructor. It just initializes the caches.
+ **/
+ KStandardDirs( );
+
+ /**
+ * KStandardDirs' destructor.
+ */
+ virtual ~KStandardDirs();
+
+ /**
+ * Adds another search dir to front of the @p fsstnd list.
+ *
+ * @li When compiling kdelibs, the prefix is added to this.
+ * @li KDEDIRS or KDEDIR is taking into account
+ * @li Additional dirs may be loaded from kdeglobals.
+ *
+ * @param dir The directory to append relative paths to.
+ */
+ void addPrefix( const QString& dir );
+
+ /**
+ * Adds another search dir to front of the XDG_CONFIG_XXX list
+ * of prefixes.
+ * This prefix is only used for resources that start with "xdgconf-"
+ *
+ * @param dir The directory to append relative paths to.
+ */
+ void addXdgConfigPrefix( const QString& dir );
+
+ /**
+ * Adds another search dir to front of the XDG_DATA_XXX list
+ * of prefixes.
+ * This prefix is only used for resources that start with "xdgdata-"
+ *
+ * @param dir The directory to append relative paths to.
+ */
+ void addXdgDataPrefix( const QString& dir );
+
+ /**
+ * Adds suffixes for types.
+ *
+ * You may add as many as you need, but it is advised that there
+ * is exactly one to make writing definite.
+ * All basic types ( kde_default) are added by addKDEDefaults(),
+ * but for those you can add more relative paths as well.
+ *
+ * The later a suffix is added, the higher its priority. Note, that the
+ * suffix should end with / but doesn't have to start with one (as prefixes
+ * should end with one). So adding a suffix for app_pics would look
+ * like KGlobal::dirs()->addResourceType("app_pics", "share/app/pics");
+ *
+ * @param type Specifies a short descriptive string to access
+ * files of this type.
+ * @param relativename Specifies a directory relative to the root
+ * of the KFSSTND.
+ * @return true if successful, false otherwise.
+ */
+ bool addResourceType( const char *type,
+ const QString& relativename );
+
+ /**
+ * Adds absolute path at the end of the search path for
+ * particular types (for example in case of icons where
+ * the user specifies extra paths).
+ *
+ * You shouldn't need this
+ * function in 99% of all cases besides adding user-given
+ * paths.
+ *
+ * @param type Specifies a short descriptive string to access files
+ * of this type.
+ * @param absdir Points to directory where to look for this specific
+ * type. Non-existant directories may be saved but pruned.
+ * @return true if successful, false otherwise.
+ */
+ bool addResourceDir( const char *type,
+ const QString& absdir);
+
+ /**
+ * Tries to find a resource in the following order:
+ * @li All PREFIX/\<relativename> paths (most recent first).
+ * @li All absolute paths (most recent first).
+ *
+ * The filename should be a filename relative to the base dir
+ * for resources. So is a way to get the path to libkdecore.la
+ * to findResource("lib", "libkdecore.la"). KStandardDirs will
+ * then look into the subdir lib of all elements of all prefixes
+ * ($KDEDIRS) for a file libkdecore.la and return the path to
+ * the first one it finds (e.g. /opt/kde/lib/libkdecore.la)
+ *
+ * @param type The type of the wanted resource
+ * @param filename A relative filename of the resource.
+ *
+ * @return A full path to the filename specified in the second
+ * argument, or QString::null if not found.
+ */
+ QString findResource( const char *type,
+ const QString& filename ) const;
+
+ /**
+ * Checks whether a resource is restricted as part of the KIOSK
+ * framework. When a resource is restricted it means that user-
+ * specific files in the resource are ignored.
+ *
+ * E.g. by restricting the "wallpaper" resource, only system-wide
+ * installed wallpapers will be found by this class. Wallpapers
+ * installed under the $KDEHOME directory will be ignored.
+ *
+ * @param type The type of the resource to check
+ * @param relPath A relative path in the resource.
+ *
+ * @return True if the resource is restricted.
+ * @since 3.1
+ */
+ bool isRestrictedResource( const char *type,
+ const QString& relPath=QString::null ) const;
+
+ /**
+ * Returns a number that identifies this version of the resource.
+ * When a change is made to the resource this number will change.
+ *
+ * @param type The type of the wanted resource
+ * @param filename A relative filename of the resource.
+ * @param deep If true, all resources are taken into account
+ * otherwise only the one returned by findResource().
+ *
+ * @return A number identifying the current version of the
+ * resource.
+ */
+ Q_UINT32 calcResourceHash( const char *type,
+ const QString& filename, bool deep) const;
+
+ /**
+ * Tries to find all directories whose names consist of the
+ * specified type and a relative path. So would
+ * findDirs("apps", "Settings") return
+ * @li /opt/kde/share/applnk/Settings/
+ * @li /home/joe/.kde/share/applnk/Settings/
+ *
+ * Note that it appends / to the end of the directories,
+ * so you can use this right away as directory names.
+ *
+ * @param type The type of the base directory.
+ * @param reldir Relative directory.
+ *
+ * @return A list of matching directories, or an empty
+ * list if the resource specified is not found.
+ */
+ QStringList findDirs( const char *type,
+ const QString& reldir ) const;
+
+ /**
+ * Tries to find the directory the file is in.
+ * It works the same as findResource(), but it doesn't
+ * return the filename but the name of the directory.
+ *
+ * This way the application can access a couple of files
+ * that have been installed into the same directory without
+ * having to look for each file.
+ *
+ * findResourceDir("lib", "libkdecore.la") would return the
+ * path of the subdir libkdecore.la is found first in
+ * (e.g. /opt/kde/lib/)
+ *
+ * @param type The type of the wanted resource
+ * @param filename A relative filename of the resource.
+ * @return The directory where the file specified in the second
+ * argument is located, or QString::null if the type
+ * of resource specified is unknown or the resource
+ * cannot be found.
+ */
+ QString findResourceDir( const char *type,
+ const QString& filename) const;
+
+
+ /**
+ * Tries to find all resources with the specified type.
+ *
+ * The function will look into all specified directories
+ * and return all filenames in these directories.
+ *
+ * @param type The type of resource to locate directories for.
+ * @param filter Only accept filenames that fit to filter. The filter
+ * may consist of an optional directory and a QRegExp
+ * wildcard expression. E.g. "images\*.jpg". Use QString::null
+ * if you do not want a filter.
+ * @param recursive Specifies if the function should decend
+ * into subdirectories.
+ * @param unique If specified, only return items which have
+ * unique suffixes - suppressing duplicated filenames.
+ *
+ * @return List of all the files whose filename matches the
+ * specified filter.
+ */
+ QStringList findAllResources( const char *type,
+ const QString& filter = QString::null,
+ bool recursive = false,
+ bool unique = false) const;
+
+ /**
+ * Tries to find all resources with the specified type.
+ *
+ * The function will look into all specified directories
+ * and return all filenames (full and relative paths) in
+ * these directories.
+ *
+ * @param type The type of resource to locate directories for.
+ * @param filter Only accept filenames that fit to filter. The filter
+ * may consist of an optional directory and a QRegExp
+ * wildcard expression. E.g. "images\*.jpg". Use QString::null
+ * if you do not want a filter.
+ * @param recursive Specifies if the function should decend
+ * into subdirectories.
+ * @param unique If specified, only return items which have
+ * unique suffixes.
+ * @param relPaths The list to store the relative paths into
+ * These can be used later to ::locate() the file
+ *
+ * @return List of all the files whose filename matches the
+ * specified filter.
+ */
+ QStringList findAllResources( const char *type,
+ const QString& filter,
+ bool recursive,
+ bool unique,
+ QStringList &relPaths) const;
+
+ /**
+ * Returns a QStringList list of pathnames in the system path.
+ *
+ * @param pstr The path which will be searched. If this is
+ * null (default), the $PATH environment variable will
+ * be searched.
+ *
+ * @return a QStringList list of pathnames in the system path.
+ */
+ static QStringList systemPaths( const QString& pstr=QString::null );
+
+ /**
+ * Finds the executable in the system path.
+ *
+ * A valid executable must
+ * be a file and have its executable bit set.
+ *
+ * @param appname The name of the executable file for which to search.
+ * @param pathstr The path which will be searched. If this is
+ * null (default), the $PATH environment variable will
+ * be searched.
+ * @param ignoreExecBit If true, an existing file will be returned
+ * even if its executable bit is not set.
+ *
+ * @return The path of the executable. If it was not found,
+ * it will return QString::null.
+ * @see findAllExe()
+ */
+ static QString findExe( const QString& appname,
+ const QString& pathstr=QString::null,
+ bool ignoreExecBit=false );
+
+ /**
+ * Finds all occurrences of an executable in the system path.
+ *
+ * @param list Will be filled with the pathnames of all the
+ * executables found. Will be empty if the executable
+ * was not found.
+ * @param appname The name of the executable for which to
+ * search.
+ * @param pathstr The path list which will be searched. If this
+ * is 0 (default), the $PATH environment variable will
+ * be searched.
+ * @param ignoreExecBit If true, an existing file will be returned
+ * even if its executable bit is not set.
+ *
+ * @return The number of executables found, 0 if none were found.
+ *
+ * @see findExe()
+ */
+ static int findAllExe( QStringList& list, const QString& appname,
+ const QString& pathstr=QString::null,
+ bool ignoreExecBit=false );
+
+ /**
+ * This function adds the defaults that are used by the current
+ * KDE version.
+ *
+ * It's a series of addResourceTypes()
+ * and addPrefix() calls.
+ * You normally wouldn't call this function because it's called
+ * for you from KGlobal.
+ */
+ void addKDEDefaults();
+
+ /**
+ * Reads customized entries out of the given config object and add
+ * them via addResourceDirs().
+ *
+ * @param config The object the entries are read from. This should
+ * contain global config files
+ * @return true if new config paths have been added
+ * from @p config.
+ **/
+ bool addCustomized(KConfig *config);
+
+ /**
+ * This function is used internally by almost all other function as
+ * it serves and fills the directories cache.
+ *
+ * @param type The type of resource
+ * @return The list of possible directories for the specified @p type.
+ * The function updates the cache if possible. If the resource
+ * type specified is unknown, it will return an empty list.
+ * Note, that the directories are assured to exist beside the save
+ * location, which may not exist, but is returned anyway.
+ */
+ QStringList resourceDirs(const char *type) const;
+
+ /**
+ * This function will return a list of all the types that KStandardDirs
+ * supports.
+ *
+ * @return All types that KDE supports
+ */
+ QStringList allTypes() const;
+
+ /**
+ * Finds a location to save files into for the given type
+ * in the user's home directory.
+ *
+ * @param type The type of location to return.
+ * @param suffix A subdirectory name.
+ * Makes it easier for you to create subdirectories.
+ * You can't pass filenames here, you _have_ to pass
+ * directory names only and add possible filename in
+ * that directory yourself. A directory name always has a
+ * trailing slash ('/').
+ * @param create If set, saveLocation() will create the directories
+ * needed (including those given by @p suffix).
+ *
+ * @return A path where resources of the specified type should be
+ * saved, or QString::null if the resource type is unknown.
+ */
+ QString saveLocation(const char *type,
+ const QString& suffix = QString::null,
+ bool create = true) const;
+
+ /**
+ * Converts an absolute path to a path relative to a certain
+ * resource.
+ *
+ * If "abs = ::locate(resource, rel)"
+ * then "rel = relativeLocation(resource, abs)" and vice versa.
+ *
+ * @param type The type of resource.
+ *
+ * @param absPath An absolute path to make relative.
+ *
+ * @return A relative path relative to resource @p type that
+ * will find @p absPath. If no such relative path exists, absPath
+ * will be returned unchanged.
+ */
+ QString relativeLocation(const char *type, const QString &absPath);
+
+ /**
+ * Recursively creates still-missing directories in the given path.
+ *
+ * The resulting permissions will depend on the current umask setting.
+ * permission = mode & ~umask.
+ *
+ * @param dir Absolute path of the directory to be made.
+ * @param mode Directory permissions.
+ * @return true if successful, false otherwise
+ */
+ static bool makeDir(const QString& dir, int mode = 0755);
+
+ /**
+ * This returns a default relative path for the standard KDE
+ * resource types. Below is a list of them so you get an idea
+ * of what this is all about.
+ *
+ * @li data - share/apps
+ * @li html - share/doc/HTML
+ * @li icon - share/icon
+ * @li config - share/config
+ * @li pixmap - share/pixmaps
+ * @li apps - share/applnk
+ * @li sound - share/sounds
+ * @li locale - share/locale
+ * @li services - share/services
+ * @li servicetypes - share/servicetypes
+ * @li mime - share/mimelnk
+ * @li wallpaper - share/wallpapers
+ * @li templates - share/templates
+ * @li exe - bin
+ * @li lib - lib
+ *
+ * @returns Static default for the specified resource. You
+ * should probably be using locate() or locateLocal()
+ * instead.
+ * @see locate()
+ * @see locateLocal()
+ */
+ static QString kde_default(const char *type);
+
+ /**
+ * @internal (for use by sycoca only)
+ */
+ QString kfsstnd_prefixes();
+
+ /**
+ * @internal (for use by sycoca only)
+ */
+ QString kfsstnd_xdg_conf_prefixes();
+
+ /**
+ * @internal (for use by sycoca only)
+ */
+ QString kfsstnd_xdg_data_prefixes();
+
+ /**
+ * Returns the toplevel directory in which KStandardDirs
+ * will store things. Most likely $HOME/.kde
+ * Don't use this function if you can use locateLocal
+ * @return the toplevel directory
+ */
+ QString localkdedir() const;
+
+ /**
+ * @internal
+ * Returns the default toplevel directory where KDE is installed.
+ */
+ static QString kfsstnd_defaultprefix();
+
+ /**
+ * @internal
+ * Returns the default bin directory in which KDE executables are stored.
+ */
+ static QString kfsstnd_defaultbindir();
+
+ /**
+ * @return $XDG_DATA_HOME
+ * See also http://www.freedesktop.org/standards/basedir/draft/basedir-spec/basedir-spec.html
+ */
+ QString localxdgdatadir() const;
+
+ /**
+ * @return $XDG_CONFIG_HOME
+ * See also http://www.freedesktop.org/standards/basedir/draft/basedir-spec/basedir-spec.html
+ */
+ QString localxdgconfdir() const;
+
+ /**
+ * Checks for existence and accessability of a file or directory.
+ * Faster than creating a QFileInfo first.
+ * @param fullPath the path to check. IMPORTANT: must end with a slash if expected to be a directory
+ * (and no slash for a file, obviously).
+ * @return true if the directory exists
+ */
+ static bool exists(const QString &fullPath);
+
+ /**
+ * Expands all symbolic links and resolves references to
+ * '/./', '/../' and extra '/' characters in @p dirname
+ * and returns the canonicalized absolute pathname.
+ * The resulting path will have no symbolic link, '/./'
+ * or '/../' components.
+ * @since 3.1
+ */
+ static QString realPath(const QString &dirname);
+
+ /**
+ * Expands all symbolic links and resolves references to
+ * '/./', '/../' and extra '/' characters in @p filename
+ * and returns the canonicalized absolute pathname.
+ * The resulting path will have no symbolic link, '/./'
+ * or '/../' components.
+ * @since 3.4
+ */
+ static QString realFilePath(const QString &filename);
+
+ private:
+
+ QStringList prefixes;
+
+ // Directory dictionaries
+ QDict<QStringList> absolutes;
+ QDict<QStringList> relatives;
+
+ mutable QDict<QStringList> dircache;
+ mutable QDict<QString> savelocations;
+
+ // Disallow assignment and copy-construction
+ KStandardDirs( const KStandardDirs& );
+ KStandardDirs& operator= ( const KStandardDirs& );
+
+ bool addedCustoms;
+
+ class KStandardDirsPrivate;
+ KStandardDirsPrivate *d;
+
+ void checkConfig() const;
+ void applyDataRestrictions(const QString &) const;
+ void createSpecialResource(const char*);
+
+ // Like their public counter parts but with an extra priority argument
+ // If priority is true, the directory is added directly after
+ // $KDEHOME/$XDG_DATA_HOME/$XDG_CONFIG_HOME
+ void addPrefix( const QString& dir, bool priority );
+ void addXdgConfigPrefix( const QString& dir, bool priority );
+ void addXdgDataPrefix( const QString& dir, bool priority );
+
+ // If priority is true, the directory is added before any other,
+ // otherwise after
+ bool addResourceType( const char *type,
+ const QString& relativename, bool priority );
+ bool addResourceDir( const char *type,
+ const QString& absdir, bool priority);
+};
+
+/**
+ * \addtogroup locates Locate Functions
+ * @{
+ * On The Usage Of 'locate' and 'locateLocal'
+ *
+ * Typical KDE applications use resource files in one out of
+ * three ways:
+ *
+ * 1) A resource file is read but is never written. A system
+ * default is supplied but the user can override this
+ * default in his local .kde directory:
+ *
+ * \code
+ * // Code example
+ * myFile = locate("appdata", "groups.lst");
+ * myData = myReadGroups(myFile); // myFile may be null
+ * \endcode
+ *
+ * 2) A resource file is read and written. If the user has no
+ * local version of the file the system default is used.
+ * The resource file is always written to the users local
+ * .kde directory.
+ *
+ * \code
+ * // Code example
+ * myFile = locate("appdata", "groups.lst")
+ * myData = myReadGroups(myFile);
+ * ...
+ * doSomething(myData);
+ * ...
+ * myFile = locateLocal("appdata", "groups.lst");
+ * myWriteGroups(myFile, myData);
+ * \endcode
+ *
+ * 3) A resource file is read and written. No system default
+ * is used if the user has no local version of the file.
+ * The resource file is always written to the users local
+ * .kde directory.
+ *
+ * \code
+ * // Code example
+ * myFile = locateLocal("appdata", "groups.lst");
+ * myData = myReadGroups(myFile);
+ * ...
+ * doSomething(myData);
+ * ...
+ * myFile = locateLocal("appdata", "groups.lst");
+ * myWriteGroups(myFile, myData);
+ * \endcode
+ **/
+
+/*!
+ * \relates KStandardDirs
+ * This function is just for convenience. It simply calls
+ *instance->dirs()->\link KStandardDirs::findResource() findResource\endlink(type, filename).
+ **/
+KDECORE_EXPORT QString locate( const char *type, const QString& filename, const KInstance* instance = KGlobal::instance() );
+
+/*!
+ * \relates KStandardDirs
+ * This function is much like locate. However it returns a
+ * filename suitable for writing to. No check is made if the
+ * specified filename actually exists. Missing directories
+ * are created. If filename is only a directory, without a
+ * specific file, filename must have a trailing slash.
+ *
+ **/
+KDECORE_EXPORT QString locateLocal( const char *type, const QString& filename, const KInstance* instance = KGlobal::instance() );
+
+/*!
+ * \relates KStandardDirs
+ * This function is much like locate. No check is made if the
+ * specified filename actually exists. Missing directories
+ * are created if @p createDir is true. If filename is only
+ * a directory, without a specific file,
+ * filename must have a trailing slash.
+ *
+ **/
+KDECORE_EXPORT QString locateLocal( const char *type, const QString& filename, bool createDir, const KInstance* instance = KGlobal::instance() );
+
+/*! @} */
+
+#endif // SSK_KSTDDIRS_H
diff --git a/kdecore/kstartupinfo.cpp b/kdecore/kstartupinfo.cpp
new file mode 100644
index 000000000..3de0cb288
--- /dev/null
+++ b/kdecore/kstartupinfo.cpp
@@ -0,0 +1,1498 @@
+/****************************************************************************
+
+ $Id$
+
+ Copyright (C) 2001-2003 Lubos Lunak <l.lunak@kde.org>
+
+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 OR COPYRIGHT HOLDERS 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.
+
+****************************************************************************/
+
+// kdDebug() can't be turned off in kdeinit
+#if 0
+#define KSTARTUPINFO_ALL_DEBUG
+#warning Extra KStartupInfo debug messages enabled.
+#endif
+
+#include <qwidget.h>
+
+#include "config.h"
+#ifdef Q_WS_X11
+//#ifdef Q_WS_X11 // FIXME(E): Re-implement in a less X11 specific way
+#include <qglobal.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// need to resolve INT32(qglobal.h)<>INT32(Xlibint.h) conflict
+#ifndef QT_CLEAN_NAMESPACE
+#define QT_CLEAN_NAMESPACE
+#endif
+
+#include "kstartupinfo.h"
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <qtimer.h>
+#ifdef Q_WS_X11
+#include <netwm.h>
+#endif
+#include <kdebug.h>
+#include <kapplication.h>
+#include <signal.h>
+#ifdef Q_WS_X11
+#include <kwinmodule.h>
+#include <kxmessages.h>
+#include <kwin.h>
+#endif
+
+static const char* const NET_STARTUP_MSG = "_NET_STARTUP_INFO";
+static const char* const NET_STARTUP_WINDOW = "_NET_STARTUP_ID";
+// DESKTOP_STARTUP_ID is used also in kinit/wrapper.c ,
+// kdesu in both kdelibs and kdebase and who knows where else
+static const char* const NET_STARTUP_ENV = "DESKTOP_STARTUP_ID";
+
+static bool auto_app_started_sending = true;
+
+static long get_num( const QString& item_P );
+static unsigned long get_unum( const QString& item_P );
+static QString get_str( const QString& item_P );
+static QCString get_cstr( const QString& item_P );
+static QStringList get_fields( const QString& txt_P );
+static QString escape_str( const QString& str_P );
+
+static Atom utf8_string_atom = None;
+
+class KStartupInfo::Data
+ : public KStartupInfoData
+ {
+ public:
+ Data() : KStartupInfoData(), age(0) {} // just because it's in a QMap
+ Data( const QString& txt_P )
+ : KStartupInfoData( txt_P ), age( 0 ) {}
+ unsigned int age;
+ };
+
+struct KStartupInfoPrivate
+ {
+ public:
+ QMap< KStartupInfoId, KStartupInfo::Data > startups;
+ // contains silenced ASN's only if !AnnounceSilencedChanges
+ QMap< KStartupInfoId, KStartupInfo::Data > silent_startups;
+ // contains ASN's that had change: but no new: yet
+ QMap< KStartupInfoId, KStartupInfo::Data > uninited_startups;
+#ifdef Q_WS_X11
+ KWinModule* wm_module;
+ KXMessages msgs;
+#endif
+ QTimer* cleanup;
+ int flags;
+ KStartupInfoPrivate( int flags_P )
+ :
+#ifdef Q_WS_X11
+ msgs( NET_STARTUP_MSG, NULL, false ),
+#endif
+ flags( flags_P ) {}
+ };
+
+KStartupInfo::KStartupInfo( int flags_P, QObject* parent_P, const char* name_P )
+ : QObject( parent_P, name_P ),
+ timeout( 60 ), d( NULL )
+ {
+ init( flags_P );
+ }
+
+KStartupInfo::KStartupInfo( bool clean_on_cantdetect_P, QObject* parent_P, const char* name_P )
+ : QObject( parent_P, name_P ),
+ timeout( 60 ), d( NULL )
+ {
+ init( clean_on_cantdetect_P ? CleanOnCantDetect : 0 );
+ }
+
+void KStartupInfo::init( int flags_P )
+ {
+ // d == NULL means "disabled"
+ if( !KApplication::kApplication())
+ return;
+ if( !KApplication::kApplication()->getDisplay())
+ return;
+
+ d = new KStartupInfoPrivate( flags_P );
+#ifdef Q_WS_X11
+ if( !( d->flags & DisableKWinModule ))
+ {
+ d->wm_module = new KWinModule( this );
+ connect( d->wm_module, SIGNAL( windowAdded( WId )), SLOT( slot_window_added( WId )));
+ connect( d->wm_module, SIGNAL( systemTrayWindowAdded( WId )), SLOT( slot_window_added( WId )));
+ }
+ else
+ d->wm_module = NULL;
+ connect( &d->msgs, SIGNAL( gotMessage( const QString& )), SLOT( got_message( const QString& )));
+#endif
+ d->cleanup = new QTimer( this, "cleanup" );
+ connect( d->cleanup, SIGNAL( timeout()), SLOT( startups_cleanup()));
+ }
+
+KStartupInfo::~KStartupInfo()
+ {
+ delete d;
+ }
+
+void KStartupInfo::got_message( const QString& msg_P )
+ {
+// TODO do something with SCREEN= ?
+ kdDebug( 172 ) << "got:" << msg_P << endl;
+ QString msg = msg_P.stripWhiteSpace();
+ if( msg.startsWith( "new:" )) // must match length below
+ got_startup_info( msg.mid( 4 ), false );
+ else if( msg.startsWith( "change:" )) // must match length below
+ got_startup_info( msg.mid( 7 ), true );
+ else if( msg.startsWith( "remove:" )) // must match length below
+ got_remove_startup_info( msg.mid( 7 ));
+ }
+
+// if the application stops responding for a while, KWinModule may get
+// the information about the already mapped window before KXMessages
+// actually gets the info about the started application (depends
+// on their order in X11 event filter in KApplication)
+// simply delay info from KWinModule a bit
+// SELI???
+namespace
+{
+class DelayedWindowEvent
+ : public QCustomEvent
+ {
+ public:
+ DelayedWindowEvent( WId w_P )
+ : QCustomEvent( QEvent::User + 15 ), w( w_P ) {}
+ Window w;
+ };
+}
+
+void KStartupInfo::slot_window_added( WId w_P )
+ {
+ kapp->postEvent( this, new DelayedWindowEvent( w_P ));
+ }
+
+void KStartupInfo::customEvent( QCustomEvent* e_P )
+ {
+ if( e_P->type() == QEvent::User + 15 )
+ window_added( static_cast< DelayedWindowEvent* >( e_P )->w );
+ else
+ QObject::customEvent( e_P );
+ }
+
+void KStartupInfo::window_added( WId w_P )
+ {
+ KStartupInfoId id;
+ KStartupInfoData data;
+ startup_t ret = check_startup_internal( w_P, &id, &data );
+ switch( ret )
+ {
+ case Match:
+ kdDebug( 172 ) << "new window match" << endl;
+ break;
+ case NoMatch:
+ break; // nothing
+ case CantDetect:
+ if( d->flags & CleanOnCantDetect )
+ clean_all_noncompliant();
+ break;
+ }
+ }
+
+void KStartupInfo::got_startup_info( const QString& msg_P, bool update_P )
+ {
+ KStartupInfoId id( msg_P );
+ if( id.none())
+ return;
+ KStartupInfo::Data data( msg_P );
+ new_startup_info_internal( id, data, update_P );
+ }
+
+void KStartupInfo::new_startup_info_internal( const KStartupInfoId& id_P,
+ Data& data_P, bool update_P )
+ {
+ if( d == NULL )
+ return;
+ if( id_P.none())
+ return;
+ if( d->startups.contains( id_P ))
+ { // already reported, update
+ d->startups[ id_P ].update( data_P );
+ d->startups[ id_P ].age = 0; // CHECKME
+ kdDebug( 172 ) << "updating" << endl;
+ if( d->startups[ id_P ].silent() == Data::Yes
+ && !( d->flags & AnnounceSilenceChanges ))
+ {
+ d->silent_startups[ id_P ] = d->startups[ id_P ];
+ d->startups.remove( id_P );
+ emit gotRemoveStartup( id_P, d->silent_startups[ id_P ] );
+ return;
+ }
+ emit gotStartupChange( id_P, d->startups[ id_P ] );
+ return;
+ }
+ if( d->silent_startups.contains( id_P ))
+ { // already reported, update
+ d->silent_startups[ id_P ].update( data_P );
+ d->silent_startups[ id_P ].age = 0; // CHECKME
+ kdDebug( 172 ) << "updating silenced" << endl;
+ if( d->silent_startups[ id_P ].silent() != Data::Yes )
+ {
+ d->startups[ id_P ] = d->silent_startups[ id_P ];
+ d->silent_startups.remove( id_P );
+ emit gotNewStartup( id_P, d->startups[ id_P ] );
+ return;
+ }
+ emit gotStartupChange( id_P, d->silent_startups[ id_P ] );
+ return;
+ }
+ if( d->uninited_startups.contains( id_P ))
+ {
+ d->uninited_startups[ id_P ].update( data_P );
+ kdDebug( 172 ) << "updating uninited" << endl;
+ if( !update_P ) // uninited finally got new:
+ {
+ d->startups[ id_P ] = d->uninited_startups[ id_P ];
+ d->uninited_startups.remove( id_P );
+ emit gotNewStartup( id_P, d->startups[ id_P ] );
+ return;
+ }
+ // no change announce, it's still uninited
+ return;
+ }
+ if( update_P ) // change: without any new: first
+ {
+ kdDebug( 172 ) << "adding uninited" << endl;
+ d->uninited_startups.insert( id_P, data_P );
+ }
+ else if( data_P.silent() != Data::Yes || d->flags & AnnounceSilenceChanges )
+ {
+ kdDebug( 172 ) << "adding" << endl;
+ d->startups.insert( id_P, data_P );
+ emit gotNewStartup( id_P, data_P );
+ }
+ else // new silenced, and silent shouldn't be announced
+ {
+ kdDebug( 172 ) << "adding silent" << endl;
+ d->silent_startups.insert( id_P, data_P );
+ }
+ d->cleanup->start( 1000 ); // 1 sec
+ }
+
+void KStartupInfo::got_remove_startup_info( const QString& msg_P )
+ {
+ KStartupInfoId id( msg_P );
+ KStartupInfoData data( msg_P );
+ if( data.pids().count() > 0 )
+ {
+ if( !id.none())
+ remove_startup_pids( id, data );
+ else
+ remove_startup_pids( data );
+ return;
+ }
+ remove_startup_info_internal( id );
+ }
+
+void KStartupInfo::remove_startup_info_internal( const KStartupInfoId& id_P )
+ {
+ if( d == NULL )
+ return;
+ if( d->startups.contains( id_P ))
+ {
+ kdDebug( 172 ) << "removing" << endl;
+ emit gotRemoveStartup( id_P, d->startups[ id_P ]);
+ d->startups.remove( id_P );
+ }
+ else if( d->silent_startups.contains( id_P ))
+ {
+ kdDebug( 172 ) << "removing silent" << endl;
+ d->silent_startups.remove( id_P );
+ }
+ else if( d->uninited_startups.contains( id_P ))
+ {
+ kdDebug( 172 ) << "removing uninited" << endl;
+ d->uninited_startups.remove( id_P );
+ }
+ return;
+ }
+
+void KStartupInfo::remove_startup_pids( const KStartupInfoData& data_P )
+ { // first find the matching info
+ if( d == NULL )
+ return;
+ for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
+ it != d->startups.end();
+ ++it )
+ {
+ if( ( *it ).hostname() != data_P.hostname())
+ continue;
+ if( !( *it ).is_pid( data_P.pids().first()))
+ continue; // not the matching info
+ remove_startup_pids( it.key(), data_P );
+ break;
+ }
+ }
+
+void KStartupInfo::remove_startup_pids( const KStartupInfoId& id_P,
+ const KStartupInfoData& data_P )
+ {
+ if( d == NULL )
+ return;
+ kdFatal( data_P.pids().count() == 0, 172 );
+ Data* data = NULL;
+ if( d->startups.contains( id_P ))
+ data = &d->startups[ id_P ];
+ else if( d->silent_startups.contains( id_P ))
+ data = &d->silent_startups[ id_P ];
+ else if( d->uninited_startups.contains( id_P ))
+ data = &d->uninited_startups[ id_P ];
+ else
+ return;
+ for( QValueList< pid_t >::ConstIterator it2 = data_P.pids().begin();
+ it2 != data_P.pids().end();
+ ++it2 )
+ data->remove_pid( *it2 ); // remove all pids from the info
+ if( data->pids().count() == 0 ) // all pids removed -> remove info
+ remove_startup_info_internal( id_P );
+ }
+
+bool KStartupInfo::sendStartup( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
+ {
+ if( id_P.none())
+ return false;
+ KXMessages msgs;
+ QString msg = QString::fromLatin1( "new: %1 %2" )
+ .arg( id_P.to_text()).arg( data_P.to_text());
+ msg = check_required_startup_fields( msg, data_P, qt_xscreen());
+ kdDebug( 172 ) << "sending " << msg << endl;
+ msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
+ return true;
+ }
+
+bool KStartupInfo::sendStartupX( Display* disp_P, const KStartupInfoId& id_P,
+ const KStartupInfoData& data_P )
+ {
+ if( id_P.none())
+ return false;
+ QString msg = QString::fromLatin1( "new: %1 %2" )
+ .arg( id_P.to_text()).arg( data_P.to_text());
+ msg = check_required_startup_fields( msg, data_P, DefaultScreen( disp_P ));
+#ifdef KSTARTUPINFO_ALL_DEBUG
+ kdDebug( 172 ) << "sending " << msg << endl;
+#endif
+ return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
+ }
+
+QString KStartupInfo::check_required_startup_fields( const QString& msg, const KStartupInfoData& data_P,
+ int screen )
+ {
+ QString ret = msg;
+ if( data_P.name().isEmpty())
+ {
+// kdWarning( 172 ) << "NAME not specified in initial startup message" << endl;
+ QString name = data_P.bin();
+ if( name.isEmpty())
+ name = "UNKNOWN";
+ ret += QString( " NAME=\"%1\"" ).arg( escape_str( name ));
+ }
+ if( data_P.screen() == -1 ) // add automatically if needed
+ ret += QString( " SCREEN=%1" ).arg( screen );
+ return ret;
+ }
+
+bool KStartupInfo::sendChange( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
+ {
+ if( id_P.none())
+ return false;
+ KXMessages msgs;
+ QString msg = QString::fromLatin1( "change: %1 %2" )
+ .arg( id_P.to_text()).arg( data_P.to_text());
+ kdDebug( 172 ) << "sending " << msg << endl;
+ msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
+ return true;
+ }
+
+bool KStartupInfo::sendChangeX( Display* disp_P, const KStartupInfoId& id_P,
+ const KStartupInfoData& data_P )
+ {
+ if( id_P.none())
+ return false;
+ QString msg = QString::fromLatin1( "change: %1 %2" )
+ .arg( id_P.to_text()).arg( data_P.to_text());
+#ifdef KSTARTUPINFO_ALL_DEBUG
+ kdDebug( 172 ) << "sending " << msg << endl;
+#endif
+ return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
+ }
+
+bool KStartupInfo::sendFinish( const KStartupInfoId& id_P )
+ {
+ if( id_P.none())
+ return false;
+ KXMessages msgs;
+ QString msg = QString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
+ kdDebug( 172 ) << "sending " << msg << endl;
+ msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
+ return true;
+ }
+
+bool KStartupInfo::sendFinishX( Display* disp_P, const KStartupInfoId& id_P )
+ {
+ if( id_P.none())
+ return false;
+ QString msg = QString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
+#ifdef KSTARTUPINFO_ALL_DEBUG
+ kdDebug( 172 ) << "sending " << msg << endl;
+#endif
+ return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
+ }
+
+bool KStartupInfo::sendFinish( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
+ {
+// if( id_P.none()) // id may be none, the pids and hostname matter then
+// return false;
+ KXMessages msgs;
+ QString msg = QString::fromLatin1( "remove: %1 %2" )
+ .arg( id_P.to_text()).arg( data_P.to_text());
+ kdDebug( 172 ) << "sending " << msg << endl;
+ msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
+ return true;
+ }
+
+bool KStartupInfo::sendFinishX( Display* disp_P, const KStartupInfoId& id_P,
+ const KStartupInfoData& data_P )
+ {
+// if( id_P.none()) // id may be none, the pids and hostname matter then
+// return false;
+ QString msg = QString::fromLatin1( "remove: %1 %2" )
+ .arg( id_P.to_text()).arg( data_P.to_text());
+#ifdef KSTARTUPINFO_ALL_DEBUG
+ kdDebug( 172 ) << "sending " << msg << endl;
+#endif
+ return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
+ }
+
+void KStartupInfo::appStarted()
+ {
+ if( kapp != NULL ) // KApplication constructor unsets the env. variable
+ appStarted( kapp->startupId());
+ else
+ appStarted( KStartupInfo::currentStartupIdEnv().id());
+ }
+
+void KStartupInfo::appStarted( const QCString& startup_id )
+ {
+ KStartupInfoId id;
+ id.initId( startup_id );
+ if( id.none())
+ return;
+ if( kapp != NULL )
+ KStartupInfo::sendFinish( id );
+ else if( getenv( "DISPLAY" ) != NULL ) // don't rely on qt_xdisplay()
+ {
+#ifdef Q_WS_X11
+ Display* disp = XOpenDisplay( NULL );
+ if( disp != NULL )
+ {
+ KStartupInfo::sendFinishX( disp, id );
+ XCloseDisplay( disp );
+ }
+#endif
+ }
+ }
+
+void KStartupInfo::disableAutoAppStartedSending( bool disable )
+ {
+ auto_app_started_sending = !disable;
+ }
+
+void KStartupInfo::silenceStartup( bool silence )
+ {
+ KStartupInfoId id;
+ id.initId( kapp->startupId());
+ if( id.none())
+ return;
+ KStartupInfoData data;
+ data.setSilent( silence ? KStartupInfoData::Yes : KStartupInfoData::No );
+ sendChange( id, data );
+ }
+
+void KStartupInfo::handleAutoAppStartedSending()
+ {
+ if( auto_app_started_sending )
+ appStarted();
+ }
+
+void KStartupInfo::setNewStartupId( QWidget* window, const QCString& startup_id )
+ {
+ bool activate = true;
+ kapp->setStartupId( startup_id );
+ if( window != NULL )
+ {
+ if( !startup_id.isEmpty() && startup_id != "0" )
+ {
+ NETRootInfo i( qt_xdisplay(), NET::Supported );
+ if( i.isSupported( NET::WM2StartupId ))
+ {
+ KStartupInfo::setWindowStartupId( window->winId(), startup_id );
+ activate = false; // WM will take care of it
+ }
+ }
+ if( activate )
+ {
+ KWin::setOnDesktop( window->winId(), KWin::currentDesktop());
+ // This is not very nice, but there's no way how to get any
+ // usable timestamp without ASN, so force activating the window.
+ // And even with ASN, it's not possible to get the timestamp here,
+ // so if the WM doesn't have support for ASN, it can't be used either.
+ KWin::forceActiveWindow( window->winId());
+ }
+ }
+ KStartupInfo::handleAutoAppStartedSending();
+ }
+
+KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoId& id_O,
+ KStartupInfoData& data_O )
+ {
+ return check_startup_internal( w_P, &id_O, &data_O );
+ }
+
+KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoId& id_O )
+ {
+ return check_startup_internal( w_P, &id_O, NULL );
+ }
+
+KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoData& data_O )
+ {
+ return check_startup_internal( w_P, NULL, &data_O );
+ }
+
+KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P )
+ {
+ return check_startup_internal( w_P, NULL, NULL );
+ }
+
+KStartupInfo::startup_t KStartupInfo::check_startup_internal( WId w_P, KStartupInfoId* id_O,
+ KStartupInfoData* data_O )
+ {
+ if( d == NULL )
+ return NoMatch;
+ if( d->startups.count() == 0 )
+ return NoMatch; // no startups
+ // Strategy:
+ //
+ // Is this a compliant app ?
+ // - Yes - test for match
+ // - No - Is this a NET_WM compliant app ?
+ // - Yes - test for pid match
+ // - No - test for WM_CLASS match
+ kdDebug( 172 ) << "check_startup" << endl;
+ QCString id = windowStartupId( w_P );
+ if( !id.isNull())
+ {
+ if( id.isEmpty() || id == "0" ) // means ignore this window
+ {
+ kdDebug( 172 ) << "ignore" << endl;
+ return NoMatch;
+ }
+ return find_id( id, id_O, data_O ) ? Match : NoMatch;
+ }
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), w_P, qt_xrootwin(),
+ NET::WMWindowType | NET::WMPid | NET::WMState );
+ pid_t pid = info.pid();
+ if( pid > 0 )
+ {
+ QCString hostname = get_window_hostname( w_P );
+ if( !hostname.isEmpty()
+ && find_pid( pid, hostname, id_O, data_O ))
+ return Match;
+ // try XClass matching , this PID stuff sucks :(
+ }
+ XClassHint hint;
+ if( XGetClassHint( qt_xdisplay(), w_P, &hint ) != 0 )
+ { // We managed to read the class hint
+ QCString res_name = hint.res_name;
+ QCString res_class = hint.res_class;
+ XFree( hint.res_name );
+ XFree( hint.res_class );
+ if( find_wclass( res_name, res_class, id_O, data_O ))
+ return Match;
+ }
+ // ignore NET::Tool and other special window types, if they can't be matched
+ NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask
+ | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
+ | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
+ if( type != NET::Normal
+ && type != NET::Override
+ && type != NET::Unknown
+ && type != NET::Dialog
+ && type != NET::Utility )
+// && type != NET::Dock ) why did I put this here?
+ return NoMatch;
+ // lets see if this is a transient
+ Window transient_for;
+ if( XGetTransientForHint( qt_xdisplay(), static_cast< Window >( w_P ), &transient_for )
+ && static_cast< WId >( transient_for ) != qt_xrootwin()
+ && transient_for != None )
+ return NoMatch;
+#endif
+ kdDebug( 172 ) << "check_startup:cantdetect" << endl;
+ return CantDetect;
+ }
+
+bool KStartupInfo::find_id( const QCString& id_P, KStartupInfoId* id_O,
+ KStartupInfoData* data_O )
+ {
+ if( d == NULL )
+ return false;
+ kdDebug( 172 ) << "find_id:" << id_P << endl;
+ KStartupInfoId id;
+ id.initId( id_P );
+ if( d->startups.contains( id ))
+ {
+ if( id_O != NULL )
+ *id_O = id;
+ if( data_O != NULL )
+ *data_O = d->startups[ id ];
+ kdDebug( 172 ) << "check_startup_id:match" << endl;
+ return true;
+ }
+ return false;
+ }
+
+bool KStartupInfo::find_pid( pid_t pid_P, const QCString& hostname_P,
+ KStartupInfoId* id_O, KStartupInfoData* data_O )
+ {
+ if( d == NULL )
+ return false;
+ kdDebug( 172 ) << "find_pid:" << pid_P << endl;
+ for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
+ it != d->startups.end();
+ ++it )
+ {
+ if( ( *it ).is_pid( pid_P ) && ( *it ).hostname() == hostname_P )
+ { // Found it !
+ if( id_O != NULL )
+ *id_O = it.key();
+ if( data_O != NULL )
+ *data_O = *it;
+ // non-compliant, remove on first match
+ remove_startup_info_internal( it.key());
+ kdDebug( 172 ) << "check_startup_pid:match" << endl;
+ return true;
+ }
+ }
+ return false;
+ }
+
+bool KStartupInfo::find_wclass( QCString res_name, QCString res_class,
+ KStartupInfoId* id_O, KStartupInfoData* data_O )
+ {
+ if( d == NULL )
+ return false;
+ res_name = res_name.lower();
+ res_class = res_class.lower();
+ kdDebug( 172 ) << "find_wclass:" << res_name << ":" << res_class << endl;
+ for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
+ it != d->startups.end();
+ ++it )
+ {
+ const QCString wmclass = ( *it ).findWMClass();
+ if( wmclass.lower() == res_name || wmclass.lower() == res_class )
+ { // Found it !
+ if( id_O != NULL )
+ *id_O = it.key();
+ if( data_O != NULL )
+ *data_O = *it;
+ // non-compliant, remove on first match
+ remove_startup_info_internal( it.key());
+ kdDebug( 172 ) << "check_startup_wclass:match" << endl;
+ return true;
+ }
+ }
+ return false;
+ }
+
+#ifdef Q_WS_X11
+static Atom net_startup_atom = None;
+
+static QCString read_startup_id_property( WId w_P )
+ {
+ QCString ret;
+ unsigned char *name_ret;
+ Atom type_ret;
+ int format_ret;
+ unsigned long nitems_ret = 0, after_ret = 0;
+ if( XGetWindowProperty( qt_xdisplay(), w_P, net_startup_atom, 0l, 4096,
+ False, utf8_string_atom, &type_ret, &format_ret, &nitems_ret, &after_ret, &name_ret )
+ == Success )
+ {
+ if( type_ret == utf8_string_atom && format_ret == 8 && name_ret != NULL )
+ ret = reinterpret_cast< char* >( name_ret );
+ if ( name_ret != NULL )
+ XFree( name_ret );
+ }
+ return ret;
+ }
+
+#endif
+
+QCString KStartupInfo::windowStartupId( WId w_P )
+ {
+#ifdef Q_WS_X11
+ if( net_startup_atom == None )
+ net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
+ if( utf8_string_atom == None )
+ utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
+ QCString ret = read_startup_id_property( w_P );
+ if( ret.isEmpty())
+ { // retry with window group leader, as the spec says
+ XWMHints* hints = XGetWMHints( qt_xdisplay(), w_P );
+ if( hints && ( hints->flags & WindowGroupHint ) != 0 )
+ ret = read_startup_id_property( hints->window_group );
+ if( hints )
+ XFree( hints );
+ }
+ return ret;
+#else
+ return QCString();
+#endif
+ }
+
+void KStartupInfo::setWindowStartupId( WId w_P, const QCString& id_P )
+ {
+#ifdef Q_WS_X11
+ if( id_P.isNull())
+ return;
+ if( net_startup_atom == None )
+ net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
+ if( utf8_string_atom == None )
+ utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
+ XChangeProperty( qt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8,
+ PropModeReplace, reinterpret_cast< unsigned char* >( id_P.data()), id_P.length());
+#endif
+ }
+
+QCString KStartupInfo::get_window_hostname( WId w_P )
+ {
+#ifdef Q_WS_X11
+ XTextProperty tp;
+ char** hh;
+ int cnt;
+ if( XGetWMClientMachine( qt_xdisplay(), w_P, &tp ) != 0
+ && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 )
+ {
+ if( cnt == 1 )
+ {
+ QCString hostname = hh[ 0 ];
+ XFreeStringList( hh );
+ return hostname;
+ }
+ XFreeStringList( hh );
+ }
+#endif
+ // no hostname
+ return QCString();
+ }
+
+void KStartupInfo::setTimeout( unsigned int secs_P )
+ {
+ timeout = secs_P;
+ // schedule removing entries that are older than the new timeout
+ QTimer::singleShot( 0, this, SLOT( startups_cleanup_no_age()));
+ }
+
+void KStartupInfo::startups_cleanup_no_age()
+ {
+ startups_cleanup_internal( false );
+ }
+
+void KStartupInfo::startups_cleanup()
+ {
+ if( d == NULL )
+ return;
+ if( d->startups.count() == 0 && d->silent_startups.count() == 0
+ && d->uninited_startups.count() == 0 )
+ {
+ d->cleanup->stop();
+ return;
+ }
+ startups_cleanup_internal( true );
+ }
+
+void KStartupInfo::startups_cleanup_internal( bool age_P )
+ {
+ if( d == NULL )
+ return;
+ for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
+ it != d->startups.end();
+ )
+ {
+ if( age_P )
+ ( *it ).age++;
+ unsigned int tout = timeout;
+ if( ( *it ).silent() == Data::Yes ) // TODO
+ tout *= 20;
+ if( ( *it ).age >= tout )
+ {
+ const KStartupInfoId& key = it.key();
+ ++it;
+ kdDebug( 172 ) << "startups entry timeout:" << key.id() << endl;
+ remove_startup_info_internal( key );
+ }
+ else
+ ++it;
+ }
+ for( QMap< KStartupInfoId, Data >::Iterator it = d->silent_startups.begin();
+ it != d->silent_startups.end();
+ )
+ {
+ if( age_P )
+ ( *it ).age++;
+ unsigned int tout = timeout;
+ if( ( *it ).silent() == Data::Yes ) // TODO
+ tout *= 20;
+ if( ( *it ).age >= tout )
+ {
+ const KStartupInfoId& key = it.key();
+ ++it;
+ kdDebug( 172 ) << "silent entry timeout:" << key.id() << endl;
+ remove_startup_info_internal( key );
+ }
+ else
+ ++it;
+ }
+ for( QMap< KStartupInfoId, Data >::Iterator it = d->uninited_startups.begin();
+ it != d->uninited_startups.end();
+ )
+ {
+ if( age_P )
+ ( *it ).age++;
+ unsigned int tout = timeout;
+ if( ( *it ).silent() == Data::Yes ) // TODO
+ tout *= 20;
+ if( ( *it ).age >= tout )
+ {
+ const KStartupInfoId& key = it.key();
+ ++it;
+ kdDebug( 172 ) << "uninited entry timeout:" << key.id() << endl;
+ remove_startup_info_internal( key );
+ }
+ else
+ ++it;
+ }
+ }
+
+void KStartupInfo::clean_all_noncompliant()
+ {
+ if( d == NULL )
+ return;
+ for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
+ it != d->startups.end();
+ )
+ {
+ if( ( *it ).WMClass() != "0" )
+ {
+ ++it;
+ continue;
+ }
+ const KStartupInfoId& key = it.key();
+ ++it;
+ kdDebug( 172 ) << "entry cleaning:" << key.id() << endl;
+ remove_startup_info_internal( key );
+ }
+ }
+
+QCString KStartupInfo::createNewStartupId()
+ {
+ // Assign a unique id, use hostname+time+pid, that should be 200% unique.
+ // Also append the user timestamp (for focus stealing prevention).
+ struct timeval tm;
+ gettimeofday( &tm, NULL );
+ char hostname[ 256 ];
+ hostname[ 0 ] = '\0';
+ if (!gethostname( hostname, 255 ))
+ hostname[sizeof(hostname)-1] = '\0';
+#ifdef Q_WS_X11
+ extern Time qt_x_user_time;
+#else
+ unsigned long qt_x_user_time = 0;
+#endif
+ QCString id = QString( "%1;%2;%3;%4_TIME%5" ).arg( hostname ).arg( tm.tv_sec )
+ .arg( tm.tv_usec ).arg( getpid()).arg( qt_x_user_time ).utf8();
+ kdDebug( 172 ) << "creating: " << id << ":" << qAppName() << endl;
+ return id;
+ }
+
+
+struct KStartupInfoIdPrivate
+ {
+ KStartupInfoIdPrivate() : id( "" ) {}
+ QCString id; // id
+ };
+
+const QCString& KStartupInfoId::id() const
+ {
+ return d->id;
+ }
+
+
+QString KStartupInfoId::to_text() const
+ {
+ return QString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
+ }
+
+KStartupInfoId::KStartupInfoId( const QString& txt_P )
+ {
+ d = new KStartupInfoIdPrivate;
+ QStringList items = get_fields( txt_P );
+ const QString id_str = QString::fromLatin1( "ID=" );
+ for( QStringList::Iterator it = items.begin();
+ it != items.end();
+ ++it )
+ {
+ if( ( *it ).startsWith( id_str ))
+ d->id = get_cstr( *it );
+ }
+ }
+
+void KStartupInfoId::initId( const QCString& id_P )
+ {
+ if( !id_P.isEmpty())
+ {
+ d->id = id_P;
+#ifdef KSTARTUPINFO_ALL_DEBUG
+ kdDebug( 172 ) << "using: " << d->id << endl;
+#endif
+ return;
+ }
+ const char* startup_env = getenv( NET_STARTUP_ENV );
+ if( startup_env != NULL && *startup_env != '\0' )
+ { // already has id
+ d->id = startup_env;
+#ifdef KSTARTUPINFO_ALL_DEBUG
+ kdDebug( 172 ) << "reusing: " << d->id << endl;
+#endif
+ return;
+ }
+ d->id = KStartupInfo::createNewStartupId();
+ }
+
+bool KStartupInfoId::setupStartupEnv() const
+ {
+ if( id().isEmpty())
+ {
+ unsetenv( NET_STARTUP_ENV );
+ return false;
+ }
+ return setenv( NET_STARTUP_ENV, id(), true ) == 0;
+ }
+
+KStartupInfoId KStartupInfo::currentStartupIdEnv()
+ {
+ const char* startup_env = getenv( NET_STARTUP_ENV );
+ KStartupInfoId id;
+ if( startup_env != NULL && *startup_env != '\0' )
+ id.d->id = startup_env;
+ else
+ id.d->id = "0";
+ return id;
+ }
+
+void KStartupInfo::resetStartupEnv()
+ {
+ unsetenv( NET_STARTUP_ENV );
+ }
+
+KStartupInfoId::KStartupInfoId()
+ {
+ d = new KStartupInfoIdPrivate;
+ }
+
+KStartupInfoId::~KStartupInfoId()
+ {
+ delete d;
+ }
+
+KStartupInfoId::KStartupInfoId( const KStartupInfoId& id_P )
+ {
+ d = new KStartupInfoIdPrivate( *id_P.d );
+ }
+
+KStartupInfoId& KStartupInfoId::operator=( const KStartupInfoId& id_P )
+ {
+ if( &id_P == this )
+ return *this;
+ delete d;
+ d = new KStartupInfoIdPrivate( *id_P.d );
+ return *this;
+ }
+
+bool KStartupInfoId::operator==( const KStartupInfoId& id_P ) const
+ {
+ return id() == id_P.id();
+ }
+
+bool KStartupInfoId::operator!=( const KStartupInfoId& id_P ) const
+ {
+ return !(*this == id_P );
+ }
+
+// needed for QMap
+bool KStartupInfoId::operator<( const KStartupInfoId& id_P ) const
+ {
+ return id() < id_P.id();
+ }
+
+bool KStartupInfoId::none() const
+ {
+ return d->id.isEmpty() || d->id == "0";
+ }
+
+unsigned long KStartupInfoId::timestamp() const
+ {
+ if( none())
+ return 0;
+ int pos = d->id.findRev( "_TIME" );
+ if( pos >= 0 )
+ {
+ bool ok;
+ unsigned long time = d->id.mid( pos + 5 ).toULong( &ok );
+ if( !ok && d->id[ pos + 5 ] == '-' ) // try if it's as a negative signed number perhaps
+ time = d->id.mid( pos + 5 ).toLong( &ok );
+ if( ok )
+ return time;
+ }
+ // libstartup-notification style :
+ // snprintf (s, len, "%s/%s/%lu/%d-%d-%s",
+ // canonicalized_launcher, canonicalized_launchee, (unsigned long) timestamp,
+ // (int) getpid (), (int) sequence_number, hostbuf);
+ int pos1 = d->id.findRev( '/' );
+ if( pos1 > 0 )
+ {
+ int pos2 = d->id.findRev( '/', pos1 - 1 );
+ if( pos2 >= 0 )
+ {
+ bool ok;
+ unsigned long time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toULong( &ok );
+ if( !ok && d->id[ pos2 + 1 ] == '-' ) // try if it's as a negative signed number perhaps
+ time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toLong( &ok );
+ if( ok )
+ return time;
+ }
+ }
+ // bah ... old KStartupInfo or a problem
+ return 0;
+ }
+
+struct KStartupInfoDataPrivate
+ {
+ KStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
+ silent( KStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ) {}
+ QString bin;
+ QString name;
+ QString description;
+ QString icon;
+ int desktop;
+ QValueList< pid_t > pids;
+ QCString wmclass;
+ QCString hostname;
+ KStartupInfoData::TriState silent;
+ unsigned long timestamp;
+ int screen;
+ };
+
+QString KStartupInfoData::to_text() const
+ {
+ QString ret = "";
+ if( !d->bin.isEmpty())
+ ret += QString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin ));
+ if( !d->name.isEmpty())
+ ret += QString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name ));
+ if( !d->description.isEmpty())
+ ret += QString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description ));
+ if( !d->icon.isEmpty())
+ ret += QString::fromLatin1( " ICON=%1" ).arg( d->icon );
+ if( d->desktop != 0 )
+ ret += QString::fromLatin1( " DESKTOP=%1" )
+ .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 ); // spec counts from 0
+ if( !d->wmclass.isEmpty())
+ ret += QString::fromLatin1( " WMCLASS=\"%1\"" ).arg( d->wmclass );
+ if( !d->hostname.isEmpty())
+ ret += QString::fromLatin1( " HOSTNAME=%1" ).arg( d->hostname );
+ for( QValueList< pid_t >::ConstIterator it = d->pids.begin();
+ it != d->pids.end();
+ ++it )
+ ret += QString::fromLatin1( " PID=%1" ).arg( *it );
+ if( d->silent != Unknown )
+ ret += QString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 );
+ if( d->timestamp != -1U )
+ ret += QString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
+ if( d->screen != -1 )
+ ret += QString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
+ return ret;
+ }
+
+KStartupInfoData::KStartupInfoData( const QString& txt_P )
+ {
+ d = new KStartupInfoDataPrivate;
+ QStringList items = get_fields( txt_P );
+ const QString bin_str = QString::fromLatin1( "BIN=" );
+ const QString name_str = QString::fromLatin1( "NAME=" );
+ const QString description_str = QString::fromLatin1( "DESCRIPTION=" );
+ const QString icon_str = QString::fromLatin1( "ICON=" );
+ const QString desktop_str = QString::fromLatin1( "DESKTOP=" );
+ const QString wmclass_str = QString::fromLatin1( "WMCLASS=" );
+ const QString hostname_str = QString::fromLatin1( "HOSTNAME=" ); // SELI nonstd
+ const QString pid_str = QString::fromLatin1( "PID=" ); // SELI nonstd
+ const QString silent_str = QString::fromLatin1( "SILENT=" );
+ const QString timestamp_str = QString::fromLatin1( "TIMESTAMP=" );
+ const QString screen_str = QString::fromLatin1( "SCREEN=" );
+ for( QStringList::Iterator it = items.begin();
+ it != items.end();
+ ++it )
+ {
+ if( ( *it ).startsWith( bin_str ))
+ d->bin = get_str( *it );
+ else if( ( *it ).startsWith( name_str ))
+ d->name = get_str( *it );
+ else if( ( *it ).startsWith( description_str ))
+ d->description = get_str( *it );
+ else if( ( *it ).startsWith( icon_str ))
+ d->icon = get_str( *it );
+ else if( ( *it ).startsWith( desktop_str ))
+ {
+ d->desktop = get_num( *it );
+ if( d->desktop != NET::OnAllDesktops )
+ ++d->desktop; // spec counts from 0
+ }
+ else if( ( *it ).startsWith( wmclass_str ))
+ d->wmclass = get_cstr( *it );
+ else if( ( *it ).startsWith( hostname_str ))
+ d->hostname = get_cstr( *it );
+ else if( ( *it ).startsWith( pid_str ))
+ addPid( get_num( *it ));
+ else if( ( *it ).startsWith( silent_str ))
+ d->silent = get_num( *it ) != 0 ? Yes : No;
+ else if( ( *it ).startsWith( timestamp_str ))
+ d->timestamp = get_unum( *it );
+ else if( ( *it ).startsWith( screen_str ))
+ d->screen = get_num( *it );
+ }
+ }
+
+KStartupInfoData::KStartupInfoData( const KStartupInfoData& data )
+{
+ d = new KStartupInfoDataPrivate( *data.d );
+}
+
+KStartupInfoData& KStartupInfoData::operator=( const KStartupInfoData& data )
+{
+ if( &data == this )
+ return *this;
+ delete d;
+ d = new KStartupInfoDataPrivate( *data.d );
+ return *this;
+}
+
+void KStartupInfoData::update( const KStartupInfoData& data_P )
+ {
+ if( !data_P.bin().isEmpty())
+ d->bin = data_P.bin();
+ if( !data_P.name().isEmpty() && name().isEmpty()) // don't overwrite
+ d->name = data_P.name();
+ if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite
+ d->description = data_P.description();
+ if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite
+ d->icon = data_P.icon();
+ if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite
+ d->desktop = data_P.desktop();
+ if( !data_P.d->wmclass.isEmpty())
+ d->wmclass = data_P.d->wmclass;
+ if( !data_P.d->hostname.isEmpty())
+ d->hostname = data_P.d->hostname;
+ for( QValueList< pid_t >::ConstIterator it = data_P.d->pids.begin();
+ it != data_P.d->pids.end();
+ ++it )
+ addPid( *it );
+ if( data_P.silent() != Unknown )
+ d->silent = data_P.silent();
+ if( data_P.timestamp() != -1U && timestamp() == -1U ) // don't overwrite
+ d->timestamp = data_P.timestamp();
+ if( data_P.screen() != -1 )
+ d->screen = data_P.screen();
+ }
+
+KStartupInfoData::KStartupInfoData()
+{
+ d = new KStartupInfoDataPrivate;
+}
+
+KStartupInfoData::~KStartupInfoData()
+{
+ delete d;
+}
+
+void KStartupInfoData::setBin( const QString& bin_P )
+ {
+ d->bin = bin_P;
+ }
+
+const QString& KStartupInfoData::bin() const
+ {
+ return d->bin;
+ }
+
+void KStartupInfoData::setName( const QString& name_P )
+ {
+ d->name = name_P;
+ }
+
+const QString& KStartupInfoData::name() const
+ {
+ return d->name;
+ }
+
+const QString& KStartupInfoData::findName() const
+ {
+ if( !name().isEmpty())
+ return name();
+ return bin();
+ }
+
+void KStartupInfoData::setDescription( const QString& desc_P )
+ {
+ d->description = desc_P;
+ }
+
+const QString& KStartupInfoData::description() const
+ {
+ return d->description;
+ }
+
+const QString& KStartupInfoData::findDescription() const
+ {
+ if( !description().isEmpty())
+ return description();
+ return name();
+ }
+
+void KStartupInfoData::setIcon( const QString& icon_P )
+ {
+ d->icon = icon_P;
+ }
+
+const QString& KStartupInfoData::findIcon() const
+ {
+ if( !icon().isEmpty())
+ return icon();
+ return bin();
+ }
+
+const QString& KStartupInfoData::icon() const
+ {
+ return d->icon;
+ }
+
+void KStartupInfoData::setDesktop( int desktop_P )
+ {
+ d->desktop = desktop_P;
+ }
+
+int KStartupInfoData::desktop() const
+ {
+ return d->desktop;
+ }
+
+void KStartupInfoData::setWMClass( const QCString& wmclass_P )
+ {
+ d->wmclass = wmclass_P;
+ }
+
+const QCString KStartupInfoData::findWMClass() const
+ {
+ if( !WMClass().isEmpty() && WMClass() != "0" )
+ return WMClass();
+ return bin().utf8();
+ }
+
+const QCString& KStartupInfoData::WMClass() const
+ {
+ return d->wmclass;
+ }
+
+void KStartupInfoData::setHostname( const QCString& hostname_P )
+ {
+ if( !hostname_P.isNull())
+ d->hostname = hostname_P;
+ else
+ {
+ char tmp[ 256 ];
+ tmp[ 0 ] = '\0';
+ if (!gethostname( tmp, 255 ))
+ tmp[sizeof(tmp)-1] = '\0';
+ d->hostname = tmp;
+ }
+ }
+
+const QCString& KStartupInfoData::hostname() const
+ {
+ return d->hostname;
+ }
+
+void KStartupInfoData::addPid( pid_t pid_P )
+ {
+ if( !d->pids.contains( pid_P ))
+ d->pids.append( pid_P );
+ }
+
+void KStartupInfoData::remove_pid( pid_t pid_P )
+ {
+ d->pids.remove( pid_P );
+ }
+
+const QValueList< pid_t >& KStartupInfoData::pids() const
+ {
+ return d->pids;
+ }
+
+bool KStartupInfoData::is_pid( pid_t pid_P ) const
+ {
+ return d->pids.contains( pid_P );
+ }
+
+void KStartupInfoData::setSilent( TriState state_P )
+ {
+ d->silent = state_P;
+ }
+
+KStartupInfoData::TriState KStartupInfoData::silent() const
+ {
+ return d->silent;
+ }
+
+void KStartupInfoData::setTimestamp( unsigned long time )
+ {
+ d->timestamp = time;
+ }
+
+unsigned long KStartupInfoData::timestamp() const
+ {
+ return d->timestamp;
+ }
+
+void KStartupInfoData::setScreen( int screen )
+ {
+ d->screen = screen;
+ }
+
+int KStartupInfoData::screen() const
+ {
+ return d->screen;
+ }
+
+static
+long get_num( const QString& item_P )
+ {
+ unsigned int pos = item_P.find( '=' );
+ return item_P.mid( pos + 1 ).toLong();
+ }
+
+static
+unsigned long get_unum( const QString& item_P )
+ {
+ unsigned int pos = item_P.find( '=' );
+ return item_P.mid( pos + 1 ).toULong();
+ }
+
+static
+QString get_str( const QString& item_P )
+ {
+ unsigned int pos = item_P.find( '=' );
+ if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == '\"' )
+ {
+ int pos2 = item_P.left( pos + 2 ).find( '\"' );
+ if( pos2 < 0 )
+ return QString::null; // 01234
+ return item_P.mid( pos + 2, pos2 - 2 - pos ); // A="C"
+ }
+ return item_P.mid( pos + 1 );
+ }
+
+static
+QCString get_cstr( const QString& item_P )
+ {
+ return get_str( item_P ).utf8();
+ }
+
+static
+QStringList get_fields( const QString& txt_P )
+ {
+ QString txt = txt_P.simplifyWhiteSpace();
+ QStringList ret;
+ QString item = "";
+ bool in = false;
+ bool escape = false;
+ for( unsigned int pos = 0;
+ pos < txt.length();
+ ++pos )
+ {
+ if( escape )
+ {
+ item += txt[ pos ];
+ escape = false;
+ }
+ else if( txt[ pos ] == '\\' )
+ escape = true;
+ else if( txt[ pos ] == '\"' )
+ in = !in;
+ else if( txt[ pos ] == ' ' && !in )
+ {
+ ret.append( item );
+ item = "";
+ }
+ else
+ item += txt[ pos ];
+ }
+ ret.append( item );
+ return ret;
+ }
+
+static QString escape_str( const QString& str_P )
+ {
+ QString ret = "";
+ for( unsigned int pos = 0;
+ pos < str_P.length();
+ ++pos )
+ {
+ if( str_P[ pos ] == '\\'
+ || str_P[ pos ] == '"' )
+ ret += '\\';
+ ret += str_P[ pos ];
+ }
+ return ret;
+ }
+
+#include "kstartupinfo.moc"
+#endif
diff --git a/kdecore/kstartupinfo.h b/kdecore/kstartupinfo.h
new file mode 100644
index 000000000..e77944dd3
--- /dev/null
+++ b/kdecore/kstartupinfo.h
@@ -0,0 +1,668 @@
+/****************************************************************************
+
+ Copyright (C) 2001-2003 Lubos Lunak <l.lunak@kde.org>
+
+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 OR COPYRIGHT HOLDERS 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.
+
+****************************************************************************/
+
+#ifndef __KSTARTUPINFO_H
+#define __KSTARTUPINFO_H
+
+#include <sys/types.h>
+#include <qobject.h>
+
+#ifdef Q_WS_X11 // FIXME(E): Redo in a less X11-specific way
+
+#include <qcstring.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+#include "kdelibs_export.h"
+
+class KStartupInfoId;
+class KStartupInfoData;
+
+class KStartupInfoPrivate;
+
+/**
+ * Class for manipulating the application startup notification.
+ *
+ * This class can be used to send information about started application,
+ * change the information and receive this information. For detailed
+ * description, see kdelibs/kdecore/README.kstartupinfo.
+ *
+ * You usually don't need to use this class for sending the notification
+ * information, as KDE libraries should do this when an application is
+ * started (e.g. KRun class).
+ *
+ * For receiving the startup notification info, create an instance and connect
+ * to its slots. It will automatically detect started applications and when
+ * they are ready.
+ *
+ * @see KStartupInfoId
+ * @see KStartupInfoData
+ *
+ * @author Lubos Lunak <l.lunak@kde.org>
+ */
+class KDECORE_EXPORT KStartupInfo
+ : public QObject
+ {
+ Q_OBJECT
+ public:
+ /**
+ * By default, the startup notification is ended for the application
+ * after it shows its first toplevel window. If you app e.g. has
+ * several toplevel windows after its startup, you can disable
+ * the automatic handling, and call appStarted() manually after
+ * all toplevel windows have been shown.
+ * @since 3.2
+ */
+ static void disableAutoAppStartedSending( bool disable = true );
+
+ /**
+ * Manual notification that the application has started.
+ * If you do not map a (toplevel) window, then startup
+ * notification will not disappear for the application
+ * until a timeout. You can use this as an alternative
+ * method in this case.
+ */
+ static void appStarted();
+
+ /**
+ * Sends explicit notification that the startup notification
+ * with id startup_id should end.
+ * @since 3.2
+ */
+ static void appStarted( const QCString& startup_id );
+
+ /**
+ * Use this function if the application got a request with startup
+ * notification from outside (for example, when KUniqueApplication::newInstance()
+ * is called, or e.g. when khelpcenter opens new URL in its window).
+ * The window can be either an already existing and visible window,
+ * or a new one, before being shown. Note that this function is usually
+ * needed only when a window is reused.
+ * @since 3.2
+ */
+ static void setNewStartupId( QWidget* window, const QCString& startup_id );
+
+ /**
+ * If your application shows temporarily some window during its startup,
+ * for example a dialog, and only after closing it shows the main window,
+ * startup notification would normally be shown while the dialog is visible.
+ * To temporarily suspend and resume the notification, use this function.
+ * Note that this is cumulative, i.e. after suspending twice, you have to
+ * resume twice.
+ * @since 3.2
+ */
+ static void silenceStartup( bool silence );
+
+ /**
+ * Creates and returns new startup id. The id includes properly setup
+ * user timestamp.
+ * @since 3.3
+ */
+ static QCString createNewStartupId();
+ /**
+ *
+ */
+ enum {
+ CleanOnCantDetect = 1 << 0,
+ DisableKWinModule = 1 << 1,
+ AnnounceSilenceChanges = 1 << 2
+ };
+
+ /**
+ * Creates an instance that will receive the startup notifications.
+ * The various flags passed may be
+ * @li CleanOnCantDetect - when a new unknown window appears, all startup
+ * notifications for applications that are not compliant with
+ * the startup protocol are removed
+ * @li DisableKWinModule - KWinModule, which is normally used to detect
+ * new windows, is disabled. With this flag, checkStartup() must be
+ * called in order to check newly mapped windows.
+ * @li AnnounceSilenceChanges - normally, startup notifications are
+ * "removed" when they're silenced, and "recreated" when they're resumed.
+ * With this flag, the change is normally announced with gotStartupChange().
+ *
+ * @param flags OR-ed combination of flags
+ * @param parent the parent of this QObject (can be 0 for no parent)
+ * @param name the name of the QObject (can be 0 for no name)
+ *
+ */
+ KStartupInfo( int flags, QObject* parent = NULL, const char* name = NULL );
+ /**
+ * Creates an instance that will receive the startup notifications.
+ *
+ * @param clean_on_cantdetect if true, and a new unknown window appears,
+ * removes all notification for applications that are not compliant
+ * with the app startup protocol
+ * @param parent the parent of this QObject (can be 0 for no parent)
+ * @param name the name of the QObject (can be 0 for no name)
+ *
+ * @obsolete
+ */
+ KStartupInfo( bool clean_on_cantdetect, QObject* parent = 0, const char* name = 0 );
+ virtual ~KStartupInfo();
+ /**
+ * Sends given notification data about started application
+ * with the given startup identification. If no notification for this identification
+ * exists yet, it is created, otherwise it's updated. Note that the name field
+ * in data is required.
+ *
+ * @param id the id of the application
+ * @param data the application's data
+ * @return true if successful, false otherwise
+ * @see KStartupInfoId
+ * @see KStartupInfoData
+ */
+ static bool sendStartup( const KStartupInfoId& id, const KStartupInfoData& data );
+
+ /**
+ * Like sendStartup , uses dpy instead of qt_xdisplay() for sending the info.
+ * @param dpy the display of the application. Note that the name field
+ * in data is required.
+ * @param id the id of the application
+ * @param data the application's data
+ * @return true if successful, false otherwise
+ */
+ static bool sendStartupX( Display* dpy, const KStartupInfoId& id,
+ const KStartupInfoData& data );
+
+ /**
+ * Sends given notification data about started application
+ * with the given startup identification. This is used for updating the notification
+ * info, if no notification for this identification exists, it's ignored.
+ * @param id the id of the application
+ * @param data the application's data
+ * @return true if successful, false otherwise
+ * @see KStartupInfoId
+ * @see KStartupInfoData
+ */
+ static bool sendChange( const KStartupInfoId& id, const KStartupInfoData& data );
+
+ /**
+ * Like sendChange , uses dpy instead of qt_xdisplay() for sending the info.
+ * @param dpy the display of the application.
+ * @param id the id of the application
+ * @param data the application's data
+ * @return true if successful, false otherwise
+ */
+ static bool sendChangeX( Display* dpy, const KStartupInfoId& id,
+ const KStartupInfoData& data );
+
+ /**
+ * Ends startup notification with the given identification.
+ * @param id the id of the application
+ * @return true if successful, false otherwise
+ */
+ static bool sendFinish( const KStartupInfoId& id );
+
+ /**
+ * Like sendFinish , uses dpy instead of qt_xdisplay() for sending the info.
+ * @param dpy the display of the application.
+ * @param id the id of the application
+ * @return true if successful, false otherwise
+ */
+ static bool sendFinishX( Display* dpy, const KStartupInfoId& id );
+
+ /**
+ * Ends startup notification with the given identification and the given data ( e.g.
+ * PIDs of processes for this startup notification that exited ).
+ * @param id the id of the application
+ * @param data the application's data
+ * @return true if successful, false otherwise
+ */
+ static bool sendFinish( const KStartupInfoId& id, const KStartupInfoData& data );
+
+ /**
+ * Like sendFinish , uses dpy instead of qt_xdisplay() for sending the info.
+ * @param dpy the display of the application.
+ * @param id the id of the application
+ * @param data the application's data
+ * @return true if successful, false otherwise
+ */
+ static bool sendFinishX( Display* dpy, const KStartupInfoId& id,
+ const KStartupInfoData& data );
+
+ /**
+ * Returns the current startup notification identification for the current
+ * startup notification environment variable. Note that KApplication constructor
+ * unsets the variable and you have to use KApplication::startupId .
+ * @return the current startup notification identification
+ */
+ static KStartupInfoId currentStartupIdEnv();
+ /**
+ * Unsets the startup notification environment variable.
+ */
+ static void resetStartupEnv();
+ /**
+ * @li NoMatch - the window doesn't match any existing startup notification
+ * @li Match - the window matches an existing startup notification
+ * @li CantDetect - unable to detect if the window matches any existing
+ * startup notification
+ */
+ enum startup_t { NoMatch, Match, CantDetect };
+ /**
+ * Checks if the given windows matches any existing startup notification.
+ * @param w the window id to check
+ * @return the result of the operation
+ */
+ startup_t checkStartup( WId w );
+ /**
+ * Checks if the given windows matches any existing startup notification, and
+ * if yes, returns the identification in id.
+ * @param w the window id to check
+ * @param id if found, the id of the startup notification will be written here
+ * @return the result of the operation
+ */
+ startup_t checkStartup( WId w, KStartupInfoId& id );
+ /**
+ * Checks if the given windows matches any existing startup notification, and
+ * if yes, returns the notification data in data.
+ * @param w the window id to check
+ * @param data if found, the data of the startup notification will be written here
+ * @return the result of the operation
+ */
+ startup_t checkStartup( WId w, KStartupInfoData& data );
+ /**
+ * Checks if the given windows matches any existing startup notification, and
+ * if yes, returns the identification in id and notification data in data.
+ * @param w the window id to check
+ * @param id if found, the id of the startup notification will be written here
+ * @param data if found, the data of the startup notification will be written here
+ * @return the result of the operation
+ */
+ startup_t checkStartup( WId w, KStartupInfoId& id, KStartupInfoData& data );
+ /**
+ * Sets the timeout for notifications, after this timeout a notification is removed.
+ * @param secs the new timeout in seconds
+ */
+ void setTimeout( unsigned int secs );
+ /**
+ * Sets the startup notification window property on the given window.
+ * @param window the id of the window
+ * @param id the startup notification id
+ */
+ static void setWindowStartupId( WId window, const QCString& id );
+ /**
+ * Returns startup notification identification of the given window.
+ * @param w the id of the window
+ * @return the startup notification id. Can be null if not found.
+ */
+ static QCString windowStartupId( WId w );
+ /**
+ * @internal
+ */
+ static void handleAutoAppStartedSending();
+ /**
+ * @internal
+ */
+ class Data;
+ signals:
+ /**
+ * Emitted when a new startup notification is created (i.e. a new application is
+ * being started).
+ * @param id the notification identification
+ * @param data the notification data
+ */
+ void gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data );
+ /**
+ * Emitted when a startup notification changes.
+ * @param id the notification identification
+ * @param data the notification data
+ */
+ void gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data );
+ /**
+ * Emitted when a startup notification is removed (either because it was detected
+ * that the application is ready or because of a timeout).
+ * @param id the notification identification
+ * @param data the notification data
+ */
+ void gotRemoveStartup( const KStartupInfoId& id, const KStartupInfoData& data );
+ protected:
+ /**
+ *
+ */
+ virtual void customEvent( QCustomEvent* e_P );
+ private slots:
+ void startups_cleanup();
+ void startups_cleanup_no_age();
+ void got_message( const QString& msg );
+ void window_added( WId w );
+ void slot_window_added( WId w );
+ private:
+ void init( int flags );
+ friend class KStartupInfoPrivate;
+ void got_startup_info( const QString& msg_P, bool update_only_P );
+ void got_remove_startup_info( const QString& msg_P );
+ void new_startup_info_internal( const KStartupInfoId& id_P,
+ Data& data_P, bool update_only_P );
+ void remove_startup_info_internal( const KStartupInfoId& id_P );
+ void remove_startup_pids( const KStartupInfoId& id, const KStartupInfoData& data );
+ void remove_startup_pids( const KStartupInfoData& data );
+ startup_t check_startup_internal( WId w, KStartupInfoId* id, KStartupInfoData* data );
+ bool find_id( const QCString& id_P, KStartupInfoId* id_O,
+ KStartupInfoData* data_O );
+ bool find_pid( pid_t pid_P, const QCString& hostname, KStartupInfoId* id_O,
+ KStartupInfoData* data_O );
+ bool find_wclass( QCString res_name_P, QCString res_class_P,
+ KStartupInfoId* id_O, KStartupInfoData* data_O );
+ static QCString get_window_hostname( WId w_P );
+ void startups_cleanup_internal( bool age_P );
+ void clean_all_noncompliant();
+ static QString check_required_startup_fields( const QString& msg,
+ const KStartupInfoData& data, int screen );
+ bool clean_on_cantdetect_; // KDE4 remove unused
+ unsigned int timeout;
+ KStartupInfoPrivate* d;
+ };
+
+class KStartupInfoIdPrivate;
+
+/**
+ * Class representing an identification of application startup notification.
+ *
+ * Every existing notification about a starting application has its own unique
+ * identification, that's used to identify and manipulate the notification.
+ *
+ * @see KStartupInfo
+ * @see KStartupInfoData
+ *
+ * @author Lubos Lunak <l.lunak@kde.org>
+ */
+class KDECORE_EXPORT KStartupInfoId
+ {
+ public:
+ /**
+ * Overloaded operator.
+ * @return true if the notification identifications are the same
+ */
+ bool operator==( const KStartupInfoId& id ) const;
+ /**
+ * Overloaded operator.
+ * @return true if the notification identifications are different
+ */
+ bool operator!=( const KStartupInfoId& id ) const;
+ /**
+ * Checks whether the identifier is valid.
+ * @return true if this object doesn't represent a valid notification identification
+ */
+ bool none() const;
+ /**
+ * Initializes this object with the given identification ( which may be also "0"
+ * for no notification ), or if "" is given, tries to read it from the startup
+ * notification environment variable, and if it's not set, creates a new one.
+ * @param id the new identification, "0" for no notification or "" to read
+ * the environment variable
+ */
+ void initId( const QCString& id = "" );
+ /**
+ * Returns the notification identifier as string.
+ * @return the identification string for the notification
+ */
+ const QCString& id() const;
+ /**
+ * Return the user timestamp for the startup notification, or 0 if no timestamp
+ * is set.
+ * @since 3.3
+ */
+ unsigned long timestamp() const;
+ /**
+ * Sets the startup notification environment variable to this identification.
+ * @return true if successful, false otherwise
+ */
+ bool setupStartupEnv() const;
+ /**
+ * Creates an empty identification
+ */
+ KStartupInfoId();
+ /**
+ * Copy constructor.
+ */
+ KStartupInfoId( const KStartupInfoId& data );
+ ~KStartupInfoId();
+ KStartupInfoId& operator=( const KStartupInfoId& data );
+ bool operator<( const KStartupInfoId& id ) const;
+ private:
+ KStartupInfoId( const QString& txt );
+ QString to_text() const;
+ friend class KStartupInfo;
+ KStartupInfoIdPrivate* d;
+ };
+
+class KStartupInfoDataPrivate;
+
+/**
+ * Class representing data about an application startup notification.
+ *
+ * Such data include the icon of the starting application, the desktop on which
+ * the application should start, the binary name of the application, etc.
+ *
+ * @see KStartupInfo
+ * @see KStartupInfoId
+ *
+ * @author Lubos Lunak <l.lunak@kde.org>
+ */
+class KDECORE_EXPORT KStartupInfoData
+ {
+ public:
+ /**
+ * Sets the binary name of the application ( e.g. 'kcontrol' ).
+ * @param bin the new binary name of the application
+ */
+ void setBin( const QString& bin );
+ /**
+ * Returns the binary name of the starting application
+ * @return the new binary name of the application
+ */
+ const QString& bin() const;
+ /**
+ * Sets the name for the notification (e.g. 'Control Center')
+ */
+ void setName( const QString& name );
+ /**
+ * Returns the name of the startup notification. If it's not available,
+ * it tries to use other information (binary name).
+ * @return the name of the startup notification
+ */
+ const QString& findName() const;
+ /**
+ * Returns the name of the startup notification, or empty if not available.
+ * @return the name of the startup notification, or an empty string
+ * if not set.
+ */
+ const QString& name() const;
+ /**
+ * Sets the description for the notification (e.g. 'Launching Control Center').
+ * I.e. name() describes what is being started, while description() is
+ * the actual action performed by the starting.
+ * @since 3.2
+ */
+ void setDescription( const QString& descr );
+ /**
+ * Returns the description of the startup notification. If it's not available,
+ * it returns name().
+ * @return the description of the startup notification
+ * @since 3.2
+ */
+ const QString& findDescription() const;
+ /**
+ * Returns the name of the startup notification, or empty if not available.
+ * @return the name of the startup notificaiton, or an empty string
+ * if not set.
+ * @since 3.2
+ */
+ const QString& description() const;
+ /**
+ * Sets the icon for the startup notification ( e.g. 'kcontrol' )
+ * @param icon the name of the icon
+ */
+ void setIcon( const QString& icon );
+ /**
+ * Returns the icon of the startup notification, and if it's not available,
+ * tries to get it from the binary name.
+ * @return the name of the startup notification's icon, or the name of
+ * the binary if not set
+ */
+ const QString& findIcon() const;
+ /**
+ * Returns the icon of the startup notification, or empty if not available.
+ * @return the name of the icon, or an empty string if not set.
+ */
+ const QString& icon() const;
+ /**
+ * Sets the desktop for the startup notification ( i.e. the desktop on which
+ * the starting application should appear ).
+ * @param desktop the desktop for the startup notification
+ */
+ void setDesktop( int desktop );
+ /**
+ * Returns the desktop for the startup notification.
+ * @return the desktop for the startup notification
+ */
+ int desktop() const;
+ /**
+ * Sets a WM_CLASS value for the startup notification, it may be used for increasing
+ * the chance that the windows created by the starting application will be
+ * detected correctly.
+ * @param wmclass the WM_CLASS value for the startup notification
+ */
+ void setWMClass( const QCString& wmclass );
+ /**
+ * Returns the WM_CLASS value for the startup notification, or binary name if not
+ * available.
+ * @return the WM_CLASS value for the startup notification, or the binary name
+ * if not set
+ */
+ const QCString findWMClass() const;
+ /**
+ * Returns the WM_CLASS value for the startup notification, or empty if not available.
+ * @return the WM_CLASS value for the startup notification, or empty
+ * if not set
+ */
+ const QCString& WMClass() const;
+ /**
+ * Adds a PID to the list of processes that belong to the startup notification. It
+ * may be used to increase the chance that the windows created by the starting
+ * application will be detected correctly, and also for detecting if the application
+ * has quit without creating any window.
+ * @param pid the PID to add
+ */
+ void addPid( pid_t pid );
+ /**
+ * Returns all PIDs for the startup notification.
+ * @return the list of all PIDs
+ */
+ const QValueList< pid_t >& pids() const;
+ /**
+ * Checks whether the given @p pid is in the list of PIDs for starup
+ * notification.
+ * @return true if the given @p pid is in the list of PIDs for the startup notification
+ */
+ bool is_pid( pid_t pid ) const;
+ /**
+ * Sets the hostname on which the application is starting. It's necessary to set
+ * it if PIDs are set.
+ * @param hostname the application's hostname. If it's a null string, the current hostname is used
+ */
+ void setHostname( const QCString& hostname = QCString());
+ /**
+ * Returns the hostname for the startup notification.
+ * @return the hostname
+ */
+ const QCString& hostname() const;
+
+ /**
+ *
+ */
+ enum TriState { Yes, No, Unknown };
+
+ /**
+ * Sets whether the visual feedback for this startup notification
+ * should be silenced (temporarily suspended).
+ * @since 3.1.1
+ */
+ void setSilent( TriState state );
+
+ /**
+ * Return the silence status for the startup notification.
+ * @return KStartupInfoData::Yes if visual feedback is silenced
+ * @since 3.1.1
+ */
+ TriState silent() const;
+
+ /**
+ * @obsolete Timestamp is already assigned in KStartupInfoId::initId().
+ * Sets timestamp for the startup notification. The timestamp is expressed
+ * as XServer time, and is used to prevent activation of the matching
+ * window if user interaction took place after this timestamp.
+ * Value -1 means no timestamp set, value 0 means that the window should
+ * not be activated.
+ */
+ void setTimestamp( unsigned long time );
+
+ /**
+ * @obsolete Use KStartupInfoId::timestamp().
+ * Return the timestamp for the startup notification, or -1 if no timestamp
+ * is set.
+ */
+ unsigned long timestamp() const;
+
+ /**
+ * The X11 screen on which the startup notification is happening, -1 if unknown.
+ */
+ int screen() const;
+
+ /**
+ * Sets the X11 screen on which the startup notification should happen.
+ * This is usually not necessary to set, as it's set by default to qt_xscreen().
+ */
+ void setScreen( int screen );
+
+ /**
+ * Updates the notification data from the given data. Some data, such as the desktop
+ * or the name, won't be rewritten if already set.
+ * @param data the data to update
+ */
+ void update( const KStartupInfoData& data );
+
+ /**
+ * Constructor. Initializes all the data to their default empty values.
+ */
+ KStartupInfoData();
+
+ /**
+ * Copy constructor.
+ */
+ KStartupInfoData( const KStartupInfoData& data );
+ ~KStartupInfoData();
+ KStartupInfoData& operator=( const KStartupInfoData& data );
+ private:
+ KStartupInfoData( const QString& txt );
+ QString to_text() const;
+ void remove_pid( pid_t pid );
+ friend class KStartupInfo;
+ friend class KStartupInfo::Data;
+ KStartupInfoDataPrivate* d;
+ };
+
+#endif //Q_WS_X11
+
+#endif
diff --git a/kdecore/kstaticdeleter.cpp b/kdecore/kstaticdeleter.cpp
new file mode 100644
index 000000000..27c5cdf6b
--- /dev/null
+++ b/kdecore/kstaticdeleter.cpp
@@ -0,0 +1,10 @@
+
+#include <kstaticdeleter.h>
+
+// this helps gcc to emit the vtbl for KStaticDeleterBase
+// only once, here in this file, not every time it's
+// used, says Seli.
+void KStaticDeleterBase::destructObject()
+{
+}
+
diff --git a/kdecore/kstaticdeleter.h b/kdecore/kstaticdeleter.h
new file mode 100644
index 000000000..ee3e5755c
--- /dev/null
+++ b/kdecore/kstaticdeleter.h
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ * 2001 KDE Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _KSTATIC_DELETER_H_
+#define _KSTATIC_DELETER_H_
+
+#include <kglobal.h>
+
+/**
+ * Static deleters are used to manage static resources. They can register
+ * themselves with KGlobal. KGlobal will call destructObject() when
+ * KGlobal::deleteStaticDeleters() is called or when it the process
+ * finishes.
+ *
+ * @see KStaticDeleter
+ * @see KGlobal::registerStaticDeleter()
+ * @see KGlobal::unregisterStaticDeleter()
+ * @see KGlobal::deleteStaticDeleters()
+ */
+class KDECORE_EXPORT KStaticDeleterBase {
+public:
+ virtual ~KStaticDeleterBase() { }
+ /**
+ * Should destruct the resources managed by this KStaticDeleterBase.
+ * Usually you also want to call it in your destructor.
+ * @see KGlobal::deleteStaticDeleters()
+ */
+ virtual void destructObject();
+};
+
+/**
+ * Little helper class to clean up static objects that are
+ * held as pointer.
+ * When the library is unloaded, or the app terminated, all static deleters
+ * are destroyed, which in turn destroys those static objects properly.
+ * There are some rules which you should accept in the KStaticDeleter managed
+ * class:
+ * @li Don't rely on the global reference variable in the destructor of the
+ * object, it will be '0' at destruction time.
+ * @li Don't rely on other KStaticDeleter managed objects in the destructor
+ * of the object, because it may be destroyed before your destructor get called.
+ * This one can be tricky, because you might not know that you actually use a
+ * KStaticDeleter managed class. So try to keep your destructor simple.
+ *
+ * A typical use is
+ * \code
+ * static KStaticDeleter<MyClass> sd;
+ *
+ * MyClass &MyClass::self() {
+ * if (!_self) { sd.setObject(_self, new MyClass()); }
+ * return *_self;
+ * }
+ * \endcode
+ */
+template<class type> class KStaticDeleter : public KStaticDeleterBase {
+public:
+ KStaticDeleter() { deleteit = 0; globalReference = 0; array = false; }
+ /**
+ * Sets the object to delete and registers the object to be
+ * deleted to KGlobal. If the given object is 0, the former
+ * registration is unregistered.
+ * @param obj the object to delete
+ * @param isArray tells the destructor to delete an array instead of an object
+ * @deprecated See the other setObject variant.
+ **/
+ KDE_DEPRECATED type *setObject( type *obj, bool isArray = false) {
+ deleteit = obj;
+ globalReference = 0;
+ array = isArray;
+ if (obj)
+ KGlobal::registerStaticDeleter(this);
+ else
+ KGlobal::unregisterStaticDeleter(this);
+ return obj;
+ }
+ /**
+ * Sets the object to delete and registers the object to be
+ * deleted to KGlobal. If the given object is 0, the former
+ * registration is unregistered.
+ * @param globalRef the static pointer where this object is stored
+ * This pointer will be reset to 0 after deletion of the object.
+ * @param obj the object to delete
+ * @param isArray tells the destructor to delete an array instead of an object
+ **/
+ type *setObject( type* & globalRef, type *obj, bool isArray = false) {
+ globalReference = &globalRef;
+ deleteit = obj;
+ array = isArray;
+ if (obj)
+ KGlobal::registerStaticDeleter(this);
+ else
+ KGlobal::unregisterStaticDeleter(this);
+ globalRef = obj;
+ return obj;
+ }
+
+ /**
+ * Destructs the object. This has the same effect as deleting
+ * the KStaticDeleter.
+ */
+ virtual void destructObject() {
+ if (globalReference)
+ *globalReference = 0;
+ if (array)
+ delete [] deleteit;
+ else
+ delete deleteit;
+ deleteit = 0;
+ }
+ virtual ~KStaticDeleter() {
+ KGlobal::unregisterStaticDeleter(this);
+ destructObject();
+ }
+private:
+ type *deleteit;
+ type **globalReference;
+ bool array;
+};
+
+#endif
diff --git a/kdecore/kstdaccel.cpp b/kdecore/kstdaccel.cpp
new file mode 100644
index 000000000..262535e45
--- /dev/null
+++ b/kdecore/kstdaccel.cpp
@@ -0,0 +1,396 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stefan Taferner (taferner@alpin.or.at)
+ Copyright (C) 2000 Nicolas Hadacek (haadcek@kde.org)
+ Copyright (C) 2001,2002 Ellis Whitehead (ellis@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#define __KSTDACCEL_CPP_ 1
+
+#include "kstdaccel.h"
+
+#include "kaccelaction.h"
+#include "kaccelbase.h"
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kshortcut.h>
+#include <kshortcutlist.h>
+
+namespace KStdAccel
+{
+
+struct KStdAccelInfo
+{
+ StdAccel id;
+ const char* psName;
+ const char* psDesc;
+ int cutDefault, cutDefault4, cutDefault3B, cutDefault4B;
+ KShortcut cut;
+ bool bInitialized;
+};
+
+/** Array of predefined KStdAccelInfo objects, which cover all
+ the "standard" accelerators. Each enum value from StdAccel
+ should appear in this table.
+*/
+static KStdAccelInfo g_infoStdAccel[] =
+{
+ {AccelNone, "Group:File", I18N_NOOP("File"), 0, 0, 0, 0, KShortcut(), false },
+ { Open, I18N_NOOP("Open"), 0, Qt::CTRL+Qt::Key_O, 0, 0, 0, KShortcut(), false },
+ { New, I18N_NOOP("New"), 0, Qt::CTRL+Qt::Key_N, 0, 0, 0, KShortcut(), false },
+ { Close, I18N_NOOP("Close"), 0, Qt::CTRL+Qt::Key_W, Qt::CTRL+Qt::Key_Escape, 0, Qt::CTRL+Qt::Key_W, KShortcut(), false },
+ { Save, I18N_NOOP("Save"), 0, Qt::CTRL+Qt::Key_S, 0, 0, 0, KShortcut(), false },
+ { Print, I18N_NOOP("Print"), 0, Qt::CTRL+Qt::Key_P, 0, 0, 0, KShortcut(), false },
+ { Quit, I18N_NOOP("Quit"), 0, Qt::CTRL+Qt::Key_Q, 0, 0, 0, KShortcut(), false },
+ {AccelNone, "Group:Edit", I18N_NOOP("Edit"), 0, 0, 0, 0, KShortcut(), false },
+ { Undo, I18N_NOOP("Undo"), 0, Qt::CTRL+Qt::Key_Z, 0, 0, 0, KShortcut(), false },
+ { Redo, I18N_NOOP("Redo"), 0, Qt::CTRL+Qt::SHIFT+Qt::Key_Z, 0, 0, 0, KShortcut(), false },
+ { Cut, I18N_NOOP("Cut"), 0, Qt::CTRL+Qt::Key_X, 0, Qt::SHIFT+Qt::Key_Delete, 0, KShortcut(), false },
+ { Copy, I18N_NOOP("Copy"), 0, Qt::CTRL+Qt::Key_C, 0, Qt::CTRL+Qt::Key_Insert, 0, KShortcut(), false },
+ { Paste, I18N_NOOP("Paste"), 0, Qt::CTRL+Qt::Key_V, 0, Qt::SHIFT+Qt::Key_Insert, 0, KShortcut(), false },
+ { PasteSelection, I18N_NOOP("Paste Selection"), 0, 0, 0, Qt::CTRL+Qt::SHIFT+Qt::Key_Insert, 0, KShortcut(), false },
+ { SelectAll, "SelectAll", I18N_NOOP("Select All"), Qt::CTRL+Qt::Key_A, 0, 0, 0, KShortcut(), false },
+ { Deselect, I18N_NOOP("Deselect"), 0, Qt::CTRL+Qt::SHIFT+Qt::Key_A, 0, 0, 0, KShortcut(), false },
+ { DeleteWordBack, "DeleteWordBack", I18N_NOOP("Delete Word Backwards"), Qt::CTRL+Qt::Key_Backspace, 0, 0, 0, KShortcut(), false },
+ { DeleteWordForward, "DeleteWordForward", I18N_NOOP("Delete Word Forward"), Qt::CTRL+Qt::Key_Delete, 0, 0, 0, KShortcut(), false },
+ { Find, I18N_NOOP("Find"), 0, Qt::CTRL+Qt::Key_F, 0, 0, 0, KShortcut(), false },
+ { FindNext, "FindNext", I18N_NOOP("Find Next"), Qt::Key_F3, 0, 0, 0, KShortcut(), false },
+ { FindPrev, "FindPrev", I18N_NOOP("Find Prev"), Qt::SHIFT+Qt::Key_F3, 0, 0, 0, KShortcut(), false },
+ { Replace, I18N_NOOP("Replace"), 0, Qt::CTRL+Qt::Key_R, 0, 0, 0, KShortcut(), false },
+ {AccelNone, "Group:Navigation", I18N_NOOP("Navigation"), 0, 0, 0, 0, KShortcut(), false },
+ { Home, I18N_NOOP2("Opposite to End","Home"), 0, Qt::CTRL+Qt::Key_Home, 0, Qt::Key_HomePage, 0, KShortcut(), false },
+ { End, I18N_NOOP("End"), 0, Qt::CTRL+Qt::Key_End, 0, 0, 0, KShortcut(), false },
+ { BeginningOfLine, "BeginningOfLine", I18N_NOOP("Beginning of Line"), Qt::Key_Home, 0, 0, 0, KShortcut(), false},
+ { EndOfLine, "EndOfLine", I18N_NOOP("End of Line"), Qt::Key_End, 0, 0, 0, KShortcut(), false},
+ { Prior, I18N_NOOP("Prior"), 0, Qt::Key_Prior, 0, 0, 0, KShortcut(), false },
+ { Next, I18N_NOOP2("Opposite to Prior","Next"), 0, Qt::Key_Next, 0, 0, 0, KShortcut(), false },
+ { GotoLine, "GotoLine", I18N_NOOP("Go to Line"), Qt::CTRL+Qt::Key_G, 0, 0, 0, KShortcut(), false },
+ { AddBookmark, "AddBookmark", I18N_NOOP("Add Bookmark"), Qt::CTRL+Qt::Key_B, 0, 0, 0, KShortcut(), false },
+ { ZoomIn, "ZoomIn", I18N_NOOP("Zoom In"), Qt::CTRL+Qt::Key_Plus, 0, 0, 0, KShortcut(), false },
+ { ZoomOut, "ZoomOut", I18N_NOOP("Zoom Out"), Qt::CTRL+Qt::Key_Minus, 0, 0, 0, KShortcut(), false },
+ { Up, I18N_NOOP("Up"), 0, Qt::ALT+Qt::Key_Up, 0, 0, 0, KShortcut(), false },
+ { Back, I18N_NOOP("Back"), 0, Qt::ALT+Qt::Key_Left, 0, Qt::Key_Back, 0, KShortcut(), false },
+ { Forward, I18N_NOOP("Forward"), 0, Qt::ALT+Qt::Key_Right, 0, Qt::Key_Forward, 0, KShortcut(), false },
+ { Reload, I18N_NOOP("Reload"), 0, Qt::Key_F5, 0, Qt::Key_Refresh, 0, KShortcut(), false },
+ { PopupMenuContext, "PopupMenuContext", I18N_NOOP("Popup Menu Context"), Qt::Key_Menu, 0, 0, 0, KShortcut(), false },
+ { ShowMenubar, "ShowMenubar", I18N_NOOP("Show Menu Bar"), Qt::CTRL+Qt::Key_M, 0, 0, 0, KShortcut(), false },
+ { BackwardWord, "BackwardWord", I18N_NOOP("Backward Word"), Qt::CTRL+Qt::Key_Left, 0, 0, 0, KShortcut(), false },
+ { ForwardWord, "ForwardWord", I18N_NOOP("Forward Word"), Qt::CTRL+Qt::Key_Right, 0, 0, 0, KShortcut(), false },
+ { TabNext, I18N_NOOP("Activate Next Tab"), 0, Qt::CTRL+Qt::Key_Period, 0, Qt::CTRL+Qt::Key_BracketRight, 0, KShortcut(), false },
+ { TabPrev, I18N_NOOP("Activate Previous Tab"), 0, Qt::CTRL+Qt::Key_Comma, 0, Qt::CTRL+Qt::Key_BracketLeft, 0, KShortcut(), false },
+ { FullScreen, "FullScreen", I18N_NOOP("Full Screen Mode"), Qt::CTRL+Qt::SHIFT+Qt::Key_F, 0, 0, 0, KShortcut(), false },
+ {AccelNone, "Group:Help", I18N_NOOP("Help"), 0, 0, 0, 0, KShortcut(), false },
+ { Help, I18N_NOOP("Help"), 0, Qt::Key_F1, 0, 0, 0, KShortcut(), false },
+ { WhatsThis, "WhatsThis", I18N_NOOP("What's This"), Qt::SHIFT+Qt::Key_F1, 0, 0, 0, KShortcut(), false },
+ {AccelNone, "Group:TextCompletion", I18N_NOOP("Text Completion"), 0, 0, 0, 0, KShortcut(), false },
+ { TextCompletion, "TextCompletion", I18N_NOOP("Text Completion"), Qt::CTRL+Qt::Key_E, 0, 0, 0, KShortcut(), false },
+ { PrevCompletion, "PrevCompletion", I18N_NOOP("Previous Completion Match"), Qt::CTRL+Qt::Key_Up, 0, 0, 0, KShortcut(), false },
+ { NextCompletion, "NextCompletion", I18N_NOOP("Next Completion Match"), Qt::CTRL+Qt::Key_Down, 0, 0, 0, KShortcut(), false },
+ { SubstringCompletion, "SubstringCompletion", I18N_NOOP("Substring Completion"), Qt::CTRL+Qt::Key_T, 0, 0, 0, KShortcut(), false },
+ { RotateUp, "RotateUp", I18N_NOOP("Previous Item in List"), Qt::Key_Up, 0, 0, 0, KShortcut(), false },
+ { RotateDown, "RotateDown", I18N_NOOP("Next Item in List"), Qt::Key_Down, 0, 0, 0, KShortcut(), false },
+ { AccelNone, 0, 0, 0, 0, 0, 0, KShortcut(), false }
+};
+
+/** Search for the KStdAccelInfo object associated with the given @p id. */
+static KStdAccelInfo* infoPtr( StdAccel id )
+{
+ if( id != AccelNone ) {
+ // Linear search. Changing the data structure doesn't seem possible
+ // (since we need groups for the config stuff), but maybe a little
+ // additional hashtable wouldn't hurt.
+ for( uint i = 0; g_infoStdAccel[i].psName != 0; i++ ) {
+ if( g_infoStdAccel[i].id == id )
+ return &g_infoStdAccel[i];
+ }
+ }
+ return 0;
+}
+
+/** Initialize the accelerator @p id by checking if it is overridden
+ in the configuration file (and if it isn't, use the default).
+*/
+static void initialize( StdAccel id )
+{
+ KConfigGroupSaver saver( KGlobal::config(), "Shortcuts" );
+ KStdAccelInfo* pInfo = infoPtr( id );
+
+ if( !pInfo ) {
+ kdWarning(125) << "KStdAccel: id not found!" << endl; // -- ellis
+ return;
+ }
+
+ if( saver.config()->hasKey( pInfo->psName ) ) {
+ QString s = saver.config()->readEntry( pInfo->psName );
+ if( s != "none" )
+ pInfo->cut.init( s );
+ else
+ pInfo->cut.clear();
+ } else
+ pInfo->cut = shortcutDefault( id );
+ pInfo->bInitialized = true;
+}
+
+QString name( StdAccel id )
+{
+ KStdAccelInfo* pInfo = infoPtr( id );
+ if( !pInfo )
+ return QString::null;
+ return pInfo->psName;
+}
+
+QString label( StdAccel id )
+{
+ KStdAccelInfo* pInfo = infoPtr( id );
+ if( !pInfo )
+ return QString::null;
+ return i18n((pInfo->psDesc) ? pInfo->psDesc : pInfo->psName);
+}
+
+// TODO: Add psWhatsThis entry to KStdAccelInfo
+QString whatsThis( StdAccel /*id*/ )
+{
+// KStdAccelInfo* pInfo = infoPtr( id );
+// if( pInfo && pInfo->psWhatsThis )
+// return i18n(pInfo->psWhatsThis);
+// else
+ return QString::null;
+}
+
+const KShortcut& shortcut( StdAccel id )
+{
+ KStdAccelInfo* pInfo = infoPtr( id );
+ if( !pInfo )
+ return KShortcut::null();
+
+ if( !pInfo->bInitialized )
+ initialize( id );
+
+ return pInfo->cut;
+}
+
+StdAccel findStdAccel( const KKeySequence& seq )
+{
+ if( !seq.isNull() ) {
+ for( uint i = 0; g_infoStdAccel[i].psName != 0; i++ ) {
+ StdAccel id = g_infoStdAccel[i].id;
+ if( id != AccelNone ) {
+ if( !g_infoStdAccel[i].bInitialized )
+ initialize( id );
+ if( g_infoStdAccel[i].cut.contains( seq ) )
+ return id;
+ }
+ }
+ }
+ return AccelNone;
+}
+
+KShortcut shortcutDefault( StdAccel id )
+{
+ return (KAccelAction::useFourModifierKeys())
+ ? shortcutDefault4(id) : shortcutDefault3(id);
+}
+
+KShortcut shortcutDefault3( StdAccel id )
+{
+ KShortcut cut;
+
+ KStdAccelInfo* pInfo = infoPtr( id );
+ if( pInfo ) {
+ if( pInfo->cutDefault )
+ cut.init( pInfo->cutDefault );
+ // FIXME: if there is no cutDefault, then this we be made the primary
+ // instead of alternate shortcut.
+ if( pInfo->cutDefault3B )
+ cut.append( KKey(pInfo->cutDefault3B) );
+ }
+
+ return cut;
+}
+
+KShortcut shortcutDefault4( StdAccel id )
+{
+ KShortcut cut;
+
+ KStdAccelInfo* pInfo = infoPtr( id );
+ if( pInfo ) {
+ KStdAccelInfo& info = *pInfo;
+ KKeySequence key2;
+
+ cut.init( (info.cutDefault4) ?
+ QKeySequence(info.cutDefault) : QKeySequence(info.cutDefault4) );
+
+ if( info.cutDefault4B )
+ key2.init( QKeySequence(info.cutDefault4B) );
+ else if( info.cutDefault3B )
+ key2.init( QKeySequence(info.cutDefault3B) );
+
+ if( key2.count() )
+ cut.append( key2 );
+ }
+
+ return cut;
+}
+
+#if 0 // unused
+void createAccelActions( KAccelActions& actions )
+{
+ actions.clear();
+
+ for( uint i = 0; g_infoStdAccel[i].psName != 0; i++ ) {
+ StdAccel id = g_infoStdAccel[i].id;
+ KStdAccelInfo* pInfo = &g_infoStdAccel[i];
+
+ if( id != AccelNone ) {
+ actions.insert( pInfo->psName,
+ i18n((pInfo->psDesc) ? pInfo->psDesc : pInfo->psName),
+ QString::null, // pInfo->psWhatsThis,
+ shortcutDefault3(id),
+ shortcutDefault4(id) );
+ } else
+ actions.insert( pInfo->psName, i18n(pInfo->psDesc) );
+ }
+}
+#endif
+
+const KShortcut& open() { return shortcut( Open ); }
+const KShortcut& openNew() { return shortcut( New ); }
+const KShortcut& close() { return shortcut( Close ); }
+const KShortcut& save() { return shortcut( Save ); }
+const KShortcut& print() { return shortcut( Print ); }
+const KShortcut& quit() { return shortcut( Quit ); }
+const KShortcut& cut() { return shortcut( Cut ); }
+const KShortcut& copy() { return shortcut( Copy ); }
+const KShortcut& paste() { return shortcut( Paste ); }
+const KShortcut& pasteSelection() { return shortcut( PasteSelection ); }
+const KShortcut& deleteWordBack() { return shortcut( DeleteWordBack ); }
+const KShortcut& deleteWordForward() { return shortcut( DeleteWordForward ); }
+const KShortcut& undo() { return shortcut( Undo ); }
+const KShortcut& redo() { return shortcut( Redo ); }
+const KShortcut& find() { return shortcut( Find ); }
+const KShortcut& findNext() { return shortcut( FindNext ); }
+const KShortcut& findPrev() { return shortcut( FindPrev ); }
+const KShortcut& replace() { return shortcut( Replace ); }
+const KShortcut& home() { return shortcut( Home ); }
+const KShortcut& end() { return shortcut( End ); }
+const KShortcut& beginningOfLine() { return shortcut( BeginningOfLine ); }
+const KShortcut& endOfLine() { return shortcut( EndOfLine ); }
+const KShortcut& prior() { return shortcut( Prior ); }
+const KShortcut& next() { return shortcut( Next ); }
+const KShortcut& backwardWord() { return shortcut( BackwardWord ); }
+const KShortcut& forwardWord() { return shortcut( ForwardWord ); }
+const KShortcut& gotoLine() { return shortcut( GotoLine ); }
+const KShortcut& addBookmark() { return shortcut( AddBookmark ); }
+const KShortcut& tabNext() { return shortcut( TabNext ); }
+const KShortcut& tabPrev() { return shortcut( TabPrev ); }
+const KShortcut& fullScreen() { return shortcut( FullScreen ); }
+const KShortcut& zoomIn() { return shortcut( ZoomIn ); }
+const KShortcut& zoomOut() { return shortcut( ZoomOut ); }
+const KShortcut& help() { return shortcut( Help ); }
+const KShortcut& completion() { return shortcut( TextCompletion ); }
+const KShortcut& prevCompletion() { return shortcut( PrevCompletion ); }
+const KShortcut& nextCompletion() { return shortcut( NextCompletion ); }
+const KShortcut& rotateUp() { return shortcut( RotateUp ); }
+const KShortcut& rotateDown() { return shortcut( RotateDown ); }
+const KShortcut& substringCompletion() { return shortcut( SubstringCompletion ); }
+const KShortcut& popupMenuContext() { return shortcut( PopupMenuContext ); }
+const KShortcut& whatsThis() { return shortcut( WhatsThis ); }
+const KShortcut& reload() { return shortcut( Reload ); }
+const KShortcut& selectAll() { return shortcut( SelectAll ); }
+const KShortcut& up() { return shortcut( Up ); }
+const KShortcut& back() { return shortcut( Back ); }
+const KShortcut& forward() { return shortcut( Forward ); }
+const KShortcut& showMenubar() { return shortcut( ShowMenubar ); }
+
+//---------------------------------------------------------------------
+// ShortcutList
+//---------------------------------------------------------------------
+
+ShortcutList::ShortcutList()
+ { }
+
+ShortcutList::~ShortcutList()
+ { }
+
+uint ShortcutList::count() const
+{
+ static uint g_nAccels = 0;
+ if( g_nAccels == 0 ) {
+ for( ; g_infoStdAccel[g_nAccels].psName != 0; g_nAccels++ )
+ ;
+ }
+ return g_nAccels;
+}
+
+QString ShortcutList::name( uint i ) const
+ { return g_infoStdAccel[i].psName; }
+
+QString ShortcutList::label( uint i ) const
+ { return i18n((g_infoStdAccel[i].psDesc) ? g_infoStdAccel[i].psDesc : g_infoStdAccel[i].psName); }
+
+QString ShortcutList::whatsThis( uint ) const
+ { return QString::null; }
+
+const KShortcut& ShortcutList::shortcut( uint i ) const
+{
+ if( !g_infoStdAccel[i].bInitialized )
+ initialize( g_infoStdAccel[i].id );
+ return g_infoStdAccel[i].cut;
+}
+
+const KShortcut& ShortcutList::shortcutDefault( uint i ) const
+{
+ static KShortcut cut;
+ cut = KStdAccel::shortcutDefault( g_infoStdAccel[i].id );
+ return cut;
+}
+
+bool ShortcutList::isConfigurable( uint i ) const
+ { return (g_infoStdAccel[i].id != AccelNone); }
+
+bool ShortcutList::setShortcut( uint i, const KShortcut& cut )
+ { g_infoStdAccel[i].cut = cut; return true; }
+
+QVariant ShortcutList::getOther( Other, uint ) const
+ { return QVariant(); }
+
+bool ShortcutList::setOther( Other, uint, QVariant )
+ { return false; }
+
+bool ShortcutList::save() const
+{
+ return writeSettings( QString::null, 0, false, true );
+}
+
+KDECORE_EXPORT QString action(StdAccel id)
+ { return name(id); }
+KDECORE_EXPORT QString description(StdAccel id)
+ { return label(id); }
+KDECORE_EXPORT int key(StdAccel id)
+ { return shortcut(id).keyCodeQt(); }
+KDECORE_EXPORT int defaultKey(StdAccel id)
+ { return shortcutDefault(id).keyCodeQt(); }
+
+KDECORE_EXPORT bool isEqual(const QKeyEvent* ev, int keyQt)
+{
+ KKey key1( ev ), key2( keyQt );
+ return key1 == key2;
+}
+
+}
+
+#undef __KSTDACCEL_CPP_
diff --git a/kdecore/kstdaccel.h b/kdecore/kstdaccel.h
new file mode 100644
index 000000000..655d7e349
--- /dev/null
+++ b/kdecore/kstdaccel.h
@@ -0,0 +1,492 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stefan Taferner (taferner@kde.org)
+ Copyright (C) 2000 Nicolas Hadacek (hadacek@kde.org)
+ Copyright (C) 2001,2002 Ellis Whitehead (ellis@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KSTDACCEL_H
+#define KSTDACCEL_H
+
+#include <qstring.h>
+#include <kshortcut.h>
+#include "kdelibs_export.h"
+
+class QKeyEvent;
+class KAccelActions;
+
+/**
+ * \namespace KStdAccel
+ * Convenient methods for access to the common accelerator keys in
+ * the key configuration. These are the standard keybindings that should
+ * be used in all KDE applications. They will be configurable,
+ * so do not hardcode the default behavior.
+ *
+ * If you want real configurable keybindings in your applications,
+ * please checkout the class KAccel in kaccel.h
+ * @see KAccelShortcutList
+ */
+namespace KStdAccel
+{
+ // Always add new std-accels to the end of this enum, never in the middle!
+ /**
+ * Defines the identifier of all standard accelerators.
+ */
+ enum StdAccel {
+ AccelNone,
+ // File menu
+ Open, New, Close, Save,
+ // The Print item
+ Print,
+ Quit,
+ // Edit menu
+ Undo, Redo, Cut, Copy, Paste, SelectAll, Deselect, DeleteWordBack,
+ DeleteWordForward, Find, FindNext, FindPrev, Replace,
+ // Navigation
+ Home, End, Prior, Next, GotoLine, AddBookmark, ZoomIn, ZoomOut,
+ Up, Back, Forward, Reload, PopupMenuContext, ShowMenubar,
+ // Help menu
+ Help, WhatsThis,
+ // Text completion
+ TextCompletion, PrevCompletion, NextCompletion, SubstringCompletion,
+ RotateUp, RotateDown,
+
+ // Tabular navigation
+ TabNext, ///< @since 3.2
+ TabPrev, ///< @since 3.2
+
+ // Full screen mode
+ FullScreen, ///< @since 3.2
+
+ // Text Navigation
+ BackwardWord, ///< @since 3.3
+ ForwardWord, ///< @since 3.3
+ BeginningOfLine, ///< @since 3.3
+ EndOfLine, ///< @since 3.3
+
+ PasteSelection ///< @since 3.4
+
+#ifndef KDE_NO_COMPAT
+ , WhatThis = WhatsThis
+#endif
+ };
+
+ /**
+ * Returns the keybinding for @p accel.
+ * @param id the id of the accelerator
+ */
+ KDECORE_EXPORT const KShortcut& shortcut(StdAccel id);
+
+ /**
+ * Returns a unique name for the given accel.
+ * @param id the id of the accelerator
+ * @return the unique name of the accelerator
+ */
+ KDECORE_EXPORT QString name(StdAccel id);
+
+ /**
+ * Returns a localized label for user-visible display.
+ * @param id the id of the accelerator
+ * @return a localized label for the accelerator
+ */
+ KDECORE_EXPORT QString label(StdAccel id);
+
+ /**
+ * Returns an extended WhatsThis description for the given accelerator.
+ * @param id the id of the accelerator
+ * @return a localized description of the accelerator
+ */
+ KDECORE_EXPORT QString whatsThis(StdAccel id);
+
+ /**
+ * Return the StdAccel id of the standard accel action which
+ * uses this key sequence, or AccelNone if none of them do.
+ * This is used by class KKeyChooser.
+ * @param keySeq the key sequence to search
+ * @return the id of the standard accelerator, or AccelNone if there
+ * is none
+ */
+ KDECORE_EXPORT StdAccel findStdAccel( const KKeySequence &keySeq );
+
+ /**
+ * Returns the hardcoded default shortcut for @p id.
+ * This does not take into account the user's configuration.
+ * @param id the id of the accelerator
+ * @return the default shortcut of the accelerator
+ */
+ KDECORE_EXPORT KShortcut shortcutDefault(StdAccel id);
+ /**
+ * Returns the hardcoded default 3 modifier shortcut for @p id.
+ * This does not take into account the user's configuration.
+ * @param id the id of the accelerator
+ * @return the default 3 modifier shortcut
+ */
+ KDECORE_EXPORT KShortcut shortcutDefault3(StdAccel id);
+ /**
+ * Returns the hardcoded default 4 modifier shortcut for @p id.
+ * This does not take into account the user's configuration.
+ * @param id the id of the accelerator
+ * @return the default 4 modifier shortcut
+ */
+ KDECORE_EXPORT KShortcut shortcutDefault4(StdAccel id);
+
+ /**
+ * Open file. Default: Ctrl-o
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& open();
+
+ /**
+ * Create a new document (or whatever). Default: Ctrl-n
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& openNew();
+
+ /**
+ * Close current document. Default: Ctrl-w
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& close();
+
+ /**
+ * Save current document. Default: Ctrl-s
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& save();
+
+ /**
+ * Print current document. Default: Ctrl-p
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& print();
+
+ /**
+ * Quit the program. Default: Ctrl-q
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& quit();
+
+ /**
+ * Undo last operation. Default: Ctrl-z
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& undo();
+
+ /**
+ * Redo. Default: Shift-Ctrl-z
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& redo();
+
+ /**
+ * Cut selected area and store it in the clipboard. Default: Ctrl-x
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& cut();
+
+ /**
+ * Copy selected area into the clipboard. Default: Ctrl-c
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& copy();
+
+ /**
+ * Paste contents of clipboard at mouse/cursor position. Default: Ctrl-v
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& paste();
+
+ /**
+ * Paste the selection at mouse/cursor position. Default: Ctrl-Shift-Insert
+ * @return the shortcut of the standard accelerator
+ * @since 3.4
+ */
+ KDECORE_EXPORT const KShortcut& pasteSelection();
+
+ /**
+ * Reload. Default: Ctrl-A
+ * @return the shortcut of the standard accelerator
+ **/
+ KDECORE_EXPORT const KShortcut& selectAll();
+
+ /**
+ * Delete a word back from mouse/cursor position. Default: Ctrl-Backspace
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& deleteWordBack();
+
+ /**
+ * Delete a word forward from mouse/cursor position. Default: Ctrl-Delete
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& deleteWordForward();
+
+ /**
+ * Find, search. Default: Ctrl-f
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& find();
+
+ /**
+ * Find/search next. Default: F3
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& findNext();
+
+ /**
+ * Find/search previous. Default: Shift-F3
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& findPrev();
+
+ /**
+ * Find and replace matches. Default: Ctrl-r
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& replace();
+
+ /**
+ * Zoom in. Default: Ctrl-Plus
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& zoomIn();
+
+ /**
+ * Zoom out. Default: Ctrl-Minus
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& zoomOut();
+
+ /**
+ * Toggle insert/overwrite (with visual feedback, e.g. in the statusbar). Default: Insert
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& insert();
+
+ /**
+ * Goto beginning of the document. Default: Ctrl-Home
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& home();
+
+ /**
+ * Goto end of the document. Default: Ctrl-End
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& end();
+
+ /**
+ * Goto beginning of current line. Default: Home
+ * @return the shortcut of the standard accelerator
+ * @since 3.3
+ */
+ KDECORE_EXPORT const KShortcut& beginningOfLine();
+
+ /**
+ * Goto end of current line. Default: End
+ * @return the shortcut of the standard accelerator
+ * @since 3.3
+ */
+ KDECORE_EXPORT const KShortcut& endOfLine();
+
+ /**
+ * Scroll up one page. Default: Prior
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& prior();
+
+ /**
+ * Scroll down one page. Default: Next
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& next();
+
+ /**
+ * Go to line. Default: Ctrl+G
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& gotoLine();
+
+ /**
+ * Add current page to bookmarks. Default: Ctrl+B
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& addBookmark();
+
+ /**
+ * Next Tab. Default: Ctrl-<
+ * @return the shortcut of the standard accelerator
+ * @since 3.2
+ */
+ KDECORE_EXPORT const KShortcut& tabNext();
+
+ /**
+ * Previous Tab. Default: Ctrl->
+ * @return the shortcut of the standard accelerator
+ * @since 3.2
+ */
+ KDECORE_EXPORT const KShortcut& tabPrev();
+
+ /**
+ * Full Screen Mode. Default: Ctrl+Shift+F
+ * @return the shortcut of the standard accelerator
+ * @since 3.2
+ */
+ KDECORE_EXPORT const KShortcut& fullScreen();
+
+ /**
+ * Help the user in the current situation. Default: F1
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& help();
+
+ /**
+ * Complete text in input widgets. Default Ctrl+E
+ * @return the shortcut of the standard accelerator
+ **/
+ KDECORE_EXPORT const KShortcut& completion();
+
+ /**
+ * Iterate through a list when completion returns
+ * multiple items. Default: Ctrl+Up
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& prevCompletion();
+
+ /**
+ * Iterate through a list when completion returns
+ * multiple items. Default: Ctrl+Down
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& nextCompletion();
+
+ /**
+ * Find a string within another string or list of strings.
+ * Default: Ctrl-T
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& substringCompletion();
+
+ /**
+ * Help users iterate through a list of entries. Default: Up
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& rotateUp();
+
+ /**
+ * Help users iterate through a list of entries. Default: Down
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& rotateDown();
+
+ /**
+ * popup a context menu. Default: Menu
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& popupMenuContext();
+
+ /**
+ * What's This button. Default: Shift+F1
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& whatsThis();
+
+ /**
+ * Reload. Default: F5
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& reload();
+
+ /**
+ * Up. Default: Alt+Up
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& up();
+
+ /**
+ * Back. Default: Alt+Left
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& back();
+
+ /**
+ * Forward. Default: ALT+Right
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& forward();
+
+ /**
+ * BackwardWord. Default: Ctrl+Left
+ * @return the shortcut of the standard accelerator
+ * @since 3.3
+ */
+ KDECORE_EXPORT const KShortcut& backwardWord();
+
+ /**
+ * ForwardWord. Default: Ctrl+Right
+ * @return the shortcut of the standard accelerator
+ * @since 3.3
+ */
+ KDECORE_EXPORT const KShortcut& forwardWord();
+
+ /**
+ * Show Menu Bar. Default: Ctrl-M
+ * @return the shortcut of the standard accelerator
+ */
+ KDECORE_EXPORT const KShortcut& showMenubar();
+
+#if !defined(KDE_NO_COMPAT) && !defined(__KSTDACCEL_CPP_)
+ /**
+ * @deprecated
+ * Obsolete. Use name(). Returns a string representation for @p accel.
+ */
+ KDECORE_EXPORT QString action(StdAccel id) KDE_DEPRECATED;
+ /**
+ * @deprecated
+ * Obsolete. Use desc(). Returns a localized description of @p accel.
+ */
+ KDECORE_EXPORT QString description(StdAccel id) KDE_DEPRECATED;
+ /**
+ * @deprecated
+ * Obsolete. Use shortcut(). Returns the keybinding for @p accel.
+ */
+ KDECORE_EXPORT int key(StdAccel) KDE_DEPRECATED;
+ /**
+ * @deprecated
+ * Obsolete. Use shortcutDefault().
+ */
+ KDECORE_EXPORT int defaultKey(StdAccel accel) KDE_DEPRECATED;
+
+ /**
+ * @deprecated. Use KKey(const QKeyEvent*) == KKey(int).
+ *
+ * Compare the keys generated by the key event with
+ * the value of the integer.
+ *
+ * If a modifier (Shift, Alt, Ctrl) key is present in
+ * QKeyEvent, its sum with the actual key value
+ * is used for comparing it with the integer parameter.
+ *
+ * @param pEvent the key event to be used in the comparison.
+ * @param keyQt the int value to be compared to the key event.
+ *
+ * @return true if the int value matches the integer representation of the QKeyEvent
+ */
+ KDECORE_EXPORT bool isEqual(const QKeyEvent* pEvent, int keyQt) KDE_DEPRECATED;
+#endif // !KDE_NO_COMPAT
+
+}
+
+#endif
diff --git a/kdecore/kstddirs.h b/kdecore/kstddirs.h
new file mode 100644
index 000000000..a009a750d
--- /dev/null
+++ b/kdecore/kstddirs.h
@@ -0,0 +1,6 @@
+// kstddirs.h is the old name, use #include <kstandarddirs.h> from now on
+#ifdef KDE_NO_COMPAT
+#error kstddirs.h is the old name, use #include <kstandarddirs.h> from now on
+#else
+#include <kstandarddirs.h>
+#endif
diff --git a/kdecore/kstringhandler.cpp b/kdecore/kstringhandler.cpp
new file mode 100644
index 000000000..185a0316a
--- /dev/null
+++ b/kdecore/kstringhandler.cpp
@@ -0,0 +1,663 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Ian Zepp (icszepp@islc.net)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kstringhandler.h"
+#include "kglobal.h"
+
+static void parsePythonRange( const QCString &range, uint &start, uint &end )
+{
+ const int colon = range.find( ':' );
+ if ( colon == -1 ) {
+ start = range.toUInt();
+ end = start;
+ } else if ( colon == int( range.length() - 1 ) ) {
+ start = range.left( colon ).toUInt();
+ } else if ( colon == 0 ) {
+ end = range.mid( 1 ).toUInt();
+ } else {
+ start = range.left( colon ).toInt();
+ end = range.mid( colon + 1 ).toInt();
+ }
+}
+
+QString KStringHandler::word( const QString &text , uint pos )
+{
+ return text.section( ' ', pos, pos );
+}
+
+QString KStringHandler::word( const QString &text , const char *range )
+{
+ // Format in: START:END
+ // Note index starts a 0 (zero)
+ //
+ // 0: first word to end
+ // 1:3 second to fourth words
+ QStringList list = QStringList::split( " ", text , true );
+ QString tmp = "";
+ QString r = range;
+
+ if ( text.isEmpty() )
+ return tmp;
+
+ uint pos = 0, cnt = list.count();
+ parsePythonRange( range, pos, cnt );
+
+ //
+ // Extract words
+ //
+ int wordsToExtract = cnt-pos+1;
+ QStringList::Iterator it = list.at( pos);
+
+ while ( (it != list.end()) && (wordsToExtract-- > 0))
+ {
+ tmp += *it;
+ tmp += " ";
+ it++;
+ }
+
+ return tmp.stripWhiteSpace();
+}
+
+//
+// Insertion and removal routines
+//
+QString KStringHandler::insword( const QString &text , const QString &word , uint pos )
+{
+ if ( text.isEmpty() )
+ return word;
+
+ if ( word.isEmpty() )
+ return text;
+
+ // Split words and add into list
+ QStringList list = QStringList::split( " ", text, true );
+
+ if ( pos >= list.count() )
+ list.append( word );
+ else
+ list.insert( list.at(pos) , word );
+
+ // Rejoin
+ return list.join( " " );
+}
+
+QString KStringHandler::setword( const QString &text , const QString &word , uint pos )
+{
+ if ( text.isEmpty() )
+ return word;
+
+ if ( word.isEmpty() )
+ return text;
+
+ // Split words and add into list
+ QStringList list = QStringList::split( " ", text, true );
+
+ if ( pos >= list.count() )
+ list.append( word );
+ else
+ {
+ list.insert( list.remove( list.at(pos) ) , word );
+ }
+
+ // Rejoin
+ return list.join( " " );
+}
+
+QString KStringHandler::remrange( const QString &text , const char *range )
+{
+ // Format in: START:END
+ // Note index starts a 0 (zero)
+ //
+ // 0: first word to end
+ // 1:3 second to fourth words
+ QStringList list = QStringList::split( " ", text , true );
+ QString tmp = "";
+ QString r = range;
+
+ if ( text.isEmpty() )
+ return tmp;
+
+ uint pos = 0, cnt = list.count();
+ parsePythonRange( range, pos, cnt );
+
+ //
+ // Remove that range of words
+ //
+ int wordsToDelete = cnt-pos+1;
+ QStringList::Iterator it = list.at( pos);
+
+ while ( (it != list.end()) && (wordsToDelete-- > 0))
+ it = list.remove( it );
+
+ return list.join( " " );
+}
+
+QString KStringHandler::remword( const QString &text , uint pos )
+{
+ QString tmp = "";
+
+ if ( text.isEmpty() )
+ return tmp;
+
+ // Split words and add into list
+ QStringList list = QStringList::split( " ", text, true );
+
+ if ( pos < list.count() )
+ list.remove( list.at( pos ) );
+
+ // Rejoin
+ return list.join( " " );
+}
+
+QString KStringHandler::remword( const QString &text , const QString &word )
+{
+ QString tmp = "";
+
+ if ( text.isEmpty() )
+ return tmp;
+
+ if ( word.isEmpty() )
+ return text;
+
+ // Split words and add into list
+ QStringList list = QStringList::split( " ", text, true );
+
+ QStringList::Iterator it = list.find(word);
+
+ if (it != list.end())
+ list.remove( it );
+
+ // Rejoin
+ return list.join( " " );
+}
+
+//
+// Capitalization routines
+//
+QString KStringHandler::capwords( const QString &text )
+{
+ if ( text.isEmpty() ) {
+ return text;
+ }
+
+ const QString strippedText = text.stripWhiteSpace();
+ const QStringList words = capwords( QStringList::split( ' ', strippedText ) );
+
+ QString result = text;
+ result.replace( strippedText, words.join( " " ) );
+ return result;
+}
+
+QStringList KStringHandler::capwords( const QStringList &list )
+{
+ QStringList tmp = list;
+ for ( QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it ) {
+ *it = ( *it )[ 0 ].upper() + ( *it ).mid( 1 );
+ }
+ return tmp;
+}
+
+//
+// Reverse routines
+//
+QString KStringHandler::reverse( const QString &text )
+{
+ QString tmp;
+
+ if ( text.isEmpty() )
+ return tmp;
+
+ QStringList list;
+ list = QStringList::split( " ", text, true );
+ list = reverse( list );
+
+ return list.join( " " );
+}
+
+QStringList KStringHandler::reverse( const QStringList &list )
+{
+ QStringList tmp;
+
+ if ( list.count() == 0 )
+ return tmp;
+
+ for ( QStringList::ConstIterator it= list.begin();
+ it != list.end();
+ it++)
+ tmp.prepend( *it );
+
+ return tmp;
+}
+
+//
+// Left, Right, Center justification
+//
+QString KStringHandler::ljust( const QString &text , uint width )
+{
+ return text.stripWhiteSpace().leftJustify( width );
+}
+
+QString KStringHandler::rjust( const QString &text , uint width )
+{
+ return text.stripWhiteSpace().rightJustify( width );
+}
+
+QString KStringHandler::center( const QString &text , uint width )
+{
+ const QString s = text.stripWhiteSpace();
+ const unsigned int length = s.length();
+ if ( width <= length ) {
+ return s;
+ }
+
+ QString result;
+ result.fill( ' ', ( width - length ) / 2 );
+ result += s;
+
+ return result.leftJustify( width );
+}
+
+QString KStringHandler::lsqueeze( const QString & str, uint maxlen )
+{
+ if (str.length() > maxlen) {
+ int part = maxlen-3;
+ return QString("..." + str.right(part));
+ }
+ else return str;
+}
+
+QString KStringHandler::csqueeze( const QString & str, uint maxlen )
+{
+ if (str.length() > maxlen && maxlen > 3) {
+ int part = (maxlen-3)/2;
+ return QString(str.left(part) + "..." + str.right(part));
+ }
+ else return str;
+}
+
+QString KStringHandler::rsqueeze( const QString & str, uint maxlen )
+{
+ if (str.length() > maxlen) {
+ int part = maxlen-3;
+ return QString(str.left(part) + "...");
+ }
+ else return str;
+}
+
+QString KStringHandler::lEmSqueeze(const QString &name, const QFontMetrics& fontMetrics, uint maxlen)
+{
+ return lPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen);
+}
+
+QString KStringHandler::lPixelSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxPixels)
+{
+ uint nameWidth = fontMetrics.width(name);
+
+ if (maxPixels < nameWidth)
+ {
+ QString tmp = name;
+ const uint em = fontMetrics.maxWidth();
+ maxPixels -= fontMetrics.width("...");
+
+ while (maxPixels < nameWidth && !tmp.isEmpty())
+ {
+ int delta = (nameWidth - maxPixels) / em;
+ delta = kClamp(delta, 1, delta); // no max
+
+ tmp.remove(0, delta);
+ nameWidth = fontMetrics.width(tmp);
+ }
+
+ return ("..." + tmp);
+ }
+
+ return name;
+}
+
+QString KStringHandler::cEmSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxlen)
+{
+ return cPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen);
+}
+
+QString KStringHandler::cPixelSqueeze(const QString& s, const QFontMetrics& fm, uint width)
+{
+ if ( s.isEmpty() || uint( fm.width( s ) ) <= width ) {
+ return s;
+ }
+
+ const unsigned int length = s.length();
+ if ( length == 2 ) {
+ return s;
+ }
+
+ const int maxWidth = width - fm.width( '.' ) * 3;
+ if ( maxWidth <= 0 ) {
+ return "...";
+ }
+
+ unsigned int leftIdx = 0, rightIdx = length;
+ unsigned int leftWidth = fm.charWidth( s, leftIdx++ );
+ unsigned int rightWidth = fm.charWidth( s, --rightIdx );
+ while ( leftWidth + rightWidth < uint( maxWidth ) ) {
+ while ( leftWidth <= rightWidth && leftWidth + rightWidth < uint( maxWidth ) ) {
+ leftWidth += fm.charWidth( s, leftIdx++ );
+ }
+ while ( rightWidth <= leftWidth && leftWidth + rightWidth < uint( maxWidth ) ) {
+ rightWidth += fm.charWidth( s, --rightIdx );
+ }
+ }
+
+ if ( leftWidth > rightWidth ) {
+ --leftIdx;
+ } else {
+ ++rightIdx;
+ }
+
+ rightIdx = length - rightIdx;
+ if ( leftIdx == 0 && rightIdx == 1 || leftIdx == 1 && rightIdx == 0 ) {
+ return "...";
+ }
+
+ return s.left( leftIdx ) + "..." + s.right( rightIdx );
+}
+
+QString KStringHandler::rEmSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxlen)
+{
+ return rPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen);
+}
+
+QString KStringHandler::rPixelSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxPixels)
+{
+ uint nameWidth = fontMetrics.width(name);
+
+ if (maxPixels < nameWidth)
+ {
+ QString tmp = name;
+ const uint em = fontMetrics.maxWidth();
+ maxPixels -= fontMetrics.width("...");
+
+ while (maxPixels < nameWidth && !tmp.isEmpty())
+ {
+ int length = tmp.length();
+ int delta = em ? (nameWidth - maxPixels) / em : length;
+ delta = kClamp(delta, 1, length) ;
+
+ tmp.remove(length - delta, delta);
+ nameWidth = fontMetrics.width(tmp);
+ }
+
+ return (tmp + "...");
+ }
+
+ return name;
+}
+
+///// File name patterns (like *.txt)
+
+bool KStringHandler::matchFileName( const QString& filename, const QString& pattern )
+{
+ int len = filename.length();
+ int pattern_len = pattern.length();
+
+ if (!pattern_len)
+ return false;
+
+ // Patterns like "Makefile*"
+ if ( pattern[ pattern_len - 1 ] == '*' && len + 1 >= pattern_len ) {
+ if ( pattern[ 0 ] == '*' )
+ {
+ return filename.find(pattern.mid(1, pattern_len - 2)) != -1;
+ }
+
+ const QChar *c1 = pattern.unicode();
+ const QChar *c2 = filename.unicode();
+ int cnt = 1;
+ while ( cnt < pattern_len && *c1++ == *c2++ )
+ ++cnt;
+ return cnt == pattern_len;
+ }
+
+ // Patterns like "*~", "*.extension"
+ if ( pattern[ 0 ] == '*' && len + 1 >= pattern_len )
+ {
+ const QChar *c1 = pattern.unicode() + pattern_len - 1;
+ const QChar *c2 = filename.unicode() + len - 1;
+ int cnt = 1;
+ while ( cnt < pattern_len && *c1-- == *c2-- )
+ ++cnt;
+ return cnt == pattern_len;
+ }
+
+ // Patterns like "Makefile"
+ return ( filename == pattern );
+}
+
+ QStringList
+KStringHandler::perlSplit(const QString & sep, const QString & s, uint max)
+{
+ bool ignoreMax = 0 == max;
+
+ QStringList l;
+
+ int searchStart = 0;
+
+ int tokenStart = s.find(sep, searchStart);
+
+ while (-1 != tokenStart && (ignoreMax || l.count() < max - 1))
+ {
+ if (!s.mid(searchStart, tokenStart - searchStart).isEmpty())
+ l << s.mid(searchStart, tokenStart - searchStart);
+
+ searchStart = tokenStart + sep.length();
+ tokenStart = s.find(sep, searchStart);
+ }
+
+ if (!s.mid(searchStart, s.length() - searchStart).isEmpty())
+ l << s.mid(searchStart, s.length() - searchStart);
+
+ return l;
+}
+
+ QStringList
+KStringHandler::perlSplit(const QChar & sep, const QString & s, uint max)
+{
+ bool ignoreMax = 0 == max;
+
+ QStringList l;
+
+ int searchStart = 0;
+
+ int tokenStart = s.find(sep, searchStart);
+
+ while (-1 != tokenStart && (ignoreMax || l.count() < max - 1))
+ {
+ if (!s.mid(searchStart, tokenStart - searchStart).isEmpty())
+ l << s.mid(searchStart, tokenStart - searchStart);
+
+ searchStart = tokenStart + 1;
+ tokenStart = s.find(sep, searchStart);
+ }
+
+ if (!s.mid(searchStart, s.length() - searchStart).isEmpty())
+ l << s.mid(searchStart, s.length() - searchStart);
+
+ return l;
+}
+
+ QStringList
+KStringHandler::perlSplit(const QRegExp & sep, const QString & s, uint max)
+{
+ bool ignoreMax = 0 == max;
+
+ QStringList l;
+
+ int searchStart = 0;
+ int tokenStart = sep.search(s, searchStart);
+ int len = sep.matchedLength();
+
+ while (-1 != tokenStart && (ignoreMax || l.count() < max - 1))
+ {
+ if (!s.mid(searchStart, tokenStart - searchStart).isEmpty())
+ l << s.mid(searchStart, tokenStart - searchStart);
+
+ searchStart = tokenStart + len;
+ tokenStart = sep.search(s, searchStart);
+ len = sep.matchedLength();
+ }
+
+ if (!s.mid(searchStart, s.length() - searchStart).isEmpty())
+ l << s.mid(searchStart, s.length() - searchStart);
+
+ return l;
+}
+
+ QString
+KStringHandler::tagURLs( const QString& text )
+{
+ /*static*/ QRegExp urlEx("(www\\.(?!\\.)|(fish|(f|ht)tp(|s))://)[\\d\\w\\./,:_~\\?=&;#@\\-\\+\\%\\$]+[\\d\\w/]");
+
+ QString richText( text );
+ int urlPos = 0, urlLen;
+ while ((urlPos = urlEx.search(richText, urlPos)) >= 0)
+ {
+ urlLen = urlEx.matchedLength();
+ QString href = richText.mid( urlPos, urlLen );
+ // Qt doesn't support (?<=pattern) so we do it here
+ if((urlPos > 0) && richText[urlPos-1].isLetterOrNumber()){
+ urlPos++;
+ continue;
+ }
+ // Don't use QString::arg since %01, %20, etc could be in the string
+ QString anchor = "<a href=\"" + href + "\">" + href + "</a>";
+ richText.replace( urlPos, urlLen, anchor );
+
+
+ urlPos += anchor.length();
+ }
+ return richText;
+}
+
+QString KStringHandler::obscure( const QString &str )
+{
+ QString result;
+ const QChar *unicode = str.unicode();
+ for ( uint i = 0; i < str.length(); ++i )
+ result += ( unicode[ i ].unicode() <= 0x21 ) ? unicode[ i ] :
+ QChar( 0x1001F - unicode[ i ].unicode() );
+
+ return result;
+}
+
+bool KStringHandler::isUtf8(const char *buf)
+{
+ int i, n;
+ register unsigned char c;
+ bool gotone = false;
+
+ if (!buf)
+ return true; // whatever, just don't crash
+
+#define F 0 /* character never appears in text */
+#define T 1 /* character appears in plain ASCII text */
+#define I 2 /* character appears in ISO-8859 text */
+#define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
+
+ static const unsigned char text_chars[256] = {
+ /* BEL BS HT LF FF CR */
+ F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */
+ /* ESC */
+ F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */
+ /* NEL */
+ X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */
+ X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */
+ };
+
+ /* *ulen = 0; */
+ for (i = 0; (c = buf[i]); i++) {
+ if ((c & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */
+ /*
+ * Even if the whole file is valid UTF-8 sequences,
+ * still reject it if it uses weird control characters.
+ */
+
+ if (text_chars[c] != T)
+ return false;
+
+ } else if ((c & 0x40) == 0) { /* 10xxxxxx never 1st byte */
+ return false;
+ } else { /* 11xxxxxx begins UTF-8 */
+ int following;
+
+ if ((c & 0x20) == 0) { /* 110xxxxx */
+ following = 1;
+ } else if ((c & 0x10) == 0) { /* 1110xxxx */
+ following = 2;
+ } else if ((c & 0x08) == 0) { /* 11110xxx */
+ following = 3;
+ } else if ((c & 0x04) == 0) { /* 111110xx */
+ following = 4;
+ } else if ((c & 0x02) == 0) { /* 1111110x */
+ following = 5;
+ } else
+ return false;
+
+ for (n = 0; n < following; n++) {
+ i++;
+ if (!(c = buf[i]))
+ goto done;
+
+ if ((c & 0x80) == 0 || (c & 0x40))
+ return false;
+ }
+ gotone = true;
+ }
+ }
+done:
+ return gotone; /* don't claim it's UTF-8 if it's all 7-bit */
+}
+
+#undef F
+#undef T
+#undef I
+#undef X
+
+QString KStringHandler::from8Bit( const char *str )
+{
+ if (!str)
+ return QString::null;
+ if (!*str) {
+ static const QString &emptyString = KGlobal::staticQString("");
+ return emptyString;
+ }
+ return KStringHandler::isUtf8( str ) ?
+ QString::fromUtf8( str ) :
+ QString::fromLocal8Bit( str );
+}
diff --git a/kdecore/kstringhandler.h b/kdecore/kstringhandler.h
new file mode 100644
index 000000000..e01c4493b
--- /dev/null
+++ b/kdecore/kstringhandler.h
@@ -0,0 +1,441 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Ian Zepp (icszepp@islc.net)
+ Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KSTRINGHANDLER_H
+#define KSTRINGHANDLER_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qregexp.h> // for the word ranges
+#include <qfontmetrics.h>
+#include "kdelibs_export.h"
+
+/**
+ * This class contains utility functions for handling strings.
+ *
+ * This class is @em not a substitute for the QString class. What
+ * I tried to do with this class is provide an easy way to
+ * cut/slice/splice words inside sentences in whatever order desired.
+ * While the main focus of this class are words (ie characters
+ * separated by spaces/tabs), the two core functions here ( split()
+ * and join() ) will function given any char to use as a separator.
+ * This will make it easy to redefine what a 'word' means in the
+ * future if needed.
+ *
+ * I freely stole some of the function names from python. I also think
+ * some of these were influenced by mIRC (yes, believe it if you will, I
+ * used to write a LOT of scripts in mIRC).
+ *
+ * The ranges are a fairly powerful way of getting/stripping words from
+ * a string. These ranges function, for the large part, as they would in
+ * python. See the word(const QString&, const char *) and remword(const QString&, uint) functions for more detail.
+ *
+ * This class contains no data members of its own. All strings are cut
+ * on the fly and returned as new qstrings/qstringlists.
+ *
+ * Quick example on how to use:
+ *
+ * \code
+ * KStringHandler kstr;
+ * QString line = "This is a test of the strings";
+ *
+ * cout << "1> " << kstr.word( line , "4:" ) << "\n";
+ * cout << "2> " << kstr.remrange( line , "2:5" ) << "\n";
+ * cout << "2> " << kstr.reverse( line ) << "\n";
+ * cout << "2> " << kstr.center( kstr.word( line , 4 ) , 15 ) << "\n";
+ * \endcode
+ *
+ * and so forth.
+ *
+ * @short Class for manipulating words and sentences in strings
+ * @author Ian Zepp <icszepp@islc.net>
+ * @see KShell
+ */
+class KDECORE_EXPORT KStringHandler
+{
+public:
+ /** Returns the nth word in the string if found
+ * Returns a EMPTY (not null) string otherwise.
+ * Note that the FIRST index is 0.
+ * @param text the string to search for the words
+ * @param pos the position of the word to search
+ * @return the word, or an empty string if not found
+ * @deprecated use QString::section instead
+ */
+ static QString word( const QString &text , uint pos ) KDE_DEPRECATED;
+
+ /** Returns a range of words from that string.
+ * Ie:
+ * @li "0" returns the very first word
+ * @li "0:" returns the first to the last word
+ * @li "0:3" returns the first to fourth words
+ * @li ":3" returns everything up to the fourth word
+ *
+ * If you grok python, you're set.
+ * @param text the string to search for the words
+ * @param range the words to return (see description)
+ * @return the words, or an empty string if not found
+ */
+ static QString word( const QString &text , const char *range );
+
+ /** Inserts a word into the string, and returns
+ * a new string with the word included. the first
+ * index is zero (0). If there are not @p pos words in the original
+ * string, the new word will be appended to the end.
+ * @param text the original text
+ * @param word the word to insert
+ * @param pos the position (in words) for the new word
+ * @return the resulting string
+ */
+ static QString insword( const QString &text , const QString &word , uint pos );
+
+ /** Replaces a word in the string, and returns
+ * a new string with the word included. the first
+ * index is zero (0). If there are not @p pos words in the original
+ * string, the new word will be appended to the end.
+ * @param text the original text
+ * @param word the word to insert
+ * @param pos the position (in words) for the new word
+ * @return the resulting string
+ */
+ static QString setword( const QString &text , const QString &word , uint pos );
+
+ /** Removes a word or ranges of words from the string,
+ * and returns a new string. The ranges definitions
+ * follow the definitions for the word() function.
+ *
+ * @li "0" removes the very first word
+ * @li "0:" removes the first the the last word
+ * @li "0:3" removes the first to fourth words
+ * @li ":3" removes everything up to the fourth word
+ * @param text the original text
+ * @param range the words to remove (see description)
+ * @return the resulting string
+ */
+ static QString remrange( const QString &text , const char *range );
+
+
+ /** Removes a word at the given index, and returns a
+ * new string. The first index is zero (0).
+ * @param text the original text
+ * @param pos the position (in words) of thw word to delete
+ * @return the resulting string
+ */
+ static QString remword( const QString &text , uint pos );
+
+ /** Removes a matching word from the string, and returns
+ * a new string. Note that only ONE match is removed.
+ * @param text the original text
+ * @param word the word to remove
+ * @return the resulting string
+ */
+ static QString remword( const QString &text , const QString &word );
+
+ /** Capitalizes each word in the string
+ * "hello there" becomes "Hello There" (string)
+ * @param text the text to capitalize
+ * @return the resulting string
+ */
+ static QString capwords( const QString &text );
+
+ /** Capitalizes each word in the list
+ * [hello, there] becomes [Hello, There] (list)
+ * @param list the list to capitalize
+ * @return the resulting list
+ */
+ static QStringList capwords( const QStringList &list );
+
+ /** Reverses the order of the words in a string
+ * "hello there" becomes "there hello" (string)
+ * @param text the text to reverse
+ * @return the resulting string
+ */
+ static QString reverse( const QString &text );
+
+ /** Reverses the order of the words in a list
+ * [hello, there] becomes [there, hello] (list)
+ * @param list the list to reverse
+ * @return the resulting list
+ */
+ static QStringList reverse( const QStringList &list );
+
+ /** Left-justifies a string and returns a string at least 'width' characters
+ * wide.
+ * If the string is longer than the @p width, the original
+ * string is returned. It is never truncated.
+ * @param text the text to justify
+ * @param width the desired width of the new string
+ * @return the resulting string
+ * @deprecated use QString::leftJustify instead
+ */
+ static QString ljust( const QString &text , uint width ) KDE_DEPRECATED;
+
+ /** Right-justifies a string and returns a string at least 'width' characters
+ * wide.
+ * If the string is longer than the @p width, the original
+ * string is returned. It is never truncated.
+ * @param text the text to justify
+ * @param width the desired width of the new string
+ * @return the resulting string
+ * @deprecated use QString::rightJustify instead
+ */
+ static QString rjust( const QString &text , uint width ) KDE_DEPRECATED;
+
+ /** Centers a string and returns a string at least 'width' characters
+ * wide.
+ * If the string is longer than the @p width, the original
+ * string is returned. It is never truncated.
+ * @param text the text to justify
+ * @param width the desired width of the new string
+ * @return the resulting string
+ */
+ static QString center( const QString &text , uint width );
+
+ /** Substitute characters at the beginning of a string by "...".
+ * @param str is the string to modify
+ * @param maxlen is the maximum length the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ */
+ static QString lsqueeze( const QString & str, uint maxlen = 40 );
+
+ /** Substitute characters at the beginning of a string by "...". Similar to
+ * method above, except that it truncates based on pixel width rather than
+ * the number of characters
+ * @param name is the string to modify
+ * @param fontMetrics is the font metrics to use to calculate character sizes
+ * @param maxlen is the maximum length in ems the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ * @since 3.2
+ */
+ static QString lEmSqueeze( const QString & name,
+ const QFontMetrics& fontMetrics,
+ uint maxlen = 30 );
+
+ /** Substitute characters at the beginning of a string by "...". Similar to
+ * method above, except that maxlen is the width in pixels to truncate to
+ * @param name is the string to modify
+ * @param fontMetrics is the font metrics to use to calculate character sizes
+ * @param maxPixels is the maximum pixel length the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ * @since 3.2
+ */
+ static QString lPixelSqueeze( const QString & name,
+ const QFontMetrics& fontMetrics,
+ uint maxPixels );
+
+ /** Substitute characters at the middle of a string by "...".
+ * @param str is the string to modify
+ * @param maxlen is the maximum length the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ */
+ static QString csqueeze( const QString & str, uint maxlen = 40 );
+
+ /** Substitute characters in the middle of a string by "...". Similar to
+ * method above, except that it truncates based on pixel width rather than
+ * the number of characters
+ * @param name is the string to modify
+ * @param fontMetrics is the font metrics to use to calculate character sizes
+ * @param maxlen is the maximum length in ems the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ * @since 3.2
+ */
+ static QString cEmSqueeze( const QString & name,
+ const QFontMetrics& fontMetrics,
+ uint maxlen = 30 );
+
+ /** Substitute characters in the middle of a string by "...". Similar to
+ * method above, except that maxlen is the width in pixels to truncate to
+ * @param name is the string to modify
+ * @param fontMetrics is the font metrics to use to calculate character sizes
+ * @param maxPixels is the maximum pixel length the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ * @since 3.2
+ */
+ static QString cPixelSqueeze( const QString & name,
+ const QFontMetrics& fontMetrics,
+ uint maxPixels );
+
+ /** Substitute characters at the end of a string by "...".
+ * @param str is the string to modify
+ * @param maxlen is the maximum length the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ */
+ static QString rsqueeze( const QString & str, uint maxlen = 40 );
+
+ /** Substitute characters at the end of a string by "...". Similar to
+ * method above, except that it truncates based on pixel width rather than
+ * the number of characters
+ * @param name is the string to modify
+ * @param fontMetrics is the font metrics to use to calculate character sizes
+ * @param maxlen is the maximum length in ems the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ * @since 3.2
+ */
+ static QString rEmSqueeze( const QString & name,
+ const QFontMetrics& fontMetrics,
+ uint maxlen = 30 );
+
+ /** Substitute characters at the end of a string by "...". Similar to
+ * method above, except that maxlen is the width in pixels to truncate to
+ * @param name is the string to modify
+ * @param fontMetrics is the font metrics to use to calculate character sizes
+ * @param maxPixels is the maximum pixel length the modified string will have
+ * If the original string is shorter than "maxlen", it is returned verbatim
+ * @return the modified string
+ * @since 3.2
+ */
+ static QString rPixelSqueeze( const QString & name,
+ const QFontMetrics& fontMetrics,
+ uint maxPixels );
+
+ /**
+ * Match a filename.
+ * @param filename is the real decoded filename (or dirname
+ * without trailing '/').
+ * @param pattern is a pattern like *.txt, *.tar.gz, Makefile.*, *README*, etc.
+ * Patterns with two asterisks like "*.*pk" are not supported.
+ * @return true if the given filename matches the given pattern
+ */
+ static bool matchFileName( const QString& filename, const QString& pattern );
+ // KDE4: move to KShell
+
+ /**
+ * Split a QString into a QStringList in a similar fashion to the static
+ * QStringList function in Qt, except you can specify a maximum number
+ * of tokens. If max is specified (!= 0) then only that number of tokens
+ * will be extracted. The final token will be the remainder of the string.
+ *
+ * Example:
+ * \code
+ * perlSplit("__", "some__string__for__you__here", 4)
+ * QStringList contains: "some", "string", "for", "you__here"
+ * \endcode
+ *
+ * @param sep is the string to use to delimit s.
+ * @param s is the input string
+ * @param max is the maximum number of extractions to perform, or 0.
+ * @return A QStringList containing tokens extracted from s.
+ */
+ static QStringList perlSplit
+ (const QString & sep, const QString & s, uint max = 0);
+
+ /**
+ * Split a QString into a QStringList in a similar fashion to the static
+ * QStringList function in Qt, except you can specify a maximum number
+ * of tokens. If max is specified (!= 0) then only that number of tokens
+ * will be extracted. The final token will be the remainder of the string.
+ *
+ * Example:
+ * \code
+ * perlSplit(' ', "kparts reaches the parts other parts can't", 3)
+ * QStringList contains: "kparts", "reaches", "the parts other parts can't"
+ * \endcode
+ *
+ * @param sep is the character to use to delimit s.
+ * @param s is the input string
+ * @param max is the maximum number of extractions to perform, or 0.
+ * @return A QStringList containing tokens extracted from s.
+ */
+ static QStringList perlSplit
+ (const QChar & sep, const QString & s, uint max = 0);
+
+ /**
+ * Split a QString into a QStringList in a similar fashion to the static
+ * QStringList function in Qt, except you can specify a maximum number
+ * of tokens. If max is specified (!= 0) then only that number of tokens
+ * will be extracted. The final token will be the remainder of the string.
+ *
+ * Example:
+ * \code
+ * perlSplit(QRegExp("[! ]", "Split me up ! I'm bored ! OK ?", 3)
+ * QStringList contains: "Split", "me", "up ! I'm bored, OK ?"
+ * \endcode
+ *
+ * @param sep is the regular expression to use to delimit s.
+ * @param s is the input string
+ * @param max is the maximum number of extractions to perform, or 0.
+ * @return A QStringList containing tokens extracted from s.
+ */
+ static QStringList perlSplit
+ (const QRegExp & sep, const QString & s, uint max = 0);
+
+ /**
+ * This method auto-detects URLs in strings, and adds HTML markup to them
+ * so that richtext or HTML-enabled widgets (such as KActiveLabel)
+ * will display the URL correctly.
+ * @param text the string which may contain URLs
+ * @return the resulting text
+ * @since 3.1
+ */
+ static QString tagURLs( const QString& text );
+
+ /**
+ Obscure string by using a simple symmetric encryption. Applying the
+ function to a string obscured by this function will result in the original
+ string.
+
+ The function can be used to obscure passwords stored to configuration
+ files. Note that this won't give you any more security than preventing
+ that the password is directly copied and pasted.
+
+ @param str string to be obscured
+ @return obscured string
+ @since 3.2
+ */
+ static QString obscure( const QString &str );
+
+ /**
+ Guess whether a string is UTF8 encoded.
+
+ @param str the string to check
+ @return true if UTF8. If false, the string is probably in Local8Bit.
+ @since 3.2
+ */
+ static bool isUtf8( const char *str );
+
+ /**
+ Construct QString from a c string, guessing whether it is UTF8- or
+ Local8Bit-encoded.
+
+ @param str the input string
+ @return the (hopefully correctly guessed) QString representation of @p str
+ @since 3.2
+ */
+ static QString from8Bit( const char *str );
+
+#ifdef KDE_NO_COMPAT
+private:
+#endif
+ /**
+ * @deprecated Use matchFileName () instead.
+ */
+ static KDE_DEPRECATED bool matchFilename( const QString& filename, const QString& pattern )
+ {
+ return matchFileName (filename, pattern);
+ }
+
+};
+#endif
diff --git a/kdecore/ksycoca.cpp b/kdecore/ksycoca.cpp
new file mode 100644
index 000000000..b4a3533fe
--- /dev/null
+++ b/kdecore/ksycoca.cpp
@@ -0,0 +1,524 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "config.h"
+
+#include "ksycoca.h"
+#include "ksycocatype.h"
+#include "ksycocafactory.h"
+
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qbuffer.h>
+
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifdef Q_OS_SOLARIS
+extern "C"
+{
+ extern int madvise(caddr_t, size_t, int);
+}
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif
+
+template class QPtrList<KSycocaFactory>;
+
+// The following limitations are in place:
+// Maximum length of a single string: 8192 bytes
+// Maximum length of a string list: 1024 strings
+// Maximum number of entries: 8192
+//
+// The purpose of these limitations is to limit the impact
+// of database corruption.
+
+class KSycocaPrivate {
+public:
+ KSycocaPrivate() {
+ database = 0;
+ readError = false;
+ updateSig = 0;
+ autoRebuild = true;
+ }
+ QFile *database;
+ QStringList changeList;
+ QString language;
+ bool readError;
+ bool autoRebuild;
+ Q_UINT32 updateSig;
+ QStringList allResourceDirs;
+};
+
+int KSycoca::version()
+{
+ return KSYCOCA_VERSION;
+}
+
+// Read-only constructor
+KSycoca::KSycoca()
+ : DCOPObject("ksycoca"), m_lstFactories(0), m_str(0), bNoDatabase(false),
+ m_sycoca_size(0), m_sycoca_mmap(0), m_timeStamp(0)
+{
+ d = new KSycocaPrivate;
+ // Register app as able to receive DCOP messages
+ if (kapp && !kapp->dcopClient()->isAttached())
+ {
+ kapp->dcopClient()->attach();
+ }
+ // We register with DCOP _before_ we try to open the database.
+ // This way we can be relative sure that the KDE framework is
+ // up and running (kdeinit, dcopserver, klaucnher, kded) and
+ // that the database is up to date.
+ openDatabase();
+ _self = this;
+}
+
+bool KSycoca::openDatabase( bool openDummyIfNotFound )
+{
+ bool result = true;
+
+ m_sycoca_mmap = 0;
+ m_str = 0;
+ QString path;
+ QCString ksycoca_env = getenv("KDESYCOCA");
+ if (ksycoca_env.isEmpty())
+ path = KGlobal::dirs()->saveLocation("cache") + "ksycoca";
+ else
+ path = QFile::decodeName(ksycoca_env);
+
+ kdDebug(7011) << "Trying to open ksycoca from " << path << endl;
+ QFile *database = new QFile(path);
+ bool bOpen = database->open( IO_ReadOnly );
+ if (!bOpen)
+ {
+ path = locate("services", "ksycoca");
+ if (!path.isEmpty())
+ {
+ kdDebug(7011) << "Trying to open global ksycoca from " << path << endl;
+ delete database;
+ database = new QFile(path);
+ bOpen = database->open( IO_ReadOnly );
+ }
+ }
+
+ if (bOpen)
+ {
+ fcntl(database->handle(), F_SETFD, FD_CLOEXEC);
+ m_sycoca_size = database->size();
+#ifdef HAVE_MMAP
+ m_sycoca_mmap = (const char *) mmap(0, m_sycoca_size,
+ PROT_READ, MAP_SHARED,
+ database->handle(), 0);
+ /* POSIX mandates only MAP_FAILED, but we are paranoid so check for
+ null pointer too. */
+ if (m_sycoca_mmap == (const char*) MAP_FAILED || m_sycoca_mmap == 0)
+ {
+ kdDebug(7011) << "mmap failed. (length = " << m_sycoca_size << ")" << endl;
+#endif
+ m_str = new QDataStream(database);
+#ifdef HAVE_MMAP
+ }
+ else
+ {
+#ifdef HAVE_MADVISE
+ (void) madvise((char*)m_sycoca_mmap, m_sycoca_size, MADV_WILLNEED);
+#endif
+ QByteArray b_array;
+ b_array.setRawData(m_sycoca_mmap, m_sycoca_size);
+ QBuffer *buffer = new QBuffer( b_array );
+ buffer->open(IO_ReadWrite);
+ m_str = new QDataStream( buffer);
+ }
+#endif
+ bNoDatabase = false;
+ }
+ else
+ {
+ kdDebug(7011) << "Could not open ksycoca" << endl;
+
+ // No database file
+ delete database;
+ database = 0;
+
+ bNoDatabase = true;
+ if (openDummyIfNotFound)
+ {
+ // We open a dummy database instead.
+ //kdDebug(7011) << "No database, opening a dummy one." << endl;
+ QBuffer *buffer = new QBuffer( QByteArray() );
+ buffer->open(IO_ReadWrite);
+ m_str = new QDataStream( buffer);
+ (*m_str) << (Q_INT32) KSYCOCA_VERSION;
+ (*m_str) << (Q_INT32) 0;
+ }
+ else
+ {
+ result = false;
+ }
+ }
+ m_lstFactories = new KSycocaFactoryList();
+ m_lstFactories->setAutoDelete( true );
+ d->database = database;
+ return result;
+}
+
+// Read-write constructor - only for KBuildSycoca
+KSycoca::KSycoca( bool /* dummy */ )
+ : DCOPObject("ksycoca_building"), m_lstFactories(0), m_str(0), bNoDatabase(false),
+ m_sycoca_size(0), m_sycoca_mmap(0)
+{
+ d = new KSycocaPrivate;
+ m_lstFactories = new KSycocaFactoryList();
+ m_lstFactories->setAutoDelete( true );
+ _self = this;
+}
+
+static void delete_ksycoca_self() {
+ delete KSycoca::_self;
+}
+
+KSycoca * KSycoca::self()
+{
+ if (!_self) {
+ qAddPostRoutine(delete_ksycoca_self);
+ _self = new KSycoca();
+ }
+ return _self;
+}
+
+KSycoca::~KSycoca()
+{
+ closeDatabase();
+ delete d;
+ _self = 0L;
+}
+
+void KSycoca::closeDatabase()
+{
+ QIODevice *device = 0;
+ if (m_str)
+ device = m_str->device();
+#ifdef HAVE_MMAP
+ if (device && m_sycoca_mmap)
+ {
+ QBuffer *buf = (QBuffer *) device;
+ buf->buffer().resetRawData(m_sycoca_mmap, m_sycoca_size);
+ // Solaris has munmap(char*, size_t) and everything else should
+ // be happy with a char* for munmap(void*, size_t)
+ munmap((char*) m_sycoca_mmap, m_sycoca_size);
+ m_sycoca_mmap = 0;
+ }
+#endif
+
+ delete m_str;
+ m_str = 0;
+ delete device;
+ if (d->database != device)
+ delete d->database;
+ device = 0;
+ d->database = 0;
+ // It is very important to delete all factories here
+ // since they cache information about the database file
+ delete m_lstFactories;
+ m_lstFactories = 0L;
+}
+
+void KSycoca::addFactory( KSycocaFactory *factory )
+{
+ assert(m_lstFactories);
+ m_lstFactories->append(factory);
+}
+
+bool KSycoca::isChanged(const char *type)
+{
+ return self()->d->changeList.contains(type);
+}
+
+void KSycoca::notifyDatabaseChanged(const QStringList &changeList)
+{
+ d->changeList = changeList;
+ //kdDebug(7011) << "got a notifyDatabaseChanged signal !" << endl;
+ // kded tells us the database file changed
+ // Close the database and forget all about what we knew
+ // The next call to any public method will recreate
+ // everything that's needed.
+ closeDatabase();
+
+ // Now notify applications
+ emit databaseChanged();
+}
+
+QDataStream * KSycoca::findEntry(int offset, KSycocaType &type)
+{
+ if ( !m_str )
+ openDatabase();
+ //kdDebug(7011) << QString("KSycoca::_findEntry(offset=%1)").arg(offset,8,16) << endl;
+ m_str->device()->at(offset);
+ Q_INT32 aType;
+ (*m_str) >> aType;
+ type = (KSycocaType) aType;
+ //kdDebug(7011) << QString("KSycoca::found type %1").arg(aType) << endl;
+ return m_str;
+}
+
+bool KSycoca::checkVersion(bool abortOnError)
+{
+ if ( !m_str )
+ {
+ if( !openDatabase(false /* don't open dummy db if not found */) )
+ return false; // No database found
+
+ // We should never get here... if a database was found then m_str shouldn't be 0L.
+ assert(m_str);
+ }
+ m_str->device()->at(0);
+ Q_INT32 aVersion;
+ (*m_str) >> aVersion;
+ if ( aVersion < KSYCOCA_VERSION )
+ {
+ kdWarning(7011) << "Found version " << aVersion << ", expecting version " << KSYCOCA_VERSION << " or higher." << endl;
+ if (!abortOnError) return false;
+ kdError(7011) << "Outdated database ! Stop kded and restart it !" << endl;
+ abort();
+ }
+ return true;
+}
+
+QDataStream * KSycoca::findFactory(KSycocaFactoryId id)
+{
+ // The constructor found no database, but we want one
+ if (bNoDatabase)
+ {
+ closeDatabase(); // close the dummy one
+ // Check if new database already available
+ if ( !openDatabase(false /* no dummy one*/) )
+ {
+ static bool triedLaunchingKdeinit = false;
+ if (!triedLaunchingKdeinit) // try only once
+ {
+ triedLaunchingKdeinit = true;
+ kdDebug(7011) << "findFactory: we have no database.... launching kdeinit" << endl;
+ KApplication::startKdeinit();
+ // Ok, the new database should be here now, open it.
+ }
+ if (!openDatabase(false))
+ return 0L; // Still no database - uh oh
+ }
+ }
+ // rewind and check
+ if (!checkVersion(false))
+ {
+ kdWarning(7011) << "Outdated database found" << endl;
+ return 0L;
+ }
+ Q_INT32 aId;
+ Q_INT32 aOffset;
+ while(true)
+ {
+ (*m_str) >> aId;
+ //kdDebug(7011) << QString("KSycoca::findFactory : found factory %1").arg(aId) << endl;
+ if (aId == 0)
+ {
+ kdError(7011) << "Error, KSycocaFactory (id = " << int(id) << ") not found!" << endl;
+ break;
+ }
+ (*m_str) >> aOffset;
+ if (aId == id)
+ {
+ //kdDebug(7011) << QString("KSycoca::findFactory(%1) offset %2").arg((int)id).arg(aOffset) << endl;
+ m_str->device()->at(aOffset);
+ return m_str;
+ }
+ }
+ return 0;
+}
+
+QString KSycoca::kfsstnd_prefixes()
+{
+ if (bNoDatabase) return "";
+ if (!checkVersion(false)) return "";
+ Q_INT32 aId;
+ Q_INT32 aOffset;
+ // skip factories offsets
+ while(true)
+ {
+ (*m_str) >> aId;
+ if ( aId )
+ (*m_str) >> aOffset;
+ else
+ break; // just read 0
+ }
+ // We now point to the header
+ QString prefixes;
+ KSycocaEntry::read(*m_str, prefixes);
+ (*m_str) >> m_timeStamp;
+ KSycocaEntry::read(*m_str, d->language);
+ (*m_str) >> d->updateSig;
+ KSycocaEntry::read(*m_str, d->allResourceDirs);
+ return prefixes;
+}
+
+Q_UINT32 KSycoca::timeStamp()
+{
+ if (!m_timeStamp)
+ (void) kfsstnd_prefixes();
+ return m_timeStamp;
+}
+
+Q_UINT32 KSycoca::updateSignature()
+{
+ if (!m_timeStamp)
+ (void) kfsstnd_prefixes();
+ return d->updateSig;
+}
+
+QString KSycoca::language()
+{
+ if (d->language.isEmpty())
+ (void) kfsstnd_prefixes();
+ return d->language;
+}
+
+QStringList KSycoca::allResourceDirs()
+{
+ if (!m_timeStamp)
+ (void) kfsstnd_prefixes();
+ return d->allResourceDirs;
+}
+
+QString KSycoca::determineRelativePath( const QString & _fullpath, const char *_resource )
+{
+ QString sRelativeFilePath;
+ QStringList dirs = KGlobal::dirs()->resourceDirs( _resource );
+ QStringList::ConstIterator dirsit = dirs.begin();
+ for ( ; dirsit != dirs.end() && sRelativeFilePath.isEmpty(); ++dirsit ) {
+ // might need canonicalPath() ...
+ if ( _fullpath.find( *dirsit ) == 0 ) // path is dirs + relativePath
+ sRelativeFilePath = _fullpath.mid( (*dirsit).length() ); // skip appsdirs
+ }
+ if ( sRelativeFilePath.isEmpty() )
+ kdFatal(7011) << QString("Couldn't find %1 in any %2 dir !!!").arg( _fullpath ).arg( _resource) << endl;
+ //else
+ // debug code
+ //kdDebug(7011) << sRelativeFilePath << endl;
+ return sRelativeFilePath;
+}
+
+KSycoca * KSycoca::_self = 0L;
+
+void KSycoca::flagError()
+{
+ qWarning("ERROR: KSycoca database corruption!");
+ if (_self)
+ {
+ if (_self->d->readError)
+ return;
+ _self->d->readError = true;
+ if (_self->d->autoRebuild)
+ if(system("kbuildsycoca") < 0) // Rebuild the damned thing.
+ qWarning("ERROR: Running KSycoca failed.");
+ }
+}
+
+void KSycoca::disableAutoRebuild()
+{
+ d->autoRebuild = false;
+}
+
+bool KSycoca::readError()
+{
+ bool b = false;
+ if (_self)
+ {
+ b = _self->d->readError;
+ _self->d->readError = false;
+ }
+ return b;
+}
+
+void KSycocaEntry::read( QDataStream &s, QString &str )
+{
+ Q_UINT32 bytes;
+ s >> bytes; // read size of string
+ if ( bytes > 8192 ) { // null string or too big
+ if (bytes != 0xffffffff)
+ KSycoca::flagError();
+ str = QString::null;
+ }
+ else if ( bytes > 0 ) { // not empty
+ int bt = bytes/2;
+ str.setLength( bt );
+ QChar* ch = (QChar *) str.unicode();
+ char t[8192];
+ char *b = t;
+ s.readRawBytes( b, bytes );
+ while ( bt-- ) {
+ *ch++ = (ushort) (((ushort)b[0])<<8) | (uchar)b[1];
+ b += 2;
+ }
+ } else {
+ str = "";
+ }
+}
+
+void KSycocaEntry::read( QDataStream &s, QStringList &list )
+{
+ list.clear();
+ Q_UINT32 count;
+ s >> count; // read size of list
+ if (count >= 1024)
+ {
+ KSycoca::flagError();
+ return;
+ }
+ for(Q_UINT32 i = 0; i < count; i++)
+ {
+ QString str;
+ read(s, str);
+ list.append( str );
+ if (s.atEnd())
+ {
+ KSycoca::flagError();
+ return;
+ }
+ }
+}
+
+void KSycoca::virtual_hook( int id, void* data )
+{ DCOPObject::virtual_hook( id, data ); }
+
+void KSycocaEntry::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "ksycoca.moc"
diff --git a/kdecore/ksycoca.h b/kdecore/ksycoca.h
new file mode 100644
index 000000000..00c72431f
--- /dev/null
+++ b/kdecore/ksycoca.h
@@ -0,0 +1,186 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef __ksycoca_h__
+#define __ksycoca_h__
+
+#include <dcopobject.h>
+#include <qobject.h>
+#include <qstringlist.h>
+#include "ksycocatype.h"
+#include <kdelibs_export.h>
+
+class QDataStream;
+class KSycocaPrivate;
+class KSycocaFactory;
+class KSycocaFactoryList;
+
+/*
+ * Sycoca file version number.
+ * If the existing file is outdated, it will not get read
+ * but instead we'll ask kded to regenerate a new one...
+*/
+#define KSYCOCA_VERSION 94
+
+/**
+ * @internal
+ * Read-only SYstem COnfiguration CAche
+ */
+class KDECORE_EXPORT KSycoca : public QObject, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+
+protected:
+ /**
+ * @internal
+ * Building database
+ */
+ KSycoca( bool /* buildDatabase */ );
+
+public:
+
+ /**
+ * Read-only database
+ */
+ KSycoca();
+
+ /**
+ * Get or create the only instance of KSycoca (read-only)
+ */
+ static KSycoca *self();
+
+ virtual ~KSycoca();
+
+ static int version();
+
+ /**
+ * @internal - called by factories in read-only mode
+ * This is how factories get a stream to an entry
+ */
+ QDataStream *findEntry(int offset, KSycocaType &type);
+ /**
+ * @internal - called by factories in read-only mode
+ */
+ QDataStream *findFactory( KSycocaFactoryId id);
+ /**
+ * @internal - returns kfsstnd stored inside database
+ */
+ QString kfsstnd_prefixes();
+ /**
+ * @internal - returns language stored inside database
+ */
+ QString language();
+
+ /**
+ * @internal - returns timestamp of database
+ *
+ * The database contains all changes made _before_ this time and
+ * _might_ contain changes made after that.
+ */
+ Q_UINT32 timeStamp();
+
+ /**
+ * @internal - returns update signature of database
+ *
+ * Signature that keeps track of changes to
+ * $KDEDIR/share/services/update_ksycoca
+ *
+ * Touching this file causes the database to be recreated
+ * from scratch.
+ */
+ Q_UINT32 updateSignature();
+
+ /**
+ * @internal - returns all directories with information
+ * stored inside sycoca.
+ */
+ QStringList allResourceDirs();
+
+ /**
+ * @internal - add a factory
+ */
+ void addFactory( KSycocaFactory * );
+
+ /**
+ * @internal
+ * @return true if building (i.e. if a KBuildSycoca);
+ */
+ virtual bool isBuilding() { return false; }
+
+ /**
+ * @internal - disables launching of kbuildsycoca
+ */
+ void disableAutoRebuild();
+
+ /**
+ * Determine relative path for a .desktop file from a full path and a resource name
+ */
+ static QString determineRelativePath( const QString & _fullpath, const char *_resource );
+
+ /**
+ * When you receive a "databaseChanged" signal, you can query here if
+ * a change has occurred in a specific resource type.
+ * @see KStandardDirs for the various resource types.
+ */
+ static bool isChanged(const char *type);
+
+ /**
+ * A read error occurs.
+ */
+ static void flagError();
+
+ /**
+ * Returns read error status and clears flag.
+ */
+ static bool readError();
+
+k_dcop:
+ /**
+ * internal function for receiving kded/kbuildsycoca's signal, when the sycoca file changes
+ */
+ void notifyDatabaseChanged(const QStringList &);
+
+signals:
+ /**
+ * Connect to this to get notified when the database changes
+ * (Usually apps showing icons do a 'refresh' to take into account the new mimetypes)
+ */
+ void databaseChanged();
+
+protected:
+ bool checkVersion(bool abortOnError=true);
+ bool openDatabase(bool openDummyIfNotFound=true);
+ void closeDatabase();
+ KSycocaFactoryList *m_lstFactories;
+ QDataStream *m_str;
+ bool bNoDatabase;
+ size_t m_sycoca_size;
+ const char *m_sycoca_mmap;
+ Q_UINT32 m_timeStamp;
+
+public:
+ static KSycoca *_self; // Internal use only.
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KSycocaPrivate *d;
+};
+
+#endif
diff --git a/kdecore/ksycocadict.cpp b/kdecore/ksycocadict.cpp
new file mode 100644
index 000000000..cc7f87471
--- /dev/null
+++ b/kdecore/ksycocadict.cpp
@@ -0,0 +1,454 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "ksycocadict.h"
+#include "ksycocaentry.h"
+#include "ksycoca.h"
+
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <kdebug.h>
+#include <stdlib.h>
+
+namespace
+{
+struct string_entry {
+ string_entry(QString _key, KSycocaEntry *_payload)
+ { keyStr = _key; key = keyStr.unicode(); length = keyStr.length(); payload = _payload; hash = 0; }
+ uint hash;
+ int length;
+ const QChar *key;
+ QString keyStr;
+ KSycocaEntry *payload;
+};
+}
+
+template class QPtrList<string_entry>;
+
+class KSycocaDictStringList : public QPtrList<string_entry>
+{
+public:
+ KSycocaDictStringList();
+};
+
+KSycocaDictStringList::KSycocaDictStringList()
+{
+ setAutoDelete(true);
+}
+
+KSycocaDict::KSycocaDict()
+ : d(0), mStr(0), mOffset(0)
+{
+}
+
+KSycocaDict::KSycocaDict(QDataStream *str, int offset)
+ : d(0), mStr(str), mOffset(offset)
+{
+ Q_UINT32 test1, test2;
+ str->device()->at(offset);
+ (*str) >> test1 >> test2;
+ if ((test1 > 0x000fffff) || (test2 > 1024))
+ {
+ KSycoca::flagError();
+ mHashTableSize = 0;
+ mOffset = 0;
+ return;
+ }
+
+ str->device()->at(offset);
+ (*str) >> mHashTableSize;
+ (*str) >> mHashList;
+ mOffset = str->device()->at(); // Start of hashtable
+}
+
+KSycocaDict::~KSycocaDict()
+{
+ delete d;
+}
+
+void
+KSycocaDict::add(const QString &key, KSycocaEntry *payload)
+{
+ if (key.isEmpty()) return; // Not allowed (should never happen)
+ if (!payload) return; // Not allowed!
+ if (!d)
+ {
+ d = new KSycocaDictStringList();
+ }
+
+ string_entry *entry= new string_entry(key, payload);
+ d->append(entry);
+}
+
+void
+KSycocaDict::remove(const QString &key)
+{
+ if (d)
+ {
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ if (entry->keyStr == key)
+ {
+ d->remove();
+ break;
+ }
+ }
+ }
+}
+
+int
+KSycocaDict::find_string(const QString &key )
+{
+ //kdDebug(7011) << QString("KSycocaDict::find_string(%1)").arg(key) << endl;
+
+ if (!mStr || !mOffset)
+ {
+ kdError(7011) << "No database available!" << endl;
+ return 0;
+ }
+
+ if (mHashTableSize == 0)
+ return 0; // Unlikely to find anything :-]
+
+ // Read hash-table data
+ uint hash = hashKey(key) % mHashTableSize;
+ //kdDebug(7011) << QString("hash is %1").arg(hash) << endl;
+
+ uint off = mOffset+sizeof(Q_INT32)*hash;
+ //kdDebug(7011) << QString("off is %1").arg(off,8,16) << endl;
+ mStr->device()->at( off );
+
+ Q_INT32 offset;
+ (*mStr) >> offset;
+
+ //kdDebug(7011) << QString("offset is %1").arg(offset,8,16) << endl;
+ if (offset == 0)
+ return 0;
+
+ if (offset > 0)
+ return offset; // Positive ID
+
+ // Lookup duplicate list.
+ offset = -offset;
+
+ mStr->device()->at(offset);
+ //kdDebug(7011) << QString("Looking up duplicate list at %1").arg(offset,8,16) << endl;
+
+ while(true)
+ {
+ (*mStr) >> offset;
+ if (offset == 0) break;
+ QString dupkey;
+ (*mStr) >> dupkey;
+ //kdDebug(7011) << QString(">> %1 %2").arg(offset,8,16).arg(dupkey) << endl;
+ if (dupkey == key) return offset;
+ }
+ //kdWarning(7011) << "Not found!" << endl;
+
+ return 0;
+}
+
+uint
+KSycocaDict::count()
+{
+ if (!d) return 0;
+
+ return d->count();
+}
+
+void
+KSycocaDict::clear()
+{
+ delete d;
+ d = 0;
+}
+
+uint
+KSycocaDict::hashKey( const QString &key)
+{
+ int l = key.length();
+ register uint h = 0;
+
+ for(uint i = 0; i < mHashList.count(); i++)
+ {
+ int pos = mHashList[i];
+ if (pos < 0)
+ {
+ pos = -pos-1;
+ if (pos < l)
+ h = ((h * 13) + (key[l-pos].cell() % 29)) & 0x3ffffff;
+ }
+ else
+ {
+ pos = pos-1;
+ if (pos < l)
+ h = ((h * 13) + (key[pos].cell() % 29)) & 0x3ffffff;
+ }
+ }
+ return h;
+}
+
+//
+// Calculate the diversity of the strings at position 'pos'
+static int
+calcDiversity(KSycocaDictStringList *d, int pos, int sz)
+{
+ if (pos == 0) return 0;
+ bool *matrix = (bool *) calloc(sz, sizeof(bool));
+ uint usz = sz;
+
+ if (pos < 0)
+ {
+ pos = -pos-1;
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ register int l = entry->length;
+ if (pos < l && pos != 0)
+ {
+ register uint hash = ((entry->hash * 13) + (entry->key[l-pos].cell() % 29)) & 0x3ffffff;
+ matrix[ hash % usz ] = true;
+ }
+ }
+ }
+ else
+ {
+ pos = pos-1;
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ if (pos < entry->length)
+ {
+ register uint hash = ((entry->hash * 13) + (entry->key[pos].cell() % 29)) & 0x3ffffff;
+ matrix[ hash % usz ] = true;
+ }
+ }
+ }
+ int diversity = 0;
+ for(int i=0;i< sz;i++)
+ if (matrix[i]) diversity++;
+
+ free((void *) matrix);
+
+ return diversity;
+}
+
+//
+// Add the diversity of the strings at position 'pos'
+static void
+addDiversity(KSycocaDictStringList *d, int pos)
+{
+ if (pos == 0) return;
+ if (pos < 0)
+ {
+ pos = -pos-1;
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ register int l = entry->length;
+ if (pos < l)
+ entry->hash = ((entry->hash * 13) + (entry->key[l-pos].cell() % 29)) & 0x3fffffff;
+ }
+ }
+ else
+ {
+ pos = pos - 1;
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ if (pos < entry->length)
+ entry->hash = ((entry->hash * 13) + (entry->key[pos].cell() % 29)) & 0x3fffffff;
+ }
+ }
+}
+
+
+void
+KSycocaDict::save(QDataStream &str)
+{
+ if (count() == 0)
+ {
+ mHashTableSize = 0;
+ mHashList.clear();
+ str << mHashTableSize;
+ str << mHashList;
+ return;
+ }
+
+ mOffset = str.device()->at();
+
+ //kdDebug(7011) << QString("KSycocaDict: %1 entries.").arg(count()) << endl;
+
+ //kdDebug(7011) << "Calculating hash keys.." << endl;
+
+ int maxLength = 0;
+ //kdDebug(7011) << "Finding maximum string length" << endl;
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ entry->hash = 0;
+ if (entry->length > maxLength)
+ maxLength = entry->length;
+ }
+
+ //kdDebug(7011) << QString("Max string length = %1").arg(maxLength) << endl;
+
+ // use "almost prime" number for sz (to calculate diversity) and later
+ // for the table size of big tables
+ // int sz = d->count()*5-1;
+ register unsigned int sz = count()*4 + 1;
+ while(!(((sz % 3) && (sz % 5) && (sz % 7) && (sz % 11) && (sz % 13)))) sz+=2;
+
+ int maxDiv = 0;
+ int maxPos = 0;
+ int lastDiv = 0;
+
+ mHashList.clear();
+
+ // try to limit diversity scan by "predicting" positions
+ // with high diversity
+ int *oldvec=new int[maxLength*2+1];
+ for (int i=0; i<(maxLength*2+1); i++) oldvec[i]=0;
+ int mindiv=0;
+
+ while(true)
+ {
+ int divsum=0,divnum=0;
+
+ maxDiv = 0;
+ maxPos = 0;
+ for(int pos=-maxLength; pos <= maxLength; pos++)
+ {
+ // cut off
+ if (oldvec[pos+maxLength]<mindiv)
+ { oldvec[pos+maxLength]=0; continue; }
+
+ int diversity = calcDiversity(d, pos, sz);
+ if (diversity > maxDiv)
+ {
+ maxDiv = diversity;
+ maxPos = pos;
+ }
+ oldvec[pos+maxLength]=diversity;
+ divsum+=diversity; divnum++;
+ }
+ // arbitrary cut-off value 3/4 of average seems to work
+ if (divnum)
+ mindiv=(3*divsum)/(4*divnum);
+
+ if (maxDiv <= lastDiv)
+ break;
+ // qWarning("Max Div = %d at pos %d", maxDiv, maxPos);
+ lastDiv = maxDiv;
+ addDiversity(d, maxPos);
+ mHashList.append(maxPos);
+ }
+
+ delete [] oldvec;
+
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ entry->hash = hashKey(entry->keyStr);
+ }
+// fprintf(stderr, "Calculating minimum table size..\n");
+
+ mHashTableSize = sz;
+
+ struct hashtable_entry {
+ string_entry *entry;
+ QPtrList<string_entry> *duplicates;
+ int duplicate_offset;
+ };
+
+ hashtable_entry *hashTable = new hashtable_entry[ sz ];
+
+ //kdDebug(7011) << "Clearing hashtable..." << endl;
+ for (unsigned int i=0; i < sz; i++)
+ {
+ hashTable[i].entry = 0;
+ hashTable[i].duplicates = 0;
+ }
+
+ //kdDebug(7011) << "Filling hashtable..." << endl;
+ for(string_entry *entry=d->first(); entry; entry = d->next())
+ {
+ int hash = entry->hash % sz;
+ if (!hashTable[hash].entry)
+ { // First entry
+ hashTable[hash].entry = entry;
+ }
+ else
+ {
+ if (!hashTable[hash].duplicates)
+ { // Second entry, build duplicate list.
+ hashTable[hash].duplicates = new QPtrList<string_entry>();
+ hashTable[hash].duplicates->append(hashTable[hash].entry);
+ hashTable[hash].duplicate_offset = 0;
+ }
+ hashTable[hash].duplicates->append(entry);
+ }
+ }
+
+ str << mHashTableSize;
+ str << mHashList;
+
+ mOffset = str.device()->at(); // mOffset points to start of hashTable
+ //kdDebug(7011) << QString("Start of Hash Table, offset = %1").arg(mOffset,8,16) << endl;
+
+ for(int pass = 1; pass <= 2; pass++)
+ {
+ str.device()->at(mOffset);
+ //kdDebug(7011) << QString("Writing hash table (pass #%1)").arg(pass) << endl;
+ for(uint i=0; i < mHashTableSize; i++)
+ {
+ Q_INT32 tmpid;
+ if (!hashTable[i].entry)
+ tmpid = (Q_INT32) 0;
+ else if (!hashTable[i].duplicates)
+ tmpid = (Q_INT32) hashTable[i].entry->payload->offset(); // Positive ID
+ else
+ tmpid = (Q_INT32) -hashTable[i].duplicate_offset; // Negative ID
+ str << tmpid;
+ //kdDebug(7011) << QString("Hash table : %1").arg(tmpid,8,16) << endl;
+ }
+ //kdDebug(7011) << QString("End of Hash Table, offset = %1").arg(str.device()->at(),8,16) << endl;
+
+ //kdDebug(7011) << QString("Writing duplicate lists (pass #%1)").arg(pass) << endl;
+ for(uint i=0; i < mHashTableSize; i++)
+ {
+ if (hashTable[i].duplicates)
+ {
+ QPtrList<string_entry> *dups = hashTable[i].duplicates;
+ hashTable[i].duplicate_offset = str.device()->at();
+
+ /*kdDebug(7011) << QString("Duplicate lists: Offset = %1 list_size = %2") .arg(hashTable[i].duplicate_offset,8,16).arg(dups->count()) << endl;
+*/
+ for(string_entry *dup = dups->first(); dup; dup=dups->next())
+ {
+ str << (Q_INT32) dup->payload->offset(); // Positive ID
+ str << dup->keyStr; // Key (QString)
+ }
+ str << (Q_INT32) 0; // End of list marker (0)
+ }
+ }
+ //kdDebug(7011) << QString("End of Dict, offset = %1").arg(str.device()->at(),8,16) << endl;
+ }
+
+ //kdDebug(7011) << "Cleaning up hash table." << endl;
+ for(uint i=0; i < mHashTableSize; i++)
+ {
+ delete hashTable[i].duplicates;
+ }
+ delete [] hashTable;
+}
+
diff --git a/kdecore/ksycocadict.h b/kdecore/ksycocadict.h
new file mode 100644
index 000000000..dec6a8cc8
--- /dev/null
+++ b/kdecore/ksycocadict.h
@@ -0,0 +1,123 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef __ksycocadict_h__
+#define __ksycocadict_h__
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <qdatastream.h>
+#include "kdelibs_export.h"
+
+class KSycocaEntry;
+class KSycocaDictStringList;
+
+/**
+ * @internal
+ * Hash table implementation for the sycoca database file
+ */
+class KDECORE_EXPORT KSycocaDict
+{
+public:
+ /**
+ * Create an empty dict, for building the database
+ */
+ KSycocaDict();
+ /**
+ * Create a dict from an existing database
+ */
+ KSycocaDict(QDataStream *str, int offset);
+
+ ~KSycocaDict();
+
+ /**
+ * Adds a 'payload' to the dictionary with key 'key'.
+ *
+ * 'payload' should have a valid offset by the time
+ * the dictionary gets saved.
+ **/
+ void add(const QString &key, KSycocaEntry *payload);
+
+ /**
+ * Removes the 'payload' from the dictionary with key 'key'.
+ *
+ * Not very fast, use with care O(N)
+ **/
+ void remove(const QString &key);
+
+ /**
+ * Looks up an entry identified by 'key'.
+ *
+ * If 0 is returned, no matching entry exists.
+ * Otherwise, the offset of the entry is returned.
+ *
+ * NOTE: It is not guaranteed that this entry is
+ * indeed the one you were looking for.
+ * After loading the entry you should check that it
+ * indeed matches the search key. If it doesn't
+ * then no matching entry exists.
+ */
+ int find_string(const QString &key );
+
+ /**
+ * The number of entries in the dictionary.
+ *
+ * Only valid when building the database.
+ */
+ uint count();
+
+ /**
+ * Reset the dictionary.
+ *
+ * Only valid when building the database.
+ */
+ void clear();
+
+ /**
+ * Save the dictionary to the stream
+ * A reasonable fast hash algorithm will be created.
+ *
+ * Typically this will find 90% of the entries directly.
+ * Average hash table size: nrOfItems * 20 bytes.
+ * Average duplicate list size: nrOfItms * avgKeyLength / 5.
+ *
+ * Unknown keys have an average 20% chance to give a false hit.
+ * (That's why your program should check the result)
+ *
+ * Example:
+ * Assume 1000 items with an average key length of 60 bytes.
+ *
+ * Approx. 900 items will hash directly to the right entry.
+ * Approx. 100 items require a lookup in the duplicate list.
+ *
+ * The hash table size will be approx. 20Kb.
+ * The duplicate list size will be approx. 12Kb.
+ **/
+ void save(QDataStream &str);
+
+protected:
+ Q_UINT32 hashKey( const QString &);
+private:
+ KSycocaDictStringList *d;
+ QDataStream *mStr;
+ Q_INT32 mOffset;
+ Q_UINT32 mHashTableSize;
+ QValueList<Q_INT32> mHashList;
+};
+
+#endif
diff --git a/kdecore/ksycocaentry.h b/kdecore/ksycocaentry.h
new file mode 100644
index 000000000..93ec00eb1
--- /dev/null
+++ b/kdecore/ksycocaentry.h
@@ -0,0 +1,123 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef __ksycocaentry_h__
+#define __ksycocaentry_h__
+
+#include "ksycocatype.h"
+
+#include <qstringlist.h>
+#include <ksharedptr.h>
+class QDataStream;
+
+/**
+ * Base class for all Sycoca entries.
+ *
+ * You can't create an instance of KSycocaEntry, but it provides
+ * the common functionality for servicetypes and services.
+ *
+ * @internal
+ * @see http://developer.kde.org/documentation/library/kdeqt/kde3arch/ksycoca.html
+ */
+class KDECORE_EXPORT KSycocaEntry : public KShared
+{
+
+public:
+ virtual bool isType(KSycocaType t) const { return (t == KST_KSycocaEntry); }
+ virtual KSycocaType sycocaType() const { return KST_KSycocaEntry; }
+
+public:
+ typedef KSharedPtr<KSycocaEntry> Ptr;
+ typedef QValueList<Ptr> List;
+public: // KDoc seems to barf on those typedefs and generates no docs after them
+ /**
+ * Default constructor
+ */
+ KSycocaEntry(const QString &path) : mOffset(0), m_bDeleted(false), mPath(path) { }
+
+ /**
+ * Safe demarshalling functions.
+ */
+ static void read( QDataStream &s, QString &str );
+ static void read( QDataStream &s, QStringList &list );
+
+ /**
+ * @internal
+ * Restores itself from a stream.
+ */
+ KSycocaEntry( QDataStream &_str, int offset ) :
+ mOffset( offset ), m_bDeleted(false)
+ {
+ read(_str, mPath);
+ }
+
+ /**
+ * @return the name of this entry
+ */
+ virtual QString name() const = 0;
+
+ /**
+ * @return the path of this entry
+ * The path can be absolute or relative.
+ * The corresponding factory should know relative to what.
+ */
+ QString entryPath() const { return mPath; }
+
+ /**
+ * @return true if valid
+ */
+ virtual bool isValid() const = 0;
+
+ /**
+ * @return true if deleted
+ */
+ virtual bool isDeleted() const { return m_bDeleted; }
+
+ /**
+ * @internal
+ * @return the position of the entry in the sycoca file
+ */
+ int offset() { return mOffset; }
+
+ /**
+ * @internal
+ * Save ourselves to the database. Don't forget to call the parent class
+ * first if you override this function.
+ */
+ virtual void save(QDataStream &s)
+ {
+ mOffset = s.device()->at(); // store position in member variable
+ s << (Q_INT32) sycocaType() << mPath;
+ }
+
+ /**
+ * @internal
+ * Load ourselves from the database. Don't call the parent class!
+ */
+ virtual void load(QDataStream &) = 0;
+
+private:
+ int mOffset;
+protected:
+ bool m_bDeleted;
+ QString mPath;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+#endif
diff --git a/kdecore/ksycocafactory.cpp b/kdecore/ksycocafactory.cpp
new file mode 100644
index 000000000..3542fa0cb
--- /dev/null
+++ b/kdecore/ksycocafactory.cpp
@@ -0,0 +1,202 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 David Faure <faure@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "ksycoca.h"
+#include "ksycocatype.h"
+#include "ksycocafactory.h"
+#include "ksycocaentry.h"
+#include "ksycocadict.h"
+#include <qstringlist.h>
+#include <qdict.h>
+#include <kdebug.h>
+
+template class QDict<KSycocaEntry>;
+template class QDict<KSharedPtr<KSycocaEntry> >;
+
+KSycocaFactory::KSycocaFactory(KSycocaFactoryId factory_id)
+ : m_resourceList(0), m_entryDict(0), m_sycocaDict(0)
+{
+ if (!KSycoca::self()->isBuilding()) // read-only database ?
+ {
+ m_str = KSycoca::self()->findFactory( factory_id );
+ // can't call factoryId() here since the constructor can't call inherited methods
+ if (m_str) // Can be 0 in case of errors
+ {
+ // Read position of index tables....
+ Q_INT32 i;
+ (*m_str) >> i;
+ m_sycocaDictOffset = i;
+ (*m_str) >> i;
+ m_beginEntryOffset = i;
+ (*m_str) >> i;
+ m_endEntryOffset = i;
+
+ int saveOffset = m_str->device()->at();
+ // Init index tables
+ m_sycocaDict = new KSycocaDict(m_str, m_sycocaDictOffset);
+ saveOffset = m_str->device()->at(saveOffset);
+ }
+ }
+ else
+ {
+ // Build new database!
+ m_str = 0;
+ m_resourceList = 0;
+ m_entryDict = new KSycocaEntryDict(977);
+ m_entryDict->setAutoDelete(true);
+ m_sycocaDict = new KSycocaDict();
+ m_beginEntryOffset = 0;
+ m_endEntryOffset = 0;
+
+ // m_resourceList will be filled in by inherited constructors
+ }
+ KSycoca::self()->addFactory(this);
+}
+
+KSycocaFactory::~KSycocaFactory()
+{
+ delete m_entryDict;
+ delete m_sycocaDict;
+}
+
+void
+KSycocaFactory::saveHeader(QDataStream &str)
+{
+ // Write header
+ str.device()->at(mOffset);
+ str << (Q_INT32) m_sycocaDictOffset;
+ str << (Q_INT32) m_beginEntryOffset;
+ str << (Q_INT32) m_endEntryOffset;
+}
+
+void
+KSycocaFactory::save(QDataStream &str)
+{
+ if (!m_entryDict) return; // Error! Function should only be called when
+ // building database
+ if (!m_sycocaDict) return; // Error!
+
+ mOffset = str.device()->at(); // store position in member variable
+ m_sycocaDictOffset = 0;
+
+ // Write header (pass #1)
+ saveHeader(str);
+
+ m_beginEntryOffset = str.device()->at();
+
+ // Write all entries.
+ int entryCount = 0;
+ for(QDictIterator<KSycocaEntry::Ptr> it ( *m_entryDict );
+ it.current();
+ ++it)
+ {
+ KSycocaEntry *entry = (*it.current());
+ entry->save(str);
+ entryCount++;
+ }
+
+ m_endEntryOffset = str.device()->at();
+
+ // Write indices...
+ // Linear index
+ str << (Q_INT32) entryCount;
+ for(QDictIterator<KSycocaEntry::Ptr> it ( *m_entryDict );
+ it.current();
+ ++it)
+ {
+ KSycocaEntry *entry = (*it.current());
+ str << (Q_INT32) entry->offset();
+ }
+
+ // Dictionary index
+ m_sycocaDictOffset = str.device()->at();
+ m_sycocaDict->save(str);
+
+ int endOfFactoryData = str.device()->at();
+
+ // Update header (pass #2)
+ saveHeader(str);
+
+ // Seek to end.
+ str.device()->at(endOfFactoryData);
+}
+
+void
+KSycocaFactory::addEntry(KSycocaEntry *newEntry, const char *)
+{
+ if (!m_entryDict) return; // Error! Function should only be called when
+ // building database
+
+ if (!m_sycocaDict) return; // Error!
+
+ QString name = newEntry->name();
+ m_entryDict->insert( name, new KSycocaEntry::Ptr(newEntry) );
+ m_sycocaDict->add( name, newEntry );
+}
+
+void
+KSycocaFactory::removeEntry(KSycocaEntry *newEntry)
+{
+ if (!m_entryDict) return; // Error! Function should only be called when
+ // building database
+
+ if (!m_sycocaDict) return; // Error!
+
+ QString name = newEntry->name();
+ m_entryDict->remove( name );
+ m_sycocaDict->remove( name );
+}
+
+KSycocaEntry::List KSycocaFactory::allEntries()
+{
+ KSycocaEntry::List list;
+ if (!m_str) return list;
+
+ // Assume we're NOT building a database
+
+ m_str->device()->at(m_endEntryOffset);
+ Q_INT32 entryCount;
+ (*m_str) >> entryCount;
+
+ if (entryCount > 8192)
+ {
+ KSycoca::flagError();
+ return list;
+ }
+
+ Q_INT32 *offsetList = new Q_INT32[entryCount];
+ for(int i = 0; i < entryCount; i++)
+ {
+ (*m_str) >> offsetList[i];
+ }
+
+ for(int i = 0; i < entryCount; i++)
+ {
+ KSycocaEntry *newEntry = createEntry(offsetList[i]);
+ if (newEntry)
+ {
+ list.append( KSycocaEntry::Ptr( newEntry ) );
+ }
+ }
+ delete [] offsetList;
+ return list;
+}
+
+void KSycocaFactory::virtual_hook( int /*id*/, void* /*data*/)
+{ /*BASE::virtual_hook( id, data );*/ }
+
diff --git a/kdecore/ksycocafactory.h b/kdecore/ksycocafactory.h
new file mode 100644
index 000000000..65bb9d98e
--- /dev/null
+++ b/kdecore/ksycocafactory.h
@@ -0,0 +1,143 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef __ksycocafactory_h__
+#define __ksycocafactory_h__
+
+#include "ksycocatype.h"
+#include "ksycocaentry.h"
+
+#include <qdict.h>
+#include <qptrlist.h>
+class KSycoca;
+class QStringList;
+class QString;
+class KSycocaDict;
+class KSycocaResourceList;
+
+typedef QDict<KSycocaEntry::Ptr> KSycocaEntryDict;
+
+/**
+ * @internal
+ * Base class for sycoca factories
+ */
+class KDECORE_EXPORT KSycocaFactory
+{
+public:
+ virtual KSycocaFactoryId factoryId() const = 0;
+
+protected: // virtual class
+ /**
+ * Create a factory which can be used to lookup from/create a database
+ * (depending on KSycoca::isBuilding())
+ */
+ KSycocaFactory( KSycocaFactoryId factory_id );
+
+public:
+ virtual ~KSycocaFactory();
+
+ /**
+ * @return the position of the factory in the sycoca file
+ */
+ int offset() { return mOffset; }
+
+ /**
+ * @return the dict, for special use by KBuildSycoca
+ */
+ KSycocaEntryDict * entryDict() { return m_entryDict; }
+
+ /**
+ * Construct an entry from a config file.
+ * To be implemented in the real factories.
+ */
+ virtual KSycocaEntry *createEntry(const QString &file, const char *resource) = 0;
+
+ /**
+ * Add an entry
+ */
+ virtual void addEntry(KSycocaEntry *newEntry, const char *resource);
+
+ /**
+ * Remove an entry
+ * Not very fast, use with care. O(N)
+ */
+ void removeEntry(KSycocaEntry *newEntry);
+
+ /**
+ * Read an entry from the database
+ */
+ virtual KSycocaEntry *createEntry(int offset)=0;
+
+ /**
+ * Get a list of all entries from the database.
+ */
+ KSycocaEntry::List allEntries();
+
+ /**
+ * Saves all entries it maintains as well as index files
+ * for these entries to the stream 'str'.
+ *
+ * Also sets mOffset to the starting position.
+ *
+ * The stream is positioned at the end of the last index.
+ *
+ * Don't forget to call the parent first when you override
+ * this function.
+ */
+ virtual void save(QDataStream &str);
+
+ /**
+ * Writes out a header to the stream 'str'.
+ * The baseclass positions the stream correctly.
+ *
+ * Don't forget to call the parent first when you override
+ * this function.
+ */
+ virtual void saveHeader(QDataStream &str);
+
+ /**
+ * @return the resources for which this factory is responsible.
+ */
+ virtual const KSycocaResourceList * resourceList() const { return m_resourceList; }
+
+private:
+ int mOffset;
+
+protected:
+ int m_sycocaDictOffset;
+ int m_beginEntryOffset;
+ int m_endEntryOffset;
+ QDataStream *m_str;
+
+ KSycocaResourceList *m_resourceList;
+ KSycocaEntryDict *m_entryDict;
+ KSycocaDict *m_sycocaDict;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/** This, instead of a typedef, allows to declare "class ..." in header files
+ * @internal
+ */
+class KDECORE_EXPORT KSycocaFactoryList : public QPtrList<KSycocaFactory>
+{
+public:
+ KSycocaFactoryList() { }
+};
+
+#endif
diff --git a/kdecore/ksycocatype.h b/kdecore/ksycocatype.h
new file mode 100644
index 000000000..889c3be6d
--- /dev/null
+++ b/kdecore/ksycocatype.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __ksycocatype_h__
+#define __ksycocatype_h__
+
+/**
+ * \relates KSycocaEntry
+ * A KSycocaType is a code (out of the KSycocaType enum) assigned to each
+ * class type derived from KSycocaEntry .
+ * To use it, call the macro K_SYCOCATYPE( your_typecode, parent_class )
+ * at the top of your class definition.
+ */
+enum KSycocaType { KST_KSycocaEntry = 0, KST_KService = 1, KST_KServiceType = 2, KST_KMimeType = 3,
+ KST_KFolderType = 4, KST_KDEDesktopMimeType = 5, KST_KExecMimeType = 6,
+ KST_KServiceGroup = 7, KST_KImageIOFormat = 8, KST_KProtocolInfo = 9,
+ KST_KServiceSeparator = 10,
+ KST_KCustom = 1000 };
+
+#define K_SYCOCATYPE( type, baseclass ) \
+public: \
+ virtual bool isType(KSycocaType t) const { if (t == type) return true; return baseclass::isType(t);} \
+ virtual KSycocaType sycocaType() const { return type; } \
+private:
+
+/**
+ * \relates KSycocaFactory
+ * A KSycocaFactoryId is a code (out of the KSycocaFactoryId enum)
+ * assigned to each class type derived from KSycocaFactory.
+ * To use it, call the macro K_SYCOCAFACTORY( your_factory_id )
+ * at the top of your class definition.
+ */
+enum KSycocaFactoryId { KST_KServiceFactory = 1,
+ KST_KServiceTypeFactory = 2,
+ KST_KServiceGroupFactory = 3,
+ KST_KImageIO = 4,
+ KST_KProtocolInfoFactory = 5,
+ KST_CTimeInfo = 100 };
+
+#define K_SYCOCAFACTORY( factory_id ) \
+public: \
+ virtual KSycocaFactoryId factoryId() const { return factory_id; } \
+private:
+
+
+
+#endif
diff --git a/kdecore/ktempdir.cpp b/kdecore/ktempdir.cpp
new file mode 100644
index 000000000..141ee71a0
--- /dev/null
+++ b/kdecore/ktempdir.cpp
@@ -0,0 +1,218 @@
+/*
+ *
+ * This file is part of the KDE libraries
+ * Copyright (c) 2003 Joseph Wenninger <jowenn@kde.org>
+ *
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#ifdef HAVE_TEST
+#include <test.h>
+#endif
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef _PATH_TMP
+#define _PATH_TMP "/tmp"
+#endif
+
+#include <qdatetime.h>
+#include <qdir.h>
+
+#include "kglobal.h"
+#include "kapplication.h"
+#include "kinstance.h"
+#include "ktempdir.h"
+#include "kstandarddirs.h"
+#include "kprocess.h"
+#include <kdebug.h>
+#include "kde_file.h"
+
+KTempDir::KTempDir(QString directoryPrefix, int mode)
+{
+ bAutoDelete = false;
+ bExisting = false;
+ mError=0;
+ if (directoryPrefix.isEmpty())
+ {
+ directoryPrefix = locateLocal("tmp", KGlobal::instance()->instanceName());
+ }
+ (void) create(directoryPrefix , mode);
+}
+
+bool
+KTempDir::create(const QString &directoryPrefix, int mode)
+{
+ // make sure the random seed is randomized
+ (void) KApplication::random();
+
+ QCString nme = QFile::encodeName(directoryPrefix) + "XXXXXX";
+ char *realName;
+ if((realName=mkdtemp(nme.data())) == 0)
+ {
+ // Recreate it for the warning, mkdtemps emptied it
+ QCString nme = QFile::encodeName(directoryPrefix) + "XXXXXX";
+ qWarning("KTempDir: Error trying to create %s: %s", nme.data(), strerror(errno));
+ mError = errno;
+ mTmpName = QString::null;
+ return false;
+ }
+
+ // got a return value != 0
+ QCString realNameStr(realName);
+ mTmpName = QFile::decodeName(realNameStr)+"/";
+ kdDebug(180) << "KTempDir: Temporary directory created :" << mTmpName << endl;
+ mode_t tmp = 0;
+ mode_t umsk = umask(tmp);
+ umask(umsk);
+ chmod(nme, mode&(~umsk));
+
+ // Success!
+ bExisting = true;
+
+ // Set uid/gid (necessary for SUID programs)
+ chown(nme, getuid(), getgid());
+ return true;
+}
+
+KTempDir::~KTempDir()
+{
+ if (bAutoDelete)
+ unlink();
+
+// KTempDirPrivate doesn't exist, so it can't be deleted
+// delete d;
+}
+
+int
+KTempDir::status() const
+{
+ return mError;
+}
+
+QString
+KTempDir::name() const
+{
+ return mTmpName;
+}
+
+bool
+KTempDir::existing() const
+{
+ return bExisting;
+}
+
+QDir *
+KTempDir::qDir()
+{
+ if (bExisting) return new QDir(mTmpName);
+ return 0;
+}
+
+void
+KTempDir::unlink()
+{
+ if (!bExisting) return;
+ if (KTempDir::removeDir(mTmpName))
+ mError=0;
+ else
+ mError=errno;
+ bExisting=false;
+}
+
+// Auxiliary recursive function for removeDirs
+static bool
+rmtree(const QCString& name)
+{
+ kdDebug() << "Checking directory for remove " << name << endl;
+ KDE_struct_stat st;
+ if ( KDE_lstat( name.data(), &st ) == -1 ) // Do not dereference symlink!
+ return false;
+ if ( S_ISDIR( st.st_mode ) )
+ {
+ // This is a directory, so process it
+ kdDebug() << "File " << name << " is DIRECTORY!" << endl;
+ KDE_struct_dirent* ep;
+ DIR* dp = ::opendir( name.data() );
+ if ( !dp )
+ return false;
+ while ( ( ep = KDE_readdir( dp ) ) )
+ {
+ kdDebug() << "CHECKING " << name << "/" << ep->d_name << endl;
+ if ( !qstrcmp( ep->d_name, "." ) || !qstrcmp( ep->d_name, ".." ) )
+ continue;
+ QCString newName( name );
+ newName += "/"; // Careful: do not add '/' instead or you get problems with Qt3.
+ newName += ep->d_name;
+ /*
+ * Be defensive and close the directory.
+ *
+ * Potential problems:
+ * - opendir/readdir/closedir is not re-entrant
+ * - unlink and rmdir invalidates a opendir/readdir/closedir
+ * - limited number of file descriptors for opendir/readdir/closedir
+ */
+ if ( ::closedir( dp ) )
+ return false;
+ // Recurse!
+ kdDebug() << "RECURSE: " << newName << endl;
+ if ( ! rmtree( newName ) )
+ return false;
+ // We have to re-open the directory before continuing
+ dp = ::opendir( name.data() );
+ if ( !dp )
+ return false;
+ }
+ if ( ::closedir( dp ) )
+ return false;
+ kdDebug() << "RMDIR dir " << name << endl;
+ return ! ::rmdir( name );
+ }
+ else
+ {
+ // This is a non-directory file, so remove it
+ kdDebug() << "UNLINKING file " << name << endl;
+ return ! ::unlink( name );
+ }
+}
+
+bool
+KTempDir::removeDir(const QString& path)
+{
+ kdDebug() << k_funcinfo << " " << path << endl;
+ if ( !QFile::exists( path ) )
+ return true; // The goal is that there is no directory
+
+ const QCString cstr( QFile::encodeName( path ) );
+ return rmtree( cstr );
+}
+
+
diff --git a/kdecore/ktempdir.h b/kdecore/ktempdir.h
new file mode 100644
index 000000000..e8455e479
--- /dev/null
+++ b/kdecore/ktempdir.h
@@ -0,0 +1,172 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2003 Joseph Wenninger <jowenn@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KTEMPDIR_H_
+#define _KTEMPDIR_H_
+
+#include <qstring.h>
+#include <stdio.h>
+#include <errno.h>
+#include "kdelibs_export.h"
+
+class QDir;
+class KTempDirPrivate;
+
+/**
+ * The KTempDir class creates a unique directory for temporary use.
+ *
+ * This is especially useful if you need to create a directory in a world
+ * writable directory like /tmp without being vulnerable to so called
+ * symlink attacks.
+ *
+ * KDE applications, however, shouldn't create files or directories in /tmp in the first
+ * place but use the "tmp" resource instead. The standard KTempDir
+ * constructor will do that by default.
+ *
+ * To create a temporary directory that starts with a certain name
+ * in the "tmp" resource, one should use:
+ * KTempDir(locateLocal("tmp", prefix));
+ *
+ * KTempFile does not create any missing directories, but locateLocal() does.
+ *
+ * See also KStandardDirs
+ *
+ * @since 3.2
+ * @author Joseph Wenninger <jowenn@kde.org>
+ */
+class KDECORE_EXPORT KTempDir
+{
+public:
+ /**
+ * Creates a temporary directory with the name:
+ * \p \<directoryPrefix\>\<six letters\>
+ *
+ * The default \p directoryPrefix is "$KDEHOME/tmp-$HOST/appname"
+ * @param directoryPrefix the prefix of the file name, or
+ * QString::null for the default value
+ * @param mode the file permissions,
+ * almost always in octal. The first digit selects permissions for
+ * the user who owns the file: read (4), write (2), and execute
+ * (1); the second selects permissions for other users in the
+ * file's group, with the same values; and the fourth for other
+ * users not in the file's group, with the same values.
+ *
+ **/
+ KTempDir(QString directoryPrefix=QString::null,
+ int mode = 0700 );
+
+
+ /**
+ * The destructor deletes the directory and it's contents if autoDelete is enabled
+ **/
+ ~KTempDir();
+
+ /**
+ * Turn automatic deletion on or off.
+ * Automatic deletion is off by default.
+ * @param autoDelete true to turn automatic deletion on
+ **/
+ void setAutoDelete(bool autoDelete) { bAutoDelete = autoDelete; }
+
+ /**
+ * Returns the status of the directory creation based on errno. (see errno.h)
+ * 0 means OK.
+ *
+ * You should check the status after object creation to check
+ * whether a directory could be created in the first place.
+ *
+ * @return the errno status, 0 means ok
+ **/
+ int status() const;
+
+ /**
+ * Returns the full path and name of the directory, including a trailing '/'.
+ * @return The name of the directory, or QString::null if creating the
+ * directory has failed or the directory has been unlinked
+ **/
+ QString name() const;
+
+
+ /**
+ * Returns the QDir* of the temporary directory.
+ * @return QDir directory information of the directory or 0 if their is no managed directory
+ * The caller has to free the pointer open for writing to the
+ **/
+ QDir *qDir();
+
+ /**
+ * Deletes the directory recursively
+ **/
+ void unlink();
+
+ /**
+ * @return true if a temporary directory has successfully been created and not been unlinked yet
+ */
+ bool existing() const;
+
+ /**
+ * @brief Remove a directory and all its contents
+ *
+ * Remove recursively a directory, even if it is not empty
+ * or contains other directories.
+ *
+ * However the function works too when the @p path given
+ * is a non-directory file. In that case it simply remove that file.
+ *
+ * The function stops on the first error.
+ *
+ * @note This function is more meant for removing a directory
+ * not created by the user. For user-created directories,
+ * using KIO::NetAccess::del is recommended instead,
+ * especially as it has user feedback for long operations.
+ *
+ * @param path Path of the directory to delete
+ * @return true if successful, otherwise false
+ * (Use errno for more details about the error.)
+ * @since 3.5.2
+ */
+ static bool removeDir( const QString& path );
+
+protected:
+
+ /**
+ * Creates a "random" directory with specified mode
+ * @param directoryPrefix to use when creating temp directory
+ * (the rest is generated randomly)
+ * @param mode directory permissions
+ * @return bool true upon sucess
+ */
+ bool create(const QString &directoryPrefix, int mode);
+
+ /**
+ * Sets the errno value
+ * @param error the value to set the status to.
+ */
+ void setError(int error) { mError = error; }
+
+private:
+ int mError;
+ QString mTmpName;
+ bool bExisting;
+ bool bAutoDelete;
+
+ KTempDirPrivate *d;
+};
+
+#endif
diff --git a/kdecore/ktempfile.cpp b/kdecore/ktempfile.cpp
new file mode 100644
index 000000000..9c6c8cdfb
--- /dev/null
+++ b/kdecore/ktempfile.cpp
@@ -0,0 +1,289 @@
+/*
+ *
+ * This file is part of the KDE libraries
+ * Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_TEST
+#include <test.h>
+#endif
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef _PATH_TMP
+#define _PATH_TMP "/tmp"
+#endif
+
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include <qtextstream.h>
+
+#include "kglobal.h"
+#include "kapplication.h"
+#include "kinstance.h"
+#include "ktempfile.h"
+#include "kstandarddirs.h"
+#include "kde_file.h"
+#include "kdebug.h"
+
+/* antlarr: KDE 4: make the parameters const QString & */
+KTempFile::KTempFile(QString filePrefix, QString fileExtension, int mode)
+{
+ bAutoDelete = false;
+ mFd = -1;
+ mStream = 0;
+ mFile = 0;
+ mTextStream = 0;
+ mDataStream = 0;
+ mError = 0;
+ bOpen = false;
+ if (fileExtension.isEmpty())
+ fileExtension = ".tmp";
+ if (filePrefix.isEmpty())
+ {
+ filePrefix = locateLocal("tmp", KGlobal::instance()->instanceName());
+ }
+ (void) create(filePrefix, fileExtension, mode);
+}
+
+KTempFile::KTempFile(bool)
+{
+ bAutoDelete = false;
+ mFd = -1;
+ mStream = 0;
+ mFile = 0;
+ mTextStream = 0;
+ mDataStream = 0;
+ mError = 0;
+ bOpen = false;
+}
+
+bool
+KTempFile::create(const QString &filePrefix, const QString &fileExtension,
+ int mode)
+{
+ // make sure the random seed is randomized
+ (void) KApplication::random();
+
+ QCString ext = QFile::encodeName(fileExtension);
+ QCString nme = QFile::encodeName(filePrefix) + "XXXXXX" + ext;
+ if((mFd = mkstemps(nme.data(), ext.length())) < 0)
+ {
+ // Recreate it for the warning, mkstemps emptied it
+ QCString nme = QFile::encodeName(filePrefix) + "XXXXXX" + ext;
+ kdWarning() << "KTempFile: Error trying to create " << nme << ": " << strerror(errno) << endl;
+ mError = errno;
+ mTmpName = QString::null;
+ return false;
+ }
+
+ // got a file descriptor. nme contains the name
+ mTmpName = QFile::decodeName(nme);
+ mode_t tmp = 0;
+ mode_t umsk = umask(tmp);
+ umask(umsk);
+ fchmod(mFd, mode&(~umsk));
+
+ // Success!
+ bOpen = true;
+
+ // Set uid/gid (necessary for SUID programs)
+ fchown(mFd, getuid(), getgid());
+
+ // Set close on exec
+ fcntl(mFd, F_SETFD, FD_CLOEXEC);
+
+ return true;
+}
+
+KTempFile::~KTempFile()
+{
+ close();
+ if (bAutoDelete)
+ unlink();
+}
+
+int
+KTempFile::status() const
+{
+ return mError;
+}
+
+QString
+KTempFile::name() const
+{
+ return mTmpName;
+}
+
+int
+KTempFile::handle() const
+{
+ return mFd;
+}
+
+FILE *
+KTempFile::fstream()
+{
+ if (mStream) return mStream;
+ if (mFd < 0) return 0;
+
+ // Create a stream
+ mStream = KDE_fdopen(mFd, "r+");
+ if (!mStream) {
+ kdWarning() << "KTempFile: Error trying to open " << mTmpName << ": " << strerror(errno) << endl;
+ mError = errno;
+ }
+ return mStream;
+}
+
+QFile *
+KTempFile::file()
+{
+ if (mFile) return mFile;
+ if ( !fstream() ) return 0;
+
+ mFile = new QFile();
+ mFile->setName( name() );
+ mFile->open(IO_ReadWrite, mStream);
+ return mFile;
+}
+
+QTextStream *
+KTempFile::textStream()
+{
+ if (mTextStream) return mTextStream;
+ if ( !file() ) return 0; // Initialize mFile
+
+ mTextStream = new QTextStream( mFile );
+ return mTextStream;
+}
+
+QDataStream *
+KTempFile::dataStream()
+{
+ if (mDataStream) return mDataStream;
+ if ( !file() ) return 0; // Initialize mFile
+
+ mDataStream = new QDataStream( mFile );
+ return mDataStream;
+}
+
+void
+KTempFile::unlink()
+{
+ if (!mTmpName.isEmpty())
+ QFile::remove( mTmpName );
+ mTmpName = QString::null;
+}
+
+#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
+#define FDATASYNC fdatasync
+#else
+#define FDATASYNC fsync
+#endif
+
+bool
+KTempFile::sync()
+{
+ int result = 0;
+
+ if (mStream)
+ {
+ do {
+ result = fflush(mStream); // We need to flush first otherwise fsync may not have our data
+ }
+ while ((result == -1) && (errno == EINTR));
+
+ if (result)
+ {
+ kdWarning() << "KTempFile: Error trying to flush " << mTmpName << ": " << strerror(errno) << endl;
+ mError = errno;
+ }
+ }
+
+ if (mFd >= 0)
+ {
+ if( qstrcmp( getenv( "KDE_EXTRA_FSYNC" ), "1" ) == 0 )
+ {
+ result = FDATASYNC(mFd);
+ if (result)
+ {
+ kdWarning() << "KTempFile: Error trying to sync " << mTmpName << ": " << strerror(errno) << endl;
+ mError = errno;
+ }
+ }
+ }
+
+ return (mError == 0);
+}
+
+#undef FDATASYNC
+
+bool
+KTempFile::close()
+{
+ int result = 0;
+ delete mTextStream; mTextStream = 0;
+ delete mDataStream; mDataStream = 0;
+ delete mFile; mFile = 0;
+
+ if (mStream)
+ {
+ result = ferror(mStream);
+ if (result)
+ mError = ENOSPC; // Assume disk full.
+
+ result = fclose(mStream);
+ mStream = 0;
+ mFd = -1;
+ if (result != 0) {
+ kdWarning() << "KTempFile: Error trying to close " << mTmpName << ": " << strerror(errno) << endl;
+ mError = errno;
+ }
+ }
+
+
+ if (mFd >= 0)
+ {
+ result = ::close(mFd);
+ mFd = -1;
+ if (result != 0) {
+ kdWarning() << "KTempFile: Error trying to close " << mTmpName << ": " << strerror(errno) << endl;
+ mError = errno;
+ }
+ }
+
+ bOpen = false;
+ return (mError == 0);
+}
+
diff --git a/kdecore/ktempfile.h b/kdecore/ktempfile.h
new file mode 100644
index 000000000..c868a3fa1
--- /dev/null
+++ b/kdecore/ktempfile.h
@@ -0,0 +1,213 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KTEMPFILE_H_
+#define _KTEMPFILE_H_
+
+#include <qstring.h>
+#include <stdio.h>
+#include <errno.h>
+#include "kdelibs_export.h"
+
+class QFile;
+class QTextStream;
+class QDataStream;
+class KSaveFile;
+class KTempFilePrivate;
+
+/**
+ * The KTempFile class creates and opens a unique file for temporary use.
+ *
+ * This is especially useful if you need to create a file in a world
+ * writable directory like /tmp without being vulnerable to so called
+ * symlink attacks.
+ *
+ * KDE applications, however, shouldn't create files in /tmp in the first
+ * place but use the "tmp" resource instead. The standard KTempFile
+ * constructor will do that by default.
+ *
+ * To create a temporary file that starts with a certain name
+ * in the "tmp" resource, one should use:
+ * KTempFile(locateLocal("tmp", prefix), extension);
+ *
+ * KTempFile does not create any missing directories, but locateLocal() does.
+ *
+ * See also KStandardDirs
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ */
+class KDECORE_EXPORT KTempFile
+{
+ friend class KSaveFile;
+public:
+ /**
+ * Creates a temporary file with the name:
+ * \<filePrefix>\<six letters>\<fileExtension>
+ *
+ * The default @p filePrefix is "$KDEHOME/tmp-$HOST/appname/"
+ * The default @p fileExtension is ".tmp"
+ * @param filePrefix the prefix of the file name, or QString::null
+ * for the default value
+ * @param fileExtension the extension of the prefix, or QString::null for the
+ * default value
+ * @param mode the file permissions
+ **/
+ KTempFile(QString filePrefix=QString::null,
+ QString fileExtension=QString::null,
+ int mode = 0600 );
+
+
+ /**
+ * The destructor closes the file.
+ * If autoDelete is enabled the file gets unlinked as well.
+ **/
+ ~KTempFile();
+
+ /**
+ * Turn automatic deletion on or off.
+ * Automatic deletion is off by default.
+ * @param autoDelete true to turn automatic deletion on
+ **/
+ void setAutoDelete(bool autoDelete) { bAutoDelete = autoDelete; }
+
+ /**
+ * Returns the status of the file based on errno. (see errno.h)
+ * 0 means OK.
+ *
+ * You should check the status after object creation to check
+ * whether a file could be created in the first place.
+ *
+ * You may check the status after closing the file to verify that
+ * the file has indeed been written correctly.
+ * @return the errno status, 0 means ok
+ **/
+ int status() const;
+
+ /**
+ * Returns the full path and name of the file.
+ *
+ * Note that in most circumstances the file needs to be closed
+ * before you use it by name.
+ *
+ * In particular, if another process or software part needs to write data
+ * to the file based on the filename, the file should be closed before doing
+ * so. Otherwise the act of closing the file later on may cause the file to
+ * get truncated to a zero-size, resulting in an unexpected loss of the data.
+ *
+ * In some cases there is only interest in the filename itself but where the
+ * actual presence of a file with such name is a problem. In that case the
+ * file should first be both closed and unlinked. Such usage is not recommended
+ * since it may lead to the kind of symlink vulnerabilities that the KTempFile
+ * design attempts to prevent.
+ *
+ * @return The name of the file, or QString::null if opening the
+ * file has failed or the file has been unlinked already.
+ **/
+ QString name() const;
+
+ /**
+ * An integer file descriptor open for writing to the file
+ * @return The file descriptor, or a negative number if opening
+ * the file failed
+ **/
+ int handle() const;
+
+ /**
+ * Returns the FILE* of the temporary file.
+ * @return FILE* stream open for writing to the file, or 0
+ * if opening the file failed
+ **/
+ FILE *fstream();
+
+ /**
+ * Returns the QTextStream for writing.
+ * @return QTextStream open for writing to the file, or 0
+ * if opening the file failed
+ **/
+ QTextStream *textStream();
+
+ /**
+ * Returns a QDataStream for writing.
+ * @return QDataStream open for writing to the file, or 0
+ * if opening the file failed
+ **/
+ QDataStream *dataStream();
+
+ /**
+ * Returns a QFile.
+ * @return A QFile open for writing to the file, or 0 if
+ * opening the file failed.
+ **/
+ QFile *file();
+
+ /**
+ * Unlinks the file from the directory. The file is
+ * deleted once the last reader/writer closes it.
+ **/
+ void unlink();
+
+ /**
+ * Flushes file to disk (fsync).
+ *
+ * If you want to be as sure as possible that the file data has
+ * actually been physically stored on disk you need to call sync().
+ *
+ * See status() for details about errors.
+ * @return true if successful, or false if an error has occurred.
+ * @since 3.3
+ **/
+ bool sync();
+
+ /**
+ * Closes the file.
+ *
+ * See status() for details about errors.
+ * @return true if successful, or false if an error has occurred.
+ **/
+ bool close();
+
+protected:
+ /**
+ * Constructor used by KSaveFile
+ **/
+ KTempFile(bool);
+
+ /**
+ * @internal
+ * Create function used internally by KTempFile and KSaveFile
+ **/
+ bool create(const QString &filePrefix,
+ const QString &fileExtension, int mode);
+
+ void setError(int error) { mError = error; }
+private:
+ int mError;
+ QString mTmpName;
+ int mFd;
+ FILE *mStream;
+ QFile *mFile;
+ QTextStream *mTextStream;
+ QDataStream *mDataStream;
+ bool bOpen;
+ bool bAutoDelete;
+
+ KTempFilePrivate *d;
+};
+
+#endif
diff --git a/kdecore/ktimezones.cpp b/kdecore/ktimezones.cpp
new file mode 100644
index 000000000..c74dc8143
--- /dev/null
+++ b/kdecore/ktimezones.cpp
@@ -0,0 +1,790 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2005 S.R.Haque <srhaque@iee.org>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <ktimezones.h>
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kprocess.h>
+#include <kstringhandler.h>
+#include <ktempfile.h>
+
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+#include <cerrno>
+#include <climits>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+
+#define UTC_ZONE "UTC"
+
+/**
+ * Find out if the given standard (e.g. "GMT") and daylight savings time
+ * (e.g. "BST", but which may be empty) abbreviated timezone names match
+ * this timezone.
+ *
+ * Thus, this class can be used as a heuristic when trying to lookup the
+ * real timezone from the abbreviated zone names.
+ */
+class AbbreviationsMatch :
+ public KTimezoneDetails
+{
+public:
+ AbbreviationsMatch(const QString &stdZone, const QString &dstZone = "")
+ {
+ m_stdZone = stdZone;
+ m_dstZone = dstZone;
+ }
+
+ void parseStarted()
+ {
+ m_foundStd = false;
+ m_foundDst = m_dstZone.isEmpty();
+ }
+
+ bool test()
+ {
+ return (m_foundStd && m_foundDst);
+ }
+
+private:
+ bool m_foundStd;
+ bool m_foundDst;
+ QString m_stdZone;
+ QString m_dstZone;
+
+ virtual void gotAbbreviation(int /*index*/, const QString &value)
+ {
+ if (m_stdZone == value)
+ {
+ m_foundStd = true;
+ }
+ if (m_dstZone == value)
+ {
+ m_foundDst = true;
+ }
+ }
+};
+
+/**
+ * Internal dummy source for UTC timezone.
+ */
+class DummySource :
+ public KTimezoneSource
+{
+public:
+ DummySource() :
+ KTimezoneSource("")
+ {
+ }
+
+ virtual bool parse(const QString &/*zone*/, KTimezoneDetails &/*dataReceiver*/) const
+ {
+ return true;
+ }
+};
+
+/**
+ * Find offset at a particular point in time.
+ */
+class OffsetFind :
+ public KTimezoneDetails
+{
+public:
+ OffsetFind(unsigned dateTime)
+ {
+ m_dateTime = dateTime;
+ }
+
+ void parseStarted()
+ {
+ m_transitionTimeIndex = 0;
+ m_localTimeIndex = -1;
+ m_abbrIndex = -1;
+ m_offset = 0;
+ m_isDst = false;
+ m_abbr = UTC_ZONE;
+ }
+
+ int offset()
+ {
+ return m_offset;
+ }
+
+ bool isDst()
+ {
+ return m_isDst;
+ }
+
+ QString abbreviation()
+ {
+ return m_abbr;
+ }
+
+private:
+ unsigned m_dateTime;
+ int m_transitionTimeIndex;
+ int m_localTimeIndex;
+ int m_abbrIndex;
+ int m_offset;
+ bool m_isDst;
+ QString m_abbr;
+
+ virtual void gotTransitionTime(int index, unsigned transitionTime)
+ {
+ if (transitionTime <= m_dateTime)
+ {
+ // Remember the index of the transition time that relates to dateTime.
+ m_transitionTimeIndex = index;
+ }
+ }
+
+ virtual void gotLocalTimeIndex(int index, unsigned localTimeIndex)
+ {
+ if (index == m_transitionTimeIndex)
+ {
+ // Remember the index of the local time that relates to dateTime.
+ m_localTimeIndex = localTimeIndex;
+ }
+ }
+
+ virtual void gotLocalTime(int index, int gmtOff, bool isDst, unsigned abbrInd)
+ {
+ if (index == m_localTimeIndex)
+ {
+ // Remember the results that relate to gmtOffset.
+ m_offset = gmtOff;
+ m_isDst = isDst;
+ m_abbrIndex = abbrInd;
+ }
+ }
+
+ virtual void gotAbbreviation(int index, const QString &value)
+ {
+ if (index == m_abbrIndex)
+ {
+ m_abbr = value;
+ }
+ }
+};
+
+const float KTimezone::UNKNOWN = 1000.0;
+
+bool KTimezone::isValidLatitude(float latitude)
+{
+ return (latitude >= -90.0) && (latitude <= 90.0);
+}
+
+bool KTimezone::isValidLongitude(float longitude)
+{
+ return (longitude >= -180.0) && (longitude <= 180.0);
+}
+
+KTimezone::KTimezone(
+ KSharedPtr<KTimezoneSource> db, const QString& name,
+ const QString &countryCode, float latitude, float longitude,
+ const QString &comment) :
+ m_db(db),
+ m_name(name),
+ m_countryCode(countryCode),
+ m_latitude(latitude),
+ m_longitude(longitude),
+ m_comment(comment),
+ d(0)
+{
+ // Detect duff values.
+ if (m_latitude * m_latitude > 90 * 90)
+ m_latitude = UNKNOWN;
+ if (m_longitude * m_longitude > 180 * 180)
+ m_longitude = UNKNOWN;
+}
+
+KTimezone::~KTimezone()
+{
+ // FIXME when needed:
+ // delete d;
+}
+
+QString KTimezone::comment() const
+{
+ return m_comment;
+}
+
+QDateTime KTimezone::convert(const KTimezone *newZone, const QDateTime &dateTime) const
+{
+ char *originalZone = ::getenv("TZ");
+
+ // Convert the given localtime to UTC.
+ ::setenv("TZ", m_name.utf8(), 1);
+ tzset();
+ unsigned utc = dateTime.toTime_t();
+
+ // Set the timezone and convert UTC to localtime.
+ ::setenv("TZ", newZone->name().utf8(), 1);
+ tzset();
+ QDateTime remoteTime;
+ remoteTime.setTime_t(utc, Qt::LocalTime);
+
+ // Now restore things
+ if (!originalZone)
+ {
+ ::unsetenv("TZ");
+ }
+ else
+ {
+ ::setenv("TZ", originalZone, 1);
+ }
+ tzset();
+ return remoteTime;
+}
+
+QString KTimezone::countryCode() const
+{
+ return m_countryCode;
+}
+
+float KTimezone::latitude() const
+{
+ return m_latitude;
+}
+
+float KTimezone::longitude() const
+{
+ return m_longitude;
+}
+
+QString KTimezone::name() const
+{
+ return m_name;
+}
+
+int KTimezone::offset(Qt::TimeSpec basisSpec) const
+{
+ char *originalZone = ::getenv("TZ");
+
+ // Get the time in the current timezone.
+ QDateTime basisTime = QDateTime::currentDateTime(basisSpec);
+
+ // Set the timezone and find out what time it is there compared to the basis.
+ ::setenv("TZ", m_name.utf8(), 1);
+ tzset();
+ QDateTime remoteTime = QDateTime::currentDateTime(Qt::LocalTime);
+ int offset = remoteTime.secsTo(basisTime);
+
+ // Now restore things
+ if (!originalZone)
+ {
+ ::unsetenv("TZ");
+ }
+ else
+ {
+ ::setenv("TZ", originalZone, 1);
+ }
+ tzset();
+ return offset;
+}
+
+int KTimezone::offset(const QDateTime &dateTime) const
+{
+ OffsetFind finder(dateTime.toTime_t());
+ int result = 0;
+ if (parse(finder))
+ {
+ result = finder.offset();
+ }
+ return result;
+}
+
+bool KTimezone::parse(KTimezoneDetails &dataReceiver) const
+{
+ dataReceiver.parseStarted();
+ bool result = m_db->parse(m_name, dataReceiver);
+ dataReceiver.parseEnded();
+ return result;
+}
+
+KTimezones::KTimezones() :
+ m_zoneinfoDir(),
+ m_zones(0),
+ d(0)
+{
+ // Create the database (and resolve m_zoneinfoDir!).
+ allZones();
+ m_UTC = new KTimezone(new DummySource(), UTC_ZONE);
+ add(m_UTC);
+}
+
+KTimezones::~KTimezones()
+{
+ // FIXME when needed:
+ // delete d;
+
+ // Autodelete behavior.
+ if (m_zones)
+ {
+ for (ZoneMap::ConstIterator it = m_zones->begin(); it != m_zones->end(); ++it)
+ {
+ delete it.data();
+ }
+ }
+ delete m_zones;
+}
+
+void KTimezones::add(KTimezone *zone)
+{
+ m_zones->insert(zone->name(), zone);
+}
+
+const KTimezones::ZoneMap KTimezones::allZones()
+{
+ // Have we already done all the hard work? If not, create the cache.
+ if (m_zones)
+ return *m_zones;
+ m_zones = new ZoneMap();
+
+ // Go read the database.
+ //
+ // On Windows, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
+ // is the place to look. The TZI binary value is the TIME_ZONE_INFORMATION structure.
+ //
+ // For Unix its all easy except knowing where to look. Try the LSB location first.
+ QFile f;
+ m_zoneinfoDir = "/usr/share/zoneinfo";
+ f.setName(m_zoneinfoDir + "/zone.tab");
+ if (!f.open(IO_ReadOnly))
+ {
+ kdDebug() << "Can't open " << f.name() << endl;
+ m_zoneinfoDir = "/usr/lib/zoneinfo";
+ f.setName(m_zoneinfoDir + "/zone.tab");
+ if (!f.open(IO_ReadOnly))
+ {
+ kdDebug() << "Can't open " << f.name() << endl;
+ m_zoneinfoDir = ::getenv("TZDIR");
+ f.setName(m_zoneinfoDir + "/zone.tab");
+ if (m_zoneinfoDir.isEmpty() || !f.open(IO_ReadOnly))
+ {
+ kdDebug() << "Can't open " << f.name() << endl;
+
+ // Solaris support. Synthesise something that looks like a zone.tab.
+ //
+ // /bin/grep -h ^Zone /usr/share/lib/zoneinfo/src/* | /bin/awk '{print "??\t+9999+99999\t" $2}'
+ //
+ // where the country code is set to "??" and the lattitude/longitude
+ // values are dummies.
+ m_zoneinfoDir = "/usr/share/lib/zoneinfo";
+ KTempFile temp;
+ KShellProcess reader;
+ reader << "/bin/grep" << "-h" << "^Zone" << m_zoneinfoDir << "/src/*" << temp.name() << "|" <<
+ "/bin/awk" << "'{print \"??\\t+9999+99999\\t\" $2}'";
+ // Note the use of blocking here...it is a trivial amount of data!
+ temp.close();
+ reader.start(KProcess::Block);
+ f.setName(temp.name());
+ if (!temp.status() || !f.open(IO_ReadOnly))
+ {
+ kdDebug() << "Can't open " << f.name() << endl;
+ return *m_zones;
+ }
+ }
+ }
+ }
+
+ // Parse the zone.tab.
+ QTextStream str(&f);
+ QRegExp lineSeparator("[ \t]");
+ QRegExp ordinateSeparator("[+-]");
+ KSharedPtr<KTimezoneSource> db(new KTimezoneSource(m_zoneinfoDir));
+ while (!str.atEnd())
+ {
+ QString line = str.readLine();
+ if (line.isEmpty() || '#' == line[0])
+ continue;
+ QStringList tokens = KStringHandler::perlSplit(lineSeparator, line, 4);
+ if (tokens.count() < 3)
+ {
+ kdError() << "invalid record: " << line << endl;
+ continue;
+ }
+
+ // Got three tokens. Now check for two ordinates plus first one is "".
+ QStringList ordinates = KStringHandler::perlSplit(ordinateSeparator, tokens[1], 2);
+ if (ordinates.count() < 2)
+ {
+ kdError() << "invalid coordinates: " << tokens[1] << endl;
+ continue;
+ }
+
+ float latitude = convertCoordinate(ordinates[1]);
+ float longitude = convertCoordinate(ordinates[2]);
+
+ // Add entry to list.
+ if (tokens[0] == "??")
+ tokens[0] = "";
+ KTimezone *timezone = new KTimezone(db, tokens[2], tokens[0], latitude, longitude, tokens[3]);
+ add(timezone);
+ }
+ f.close();
+ return *m_zones;
+}
+
+/**
+ * Convert sHHMM or sHHMMSS to a floating point number of degrees.
+ */
+float KTimezones::convertCoordinate(const QString &coordinate)
+{
+ int value = coordinate.toInt();
+ int degrees = 0;
+ int minutes = 0;
+ int seconds = 0;
+
+ if (coordinate.length() > 11)
+ {
+ degrees = value / 10000;
+ value -= degrees * 10000;
+ minutes = value / 100;
+ value -= minutes * 100;
+ seconds = value;
+ }
+ else
+ {
+ degrees = value / 100;
+ value -= degrees * 100;
+ minutes = value;
+ }
+ value = degrees * 3600 + minutes * 60 + seconds;
+ return value / 3600.0;
+}
+
+const KTimezone *KTimezones::local()
+{
+ const KTimezone *local = 0;
+
+ // First try the simplest solution of checking for well-formed TZ setting.
+ char *envZone = ::getenv("TZ");
+ if (envZone)
+ {
+ if (envZone[0] == '\0')
+ {
+ return m_UTC;
+ }
+ else
+ if (envZone[0] == ':')
+ {
+ envZone++;
+ }
+ local = zone(envZone);
+ }
+ if (local)
+ return local;
+
+ // Try to match /etc/localtime against the list of zoneinfo files.
+ QFile f;
+ f.setName("/etc/localtime");
+ if (f.open(IO_ReadOnly))
+ {
+ // Compute the MD5 sum of /etc/localtime.
+ KMD5 context("");
+ context.reset();
+ context.update(f);
+ QIODevice::Offset referenceSize = f.size();
+ QString referenceMd5Sum = context.hexDigest();
+ f.close();
+ if (!m_zoneinfoDir.isEmpty())
+ {
+ // Compare it with each zoneinfo file.
+ for (ZoneMap::Iterator it = m_zones->begin(); it != m_zones->end(); ++it)
+ {
+ KTimezone *zone = it.data();
+ f.setName(m_zoneinfoDir + '/' + zone->name());
+ if (f.open(IO_ReadOnly))
+ {
+ QIODevice::Offset candidateSize = f.size();
+ QString candidateMd5Sum;
+ if (candidateSize == referenceSize)
+ {
+ // Only do the heavy lifting for file sizes which match.
+ context.reset();
+ context.update(f);
+ candidateMd5Sum = context.hexDigest();
+ }
+ f.close();
+ if (candidateMd5Sum == referenceMd5Sum)
+ {
+ // kdError() << "local=" << zone->name() << endl;
+ local = zone;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (local)
+ return local;
+
+ // BSD support.
+ QString fileZone;
+ f.setName("/etc/timezone");
+ if (!f.open(IO_ReadOnly))
+ {
+ kdDebug() << "Can't open " << f.name() << endl;
+
+ // Solaris support using /etc/default/init.
+ f.setName("/etc/default/init");
+ if (!f.open(IO_ReadOnly))
+ {
+ kdDebug() << "Can't open " << f.name() << endl;
+ }
+ else
+ {
+ QTextStream ts(&f);
+ ts.setEncoding(QTextStream::Latin1);
+
+ // Read the last line starting "TZ=".
+ while (!ts.atEnd())
+ {
+ fileZone = ts.readLine();
+ if (fileZone.startsWith("TZ="))
+ {
+ fileZone = fileZone.mid(3);
+
+ // kdError() << "local=" << fileZone << endl;
+ local = zone(fileZone);
+ }
+ }
+ f.close();
+ }
+ }
+ else
+ {
+ QTextStream ts(&f);
+ ts.setEncoding(QTextStream::Latin1);
+
+ // Read the first line.
+ if (!ts.atEnd())
+ {
+ fileZone = ts.readLine();
+
+ // kdError() << "local=" << fileZone << endl;
+ local = zone(fileZone);
+ }
+ f.close();
+ }
+ if (local)
+ return local;
+
+ // None of the deterministic stuff above has worked: try a heuristic. We
+ // try to find a pair of matching timezone abbreviations...that way, we'll
+ // likely return a value in the user's own country.
+ if (!m_zoneinfoDir.isEmpty())
+ {
+ tzset();
+ AbbreviationsMatch matcher(tzname[0], tzname[1]);
+ int bestOffset = INT_MAX;
+ for (ZoneMap::Iterator it = m_zones->begin(); it != m_zones->end(); ++it)
+ {
+ KTimezone *zone = it.data();
+ int candidateOffset = QABS(zone->offset(Qt::LocalTime));
+ if (zone->parse(matcher) && matcher.test() && (candidateOffset < bestOffset))
+ {
+ // kdError() << "local=" << zone->name() << endl;
+ bestOffset = candidateOffset;
+ local = zone;
+ }
+ }
+ }
+ if (local)
+ return local;
+ return m_UTC;
+}
+
+const KTimezone *KTimezones::zone(const QString &name)
+{
+ if (name.isEmpty())
+ return m_UTC;
+ ZoneMap::ConstIterator it = m_zones->find(name);
+ if (it != m_zones->end())
+ return it.data();
+
+ // Error.
+ return 0;
+}
+
+KTimezoneDetails::KTimezoneDetails()
+{
+}
+
+KTimezoneDetails::~KTimezoneDetails()
+{
+}
+
+void KTimezoneDetails::gotAbbreviation(int /*index*/, const QString &)
+{}
+
+void KTimezoneDetails::gotHeader(
+ unsigned, unsigned, unsigned,
+ unsigned, unsigned, unsigned)
+{}
+
+void KTimezoneDetails::gotLeapAdjustment(int /*index*/, unsigned, unsigned)
+{}
+
+void KTimezoneDetails::gotLocalTime(int /*index*/, int, bool, unsigned)
+{}
+
+void KTimezoneDetails::gotLocalTimeIndex(int /*index*/, unsigned)
+{}
+
+void KTimezoneDetails::gotIsStandard(int /*index*/, bool)
+{}
+
+void KTimezoneDetails::gotTransitionTime(int /*index*/, unsigned)
+{}
+
+void KTimezoneDetails::gotIsUTC(int /*index*/, bool)
+{}
+
+void KTimezoneDetails::parseEnded()
+{}
+
+void KTimezoneDetails::parseStarted()
+{}
+
+KTimezoneSource::KTimezoneSource(const QString &db) :
+ m_db(db)
+{
+}
+
+KTimezoneSource::~KTimezoneSource()
+{
+}
+
+QString KTimezoneSource::db()
+{
+ return m_db;
+}
+
+bool KTimezoneSource::parse(const QString &zone, KTimezoneDetails &dataReceiver) const
+{
+ QFile f(m_db + '/' + zone);
+ if (!f.open(IO_ReadOnly))
+ {
+ kdError() << "Cannot open " << f.name() << endl;
+ return false;
+ }
+
+ // Structures that represent the zoneinfo file.
+ Q_UINT8 T, z, i_, f_;
+ struct
+ {
+ Q_UINT32 ttisgmtcnt;
+ Q_UINT32 ttisstdcnt;
+ Q_UINT32 leapcnt;
+ Q_UINT32 timecnt;
+ Q_UINT32 typecnt;
+ Q_UINT32 charcnt;
+ } tzh;
+ Q_UINT32 transitionTime;
+ Q_UINT8 localTimeIndex;
+ struct
+ {
+ Q_INT32 gmtoff;
+ Q_INT8 isdst;
+ Q_UINT8 abbrind;
+ } tt;
+ Q_UINT32 leapTime;
+ Q_UINT32 leapSeconds;
+ Q_UINT8 isStandard;
+ Q_UINT8 isUTC;
+
+ QDataStream str(&f);
+ str >> T >> z >> i_ >> f_;
+ // kdError() << "signature: " << QChar(T) << QChar(z) << QChar(i_) << QChar(f_) << endl;
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ str >> tzh.ttisgmtcnt;
+ str >> tzh.ttisgmtcnt >> tzh.ttisstdcnt >> tzh.leapcnt >> tzh.timecnt >> tzh.typecnt >> tzh.charcnt;
+ // kdError() << "header: " << tzh.ttisgmtcnt << ", " << tzh.ttisstdcnt << ", " << tzh.leapcnt << ", " <<
+ // tzh.timecnt << ", " << tzh.typecnt << ", " << tzh.charcnt << endl;
+ dataReceiver.gotHeader(tzh.ttisgmtcnt, tzh.ttisstdcnt, tzh.leapcnt, tzh.timecnt, tzh.typecnt, tzh.charcnt);
+ for (i = 0; i < tzh.timecnt; i++)
+ {
+ str >> transitionTime;
+ dataReceiver.gotTransitionTime(i, transitionTime);
+ }
+ for (i = 0; i < tzh.timecnt; i++)
+ {
+ // NB: these appear to be 1-based, not zero-based!
+ str >> localTimeIndex;
+ dataReceiver.gotLocalTimeIndex(i, localTimeIndex);
+ }
+ for (i = 0; i < tzh.typecnt; i++)
+ {
+ str >> tt.gmtoff >> tt.isdst >> tt.abbrind;
+ // kdError() << "local type: " << tt.gmtoff << ", " << tt.isdst << ", " << tt.abbrind << endl;
+ dataReceiver.gotLocalTime(i, tt.gmtoff, (tt.isdst != 0), tt.abbrind);
+ }
+
+ // Make sure we don't run foul of maliciously coded timezone abbreviations.
+ if (tzh.charcnt > 64)
+ {
+ kdError() << "excessive length for timezone abbreviations: " << tzh.charcnt << endl;
+ return false;
+ }
+ QByteArray array(tzh.charcnt);
+ str.readRawBytes(array.data(), array.size());
+ char *abbrs = array.data();
+ if (abbrs[tzh.charcnt - 1] != 0)
+ {
+ // These abbrevations are corrupt!
+ kdError() << "timezone abbreviations not terminated: " << abbrs[tzh.charcnt - 1] << endl;
+ return false;
+ }
+ char *abbr = abbrs;
+ while (abbr < abbrs + tzh.charcnt)
+ {
+ // kdError() << "abbr: " << abbr << endl;
+ dataReceiver.gotAbbreviation((abbr - abbrs), abbr);
+ abbr += strlen(abbr) + 1;
+ }
+ for (i = 0; i < tzh.leapcnt; i++)
+ {
+ str >> leapTime >> leapSeconds;
+ // kdError() << "leap entry: " << leapTime << ", " << leapSeconds << endl;
+ dataReceiver.gotLeapAdjustment(i, leapTime, leapSeconds);
+ }
+ for (i = 0; i < tzh.ttisstdcnt; i++)
+ {
+ str >> isStandard;
+ // kdError() << "standard: " << isStandard << endl;
+ dataReceiver.gotIsStandard(i, (isStandard != 0));
+ }
+ for (i = 0; i < tzh.ttisgmtcnt; i++)
+ {
+ str >> isUTC;
+ // kdError() << "UTC: " << isUTC << endl;
+ dataReceiver.gotIsUTC(i, (isUTC != 0));
+ }
+ return true;
+}
diff --git a/kdecore/ktimezones.h b/kdecore/ktimezones.h
new file mode 100644
index 000000000..28b7e1ad9
--- /dev/null
+++ b/kdecore/ktimezones.h
@@ -0,0 +1,351 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2005 S.R.Haque <srhaque@iee.org>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KTIMEZONES_H
+#define _KTIMEZONES_H
+
+#include "kdelibs_export.h"
+#include <qdatetime.h>
+#include <qnamespace.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <ksharedptr.h>
+
+class KTimezoneDetails;
+class KTimezoneDetailsPrivate;
+class KTimezonePrivate;
+class KTimezonesPrivate;
+
+/**
+ * The KTimezoneSource class contains information source-dependent functions
+ * related to a timezone. Create subclasses to implement custom sources of
+ * timezone information.
+ *
+ * For example, to be able to create {@link KTimezone } objects from libical's
+ * VTIMEZONE objects:
+ *<ul>
+ * <li>Subclass this class with a custom {@link parse() } routine.
+ * <li>Create one or more instances of this class.
+ * <li>Use the instance(s) to create {@link KTimezone } objects.
+ * <li>If required, add the objects to a {@link KTimezones } database.
+ *</ul>
+ * @since 3.5
+ * @author S.R.Haque <srhaque@iee.org>.
+ */
+class KDECORE_EXPORT KTimezoneSource :
+ public KShared
+{
+public:
+ KTimezoneSource(const QString &db);
+ virtual ~KTimezoneSource();
+
+ /**
+ * Location of system timezone information.
+ * @return value which can be combined with zone name to retrieve timezone info.
+ */
+ virtual QString db();
+
+ /**
+ * Extract timezone detail information. The default implementation consists
+ * of a parser for zoneinfo files in tzfile(5).
+ * @return true if the parse encountered no errors.
+ */
+ virtual bool parse(const QString &zone, KTimezoneDetails &dataReceiver) const;
+
+private:
+ QString m_db;
+};
+
+/**
+ * The KTimezone class contains core functions related to a timezone. Instances
+ * are created in the context of a {@link KTimezoneSource } which provides
+ * extended functionality via {@link KTimezoneDetails }.
+ *
+ * @see KTimezoneSource
+ * @see KTimezoneDetails
+ * @since 3.5
+ * @author S.R.Haque <srhaque@iee.org>.
+ */
+class KDECORE_EXPORT KTimezone
+{
+public:
+ /**
+ * A representation for unknown locations; this is a float
+ * that does not represent a real latitude or longitude.
+ */
+ static const float UNKNOWN;
+
+ /**
+ * A test for a valid latitude. The valid range is +90.0 (North Pole)
+ * to -90.0 (South Pole).
+ */
+ static bool isValidLatitude(float latitude);
+
+ /**
+ * A test for a valid longitude. The valid range is +180.0 (east of
+ * Greenwich) to -180.0 (west of Greenwich).
+ */
+ static bool isValidLongitude(float longitude);
+
+ /**
+ * Create a timezone.
+ *
+ * @param db database of timezones.
+ * @param name in system-dependent format.
+ * @param countryCode ISO 3166 2-character country code, empty if unknown.
+ * @param latitude in degrees, UNKNOWN if not known.
+ * @param longitude in degrees, UNKNOWN if not known.
+ * @param comment description of the timezone, if any.
+ */
+ KTimezone(
+ KSharedPtr<KTimezoneSource> db, const QString &name,
+ const QString &countryCode = QString(), float latitude = UNKNOWN, float longitude = UNKNOWN,
+ const QString &comment = QString());
+ ~KTimezone();
+
+ /**
+ * Returns the name of the timezone.
+ *
+ * @return name in system-dependent format.
+ */
+ QString name() const;
+
+ /**
+ * Returns the two-letter country code of the timezone.
+ *
+ * @return ISO 3166 2-character country code, empty if unknown.
+ */
+ QString countryCode() const;
+
+ /**
+ * Returns the latitude of the timezone.
+ *
+ * @return latitude in degrees, UNKNOWN if not known.
+ */
+ float latitude() const;
+
+ /**
+ * Returns the latitude of the timezone.
+ *
+ * @return latitude in degrees, UNKNOWN if not known.
+ */
+ float longitude() const;
+
+ /**
+ * Returns the current offset of this timezone to UTC or the local
+ * timezone in seconds.
+ *
+ * Take care if you cache the results of this routine; that would
+ * break if the result were stored across a daylight savings change.
+ *
+ * @return offset in seconds.
+ */
+ int offset(Qt::TimeSpec basisSpec = Qt::UTC) const;
+
+ /**
+ * Returns the offset of the given timezone to UTC at the given
+ * date/time (which is interpreted as being UTC).
+ *
+ * @return offset in seconds.
+ */
+ int offset(const QDateTime &dateTime) const;
+
+ /**
+ * Convert a date/time (which is interpreted as being localtime in this
+ * timezone) into localtime in the given timezone.
+ *
+ * @return converted date/time.
+ */
+ QDateTime convert(const KTimezone *newZone, const QDateTime &dateTime) const;
+
+ /**
+ * Returns any comment for the timezone.
+ *
+ * @return comment, may be empty.
+ */
+ QString comment() const;
+
+ /**
+ * Extract timezone detail information.
+ * @return true if the parse encountered no errors.
+ */
+ bool parse(KTimezoneDetails &dataReceiver) const;
+
+private:
+ KTimezone(const KTimezone&);
+ KTimezone& operator=(const KTimezone&);
+
+ KSharedPtr<KTimezoneSource> m_db;
+ QString m_name;
+ QString m_countryCode;
+ float m_latitude;
+ float m_longitude;
+ QString m_comment;
+ KTimezonePrivate *d;
+};
+
+/**
+ * The KTimezoneDetails class contains extended functions related to a
+ * timezone.
+ *
+ * The parser must be customised by overriding the given virtual callbacks:
+ *<ul>
+ * <li>{@link parseEnded() }
+ * <li>{@link parseStarted() }
+ * <li>{@link gotHeader() }
+ * <li>{@link gotTransitionTime() }
+ * <li>{@link gotLocalTimeIndex() }
+ * <li>{@link gotLocalTime() }
+ * <li>{@link gotAbbreviation() }
+ * <li>{@link gotLeapAdjustment() }
+ * <li>{@link gotIsStandard() }
+ * <li>{@link gotIsUTC() }
+ *</ul>
+ *
+ * @see KTimezone
+ * @since 3.5
+ * @author S.R.Haque <srhaque@iee.org>.
+ */
+class KDECORE_EXPORT KTimezoneDetails
+{
+public:
+ KTimezoneDetails();
+ virtual ~KTimezoneDetails();
+
+ /**
+ * Always called after all other callbacks.
+ */
+ virtual void parseEnded();
+
+ /**
+ * Always called before any other callback.
+ */
+ virtual void parseStarted();
+
+ /**
+ * Called when the header is seen.
+ */
+ virtual void gotHeader(
+ unsigned ttIsGmtCnt, unsigned ttIsStdCnt, unsigned leapCnt,
+ unsigned timeCnt, unsigned typeCnt, unsigned charCnt);
+
+ /**
+ * Called when a transition time is seen.
+ */
+ virtual void gotTransitionTime(int index, unsigned transitionTime);
+
+ /**
+ * Called when a local time index is seen.
+ */
+ virtual void gotLocalTimeIndex(int index, unsigned localTimeIndex);
+
+ /**
+ * Called when a local time is seen.
+ */
+ virtual void gotLocalTime(int index, int gmtOff, bool isDst, unsigned abbrIndex);
+
+ /**
+ * Called when a timezone abbreviation is seen. Note that the index here
+ * is NOT a simple incrementing integer, rather it matches the sequence
+ * of abbrIndex values from {@link gotLocalTime() }.
+ */
+ virtual void gotAbbreviation(int index, const QString &abbr);
+
+ /**
+ * Called when a leap second adjustment is seen.
+ */
+ virtual void gotLeapAdjustment(int index, unsigned leapTime, unsigned leapSeconds);
+
+ /**
+ * Called when a standard/wall time indicator is seen.
+ */
+ virtual void gotIsStandard(int index, bool isStandard);
+
+ /**
+ * Called when a UTC/local time indicator is seen.
+ */
+ virtual void gotIsUTC(int index, bool isUTC);
+
+private:
+ KTimezoneDetailsPrivate *d;
+};
+
+/**
+ * The KTimezones class models a timezone database. It supports system
+ * timezones, and also has support for private timezone entries.
+ *
+ * @since 3.5
+ * @author S.R.Haque <srhaque@iee.org>.
+ */
+class KDECORE_EXPORT KTimezones
+{
+public:
+ KTimezones();
+ ~KTimezones();
+
+ /**
+ * Returns the local timezone. The idea of this routine is to provide a
+ * robust lookup of the local timezone.
+ *
+ * The problem is that on Unix systems, there are a variety of mechanisms
+ * for setting this information, and no real way of getting it. For example,
+ * if you set your timezone to "Europe/London", then the tzname[]
+ * maintained by tzset() typically returns { "GMT", "BST" }. The point of
+ * this routine is to actually return "Europe/London" (or rather, the
+ * corresponding KTimezone).
+ *
+ * @return local timezone. If necessary, we will use a series of heuristics
+ * which end by returning UTC. We will never return NULL.
+ */
+ const KTimezone *local();
+
+ /**
+ * Returns the given timezone.
+ *
+ * @param name Name of timezone. Empty is equivalent to UTC.
+ * @return named timezone, NULL on error.
+ */
+ const KTimezone *zone(const QString &name);
+
+ typedef QMap<QString, KTimezone *> ZoneMap;
+
+ /**
+ * Return timezone database.
+ * @return known timezones.
+ */
+ const ZoneMap allZones();
+
+ /**
+ * Add user-defined timezone to database.
+ */
+ void add(KTimezone *zone);
+
+private:
+ KTimezones(const KTimezones&);
+ KTimezones& operator=(const KTimezones&);
+
+ float convertCoordinate(const QString &coordinate);
+
+ QString m_zoneinfoDir;
+ ZoneMap *m_zones;
+ KTimezone *m_UTC;
+ KTimezonesPrivate *d;
+};
+
+#endif
diff --git a/kdecore/ktypelist.h b/kdecore/ktypelist.h
new file mode 100644
index 000000000..343cee2ab
--- /dev/null
+++ b/kdecore/ktypelist.h
@@ -0,0 +1,473 @@
+/*
+ This work is derived from:
+ ----
+ The Loki Library
+ Copyright (c) 2001 by Andrei Alexandrescu
+ This code accompanies the book:
+ Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
+ Patterns Applied". Copyright (c) 2001. Addison-Wesley.
+ Permission to use, copy, modify, distribute and sell this software for any
+ purpose is hereby granted without fee, provided that the above copyright
+ notice appear in all copies and that both that copyright notice and this
+ permission notice appear in supporting documentation.
+ The author or Addison-Welsey Longman make no representations about the
+ suitability of this software for any purpose. It is provided "as is"
+ without express or implied warranty.
+ ----
+
+ Simon: Actually we could put a lot more of typelist stuff in here, like
+ real list management (append, erase, ...) or other things, but
+ for now I just added the basic typelist and a length template,
+ to keep compile time at a minimum. If we really need more we can
+ still add it :)
+ Holger: Now we add a Template to create the TypeList
+*/
+#ifndef __ktypelist_h__
+#define __ktypelist_h__
+
+// Convenience macros for transforming flat type enumerations into the
+// recursive typelist structure
+
+#define K_TYPELIST_1(T1) KTypeList<T1, ::KDE::NullType>
+
+#define K_TYPELIST_2(T1, T2) KTypeList<T1, K_TYPELIST_1(T2) >
+
+#define K_TYPELIST_3(T1, T2, T3) KTypeList<T1, K_TYPELIST_2(T2, T3) >
+
+#define K_TYPELIST_4(T1, T2, T3, T4) \
+ KTypeList<T1, K_TYPELIST_3(T2, T3, T4) >
+
+#define K_TYPELIST_5(T1, T2, T3, T4, T5) \
+ KTypeList<T1, K_TYPELIST_4(T2, T3, T4, T5) >
+
+#define K_TYPELIST_6(T1, T2, T3, T4, T5, T6) \
+ KTypeList<T1, K_TYPELIST_5(T2, T3, T4, T5, T6) >
+
+#define K_TYPELIST_7(T1, T2, T3, T4, T5, T6, T7) \
+ KTypeList<T1, K_TYPELIST_6(T2, T3, T4, T5, T6, T7) >
+
+#define K_TYPELIST_8(T1, T2, T3, T4, T5, T6, T7, T8) \
+ KTypeList<T1, K_TYPELIST_7(T2, T3, T4, T5, T6, T7, T8) >
+
+#define K_TYPELIST_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) \
+ KTypeList<T1, K_TYPELIST_8(T2, T3, T4, T5, T6, T7, T8, T9) >
+
+#define K_TYPELIST_10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) \
+ KTypeList<T1, K_TYPELIST_9(T2, T3, T4, T5, T6, T7, T8, T9, T10) >
+
+#define K_TYPELIST_11(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) \
+ KTypeList<T1, K_TYPELIST_10(T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) >
+
+#define K_TYPELIST_12(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) \
+ KTypeList<T1, K_TYPELIST_11(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12) >
+
+#define K_TYPELIST_13(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) \
+ KTypeList<T1, K_TYPELIST_12(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13) >
+
+#define K_TYPELIST_14(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14) \
+ KTypeList<T1, K_TYPELIST_13(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14) >
+
+#define K_TYPELIST_15(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15) \
+ KTypeList<T1, K_TYPELIST_14(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15) >
+
+#define K_TYPELIST_16(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16) \
+ KTypeList<T1, K_TYPELIST_15(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16) >
+
+#define K_TYPELIST_17(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17) \
+ KTypeList<T1, K_TYPELIST_16(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17) >
+
+#define K_TYPELIST_18(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18) \
+ KTypeList<T1, K_TYPELIST_17(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18) >
+
+#define K_TYPELIST_19(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19) \
+ KTypeList<T1, K_TYPELIST_18(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19) >
+
+#define K_TYPELIST_20(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20) \
+ KTypeList<T1, K_TYPELIST_19(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20) >
+
+#define K_TYPELIST_21(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21) \
+ KTypeList<T1, K_TYPELIST_20(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21) >
+
+#define K_TYPELIST_22(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22) \
+ KTypeList<T1, K_TYPELIST_21(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22) >
+
+#define K_TYPELIST_23(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23) \
+ KTypeList<T1, K_TYPELIST_22(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23) >
+
+#define K_TYPELIST_24(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24) \
+ KTypeList<T1, K_TYPELIST_23(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24) >
+
+#define K_TYPELIST_25(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25) \
+ KTypeList<T1, K_TYPELIST_24(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25) >
+
+#define K_TYPELIST_26(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26) \
+ KTypeList<T1, K_TYPELIST_25(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26) >
+
+#define K_TYPELIST_27(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27) \
+ KTypeList<T1, K_TYPELIST_26(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27) >
+
+#define K_TYPELIST_28(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28) \
+ KTypeList<T1, K_TYPELIST_27(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28) >
+
+#define K_TYPELIST_29(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29) \
+ KTypeList<T1, K_TYPELIST_28(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29) >
+
+#define K_TYPELIST_30(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30) \
+ KTypeList<T1, K_TYPELIST_29(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30) >
+
+#define K_TYPELIST_31(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31) \
+ KTypeList<T1, K_TYPELIST_30(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31) >
+
+#define K_TYPELIST_32(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32) \
+ KTypeList<T1, K_TYPELIST_31(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32) >
+
+#define K_TYPELIST_33(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33) \
+ KTypeList<T1, K_TYPELIST_32(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33) >
+
+#define K_TYPELIST_34(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34) \
+ KTypeList<T1, K_TYPELIST_33(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34) >
+
+#define K_TYPELIST_35(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35) \
+ KTypeList<T1, K_TYPELIST_34(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35) >
+
+#define K_TYPELIST_36(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36) \
+ KTypeList<T1, K_TYPELIST_35(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36) >
+
+#define K_TYPELIST_37(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37) \
+ KTypeList<T1, K_TYPELIST_36(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37) >
+
+#define K_TYPELIST_38(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38) \
+ KTypeList<T1, K_TYPELIST_37(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38) >
+
+#define K_TYPELIST_39(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39) \
+ KTypeList<T1, K_TYPELIST_38(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39) >
+
+#define K_TYPELIST_40(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40) \
+ KTypeList<T1, K_TYPELIST_39(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40) >
+
+#define K_TYPELIST_41(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41) \
+ KTypeList<T1, K_TYPELIST_40(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41) >
+
+#define K_TYPELIST_42(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42) \
+ KTypeList<T1, K_TYPELIST_41(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42) >
+
+#define K_TYPELIST_43(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43) \
+ KTypeList<T1, K_TYPELIST_42(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43) >
+
+#define K_TYPELIST_44(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44) \
+ KTypeList<T1, K_TYPELIST_43(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44) >
+
+#define K_TYPELIST_45(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45) \
+ KTypeList<T1, K_TYPELIST_44(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45) >
+
+#define K_TYPELIST_46(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46) \
+ KTypeList<T1, K_TYPELIST_45(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46) >
+
+#define K_TYPELIST_47(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47) \
+ KTypeList<T1, K_TYPELIST_46(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47) >
+
+#define K_TYPELIST_48(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47, T48) \
+ KTypeList<T1, K_TYPELIST_47(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47, T48) >
+
+#define K_TYPELIST_49(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47, T48, T49) \
+ KTypeList<T1, K_TYPELIST_48(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47, T48, T49) >
+
+#define K_TYPELIST_50(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50) \
+ KTypeList<T1, K_TYPELIST_49(T2, T3, T4, T5, T6, T7, T8, T9, T10, \
+ T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \
+ T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50) >
+
+namespace KDE
+{
+ class NullType;
+}
+
+/**
+ * The building block of typelists of any length.
+ * Use it through the K_TYPELIST_NN macros.
+ * Defines nested types:
+ * @li Head (first element, a non-typelist type by convention)
+ * @li Tail (second element, can be another typelist)
+ */
+template <class T, class U>
+struct KTypeList
+{
+ /// first element, a non-typelist type by convention
+ typedef T Head;
+ /// second element, can be another typelist
+ typedef U Tail;
+};
+
+// forward decl.
+template <class TList> struct KTypeListLength;
+
+template <>
+struct KTypeListLength<KDE::NullType>
+{
+/**
+ * Zero length type list.
+ */
+ enum { Value = 0 };
+};
+
+/**
+ * A class template for determining the length of a typelist. To be
+ * used like KTypeListLength< typelist >::Value;
+ */
+template <class T, class U>
+struct KTypeListLength< KTypeList<T, U> >
+{
+ /**
+ * The length of the type list.
+ */
+ enum { Value = 1 + KTypeListLength<U>::Value };
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// class template IndexOf
+// Finds the index of a type in a typelist
+// Invocation (TList is a typelist and T is a type):
+// IndexOf<TList, T>::value
+// returns the position of T in TList, or NullType if T is not found in TList
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TList, class T> struct KTypeListIndexOf;
+
+template <class T>
+struct KTypeListIndexOf<KDE::NullType, T>
+{
+ enum { value = -1 };
+};
+
+template <class T, class Tail>
+struct KTypeListIndexOf< KTypeList<T, Tail>, T >
+{
+ enum { value = 0 };
+};
+
+template <class Head, class Tail, class T>
+struct KTypeListIndexOf< KTypeList<Head, Tail>, T >
+{
+private:
+ enum { temp = KTypeListIndexOf<Tail, T>::value };
+public:
+ enum { value = (temp == -1 ? -1 : 1 + temp) };
+};
+
+
+
+/**
+ * KMakeTypeList the prefered way to create a typelist for you.
+ *
+ * \code
+ * typedef KMakeTypeList<MyType1,MyWidget,MyQobject,MyKoffice>::Result Products;
+ * K_EXPORT_COMPONENT_FACTORY( libmyplugin, KGenericFactory&lt;Products&gt; )
+ *
+ * \endcode
+ *
+ *
+ * @author Holger Freyther based on the Loki library. See copyright statement at the top
+ * @since 3.3
+ */
+template<
+ typename T1 = KDE::NullType, typename T2 = KDE::NullType, typename T3 = KDE::NullType,
+ typename T4 = KDE::NullType, typename T5 = KDE::NullType, typename T6 = KDE::NullType,
+ typename T7 = KDE::NullType, typename T8 = KDE::NullType, typename T9 = KDE::NullType,
+ typename T10 = KDE::NullType, typename T11 = KDE::NullType, typename T12 = KDE::NullType,
+ typename T13 = KDE::NullType, typename T14 = KDE::NullType, typename T15 = KDE::NullType,
+ typename T16 = KDE::NullType, typename T17 = KDE::NullType, typename T18 = KDE::NullType
+ >
+struct KMakeTypeList{
+private:
+typedef typename KMakeTypeList
+<
+ T2 , T3 , T4 ,
+ T5 , T6 , T7 ,
+ T8 , T9 , T10,
+ T11, T12, T13,
+ T14, T15, T16,
+ T17, T18
+>::Result TailResult;
+
+public:
+ typedef KTypeList<T1, TailResult> Result;
+};
+
+template<>
+struct KMakeTypeList<>
+{
+ typedef KDE::NullType Result;
+};
+
+
+#endif
+
diff --git a/kdecore/kuniqueapp.h b/kdecore/kuniqueapp.h
new file mode 100644
index 000000000..d3ec22dd5
--- /dev/null
+++ b/kdecore/kuniqueapp.h
@@ -0,0 +1,6 @@
+// kuniqueapp.h is the old name. Use #include <kuniqueapplication.h> from now on
+#ifdef KDE_NO_COMPAT
+#error kuniqueapp.h is the old name. Use #include <kuniqueapplication.h> from now on
+#else
+#include <kuniqueapplication.h>
+#endif
diff --git a/kdecore/kuniqueapplication.cpp b/kdecore/kuniqueapplication.cpp
new file mode 100644
index 000000000..1ef94fbbe
--- /dev/null
+++ b/kdecore/kuniqueapplication.cpp
@@ -0,0 +1,495 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+
+ $Id$
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qptrlist.h>
+#include <qtimer.h>
+
+#include <dcopclient.h>
+#include <kcmdlineargs.h>
+#include <kstandarddirs.h>
+#include <kaboutdata.h>
+
+#if defined Q_WS_X11
+#include <kwin.h>
+#include <kstartupinfo.h>
+#endif
+
+#include <kconfig.h>
+#include "kdebug.h"
+#include "kuniqueapplication.h"
+
+#if defined Q_WS_X11
+#include <netwm.h>
+#include <X11/Xlib.h>
+#define DISPLAY "DISPLAY"
+#else
+# ifdef Q_WS_QWS
+# define DISPLAY "QWS_DISPLAY"
+# else
+# define DISPLAY "DISPLAY"
+# endif
+#endif
+
+bool KUniqueApplication::s_nofork = false;
+bool KUniqueApplication::s_multipleInstances = false;
+bool KUniqueApplication::s_uniqueTestDone = false;
+bool KUniqueApplication::s_handleAutoStarted = false;
+
+static KCmdLineOptions kunique_options[] =
+{
+ { "nofork", "Don't run in the background.", 0 },
+ KCmdLineLastOption
+};
+
+struct DCOPRequest {
+ QCString fun;
+ QByteArray data;
+ DCOPClientTransaction *transaction;
+};
+
+class KUniqueApplicationPrivate {
+public:
+ QPtrList <DCOPRequest> requestList;
+ bool processingRequest;
+ bool firstInstance;
+};
+
+void
+KUniqueApplication::addCmdLineOptions()
+{
+ KCmdLineArgs::addCmdLineOptions(kunique_options, 0, "kuniqueapp", "kde" );
+}
+
+bool
+KUniqueApplication::start()
+{
+ if( s_uniqueTestDone )
+ return true;
+ s_uniqueTestDone = true;
+ addCmdLineOptions(); // Make sure to add cmd line options
+#ifdef Q_WS_WIN
+ s_nofork = true;
+#else
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kuniqueapp");
+ s_nofork = !args->isSet("fork");
+ delete args;
+#endif
+
+ QCString appName = KCmdLineArgs::about->appName();
+
+ if (s_nofork)
+ {
+ if (s_multipleInstances)
+ {
+ QCString pid;
+ pid.setNum(getpid());
+ appName = appName + "-" + pid;
+ }
+
+ // Check to make sure that we're actually able to register with the DCOP
+ // server.
+
+#ifndef Q_WS_WIN //TODO
+ if(dcopClient()->registerAs(appName, false).isEmpty()) {
+ startKdeinit();
+ if(dcopClient()->registerAs(appName, false).isEmpty()) {
+ kdError() << "KUniqueApplication: Can't setup DCOP communication." << endl;
+ ::exit(255);
+ }
+ }
+#endif
+
+ // We'll call newInstance in the constructor. Do nothing here.
+ return true;
+ }
+ DCOPClient *dc;
+ int fd[2];
+ signed char result;
+ if (0 > pipe(fd))
+ {
+ kdError() << "KUniqueApplication: pipe() failed!" << endl;
+ ::exit(255);
+ }
+ int fork_result = fork();
+ switch(fork_result) {
+ case -1:
+ kdError() << "KUniqueApplication: fork() failed!" << endl;
+ ::exit(255);
+ break;
+ case 0:
+ // Child
+ ::close(fd[0]);
+ if (s_multipleInstances)
+ appName.append("-").append(QCString().setNum(getpid()));
+ dc = dcopClient();
+ {
+ QCString regName = dc->registerAs(appName, false);
+ if (regName.isEmpty())
+ {
+ // Check DISPLAY
+ if (QCString(getenv(DISPLAY)).isEmpty())
+ {
+ kdError() << "KUniqueApplication: Can't determine DISPLAY. Aborting." << endl;
+ result = -1; // Error
+ ::write(fd[1], &result, 1);
+ ::exit(255);
+ }
+
+ // Try to launch kdeinit.
+ startKdeinit();
+ regName = dc->registerAs(appName, false);
+ if (regName.isEmpty())
+ {
+ kdError() << "KUniqueApplication: Can't setup DCOP communication." << endl;
+ result = -1;
+ delete dc; // Clean up DCOP commmunication
+ ::write(fd[1], &result, 1);
+ ::exit(255);
+ }
+ }
+ if (regName != appName)
+ {
+ // Already running. Ok.
+ result = 0;
+ delete dc; // Clean up DCOP commmunication
+ ::write(fd[1], &result, 1);
+ ::close(fd[1]);
+#if 0
+#ifdef Q_WS_X11
+ // say we're up and running ( probably no new window will appear )
+ KStartupInfoId id;
+ if( kapp != NULL ) // KApplication constructor unsets the env. variable
+ id.initId( kapp->startupId());
+ else
+ id = KStartupInfo::currentStartupIdEnv();
+ if( !id.none())
+ {
+ Display* disp = XOpenDisplay( NULL );
+ if( disp != NULL ) // use extra X connection
+ {
+ KStartupInfo::sendFinishX( disp, id );
+ XCloseDisplay( disp );
+ }
+ }
+#else //FIXME(E): implement
+#endif
+#endif
+ return false;
+ }
+ dc->setPriorityCall(true);
+ }
+
+ {
+#ifdef Q_WS_X11
+ KStartupInfoId id;
+ if( kapp != NULL ) // KApplication constructor unsets the env. variable
+ id.initId( kapp->startupId());
+ else
+ id = KStartupInfo::currentStartupIdEnv();
+ if( !id.none())
+ { // notice about pid change
+ Display* disp = XOpenDisplay( NULL );
+ if( disp != NULL ) // use extra X connection
+ {
+ KStartupInfoData data;
+ data.addPid( getpid());
+ KStartupInfo::sendChangeX( disp, id, data );
+ XCloseDisplay( disp );
+ }
+ }
+#else //FIXME(E): Implement
+#endif
+ }
+ result = 0;
+ ::write(fd[1], &result, 1);
+ ::close(fd[1]);
+ return true; // Finished.
+ default:
+ // Parent
+// DCOPClient::emergencyClose();
+// dcopClient()->detach();
+ if (s_multipleInstances)
+ appName.append("-").append(QCString().setNum(fork_result));
+ ::close(fd[1]);
+ for(;;)
+ {
+ int n = ::read(fd[0], &result, 1);
+ if (n == 1) break;
+ if (n == 0)
+ {
+ kdError() << "KUniqueApplication: Pipe closed unexpectedly." << endl;
+ ::exit(255);
+ }
+ if (errno != EINTR)
+ {
+ kdError() << "KUniqueApplication: Error reading from pipe." << endl;
+ ::exit(255);
+ }
+ }
+ ::close(fd[0]);
+
+ if (result != 0)
+ ::exit(result); // Error occurred in child.
+
+ dc = new DCOPClient();
+ if (!dc->attach())
+ {
+ kdError() << "KUniqueApplication: Parent process can't attach to DCOP." << endl;
+ delete dc; // Clean up DCOP commmunication
+ ::exit(255);
+ }
+ if (!dc->isApplicationRegistered(appName)) {
+ kdError() << "KUniqueApplication: Registering failed!" << endl;
+ }
+
+ QCString new_asn_id;
+#if defined Q_WS_X11
+ KStartupInfoId id;
+ if( kapp != NULL ) // KApplication constructor unsets the env. variable
+ id.initId( kapp->startupId());
+ else
+ id = KStartupInfo::currentStartupIdEnv();
+ if( !id.none())
+ new_asn_id = id.id();
+#endif
+
+ QByteArray data, reply;
+ QDataStream ds(data, IO_WriteOnly);
+
+ KCmdLineArgs::saveAppArgs(ds);
+ ds << new_asn_id;
+
+ dc->setPriorityCall(true);
+ QCString replyType;
+ if (!dc->call(appName, KCmdLineArgs::about->appName(), "newInstance()", data, replyType, reply))
+ {
+ kdError() << "Communication problem with " << KCmdLineArgs::about->appName() << ", it probably crashed." << endl;
+ delete dc; // Clean up DCOP commmunication
+ ::exit(255);
+ }
+ dc->setPriorityCall(false);
+ if (replyType != "int")
+ {
+ kdError() << "KUniqueApplication: DCOP communication error!" << endl;
+ delete dc; // Clean up DCOP commmunication
+ ::exit(255);
+ }
+ QDataStream rs(reply, IO_ReadOnly);
+ int exitCode;
+ rs >> exitCode;
+ delete dc; // Clean up DCOP commmunication
+ ::exit(exitCode);
+ break;
+ }
+ return false; // make insure++ happy
+}
+
+
+KUniqueApplication::KUniqueApplication(bool allowStyles, bool GUIenabled, bool configUnique)
+ : KApplication( allowStyles, GUIenabled, initHack( configUnique )),
+ DCOPObject(KCmdLineArgs::about->appName())
+{
+ d = new KUniqueApplicationPrivate;
+ d->processingRequest = false;
+ d->firstInstance = true;
+
+ if (s_nofork)
+ // Can't call newInstance directly from the constructor since it's virtual...
+ QTimer::singleShot( 0, this, SLOT(newInstanceNoFork()) );
+}
+
+
+#ifdef Q_WS_X11
+KUniqueApplication::KUniqueApplication(Display *display, Qt::HANDLE visual,
+ Qt::HANDLE colormap, bool allowStyles, bool configUnique)
+ : KApplication( display, visual, colormap, allowStyles, initHack( configUnique )),
+ DCOPObject(KCmdLineArgs::about->appName())
+{
+ d = new KUniqueApplicationPrivate;
+ d->processingRequest = false;
+ d->firstInstance = true;
+
+ if (s_nofork)
+ // Can't call newInstance directly from the constructor since it's virtual...
+ QTimer::singleShot( 0, this, SLOT(newInstanceNoFork()) );
+}
+#endif
+
+
+KUniqueApplication::~KUniqueApplication()
+{
+ delete d;
+}
+
+// this gets called before even entering QApplication::QApplication()
+KInstance* KUniqueApplication::initHack( bool configUnique )
+{
+ KInstance* inst = new KInstance( KCmdLineArgs::about );
+ if (configUnique)
+ {
+ KConfigGroupSaver saver( inst->config(), "KDE" );
+ s_multipleInstances = inst->config()->readBoolEntry("MultipleInstances", false);
+ }
+ if( !start())
+ // Already running
+ ::exit( 0 );
+ return inst;
+}
+
+void KUniqueApplication::newInstanceNoFork()
+{
+ if (dcopClient()->isSuspended())
+ {
+ // Try again later.
+ QTimer::singleShot( 200, this, SLOT(newInstanceNoFork()) );
+ return;
+ }
+
+ s_handleAutoStarted = false;
+ newInstance();
+ d->firstInstance = false;
+#if defined Q_WS_X11
+ // KDE4 remove
+ // A hack to make startup notification stop for apps which override newInstance()
+ // and reuse an already existing window there, but use KWin::activateWindow()
+ // instead of KStartupInfo::setNewStartupId(). Therefore KWin::activateWindow()
+ // for now sets this flag. Automatically ending startup notification always
+ // would cause problem if the new window would show up with a small delay.
+ if( s_handleAutoStarted )
+ KStartupInfo::handleAutoAppStartedSending();
+#endif
+ // What to do with the return value ?
+}
+
+bool KUniqueApplication::process(const QCString &fun, const QByteArray &data,
+ QCString &replyType, QByteArray &replyData)
+{
+ if (fun == "newInstance()")
+ {
+ delayRequest(fun, data);
+ return true;
+ } else
+ return DCOPObject::process(fun, data, replyType, replyData);
+}
+
+void
+KUniqueApplication::delayRequest(const QCString &fun, const QByteArray &data)
+{
+ DCOPRequest *request = new DCOPRequest;
+ request->fun = fun;
+ request->data = data;
+ request->transaction = dcopClient()->beginTransaction();
+ d->requestList.append(request);
+ if (!d->processingRequest)
+ {
+ QTimer::singleShot(0, this, SLOT(processDelayed()));
+ }
+}
+
+void
+KUniqueApplication::processDelayed()
+{
+ if (dcopClient()->isSuspended())
+ {
+ // Try again later.
+ QTimer::singleShot( 200, this, SLOT(processDelayed()));
+ return;
+ }
+ d->processingRequest = true;
+ while( !d->requestList.isEmpty() )
+ {
+ DCOPRequest *request = d->requestList.take(0);
+ QByteArray replyData;
+ QCString replyType;
+ if (request->fun == "newInstance()") {
+ dcopClient()->setPriorityCall(false);
+ QDataStream ds(request->data, IO_ReadOnly);
+ KCmdLineArgs::loadAppArgs(ds);
+ if( !ds.atEnd()) // backwards compatibility
+ {
+ QCString asn_id;
+ ds >> asn_id;
+ setStartupId( asn_id );
+ }
+ s_handleAutoStarted = false;
+ int exitCode = newInstance();
+ d->firstInstance = false;
+#if defined Q_WS_X11
+ if( s_handleAutoStarted )
+ KStartupInfo::handleAutoAppStartedSending(); // KDE4 remove?
+#endif
+ QDataStream rs(replyData, IO_WriteOnly);
+ rs << exitCode;
+ replyType = "int";
+ }
+ dcopClient()->endTransaction( request->transaction, replyType, replyData);
+ delete request;
+ }
+
+ d->processingRequest = false;
+}
+
+bool KUniqueApplication::restoringSession()
+{
+ return d->firstInstance && isRestored();
+}
+
+int KUniqueApplication::newInstance()
+{
+ if (!d->firstInstance)
+ {
+
+ if ( mainWidget() )
+ {
+ mainWidget()->show();
+#if defined Q_WS_X11
+ // This is the line that handles window activation if necessary,
+ // and what's important, it does it properly. If you reimplement newInstance(),
+ // and don't call the inherited one, use this (but NOT when newInstance()
+ // is called for the first time, like here).
+ KStartupInfo::setNewStartupId( mainWidget(), kapp->startupId());
+#endif
+ }
+ }
+ return 0; // do nothing in default implementation
+}
+
+void KUniqueApplication::setHandleAutoStarted()
+{
+ s_handleAutoStarted = false;
+}
+
+void KUniqueApplication::virtual_hook( int id, void* data )
+{ KApplication::virtual_hook( id, data );
+ DCOPObject::virtual_hook( id, data ); }
+
+#include "kuniqueapplication.moc"
diff --git a/kdecore/kuniqueapplication.h b/kdecore/kuniqueapplication.h
new file mode 100644
index 000000000..049627f62
--- /dev/null
+++ b/kdecore/kuniqueapplication.h
@@ -0,0 +1,221 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 2000-2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KUNIQUEAPP_H
+#define _KUNIQUEAPP_H
+
+#include <kapplication.h>
+#include <dcopobject.h>
+
+class KUniqueApplicationPrivate;
+
+/**
+ * Maintains only a single
+ * instance of a running application at a time.
+ *
+ * If another instance
+ * is started, it will determine (via DCOP) whether it is the first instance
+ * or a second instance. If it is a second instance, it will forward on
+ * the information to the first instance and then quit.
+ *
+ * The .desktop file for the application should state X-DCOP-ServiceType=Unique,
+ * see kapplication.h
+ *
+ * If your application is used to open files, it should also support the --tempfile
+ * option (see KCmdLineArgs::addTempFileOption()), to delete tempfiles after use.
+ * Add X-KDE-HasTempFileOption=true to the .desktop file to indicate this.
+ *
+ * @see KApplication DCOPObject
+ * @author Preston Brown <pbrown@kde.org>
+ */
+class KDECORE_EXPORT KUniqueApplication : public KApplication, public DCOPObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor. Takes command line arguments from KCmdLineArgs
+ *
+ * @param allowStyles Set to false to disable the loading on plugin based
+ * styles. This is only useful to applications that do not display a GUI
+ * normally. If you do create an application with @p allowStyles set to false
+ * it normally runs in the background but under special circumstances
+ * displays widgets. Call KApplication::enableStyles() before
+ * displaying any widgets.
+ * @param GUIenabled Set to false to disable all GUI stuff. This implies
+ * no styles either.
+ * @param configUnique If true, the uniqueness of the application will
+ * depend on the value of the "MultipleInstances"
+ * key in the "KDE" group of the application config file.
+ */
+ KUniqueApplication( bool allowStyles=true,
+ bool GUIenabled=true,
+ bool configUnique=false);
+
+#ifdef Q_WS_X11
+ /**
+ * Constructor. Takes command line arguments from KCmdLineArgs
+ *
+ * @param display Will be passed to Qt as the X display. The display
+ * must be valid and already opened.
+ * @param visual Pointer to the X11 visual that should be used by the
+ * application. If NULL, the default visual will be used instead.
+ * @param colormap The colormap that should be used by the application.
+ * If 0, the default colormap will be used instead.
+ * @param allowStyles Set to false to disable the loading on plugin based
+ * styles. This is only useful to applications that do not display a GUI
+ * normally. If you do create an application with @p allowStyles set to false
+ * it normally runs in the background but under special circumstances
+ * displays widgets. Call KApplication::enableStyles() before
+ * displaying any widgets.
+ * @param configUnique If true, the uniqueness of the application will
+ * depend on the value of the "MultipleInstances"
+ * key in the "KDE" group of the application config file.
+ * @since KDE 3.3
+ */
+ KUniqueApplication( Display *display,
+ Qt::HANDLE visual=0,
+ Qt::HANDLE colormap=0,
+ bool allowStyles=true,
+ bool configUnique=false);
+#endif
+
+ /**
+ * Adds command line options specific for KUniqueApplication.
+ *
+ * Should be called before calling KUniqueApplication constructor
+ * and / or start().
+ */
+ static void addCmdLineOptions();
+
+ /**
+ * Forks and registers with dcop.
+ *
+ * The command line arguments are being sent via DCOP to newInstance()
+ * and will be received once the application enters the event loop.
+ *
+ * Typically this is used like:
+ * \code
+ * int main(int argc, char **argv) {
+ * KAboutData about("myappname", "myAppName", .....);
+ * KCmdLineArgs::init(argc, argv, &about);
+ * KCmdLineArgs::addCmdLineOptions( myCmdOptions );
+ * KUniqueApplication::addCmdLineOptions();
+ *
+ * if (!KUniqueApplication::start()) {
+ * fprintf(stderr, "myAppName is already running!\n");
+ * exit(0);
+ * }
+ * KUniqueApplication a;
+ * a.exec();
+ * }
+ * \endcode
+ * Note that it's not necessary to call start() explicitly. It will be
+ * called automatically before creating KUniqueApplication if it hasn't
+ * been called yet, without any performance impact.
+ *
+ * @return true if registration is successful.
+ * false if another process was already running.
+ */
+ static bool start();
+
+ /**
+ * Destructor
+ */
+ virtual ~KUniqueApplication();
+
+ /**
+ * Dispatches any incoming DCOP message for a new instance.
+ *
+ * If it is not a request for a new instance, return false.
+ * Overloaded from DCOPObject to make sure that the application
+ * stays unique.
+ * @param fun DCOP function signature
+ * @param data the data for the arguments
+ * @param replyType the type of the reply value
+ * @param replyData the reply
+ * @see DCOPObject
+ */
+ bool process(const QCString &fun, const QByteArray &data,
+ QCString &replyType, QByteArray &replyData);
+
+ /**
+ * Creates a new "instance" of the application.
+ *
+ * Usually this will involve making some calls into the GUI portion of your
+ * application asking for a new window to be created, possibly with
+ * some data already loaded based on the arguments received.
+ *
+ * Command line arguments have been passed to KCmdLineArgs before this
+ * function is called and can be checked in the usual way.
+ *
+ * The default implementation ensures the mainwindow of the already
+ * running instance is shown and activated if necessary. You should
+ * prefer using it from your overridden method instead of doing
+ * it directly.
+ *
+ * Note that newInstance() is called also in the first started
+ * application process.
+ *
+ * @return An exit value. The calling process will exit with this value.
+ */
+ virtual int newInstance();
+
+ /**
+ * Returns whether newInstance() is being called while session
+ * restoration is in progress.
+ *
+ * @since KDE 3.3
+ */
+ bool restoringSession();
+
+ /**
+ * @internal
+ */
+ static void setHandleAutoStarted();
+
+private:
+ /**
+ * Delays the processing of a DCOP request.
+ */
+ void delayRequest(const QCString &fun, const QByteArray &data);
+
+private slots:
+ /**
+ * Delayed processing of DCOP requests.
+ */
+ void processDelayed();
+
+ void newInstanceNoFork();
+
+ static KInstance* initHack( bool configUnique );
+
+private:
+ static bool s_nofork;
+ static bool s_multipleInstances;
+ static bool s_uniqueTestDone;
+ static bool s_handleAutoStarted;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KUniqueApplicationPrivate *d;
+};
+
+#endif
diff --git a/kdecore/kunload.h b/kdecore/kunload.h
new file mode 100644
index 000000000..fbdf62556
--- /dev/null
+++ b/kdecore/kunload.h
@@ -0,0 +1,22 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Michael Matz <matz@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#define _UNLOAD(p)
diff --git a/kdecore/kurl.cpp b/kdecore/kurl.cpp
new file mode 100644
index 000000000..0f54d19c4
--- /dev/null
+++ b/kdecore/kurl.cpp
@@ -0,0 +1,2356 @@
+/*
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ * The currently active RFC for URL/URIs is RFC3986
+ * Previous (and now deprecated) RFCs are RFC1738 and RFC2396
+ */
+
+#include "kurl.h"
+
+// KDE_QT_ONLY is first used for dcop/client (e.g. marshalling)
+#ifndef KDE_QT_ONLY
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kidna.h>
+#include <kprotocolinfo.h>
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qurl.h>
+#include <qdir.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qstylesheet.h>
+#include <qmap.h>
+#include <qtextcodec.h>
+#include <qmutex.h>
+
+#ifdef Q_WS_WIN
+# define KURL_ROOTDIR_PATH "C:/"
+#else
+# define KURL_ROOTDIR_PATH "/"
+#endif
+
+static const QString fileProt = "file";
+
+static QTextCodec * codecForHint( int encoding_hint /* not 0 ! */ )
+{
+ return QTextCodec::codecForMib( encoding_hint );
+}
+
+// encoding_offset:
+// 0 encode both @ and /
+// 1 encode @ but not /
+// 2 encode neither @ or /
+static QString encode( const QString& segment, int encoding_offset, int encoding_hint, bool isRawURI = false )
+{
+ const char *encode_string = "/@<>#\"&?={}|^~[]\'`\\:+%";
+ encode_string += encoding_offset;
+
+ QCString local;
+ if (encoding_hint==0)
+ local = segment.local8Bit();
+ else
+ {
+ QTextCodec * textCodec = codecForHint( encoding_hint );
+ if (!textCodec)
+ local = segment.local8Bit();
+ else
+ local = textCodec->fromUnicode( segment );
+ }
+
+ int old_length = isRawURI ? local.size() - 1 : local.length();
+
+ if ( !old_length )
+ return segment.isNull() ? QString::null : QString(""); // differentiate null and empty
+
+ // a worst case approximation
+ QChar *new_segment = new QChar[ old_length * 3 + 1 ];
+ int new_length = 0;
+
+ for ( int i = 0; i < old_length; i++ )
+ {
+ // 'unsave' and 'reserved' characters
+ // according to RFC 1738,
+ // 2.2. URL Character Encoding Issues (pp. 3-4)
+ // WABA: Added non-ascii
+ unsigned char character = local[i];
+ if ( (character <= 32) || (character >= 127) ||
+ strchr(encode_string, character) )
+ {
+ new_segment[ new_length++ ] = '%';
+
+ unsigned int c = character / 16;
+ c += (c > 9) ? ('A' - 10) : '0';
+ new_segment[ new_length++ ] = c;
+
+ c = character % 16;
+ c += (c > 9) ? ('A' - 10) : '0';
+ new_segment[ new_length++ ] = c;
+
+ }
+ else
+ new_segment[ new_length++ ] = local[i];
+ }
+
+ QString result = QString(new_segment, new_length);
+ delete [] new_segment;
+ return result;
+}
+
+static QString encodeHost( const QString& segment, bool encode_slash, int encoding_hint )
+{
+ // Hostnames are encoded differently
+ // we use the IDNA transformation instead
+
+ // Note: when merging qt-addon, use QResolver::domainToAscii here
+#ifndef KDE_QT_ONLY
+ Q_UNUSED( encode_slash );
+ Q_UNUSED( encoding_hint );
+ QString host = KIDNA::toAscii(segment);
+ if (host.isEmpty())
+ return segment;
+ return host;
+#else
+ return encode(segment, encode_slash ? 0 : 1, encoding_hint);
+#endif
+}
+
+static int hex2int( unsigned int _char )
+{
+ if ( _char >= 'A' && _char <='F')
+ return _char - 'A' + 10;
+ if ( _char >= 'a' && _char <='f')
+ return _char - 'a' + 10;
+ if ( _char >= '0' && _char <='9')
+ return _char - '0';
+ return -1;
+}
+
+// WABA: The result of lazy_encode isn't usable for a URL which
+// needs to satisfies RFC requirements. However, the following
+// operation will make it usable again:
+// encode(decode(...))
+//
+// As a result one can see that url.prettyURL() does not result in
+// a RFC compliant URL but that the following sequence does:
+// KURL(url.prettyURL()).url()
+
+
+static QString lazy_encode( const QString& segment, bool encodeAt=true )
+{
+ int old_length = segment.length();
+
+ if ( !old_length )
+ return QString::null;
+
+ // a worst case approximation
+ QChar *new_segment = new QChar[ old_length * 3 + 1 ];
+ int new_length = 0;
+
+ for ( int i = 0; i < old_length; i++ )
+ {
+ unsigned int character = segment[i].unicode(); // Don't use latin1()
+ // It returns 0 for non-latin1 values
+ // Small set of really ambiguous chars
+ if ((character < 32) || // Low ASCII
+ ((character == '%') && // The escape character itself
+ (i+2 < old_length) && // But only if part of a valid escape sequence!
+ (hex2int(segment[i+1].unicode())!= -1) &&
+ (hex2int(segment[i+2].unicode())!= -1)) ||
+ (character == '?') || // Start of query delimiter
+ ((character == '@') && encodeAt) || // Username delimiter
+ (character == '#') || // Start of reference delimiter
+ ((character == 32) && (i+1 == old_length || segment[i+1] == ' '))) // A trailing space
+ {
+ new_segment[ new_length++ ] = '%';
+
+ unsigned int c = character / 16;
+ c += (c > 9) ? ('A' - 10) : '0';
+ new_segment[ new_length++ ] = c;
+
+ c = character % 16;
+ c += (c > 9) ? ('A' - 10) : '0';
+ new_segment[ new_length++ ] = c;
+ }
+ else
+ new_segment[ new_length++ ] = segment[i];
+ }
+
+ QString result = QString(new_segment, new_length);
+ delete [] new_segment;
+ return result;
+}
+
+static void decode( const QString& segment, QString &decoded, QString &encoded, int encoding_hint=0, bool updateDecoded = true, bool isRawURI = false )
+{
+ decoded = QString::null;
+ encoded = segment;
+
+ int old_length = segment.length();
+ if ( !old_length )
+ return;
+
+ QTextCodec *textCodec = 0;
+ if (encoding_hint)
+ textCodec = codecForHint( encoding_hint );
+
+ if (!textCodec)
+ textCodec = QTextCodec::codecForLocale();
+
+ QCString csegment = textCodec->fromUnicode(segment);
+ // Check if everything went ok
+ if (textCodec->toUnicode(csegment) != segment)
+ {
+ // Uh oh
+ textCodec = codecForHint( 106 ); // Fall back to utf-8
+ csegment = textCodec->fromUnicode(segment);
+ }
+ old_length = csegment.length();
+
+ int new_length = 0;
+ int new_length2 = 0;
+
+ // make a copy of the old one
+ char *new_segment = new char[ old_length + 1 ];
+ QChar *new_usegment = new QChar[ old_length * 3 + 1 ];
+
+ int i = 0;
+ while( i < old_length )
+ {
+ bool bReencode = false;
+ unsigned char character = csegment[ i++ ];
+ if ((character <= ' ') || (character > 127))
+ bReencode = true;
+
+ new_usegment [ new_length2++ ] = character;
+ if (character == '%' )
+ {
+ int a = i+1 < old_length ? hex2int( csegment[i] ) : -1;
+ int b = i+1 < old_length ? hex2int( csegment[i+1] ) : -1;
+ if ((a == -1) || (b == -1)) // Only replace if sequence is valid
+ {
+ // Contains stray %, make sure to re-encode!
+ bReencode = true;
+ }
+ else
+ {
+ // Valid %xx sequence
+ character = a * 16 + b; // Replace with value of %dd
+ if (!isRawURI && !character && updateDecoded)
+ break; // Stop at %00
+
+ new_usegment [ new_length2++ ] = (unsigned char) csegment[i++];
+ new_usegment [ new_length2++ ] = (unsigned char) csegment[i++];
+ }
+ }
+ if (bReencode)
+ {
+ new_length2--;
+ new_usegment [ new_length2++ ] = '%';
+
+ unsigned int c = character / 16;
+ c += (c > 9) ? ('A' - 10) : '0';
+ new_usegment[ new_length2++ ] = c;
+
+ c = character % 16;
+ c += (c > 9) ? ('A' - 10) : '0';
+ new_usegment[ new_length2++ ] = c;
+ }
+
+ new_segment [ new_length++ ] = character;
+ }
+ new_segment [ new_length ] = 0;
+
+ encoded = QString( new_usegment, new_length2);
+
+ // Encoding specified
+ if (updateDecoded)
+ {
+ decoded = textCodec->toUnicode( new_segment );
+ if ( isRawURI ) {
+ int length = qstrlen( new_segment );
+ while ( length < new_length ) {
+ decoded += QChar::null;
+ length += 1;
+ decoded += textCodec->toUnicode( new_segment + length );
+ length += qstrlen( new_segment + length );
+ }
+ }
+
+ QCString validate = textCodec->fromUnicode(decoded);
+
+ if (strcmp(validate.data(), new_segment) != 0)
+ {
+ decoded = QString::fromLocal8Bit(new_segment, new_length);
+ }
+ }
+
+ delete [] new_segment;
+ delete [] new_usegment;
+}
+
+static QString decode(const QString &segment, int encoding_hint = 0, bool isRawURI = false)
+{
+ QString result;
+ QString tmp;
+ decode(segment, result, tmp, encoding_hint, true, isRawURI);
+ return result;
+}
+
+static QString cleanpath(const QString &_path, bool cleanDirSeparator, bool decodeDots)
+{
+ if (_path.isEmpty()) return QString::null;
+
+ if (QDir::isRelativePath(_path))
+ return _path; // Don't mangle mailto-style URLs
+
+ QString path = _path;
+
+ int len = path.length();
+
+ if (decodeDots)
+ {
+#ifndef KDE_QT_ONLY
+ static const QString &encodedDot = KGlobal::staticQString("%2e");
+#else
+ QString encodedDot("%2e");
+#endif
+ if (path.find(encodedDot, 0, false) != -1)
+ {
+#ifndef KDE_QT_ONLY
+ static const QString &encodedDOT = KGlobal::staticQString("%2E"); // Uppercase!
+#else
+ QString encodedDOT("%2E");
+#endif
+ path.replace(encodedDot, ".");
+ path.replace(encodedDOT, ".");
+ len = path.length();
+ }
+ }
+
+ bool slash = (len && path[len-1] == '/') ||
+ (len > 1 && path[len-2] == '/' && path[len-1] == '.');
+
+ // The following code cleans up directory path much like
+ // QDir::cleanDirPath() except it can be made to ignore multiple
+ // directory separators by setting the flag to false. That fixes
+ // bug# 15044, mail.altavista.com and other similar brain-dead server
+ // implementations that do not follow what has been specified in
+ // RFC 2396!! (dA)
+ QString result;
+ int cdUp, orig_pos, pos;
+
+ cdUp = 0;
+ pos = orig_pos = len;
+ while ( pos && (pos = path.findRev('/',--pos)) != -1 )
+ {
+ len = orig_pos - pos - 1;
+ if ( len == 2 && path[pos+1] == '.' && path[pos+2] == '.' )
+ cdUp++;
+ else
+ {
+ // Ignore any occurrences of '.'
+ // This includes entries that simply do not make sense like /..../
+ if ( (len || !cleanDirSeparator) &&
+ (len != 1 || path[pos+1] != '.' ) )
+ {
+ if ( !cdUp )
+ result.prepend(path.mid(pos, len+1));
+ else
+ cdUp--;
+ }
+ }
+ orig_pos = pos;
+ }
+
+#ifdef Q_WS_WIN // prepend drive letter if exists (js)
+ if (orig_pos >= 2 && isalpha(path[0].latin1()) && path[1]==':') {
+ result.prepend(QString(path[0])+":");
+ }
+#endif
+
+ if ( result.isEmpty() )
+ result = KURL_ROOTDIR_PATH;
+ else if ( slash && result[result.length()-1] != '/' )
+ result.append('/');
+
+ return result;
+}
+
+bool KURL::isRelativeURL(const QString &_url)
+{
+ int len = _url.length();
+ if (!len) return true; // Very short relative URL.
+ const QChar *str = _url.unicode();
+
+ // Absolute URL must start with alpha-character
+ if (!isalpha(str[0].latin1()))
+ return true; // Relative URL
+
+ for(int i = 1; i < len; i++)
+ {
+ char c = str[i].latin1(); // Note: non-latin1 chars return 0!
+ if (c == ':')
+ return false; // Absolute URL
+
+ // Protocol part may only contain alpha, digit, + or -
+ if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-'))
+ return true; // Relative URL
+ }
+ // URL did not contain ':'
+ return true; // Relative URL
+}
+
+KURL::List::List(const KURL &url)
+{
+ append( url );
+}
+
+KURL::List::List(const QStringList &list)
+{
+ for (QStringList::ConstIterator it = list.begin();
+ it != list.end();
+ it++)
+ {
+ append( KURL(*it) );
+ }
+}
+
+QStringList KURL::List::toStringList() const
+{
+ QStringList lst;
+ for( KURL::List::ConstIterator it = begin();
+ it != end();
+ it++)
+ {
+ lst.append( (*it).url() );
+ }
+ return lst;
+}
+
+
+KURL::KURL()
+{
+ reset();
+}
+
+KURL::~KURL()
+{
+}
+
+
+KURL::KURL( const QString &url, int encoding_hint )
+{
+ reset();
+ parse( url, encoding_hint );
+}
+
+KURL::KURL( const char * url, int encoding_hint )
+{
+ reset();
+ parse( QString::fromLatin1(url), encoding_hint );
+}
+
+KURL::KURL( const QCString& url, int encoding_hint )
+{
+ reset();
+ parse( QString::fromLatin1(url), encoding_hint );
+}
+
+KURL::KURL( const KURL& _u )
+{
+ *this = _u;
+}
+
+QDataStream & operator<< (QDataStream & s, const KURL & a)
+{
+ QString QueryForWire=a.m_strQuery_encoded;
+ if (!a.m_strQuery_encoded.isNull())
+ QueryForWire.prepend("?");
+
+ s << a.m_strProtocol << a.m_strUser << a.m_strPass << a.m_strHost
+ << a.m_strPath << a.m_strPath_encoded << QueryForWire << a.m_strRef_encoded
+ << Q_INT8(a.m_bIsMalformed ? 1 : 0) << a.m_iPort;
+ return s;
+}
+
+QDataStream & operator>> (QDataStream & s, KURL & a)
+{
+ Q_INT8 malf;
+ QString QueryFromWire;
+ s >> a.m_strProtocol >> a.m_strUser >> a.m_strPass >> a.m_strHost
+ >> a.m_strPath >> a.m_strPath_encoded >> QueryFromWire >> a.m_strRef_encoded
+ >> malf >> a.m_iPort;
+ a.m_bIsMalformed = (malf != 0);
+
+ if ( QueryFromWire.isNull() )
+ a.m_strQuery_encoded = QString::null;
+ else if ( QueryFromWire.length() == 1 ) // empty query
+ a.m_strQuery_encoded = "";
+ else
+ a.m_strQuery_encoded = QueryFromWire.mid(1);
+
+ a.m_iUriMode = KURL::uriModeForProtocol( a.m_strProtocol );
+
+ return s;
+}
+
+#ifndef QT_NO_NETWORKPROTOCOL
+KURL::KURL( const QUrl &u )
+{
+ *this = u;
+}
+#endif
+
+KURL::KURL( const KURL& _u, const QString& _rel_url, int encoding_hint )
+{
+ if (_u.hasSubURL()) // Operate on the last suburl, not the first
+ {
+ KURL::List lst = split( _u );
+ KURL u(lst.last(), _rel_url, encoding_hint);
+ lst.remove( lst.last() );
+ lst.append( u );
+ *this = join( lst );
+ return;
+ }
+ // WORKAROUND THE RFC 1606 LOOPHOLE THAT ALLOWS
+ // http:/index.html AS A VALID SYNTAX FOR RELATIVE
+ // URLS. ( RFC 2396 section 5.2 item # 3 )
+ QString rUrl = _rel_url;
+ int len = _u.m_strProtocol.length();
+ if ( !_u.m_strHost.isEmpty() && !rUrl.isEmpty() &&
+ rUrl.find( _u.m_strProtocol, 0, false ) == 0 &&
+ rUrl[len] == ':' && (rUrl[len+1] != '/' ||
+ (rUrl[len+1] == '/' && rUrl[len+2] != '/')) )
+ {
+ rUrl.remove( 0, rUrl.find( ':' ) + 1 );
+ }
+
+ if ( rUrl.isEmpty() )
+ {
+ *this = _u;
+ }
+ else if ( rUrl[0] == '#' )
+ {
+ *this = _u;
+ m_strRef_encoded = rUrl.mid(1);
+ if ( m_strRef_encoded.isNull() )
+ m_strRef_encoded = ""; // we know there was an (empty) html ref, we saw the '#'
+ }
+ else if ( isRelativeURL( rUrl) )
+ {
+ *this = _u;
+ m_strQuery_encoded = QString::null;
+ m_strRef_encoded = QString::null;
+ if ( rUrl[0] == '/')
+ {
+ if ((rUrl.length() > 1) && (rUrl[1] == '/'))
+ {
+ m_strHost = QString::null;
+ // File protocol returns file:/// without host, strip // from rUrl
+ if (_u.m_strProtocol == fileProt)
+ rUrl.remove(0, 2);
+ }
+ m_strPath = QString::null;
+ m_strPath_encoded = QString::null;
+ }
+ else if ( rUrl[0] != '?' )
+ {
+ int pos = m_strPath.findRev( '/' );
+ if (pos >= 0)
+ m_strPath.truncate(pos);
+ m_strPath += '/';
+ if (!m_strPath_encoded.isEmpty())
+ {
+ pos = m_strPath_encoded.findRev( '/' );
+ if (pos >= 0)
+ m_strPath_encoded.truncate(pos);
+ m_strPath_encoded += '/';
+ }
+ }
+ else
+ {
+ if ( m_strPath.isEmpty() )
+ m_strPath = '/';
+ }
+ KURL tmp( url() + rUrl, encoding_hint);
+ *this = tmp;
+ cleanPath(false);
+ }
+ else
+ {
+ KURL tmp( rUrl, encoding_hint);
+ *this = tmp;
+ // Preserve userinfo if applicable.
+ if (!_u.m_strUser.isEmpty() && m_strUser.isEmpty() && (_u.m_strHost == m_strHost) && (_u.m_strProtocol == m_strProtocol))
+ {
+ m_strUser = _u.m_strUser;
+ m_strPass = _u.m_strPass;
+ }
+ cleanPath(false);
+ }
+}
+
+void KURL::reset()
+{
+ m_strProtocol = QString::null;
+ m_strUser = QString::null;
+ m_strPass = QString::null;
+ m_strHost = QString::null;
+ m_strPath = QString::null;
+ m_strPath_encoded = QString::null;
+ m_strQuery_encoded = QString::null;
+ m_strRef_encoded = QString::null;
+ m_bIsMalformed = true;
+ m_iPort = 0;
+ m_iUriMode = Auto;
+}
+
+bool KURL::isEmpty() const
+{
+ return (m_strPath.isEmpty() && m_strProtocol.isEmpty());
+}
+
+void KURL::parse( const QString& _url, int encoding_hint )
+{
+ if ( _url.isEmpty() || m_iUriMode == Invalid )
+ {
+ m_strProtocol = _url;
+ m_iUriMode = Invalid;
+ return;
+ }
+
+ const QChar* buf = _url.unicode();
+ const QChar* orig = buf;
+ uint len = _url.length();
+ uint pos = 0;
+
+ // Node 1: Accept alpha or slash
+ QChar x = buf[pos++];
+#ifdef Q_WS_WIN
+ /* win32: accept <letter>: or <letter>:/ or <letter>:\ */
+ const bool alpha = isalpha((int)x);
+ if (alpha && len<2)
+ goto NodeErr;
+ if (alpha && buf[pos]==':' && (len==2 || (len>2 && (buf[pos+1]=='/' || buf[pos+1]=='\\'))))
+#else
+ if ( x == '/' )
+#endif
+ {
+ // A slash means we immediately proceed to parse it as a file URL.
+ m_iUriMode = URL;
+ m_strProtocol = fileProt;
+ parseURL( _url, encoding_hint );
+ return;
+ }
+ if ( !isalpha( (int)x ) )
+ goto NodeErr;
+
+ // Node 2: Accept any amount of (alpha|digit|'+'|'-')
+ // '.' is not currently accepted, because current KURL may be confused.
+ // Proceed with :// :/ or :
+ while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
+ buf[pos] == '+' || buf[pos] == '-')) pos++;
+
+ if (pos < len && buf[pos] == ':' )
+ {
+ m_strProtocol = QString( orig, pos ).lower();
+ if ( m_iUriMode == Auto )
+ m_iUriMode = uriModeForProtocol( m_strProtocol );
+ // Proceed to correct parse function.
+ switch ( m_iUriMode )
+ {
+ case RawURI:
+ parseRawURI( _url );
+ return;
+ case Mailto:
+ parseMailto( _url );
+ return;
+ case URL:
+ parseURL( _url, encoding_hint );
+ return;
+ default:
+ // Unknown URI mode results in an invalid URI.
+ break;
+ }
+ }
+
+NodeErr:
+ reset();
+ m_strProtocol = _url;
+ m_iUriMode = Invalid;
+}
+
+void KURL::parseRawURI( const QString& _url, int encoding_hint )
+{
+ uint len = _url.length();
+ const QChar* buf = _url.unicode();
+
+ uint pos = 0;
+
+ // Accept any amount of (alpha|digit|'+'|'-')
+ // '.' is not currently accepted, because current KURL may be confused.
+ // Proceed with :
+ while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
+ buf[pos] == '+' || buf[pos] == '-')) pos++;
+
+ // Note that m_strProtocol is already set here, so we just skip over the protocol.
+ if (pos < len && buf[pos] == ':' )
+ pos++;
+ else { // can't happen, the caller checked all this already
+ reset();
+ m_strProtocol = _url;
+ m_iUriMode = Invalid;
+ return;
+ }
+
+ if ( pos == len ) // can't happen, the caller checked this already
+ m_strPath = QString::null;
+ else
+ m_strPath = decode( QString( buf + pos, len - pos ), encoding_hint, true );
+
+ m_bIsMalformed = false;
+
+ return;
+}
+
+void KURL::parseMailto( const QString& _url, int encoding_hint )
+{
+ parseURL( _url, encoding_hint);
+ if ( m_bIsMalformed )
+ return;
+ QRegExp mailre("(.+@)(.+)");
+ if ( mailre.exactMatch( m_strPath ) )
+ {
+#ifndef KDE_QT_ONLY
+ QString host = KIDNA::toUnicode( mailre.cap( 2 ) );
+ if (host.isEmpty())
+ host = mailre.cap( 2 ).lower();
+#else
+ QString host = mailre.cap( 2 ).lower();
+#endif
+ m_strPath = mailre.cap( 1 ) + host;
+ }
+}
+
+void KURL::parseURL( const QString& _url, int encoding_hint )
+{
+ QString port;
+ bool badHostName = false;
+ int start = 0;
+ uint len = _url.length();
+ const QChar* buf = _url.unicode();
+
+ QChar delim;
+ QString tmp;
+
+ uint pos = 0;
+
+ // Node 1: Accept alpha or slash
+ QChar x = buf[pos++];
+#ifdef Q_WS_WIN
+ /* win32: accept <letter>: or <letter>:/ or <letter>:\ */
+ const bool alpha = isalpha((int)x);
+ if (alpha && len<2)
+ goto NodeErr;
+ if (alpha && buf[pos]==':' && (len==2 || (len>2 && (buf[pos+1]=='/' || buf[pos+1]=='\\'))))
+#else
+ if ( x == '/' )
+#endif
+ goto Node9;
+ if ( !isalpha( (int)x ) )
+ goto NodeErr;
+
+ // Node 2: Accept any amount of (alpha|digit|'+'|'-')
+ // '.' is not currently accepted, because current KURL may be confused.
+ // Proceed with :// :/ or :
+ while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
+ buf[pos] == '+' || buf[pos] == '-')) pos++;
+
+ // Note that m_strProtocol is already set here, so we just skip over the protocol.
+ if ( pos+2 < len && buf[pos] == ':' && buf[pos+1] == '/' && buf[pos+2] == '/' )
+ {
+ pos += 3;
+ }
+ else if (pos+1 < len && buf[pos] == ':' ) // Need to always compare length()-1 otherwise KURL passes "http:" as legal!!
+ {
+ pos++;
+ start = pos;
+ goto Node9;
+ }
+ else
+ goto NodeErr;
+
+ //Node 3: We need at least one character here
+ if ( pos == len )
+ goto NodeErr;
+ start = pos;
+
+ // Node 4: Accept any amount of characters.
+ if (buf[pos] == '[') // An IPv6 host follows.
+ goto Node8;
+ // Terminate on / or @ or ? or # or " or ; or <
+ x = buf[pos];
+ while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') )
+ {
+ if ((x == '\"') || (x == ';') || (x == '<'))
+ badHostName = true;
+ if (++pos == len)
+ break;
+ x = buf[pos];
+ }
+ if ( pos == len )
+ {
+ if (badHostName)
+ goto NodeErr;
+
+ setHost(decode(QString( buf + start, pos - start ), encoding_hint));
+ goto NodeOk;
+ }
+ if ( x == '@' )
+ {
+ m_strUser = decode(QString( buf + start, pos - start ), encoding_hint);
+ pos++;
+ goto Node7;
+ }
+ else if ( (x == '/') || (x == '?') || (x == '#'))
+ {
+ if (badHostName)
+ goto NodeErr;
+
+ setHost(decode(QString( buf + start, pos - start ), encoding_hint));
+ start = pos;
+ goto Node9;
+ }
+ else if ( x != ':' )
+ goto NodeErr;
+ m_strUser = decode(QString( buf + start, pos - start ), encoding_hint);
+ pos++;
+
+ // Node 5: We need at least one character
+ if ( pos == len )
+ goto NodeErr;
+ start = pos++;
+
+ // Node 6: Read everything until @, /, ? or #
+ while( (pos < len) &&
+ (buf[pos] != '@') &&
+ (buf[pos] != '/') &&
+ (buf[pos] != '?') &&
+ (buf[pos] != '#')) pos++;
+ // If we now have a '@' the ':' seperates user and password.
+ // Otherwise it seperates host and port.
+ if ( (pos == len) || (buf[pos] != '@') )
+ {
+ // Ok the : was used to separate host and port
+ if (badHostName)
+ goto NodeErr;
+ setHost(m_strUser);
+ m_strUser = QString::null;
+ QString tmp( buf + start, pos - start );
+ char *endptr;
+ m_iPort = (unsigned short int)strtol(tmp.ascii(), &endptr, 10);
+ if ((pos == len) && (strlen(endptr) == 0))
+ goto NodeOk;
+ // there is more after the digits
+ pos -= strlen(endptr);
+ if ((buf[pos] != '@') &&
+ (buf[pos] != '/') &&
+ (buf[pos] != '?') &&
+ (buf[pos] != '#'))
+ goto NodeErr;
+
+ start = pos;
+ goto Node9;
+ }
+ m_strPass = decode(QString( buf + start, pos - start), encoding_hint);
+ pos++;
+
+ // Node 7: We need at least one character
+ Node7:
+ if ( pos == len )
+ goto NodeErr;
+
+ Node8:
+ if (buf[pos] == '[')
+ {
+ // IPv6 address
+ start = ++pos; // Skip '['
+
+ if (pos == len)
+ {
+ badHostName = true;
+ goto NodeErr;
+ }
+ // Node 8a: Read everything until ] or terminate
+ badHostName = false;
+ x = buf[pos];
+ while( (x != ']') )
+ {
+ if ((x == '\"') || (x == ';') || (x == '<'))
+ badHostName = true;
+ if (++pos == len)
+ {
+ badHostName = true;
+ break;
+ }
+ x = buf[pos];
+ }
+ if (badHostName)
+ goto NodeErr;
+ setHost(decode(QString( buf + start, pos - start ), encoding_hint));
+ if (pos < len) pos++; // Skip ']'
+ if (pos == len)
+ goto NodeOk;
+ }
+ else
+ {
+ // Non IPv6 address, with a user
+ start = pos;
+
+ // Node 8b: Read everything until / : or terminate
+ badHostName = false;
+ x = buf[pos];
+ while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') )
+ {
+ if ((x == '\"') || (x == ';') || (x == '<'))
+ badHostName = true;
+ if (++pos == len)
+ break;
+ x = buf[pos];
+ }
+ if (badHostName)
+ goto NodeErr;
+ if ( pos == len )
+ {
+ setHost(decode(QString( buf + start, pos - start ), encoding_hint));
+ goto NodeOk;
+ }
+ setHost(decode(QString( buf + start, pos - start ), encoding_hint));
+ }
+ x = buf[pos];
+ if ( x == '/' || x == '#' || x == '?' )
+ {
+ start = pos;
+ goto Node9;
+ }
+ else if ( x != ':' )
+ goto NodeErr;
+ pos++;
+
+ // Node 8c: Accept at least one digit
+ if ( pos == len )
+ goto NodeErr;
+ start = pos;
+ if ( !isdigit( buf[pos++] ) )
+ goto NodeErr;
+
+ // Node 8d: Accept any amount of digits
+ while( pos < len && isdigit( buf[pos] ) ) pos++;
+ port = QString( buf + start, pos - start );
+ m_iPort = port.toUShort();
+ if ( pos == len )
+ goto NodeOk;
+ start = pos;
+
+ Node9: // parse path until query or reference reached
+
+ while( pos < len && buf[pos] != '#' && buf[pos]!='?' ) pos++;
+
+ tmp = QString( buf + start, pos - start );
+ //kdDebug(126)<<" setting encoded path to:"<<tmp<<endl;
+ setEncodedPath( tmp, encoding_hint );
+
+ if ( pos == len )
+ goto NodeOk;
+
+ //Node10: // parse query or reference depending on what comes first
+ delim = (buf[pos++]=='#'?'?':'#');
+
+ start = pos;
+
+ while(pos < len && buf[pos]!=delim ) pos++;
+
+ tmp = QString(buf + start, pos - start);
+ if (delim=='#')
+ _setQuery(tmp, encoding_hint);
+ else
+ m_strRef_encoded = tmp;
+
+ if (pos == len)
+ goto NodeOk;
+
+ //Node11: // feed the rest into the remaining variable
+ tmp = QString( buf + pos + 1, len - pos - 1);
+ if (delim == '#')
+ m_strRef_encoded = tmp;
+ else
+ _setQuery(tmp, encoding_hint);
+
+ NodeOk:
+ //kdDebug(126)<<"parsing finished. m_strProtocol="<<m_strProtocol<<" m_strHost="<<m_strHost<<" m_strPath="<<m_strPath<<endl;
+ m_bIsMalformed = false; // Valid URL
+
+ //kdDebug()<<"Prot="<<m_strProtocol<<"\nUser="<<m_strUser<<"\nPass="<<m_strPass<<"\nHost="<<m_strHost<<"\nPath="<<m_strPath<<"\nQuery="<<m_strQuery_encoded<<"\nRef="<<m_strRef_encoded<<"\nPort="<<m_iPort<<endl;
+ if (m_strProtocol.isEmpty())
+ {
+ m_iUriMode = URL;
+ m_strProtocol = fileProt;
+ }
+ return;
+
+ NodeErr:
+// kdDebug(126) << "KURL couldn't parse URL \"" << _url << "\"" << endl;
+ reset();
+ m_strProtocol = _url;
+ m_iUriMode = Invalid;
+}
+
+KURL& KURL::operator=( const QString& _url )
+{
+ reset();
+ parse( _url );
+
+ return *this;
+}
+
+KURL& KURL::operator=( const char * _url )
+{
+ reset();
+ parse( QString::fromLatin1(_url) );
+
+ return *this;
+}
+
+#ifndef QT_NO_NETWORKPROTOCOL
+KURL& KURL::operator=( const QUrl & u )
+{
+ m_strProtocol = u.protocol();
+ m_iUriMode = Auto;
+ m_strUser = u.user();
+ m_strPass = u.password();
+ m_strHost = u.host();
+ m_strPath = u.path( false );
+ m_strPath_encoded = QString::null;
+ m_strQuery_encoded = u.query();
+ m_strRef_encoded = u.ref();
+ m_bIsMalformed = !u.isValid();
+ m_iPort = u.port();
+
+ return *this;
+}
+#endif
+
+KURL& KURL::operator=( const KURL& _u )
+{
+ m_strProtocol = _u.m_strProtocol;
+ m_strUser = _u.m_strUser;
+ m_strPass = _u.m_strPass;
+ m_strHost = _u.m_strHost;
+ m_strPath = _u.m_strPath;
+ m_strPath_encoded = _u.m_strPath_encoded;
+ m_strQuery_encoded = _u.m_strQuery_encoded;
+ m_strRef_encoded = _u.m_strRef_encoded;
+ m_bIsMalformed = _u.m_bIsMalformed;
+ m_iPort = _u.m_iPort;
+ m_iUriMode = _u.m_iUriMode;
+
+ return *this;
+}
+
+bool KURL::operator<( const KURL& _u) const
+{
+ int i;
+ if (!_u.isValid())
+ {
+ if (!isValid())
+ {
+ i = m_strProtocol.compare(_u.m_strProtocol);
+ return (i < 0);
+ }
+ return false;
+ }
+ if (!isValid())
+ return true;
+
+ i = m_strProtocol.compare(_u.m_strProtocol);
+ if (i) return (i < 0);
+
+ i = m_strHost.compare(_u.m_strHost);
+ if (i) return (i < 0);
+
+ if (m_iPort != _u.m_iPort) return (m_iPort < _u.m_iPort);
+
+ i = m_strPath.compare(_u.m_strPath);
+ if (i) return (i < 0);
+
+ i = m_strQuery_encoded.compare(_u.m_strQuery_encoded);
+ if (i) return (i < 0);
+
+ i = m_strRef_encoded.compare(_u.m_strRef_encoded);
+ if (i) return (i < 0);
+
+ i = m_strUser.compare(_u.m_strUser);
+ if (i) return (i < 0);
+
+ i = m_strPass.compare(_u.m_strPass);
+ if (i) return (i < 0);
+
+ return false;
+}
+
+bool KURL::operator==( const KURL& _u ) const
+{
+ if ( !isValid() || !_u.isValid() )
+ return false;
+
+ if ( m_strProtocol == _u.m_strProtocol &&
+ m_strUser == _u.m_strUser &&
+ m_strPass == _u.m_strPass &&
+ m_strHost == _u.m_strHost &&
+ m_strPath == _u.m_strPath &&
+ // The encoded path may be null, but the URLs are still equal (David)
+ ( m_strPath_encoded.isNull() || _u.m_strPath_encoded.isNull() ||
+ m_strPath_encoded == _u.m_strPath_encoded ) &&
+ m_strQuery_encoded == _u.m_strQuery_encoded &&
+ m_strRef_encoded == _u.m_strRef_encoded &&
+ m_iPort == _u.m_iPort )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool KURL::operator==( const QString& _u ) const
+{
+ KURL u( _u );
+ return ( *this == u );
+}
+
+bool KURL::cmp( const KURL &u, bool ignore_trailing ) const
+{
+ return equals( u, ignore_trailing );
+}
+
+bool KURL::equals( const KURL &_u, bool ignore_trailing ) const
+{
+ if ( !isValid() || !_u.isValid() )
+ return false;
+
+ if ( ignore_trailing )
+ {
+ QString path1 = path(1);
+ QString path2 = _u.path(1);
+ if ( path1 != path2 )
+ return false;
+
+ if ( m_strProtocol == _u.m_strProtocol &&
+ m_strUser == _u.m_strUser &&
+ m_strPass == _u.m_strPass &&
+ m_strHost == _u.m_strHost &&
+ m_strQuery_encoded == _u.m_strQuery_encoded &&
+ m_strRef_encoded == _u.m_strRef_encoded &&
+ m_iPort == _u.m_iPort )
+ return true;
+
+ return false;
+ }
+
+ return ( *this == _u );
+}
+
+bool KURL::isParentOf( const KURL& _u ) const
+{
+ if ( !isValid() || !_u.isValid() )
+ return false;
+
+ if ( m_strProtocol == _u.m_strProtocol &&
+ m_strUser == _u.m_strUser &&
+ m_strPass == _u.m_strPass &&
+ m_strHost == _u.m_strHost &&
+ m_strQuery_encoded == _u.m_strQuery_encoded &&
+ m_strRef_encoded == _u.m_strRef_encoded &&
+ m_iPort == _u.m_iPort )
+ {
+ if ( path().isEmpty() || _u.path().isEmpty() )
+ return false; // can't work with implicit paths
+
+ QString p1( cleanpath( path(), true, false ) );
+ if ( p1[p1.length()-1] != '/' )
+ p1 += '/';
+ QString p2( cleanpath( _u.path(), true, false ) );
+ if ( p2[p2.length()-1] != '/' )
+ p2 += '/';
+
+ //kdDebug(126) << "p1=" << p1 << endl;
+ //kdDebug(126) << "p2=" << p2 << endl;
+ //kdDebug(126) << "p1.length()=" << p1.length() << endl;
+ //kdDebug(126) << "p2.left(!$)=" << p2.left( p1.length() ) << endl;
+ return p2.startsWith( p1 );
+ }
+ return false;
+}
+
+void KURL::setFileName( const QString& _txt )
+{
+ m_strRef_encoded = QString::null;
+ int i = 0;
+ while( _txt[i] == '/' ) ++i;
+ QString tmp;
+ if ( i )
+ tmp = _txt.mid( i );
+ else
+ tmp = _txt;
+
+ QString path = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded;
+ if ( path.isEmpty() )
+ path = "/";
+ else
+ {
+ int lastSlash = path.findRev( '/' );
+ if ( lastSlash == -1)
+ {
+ // The first character is not a '/' ???
+ // This looks strange ...
+ path = "/";
+ }
+ else if ( path.right(1) != "/" )
+ path.truncate( lastSlash+1 ); // keep the "/"
+ }
+ if (m_strPath_encoded.isEmpty())
+ {
+ path += tmp;
+ setPath( path );
+ }
+ else
+ {
+ path += encode_string(tmp);
+ setEncodedPath( path );
+ }
+ cleanPath();
+}
+
+void KURL::cleanPath( bool cleanDirSeparator ) // taken from the old KURL
+{
+ if (m_iUriMode != URL) return;
+ m_strPath = cleanpath(m_strPath, cleanDirSeparator, false);
+ // WABA: Is this safe when "/../" is encoded with %?
+ m_strPath_encoded = cleanpath(m_strPath_encoded, cleanDirSeparator, true);
+}
+
+static QString trailingSlash( int _trailing, const QString &path )
+{
+ QString result = path;
+
+ if ( _trailing == 0 )
+ return result;
+ else if ( _trailing == 1 )
+ {
+ int len = result.length();
+ if ( (len == 0) || (result[ len - 1 ] != '/') )
+ result += "/";
+ return result;
+ }
+ else if ( _trailing == -1 )
+ {
+ if ( result == "/" )
+ return result;
+ int len = result.length();
+ while (len > 1 && result[ len - 1 ] == '/')
+ {
+ len--;
+ }
+ result.truncate( len );
+ return result;
+ }
+ else {
+ assert( 0 );
+ return QString::null;
+ }
+}
+
+void KURL::adjustPath( int _trailing )
+{
+ if (!m_strPath_encoded.isEmpty())
+ {
+ m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded );
+ }
+ m_strPath = trailingSlash( _trailing, m_strPath );
+}
+
+
+QString KURL::encodedPathAndQuery( int _trailing, bool _no_empty_path, int encoding_hint ) const
+{
+ QString tmp;
+ if (!m_strPath_encoded.isEmpty() && encoding_hint == 0)
+ {
+ tmp = trailingSlash( _trailing, m_strPath_encoded );
+ }
+ else
+ {
+ tmp = path( _trailing );
+ if ( _no_empty_path && tmp.isEmpty() )
+ tmp = "/";
+ if (m_iUriMode == Mailto)
+ {
+ tmp = encode( tmp, 2, encoding_hint );
+ }
+ else
+ {
+ tmp = encode( tmp, 1, encoding_hint );
+ }
+ }
+
+ // TODO apply encoding_hint to the query
+ if (!m_strQuery_encoded.isNull())
+ tmp += '?' + m_strQuery_encoded;
+ return tmp;
+}
+
+void KURL::setEncodedPath( const QString& _txt, int encoding_hint )
+{
+ m_strPath_encoded = _txt;
+
+ decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint );
+ // Throw away encoding for local files, makes file-operations faster.
+ if (m_strProtocol == fileProt)
+ m_strPath_encoded = QString::null;
+
+ if ( m_iUriMode == Auto )
+ m_iUriMode = URL;
+}
+
+
+void KURL::setEncodedPathAndQuery( const QString& _txt, int encoding_hint )
+{
+ int pos = _txt.find( '?' );
+ if ( pos == -1 )
+ {
+ setEncodedPath(_txt, encoding_hint);
+ m_strQuery_encoded = QString::null;
+ }
+ else
+ {
+ setEncodedPath(_txt.left( pos ), encoding_hint);
+ _setQuery(_txt.right(_txt.length() - pos - 1), encoding_hint);
+ }
+}
+
+QString KURL::path( int _trailing ) const
+{
+ return trailingSlash( _trailing, path() );
+}
+
+bool KURL::isLocalFile() const
+{
+ if ( (m_strProtocol != fileProt ) || hasSubURL() )
+ return false;
+
+ if (m_strHost.isEmpty() || (m_strHost == "localhost"))
+ return true;
+
+ char hostname[ 256 ];
+ hostname[ 0 ] = '\0';
+ if (!gethostname( hostname, 255 ))
+ hostname[sizeof(hostname)-1] = '\0';
+
+ for(char *p = hostname; *p; p++)
+ *p = tolower(*p);
+
+ return (m_strHost == hostname);
+}
+
+void KURL::setFileEncoding(const QString &encoding)
+{
+ if (!isLocalFile())
+ return;
+
+ QString q = query();
+
+ if (!q.isEmpty() && (q[0] == '?'))
+ q = q.mid(1);
+
+ QStringList args = QStringList::split('&', q);
+ for(QStringList::Iterator it = args.begin();
+ it != args.end();)
+ {
+ QString s = decode_string(*it);
+ if (s.startsWith("charset="))
+ it = args.erase(it);
+ else
+ ++it;
+ }
+ if (!encoding.isEmpty())
+ args.append("charset="+encode_string(encoding));
+
+ if (args.isEmpty())
+ _setQuery(QString::null);
+ else
+ _setQuery(args.join("&"));
+}
+
+QString KURL::fileEncoding() const
+{
+ if (!isLocalFile())
+ return QString::null;
+
+ QString q = query();
+
+ if (q.isEmpty())
+ return QString::null;
+
+ if (q[0] == '?')
+ q = q.mid(1);
+
+ QStringList args = QStringList::split('&', q);
+ for(QStringList::ConstIterator it = args.begin();
+ it != args.end();
+ ++it)
+ {
+ QString s = decode_string(*it);
+ if (s.startsWith("charset="))
+ return s.mid(8);
+ }
+ return QString::null;
+}
+
+bool KURL::hasSubURL() const
+{
+ if ( m_strProtocol.isEmpty() || m_bIsMalformed )
+ return false;
+ if (m_strRef_encoded.isEmpty())
+ return false;
+ if (m_strRef_encoded.startsWith("gzip:"))
+ return true;
+ if (m_strRef_encoded.startsWith("bzip:"))
+ return true;
+ if (m_strRef_encoded.startsWith("bzip2:"))
+ return true;
+ if (m_strRef_encoded.startsWith("tar:"))
+ return true;
+ if (m_strRef_encoded.startsWith("ar:"))
+ return true;
+ if (m_strRef_encoded.startsWith("zip:"))
+ return true;
+ if ( m_strProtocol == "error" ) // anything that starts with error: has suburls
+ return true;
+ return false;
+}
+
+QString KURL::url( int _trailing, int encoding_hint ) const
+{
+ if( m_bIsMalformed )
+ {
+ // Return the whole url even when the url is
+ // malformed. Under such conditions the url
+ // is stored in m_strProtocol.
+ return m_strProtocol;
+ }
+
+ QString u = m_strProtocol;
+ if (!u.isEmpty())
+ u += ":";
+
+ if ( hasHost() || (m_strProtocol == fileProt) )
+ {
+ u += "//";
+ if ( hasUser() )
+ {
+ u += encode(m_strUser, 0, encoding_hint);
+ if ( hasPass() )
+ {
+ u += ":";
+ u += encode(m_strPass, 0, encoding_hint);
+ }
+ u += "@";
+ }
+ if ( m_iUriMode == URL )
+ {
+ bool IPv6 = (m_strHost.find(':') != -1);
+ if (IPv6)
+ u += '[' + m_strHost + ']';
+ else
+ u += encodeHost(m_strHost, true, encoding_hint);
+ if ( m_iPort != 0 ) {
+ QString buffer;
+ buffer.sprintf( ":%u", m_iPort );
+ u += buffer;
+ }
+ }
+ else
+ {
+ u += m_strHost;
+ }
+ }
+
+ if ( m_iUriMode == URL || m_iUriMode == Mailto )
+ u += encodedPathAndQuery( _trailing, false, encoding_hint );
+ else
+ u += encode( m_strPath, 21, encoding_hint, true );
+
+ if ( hasRef() )
+ {
+ u += "#";
+ u += m_strRef_encoded;
+ }
+
+ return u;
+}
+
+QString KURL::prettyURL( int _trailing ) const
+{
+ if( m_bIsMalformed )
+ {
+ // Return the whole url even when the url is
+ // malformed. Under such conditions the url
+ // is stored in m_strProtocol.
+ return m_strProtocol;
+ }
+
+ QString u = m_strProtocol;
+ if (!u.isEmpty())
+ u += ":";
+
+ if ( hasHost() || (m_strProtocol == fileProt) )
+ {
+ u += "//";
+ if ( hasUser() )
+ {
+ u += encode(m_strUser, 0, 0);
+ // Don't show password!
+ u += "@";
+ }
+ if ( m_iUriMode == URL )
+ {
+ bool IPv6 = (m_strHost.find(':') != -1);
+ if (IPv6)
+ {
+ u += '[' + m_strHost + ']';
+ }
+ else
+ {
+ u += lazy_encode(m_strHost);
+ }
+ }
+ else
+ {
+ u += lazy_encode(m_strHost);
+ }
+ if ( m_iPort != 0 ) {
+ QString buffer;
+ buffer.sprintf( ":%u", m_iPort );
+ u += buffer;
+ }
+ }
+
+ if (m_iUriMode == Mailto)
+ {
+ u += lazy_encode( m_strPath, false );
+ }
+ else
+ {
+ u += trailingSlash( _trailing, lazy_encode( m_strPath ) );
+ }
+
+ if (!m_strQuery_encoded.isNull())
+ u += '?' + m_strQuery_encoded;
+
+ if ( hasRef() )
+ {
+ u += "#";
+ u += m_strRef_encoded;
+ }
+
+ return u;
+}
+
+QString KURL::prettyURL( int _trailing, AdjustementFlags _flags) const
+{
+ QString u = prettyURL(_trailing);
+ if (_flags & StripFileProtocol && u.startsWith("file://")) {
+ u.remove(0, 7);
+#ifdef Q_WS_WIN
+ return QDir::convertSeparators(u);
+#endif
+ }
+ return u;
+}
+
+QString KURL::pathOrURL() const
+{
+ if ( isLocalFile() && m_strRef_encoded.isNull() && m_strQuery_encoded.isNull() ) {
+ return path();
+ } else {
+ return prettyURL();
+ }
+}
+
+QString KURL::htmlURL() const
+{
+ return QStyleSheet::escape(prettyURL());
+}
+
+KURL::List KURL::split( const KURL& _url )
+{
+ QString ref;
+ KURL::List lst;
+ KURL url = _url;
+
+ while(true)
+ {
+ KURL u = url;
+ u.m_strRef_encoded = QString::null;
+ lst.append(u);
+ if (url.hasSubURL())
+ {
+ url = KURL(url.m_strRef_encoded);
+ }
+ else
+ {
+ ref = url.m_strRef_encoded;
+ break;
+ }
+ }
+
+ // Set HTML ref in all URLs.
+ KURL::List::Iterator it;
+ for( it = lst.begin() ; it != lst.end(); ++it )
+ {
+ (*it).m_strRef_encoded = ref;
+ }
+
+ return lst;
+}
+
+KURL::List KURL::split( const QString& _url )
+{
+ return split(KURL(_url));
+}
+
+KURL KURL::join( const KURL::List & lst )
+{
+ if (lst.isEmpty()) return KURL();
+ KURL tmp;
+
+ KURL::List::ConstIterator first = lst.fromLast();
+ for( KURL::List::ConstIterator it = first; it != lst.end(); --it )
+ {
+ KURL u(*it);
+ if (it != first)
+ {
+ if (!u.m_strRef_encoded) u.m_strRef_encoded = tmp.url();
+ else u.m_strRef_encoded += "#" + tmp.url(); // Support more than one suburl thingy
+ }
+ tmp = u;
+ }
+
+ return tmp;
+}
+
+QString KURL::fileName( bool _strip_trailing_slash ) const
+{
+ QString fname;
+ if (hasSubURL()) { // If we have a suburl, then return the filename from there
+ KURL::List list = KURL::split(*this);
+ KURL::List::Iterator it = list.fromLast();
+ return (*it).fileName(_strip_trailing_slash);
+ }
+ const QString &path = m_strPath;
+
+ int len = path.length();
+ if ( len == 0 )
+ return fname;
+
+ if ( _strip_trailing_slash )
+ {
+ while ( len >= 1 && path[ len - 1 ] == '/' )
+ len--;
+ }
+ else if ( path[ len - 1 ] == '/' )
+ return fname;
+
+ // Does the path only consist of '/' characters ?
+ if ( len == 1 && path[ 0 ] == '/' )
+ return fname;
+
+ // Skip last n slashes
+ int n = 1;
+ if (!m_strPath_encoded.isEmpty())
+ {
+ // This is hairy, we need the last unencoded slash.
+ // Count in the encoded string how many encoded slashes follow the last
+ // unencoded one.
+ int i = m_strPath_encoded.findRev( '/', len - 1 );
+ QString fileName_encoded = m_strPath_encoded.mid(i+1);
+ n += fileName_encoded.contains("%2f", false);
+ }
+ int i = len;
+ do {
+ i = path.findRev( '/', i - 1 );
+ }
+ while (--n && (i > 0));
+
+ // If ( i == -1 ) => the first character is not a '/'
+ // So it's some URL like file:blah.tgz, return the whole path
+ if ( i == -1 ) {
+ if ( len == (int)path.length() )
+ fname = path;
+ else
+ // Might get here if _strip_trailing_slash is true
+ fname = path.left( len );
+ }
+ else
+ {
+ fname = path.mid( i + 1, len - i - 1 ); // TO CHECK
+ }
+ return fname;
+}
+
+void KURL::addPath( const QString& _txt )
+{
+ if (hasSubURL())
+ {
+ KURL::List lst = split( *this );
+ KURL &u = lst.last();
+ u.addPath(_txt);
+ *this = join( lst );
+ return;
+ }
+
+ m_strPath_encoded = QString::null;
+
+ if ( _txt.isEmpty() )
+ return;
+
+ int i = 0;
+ int len = m_strPath.length();
+ // Add the trailing '/' if it is missing
+ if ( _txt[0] != '/' && ( len == 0 || m_strPath[ len - 1 ] != '/' ) )
+ m_strPath += "/";
+
+ // No double '/' characters
+ i = 0;
+ if ( len != 0 && m_strPath[ len - 1 ] == '/' )
+ {
+ while( _txt[i] == '/' )
+ ++i;
+ }
+
+ m_strPath += _txt.mid( i );
+}
+
+QString KURL::directory( bool _strip_trailing_slash_from_result,
+ bool _ignore_trailing_slash_in_path ) const
+{
+ QString result = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded;
+ if ( _ignore_trailing_slash_in_path )
+ result = trailingSlash( -1, result );
+
+ if ( result.isEmpty() || result == "/" )
+ return result;
+
+ int i = result.findRev( "/" );
+ // If ( i == -1 ) => the first character is not a '/'
+ // So it's some URL like file:blah.tgz, with no path
+ if ( i == -1 )
+ return QString::null;
+
+ if ( i == 0 )
+ {
+ result = "/";
+ return result;
+ }
+
+ if ( _strip_trailing_slash_from_result )
+ result = result.left( i );
+ else
+ result = result.left( i + 1 );
+
+ if (!m_strPath_encoded.isEmpty())
+ result = decode(result);
+
+ return result;
+}
+
+
+bool KURL::cd( const QString& _dir )
+{
+ if ( _dir.isEmpty() || m_bIsMalformed )
+ return false;
+
+ if (hasSubURL())
+ {
+ KURL::List lst = split( *this );
+ KURL &u = lst.last();
+ u.cd(_dir);
+ *this = join( lst );
+ return true;
+ }
+
+ // absolute path ?
+ if ( _dir[0] == '/' )
+ {
+ m_strPath_encoded = QString::null;
+ m_strPath = _dir;
+ setHTMLRef( QString::null );
+ m_strQuery_encoded = QString::null;
+ return true;
+ }
+
+ // Users home directory on the local disk ?
+ if ( ( _dir[0] == '~' ) && ( m_strProtocol == fileProt ))
+ {
+ m_strPath_encoded = QString::null;
+ m_strPath = QDir::homeDirPath();
+ m_strPath += "/";
+ m_strPath += _dir.right(m_strPath.length() - 1);
+ setHTMLRef( QString::null );
+ m_strQuery_encoded = QString::null;
+ return true;
+ }
+
+ // relative path
+ // we always work on the past of the first url.
+ // Sub URLs are not touched.
+
+ // append '/' if necessary
+ QString p = path(1);
+ p += _dir;
+ p = cleanpath( p, true, false );
+ setPath( p );
+
+ setHTMLRef( QString::null );
+ m_strQuery_encoded = QString::null;
+
+ return true;
+}
+
+KURL KURL::upURL( ) const
+{
+ if (!query().isEmpty())
+ {
+ KURL u(*this);
+ u._setQuery(QString::null);
+ return u;
+ };
+
+ if (!hasSubURL())
+ {
+ KURL u(*this);
+
+ u.cd("../");
+
+ return u;
+ }
+
+ // We have a subURL.
+ KURL::List lst = split( *this );
+ if (lst.isEmpty())
+ return KURL(); // Huh?
+ while (true)
+ {
+ KURL &u = lst.last();
+ QString old = u.path();
+ u.cd("../");
+ if (u.path() != old)
+ break; // Finshed.
+ if (lst.count() == 1)
+ break; // Finished.
+ lst.remove(lst.fromLast());
+ }
+ return join( lst );
+}
+
+QString KURL::htmlRef() const
+{
+ if ( !hasSubURL() )
+ {
+ return decode( ref() );
+ }
+
+ List lst = split( *this );
+ return decode( (*lst.begin()).ref() );
+}
+
+QString KURL::encodedHtmlRef() const
+{
+ if ( !hasSubURL() )
+ {
+ return ref();
+ }
+
+ List lst = split( *this );
+ return (*lst.begin()).ref();
+}
+
+void KURL::setHTMLRef( const QString& _ref )
+{
+ if ( !hasSubURL() )
+ {
+ m_strRef_encoded = encode( _ref, 0, 0 /*?*/);
+ return;
+ }
+
+ List lst = split( *this );
+
+ (*lst.begin()).setRef( encode( _ref, 0, 0 /*?*/) );
+
+ *this = join( lst );
+}
+
+bool KURL::hasHTMLRef() const
+{
+ if ( !hasSubURL() )
+ {
+ return hasRef();
+ }
+
+ List lst = split( *this );
+ return (*lst.begin()).hasRef();
+}
+
+void
+KURL::setProtocol( const QString& _txt )
+{
+ m_strProtocol = _txt;
+ if ( m_iUriMode == Auto ) m_iUriMode = uriModeForProtocol( m_strProtocol );
+ m_bIsMalformed = false;
+}
+
+void
+KURL::setUser( const QString& _txt )
+{
+ if ( _txt.isEmpty() )
+ m_strUser = QString::null;
+ else
+ m_strUser = _txt;
+}
+
+void
+KURL::setPass( const QString& _txt )
+{
+ if ( _txt.isEmpty() )
+ m_strPass = QString::null;
+ else
+ m_strPass = _txt;
+}
+
+void
+KURL::setHost( const QString& _txt )
+{
+ if ( m_iUriMode == Auto )
+ m_iUriMode = URL;
+ switch ( m_iUriMode )
+ {
+ case URL:
+#ifndef KDE_QT_ONLY
+ m_strHost = KIDNA::toUnicode(_txt);
+ if (m_strHost.isEmpty())
+ m_strHost = _txt.lower(); // Probably an invalid hostname, but...
+#else
+ m_strHost = _txt.lower();
+#endif
+ break;
+ default:
+ m_strHost = _txt;
+ break;
+ }
+}
+
+void
+KURL::setPort( unsigned short int _p )
+{
+ m_iPort = _p;
+}
+
+void KURL::setPath( const QString & path )
+{
+ if (isEmpty())
+ m_bIsMalformed = false;
+ if (m_strProtocol.isEmpty())
+ {
+ m_strProtocol = fileProt;
+ }
+ m_strPath = path;
+ m_strPath_encoded = QString::null;
+ if ( m_iUriMode == Auto )
+ m_iUriMode = URL;
+}
+
+void KURL::setDirectory( const QString &dir)
+{
+ if ( dir.endsWith("/"))
+ setPath(dir);
+ else
+ setPath(dir+"/");
+}
+
+void KURL::setQuery( const QString &_txt, int encoding_hint)
+{
+ if (_txt[0] == '?')
+ _setQuery( _txt.length() > 1 ? _txt.mid(1) : "" /*empty, not null*/, encoding_hint );
+ else
+ _setQuery( _txt, encoding_hint );
+}
+
+// This is a private function that expects a query without '?'
+void KURL::_setQuery( const QString &_txt, int encoding_hint)
+{
+ m_strQuery_encoded = _txt;
+ if (!_txt.length())
+ return;
+
+ int l = m_strQuery_encoded.length();
+ int i = 0;
+ QString result;
+ while (i < l)
+ {
+ int s = i;
+ // Re-encode. Break encoded string up according to the reserved
+ // characters '&:;=/?' and re-encode part by part.
+ while(i < l)
+ {
+ char c = m_strQuery_encoded[i].latin1();
+ if ((c == '&') || (c == ':') || (c == ';') ||
+ (c == '=') || (c == '/') || (c == '?'))
+ break;
+ i++;
+ }
+ if (i > s)
+ {
+ QString tmp = m_strQuery_encoded.mid(s, i-s);
+ QString newTmp;
+ decode( tmp, newTmp, tmp, encoding_hint, false );
+ result += tmp;
+ }
+ if (i < l)
+ {
+ result += m_strQuery_encoded[i];
+ i++;
+ }
+ }
+ m_strQuery_encoded = result;
+}
+
+QString KURL::query() const
+{
+ if (m_strQuery_encoded.isNull())
+ return QString::null;
+ return '?'+m_strQuery_encoded;
+}
+
+QString KURL::decode_string(const QString &str, int encoding_hint)
+{
+ return decode(str, encoding_hint);
+}
+
+QString KURL::encode_string(const QString &str, int encoding_hint)
+{
+ return encode(str, 1, encoding_hint);
+}
+
+QString KURL::encode_string_no_slash(const QString &str, int encoding_hint)
+{
+ return encode(str, 0, encoding_hint);
+}
+
+bool urlcmp( const QString& _url1, const QString& _url2 )
+{
+ // Both empty ?
+ if ( _url1.isEmpty() && _url2.isEmpty() )
+ return true;
+ // Only one empty ?
+ if ( _url1.isEmpty() || _url2.isEmpty() )
+ return false;
+
+ KURL::List list1 = KURL::split( _url1 );
+ KURL::List list2 = KURL::split( _url2 );
+
+ // Malformed ?
+ if ( list1.isEmpty() || list2.isEmpty() )
+ return false;
+
+ return ( list1 == list2 );
+}
+
+bool urlcmp( const QString& _url1, const QString& _url2, bool _ignore_trailing, bool _ignore_ref )
+{
+ // Both empty ?
+ if ( _url1.isEmpty() && _url2.isEmpty() )
+ return true;
+ // Only one empty ?
+ if ( _url1.isEmpty() || _url2.isEmpty() )
+ return false;
+
+ KURL::List list1 = KURL::split( _url1 );
+ KURL::List list2 = KURL::split( _url2 );
+
+ // Malformed ?
+ if ( list1.isEmpty() || list2.isEmpty() )
+ return false;
+
+ unsigned int size = list1.count();
+ if ( list2.count() != size )
+ return false;
+
+ if ( _ignore_ref )
+ {
+ (*list1.begin()).setRef(QString::null);
+ (*list2.begin()).setRef(QString::null);
+ }
+
+ KURL::List::Iterator it1 = list1.begin();
+ KURL::List::Iterator it2 = list2.begin();
+ for( ; it1 != list1.end() ; ++it1, ++it2 )
+ if ( !(*it1).equals( *it2, _ignore_trailing ) )
+ return false;
+
+ return true;
+}
+
+QMap< QString, QString > KURL::queryItems( int options ) const {
+ return queryItems(options, 0);
+}
+
+QMap< QString, QString > KURL::queryItems( int options, int encoding_hint ) const {
+ if ( m_strQuery_encoded.isEmpty() )
+ return QMap<QString,QString>();
+
+ QMap< QString, QString > result;
+ QStringList items = QStringList::split( '&', m_strQuery_encoded );
+ for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
+ int equal_pos = (*it).find( '=' );
+ if ( equal_pos > 0 ) { // = is not the first char...
+ QString name = (*it).left( equal_pos );
+ if ( options & CaseInsensitiveKeys )
+ name = name.lower();
+ QString value = (*it).mid( equal_pos + 1 );
+ if ( value.isEmpty() )
+ result.insert( name, QString::fromLatin1("") );
+ else {
+ // ### why is decoding name not necessary?
+ value.replace( '+', ' ' ); // + in queries means space
+ result.insert( name, decode_string( value, encoding_hint ) );
+ }
+ } else if ( equal_pos < 0 ) { // no =
+ QString name = (*it);
+ if ( options & CaseInsensitiveKeys )
+ name = name.lower();
+ result.insert( name, QString::null );
+ }
+ }
+
+ return result;
+}
+
+QString KURL::queryItem( const QString& _item ) const
+{
+ return queryItem( _item, 0 );
+}
+
+QString KURL::queryItem( const QString& _item, int encoding_hint ) const
+{
+ QString item = _item + '=';
+ if ( m_strQuery_encoded.length() <= 1 )
+ return QString::null;
+
+ QStringList items = QStringList::split( '&', m_strQuery_encoded );
+ unsigned int _len = item.length();
+ for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it )
+ {
+ if ( (*it).startsWith( item ) )
+ {
+ if ( (*it).length() > _len )
+ {
+ QString str = (*it).mid( _len );
+ str.replace( '+', ' ' ); // + in queries means space.
+ return decode_string( str, encoding_hint );
+ }
+ else // empty value
+ return QString::fromLatin1("");
+ }
+ }
+
+ return QString::null;
+}
+
+void KURL::removeQueryItem( const QString& _item )
+{
+ QString item = _item + '=';
+ if ( m_strQuery_encoded.length() <= 1 )
+ return;
+
+ QStringList items = QStringList::split( '&', m_strQuery_encoded );
+ for ( QStringList::Iterator it = items.begin(); it != items.end(); )
+ {
+ if ( (*it).startsWith( item ) || (*it == _item) )
+ {
+ QStringList::Iterator deleteIt = it;
+ ++it;
+ items.remove(deleteIt);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ m_strQuery_encoded = items.join( "&" );
+}
+
+void KURL::addQueryItem( const QString& _item, const QString& _value, int encoding_hint )
+{
+ QString item = _item + '=';
+ QString value = encode( _value, 0, encoding_hint );
+
+ if (!m_strQuery_encoded.isEmpty())
+ m_strQuery_encoded += '&';
+ m_strQuery_encoded += item + value;
+}
+
+// static
+KURL KURL::fromPathOrURL( const QString& text )
+{
+ if ( text.isEmpty() )
+ return KURL();
+
+ KURL url;
+ if (!QDir::isRelativePath(text))
+ url.setPath( text );
+ else
+ url = text;
+
+ return url;
+}
+
+static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent)
+{
+ QString _base_dir(QDir::cleanDirPath(base_dir));
+ QString _path(QDir::cleanDirPath(path.isEmpty() || (path[0] != '/') ? _base_dir+"/"+path : path));
+
+ if (_base_dir.isEmpty())
+ return _path;
+
+ if (_base_dir[_base_dir.length()-1] != '/')
+ _base_dir.append('/');
+
+ QStringList list1 = QStringList::split('/', _base_dir);
+ QStringList list2 = QStringList::split('/', _path);
+
+ // Find where they meet
+ uint level = 0;
+ uint maxLevel = QMIN(list1.count(), list2.count());
+ while((level < maxLevel) && (list1[level] == list2[level])) level++;
+
+ QString result;
+ // Need to go down out of the first path to the common branch.
+ for(uint i = level; i < list1.count(); i++)
+ result.append("../");
+
+ // Now up up from the common branch to the second path.
+ for(uint i = level; i < list2.count(); i++)
+ result.append(list2[i]).append("/");
+
+ if ((level < list2.count()) && (path[path.length()-1] != '/'))
+ result.truncate(result.length()-1);
+
+ isParent = (level == list1.count());
+
+ return result;
+}
+
+QString KURL::relativePath(const QString &base_dir, const QString &path, bool *isParent)
+{
+ bool parent = false;
+ QString result = _relativePath(base_dir, path, parent);
+ if (parent)
+ result.prepend("./");
+
+ if (isParent)
+ *isParent = parent;
+
+ return result;
+}
+
+
+QString KURL::relativeURL(const KURL &base_url, const KURL &url, int encoding_hint)
+{
+ if ((url.protocol() != base_url.protocol()) ||
+ (url.host() != base_url.host()) ||
+ (url.port() && url.port() != base_url.port()) ||
+ (url.hasUser() && url.user() != base_url.user()) ||
+ (url.hasPass() && url.pass() != base_url.pass()))
+ {
+ return url.url(0, encoding_hint);
+ }
+
+ QString relURL;
+
+ if ((base_url.path() != url.path()) || (base_url.query() != url.query()))
+ {
+ bool dummy;
+ QString basePath = base_url.directory(false, false);
+ relURL = encode( _relativePath(basePath, url.path(), dummy), 1, encoding_hint);
+ relURL += url.query();
+ }
+
+ if ( url.hasRef() )
+ {
+ relURL += "#";
+ relURL += url.ref();
+ }
+
+ if ( relURL.isEmpty() )
+ return "./";
+
+ return relURL;
+}
+
+int KURL::uriMode() const
+{
+ return m_iUriMode;
+}
+
+KURL::URIMode KURL::uriModeForProtocol(const QString& protocol)
+{
+#ifndef KDE_QT_ONLY
+ KURL::URIMode mode = Auto;
+ if (protocol == fileProt)
+ return URL;
+ if (KGlobal::_instance)
+ mode = KProtocolInfo::uriParseMode(protocol);
+ if (mode == Auto ) {
+#else
+ KURL::URIMode mode = Auto;
+#endif
+ if ( protocol == "ed2k" || protocol == "sig2dat" || protocol == "slsk" || protocol == "data" ) mode = RawURI;
+ else if ( protocol == "mailto" ) mode = Mailto;
+ else mode = URL;
+#ifndef KDE_QT_ONLY
+ }
+#endif
+ return mode;
+}
diff --git a/kdecore/kurl.h b/kdecore/kurl.h
new file mode 100644
index 000000000..d637d620c
--- /dev/null
+++ b/kdecore/kurl.h
@@ -0,0 +1,1828 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Torben Weis <weis@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef __kurl_h__
+#define __kurl_h__
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include "kdelibs_export.h"
+
+class QUrl;
+class QStringList;
+template <typename K, typename V> class QMap;
+
+class KURLPrivate;
+
+// Defines that file-urls look like file:///path/file instead of file:/path/file
+#define KURL_TRIPLE_SLASH_FILE_PROT
+
+/**
+ * @brief Represents and parses a URL
+ *
+ * A prototypical URL looks like:
+ * @code
+ * protocol://user:password@hostname:port/path/to/file.ext#reference
+ * @endcode
+ *
+ * KURL handles escaping of URLs. This means that the specification
+ * of a full URL will differ from the corresponding string that would specify a
+ * local file or directory in file-operations like fopen. This is because an URL
+ * doesn't allow certain characters and escapes them.
+ *
+ * For examle:
+ * - '#' -> "%23"
+ * (In a URL the hash-character @c '#' is used to specify a "reference", i.e.
+ * the position within a document)
+ * - space -> "%20"
+ *
+ * The constructor KURL(const QString&) expects a string properly escaped,
+ * or at least non-ambiguous.
+ * For instance a local file or directory <tt>"/bar/#foo#"</tt> would have the
+ * URL <tt>"file:///bar/%23foo%23"</tt>.
+ * If you have the absolute path and need the URL-escaping you should create
+ * KURL via the default-constructor and then call setPath(const QString&):
+ * @code
+ * KURL kurl;
+ * kurl.setPath( "/bar/#foo#" );
+ * QString url = kurl.url(); // -> "file:///bar/%23foo%23"
+ * @endcode
+ *
+ * If you have the URL of a local file or directory and need the absolute path,
+ * you would use path().
+ * @code
+ * KURL url( "file:///bar/%23foo%23" );
+ * ...
+ * if ( url.isLocalFile() )
+ * QString path = url.path(); // -> "/bar/#foo#"
+ * @endcode
+ *
+ * The other way round: if the user can enter a string, that can be either a
+ * path or a URL, then you need to use KURL::fromPathOrURL() to build a KURL.
+ *
+ * This must also be considered, when you have separated directory and file
+ * strings and need to put them together.
+ * While you can simply concatenate normal path strings, you must take care if
+ * the directory-part is already an escaped URL.
+ * (This might be needed if the user specifies a relative path, and your
+ * program supplies the rest from elsewhere.)
+ *
+ * Wrong:
+ * @code
+ * QString dirUrl = "file:///bar/";
+ * QString fileName = "#foo#";
+ * QString invalidURL = dirUrl + fileName; // -> "file:///bar/#foo#" won't behave like you would expect.
+ * @endcode
+ * Instead you should use addPath().
+ *
+ * Right:
+ * @code
+ * KURL url( "file:///bar/" );
+ * QString fileName = "#foo#";
+ * url.addPath( fileName );
+ * QString validURL = url.url(); // -> "file:///bar/%23foo%23"
+ * @endcode
+ *
+ * Also consider that some URLs contain the password, but this shouldn't be
+ * visible. Your program should use prettyURL() every time it displays a
+ * URL, whether in the GUI or in debug output or...
+ *
+ * @code
+ * KURL url( "ftp://name:password@ftp.faraway.org/bar/%23foo%23");
+ * QString visibleURL = url.prettyURL(); // -> "ftp://name@ftp.faraway.org/bar/%23foo%23"
+ * @endcode
+ * Note that prettyURL() doesn't change the character escapes (like <tt>"%23"</tt>).
+ * Otherwise the URL would be invalid and the user wouldn't be able to use it in another
+ * context.
+ *
+ * KURL has some restrictions regarding the path
+ * encoding. KURL works internally with the decoded path and
+ * and encoded query. For example,
+ * @code
+ * http://localhost/cgi-bin/test%20me.pl?cmd=Hello%20you
+ * @endcode
+ * would result in a decoded path <tt>"/cgi-bin/test me.pl"</tt>
+ * and in the encoded query <tt>"?cmd=Hello%20you"</tt>.
+ * Since path is internally always encoded you may @em not use
+ * <tt>"%00"</tt> in the path, although this is OK for the query.
+ *
+ * @author Torben Weis <weis@kde.org>
+ */
+class KDECORE_EXPORT KURL
+{
+public:
+ /**
+ * Flags to choose how file: URLs are treated when creating their QString
+ * representation with prettyURL(int,AdjustementFlags)
+ *
+ * However it is recommended to use pathOrURL() instead of this variant of prettyURL()
+ */
+ enum AdjustementFlags
+ {
+ /**
+ * Do not treat file: URLs differently
+ */
+ NoAdjustements = 0,
+ /**
+ * Strip the file: protocol from the string, i.e. return only the path and
+ * filename as a local path
+ */
+ StripFileProtocol = 1
+ };
+
+ /**
+ * Defines the type of URI we are processing.
+ */
+ enum URIMode
+ {
+ /**
+ * Automatically detected. Using this mode, an appropriate processing
+ * mode will be selected when the URI is first processed.
+ */
+ Auto,
+ /**
+ * Invalid URI. This is something that can't be parsed as a URI at all.
+ * The contents are accessible through the protocol() method.
+ */
+ Invalid,
+ /**
+ * Raw URI. This type of URI should not be processed in any way.
+ * Contents are accessible through the path() method.
+ */
+ RawURI,
+ /**
+ * Standards compliant URL. Process as a syntactically correct URL.
+ */
+ URL,
+ /**
+ * Mailto URI. path() contains an email address which should have its
+ * domain part processed as a DNS name. The email address is accessible
+ * through the path() method.
+ */
+ Mailto
+ };
+
+ /**
+ * KURL::List is a QValueList that contains KURLs with a few
+ * convenience methods.
+ * @see KURL
+ * @see QValueList
+ */
+ class KDECORE_EXPORT List : public QValueList<KURL>
+ {
+ public:
+ /**
+ * Creates an empty List.
+ */
+ List() { }
+ /**
+ * @brief Creates a list that contains the given URL as only item
+ *
+ * @param url the URL to add
+ */
+ List(const KURL &url);
+ /**
+ * @brief Creates a list that contains the URLs from the given list
+ *
+ * This equivalent to iterating over the input list and using each item
+ * as the argument to KURL's constructor, i.e. the resulting list will
+ * have as many elements as the input list, but not all entries might
+ * be valid.
+ *
+ * @param list the list containing the URLs as strings
+ *
+ * @see KURL(const QString &, int)
+ */
+ List(const QStringList &list);
+ /**
+ * @brief Converts the URLs of this list to a list of strings
+ *
+ * This is equivalent to iterating over the list and calling url() on
+ * each item.
+ * If you need a list of user visible URLs, i.e. not containing password
+ * information, iterate over the list yourself and call prettyURL() on
+ * each item instead.
+ *
+ * @return the list of strings
+ *
+ * @see KURL::url()
+ */
+ QStringList toStringList() const;
+ };
+ /**
+ * @brief Constructs an empty URL
+ *
+ * The created instance will also be invalid, see isValid()
+ */
+ KURL();
+
+ /**
+ * @brief Destructs the KURL object
+ */
+ ~KURL();
+
+ /**
+ * @brief Usual constructor, to construct from a string
+ *
+ * @warning It is dangerous to feed UNIX filenames into this function,
+ * this will work most of the time but not always.
+ *
+ * For example <tt>"/home/Torben%20Weis"</tt> will be considered a URL
+ * pointing to the file <tt>"/home/Torben Weis"</tt> instead
+ * of to the file <tt>"/home/Torben%20Weis"</tt>.
+ *
+ * This means that if you have a usual UNIX like path you should not use
+ * this constructor. Instead use fromPathOrURL()
+ *
+ * @param url a URL, not a filename. If the URL does not have a protocol
+ * part, @c "file:" is assumed
+ * @param encoding_hint MIB of original encoding of URL.
+ * See QTextCodec::mibEnum()
+ *
+ * @see fromPathOrURL()
+ */
+ KURL( const QString& url, int encoding_hint = 0 );
+ /**
+ * @brief Constructor taking an URL encoded in a C string
+ *
+ * Constructor taking a char * @p url, which is an @em encoded representation
+ * of the URL, exactly like the usual constructor. This is useful when
+ * the URL, in its encoded form, is strictly ASCII.
+ *
+ * @warning It is dangerous to feed UNIX filenames into this function,
+ * this will work most of the time but not always.
+ *
+ * For example <tt>"/home/Torben%20Weis"</tt> will be considered a URL
+ * pointing to the file <tt>"/home/Torben Weis"</tt> instead
+ * of to the file <tt>"/home/Torben%20Weis"</tt>.
+ *
+ * This means that if you have a usual UNIX like path you should not use
+ * this constructor. Instead use fromPathOrURL()
+ *
+ * @param url an encoded URL. If the URL does not have a protocol part,
+ * @c "file:" is assumed
+ * @param encoding_hint MIB of original encoding of URL.
+ * See QTextCodec::mibEnum()
+ *
+ * @see fromPathOrURL()
+ * @see QString::fromLatin1()
+ */
+ KURL( const char * url, int encoding_hint = 0 );
+ /**
+ * @brief Constructor taking an URL encoded in a QCString
+ *
+ * Constructor taking a QCString @p url, which is an @em encoded
+ * representation of the URL, exactly like the usual constructor. This is
+ * useful when the URL, in its encoded form, is strictly ASCII.
+ *
+ * @warning It is dangerous to feed UNIX filenames into this function,
+ * this will work most of the time but not always.
+ *
+ * For example <tt>"/home/Torben%20Weis"</tt> will be considered a URL
+ * pointing to the file <tt>"/home/Torben Weis"</tt> instead
+ * of to the file <tt>"/home/Torben%20Weis"</tt>.
+ *
+ * This means that if you have a usual UNIX like path you should not use
+ * this constructor. Instead use fromPathOrURL()
+ *
+ * @param url A encoded URL. If the URL does not have a protocol part,
+ * @c "file:" is assumed
+ * @param encoding_hint MIB of original encoding of URL.
+ * See QTextCodec::mibEnum()
+ *
+ * @see fromPathOrURL()
+ * @see QString::fromLatin1()
+ */
+ KURL( const QCString& url, int encoding_hint = 0 );
+
+ /**
+ * @brief Copy constructor
+ *
+ * @param u the KURL to copy
+ */
+ KURL( const KURL& u );
+ /**
+ * @brief Constructor taking a Qt URL
+ *
+ * Converts from a Qt URL.
+ *
+ * @param u the QUrl
+ */
+ KURL( const QUrl &u );
+ /**
+ * @brief Constructor allowing relative URLs
+ *
+ * @warning It is dangerous to feed UNIX filenames into this function,
+ * this will work most of the time but not always.
+ *
+ * For example <tt>"/home/Torben%20Weis"</tt> will be considered a URL
+ * pointing to the file <tt>"/home/Torben Weis"</tt> instead
+ * of to the file <tt>"/home/Torben%20Weis"</tt>.
+ *
+ * This means that if you have a usual UNIX like path you should not use
+ * this constructor. Instead use fromPathOrURL()
+ *
+ * @param _baseurl The base url.
+ * @param _rel_url A relative or absolute URL.
+ * If this is an absolute URL then @p _baseurl will be ignored.
+ * If this is a relative URL it will be combined with @p _baseurl.
+ * Note that @p _rel_url should be encoded too, in any case.
+ * So do NOT pass a path here (use setPath() or addPath() or
+ * fromPathOrURL() instead)
+ * @param encoding_hint MIB of original encoding of URL.
+ * See QTextCodec::mibEnum()
+ *
+ * @see fromPathOrURL()
+ */
+ KURL( const KURL& _baseurl, const QString& _rel_url, int encoding_hint=0 );
+
+ /**
+ * @brief Returns the protocol for the URL
+ *
+ * Examples for a protocol string are @c "file", @c "http", etc. but also
+ * @c "mailto:" and other pseudo protocols.
+ *
+ * @return the protocol of the URL, does not include the colon. If the
+ * URL is malformed, @c QString::null will be returned
+ *
+ * @see setProtocol()
+ * @see isValid()
+ */
+ QString protocol() const { return m_bIsMalformed ? QString::null : m_strProtocol; }
+ /**
+ * @brief Sets the protocol for the URL
+ *
+ * Examples for a protocol string are @c "file", @c "http", etc. but also
+ * @c "mailto:" and other pseudo protocols.
+ *
+ * @param _txt the new protocol of the URL (without colon)
+ *
+ * @see protocol()
+ */
+ void setProtocol( const QString& _txt );
+
+ /**
+ * @brief Returns the URI processing mode for the URL
+ *
+ * @return the URI processing mode set for this URL
+ *
+ * @see URIMode
+ * @see uriModeForProtocol()
+ *
+ * @since 3.2
+ */
+ int uriMode() const;
+
+ /**
+ * @brief Returns the decoded user name (login, user id, etc) included in
+ * the URL
+ *
+ * @return the user name or @c QString::null if there is no user name
+ *
+ * @see setUser()
+ * @see hasUser()
+ */
+ QString user() const { return m_strUser; }
+ /**
+ * @brief Sets the user name (login, user id, etc) to include in the URL
+ *
+ * Special characters in the user name will appear encoded in the URL.
+ * If there is a password associated with the user, it can be set using
+ * setPass().
+ *
+ * @param _txt the name of the user or @c QString::null to remove the user
+ *
+ * @see user()
+ * @see hasUser()
+ * @see hasPass()
+ */
+ void setUser( const QString& _txt );
+ /**
+ * @brief Tests if this URL has a user name included in it
+ *
+ * @return @c true if the URL has an non-empty user name
+ *
+ * @see user()
+ * @see setUser()
+ * @see hasPass()
+ */
+ bool hasUser() const { return !m_strUser.isEmpty(); }
+
+ /**
+ * @brief Returns the decoded password (corresponding to user()) included
+ * in the URL
+ *
+ * @note a password can only appear in a URL string if you also set
+ * a user, see setUser().
+ *
+ * @return the password or @c QString::null if it does not exist
+ *
+ * @see setPass()
+ * @see hasPass()
+ * @see hasUser()
+ */
+ QString pass() const { return m_strPass; }
+ /**
+ * @brief Sets the password (corresponding to user()) to include in the URL
+ *
+ * Special characters in the password will appear encoded in the URL.
+ * @note a password can only appear in a URL string if you also set
+ * a user, see setUser().
+ *
+ * @param _txt the password to set or @c QString::null to remove the password
+ *
+ * @see pass()
+ * @see hasPass()
+ * @see hasUser()
+ */
+ void setPass( const QString& _txt );
+ /**
+ * @brief Tests if this URL has a password included in it
+ *
+ * @note a password can only appear in a URL string if you also set
+ * a user, see setUser().
+ *
+ * @return @c true if there is a non-empty password set
+ *
+ * @see pass()
+ * @see setPass()
+ * @see hasUser()
+ */
+ bool hasPass() const { return !m_strPass.isEmpty(); }
+
+ /**
+ * @brief Returns the decoded hostname included in the URL
+ *
+ * @return the name of the host or @c QString::null if no host is set
+ *
+ * @see setHost()
+ * @see hasHost()
+ */
+ QString host() const { return m_strHost; }
+
+ /**
+ * @brief Sets the hostname to include in the URL
+ *
+ * Special characters in the hostname will appear encoded in the URL.
+ *
+ * @param _txt the new name of the host or QString::null to remove the host
+ *
+ * @see host()
+ * @see hasHost()
+ */
+ void setHost( const QString& _txt );
+ /**
+ * @brief Tests if this URL has a hostname included in it
+ *
+ * @return @c true if the URL has a non-empty host
+ *
+ * @see host()
+ * @see setHost()
+ */
+ bool hasHost() const { return !m_strHost.isEmpty(); }
+
+ /**
+ * @brief Returns the port number included in the URL
+ *
+ * @return the port number or @c 0 if there is no port number specified in
+ * the URL
+ *
+ * @see setPort()
+ * @see host()
+ */
+ unsigned short int port() const { return m_iPort; }
+ /**
+ * @brief Sets the port number to include in the URL
+ *
+ * @param _p the new port number or @c 0 to have no port number
+ *
+ * @see port()
+ * @see setHost()
+ */
+ void setPort( unsigned short int _p );
+
+ /**
+ * @brief Returns the current decoded path
+ *
+ * This does @em not include the query.
+ *
+ * @return the path of the URL (without query), or @c QString::null if no
+ * path is set
+ *
+ * @see path(int)
+ * @see setPath()
+ * @see hasPath()
+ */
+ QString path() const { return m_strPath; }
+
+ /**
+ * @brief Returns the current decoded path
+ *
+ * This does @em not include the query, see query() for accessing it.
+ *
+ * The @p _trailing parameter allows to ensure the existance or absence of
+ * the last (trailing) @c '/' character in the path.
+ * If the URL has no path, then no @c '/' is added anyway.
+ * And on the other side: if the path is just @c "/", then this character
+ * won't be stripped.
+ *
+ * Reason: <tt>"ftp://weis@host"</tt> means something completely different
+ * than <tt>"ftp://weis@host/"</tt>.
+ * So adding or stripping the '/' would really alter the URL, while
+ * <tt>"ftp://host/path"</tt> and <tt>"ftp://host/path/"</tt> mean the same
+ * directory.
+ *
+ * @param _trailing May be ( @c -1, @c 0, @c +1 ). @c -1 strips a trailing
+ * @c '/', @c +1 adds a trailing @c '/' if there is none yet
+ * and @c 0 returns the path unchanged
+ *
+ * @return the path of the URL (without query), or @c QString::null if no
+ * path is set
+ *
+ * @see path()
+ * @see setPath()
+ * @see hasPath()
+ * @see adjustPath()
+ */
+ QString path( int _trailing ) const;
+
+ /**
+ * @brief Sets the decoded path of the URL
+ *
+ * This does @em not changed the query, see setQuery() for that.
+ *
+ * The @p path is considered to be decoded, i.e. characters not allowed in
+ * path, for example @c '?' will be encoded and does not indicate the
+ * beginning of the query part. Something that might look encoded,
+ * like @c "%3f" will not become decoded.
+ *
+ * @param path the new, decoded, path or @c QString::null to remove the path
+ *
+ * @see path()
+ * @see path(int)
+ * @see hasPath()
+ */
+ void setPath( const QString& path );
+
+ /**
+ * @brief Tests if this URL has a path included in it
+ *
+ * @return @c true if there is a non-empty path
+ *
+ * @see path()
+ * @see setPath()
+ */
+ bool hasPath() const { return !m_strPath.isEmpty(); }
+
+ /**
+ * @brief Resolves @c "." and @c ".." components in path
+ *
+ * Some servers seem not to like the removal of extra @c '/'
+ * even though it is against the specification in RFC 2396.
+ *
+ * @param cleanDirSeparator if @c true, occurrences of consecutive
+ * directory separators (e.g. <tt>"/foo//bar"</tt>) are cleaned up as
+ * well
+ *
+ * @see hasPath()
+ * @see adjustPath()
+ */
+ void cleanPath(bool cleanDirSeparator = true);
+
+ /**
+ * @brief Adds or removes a trailing slash to/from the path
+ *
+ * The @p _trailing parameter allows to ensure the existance or absence of
+ * the last (trailing) @c '/' character in the path.
+ * If the URL has no path, then no @c '/' is added anyway.
+ * And on the other side: if the path is just @c "/", then this character
+ * won't be stripped.
+ *
+ * Reason: <tt>"ftp://weis@host"</tt> means something completely different
+ * than <tt>"ftp://weis@host/"</tt>.
+ * So adding or stripping the '/' would really alter the URL, while
+ * <tt>"ftp://host/path"</tt> and <tt>"ftp://host/path/"</tt> mean the same
+ * directory.
+ *
+ * @param _trailing May be ( @c -1, @c 0, @c +1 ). @c -1 strips a trailing
+ * @c '/', @c +1 adds a trailing @c '/' if there is none yet
+ * and @c 0 returns the path unchanged
+ *
+ * @see hasPath()
+ * @see cleanPath()
+ */
+ void adjustPath(int _trailing);
+
+ /**
+ * @brief Sets both path and query of the URL in their encoded form
+ *
+ * This is useful for HTTP. It looks first for @c '?' and decodes then,
+ * see setEncodedPath().
+ * The encoded path is the concatenation of the current path and the query.
+ *
+ * @param _txt the new encoded path and encoded query
+ * @param encoding_hint MIB of original encoding of @p _txt .
+ * See QTextCodec::mibEnum()
+ *
+ * @see encodedPathAndQuery()
+ * @see setPath()
+ * @see setQuery()
+ */
+ void setEncodedPathAndQuery( const QString& _txt, int encoding_hint = 0 );
+
+ /**
+ * @brief Sets the (already encoded) path of the URL
+ *
+ * @param _txt the new encoded path
+ * @param encoding_hint MIB of original encoding of @p _txt .
+ * See QTextCodec::mibEnum()
+ *
+ * @see setEncodedPathAndQuery()
+ * @see setPath()
+ */
+ void setEncodedPath(const QString& _txt, int encoding_hint = 0 );
+
+ /**
+ * @brief Returns the encoded path and the query
+ *
+ * The @p _trailing parameter allows to ensure the existance or absence of
+ * the last (trailing) @c '/' character in the path.
+ * If the URL has no path, then no @c '/' is added anyway.
+ * And on the other side: if the path is just @c "/", then this character
+ * won't be stripped.
+ *
+ * Reason: <tt>"ftp://weis@host"</tt> means something completely different
+ * than <tt>"ftp://weis@host/"</tt>.
+ * So adding or stripping the '/' would really alter the URL, while
+ * <tt>"ftp://host/path"</tt> and <tt>"ftp://host/path/"</tt> mean the same
+ * directory.
+ *
+ * @param _trailing May be ( @c -1, @c 0, @c +1 ). @c -1 strips a trailing
+ * @c '/', @c +1 adds a trailing @c '/' if there is none yet
+ * and @c 0 returns the path unchanged
+ * @param _no_empty_path if set to @c true then an empty path is substituted
+ * by @c "/"
+ * @param encoding_hint MIB of desired encoding of URL.
+ * See QTextCodec::mibEnum()
+ *
+ * @return the concatenation of the encoded path , @c '?' and the
+ * encoded query
+ *
+ * @see setEncodedPathAndQuery()
+ * @see path()
+ * @see query()
+ */
+ QString encodedPathAndQuery( int _trailing = 0, bool _no_empty_path = false, int encoding_hint = 0) const;
+
+ /**
+ * @brief Sets the encoded query of the URL
+ *
+ * The query should start with a @c '?'. If it doesn't @c '?' is prepended.
+ *
+ * @param _txt this is considered to be encoded. This has a good reason:
+ * the query may contain the @c '0' character
+ *
+ * @param encoding_hint MIB of the encoding. Reserved, should be @c 0 .
+ * See QTextCodec::mibEnum()
+ *
+ * @see query()
+ */
+ void setQuery( const QString& _txt, int encoding_hint = 0);
+
+ /**
+ * @brief Returns the encoded query of the URL
+ *
+ * The query may contain the @c '0' character.
+ * If a query is present it always starts with a @c '?'.
+ * A single @c '?' means an empty query.
+ * An empty string means no query.
+ *
+ * @return the encoded query or @c QString::null if there is none
+ *
+ * @see setQuery()
+ */
+ QString query() const;
+
+ /**
+ * @brief Returns the encoded reference of the URL
+ *
+ * The reference is @em never decoded automatically.
+ *
+ * @return the undecoded reference, or @c QString::null if there is none
+ *
+ * @see setRef()
+ * @see hasRef()
+ * @see htmlRef()
+ */
+ QString ref() const { return m_strRef_encoded; }
+
+ /**
+ * @brief Sets the encoded reference part (everything after @c '#')
+ *
+ * This is considered to be encoded, i.e. characters that are not allowed
+ * as part of the reference will @em not be encoded.
+ *
+ * @param _txt the encoded reference or @c QString::null to remove it
+ *
+ * @see ref()
+ * @see hasRef()
+ */
+ void setRef( const QString& _txt ) { m_strRef_encoded = _txt; }
+
+ /**
+ * @brief Tests if the URL has a reference part
+ *
+ * @return @c true if the URL has a reference part. In a URL like
+ * <tt>"http://www.kde.org/kdebase.tar#tar:/README"</tt> it would
+ * return @c true as well
+ *
+ * @see ref()
+ * @see setRef()
+ */
+ bool hasRef() const { return !m_strRef_encoded.isNull(); }
+
+ /**
+ * @brief Returns decoded the HTML-style reference
+ * (the part of the URL after @c '#')
+ *
+ * @return the HTML-style reference
+ *
+ * @see encodedHtmlRef()
+ * @see setHTMLRef()
+ * @see hasHTMLRef()
+ * @see split()
+ * @see hasSubURL()
+ * @see ref()
+ */
+ QString htmlRef() const;
+
+ /**
+ * @brief Returns the encoded HTML-style reference
+ * (the part of the URL after @c '#')
+ *
+ * @return the HTML-style reference in its original, encoded, form
+ *
+ * @see htmlRef()
+ * @see setHTMLRef()
+ * @see hasHTMLRef()
+ */
+ QString encodedHtmlRef() const;
+
+ /**
+ * @brief Sets the decoded HTML-style reference
+ *
+ * @param _ref the new reference. This is considered to be @em not encoded in
+ * contrast to setRef(). Use @c QString::null to remove it
+ *
+ * @see htmlRef()
+ * @see hasHTMLRef()
+ */
+ void setHTMLRef( const QString& _ref );
+
+ /**
+ * @brief Tests if there is an HTML-style reference
+ *
+ * @return @c true if the URL has an HTML-style reference
+ *
+ * @see htmlRef()
+ * @see encodedHtmlRef()
+ * @see setHTMLRef()
+ * @see hasRef()
+ */
+ bool hasHTMLRef() const;
+
+ /**
+ * @brief Tests if the URL is well formed
+ *
+ * @return @c false if the URL is malformed. This function does @em not test
+ * whether sub URLs are well-formed as well
+ */
+ bool isValid() const { return !m_bIsMalformed; }
+ /**
+ * @brief Tests if the URL is malformed
+ *
+ * @return @c true if the URL is malformed. This function does @em not test
+ * whether sub URLs are well-formed as well
+ *
+ * @deprecated Use !isValid() instead
+ *
+ * @see isValid()
+ */
+ KDE_DEPRECATED bool isMalformed() const { return !isValid(); }
+
+ /**
+ * @brief Tests if the file is local
+ *
+ * @return @c true if the file is a plain local file and has no filter
+ * protocols attached to it
+ */
+ bool isLocalFile() const;
+
+ /**
+ * @brief Adds file encoding information
+ *
+ * Adds encoding information to the URL by adding a @c "charset" parameter.
+ * If there is already a charset parameter, it will be replaced.
+ *
+ * @param encoding the encoding to add or @c QString::null to remove the
+ * encoding
+ *
+ * @see fileEncoding()
+ * @see QTextCodec::codecForName()
+ */
+ void setFileEncoding(const QString &encoding);
+
+ /**
+ * @brief Returns encoding information of the URL
+ *
+ * The encoding information is the content of the @c "charset" parameter.
+ *
+ * @return an encoding suitable for QTextCodec::codecForName()
+ * or @c QString::null if not encoding was specified
+ */
+ QString fileEncoding() const;
+
+ /**
+ * @brief Tests if the URL has any sub URLs
+ *
+ * See split() for examples for sub URLs.
+ *
+ * @return @c true if the file has at least one sub URL
+ *
+ * @see split()
+ */
+ bool hasSubURL() const;
+
+ /**
+ * @brief Adds to the current path
+ *
+ * Assumes that the current path is a directory. @p _txt is appended to the
+ * current path. The function adds @c '/' if needed while concatenating.
+ * This means it does not matter whether the current path has a trailing
+ * @c '/' or not. If there is none, it becomes appended. If @p _txt
+ * has a leading @c '/' then this one is stripped.
+ *
+ * @param txt the text to add. It is considered to be decoded
+ *
+ * @see setPath()
+ * @see hasPath()
+ */
+ void addPath( const QString& txt );
+
+ /**
+ * @brief Returns the value of a certain query item
+ *
+ * @param item item whose value we want
+ *
+ * @return the value of the given query item name or @c QString::null if the
+ * specified item does not exist
+ *
+ * @see addQueryItem()
+ * @see removeQueryItem()
+ * @see queryItems()
+ * @see query()
+ */
+ QString queryItem( const QString& item ) const;
+
+ /**
+ * @brief Returns the value of a certain query item
+ *
+ * @param item item whose value we want
+ * @param encoding_hint MIB of encoding of query.
+ * See QTextCodec::mibEnum()
+ *
+ * @return the value of the given query item name or @c QString::null if the
+ * specified item does not exist
+ *
+ * @see addQueryItem()
+ * @see removeQueryItem()
+ * @see queryItems()
+ * @see query()
+ */
+ QString queryItem( const QString& item, int encoding_hint ) const;
+
+ /**
+ * Options for queryItems()
+ *
+ * @since 3.1
+ */
+ enum QueryItemsOptions
+ {
+ /**
+ * Normalize query keys to lowercase
+ */
+ CaseInsensitiveKeys = 1
+ };
+
+ /**
+ * @internal, override for the below function
+ */
+ QMap< QString, QString > queryItems( int options=0 ) const;
+
+ /**
+ * @brief Returns the list of query items as a map mapping keys to values
+ *
+ * @param options any of QueryItemsOptions <em>OR</em>ed together
+ * @param encoding_hint MIB of encoding of query.
+ * See QTextCodec::mibEnum()
+ *
+ * @return the map of query items or the empty map if the URL has no
+ * query items
+ *
+ * @see queryItem()
+ * @see addQueryItem()
+ * @see removeQueryItem()
+ * @see query()
+ *
+ * @since 3.1
+ */
+ QMap< QString, QString > queryItems( int options, int encoding_hint ) const;
+
+ /**
+ * @brief Adds an additional query item
+ *
+ * To replace an existing query item, the item should first be
+ * removed with removeQueryItem()
+ *
+ * @param _item name of item to add
+ * @param _value value of item to add
+ * @param encoding_hint MIB of encoding to use for _value.
+ * See QTextCodec::mibEnum()
+ *
+ * @see queryItem()
+ * @see queryItems()
+ * @see query()
+ */
+ void addQueryItem( const QString& _item, const QString& _value, int encoding_hint = 0 );
+
+ /**
+ * @brief Removea an item from the query
+ *
+ * @param _item name of item to remove
+ *
+ * @see addQueryItem()
+ * @see queryItem()
+ * @see queryItems()
+ * @see query()
+ */
+ void removeQueryItem( const QString& _item );
+
+ /**
+ * @brief Sets the filename of the path
+ *
+ * In comparison to addPath() this function does not assume that the current
+ * path is a directory. This is only assumed if the current path ends
+ * with @c '/'.
+ *
+ * If the current path ends with @c '/' then @p _txt is just appended,
+ * otherwise all text behind the last @c '/' in the current path is erased
+ * and @p _txt is appended then. It does not matter whether @p _txt starts
+ * with @c '/' or not.
+ *
+ * Any reference is reset.
+ *
+ * @param _txt the filename to be set. It is considered to be decoded
+ *
+ * @see fileName()
+ * @see setDirectory()
+ * @see setPath()
+ */
+ void setFileName( const QString&_txt );
+
+ /**
+ * @brief Returns the filename of the path
+ *
+ * @p _ignore_trailing_slash_in_path tells whether a trailing @c '/' should
+ * be ignored. This means that the function would return @c "torben" for
+ * <tt>"file:///hallo/torben/"</tt> and <tt>"file:///hallo/torben"</tt>.
+ *
+ * @param _ignore_trailing_slash_in_path if set to @c false, then everything
+ * behind the last @c '/' is considered to be the filename
+ *
+ * @return the filename of the current path. The returned string is decoded.
+ * @c QString::null if there is no file (and thus no path)
+ *
+ * @see setFileName()
+ * @see directory()
+ * @see path()
+ */
+ QString fileName( bool _ignore_trailing_slash_in_path = true ) const;
+
+ /**
+ * @brief Returns the directory of the path
+ *
+ * The directory is everything between the last and the second last @c '/'
+ * is returned. For example <tt>"file:///hallo/torben/"</tt> would return
+ * <tt>"/hallo/torben/"</tt> while <tt>"file:///hallo/torben"</tt> would
+ * return <tt>"hallo/"</tt>.
+ *
+ * @p _ignore_trailing_slash_in_path tells whether a trailing @c '/' should
+ * be ignored. This means that the function would return @c "/hallo"
+ * (or @c "/hallo" depending on @p _strip_trailing_slash_from_result) for
+ * <tt>"file:///hallo/torben/"</tt> and <tt>"file:///hallo/torben"</tt>.
+ *
+ * @param _strip_trailing_slash_from_result tells whether the returned result
+ * should end with @c '/' or not. If the path is empty or just @c "/"
+ * then this flag has no effect
+ * @param _ignore_trailing_slash_in_path if set to @c false, then everything
+ * behind the last @c '/' is considered to be the filename
+ *
+ * @return the directory part of the current path or @c QString::null when
+ * there is no path. The returned string is decoded
+ *
+ * @see setDirectory()
+ * @see fileName()
+ * @see path()
+ */
+ QString directory( bool _strip_trailing_slash_from_result = true,
+ bool _ignore_trailing_slash_in_path = true ) const;
+
+ /**
+ * @brief Sets the directory of the path, leaving the filename empty
+ *
+ * @param dir the decoded directory to set
+ *
+ * @see directory()
+ * @see setFileName()
+ * @see setPath()
+ */
+ void setDirectory(const QString &dir);
+
+ /**
+ * @brief Changes the directory by descending into the given directory
+ *
+ * It is assumed the current URL represents a directory.
+ * If @p _dir starts with a @c '/' the current URL will be
+ * <tt>"protocol://host/dir"</tt> otherwise @p _dir will be appended to the
+ * path. @p _dir can be @c ".."
+ *
+ * This function won't strip protocols. That means that when you are in
+ * <tt>"file:///dir/dir2/my.tgz#tar:/"</tt> and you do <tt>cd("..")</tt> you
+ * will still be in <tt>"file:///dir/dir2/my.tgz#tar:/"</tt>
+ *
+ * @param _dir the directory to change to
+ * @return @c true if successful
+ *
+ * @see directory()
+ * @see path()
+ */
+ bool cd( const QString& _dir );
+
+ /**
+ * @brief Returns the URL as string, with all escape sequences intact,
+ * encoded in a given charset
+ *
+ * This is used in particular for encoding URLs in UTF-8 before using them
+ * in a drag and drop operation.
+ *
+ * @note that the string returned by url() will include the password of the
+ * URL. If you want to show the URL to the user, use prettyURL().
+ *
+ * The @p _trailing parameter allows to ensure the existance or absence of
+ * the last (trailing) @c '/' character in the path.
+ * If the URL has no path, then no @c '/' is added anyway.
+ * And on the other side: if the path is just @c "/", then this character
+ * won't be stripped.
+ *
+ * Reason: <tt>"ftp://weis@host"</tt> means something completely different
+ * than <tt>"ftp://weis@host/"</tt>.
+ * So adding or stripping the '/' would really alter the URL, while
+ * <tt>"ftp://host/path"</tt> and <tt>"ftp://host/path/"</tt> mean the same
+ * directory.
+ *
+ * @param _trailing May be ( @c -1, @c 0, @c +1 ). @c -1 strips a trailing
+ * @c '/', @c +1 adds a trailing @c '/' if there is none yet
+ * and @c 0 returns the path unchanged
+ * @param encoding_hint MIB of encoding to use.
+ * See QTextCodec::mibEnum()
+ *
+ * @return the complete URL, with all escape sequences intact, encoded
+ * in a given charset
+ *
+ * @see prettyURL()
+ * @see pathOrURL()
+ * @see htmlURL()
+ */
+ QString url( int _trailing = 0, int encoding_hint = 0) const;
+
+ /**
+ * @brief Returns the URL as string in human-friendly format
+ *
+ * Example:
+ * @code
+ * http://localhost:8080/test.cgi?test=hello world&name=fred
+ * @endcode
+ *
+ * Does @em not contain the password if the URL has one, use url() if you
+ * need to have it in the string.
+ *
+ * The @p _trailing parameter allows to ensure the existance or absence of
+ * the last (trailing) @c '/' character in the path.
+ * If the URL has no path, then no @c '/' is added anyway.
+ * And on the other side: if the path is just @c "/", then this character
+ * won't be stripped.
+ *
+ * Reason: <tt>"ftp://weis@host"</tt> means something completely different
+ * than <tt>"ftp://weis@host/"</tt>.
+ * So adding or stripping the '/' would really alter the URL, while
+ * <tt>"ftp://host/path"</tt> and <tt>"ftp://host/path/"</tt> mean the same
+ * directory.
+ *
+ * @param _trailing May be ( @c -1, @c 0, @c +1 ). @c -1 strips a trailing
+ * @c '/', @c +1 adds a trailing @c '/' if there is none yet
+ * and @c 0 returns the path unchanged
+ * @return a human readable URL, with no non-necessary encodings/escaped
+ * characters. Password will not be shown
+ *
+ * @see url()
+ * @see pathOrURL()
+ */
+ QString prettyURL( int _trailing = 0) const;
+
+ /**
+ * @brief Returns the URL as string in human-friendly format
+ * Example:
+ * @code
+ * http://localhost:8080/test.cgi?test=hello world&name=fred
+ * @endcode
+ *
+ * Does @em not contain the password if the URL has one, use url() if you
+ * need to have it in the string.
+ *
+ * The @p _trailing parameter allows to ensure the existance or absence of
+ * the last (trailing) @c '/' character in the path.
+ * If the URL has no path, then no @c '/' is added anyway.
+ * And on the other side: if the path is just @c "/", then this character
+ * won't be stripped.
+ *
+ * Reason: <tt>"ftp://weis@host"</tt> means something completely different
+ * than <tt>"ftp://weis@host/"</tt>.
+ * So adding or stripping the '/' would really alter the URL, while
+ * <tt>"ftp://host/path"</tt> and <tt>"ftp://host/path/"</tt> mean the same
+ * directory.
+ *
+ * @param _trailing May be ( @c -1, @c 0, @c +1 ). @c -1 strips a trailing
+ * @c '/', @c +1 adds a trailing @c '/' if there is none yet
+ * and @c 0 returns the path unchanged
+ * @param _flags if StripFileProtocol, @c "file://" will be stripped.
+ * The use of this method is now discouraged, better use pathOrURL().
+ *
+ * @return a human readable URL, with no non-necessary encodings/escaped
+ * characters. Password will not be shown
+ *
+ * @see prettyURL()
+ * @see url()
+ * @see pathOrURL()
+ */
+ QString prettyURL( int _trailing, AdjustementFlags _flags) const;
+ // ### BIC: Merge the two above + spell it as "Adjustment"
+ // Or remove completely, and let people use pathOrURL() instead
+
+ /**
+ * @brief Returns the URL as a string depending if it is a local file
+ *
+ * It will be either the URL (as prettyURL() would return) or, when the URL
+ * is a local file without query or ref, the path().
+ *
+ * Use this method, together with its opposite, fromPathOrURL(),
+ * to display and even let the user edit URLs.
+ *
+ * @return the path or URL string depending on its properties
+ *
+ * @see prettyURL()
+ * @see path()
+ * @see url()
+ * @see isLocalFile()
+ *
+ * @since 3.4
+ */
+ QString pathOrURL() const;
+
+ /**
+ * @brief Returns the URL as string, escaped for HTML
+ *
+ * @return a human readable URL, with no non-necessary encodings/escaped
+ * characters which is HTML encoded for safe inclusion in HTML or
+ * rich text. Password will not be shown.
+ *
+ * @see prettyURL()
+ * @see url()
+ * @see pathOrURL()
+ */
+ QString htmlURL() const;
+
+
+ /**
+ * @brief Tests if the KURL is empty
+ *
+ * An empty URL has neither path nor protocol set.
+ *
+ * @return @c true if the URL is empty
+ *
+ * @see hasPath()
+ * @see protocol()
+ * @see isValid()
+ */
+ bool isEmpty() const;
+
+ /**
+ * @brief Returns the URL that is the best possible candidate for on level
+ * higher in the path hierachy
+ *
+ * This function is useful to implement the "Up" button in a file manager for
+ * example.
+ * cd() never strips a sub-protocol. That means that if you are in
+ * <tt>"file:///home/x.tgz#gzip:/#tar:/"</tt> and hit the up button you
+ * expect to see <tt>"file:///home"</tt>. The algorithm tries to go up on the
+ * right-most URL. If that is not possible it strips the right most URL. It
+ * continues stripping URLs until it can go up.
+ *
+ * @return a URL that is a level higher
+ *
+ * @see cd()
+ * @see split()
+ * @see hasSubURL()
+ * @see path()
+ */
+ KURL upURL( ) const;
+
+ /**
+ * @brief Tests if this URL is less than the given URL
+ *
+ * The current URL is consideres <tt>"less than"</tt> then @p _u if
+ * (tested in this order):
+ * - it is not valid but @p _u is. See isValid()
+ * - its protocol is "less than" @p _u's protocol. See protocol()
+ * - its host is "less than" @p _u's host. See host()
+ * - its port is "less than" @p _u's port. See port()
+ * - its path is "less than" @p _u's path. See path()
+ * - its encoded query is "less than" @p _u's encoded query. See query()
+ * - its endoded reference is "less than" @p _u's encoded reference.
+ * See ref()
+ * - its username is "less than" @p _u's username. See user()
+ * - its password is "less than" @p _u's password. See pass()
+ *
+ * Examples:
+ * @code
+ * KURL url1;
+ * KURL url2;
+ *
+ * bool lessThan = url1 < url2; // false. Both invalid, no protocols
+ *
+ * url2.setProtocol( QString::null );
+ * lessThan = url1 < url2; // true. url2 is valid because of setProtocol()
+ *
+ * url1.setProtocol( QString::null );
+ * lessThan = url1 < url2; // false. Both valid and everything empty
+ *
+ * url1.setProtocol( "http" );
+ * url2.setProtocol( "https" );
+ * lessThan = url1 < url2; // true. "http" < "https"
+ *
+ * url2.setHost( "api.kde.org" );
+ * url2.setProtocol( "http" );
+ * url2.setProtocol( "www.kde.org" );
+ * lessThan = url1 < url2; // true. protocols equal and "api" < "www"
+ *
+ * url1.setProtocol( "https" );
+ * url2.setProtocol( "http" );
+ * lessThan = url1 < url2; // false. "https" > "http". host doesn't matter yet
+ * @endcode
+ *
+ * @param _u the URL to compare to
+ *
+ * @return @c true if the URL is less than @p _u. Otherwise @c false
+ * (equal or greater than)
+ *
+ * @see operator==()
+ * @see QString::compare()
+ */
+ bool operator<(const KURL& _u) const;
+
+ /**
+ * @brief Copies the values of the given URL into this one
+ *
+ * Just assigns each member using the member's assignment operator.
+ *
+ * @param _u the URL to take the values from
+ *
+ * @return a reference to this URL (*this)
+ *
+ * @see equals()
+ */
+ KURL& operator=( const KURL& _u );
+
+ /**
+ * @brief Assigns the URL, given as a string, to this one
+ *
+ * This will reset the current URL and parse the given string.
+ * See the similar constructor for known limitations.
+ *
+ * @param _url the QString to parse for values
+ *
+ * @return a reference to this URL (*this)
+ *
+ * @see equals()
+ * @see KURL(const QString &, int)
+ */
+ KURL& operator=( const QString& _url );
+
+ /**
+ * @brief Assigns the URL, given as a C string, to this one
+ *
+ * This will reset the current URL and parse the given string.
+ * See the similar constructor for known limitations.
+ *
+ * @param _url the C string to parse for values
+ *
+ * @return a reference to this URL (*this)
+ *
+ * @see equals()
+ * @see KURL(const char *, int)
+ */
+ KURL& operator=( const char * _url );
+
+ /**
+ * @brief Assigns the URL, given as a Qt URL, to this one
+ *
+ * This will reset the current URL and parse the given string.
+ *
+ * @param u the Qt URL to take the values from
+ *
+ * @return a reference to this URL (*this)
+ *
+ * @see equals()
+ * @see KURL(const QUrl &)
+ */
+ KURL& operator=( const QUrl & u );
+
+ /**
+ * @brief Tests if this URL is equal to the given one
+ *
+ * Tests each member for equality unless one of the URLs is invalid
+ * in which case they are not considered equal (even if both are invalid).
+ *
+ * Same as equals() when used with @p ignore_trailing set to
+ * @c false (default)
+ *
+ * @param _u the URL to compare to
+ *
+ * @return @c true if equal and neither this URL nor @p _u is malformed.
+ * Otherwise @c false
+ *
+ * @see equals()
+ * @see isValid()
+ * @see operator!=()
+ * @see operator<()
+ */
+ bool operator==( const KURL& _u ) const;
+
+ /**
+ * @brief Tests if this URL is equal to the one given as a string
+ *
+ * Creates a KURL instance for @p _u and compares with that using
+ * the equality operator for two KURLs.
+ *
+ * See the respective constructor for known limitations.
+ *
+ * @param _u the string to compare to
+ *
+ * @return @c true if equal and neither this URL nor @p _u is malformed.
+ * Otherwise @c false
+ *
+ * @see KURL(const QString &, int)
+ * @see operator==(const KURL &)
+ * @see equals()
+ * @see isValid()
+ * @see operator!=()
+ * @see operator<()
+ */
+ bool operator==( const QString& _u ) const;
+
+ /**
+ * @brief Tests if this URL is different from the given one
+ *
+ * Tests by negating the result of operator==()
+ *
+ * @param _u the URL to compare to
+ *
+ * @return the negated result of operator==()
+ *
+ * @see operator==()
+ * @see operator<()
+ */
+ bool operator!=( const KURL& _u ) const { return !( *this == _u ); }
+
+ /**
+ * @brief Tests if this URL is different from the one given as a string
+ *
+ * Tests by negating the result of operator==(const QString &)
+ *
+ * @param _u the URL to compare to
+ *
+ * @return the negated result of operator==(const QString &)
+ *
+ * @see operator==(const QString &)
+ * @see operator<()
+ */
+ bool operator!=( const QString& _u ) const { return !( *this == _u ); }
+
+ /**
+ * @brief Compares this URL with another one
+ *
+ * The same as equals(), just with a less obvious name.
+ *
+ * @param u the URL to compare this one with
+ * @param ignore_trailing set to @c true to ignore trailing @c '/' characters
+ *
+ * @return @c true if both URLs are the same
+ *
+ * @see operator==. This function should be used if you want to
+ * ignore trailing @c '/' characters
+ *
+ * @deprecated Use equals() instead.
+ */
+ bool cmp( const KURL &u, bool ignore_trailing = false ) const KDE_DEPRECATED;
+
+ /**
+ * @brief Compares this URL with another one
+ *
+ * @param u the URL to compare this one with
+ * @param ignore_trailing set to @c true to ignore trailing @c '/' characters
+ *
+ * @return @c true if both urls are the same
+ *
+ * @see operator==. This function should be used if you want to
+ * ignore trailing @c '/' characters
+ *
+ * @since 3.1
+ */
+ bool equals( const KURL &u, bool ignore_trailing = false ) const; // TODO KDE4: add bool _ignore_ref = false
+
+ /**
+ * @brief Tests if the given URL is parent of this URL
+ *
+ * For instance, <tt>"ftp://host/dir/"</tt> is a parent of
+ * <tt>"ftp://host/dir/subdir/subsubdir/"</tt>.
+ *
+ * @return @c true if this URL is a parent of @p u (or the same URL as @p u)
+ *
+ * @see equals()
+ * @see cd()
+ */
+ bool isParentOf( const KURL& u ) const;
+
+ /**
+ * @brief Splits nested URLs into a list of URLs
+ *
+ * Example for a nested URL:
+ * @code
+ * file:///home/weis/kde.tgz#gzip:/#tar:/kdebase
+ * @endcode
+ * A URL like <tt>"http://www.kde.org#tar:/kde/README.hml#ref1"</tt> will be
+ * split in <tt>"http://www.kde.org#ref1"</tt> and
+ * <tt>"tar:/kde/README.html#ref1"</tt>.
+ *
+ * That means in turn that @c "#ref1" is an HTML-style reference and not a
+ * new sub URL. Since HTML-style references mark a certain position in a
+ * document this reference is appended to every URL.
+ *
+ * The idea behind this is that browsers, for example, only look at the first
+ * URL while the rest is not of interest to them.
+ *
+ * @param _url the URL that has to be split
+ *
+ * @return an empty list on error or the list of split URLs
+ *
+ * @see hasSubURL()
+ * @see KURL(const QString&, int)
+ * @see join()
+ */
+ static List split( const QString& _url );
+
+ /**
+ * @brief Splits nested URLs into a list of URLs
+ *
+ * Example for a nested URL:
+ * @code
+ * file:///home/weis/kde.tgz#gzip:/#tar:/kdebase
+ * @endcode
+ * A URL like <tt>"http://www.kde.org#tar:/kde/README.hml#ref1"</tt> will be
+ * split in <tt>"http://www.kde.org#ref1"</tt> and
+ * <tt>"tar:/kde/README.html#ref1"</tt>.
+ *
+ * That means in turn that @c "#ref1" is an HTML-style reference and not a
+ * new sub URL. Since HTML-style references mark a certain position in a
+ * document this reference is appended to every URL.
+ *
+ * The idea behind this is that browsers, for example, only look at the first
+ * URL while the rest is not of interest to them.
+ *
+ * @param _url the URL that has to be split
+ *
+ * @return an empty list on error or the list of split URLs
+ *
+ * @see hasSubURL()
+ * @see join()
+ */
+ static List split( const KURL& _url );
+
+ /**
+ * @brief Joins a list of URLs into a single URL with sub URLs
+ *
+ * Reverses split(). Only the first URL may have a reference. This reference
+ * is considered to be HTML-like and is appended at the end of the resulting
+ * joined URL.
+ *
+ * @param _list the list to join
+ *
+ * @return the joined URL or an invalid URL if the list is empty
+ *
+ * @see split()
+ */
+ static KURL join( const List& _list );
+
+ /**
+ * @brief Creates a KURL object from a QString representing either an
+ * absolute path or a real URL
+ *
+ * Use this method instead of
+ * @code
+ * QString someDir = ...
+ * KURL url = someDir;
+ * @endcode
+ *
+ * Otherwise some characters (e.g. the '#') won't be encoded properly.
+ *
+ * @param text the string representation of the URL to convert
+ *
+ * @return the new KURL
+ *
+ * @see pathOrURL()
+ * @see KURL(const QString&, int)
+ *
+ * @since 3.1
+ */
+ static KURL fromPathOrURL( const QString& text );
+
+ /**
+ * @brief Encodes a string for use in URLs
+ *
+ * Convenience function.
+ *
+ * Convert unicoded string to local encoding and use %%-style
+ * encoding for all common delimiters / non-ascii characters.
+ *
+ * @param str the string to encode (can be @c QString::null)
+ * @param encoding_hint MIB of encoding to use.
+ * See QTextCodec::mibEnum()
+ *
+ * @return the encoded string
+ *
+ * @see encode_string_no_slash()
+ * @see decode_string()
+ */
+ static QString encode_string(const QString &str, int encoding_hint = 0);
+
+ /**
+ * @brief Encodes a string for use in URLs
+ *
+ * Convenience function.
+ *
+ * Convert unicoded string to local encoding and use %%-style
+ * encoding for all common delimiters and non-ascii characters
+ * as well as the slash @c '/'.
+ *
+ * @param str the string to encode (can be @c QString::null)
+ * @param encoding_hint MIB of encoding to use.
+ * See QTextCodec::mibEnum()
+ *
+ * @see encode_string()
+ * @see decode_string()
+ */
+ static QString encode_string_no_slash(const QString &str, int encoding_hint = 0);
+
+ /**
+ * @brief Decodes a string as used in URLs
+ *
+ * Convenience function.
+ *
+ * Decode %-style encoding and convert from local encoding to unicode.
+ *
+ * Reverse of encode_string()
+ *
+ * @param str the string to decode (can be @c QString::null)
+ * @param encoding_hint MIB of original encoding of @p str .
+ * See QTextCodec::mibEnum()
+ *
+ * @return the decoded string
+ *
+ * @see encode_string()
+ * @see encode_string_no_slash()
+ */
+ static QString decode_string(const QString &str, int encoding_hint = 0);
+
+ /**
+ * @brief Tests if a given URL is a relative as opposed to an absolute URL
+ *
+ * Convenience function.
+ *
+ * Returns whether @p _url is likely to be a "relative" URL instead of
+ * an "absolute" URL.
+ *
+ * @param _url the URL to examine
+ * @return @c true when the URL is likely to be "relative",
+ * @c false otherwise
+ *
+ * @see relativeURL()
+ */
+ static bool isRelativeURL(const QString &_url);
+
+ /**
+ * @brief Creates an URL relative to a base URL for a given input URL
+ *
+ * Convenience function
+ *
+ * Returns a "relative URL" based on @p base_url that points to @p url.
+ *
+ * If no "relative URL" can be created, e.g. because the protocol
+ * and/or hostname differ between @p base_url and @p url an absolute
+ * URL is returned.
+ *
+ * @note if @p base_url represents a directory, it should contain
+ * a trailing slash
+ *
+ * @param base_url the URL to derive from
+ * @param url the URL to point to relatively from @p base_url
+ * @param encoding_hint MIB of original encoding of @p str .
+ * See QTextCodec::mibEnum()
+ *
+ * @see isRelativeURL()
+ * @see relativePath()
+ * @see adjustPath()
+ */
+ static QString relativeURL(const KURL &base_url, const KURL &url, int encoding_hint = 0);
+
+ /**
+ * @brief Creates a path relative to a base path for a given input path
+ *
+ * Convenience function
+ *
+ * Returns a relative path based on @p base_dir that points to @p path.
+ *
+ * @param base_dir the base directory to derive from
+ * @param path the new target directory
+ * @param isParent an optional pointer to a boolean which, if provided, will
+ * be set to reflect whether @p path has @p base_dir as a parent dir
+ *
+ * @see relativeURL()
+ */
+ static QString relativePath(const QString &base_dir, const QString &path, bool *isParent=0);
+
+ /**
+ * @brief Determines which URI mode is suitable for processing URIs of a
+ * given protocol
+ *
+ * @param protocol the protocol name. See protocol()
+ *
+ * @return the URIMode suitable for the given protocol
+ *
+ * @see uriMode()
+ *
+ * @since 3.2
+ */
+ static URIMode uriModeForProtocol(const QString& protocol);
+
+#ifdef KDE_NO_COMPAT
+private:
+#endif
+ /**
+ * @deprecated change code to call fileName()
+ */
+ QString filename( bool _ignore_trailing_slash_in_path = true ) const
+ {
+ return fileName(_ignore_trailing_slash_in_path);
+ }
+
+protected:
+ /**
+ * @brief Resets the members to their "null" state
+ *
+ * All QString members get reset to @c QString::null, the port to @c 0
+ * the URIMode to @c Auto and the URL becomes invalid.
+ *
+ * This is like assigning a null URL, but more efficient as it doesn't
+ * require the temporary object.
+ *
+ * Called by constructors, assignment operators and the parse methods in case
+ * of a parsing error.
+ *
+ * @see isValid()
+ * @see isEmpty()
+ */
+ void reset();
+
+ /**
+ * @brief Parses the given string and fills the URL's values on success
+ *
+ * Treats the string as an URL.
+ *
+ * @param _url the string to parse
+ * @param encoding_hint MIB of original encoding of @p str .
+ * See QTextCodec::mibEnum()
+ */
+ void parseURL( const QString& _url, int encoding_hint = 0 );
+ /**
+ * @brief Parses the given string and fills the URL's values on success
+ *
+ * Treats the string as a generic URI.
+ *
+ * @param _url the string to parse
+ * @param encoding_hint MIB of original encoding of @p str .
+ * See QTextCodec::mibEnum()
+ */
+ void parseRawURI( const QString& _url, int encoding_hint = 0 );
+ /**
+ * @brief Parses the given string and fills the URL's values on success
+ *
+ * Treats the string as a @c "mailto:" URI.
+ *
+ * @param _url the string to parse
+ * @param encoding_hint MIB of original encoding of @p str .
+ * See QTextCodec::mibEnum()
+ */
+ void parseMailto( const QString& _url, int encoding_hint = 0 );
+ /**
+ * @brief Parses the given string and fills the URL's values on success
+ *
+ * @param _url the string to parse
+ * @param encoding_hint MIB of original encoding of @p str .
+ * See QTextCodec::mibEnum()
+ */
+ void parse( const QString& _url, int encoding_hint = 0 );
+
+private:
+ void _setQuery( const QString& _txt, int encoding_hint = 0);
+
+ QString m_strProtocol;
+ QString m_strUser;
+ QString m_strPass;
+ QString m_strHost;
+ QString m_strPath;
+ QString m_strRef_encoded;
+ QString m_strQuery_encoded;
+ bool m_bIsMalformed : 1;
+ enum URIMode m_iUriMode : 3;
+ uint freeForUse : 4;
+ unsigned short int m_iPort;
+ QString m_strPath_encoded;
+
+ friend KDECORE_EXPORT QDataStream & operator<< (QDataStream & s, const KURL & a);
+ friend KDECORE_EXPORT QDataStream & operator>> (QDataStream & s, KURL & a);
+private:
+ KURLPrivate* d;
+};
+
+/**
+ * \relates KURL
+ * Compares URLs. They are parsed, split and compared.
+ * Two malformed URLs with the same string representation
+ * are nevertheless considered to be unequal.
+ * That means no malformed URL equals anything else.
+ */
+KDECORE_EXPORT bool urlcmp( const QString& _url1, const QString& _url2 );
+
+/**
+ * \relates KURL
+ * Compares URLs. They are parsed, split and compared.
+ * Two malformed URLs with the same string representation
+ * are nevertheless considered to be unequal.
+ * That means no malformed URL equals anything else.
+ *
+ * @param _url1 A reference URL
+ * @param _url2 A URL that will be compared with the reference URL
+ * @param _ignore_trailing Described in KURL::cmp
+ * @param _ignore_ref If true, disables comparison of HTML-style references.
+ */
+KDECORE_EXPORT bool urlcmp( const QString& _url1, const QString& _url2, bool _ignore_trailing, bool _ignore_ref );
+
+KDECORE_EXPORT QDataStream & operator<< (QDataStream & s, const KURL & a);
+KDECORE_EXPORT QDataStream & operator>> (QDataStream & s, KURL & a);
+
+#endif
diff --git a/kdecore/kurldrag.cpp b/kdecore/kurldrag.cpp
new file mode 100644
index 000000000..092bf76cd
--- /dev/null
+++ b/kdecore/kurldrag.cpp
@@ -0,0 +1,294 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 "kurldrag.h"
+#include <qstrlist.h>
+#include <qdragobject.h>
+#include <qfont.h>
+#include <unistd.h>
+
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+class KURLDragPrivate
+{
+public:
+ bool m_exportAsText;
+};
+
+KURLDrag::KURLDrag( const KURL::List &urls, QWidget* dragSource, const char * name )
+ : QUriDrag(dragSource, name), m_metaData(), d( 0 )
+{
+ init(urls);
+}
+
+KURLDrag::KURLDrag( const KURL::List &urls, const QMap<QString,QString>& metaData,
+ QWidget* dragSource, const char * name )
+ : QUriDrag(dragSource, name), m_metaData(metaData), d( 0 )
+{
+ init(urls);
+}
+
+KURLDrag::~KURLDrag()
+{
+ delete d;
+}
+
+void KURLDrag::init(const KURL::List &urls)
+{
+ KURL::List::ConstIterator uit = urls.begin();
+ KURL::List::ConstIterator uEnd = urls.end();
+ // Get each URL encoded in utf8 - and since we get it in escaped
+ // form on top of that, .latin1() is fine.
+ for ( ; uit != uEnd ; ++uit )
+ {
+ m_urls.append( urlToString(*uit).latin1() );
+ }
+ setUris(m_urls);
+}
+
+void KURLDrag::setExportAsText( bool exp )
+{
+ // For now d is only used here, so create it on demand
+ if ( !d )
+ d = new KURLDragPrivate;
+ d->m_exportAsText = exp;
+}
+
+KURLDrag * KURLDrag::newDrag( const KURL::List &urls, QWidget* dragSource, const char * name )
+{
+ return new KURLDrag( urls, QMap<QString, QString>(), dragSource, name );
+}
+
+KURLDrag * KURLDrag::newDrag( const KURL::List &urls, const QMap<QString, QString>& metaData,
+ QWidget* dragSource, const char * name )
+{
+ return new KURLDrag( urls, metaData, dragSource, name );
+}
+
+bool KURLDrag::decode( const QMimeSource *e, KURL::List &uris )
+{
+ if ( e->provides( "application/x-kde-urilist" ) ) {
+ QByteArray payload = e->encodedData( "application/x-kde-urilist" );
+ if ( payload.size() ) {
+ uint c=0;
+ const char* d = payload.data();
+ while (c < payload.size() && d[c]) {
+ uint f = c;
+ // Find line end
+ while (c < payload.size() && d[c] && d[c]!='\r'
+ && d[c] != '\n')
+ c++;
+ QCString s(d+f,c-f+1);
+ if ( s[0] != '#' ) // non-comment?
+ uris.append(stringToUrl(s));
+ // Skip junk
+ while (c < payload.size() && d[c] &&
+ (d[c]=='\n' || d[c]=='\r'))
+ c++;
+ }
+ return !uris.isEmpty();
+ }
+ }
+
+ QStrList lst;
+ QUriDrag::decode( e, lst );
+ for (QStrListIterator it(lst); *it; ++it)
+ {
+ KURL url = stringToUrl( *it );
+ if ( !url.isValid() )
+ {
+ uris.clear();
+ break;
+ }
+ uris.append( url );
+ }
+ return !uris.isEmpty();
+}
+
+bool KURLDrag::decode( const QMimeSource *e, KURL::List &uris, QMap<QString,QString>& metaData )
+{
+ if ( decode( e, uris ) ) // first decode the URLs (see above)
+ {
+ QByteArray ba = e->encodedData( "application/x-kio-metadata" );
+ if ( ba.size() )
+ {
+ QString s = ba.data();
+ QStringList l = QStringList::split( "$@@$", s );
+ QStringList::ConstIterator it = l.begin();
+ bool readingKey = true; // true, then false, then true, etc.
+ QString key;
+ for ( ; it != l.end(); ++it ) {
+ if ( readingKey )
+ key = *it;
+ else
+ metaData.replace( key, *it );
+ readingKey = !readingKey;
+ }
+ Q_ASSERT( readingKey ); // an odd number of items would be, well, odd ;-)
+ }
+ return true; // Success, even if no metadata was found
+ }
+ return false; // Couldn't decode the URLs
+}
+
+#ifdef Q_WS_QWS
+bool KURLDrag::decode( QStringList const &e, KURL::List &uris )
+{
+ QStringList::ConstIterator end(e.end());
+ for(QStringList::ConstIterator it=e.begin(); it!=end; ++it)
+ {
+ KURL url = KURL( *it, 106 ); // 106 is mib enum for utf8 codec
+ if ( !url.isValid() )
+ {
+ uris.clear();
+ break;
+ }
+ uris.append( url );
+ }
+ return !uris.isEmpty();
+}
+#endif
+
+////
+
+const char * KURLDrag::format( int i ) const
+{
+ if ( i == 0 )
+ return "text/uri-list";
+ else if ( i == 1 )
+ return "application/x-kio-metadata";
+ if ( d && d->m_exportAsText == false )
+ return 0;
+ if ( i == 2 )
+ return "text/plain";
+ else if ( i == 3 ) //Support this for apps that use plain XA_STRING clipboard
+ return "text/plain;charset=ISO-8859-1";
+ else if ( i == 4 ) //Support this for apps that use the UTF_STRING clipboard
+ return "text/plain;charset=UTF-8";
+ else return 0;
+}
+
+QByteArray KURLDrag::encodedData( const char* mime ) const
+{
+ QByteArray a;
+ QCString mimetype( mime );
+ if ( mimetype == "text/uri-list" )
+ return QUriDrag::encodedData( mime );
+ else if ( mimetype == "text/plain" )
+ {
+ QStringList uris;
+ for (QStrListIterator it(m_urls); *it; ++it)
+ uris.append(stringToUrl(*it).prettyURL());
+
+ QCString s = uris.join( "\n" ).local8Bit();
+ if( uris.count() > 1 ) // terminate last line, unless it's the only line
+ s.append( "\n" );
+ a.resize( s.length());
+ memcpy( a.data(), s.data(), s.length()); // no trailing zero in clipboard text
+ }
+ else if ( mimetype.lower() == "text/plain;charset=iso-8859-1")
+ {
+ QStringList uris;
+ for (QStrListIterator it(m_urls); *it; ++it)
+ for (QStrListIterator it(m_urls); *it; ++it)
+ uris.append(stringToUrl(*it).url(0, 4)); // 4 is mib for latin1
+
+ QCString s = uris.join( "\n" ).latin1();
+ if( uris.count() > 1 )
+ s.append( "\n" );
+ a.resize( s.length());
+ memcpy( a.data(), s.data(), s.length());
+ }
+ else if ( mimetype.lower() == "text/plain;charset=utf-8")
+ {
+ QStringList uris;
+ for (QStrListIterator it(m_urls); *it; ++it)
+ uris.append(stringToUrl(*it).prettyURL());
+
+ QCString s = uris.join( "\n" ).utf8();
+ if( uris.count() > 1 )
+ s.append( "\n" );
+ a.resize( s.length());
+ memcpy( a.data(), s.data(), s.length());
+ }
+ else if ( mimetype == "application/x-kio-metadata" )
+ {
+ if ( !m_metaData.isEmpty() )
+ {
+ QString s;
+ QMap<QString,QString>::ConstIterator it;
+ for( it = m_metaData.begin(); it != m_metaData.end(); ++it )
+ {
+ s += it.key();
+ s += "$@@$";
+ s += it.data();
+ s += "$@@$";
+ }
+ a.resize( s.length() + 1 );
+ memcpy( a.data(), s.latin1(), a.size() );
+ }
+ }
+ return a;
+}
+
+KURL KURLDrag::stringToUrl(const QCString &s)
+{
+ if (strncmp(s.data(), "file:", 5) == 0)
+ return KURL(s, KGlobal::locale()->fileEncodingMib());
+
+ return KURL(s, 106); // 106 is mib enum for utf8 codec;
+}
+
+QString KURLDrag::urlToString(const KURL &url)
+{
+ if (url.isLocalFile())
+ {
+#if 1
+ return url.url(0, KGlobal::locale()->fileEncodingMib());
+#else
+ // According to the XDND spec, file:/ URLs for DND must have
+ // the hostname part. But in really it just breaks many apps,
+ // so it's disabled for now.
+ QString s = url.url(0, KGlobal::locale()->fileEncodingMib());
+ if( !s.startsWith( "file://" ))
+ {
+ char hostname[257];
+ if ( gethostname( hostname, 255 ) == 0 )
+ {
+ hostname[256] = '\0';
+ return QString( "file://" ) + hostname + s.mid( 5 );
+ }
+ }
+#endif
+ }
+
+ if ( url.protocol() == "mailto" ) {
+ return url.path();
+ }
+
+ return url.url(0, 106); // 106 is mib enum for utf8 codec
+}
+
+// deprecated ctor
+KURLDrag::KURLDrag( const QStrList & urls, const QMap<QString,QString>& metaData,
+ QWidget * dragSource, const char* name ) :
+QUriDrag( urls, dragSource, name ), m_urls( urls ), m_metaData( metaData ), d( 0 ) {}
diff --git a/kdecore/kurldrag.h b/kdecore/kurldrag.h
new file mode 100644
index 000000000..fec73f322
--- /dev/null
+++ b/kdecore/kurldrag.h
@@ -0,0 +1,165 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 __KURLDRAG_H
+#define __KURLDRAG_H
+
+#include <qstringlist.h>
+#include <qdragobject.h>
+#include <kurl.h>
+#include "kdelibs_export.h"
+class QMimeSource;
+
+class KURLDragPrivate;
+/**
+ * This class is to be used instead of QUriDrag when using KURL.
+ * The reason is: QUriDrag (and the XDND/W3C standards) expect URLs to
+ * be encoded in UTF-8 (unicode), but KURL uses the current locale
+ * by default.
+ * The other reasons for using this class are:
+ * @li it exports text/plain (for dropping/pasting into lineedits, mails etc.)
+ * @li it has support for metadata, shipped as part of the dragobject
+ * This is important, for instance to set a correct HTTP referrer (some websites
+ * require it for downloading e.g. an image).
+ *
+ * To create a drag object, use the KURLDrag constructor.
+ * To handle drops, use QUriDrag::canDecode() and KURLDrag::decode()
+ */
+class KDECORE_EXPORT KURLDrag : public QUriDrag
+{
+public:
+ /**
+ * Constructs an object to drag the list of URLs in @p urls.
+ * The @p dragSource and @p name arguments are passed on to QUriDrag,
+ * and the list of urls is converted to UTF-8 before being passed
+ * to QUriDrag.
+ * @param urls the list of URLs
+ * @param dragSource the parent of the QObject. Should be set when doing drag-n-drop,
+ * but should be 0 when copying to the clipboard
+ * @param name the name of the QObject
+ */
+ KURLDrag( const KURL::List &urls, QWidget* dragSource = 0, const char * name = 0 );
+ /**
+ * Constructs an object to drag the list of URLs in @p urls.
+ * This version also includes metadata.
+ * @param urls the list of URLs
+ * @param metaData a map containing meta data
+ * @param dragSource the parent of the QObject. Should be set when doing drag-n-drop,
+ * but should be 0 when copying to the clipboard
+ * @param name the name of the QObject
+ * @see metaData()
+ */
+ KURLDrag( const KURL::List &urls, const QMap<QString, QString>& metaData,
+ QWidget* dragSource = 0, const char * name = 0 );
+
+ virtual ~KURLDrag();
+
+ /**
+ * By default, KURLDrag also exports the URLs as plain text, for e.g. dropping onto a text editor.
+ * But in some cases this might not be wanted, e.g. if using the KURLDrag in a KMultipleDrag
+ * and another component of the multiple-drag provides better plain text data.
+ * In such a case, setExportAsText( false ) should be called.
+ * @since 3.4
+ */
+ void setExportAsText( bool exp );
+
+ /**
+ * @deprecated Is equivalent with "new KURLDrag(urls, dragSource, name)".
+ */
+ static KURLDrag * newDrag( const KURL::List &urls, QWidget* dragSource = 0, const char * name = 0 ) KDE_DEPRECATED;
+
+ /**
+ * @deprecated Is equivalent with "new KURLDrag(urls, metaData, dragSource, name)".
+ */
+ static KURLDrag * newDrag( const KURL::List &urls, const QMap<QString, QString>& metaData,
+ QWidget* dragSource = 0, const char * name = 0 ) KDE_DEPRECATED;
+
+ /**
+ * Meta-data to associate with those URLs.
+ * This is an alternative way of setting the metadata:
+ * either use the constructor to pass it all at once, or use
+ * drag->metaData()["key"] = data;
+ * @see KIO::TransferJob
+ */
+ QMap<QString, QString> &metaData() { return m_metaData; }
+
+ /**
+ * Convenience method that decodes the contents of @p e
+ * into a list of KURLs. Decoding will fail if at least one decoded value
+ * is not a valid KURL.
+ * @param e the mime source
+ * @param urls the list of urls will be written here
+ * @return true if successful, false otherwise
+ */
+ static bool decode( const QMimeSource *e, KURL::List &urls );
+
+ /**
+ * Convenience method that decodes the contents of @p e
+ * into a list of KURLs and a set of metadata. Decoding will fail if
+ * at least one decoded value is not a valid KURL.
+ * You should be using this one, if possible.
+ * @param e the mime source
+ * @param urls the list of urls will be written here
+ * @param metaData the metadata map will be written here
+ * @return true if successful, false otherwise
+ */
+ static bool decode( const QMimeSource *e, KURL::List &urls, QMap<QString,QString>& metaData );
+
+ /**
+ * Converts a URL to a string representation suitable for dragging.
+ * @since 3.2
+ */
+ static QString urlToString(const KURL &url);
+
+ /**
+ * Converts a string used for dragging to a URL.
+ * @since 3.2
+ */
+ static KURL stringToUrl(const QCString &s);
+
+#ifdef Q_WS_QWS
+ /**
+ * Convenience method that decodes the contents of @p e
+ * into a list of KURLs for Qt versions without a MIME clipboard.
+ * Decoding will fail if at least one value in the list is not a valid KURL.
+ */
+ static bool decode( QStringList const &e, KURL::List &uris );
+#endif
+
+ /// @reimp
+ virtual const char * format( int i ) const;
+ /// @reimp
+ virtual QByteArray encodedData( const char* mime ) const;
+
+protected:
+ /**
+ * @deprecated Use a KURLDrag constructor with a KURL::List
+ */
+ KURLDrag( const QStrList & urls, const QMap<QString,QString>& metaData,
+ QWidget * dragSource, const char* name ) KDE_DEPRECATED;
+
+private:
+ void init(const KURL::List &urls);
+
+ QStrList m_urls;
+ QMap<QString,QString> m_metaData;
+ KURLDragPrivate* d;
+};
+
+#endif
diff --git a/kdecore/kuser.cpp b/kdecore/kuser.cpp
new file mode 100644
index 000000000..184cedadd
--- /dev/null
+++ b/kdecore/kuser.cpp
@@ -0,0 +1,425 @@
+/*
+ * KUser - represent a user/account
+ * Copyright (C) 2002 Tim Jansen <tim@tjansen.de>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <kuser.h>
+
+#include "kstringhandler.h"
+#include <qvaluelist.h>
+#include <qstringlist.h>
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <grp.h>
+
+
+class KUserPrivate : public KShared
+{
+public:
+ bool valid;
+ long uid, gid;
+ QString loginName, fullName;
+ QString roomNumber, workPhone, homePhone;
+ QString homeDir, shell;
+
+ KUserPrivate() : valid(false) {}
+
+ KUserPrivate(long _uid,
+ long _gid,
+ const QString &_loginname,
+ const QString &_fullname,
+ const QString &_room,
+ const QString &_workPhone,
+ const QString &_homePhone,
+ const QString &_homedir,
+ const QString &_shell) :
+ valid(true),
+ uid(_uid),
+ gid(_gid),
+ loginName(_loginname),
+ fullName(_fullname),
+ roomNumber(_room),
+ workPhone(_workPhone),
+ homePhone(_homePhone),
+ homeDir(_homedir),
+ shell(_shell) {}
+};
+
+
+KUser::KUser(UIDMode mode) {
+ long _uid = ::getuid(), _euid;
+ if (mode == UseEffectiveUID && (_euid = ::geteuid()) != _uid )
+ fillPasswd( ::getpwuid( _euid ) );
+ else {
+ fillName( ::getenv( "LOGNAME" ) );
+ if (uid() != _uid) {
+ fillName( ::getenv( "USER" ) );
+ if (uid() != _uid)
+ fillPasswd( ::getpwuid( _uid ) );
+ }
+ }
+}
+
+KUser::KUser(long uid) {
+ fillPasswd( ::getpwuid( uid ) );
+}
+
+KUser::KUser(const QString& name) {
+ fillName( name.local8Bit().data() );
+}
+
+KUser::KUser(const char *name) {
+ fillName( name );
+}
+
+KUser::KUser(struct passwd *p) {
+ fillPasswd(p);
+}
+
+KUser::KUser(const KUser & user)
+ : d(user.d)
+{
+}
+
+KUser& KUser::operator =(const KUser& user)
+{
+ d = user.d;
+ return *this;
+}
+
+bool KUser::operator ==(const KUser& user) const {
+ if (isValid() != user.isValid())
+ return false;
+ if (isValid())
+ return uid() == user.uid();
+ else
+ return true;
+}
+
+bool KUser::operator !=(const KUser& user) const {
+ return !operator ==(user);
+}
+
+void KUser::fillName(const char *name) {
+ fillPasswd(name ? ::getpwnam( name ) : 0);
+}
+
+void KUser::fillPasswd(struct passwd *p) {
+ if (p) {
+ QString gecos = KStringHandler::from8Bit(p->pw_gecos);
+ QStringList gecosList = QStringList::split(',', gecos, true);
+
+ d = new KUserPrivate(p->pw_uid,
+ p->pw_gid,
+ QString::fromLocal8Bit(p->pw_name),
+ (gecosList.size() > 0) ? gecosList[0] : QString::null,
+ (gecosList.size() > 1) ? gecosList[1] : QString::null,
+ (gecosList.size() > 2) ? gecosList[2] : QString::null,
+ (gecosList.size() > 3) ? gecosList[3] : QString::null,
+ QString::fromLocal8Bit(p->pw_dir),
+ QString::fromLocal8Bit(p->pw_shell));
+ }
+ else
+ d = new KUserPrivate();
+}
+
+bool KUser::isValid() const {
+ return d->valid;
+}
+
+long KUser::uid() const {
+ if (d->valid)
+ return d->uid;
+ else
+ return -1;
+}
+
+long KUser::gid() const {
+ if (d->valid)
+ return d->gid;
+ else
+ return -1;
+}
+
+bool KUser::isSuperUser() const {
+ return uid() == 0;
+}
+
+QString KUser::loginName() const {
+ if (d->valid)
+ return d->loginName;
+ else
+ return QString::null;
+}
+
+QString KUser::fullName() const {
+ if (d->valid)
+ return d->fullName;
+ else
+ return QString::null;
+}
+
+QString KUser::roomNumber() const {
+ if (d->valid)
+ return d->roomNumber;
+ else
+ return QString::null;
+}
+
+QString KUser::workPhone() const {
+ if (d->valid)
+ return d->workPhone;
+ else
+ return QString::null;
+}
+
+QString KUser::homePhone() const {
+ if (d->valid)
+ return d->homePhone;
+ else
+ return QString::null;
+}
+
+QString KUser::homeDir() const {
+ if (d->valid)
+ return d->homeDir;
+ else
+ return QString::null;
+}
+
+QString KUser::shell() const {
+ if (d->valid)
+ return d->shell;
+ else
+ return QString::null;
+}
+
+QValueList<KUserGroup> KUser::groups() const {
+ QValueList<KUserGroup> result;
+ QValueList<KUserGroup> allGroups = KUserGroup::allGroups();
+ QValueList<KUserGroup>::const_iterator it;
+ for ( it = allGroups.begin(); it != allGroups.end(); ++it ) {
+ QValueList<KUser> users = (*it).users();
+ if ( users.find( *this ) != users.end()) {
+ result.append(*it);
+ }
+ }
+ return result;
+}
+
+QStringList KUser::groupNames() const {
+ QStringList result;
+ QValueList<KUserGroup> allGroups = KUserGroup::allGroups();
+ QValueList<KUserGroup>::const_iterator it;
+ for ( it = allGroups.begin(); it != allGroups.end(); ++it ) {
+ QValueList<KUser> users = (*it).users();
+ if ( users.find( *this ) != users.end()) {
+ result.append((*it).name());
+ }
+ }
+ return result;
+}
+
+
+QValueList<KUser> KUser::allUsers() {
+ QValueList<KUser> result;
+
+ struct passwd* p;
+
+ while ((p = getpwent())) {
+ result.append(KUser(p));
+ }
+
+ endpwent();
+
+ return result;
+}
+
+QStringList KUser::allUserNames() {
+ QStringList result;
+
+ struct passwd* p;
+
+ while ((p = getpwent())) {
+ result.append(QString::fromLocal8Bit(p->pw_name));
+ }
+
+ endpwent();
+ return result;
+}
+
+
+KUser::~KUser() {
+}
+
+class KUserGroupPrivate : public KShared
+{
+public:
+ bool valid;
+ long gid;
+ QString name;
+ QValueList<KUser> users;
+
+ KUserGroupPrivate() : valid(false) {}
+
+ KUserGroupPrivate(long _gid,
+ const QString & _name,
+ const QValueList<KUser> & _users):
+ valid(true),
+ gid(_gid),
+ name(_name),
+ users(_users) {}
+};
+
+KUserGroup::KUserGroup(KUser::UIDMode mode) {
+ KUser user(mode);
+ fillGroup(getgrgid(user.gid()));
+}
+
+KUserGroup::KUserGroup(long gid) {
+ fillGroup(getgrgid(gid));
+}
+
+KUserGroup::KUserGroup(const QString& name) {
+ fillName(name.local8Bit().data());
+}
+
+KUserGroup::KUserGroup(const char *name) {
+ fillName(name);
+}
+
+KUserGroup::KUserGroup(struct group *g) {
+ fillGroup(g);
+}
+
+
+KUserGroup::KUserGroup(const KUserGroup & group)
+ : d(group.d)
+{
+}
+
+KUserGroup& KUserGroup::operator =(const KUserGroup& group) {
+ d = group.d;
+ return *this;
+}
+
+bool KUserGroup::operator ==(const KUserGroup& group) const {
+ if (isValid() != group.isValid())
+ return false;
+ if (isValid())
+ return gid() == group.gid();
+ else
+ return true;
+}
+
+bool KUserGroup::operator !=(const KUserGroup& user) const {
+ return !operator ==(user);
+}
+
+void KUserGroup::fillName(const char *name) {
+ fillGroup(name ? ::getgrnam( name ) : 0);
+}
+
+void KUserGroup::fillGroup(struct group *p) {
+ if (!p) {
+ d = new KUserGroupPrivate();
+ return;
+ }
+
+ QString name = KStringHandler::from8Bit(p->gr_name);
+ QValueList<KUser> users;
+
+ char **user = p->gr_mem;
+ for ( ; *user; user++) {
+ KUser kUser(QString::fromLocal8Bit(*user));
+ users.append(kUser);
+ }
+
+ d = new KUserGroupPrivate(p->gr_gid,
+ QString::fromLocal8Bit(p->gr_name),
+ users);
+
+}
+
+bool KUserGroup::isValid() const {
+ return d->valid;
+}
+
+long KUserGroup::gid() const {
+ if (d->valid)
+ return d->gid;
+ else
+ return -1;
+}
+
+QString KUserGroup::name() const {
+ if (d->valid)
+ return d->name;
+ else
+ return QString::null;
+}
+
+const QValueList<KUser>& KUserGroup::users() const {
+ return d->users;
+}
+
+QStringList KUserGroup::userNames() const {
+ QStringList result;
+ QValueList<KUser>::const_iterator it;
+ for ( it = d->users.begin(); it != d->users.end(); ++it ) {
+ result.append((*it).loginName());
+ }
+ return result;
+}
+
+
+
+QValueList<KUserGroup> KUserGroup::allGroups() {
+ QValueList<KUserGroup> result;
+
+ struct group* g;
+ while ((g = getgrent())) {
+ result.append(KUserGroup(g));
+ }
+
+ endgrent();
+
+ return result;
+}
+
+QStringList KUserGroup::allGroupNames() {
+ QStringList result;
+
+ struct group* g;
+ while ((g = getgrent())) {
+ result.append(QString::fromLocal8Bit(g->gr_name));
+ }
+
+ endgrent();
+
+ return result;
+}
+
+
+KUserGroup::~KUserGroup() {
+}
+
diff --git a/kdecore/kuser.h b/kdecore/kuser.h
new file mode 100644
index 000000000..9826d994c
--- /dev/null
+++ b/kdecore/kuser.h
@@ -0,0 +1,384 @@
+/*
+ * KUser - represent a user/account
+ * Copyright (C) 2002-2003 Tim Jansen <tim@tjansen.de>
+ * Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org>
+ * Copyright (C) 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KUSER_H
+#define KUSER_H
+
+#include "ksharedptr.h"
+
+class KUserGroup;
+class QString;
+class QStringList;
+class KUserPrivate;
+struct passwd;
+template <class T> class QValueList;
+
+/**
+ * @short Represents a user on your system
+ *
+ * This class represents a user on your system. You can either get
+ * information about the current user, of fetch information about
+ * a user on the system. Instances of this class will be explicitly shared,
+ * so copying objects is very cheap and you can safely pass objects by value.
+ *
+ * @author Tim Jansen <tim@tjansen.de>
+ * @since 3.2
+ */
+class KDECORE_EXPORT KUser {
+
+public:
+
+ enum UIDMode {
+ UseEffectiveUID, ///< Use the effective user id.
+ UseRealUserID ///< Use the real user id.
+ };
+
+ /**
+ * Creates an object that contains information about the current user.
+ * (as returned by getuid(2) or geteuid(2), taking $LOGNAME/$USER into
+ * account).
+ * @param mode if #UseEffectiveUID is passed the effective
+ * user is returned.
+ * If #UseRealUserID is passed the real user will be
+ * returned.
+ * The real UID will be different than the effective UID in setuid
+ * programs; in
+ * such a case use the effective UID for checking permissions, and
+ * the real UID for displaying information about the user.
+ */
+ // XXX KDE4: Make this explicit
+ KUser(UIDMode mode = UseEffectiveUID);
+
+ /**
+ * Creates an object for the user with the given user id.
+ * If the user does not exist isValid() will return false.
+ * @param uid the user id
+ */
+ // XXX KDE4: Make this explicit; give parameter as uid_t instead of "long"
+ KUser(long uid);
+
+ /**
+ * Creates an object that contains information about the user with the given
+ * name. If the user does not exist isValid() will return false.
+ *
+ * @param name the name of the user
+ */
+ // XXX KDE4: Make this explicit
+ KUser(const QString& name);
+
+ /**
+ * Creates an object that contains information about the user with the given
+ * name. If the user does not exist isValid() will return false.
+ *
+ * @param name the name of the user
+ */
+ // XXX KDE4: Make this explicit
+ KUser(const char *name);
+
+ /**
+ * Creates an object from a passwd structure.
+ * If the pointer is null isValid() will return false.
+ *
+ * @param p the passwd structure to create the user from
+ */
+ // XXX KDE4: Make this explicit
+ KUser(struct passwd *p);
+
+ /**
+ * Creates an object from another KUser object
+ * @param user the user to create the new object from
+ */
+ KUser(const KUser & user);
+
+ /**
+ * Copies a user
+ * @param user the user to copy
+ * @return this object
+ */
+ KUser& operator =(const KUser& user);
+
+ /**
+ * Two KUser objects are equal if isValid() is true
+ * and the uid() are identical.
+ */
+ bool operator ==(const KUser& user) const;
+
+ /**
+ * Two KUser objects are not equal if either isValid() is
+ * not true or uid() are not identical.
+ */
+ bool operator !=(const KUser &user) const;
+
+ /**
+ * Returns true if the user is valid. A KUser object can be invalid if
+ * you created it with an non-existing uid or name.
+ * @return true if the user is valid
+ */
+ bool isValid() const;
+
+ /**
+ * Returns the user id of the user.
+ * @return the id of the user or -1 if user is invalid
+ */
+ // XXX KDE4: Make this return uid_t
+ long uid() const;
+
+
+ /**
+ * Returns the group id of the user.
+ * @return the id of the group or -1 if user is invalid
+ */
+ // XXX KDE4: Make this return gid_t
+ long gid() const;
+
+ /**
+ * Checks whether the user it the super user (root).
+ * @return true if the user is root
+ */
+ bool isSuperUser() const;
+
+ /**
+ * The login name of the user.
+ * @return the login name of the user or QString::null if user is invalid
+ */
+ QString loginName() const;
+
+ /**
+ * The full name of the user.
+ * @return the full name of the user or QString::null if user is invalid
+ */
+ QString fullName() const;
+
+ /**
+ * The user's room number.
+ * @return the room number of the user or QString::null if not set or the
+ * user is invalid
+ */
+ QString roomNumber() const;
+
+ /**
+ * The user's work phone.
+ * @return the work phone of the user or QString::null if not set or the
+ * user is invalid
+ */
+ QString workPhone() const;
+
+ /**
+ * The user's home phone.
+ * @return the home phone of the user or QString::null if not set or the
+ * user is invalid
+ */
+ QString homePhone() const;
+
+ /**
+ * The path to the user's home directory.
+ * @return the home directory of the user or QString::null if the
+ * user is invalid
+ */
+ QString homeDir() const;
+
+ /**
+ * The path to the user's login shell.
+ * @return the login shell of the user or QString::null if the
+ * user is invalid
+ */
+ QString shell() const;
+
+ /**
+ * Returns all groups of the user
+ * @return all groups of the user
+ */
+ QValueList<KUserGroup> groups() const;
+
+ /**
+ * Returns all group names of the user
+ * @return all group names of the user
+ */
+ QStringList groupNames() const;
+
+
+ /**
+ * Destructor.
+ */
+ ~KUser();
+
+ /**
+ * Returns all users of the system.
+ * @return all users of the system.
+ */
+ static QValueList<KUser> allUsers();
+
+ /**
+ * Returns all user names of the system.
+ * @return all user names of the system.
+ */
+ static QStringList allUserNames();
+
+private:
+ KSharedPtr<KUserPrivate> d;
+ void fillPasswd(struct passwd* p);
+ void fillName(const char* name);
+};
+
+class KUserGroupPrivate;
+
+struct group;
+
+/**
+ * @short Represents a group on your system
+ *
+ * This class represents a group on your system. You can either get
+ * information about the group of the current user, of fetch information about
+ * a group on the system. Instances of this class will be explicitly shared,
+ * so copying objects is very cheap and you can safely pass objects by value.
+ *
+ * @author Jan Schaefer <j_schaef@informatik.uni-kl.de>
+ * @since 3.3
+ */
+class KDECORE_EXPORT KUserGroup {
+
+public:
+
+ /**
+ * Create an object from the group of the current user.
+ * @param mode if #KUser::UseEffectiveUID is passed the effective user
+ * will be used. If #KUser::UseRealUserID is passed the real user
+ * will be used.
+ * The real UID will be different than the effective UID in setuid
+ * programs; in such a case use the effective UID for checking
+ * permissions, and the real UID for displaying information about
+ * the group associated with the user.
+ */
+ explicit KUserGroup(KUser::UIDMode mode = KUser::UseEffectiveUID);
+
+ /**
+ * Create an object from a group id.
+ * If the group does not exist, isValid() will return false.
+ * @param gid the group id
+ */
+ // XXX KDE4: Give parameter as gid_t instead of "long"
+ explicit KUserGroup(long gid);
+
+ /**
+ * Create an object from a group name.
+ * If the group does not exist, isValid() will return false.
+ * @param name the name of the group
+ */
+ explicit KUserGroup(const QString& name);
+
+ /**
+ * Create an object from a group name.
+ * If the group does not exist, isValid() will return false.
+ * @param name the name of the group
+ */
+ explicit KUserGroup(const char *name);
+
+ /**
+ * Creates an object from a group structure.
+ * If the pointer is null, isValid() will return false.
+ * @param g the group structure to create the group from.
+ */
+ explicit KUserGroup(struct group *g);
+
+ /**
+ * Creates a new KUserGroup instance from another KUserGroup object
+ * @param group the KUserGroup to copy
+ */
+ KUserGroup(const KUserGroup & group);
+
+ /**
+ * Copies a group
+ * @param group the group that should be copied
+ * @return this group
+ */
+ KUserGroup& operator =(const KUserGroup& group);
+
+ /**
+ * Two KUserGroup objects are equal if isValid() is true
+ * and gid() are identical
+ * @return true if the groups are identical
+ */
+ bool operator ==(const KUserGroup& group) const;
+
+ /**
+ * Two KUserGroup objects are not equal if either
+ * isValid() is not true or gid() are not identical
+ * @return true if the groups are not identical
+ */
+ bool operator !=(const KUserGroup& group) const;
+
+ /**
+ * Returns wether the group is valid.
+ * A KUserGroup object can be invalid if it is
+ * created with a non-existing gid or name.
+ * @return true if the group is valid
+ */
+ bool isValid() const;
+
+ /**
+ * Returns the group id of the group.
+ * @return the group id of the group or -1 if the group is invalid
+ */
+ // XXX KDE4: Return gid_t instead of "long"
+ long gid() const;
+
+ /**
+ * The name of the group.
+ * @return the name of the group
+ */
+ QString name() const;
+
+ /**
+ * Returns a list of all users of the group.
+ * @return a list of all users of the group
+ */
+ const QValueList<KUser>& users() const;
+
+ /**
+ * Returns a list of all user login names of the group.
+ * @return a list of all user login names of the group
+ */
+ QStringList userNames() const;
+
+
+ /**
+ * Destructor.
+ */
+ ~KUserGroup();
+
+ /**
+ * Returns a list of all groups on this system
+ */
+ static QValueList<KUserGroup> allGroups();
+
+ /**
+ * Returns a list of all group names on this system
+ */
+ static QStringList allGroupNames();
+
+private:
+ KSharedPtr<KUserGroupPrivate> d;
+ void fillGroup(struct group* g);
+ void fillName(const char* name);
+};
+
+
+#endif
diff --git a/kdecore/kvmallocator.cpp b/kdecore/kvmallocator.cpp
new file mode 100644
index 000000000..21d418434
--- /dev/null
+++ b/kdecore/kvmallocator.cpp
@@ -0,0 +1,274 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+//----------------------------------------------------------------------------
+//
+// Virtual Memory Allocator
+
+// TODO: Add large file support.
+// TODO: Error reporting. (e.g. disk-full)
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include <qintdict.h>
+#include <qmap.h>
+
+#include <ktempfile.h>
+#include <kdebug.h>
+
+#include "kvmallocator.h"
+
+
+#define KVM_ALIGN 4095
+
+struct KVMAllocator::Block
+{
+ off_t start;
+ size_t length; // Requested length
+ size_t size; // Actual size
+ void *mmap;
+};
+
+
+class KVMAllocatorPrivate
+{
+public:
+ KTempFile *tempfile;
+ off_t max_length;
+ QMap<off_t, KVMAllocator::Block> used_blocks;
+ QMap<off_t, KVMAllocator::Block> free_blocks;
+};
+
+/**
+ * Create a KVMAllocator
+ */
+KVMAllocator::KVMAllocator()
+{
+ d = new KVMAllocatorPrivate;
+ d->tempfile = 0;
+ d->max_length = 0;
+}
+
+/**
+ * Destruct the KVMAllocator and release all memory.
+ */
+KVMAllocator::~KVMAllocator()
+{
+ delete d->tempfile;
+ delete d;
+}
+
+/**
+ * Allocate a virtual memory block.
+ * @param _size Size in bytes of the memory block.
+ */
+KVMAllocator::Block *
+KVMAllocator::allocate(size_t _size)
+{
+ if (!d->tempfile)
+ {
+ d->tempfile = new KTempFile(QString::null, "vmdata");
+ d->tempfile->unlink();
+ }
+ // Search in free list
+ QMap<off_t,KVMAllocator::Block>::iterator it;
+ it = d->free_blocks.begin();
+ while (it != d->free_blocks.end())
+ {
+ if (it.data().size > _size)
+ {
+ Block &free_block = it.data();
+ Block block;
+ kdDebug(180)<<"VM alloc: using block from free list "<<(long)free_block.start<<" size ="<<(long)free_block.size<<" request = "<<_size<< endl;
+ block.start = free_block.start;
+ block.length = _size;
+ block.size = (_size + KVM_ALIGN) & ~KVM_ALIGN;
+ block.mmap = 0;
+ free_block.size -= block.size;
+ free_block.start += block.size;
+ if (!free_block.size)
+ d->free_blocks.remove(it);
+ it = d->used_blocks.replace(block.start, block);
+ return &(it.data());
+ }
+ ++it;
+ }
+
+
+ // Create new block
+ Block block;
+ block.start = d->max_length;
+ block.length = _size;
+ block.size = (_size + KVM_ALIGN) & ~KVM_ALIGN;
+ block.mmap = 0;
+ kdDebug(180)<<"VM alloc: using new block "<<(long)block.start<<" size ="<<(long)block.size<<" request = "<<_size<< endl;
+ it = d->used_blocks.replace(block.start, block);
+ d->max_length += block.size;
+ return &(it.data());
+}
+
+/**
+ * Free a virtual memory block
+ */
+void
+KVMAllocator::free(Block *block_p)
+{
+ Block block = *block_p;
+ if (block.mmap)
+ {
+ kdDebug(180)<<"VM free: Block "<<(long)block.start<<" is still mmapped!"<<endl;
+ return;
+ }
+ QMap<off_t,KVMAllocator::Block>::iterator it;
+ it = d->used_blocks.find(block.start);
+ if (it == d->used_blocks.end())
+ {
+ kdDebug(180)<<"VM free: Block "<<(long)block.start<<" is not allocated."<<endl;
+ return;
+ }
+ d->used_blocks.remove(it);
+ it = d->free_blocks.replace(block.start, block);
+ QMap<off_t,KVMAllocator::Block>::iterator before = it;
+ --before;
+ if (before != d->free_blocks.end())
+ {
+ Block &block_before = before.data();
+ if ((block_before.start + off_t(block_before.size)) == block.start)
+ {
+ // Merge blocks.
+ kdDebug(180) << "VM merging: Block "<< (long)block_before.start<<
+ " with "<< (long)block.start<< " (before)" << endl;
+ block.size += block_before.size;
+ block.start = block_before.start;
+ it.data() = block;
+ d->free_blocks.remove(before);
+ }
+ }
+
+ QMap<off_t,KVMAllocator::Block>::iterator after = it;
+ ++after;
+ if (after != d->free_blocks.end())
+ {
+ Block &block_after = after.data();
+ if ((block.start + off_t(block.size)) == block_after.start)
+ {
+ // Merge blocks.
+ kdDebug(180) << "VM merging: Block "<< (long)block.start<<
+ " with "<< (long)block_after.start<< " (after)" << endl;
+ block.size += block_after.size;
+ it.data() = block;
+ d->free_blocks.remove(after);
+ }
+ }
+}
+
+/**
+ * Copy data from a virtual memory block to normal memory
+ */
+void
+KVMAllocator::copy(void *dest, Block *src, int _offset, size_t length)
+{
+ (void) copyBlock(dest, src, _offset, length);
+}
+
+bool
+KVMAllocator::copyBlock(void *dest, Block *src, int _offset, size_t length)
+{
+ //kdDebug(180)<<"VM read: seek "<<(long)src->start<<" +"<<_offset<<":"<<length<<endl;
+ lseek(d->tempfile->handle(), src->start+_offset, SEEK_SET);
+ if (length == 0)
+ length = src->length - _offset;
+ int to_go = length;
+ int done = 0;
+ char *buf = (char *) dest;
+ while(to_go > 0)
+ {
+ int n = read(d->tempfile->handle(), buf+done, to_go);
+ if (n <= 0)
+ {
+ if (n < 0)
+ return false; // Error
+ else
+ return true; // End of data
+ }
+ done += n;
+ to_go -= n;
+ }
+ // Done.
+ return true;
+}
+
+/**
+ * Copy data from normal memory to a virtual memory block
+ */
+void
+KVMAllocator::copy(Block *dest, void *src, int _offset, size_t length)
+{
+ (void) copyBlock(dest, src, _offset, length);
+}
+
+bool
+KVMAllocator::copyBlock(Block *dest, void *src, int _offset, size_t length)
+{
+ //kdDebug(180)<<"VM write: seek "<<(long)dest->start<<" +"<<_offset<< ":" << length << endl;
+ lseek(d->tempfile->handle(), dest->start+_offset, SEEK_SET);
+ if (length == 0)
+ length = dest->length - _offset;
+ int to_go = length;
+ int done = 0;
+ char *buf = (char *) src;
+ while(to_go > 0)
+ {
+ int n = write(d->tempfile->handle(), buf+done, to_go);
+ if (n <= 0) return false; // Error
+ done += n;
+ to_go -= n;
+ }
+ // Done.
+ return true;
+}
+
+/**
+ * Map a virtual memory block in memory
+ */
+void *
+KVMAllocator::map(Block *block)
+{
+ if (block->mmap)
+ return block->mmap;
+
+ void *result = mmap(0, block->length, PROT_READ| PROT_WRITE,
+ MAP_SHARED, d->tempfile->handle(), block->start);
+ block->mmap = result;
+ return block->mmap;
+}
+
+/**
+ * Unmap a virtual memory block
+ */
+void
+KVMAllocator::unmap(Block *block)
+{
+ // The following cast is necassery for Solaris.
+ // (touch it and die). --Waba
+ munmap((char *)block->mmap, block->length);
+ block->mmap = 0;
+}
diff --git a/kdecore/kvmallocator.h b/kdecore/kvmallocator.h
new file mode 100644
index 000000000..50ce78e8d
--- /dev/null
+++ b/kdecore/kvmallocator.h
@@ -0,0 +1,119 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (C) 2000 Waldo Bastian (bastian@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+//----------------------------------------------------------------------------
+//
+// KDE Virtual Memory Allocator
+
+#ifndef KVMALLOCATOR_H
+#define KVMALLOCATOR_H
+
+#include <sys/types.h>
+#include "kdelibs_export.h"
+
+class KVMAllocatorPrivate;
+
+/**
+ * KVMAllocator is a virtual memory allocator.
+ * Memory is allocated block-wise in a tmp file.
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ */
+class KDECORE_EXPORT KVMAllocator
+{
+public:
+ struct Block;
+
+ /**
+ * Create a KVMAllocator
+ */
+ KVMAllocator();
+
+ /**
+ * Destruct the KVMAllocator and release all memory.
+ */
+ ~KVMAllocator();
+
+ /**
+ * Allocate a virtual memory block.
+ * @param _size Size in bytes of the memory block.
+ * @return the allocated memory block
+ */
+ Block *allocate(size_t _size);
+
+ /**
+ * Free a virtual memory block.
+ * @param block the block to free
+ */
+ void free(Block *block);
+
+ /**
+ * Copy @p length bytes from @p _offset in the virtual memory block
+ * @p src to normal memory at address *dest.
+ * @param dest the destination of the data
+ * @param src the source block
+ * @param _offset the offset in the source block
+ * @param length the length of the data to copy
+ * @return true on success, false on failure, see errno for details
+ * @since 3.2
+ */
+ bool copyBlock(void *dest, Block *src, int _offset = 0, size_t length = 0);
+
+ /**
+ * @deprecated
+ * @see copyBlock
+ */
+ void copy(void *dest, Block *src, int _offset = 0, size_t length = 0) KDE_DEPRECATED;
+
+ /**
+ * Copy @p length bytes from normal memory at address @p src to
+ * @p _offset in the virtual memory block @p dest.
+ * @param dest the block to copy the data to
+ * @param src the source location of the data
+ * @param _offset the offset in the destination block
+ * @param length the length of the data to copy
+ * @return true on success, false on failure, see errno for details
+ * @since 3.2
+ */
+ bool copyBlock(Block *dest, void *src, int _offset = 0, size_t length = 0);
+
+ /**
+ * @deprecated
+ * @see copyBlock
+ */
+ void copy(Block *dest, void *src, int _offset = 0, size_t length = 0) KDE_DEPRECATED;
+
+ /**
+ * Map a virtual memory block in memory
+ * @param block the block to map
+ */
+ void *map(Block *block);
+
+ /**
+ * Unmap a virtual memory block
+ * @param block the block to unmap
+ */
+ void unmap(Block *block);
+
+private:
+ KVMAllocatorPrivate *d;
+};
+
+#endif
diff --git a/kdecore/kwin.cpp b/kdecore/kwin.cpp
new file mode 100644
index 000000000..1e94b99db
--- /dev/null
+++ b/kdecore/kwin.cpp
@@ -0,0 +1,1269 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
+
+ $Id$
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYSENT_H
+#include <sysent.h>
+#endif
+
+#include <kuniqueapplication.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qwhatsthis.h>
+#include <qcstring.h>
+#include <qdialog.h>
+
+#include "config.h"
+#include "kwin.h"
+#include "kapplication.h"
+
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include <kdatastream.h>
+#include <klocale.h>
+#include <dcopclient.h>
+#include <dcopref.h>
+#ifdef Q_WS_X11
+#include <kstartupinfo.h>
+#include <kxerrorhandler.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#include "netwm.h"
+
+static bool atoms_created = false;
+extern Atom qt_wm_protocols;
+extern Time qt_x_time;
+extern Time qt_x_user_time;
+
+static Atom net_wm_context_help;
+static Atom kde_wm_change_state;
+static Atom kde_wm_window_opacity;
+static Atom kde_wm_window_shadow;
+static Atom kwin_UTF8_STRING;
+static Atom net_wm_cm;
+
+static void kwin_net_create_atoms() {
+ if (!atoms_created){
+ const int max = 20;
+ Atom* atoms[max];
+ const char* names[max];
+ Atom atoms_return[max];
+ int n = 0;
+
+ atoms[n] = &net_wm_context_help;
+ names[n++] = "_NET_WM_CONTEXT_HELP";
+
+ atoms[n] = &kde_wm_change_state;
+ names[n++] = "_KDE_WM_CHANGE_STATE";
+
+ atoms[n] = &kde_wm_window_opacity;
+ names[n++] = (char*) "_KDE_WM_WINDOW_OPACITY";
+
+ atoms[n] = &kde_wm_window_shadow;
+ names[n++] = (char*) "_KDE_WM_WINDOW_SHADOW";
+
+ char net_wm_cm_name[ 100 ];
+ sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( qt_xdisplay()));
+ atoms[n] = &net_wm_cm;
+ names[n++] = net_wm_cm_name;
+
+ // we need a const_cast for the shitty X API
+ XInternAtoms( qt_xdisplay(), const_cast<char**>(names), n, false, atoms_return );
+ for (int i = 0; i < n; i++ )
+ *atoms[i] = atoms_return[i];
+
+ atoms_created = True;
+ }
+}
+#endif
+
+/*
+ Sends a client message to the ROOT window.
+ */
+#ifdef Q_WS_X11
+static void sendClientMessageToRoot(Window w, Atom a, long x, long y = 0, long z = 0 ){
+ 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] = x;
+ ev.xclient.data.l[1] = y;
+ ev.xclient.data.l[2] = z;
+ mask = SubstructureRedirectMask;
+ XSendEvent(qt_xdisplay(), qt_xrootwin(), False, mask, &ev);
+}
+#endif
+
+/*
+ Send a client message to window w
+ */
+#ifdef Q_WS_X11
+static void sendClientMessage(Window w, Atom a, long x){
+ 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] = x;
+ ev.xclient.data.l[1] = CurrentTime;
+ mask = 0L;
+ if (w == qt_xrootwin())
+ mask = SubstructureRedirectMask; /* magic! */
+ XSendEvent(qt_xdisplay(), w, False, mask, &ev);
+}
+#endif
+
+bool KWin::compositingActive()
+{
+#ifdef Q_WS_X11
+ kwin_net_create_atoms();
+ return XGetSelectionOwner( qt_xdisplay(), net_wm_cm ) != None;
+#else
+ return false;
+#endif
+}
+
+#ifdef Q_WS_X11
+namespace
+{
+class ContextWidget : public QWidget
+{
+public:
+ ContextWidget();
+ virtual bool x11Event( XEvent * ev);
+};
+
+ContextWidget::ContextWidget()
+ : QWidget(0,0)
+ {
+ kwin_net_create_atoms();
+ kapp->installX11EventFilter( this );
+ QWhatsThis::enterWhatsThisMode();
+ QCursor c = *QApplication::overrideCursor();
+ QWhatsThis::leaveWhatsThisMode();
+ XGrabPointer( qt_xdisplay(), qt_xrootwin(), true,
+ (uint)( ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | EnterWindowMask |
+ LeaveWindowMask ),
+ GrabModeAsync, GrabModeAsync,
+ None, c.handle(), CurrentTime );
+ qApp->enter_loop();
+ }
+
+
+bool ContextWidget::x11Event( XEvent * ev)
+ {
+ if ( ev->type == ButtonPress && ev->xbutton.button == Button1 ) {
+ XUngrabPointer( qt_xdisplay(), ev->xbutton.time );
+ Window root;
+ Window child = qt_xrootwin();
+ int root_x, root_y, lx, ly;
+ uint state;
+ Window w;
+ do {
+ w = child;
+ XQueryPointer( qt_xdisplay(), w, &root, &child,
+ &root_x, &root_y, &lx, &ly, &state );
+ } while ( child != None && child != w );
+
+ ::sendClientMessage(w, qt_wm_protocols, net_wm_context_help);
+ XEvent e = *ev;
+ e.xbutton.window = w;
+ e.xbutton.subwindow = w;
+ e.xbutton.x = lx;
+ e.xbutton.y = ly;
+ XSendEvent( qt_xdisplay(), w, true, ButtonPressMask, &e );
+ qApp->exit_loop();
+ return true;
+ }
+ return false;
+ }
+} // namespace
+#endif
+
+void KWin::invokeContextHelp()
+{
+#ifdef Q_WS_X11
+ ContextWidget w;
+#endif
+}
+
+void KWin::setSystemTrayWindowFor( WId trayWin, WId forWin )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), trayWin, qt_xrootwin(), 0 );
+ if ( !forWin )
+ forWin = qt_xrootwin();
+ info.setKDESystemTrayWinFor( forWin );
+ NETRootInfo rootinfo( qt_xdisplay(), NET::Supported );
+ if( !rootinfo.isSupported( NET::WMKDESystemTrayWinFor )) {
+ DCOPRef ref( "kded", "kded" );
+ if( !ref.send( "loadModule", QCString( "kdetrayproxy" )))
+ kdWarning( 176 ) << "Loading of kdetrayproxy failed." << endl;
+ }
+#endif
+}
+
+void KWin::activateWindow( WId win, long time )
+{
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), 0 );
+ if( time == 0 )
+ time = qt_x_user_time;
+ info.setActiveWindow( win, NET::FromApplication, time,
+ kapp->activeWindow() ? kapp->activeWindow()->winId() : 0 );
+#endif // Q_WS_X11 ...
+ KUniqueApplication::setHandleAutoStarted();
+}
+
+void KWin::forceActiveWindow( WId win, long time )
+{
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), 0 );
+ if( time == 0 )
+ time = qt_x_time;
+ info.setActiveWindow( win, NET::FromTool, time, 0 );
+#endif // Q_WS_X11
+ KUniqueApplication::setHandleAutoStarted();
+}
+
+void KWin::setActiveWindow( WId win )
+{
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), 0 );
+ info.setActiveWindow( win, NET::FromUnknown, 0, 0 );
+#endif
+ KUniqueApplication::setHandleAutoStarted();
+}
+
+void KWin::demandAttention( WId win, bool set )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
+ info.setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
+#endif
+}
+
+void KWin::setUserTime( WId win, long time )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
+ info.setUserTime( time );
+#endif
+}
+
+KWin::WindowInfo KWin::windowInfo( WId win, unsigned long properties, unsigned long properties2 )
+{
+ return WindowInfo( win, properties, properties2 );
+}
+
+
+WId KWin::transientFor( WId win )
+{
+#ifdef Q_WS_X11
+ KXErrorHandler handler; // ignore badwindow
+ Window transient_for = None;
+ if( XGetTransientForHint( qt_xdisplay(), win, &transient_for ))
+ return transient_for;
+ // XGetTransientForHint() did sync
+ return None;
+#else
+ return 0L;
+#endif
+}
+
+void KWin::setMainWindow( QWidget* subwindow, WId mainwindow )
+{
+#ifdef Q_WS_X11
+ if( mainwindow != 0 )
+ {
+ /*
+ Grmbl. See QDialog::show(). That should get fixed in Qt somehow.
+ */
+ if( qt_cast< QDialog* >( subwindow ) != NULL
+ && subwindow->parentWidget() == NULL
+ && kapp->mainWidget() != NULL )
+ {
+ kdWarning() << "KWin::setMainWindow(): There either mustn't be kapp->mainWidget(),"
+ " or the dialog must have a non-NULL parent, otherwise Qt will reset the change. Bummer." << endl;
+ }
+ XSetTransientForHint( qt_xdisplay(), subwindow->winId(), mainwindow );
+ }
+ else
+ XDeleteProperty( qt_xdisplay(), subwindow->winId(), XA_WM_TRANSIENT_FOR );
+#endif
+}
+
+WId KWin::groupLeader( WId win )
+{
+#ifdef Q_WS_X11
+ KXErrorHandler handler; // ignore badwindow
+ XWMHints *hints = XGetWMHints( qt_xdisplay(), win );
+ Window window_group = None;
+ if ( hints )
+ {
+ if( hints->flags & WindowGroupHint )
+ window_group = hints->window_group;
+ XFree( reinterpret_cast< char* >( hints ));
+ }
+ // XGetWMHints() did sync
+ return window_group;
+#else
+ return 0L;
+#endif
+}
+
+// this one is deprecated, KWin::WindowInfo should be used instead
+KWin::Info KWin::info( WId win )
+{
+ Info w;
+#ifdef Q_WS_X11
+ NETWinInfo inf( qt_xdisplay(), win, qt_xrootwin(),
+ NET::WMState |
+ NET::WMStrut |
+ NET::WMWindowType |
+ NET::WMName |
+ NET::WMVisibleName |
+ NET::WMDesktop |
+ NET::WMPid |
+ NET::WMKDEFrameStrut |
+ NET::XAWMState
+ );
+
+ w.win = win;
+ w.state = inf.state();
+ w.mappingState = inf.mappingState();
+ w.strut = inf.strut();
+ w.windowType = inf.windowType( -1U );
+ if ( inf.name() ) {
+ w.name = QString::fromUtf8( inf.name() );
+ } else {
+ char* c = 0;
+ if ( XFetchName( qt_xdisplay(), win, &c ) != 0 ) {
+ w.name = QString::fromLocal8Bit( c );
+ XFree( c );
+ }
+ }
+ if ( inf.visibleName() )
+ w.visibleName = QString::fromUtf8( inf.visibleName() );
+ else
+ w.visibleName = w.name;
+
+ w.desktop = inf.desktop();
+ w.onAllDesktops = inf.desktop() == NETWinInfo::OnAllDesktops;
+ w.pid = inf.pid();
+ NETRect frame, geom;
+ inf.kdeGeometry( frame, geom );
+ w.geometry.setRect( geom.pos.x, geom.pos.y, geom.size.width, geom.size.height );
+ w.frameGeometry.setRect( frame.pos.x, frame.pos.y, frame.size.width, frame.size.height );
+#endif
+ return w;
+}
+
+QPixmap KWin::icon( WId win, int width, int height, bool scale )
+{
+ return icon( win, width, height, scale, NETWM | WMHints | ClassHint | XApp );
+}
+
+
+QPixmap KWin::icon( WId win, int width, int height, bool scale, int flags )
+{
+#ifdef Q_WS_X11
+ KXErrorHandler handler; // ignore badwindow
+#endif
+ QPixmap result;
+#ifdef Q_WS_X11
+ if( flags & NETWM ) {
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMIcon );
+ NETIcon ni = info.icon( width, height );
+ if ( ni.data && ni.size.width > 0 && ni.size.height > 0 ) {
+ QImage img( (uchar*) ni.data, (int) ni.size.width, (int) ni.size.height, 32, 0, 0, QImage::IgnoreEndian );
+ img.setAlphaBuffer( true );
+ if ( scale && width > 0 && height > 0 &&img.size() != QSize( width, height ) && !img.isNull() )
+ img = img.smoothScale( width, height );
+ if ( !img.isNull() )
+ result.convertFromImage( img );
+ return result;
+ }
+ }
+
+ if( flags & WMHints ) {
+ Pixmap p = None;
+ Pixmap p_mask = None;
+
+ XWMHints *hints = XGetWMHints(qt_xdisplay(), win );
+ if (hints && (hints->flags & IconPixmapHint)){
+ p = hints->icon_pixmap;
+ }
+ if (hints && (hints->flags & IconMaskHint)){
+ p_mask = hints->icon_mask;
+ }
+ if (hints)
+ XFree((char*)hints);
+
+ if (p != None){
+ Window root;
+ int x, y;
+ unsigned int w = 0;
+ unsigned int h = 0;
+ unsigned int border_w, depth;
+ XGetGeometry(qt_xdisplay(), p, &root,
+ &x, &y, &w, &h, &border_w, &depth);
+ if (w > 0 && h > 0){
+ QPixmap pm(w, h, depth);
+ // Always detach before doing something behind QPixmap's back.
+ pm.detach();
+ XCopyArea(qt_xdisplay(), p, pm.handle(),
+ qt_xget_temp_gc(qt_xscreen(), depth==1),
+ 0, 0, w, h, 0, 0);
+ if (p_mask != None){
+ QBitmap bm(w, h);
+ XCopyArea(qt_xdisplay(), p_mask, bm.handle(),
+ qt_xget_temp_gc(qt_xscreen(), true),
+ 0, 0, w, h, 0, 0);
+ pm.setMask(bm);
+ }
+ if ( scale && width > 0 && height > 0 && !pm.isNull() &&
+ ( (int) w != width || (int) h != height) ){
+ result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
+ } else {
+ result = pm;
+ }
+ }
+ }
+ }
+
+ // Since width can be any arbitrary size, but the icons cannot,
+ // take the nearest value for best results (ignoring 22 pixel
+ // icons as they don't exist for apps):
+ int iconWidth;
+ if( width < 24 )
+ iconWidth = 16;
+ else if( width < 40 )
+ iconWidth = 32;
+ else
+ iconWidth = 48;
+
+ if( flags & ClassHint ) {
+ // Try to load the icon from the classhint if the app didn't specify
+ // its own:
+ if( result.isNull() ) {
+
+ XClassHint hint;
+ if( XGetClassHint( qt_xdisplay(), win, &hint ) ) {
+ QString className = hint.res_class;
+
+ QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( className.lower(), KIcon::Small, iconWidth,
+ KIcon::DefaultState, 0, true );
+ if( scale && !pm.isNull() )
+ result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
+ else
+ result = pm;
+
+ XFree( hint.res_name );
+ XFree( hint.res_class );
+ }
+ }
+ }
+
+ if( flags & XApp ) {
+ // If the icon is still a null pixmap, load the 'xapp' icon
+ // as a last resort:
+ if ( result.isNull() ) {
+ QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( "xapp", KIcon::Small, iconWidth,
+ KIcon::DefaultState, 0, true );
+ if( scale && !pm.isNull() )
+ result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
+ else
+ result = pm;
+ }
+ }
+#endif
+ return result;
+}
+
+void KWin::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
+{
+#ifdef Q_WS_X11
+ if ( icon.isNull() )
+ return;
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
+ QImage img = icon.convertToImage().convertDepth( 32 );
+ NETIcon ni;
+ ni.size.width = img.size().width();
+ ni.size.height = img.size().height();
+ ni.data = (unsigned char *) img.bits();
+ info.setIcon( ni, true );
+ if ( miniIcon.isNull() )
+ return;
+ img = miniIcon.convertToImage().convertDepth( 32 );
+ ni.size.width = img.size().width();
+ ni.size.height = img.size().height();
+ ni.data = (unsigned char *) img.bits();
+ info.setIcon( ni, false );
+#endif
+}
+
+void KWin::setType( WId win, NET::WindowType windowType )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
+ info.setWindowType( windowType );
+#endif
+}
+
+void KWin::setState( WId win, unsigned long state )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
+ info.setState( state, state );
+#endif
+}
+
+void KWin::clearState( WId win, unsigned long state )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
+ info.setState( 0, state );
+#endif
+}
+
+void KWin::setOpacity( WId win, uint percent )
+{
+#ifdef Q_WS_X11
+ kwin_net_create_atoms();
+ if (percent > 99)
+ XDeleteProperty (qt_xdisplay(), win, kde_wm_window_opacity);
+ else
+ {
+ long opacity = long(0xFFFFFFFF/100.0*percent);
+ XChangeProperty(qt_xdisplay(), win, kde_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &opacity, 1L);
+ }
+#endif
+}
+
+void KWin::setShadowSize( WId win, uint percent )
+{
+#ifdef Q_WS_X11
+ kwin_net_create_atoms();
+ long shadowSize = long(0xFFFFFFFF/100.0*percent);
+ XChangeProperty(qt_xdisplay(), win, kde_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &shadowSize, 1L);
+#endif
+}
+
+void KWin::setOnAllDesktops( WId win, bool b )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
+ if ( b )
+ info.setDesktop( NETWinInfo::OnAllDesktops );
+ else if ( info.desktop() == NETWinInfo::OnAllDesktops ) {
+ NETRootInfo rinfo( qt_xdisplay(), NET::CurrentDesktop );
+ info.setDesktop( rinfo.currentDesktop() );
+ }
+#endif
+}
+
+void KWin::setOnDesktop( WId win, int desktop )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
+ info.setDesktop( desktop );
+#endif
+}
+
+void KWin::setExtendedStrut( WId win, int left_width, int left_start, int left_end,
+ int right_width, int right_start, int right_end, int top_width, int top_start, int top_end,
+ int bottom_width, int bottom_start, int bottom_end )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
+ NETExtendedStrut strut;
+ strut.left_width = left_width;
+ strut.right_width = right_width;
+ strut.top_width = top_width;
+ strut.bottom_width = bottom_width;
+ strut.left_start = left_start;
+ strut.left_end = left_end;
+ strut.right_start = right_start;
+ strut.right_end = right_end;
+ strut.top_start = top_start;
+ strut.top_end = top_end;
+ strut.bottom_start = bottom_start;
+ strut.bottom_end = bottom_end;
+ info.setExtendedStrut( strut );
+#endif
+}
+
+void KWin::setStrut( WId win, int left, int right, int top, int bottom )
+{
+#ifdef Q_WS_X11
+ NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
+ NETStrut strut;
+ strut.left = left;
+ strut.right = right;
+ strut.top = top;
+ strut.bottom = bottom;
+ info.setStrut( strut );
+#endif
+}
+
+int KWin::currentDesktop()
+{
+#ifdef Q_WS_X11
+ if (!qt_xdisplay())
+#endif
+ return 1;
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
+ return info.currentDesktop();
+#endif
+}
+
+int KWin::numberOfDesktops()
+{
+#ifdef Q_WS_X11
+ if (!qt_xdisplay())
+#endif
+ return 0;
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), NET::NumberOfDesktops );
+ return info.numberOfDesktops();
+#endif
+}
+
+void KWin::setCurrentDesktop( int desktop )
+{
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
+ info.setCurrentDesktop( desktop );
+#endif
+}
+
+void KWin::setCurrentDesktopViewport( int desktop, QPoint viewport )
+{
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
+ NETPoint netview;
+ netview.x = viewport.x();
+ netview.y = viewport.y();
+ info.setDesktopViewport( desktop, netview );
+#endif
+}
+
+void KWin::iconifyWindow( WId win, bool animation)
+{
+#ifdef Q_WS_X11
+ if ( !animation )
+ {
+ kwin_net_create_atoms();
+ sendClientMessageToRoot( win, kde_wm_change_state, IconicState, 1 );
+ }
+ XIconifyWindow( qt_xdisplay(), win, qt_xscreen() );
+#endif
+}
+
+
+void KWin::deIconifyWindow( WId win, bool animation )
+{
+#ifdef Q_WS_X11
+ if ( !animation )
+ {
+ kwin_net_create_atoms();
+ sendClientMessageToRoot( win, kde_wm_change_state, NormalState, 1 );
+ }
+ XMapWindow( qt_xdisplay(), win );
+#endif
+}
+
+void KWin::raiseWindow( WId win )
+{
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), NET::Supported );
+ if( info.isSupported( NET::WM2RestackWindow ))
+ info.restackRequest( win, None, Above );
+ else
+ XRaiseWindow( qt_xdisplay(), win );
+#endif
+}
+
+void KWin::lowerWindow( WId win )
+{
+#ifdef Q_WS_X11
+ NETRootInfo info( qt_xdisplay(), NET::Supported );
+ if( info.isSupported( NET::WM2RestackWindow ))
+ info.restackRequest( win, None, Below );
+ else
+ XLowerWindow( qt_xdisplay(), win );
+#endif
+}
+
+void KWin::appStarted()
+{
+#ifdef Q_WS_X11
+ KStartupInfo::appStarted();
+#endif
+}
+
+class KWin::WindowInfoPrivate
+{
+ public:
+ WindowInfoPrivate()
+#ifdef Q_WS_X11
+ : info( NULL )
+#endif
+ {}
+#ifdef Q_WS_X11
+ ~WindowInfoPrivate() { delete info; }
+ NETWinInfo* info;
+#endif
+ WId win_;
+ QString name_;
+ QString iconic_name_;
+ QRect geometry_;
+ QRect frame_geometry_;
+ int ref;
+ bool valid;
+ private:
+ WindowInfoPrivate( const WindowInfoPrivate& );
+ void operator=( const WindowInfoPrivate& );
+};
+
+// KWin::info() should be updated too if something has to be changed here
+KWin::WindowInfo::WindowInfo( WId win, unsigned long properties, unsigned long properties2 )
+{
+#ifdef Q_WS_X11
+ KXErrorHandler handler;
+ d = new WindowInfoPrivate;
+ d->ref = 1;
+ if( properties == 0 )
+ properties = NET::WMState |
+ NET::WMStrut |
+ NET::WMWindowType |
+ NET::WMName |
+ NET::WMVisibleName |
+ NET::WMIconName |
+ NET::WMVisibleIconName |
+ NET::WMDesktop |
+ NET::WMPid |
+ NET::WMKDEFrameStrut |
+ NET::XAWMState |
+ NET::WMGeometry;
+ if( properties & NET::WMVisibleIconName )
+ properties |= NET::WMIconName | NET::WMVisibleName; // force, in case it will be used as a fallback
+ if( properties & NET::WMVisibleName )
+ properties |= NET::WMName; // force, in case it will be used as a fallback
+ if( properties2 & NET::WM2ExtendedStrut )
+ properties |= NET::WMStrut; // will be used as fallback
+ properties |= NET::XAWMState; // force to get error detection for valid()
+ unsigned long props[ 2 ] = { properties, properties2 };
+ d->info = new NETWinInfo( qt_xdisplay(), win, qt_xrootwin(), props, 2 );
+ d->win_ = win;
+ if( properties & NET::WMName ) {
+ if( d->info->name() && d->info->name()[ 0 ] != '\0' )
+ d->name_ = QString::fromUtf8( d->info->name() );
+ else
+ d->name_ = readNameProperty( win, XA_WM_NAME );
+ }
+ if( properties & NET::WMIconName ) {
+ if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' )
+ d->iconic_name_ = QString::fromUtf8( d->info->iconName());
+ else
+ d->iconic_name_ = readNameProperty( win, XA_WM_ICON_NAME );
+ }
+ if( properties & ( NET::WMGeometry | NET::WMKDEFrameStrut )) {
+ NETRect frame, geom;
+ d->info->kdeGeometry( frame, geom );
+ d->geometry_.setRect( geom.pos.x, geom.pos.y, geom.size.width, geom.size.height );
+ d->frame_geometry_.setRect( frame.pos.x, frame.pos.y, frame.size.width, frame.size.height );
+ }
+ d->valid = !handler.error( false ); // no sync - NETWinInfo did roundtrips
+#endif
+}
+
+// this one is only to make QValueList<> or similar happy
+KWin::WindowInfo::WindowInfo()
+ : d( NULL )
+{
+}
+
+KWin::WindowInfo::~WindowInfo()
+{
+ if( d != NULL ) {
+ if( --d->ref == 0 ) {
+ delete d;
+ }
+ }
+}
+
+KWin::WindowInfo::WindowInfo( const WindowInfo& wininfo )
+ : d( wininfo.d )
+{
+ if( d != NULL )
+ ++d->ref;
+}
+
+KWin::WindowInfo& KWin::WindowInfo::operator=( const WindowInfo& wininfo )
+{
+ if( d != wininfo.d ) {
+ if( d != NULL )
+ if( --d->ref == 0 )
+ delete d;
+ d = wininfo.d;
+ if( d != NULL )
+ ++d->ref;
+ }
+ return *this;
+}
+
+bool KWin::WindowInfo::valid( bool withdrawn_is_valid ) const
+{
+ if( !d->valid )
+ return false;
+ if( !withdrawn_is_valid && mappingState() == NET::Withdrawn )
+ return false;
+ return true;
+}
+
+WId KWin::WindowInfo::win() const
+{
+ return d->win_;
+}
+
+unsigned long KWin::WindowInfo::state() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMState ) == 0, 176 )
+ << "Pass NET::WMState to KWin::windowInfo()" << endl;
+ return d->info->state();
+#else
+ return 0;
+#endif
+}
+
+NET::MappingState KWin::WindowInfo::mappingState() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::XAWMState ) == 0, 176 )
+ << "Pass NET::XAWMState to KWin::windowInfo()" << endl;
+ return d->info->mappingState();
+#else
+ return NET::Visible;
+#endif
+}
+
+NETExtendedStrut KWin::WindowInfo::extendedStrut() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) == 0, 176 )
+ << "Pass NET::WM2ExtendedStrut to second argument of KWin::windowInfo()" << endl;
+ NETExtendedStrut ext = d->info->extendedStrut();
+ NETStrut str = d->info->strut();
+ if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
+ && ( str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0 )) {
+ // build extended from simple
+ if( str.left != 0 ) {
+ ext.left_width = str.left;
+ ext.left_start = 0;
+ ext.left_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
+ }
+ if( str.right != 0 ) {
+ ext.right_width = str.right;
+ ext.right_start = 0;
+ ext.right_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
+ }
+ if( str.top != 0 ) {
+ ext.top_width = str.top;
+ ext.top_start = 0;
+ ext.top_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
+ }
+ if( str.bottom != 0 ) {
+ ext.bottom_width = str.bottom;
+ ext.bottom_start = 0;
+ ext.bottom_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
+ }
+ }
+ return ext;
+#else
+ NETExtendedStrut n;
+ return n;
+#endif
+}
+
+NETStrut KWin::WindowInfo::strut() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMStrut ) == 0, 176 )
+ << "Pass NET::WMStrut to KWin::windowInfo()" << endl;
+ return d->info->strut();
+#else
+ NETStrut n;
+ return n;
+#endif
+}
+
+NET::WindowType KWin::WindowInfo::windowType( int supported_types ) const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMWindowType ) == 0, 176 )
+ << "Pass NET::WMWindowType to KWin::windowInfo()" << endl;
+ return d->info->windowType( supported_types );
+#else
+ return 0;
+#endif
+}
+
+QString KWin::WindowInfo::visibleNameWithState() const
+{
+ QString s = visibleName();
+ if ( isMinimized() ) {
+ s.prepend('(');
+ s.append(')');
+ }
+ return s;
+}
+
+QString KWin::Info::visibleNameWithState() const
+{
+ QString s = visibleName;
+ if ( isMinimized() ) {
+ s.prepend('(');
+ s.append(')');
+ }
+ return s;
+}
+
+QString KWin::WindowInfo::visibleName() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMVisibleName ) == 0, 176 )
+ << "Pass NET::WMVisibleName to KWin::windowInfo()" << endl;
+ return d->info->visibleName() && d->info->visibleName()[ 0 ] != '\0'
+ ? QString::fromUtf8(d->info->visibleName()) : name();
+#else
+ return QString("name");
+#endif
+}
+
+QString KWin::WindowInfo::name() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMName ) == 0, 176 )
+ << "Pass NET::WMName to KWin::windowInfo()" << endl;
+ return d->name_;
+#else
+ return QString();
+#endif
+}
+
+QString KWin::WindowInfo::visibleIconNameWithState() const
+{
+ QString s = visibleIconName();
+ if ( isMinimized() ) {
+ s.prepend('(');
+ s.append(')');
+ }
+ return s;
+}
+
+QString KWin::WindowInfo::visibleIconName() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMVisibleIconName ) == 0, 176 )
+ << "Pass NET::WMVisibleIconName to KWin::windowInfo()" << endl;
+ if( d->info->visibleIconName() && d->info->visibleIconName()[ 0 ] != '\0' )
+ return QString::fromUtf8( d->info->visibleIconName());
+ if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' )
+ return QString::fromUtf8( d->info->iconName());
+ if( !d->iconic_name_.isEmpty())
+ return d->iconic_name_;
+#endif
+ return visibleName();
+}
+
+QString KWin::WindowInfo::iconName() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMIconName ) == 0, 176 )
+ << "Pass NET::WMIconName to KWin::windowInfo()" << endl;
+ if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' )
+ return QString::fromUtf8( d->info->iconName());
+ if( !d->iconic_name_.isEmpty())
+ return d->iconic_name_;
+#endif
+ return name();
+}
+
+bool KWin::WindowInfo::isOnCurrentDesktop() const
+{
+#ifdef Q_WS_X11
+ return isOnDesktop( KWin::currentDesktop());
+#else
+ return false;
+#endif
+}
+
+bool KWin::WindowInfo::isOnDesktop( int desktop ) const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 )
+ << "Pass NET::WMDesktop to KWin::windowInfo()" << endl;
+ return d->info->desktop() == desktop || d->info->desktop() == NET::OnAllDesktops;
+#else
+ return false;
+#endif
+}
+
+bool KWin::WindowInfo::onAllDesktops() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 )
+ << "Pass NET::WMDesktop to KWin::windowInfo()" << endl;
+ return d->info->desktop() == NET::OnAllDesktops;
+#else
+ return false;
+#endif
+}
+
+int KWin::WindowInfo::desktop() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 )
+ << "Pass NET::WMDesktop to KWin::windowInfo()" << endl;
+ return d->info->desktop();
+#else
+ return 1;
+#endif
+}
+
+QRect KWin::WindowInfo::geometry() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMGeometry ) == 0, 176 )
+ << "Pass NET::WMGeometry to KWin::windowInfo()" << endl;
+ return d->geometry_;
+#else
+ return QRect( 100, 100, 200, 200 );
+#endif
+}
+
+QRect KWin::WindowInfo::frameGeometry() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMKDEFrameStrut ) == 0, 176 )
+ << "Pass NET::WMKDEFrameStrut to KWin::windowInfo()" << endl;
+ return d->frame_geometry_;
+#else
+ return QRect();
+#endif
+}
+
+WId KWin::WindowInfo::transientFor() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2TransientFor ) == 0, 176 )
+ << "Pass NET::WM2TransientFor to KWin::windowInfo()" << endl;
+ return d->info->transientFor();
+#else
+ return 0;
+#endif
+}
+
+WId KWin::WindowInfo::groupLeader() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2GroupLeader ) == 0, 176 )
+ << "Pass NET::WM2GroupLeader to KWin::windowInfo()" << endl;
+ return d->info->groupLeader();
+#else
+ return 0;
+#endif
+}
+
+QCString KWin::WindowInfo::windowClassClass() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
+ << "Pass NET::WM2WindowClass to KWin::windowInfo()" << endl;
+ return d->info->windowClassClass();
+#else
+ return 0;
+#endif
+}
+
+QCString KWin::WindowInfo::windowClassName() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
+ << "Pass NET::WM2WindowClass to KWin::windowInfo()" << endl;
+ return d->info->windowClassName();
+#else
+ return 0;
+#endif
+}
+
+QCString KWin::WindowInfo::windowRole() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowRole ) == 0, 176 )
+ << "Pass NET::WM2WindowRole to KWin::windowInfo()" << endl;
+ return d->info->windowRole();
+#else
+ return 0;
+#endif
+}
+
+QCString KWin::WindowInfo::clientMachine() const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ClientMachine ) == 0, 176 )
+ << "Pass NET::WM2ClientMachine to KWin::windowInfo()" << endl;
+ return d->info->clientMachine();
+#else
+ return 0;
+#endif
+}
+
+bool KWin::WindowInfo::actionSupported( NET::Action action ) const
+{
+#ifdef Q_WS_X11
+ kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2AllowedActions ) == 0, 176 )
+ << "Pass NET::WM2AllowedActions to KWin::windowInfo()" << endl;
+ if( allowedActionsSupported())
+ return d->info->allowedActions() & action;
+ else
+#endif
+ return true; // no idea if it's supported or not -> pretend it is
+}
+
+// see NETWM spec section 7.6
+bool KWin::WindowInfo::isMinimized() const
+{
+#ifdef Q_WS_X11
+ if( mappingState() != NET::Iconic )
+ return false;
+ // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows
+ if(( state() & NET::Hidden ) != 0
+ && ( state() & NET::Shaded ) == 0 ) // shaded may have NET::Hidden too
+ return true;
+ // older WMs use WithdrawnState for other virtual desktops
+ // and IconicState only for minimized
+ return icccmCompliantMappingState() ? false : true;
+#else
+ return false;
+#endif
+}
+
+bool KWin::Info::isMinimized() const
+{
+#ifdef Q_WS_X11
+ if( mappingState != NET::Iconic )
+ return false;
+ // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows
+ if(( state & NET::Hidden ) != 0
+ && ( state & NET::Shaded ) == 0 ) // shaded may have NET::Hidden too
+ return true;
+ // older WMs use WithdrawnState for other virtual desktops
+ // and IconicState only for minimized
+ return icccmCompliantMappingState() ? false : true;
+#else
+ return false;
+#endif
+}
+
+bool KWin::Info::isIconified() const
+{
+ return isMinimized();
+}
+
+bool KWin::icccmCompliantMappingState()
+{
+#ifdef Q_WS_X11
+ static enum { noidea, yes, no } wm_is_1_2_compliant = noidea;
+ if( wm_is_1_2_compliant == noidea ) {
+ NETRootInfo info( qt_xdisplay(), NET::Supported );
+ wm_is_1_2_compliant = info.isSupported( NET::Hidden ) ? yes : no;
+ }
+ return wm_is_1_2_compliant == yes;
+#else
+ return false;
+#endif
+}
+
+bool KWin::allowedActionsSupported()
+{
+#ifdef Q_WS_X11
+ static enum { noidea, yes, no } wm_supports_allowed_actions = noidea;
+ if( wm_supports_allowed_actions == noidea ) {
+ NETRootInfo info( qt_xdisplay(), NET::Supported );
+ wm_supports_allowed_actions = info.isSupported( NET::WM2AllowedActions ) ? yes : no;
+ }
+ return wm_supports_allowed_actions == yes;
+#else
+ return false;
+#endif
+}
+
+QString KWin::readNameProperty( WId win, unsigned long atom )
+{
+#ifdef Q_WS_X11
+ XTextProperty tp;
+ char **text = NULL;
+ int count;
+#endif
+ QString result;
+#ifdef Q_WS_X11
+ if ( XGetTextProperty( qt_xdisplay(), win, &tp, atom ) != 0 && tp.value != NULL )
+ {
+ if (!kwin_UTF8_STRING)
+ kwin_UTF8_STRING = XInternAtom( qt_xdisplay(), "UTF8_STRING", False);
+
+ if ( tp.encoding == kwin_UTF8_STRING ) {
+ result = QString::fromUtf8 ( (const char*) tp.value );
+ }
+ else if ( XmbTextPropertyToTextList( qt_xdisplay(), &tp, &text, &count) == Success &&
+ text != NULL && count > 0 ) {
+ result = QString::fromLocal8Bit( text[0] );
+ } else if ( tp.encoding == XA_STRING )
+ result = QString::fromLocal8Bit( (const char*) tp.value );
+ if( text != NULL )
+ XFreeStringList( text );
+ XFree( tp.value );
+ }
+#endif
+ return result;
+}
+
+//#endif
diff --git a/kdecore/kwin.h b/kdecore/kwin.h
new file mode 100644
index 000000000..45d0eede9
--- /dev/null
+++ b/kdecore/kwin.h
@@ -0,0 +1,721 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KWIN_H
+#define KWIN_H
+
+#include <sys/types.h>
+#include <qwindowdefs.h>
+#include <qstring.h>
+#include <qpixmap.h>
+#include "kdelibs_export.h"
+
+#ifdef Q_OS_UNIX
+
+#include <netwm_def.h>
+class NETWinInfo;
+
+/**
+ * Convenience access to certain properties and features of the
+ * window manager.
+ *
+ * This class is not supposed to be instantiated. It exists mostly as
+ * a namespace for the static member functions.
+ *
+ * In KDE 2 and KDE 3, communication with the windowmanager is done with the
+ * NET-protocol, a common window manager specification designed by
+ * various authors of X11 window managers (including those of the KDE
+ * project). The full specification can be found at
+ * www.freedesktop.org/standards/wm-spec .
+ *
+ * To access features of the NET-protocol, use the classes NETRootInfo
+ * and NETWinInfo.
+ *
+ * The purpose of this class is to to provide easy access to the
+ * most-commonly used NET-features with a simpler, KDEish interface.
+ *
+ * In addition, it encapsulates KDE functionality not yet provided by
+ * the NET hints. Currently that is invokeContextHelp() and
+ * setSystemTrayWindowFor() only.
+ *
+ * @short Class for interaction with the window manager.
+ * @see NET
+ * @see NetWinInfo
+ * @author Matthias Ettrich (ettrich@kde.org)
+*/
+class KDECORE_EXPORT KWin
+{
+public:
+
+ /**
+ * Requests that window @p win is activated.
+ *
+ * There are two ways how to activate a window, by calling
+ * activateWindow() and forceActiveWindow(). Generally,
+ * applications shouldn't make attempts to explicitly activate
+ * their windows, and instead let the user to activate them.
+ * In the special cases where this may be needed, applications
+ * should use activateWindow(). Window manager may consider whether
+ * this request wouldn't result in focus stealing, which
+ * would be obtrusive, and may refuse the request.
+ *
+ * The usage of forceActiveWindow() is meant only for pagers
+ * and similar tools, which represent direct user actions
+ * related to window manipulation.
+ * Except for rare cases, this request will be always honored,
+ * and normal applications are forbidden to use it.
+ *
+ * In case of problems, consult the KWin README in the kdebase
+ * package (kdebase/kwin/README), or ask on the kwin@kde.org
+ * mailing list.
+ *
+ * @param win the id of the window to make active
+ * @param time X server timestamp of the user activity that
+ * caused this request
+ * @since 3.2
+ */
+ static void activateWindow( WId win, long time = 0 );
+
+ /**
+ * Sets window @p win to be the active window. Note that this
+ * should be called only in special cases, applications
+ * shouldn't force themselves or other windows to be the active
+ * window. Generally, this call should used only by pagers
+ * and similar tools. See the explanation in description
+ * of activateWindow().
+ *
+ * @param win the id of the window to make active
+ * @param time X server timestamp of the user activity that
+ * caused this request
+ *
+ * @since 3.2
+ */
+ static void forceActiveWindow( WId win, long time = 0 );
+ /**
+ * @deprecated Consider using activateWindow(), use forceActiveWindow()
+ * only if necessary.
+ */
+ static void setActiveWindow( WId win ) KDE_DEPRECATED;
+
+ /**
+ * When application finishes some operation and wants to notify
+ * the user about it, it can call demandAttention(). Instead
+ * of activating the window, which could be obtrusive, the window
+ * will be marked specially as demanding user's attention.
+ * See also explanation in description of activateWindow().
+ *
+ * Note that it's usually better to use KNotifyClient.
+ *
+ * @since 3.2
+ */
+ static void demandAttention( WId win, bool set = true );
+
+ /**
+ * Sets user timestamp @p time on window @p win. The timestamp
+ * is expressed as XServer time. If a window
+ * is shown with user timestamp older than the time of the last
+ * user action, it won't be activated after being shown.
+ * The most common case is the special value 0 which means
+ * not to activate the window after being shown.
+ *
+ * @since 3.2
+ */
+ static void setUserTime( WId win, long time );
+
+ /**
+ * Invokes interactive context help.
+ */
+ static void invokeContextHelp();
+
+
+ /**
+ * Sets the parent window of @p subwindow to be @p mainwindow.
+ * This overrides the parent set the usual way as the QWidget parent,
+ * but only for the window manager - e.g. stacking order and window grouping
+ * will be affected, but features like automatic deletion of children
+ * when the parent is deleted are unaffected and normally use
+ * the QWidget parent.
+ *
+ * This function should be used before a dialog is shown for a window
+ * that belongs to another application.
+ *
+ * @since 3.4
+ */
+ static void setMainWindow( QWidget* subwindow, WId mainwindow );
+
+ /**
+ * Makes @p trayWin a system tray window for @p forWin.
+ *
+ * A system tray window serves as an icon replacement. It's
+ * displayed inside the panel's system tray.
+ * @param trayWin the id of the system tray window
+ * @param forWin the id of the window represented by the system
+ * tray window
+ */
+ static void setSystemTrayWindowFor( WId trayWin, WId forWin );
+
+ class WindowInfo;
+ class WindowInfoPrivate;
+ /**
+ * Returns information about window @p win. It is recommended to check
+ * whether the returned info is valid by calling the valid() method.
+ * @param win the id of the window
+ * @param properties all properties that should be retrieved (see NET::Property
+ * enum for details) - passing 0 means all properties. Unlisted properties
+ * cause related information to be invalid in the returned data, but
+ * make this function faster when not all data is needed.
+ * @param properties2 additional properties (see NET::Property2 enum). Note that
+ * specifying 0 means no properties, not all.
+ * @return the window information
+ * @since 3.2
+ */
+ static WindowInfo windowInfo( WId win, unsigned long properties = 0, unsigned long properties2 = 0 );
+
+ /**
+ * Returns the WM_TRANSIENT_FOR property for the given window, i.e. the mainwindow
+ * for this window.
+ *
+ * @param window the id of the window
+ * @since 3.2
+ */
+ static WId transientFor( WId window );
+
+ /**
+ * Returns the leader window for the group the given window is in, if any.
+ * @param window the id of the window
+ * @since 3.2
+ */
+ static WId groupLeader( WId window );
+
+ /**
+ * Returns an icon for window @p win.
+ *
+ * If @p width and @p height are specified, the best icon for the requested
+ * size is returned.
+ *
+ * If @p scale is true, the icon is smooth-scaled to have exactly
+ * the requested size.
+ *
+ * @param win the id of the window
+ * @param width the desired width, or -1
+ * @param height the desired height, or -1
+ * @param scale if true the icon will be scaled to the desired size. Otherwise the
+ * icon will not be modified.
+ * @return the icon of the window
+ */
+ static QPixmap icon( WId win, int width = -1, int height = -1, bool scale = false );
+
+ /**
+ * Masks specifying from which sources to read an icon. They are tried from the best
+ * until an icon is found.
+ * @li NETWM from property from the window manager specification
+ * @li WMHints from WMHints property
+ * @li ClassHint load icon after getting name from the classhint
+ * @li XApp load the standard X icon (last fallback)
+ */
+ enum IconSource { NETWM = 1, //!< read from property from the window manager specification
+ WMHints = 2, //!< read from WMHints property
+ ClassHint = 4, //!< load icon after getting name from the classhint
+ XApp = 8 //!<load the standard X icon (last fallback)
+ };
+ /**
+ * @overload
+ *
+ * Overloaded variant that allows specifying from which sources the icon should be read.
+ * You should usually prefer the simpler variant which tries all possibilities to get
+ * an icon.
+ *
+ * @param win the id of the window
+ * @param width the desired width, or -1
+ * @param height the desired height, or -1
+ * @param scale if true the icon will be scaled to the desired size. Otherwise the
+ * icon will not be modified.
+ * @param flags OR-ed flags from the IconSource enum
+ * @since 3.2
+ */
+ static QPixmap icon( WId win, int width, int height, bool scale, int flags );
+
+ /**
+ * Sets an @p icon and a @p miniIcon on window @p win
+ * @param win the id of the window
+ * @param icon the new icon
+ * @param miniIcon the new mini icon
+ */
+ static void setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon );
+
+ /**
+ * Sets the type of window @p win to @p windowType.
+ *
+ * @param win the id of the window
+ * @param windowType the type of the window (see NET::WindowType)
+ */
+ static void setType( WId win, NET::WindowType windowType );
+
+ /**
+ * Sets the state of window @p win to @p state.
+ *
+ * Possible values are or'ed combinations of NET::Modal,
+ * NET::Sticky, NET::MaxVert, NET::MaxHoriz, NET::Shaded,
+ * NET::SkipTaskbar, NET::SkipPager, NET::Hidden,
+ * NET::FullScreen, NET::KeepAbove, NET::KeepBelow, NET::StaysOnTop
+ *
+ * @param win the id of the window
+ * @param state the new flags that will be set
+ */
+ static void setState( WId win, unsigned long state );
+
+ /**
+ * Clears the state of window @p win from @p state.
+ *
+ * Possible values are or'ed combinations of NET::Modal,
+ * NET::Sticky, NET::MaxVert, NET::MaxHoriz, NET::Shaded,
+ * NET::SkipTaskbar, NET::SkipPager, NET::Hidden,
+ * NET::FullScreen, NET::KeepAbove, NET::KeepBelow, NET::StaysOnTop
+ *
+ * @param win the id of the window
+ * @param state the flags that will be cleared
+ */
+ static void clearState( WId win, unsigned long state );
+
+ /**
+ * Sets the opacity of window @p win to percetage @p percent.
+ *
+ * Convenience function that just sets an X property
+ * needs a running composite manager for any visible effect
+ *
+ * @param win the id of the window
+ * @param percent the opacity value in percent (will be justified to [ 0: transparent - 100: opaque ])
+ * @since 3.4
+ */
+ static void setOpacity( WId win, uint percent );
+
+ /**
+ * Sets the shadowsize of window @p win to percetage @p percent.
+ *
+ * Convenience function that just sets an X property
+ * needs the running KDE kompmgr manager for any visible effect
+ *
+ * @param win the id of the window
+ * @param percent the opacity value in percent (0 leads to a completely unshadowed window)
+ * @since 3.4
+ */
+ static void setShadowSize( WId win, uint percent );
+
+ /**
+ * Sets window @p win to be present on all virtual desktops if @p
+ * is true. Otherwise the window lives only on one single desktop.
+ *
+ * @param win the id of the window
+ * @param b true to show the window on all desktops, false
+ * otherwise
+ */
+ static void setOnAllDesktops( WId win, bool b );
+
+ /**
+ * Moves window @p win to desktop @p desktop.
+ *
+ * @param win the id of the window
+ * @param desktop the number of the new desktop
+ */
+ static void setOnDesktop( WId win, int desktop);
+
+ /**
+ * Sets the strut of window @p win to @p to @p left width
+ * ranging from @p left_start to @p left_end on the left edge,
+ * and simiarly for the other edges. For not reserving a strut, pass 0 as the width.
+ * E.g. to reserve 10x10 square in the topleft corner, use e.g.
+ * setExtendedStrut( w, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 ).
+ *
+ * @param win the id of the window
+ * @param left_width width of the strut at the left edge
+ * @param left_start starting y coordinate of the strut at the left edge
+ * @param left_end ending y coordinate of the strut at the left edge
+ * @param right_width width of the strut at the right edge
+ * @param right_start starting y coordinate of the strut at the right edge
+ * @param right_end ending y coordinate of the strut at the right edge
+ * @param top_width width of the strut at the top edge
+ * @param top_start starting x coordinate of the strut at the top edge
+ * @param top_end ending x coordinate of the strut at the top edge
+ * @param bottom_width width of the strut at the bottom edge
+ * @param bottom_start starting x coordinate of the strut at the bottom edge
+ * @param bottom_end ending x coordinate of the strut at the bottom edge
+ */
+ static void setExtendedStrut( WId win, int left_width, int left_start, int left_end,
+ int right_width, int right_start, int right_end, int top_width, int top_start, int top_end,
+ int bottom_width, int bottom_start, int bottom_end );
+
+ /**
+ * @deprecated use setExtendedStrut()
+ * Sets the strut of window @p win to @p left, @p right, @p top, @p bottom.
+ *
+ * @param win the id of the window
+ * @param left the left strut
+ * @param right the right strut
+ * @param top the top strut
+ * @param bottom the bottom strut
+ */
+ static void setStrut( WId win, int left, int right, int top, int bottom );
+ /**
+ * Convenience function to access the current desktop. See NETRootInfo.
+ * @return the number of the current desktop
+ */
+ static int currentDesktop();
+
+ /**
+ * Convenience function to access the number of desktops. See
+ * NETRootInfo.
+ * @return the number of desktops
+ */
+ static int numberOfDesktops();
+
+ /**
+ * Convenience function to set the current desktop to @p desktop.
+ * See NETRootInfo.
+ * @param desktop the number of the new desktop
+ */
+ static void setCurrentDesktop( int desktop );
+
+ /**
+ * Convenience function to set the current viewport to @p viewport.
+ * See NETRootInfo.
+ * @param desktop the number of the new desktop
+ * @param viewport the position of the new viewport
+ * @since 3.5.5
+ */
+ static void setCurrentDesktopViewport( int desktop, QPoint viewport );
+
+ /**
+ * Iconifies a window. Compatible to XIconifyWindow but has an
+ * additional parameter @p animation.
+ *
+ * @param win the id of the window
+ * @param animation true to show an animation
+ * @see deIconifyWindow()
+ */
+ static void iconifyWindow( WId win, bool animation = true );
+
+ /**
+ * DeIconifies a window. Compatible to XMapWindow but has an
+ * additional parameter @p animation.
+ *
+ * @param win the id of the window
+ * @param animation true to show an animation
+ * @see iconifyWindow()
+ */
+ static void deIconifyWindow( WId win, bool animation = true );
+
+ /**
+ * Raises the given window. This call is only for pagers and similar
+ * tools that represent direct user actions. Applications should not
+ * use it, they should keep using QWidget::raise() or XRaiseWindow()
+ * if necessary.
+ * @since 3.2
+ */
+ static void raiseWindow( WId win );
+
+ /**
+ * Lowers the given window. This call is only for pagers and similar
+ * tools that represent direct user actions. Applications should not
+ * use it, they should keep using QWidget::lower() or XLowerWindow()
+ * if necessary.
+ * @since 3.2
+ */
+ static void lowerWindow( WId win );
+
+ /**
+ * @internal
+ * Returns true if the WM uses IconicState also for windows
+ * on inactive virtual desktops.
+ */
+ static bool icccmCompliantMappingState();
+
+ /**
+ * Returns true if the WM announces which actions it allows for windows.
+ * @since 3.2
+ */
+ static bool allowedActionsSupported();
+
+ /**
+ * Function that reads and returns the contents of the given text
+ * property (WM_NAME, WM_ICON_NAME,...).
+ * @since 3.2
+ */
+ static QString readNameProperty( WId window, unsigned long atom );
+
+ /**
+ * Returns true if a compositing manager is running (i.e. ARGB windows
+ * are supported, effects will be provided, etc.).
+ */
+ static bool compositingActive();
+
+ /**
+ * @deprecated Use WindowInfo .
+ */
+ struct KDECORE_EXPORT Info
+ {
+ /// The window's id.
+ WId win;
+ /// The window's state.
+ long unsigned int state;
+ /// The mapping state.
+ bool isMinimized() const;
+ bool isIconified() const;
+ NET::MappingState mappingState;
+ /// The strut.
+ NETStrut strut;
+ /// The window type.
+ NET::WindowType windowType;
+ /// The visible name of the window.
+ QString visibleName;
+ /// The name of the window.
+ QString name;
+ /// The number of the window's desktop.
+ int desktop;
+ /// true if the window is on all desktops.
+ bool onAllDesktops;
+ /// The process id of the window's owner
+ pid_t pid;
+ /// Position and size of the window contents.
+ QRect geometry;
+ /// Position and size of the window's frame.
+ QRect frameGeometry;
+
+ QString visibleNameWithState() const;
+ };
+
+ /**
+ * @deprecated
+ * Use windowInfo() .
+ */
+ static Info info( WId win ) KDE_DEPRECATED;
+
+#ifdef KDE_NO_COMPAT
+private:
+#endif
+ /**
+ * @deprecated
+ * Use KStartupInfo::appStarted
+ */
+ static void appStarted() KDE_DEPRECATED;
+};
+
+
+/**
+ * Information about a window.
+ * @since 3.2
+ */
+class KDECORE_EXPORT KWin::WindowInfo
+{
+public:
+ /**
+ * Reads all the info about the given window.
+ */
+ WindowInfo( WId window, unsigned long properties, unsigned long properties2 );
+ WindowInfo(); // to make QValueList and others happy
+ ~WindowInfo();
+ /**
+ * Returns false if this window info is not valid (most probably the given
+ * window doesn't exist).
+ * @param withdrawn_is_valid if true, windows in the withdrawn state
+ * (i.e. not managed) are also considered. This is usually not the case.
+ */
+ bool valid( bool withdrawn_is_valid = false ) const;
+ /**
+ * Returns the window identifier.
+ */
+ WId win() const;
+ /**
+ * Returns the window's state flags (see the NET::State enum for details).
+ * Requires NET::WMState passed to KWin::windowInfo().
+ */
+ unsigned long state() const;
+ /**
+ * Returns true if the window has the given state flag set (see the NET::State enum for details).
+ * Requires NET::WMState passed to KWin::windowInfo().
+ * @since 3.2.1
+ */
+ bool hasState( unsigned long s ) const { return ( state() & s ) == s; }
+ /**
+ * Returns true if the window is minimized. Note that it is true only if
+ * the window is truly minimized, not shaded or on another virtual desktops,
+ * which makes it different from mappingState() == NET::Iconic
+ * or QWidget::isMinimized().
+ * Requires NET::WMState and NET::XAWMState passed to KWin::windowInfo().
+ */
+ bool isMinimized() const;
+ /**
+ * Returns the mapping state of the window (see NET::MappingState). Note that
+ * it's very likely that you don't want to use this function, and use isOnDesktop(),
+ * isMinimized() etc. instead.
+ * Requires NET::XAWMState passed to KWin::windowInfo().
+ */
+ NET::MappingState mappingState() const;
+ /**
+ * Returns the window extended (partial) strut.
+ * Requires NET::WM2ExtendedStrut passed to KWin::windowInfo().
+ */
+ NETExtendedStrut extendedStrut() const;
+ /**
+ * @deprecated use extendedStrut()
+ * Returns the window strut.
+ * Requires NET::WMStrut passed to KWin::windowInfo().
+ */
+ NETStrut strut() const;
+ /**
+ * Returns the window type of this window (see NET::WindowType). The argument
+ * should be all window types your application supports (see NET::WindowTypeMask).
+ * Requires NET::WMWindowType passed to KWin::windowInfo().
+ */
+ NET::WindowType windowType( int supported_types ) const;
+ /**
+ * Returns the visible name of the window (i.e. including possible <2> appended
+ * when there are two or more windows with the same name).
+ * Requires NET::WMVisibleName passed to KWin::windowInfo().
+ */
+ QString visibleName() const;
+ /**
+ * Returns a visible name with state.
+ *
+ * This is a simple convenience function that returns the
+ * visible name but with parentheses around minimized windows.
+ * Requires NET::WMVisibleName, NET::WMState and NET::XAWMState passed
+ * to KWin::windowInfo().
+ * @return the window name with state
+ */
+ QString visibleNameWithState() const;
+ /**
+ * Returns the name of the window, as specified by the application, without
+ * any modifications. You should often use visibleName() instead.
+ * Requires NET::WMName passed to KWin::windowInfo().
+ */
+ QString name() const;
+ /**
+ * Returns the visible name of the window that should be shown in taskbar
+ * and all other "iconic" representations of the window. Note that this
+ * has nothing to do with normal icons.
+ * Requires NET::WMVisibleIconName passed to KWin::windowInfo().
+ */
+ QString visibleIconName() const;
+ /**
+ * Returns a visible name with state.
+ *
+ * This is a simple convenience function that returns the
+ * visible iconic name but with parentheses around minimized windows.
+ * Note that this has nothing to do with normal icons.
+ * Requires NET::WMVisibleIconName, NET::WMState and NET::XAWMState passed
+ * to KWin::windowInfo().
+ * @return the window iconic name with state
+ */
+ QString visibleIconNameWithState() const;
+ /**
+ * Returns the name of the window that should be shown in taskbar and all other
+ * "iconic" representations of the window. Note that this has nothing to do
+ * with normal icons.
+ * Requires NET::WMIconName passed to KWin::windowInfo().
+ */
+ QString iconName() const;
+ /**
+ * Returns true if the window is on the currently active virtual desktop.
+ * Requires NET::WMDesktop passed to KWin::windowInfo().
+ */
+ bool isOnCurrentDesktop() const;
+ /**
+ * Returns true if the window is on the given virtual desktop.
+ * Requires NET::WMDesktop passed to KWin::windowInfo().
+ */
+ bool isOnDesktop( int desktop ) const;
+ /**
+ * Returns true if the window is on all desktops
+ * (equal to desktop()==NET::OnAllDesktops).
+ * Requires NET::WMDesktop passed to KWin::windowInfo().
+ */
+ bool onAllDesktops() const;
+ /**
+ * Returns the virtual desktop this window is on (NET::OnAllDesktops if the window
+ * is on all desktops). You should prefer using isOnDesktop().
+ * Requires NET::WMDesktop passed to KWin::windowInfo().
+ */
+ int desktop() const;
+ /**
+ * Returns the position and size of the window contents.
+ * Requires NET::WMGeometry passed to KWin::windowInfo().
+ */
+ QRect geometry() const;
+ /**
+ * Returns the frame geometry of the window, i.e. including the window decoration.
+ * Requires NET::WMKDEFrameStrut passed to KWin::windowInfo().
+ */
+ QRect frameGeometry() const;
+ /**
+ * Returns the WM_TRANSIENT_FOR property for the window, i.e. the mainwindow
+ * for this window.
+ * Requires NET::WM2TransientFor passed to KWin::windowInfo().
+ */
+ WId transientFor() const;
+ /**
+ * Returns the leader window for the group the window is in, if any.
+ * Requires NET::WM2GroupLeader passed to KWin::windowInfo().
+ */
+ WId groupLeader() const;
+
+ /**
+ * Returns the class component of the window class for the window
+ * (i.e. WM_CLASS property).
+ * Requires NET::WM2WindowClass passed to KWin::windowInfo().
+ * @since 3.3
+ */
+ QCString windowClassClass() const;
+
+ /**
+ * Returns the name component of the window class for the window
+ * (i.e. WM_CLASS property).
+ * Requires NET::WM2WindowClass passed to KWin::windowInfo().
+ * @since 3.3
+ */
+ QCString windowClassName() const;
+
+ /**
+ * Returns the window role for the window (i.e. WM_WINDOW_ROLE property).
+ * Requires NET::WM2WindowRole passed to KWin::windowInfo().
+ * @since 3.3
+ */
+ QCString windowRole() const;
+
+ /**
+ * Returns the client machine for the window (i.e. WM_CLIENT_MACHINE property).
+ * Requires NET::WMClientMachine passed to KWin::windowInfo().
+ * @since 3.3
+ */
+ QCString clientMachine() const;
+
+ /**
+ * Returns true if the given action is currently supported for the window
+ * by the window manager.
+ * Requires NET::WM2AllowedActions passed to KWin::windowInfo().
+ */
+ bool actionSupported( NET::Action action ) const;
+
+ WindowInfo( const WindowInfo& );
+ WindowInfo& operator=( const WindowInfo& );
+private:
+ WindowInfoPrivate* d;
+};
+
+#endif //Q_OS_UNIX
+
+#endif
diff --git a/kdecore/kwinmodule.cpp b/kdecore/kwinmodule.cpp
new file mode 100644
index 000000000..9e3532b0f
--- /dev/null
+++ b/kdecore/kwinmodule.cpp
@@ -0,0 +1,480 @@
+/*
+ $Id$
+
+ This file is part of the KDE libraries
+ Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qwidget.h>
+#ifdef Q_WS_X11 //FIXME
+#include "kwinmodule.h"
+#include "kwin.h"
+#include <X11/Xatom.h>
+#include "kapplication.h"
+#include "kdebug.h"
+#include <qtl.h>
+#include <qptrlist.h>
+#include <klocale.h>
+#include <dcopclient.h>
+#include "netwm.h"
+
+static KWinModulePrivate* static_d = 0;
+
+static unsigned long windows_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking |
+ NET::NumberOfDesktops |
+ NET::DesktopGeometry |
+ NET::DesktopViewport |
+ NET::CurrentDesktop |
+ NET::DesktopNames |
+ NET::ActiveWindow |
+ NET::WorkArea |
+ NET::KDESystemTrayWindows,
+ NET::WM2ShowingDesktop };
+
+static unsigned long desktop_properties[ 2 ] = {
+ NET::NumberOfDesktops |
+ NET::DesktopGeometry |
+ NET::DesktopViewport |
+ NET::CurrentDesktop |
+ NET::DesktopNames |
+ NET::ActiveWindow |
+ NET::WorkArea |
+ NET::KDESystemTrayWindows,
+ NET::WM2ShowingDesktop };
+
+class KWinModulePrivate : public QWidget, public NETRootInfo4
+{
+public:
+ KWinModulePrivate(int _what)
+ : QWidget(0,0), NETRootInfo4( qt_xdisplay(),
+ _what >= KWinModule::INFO_WINDOWS ?
+ windows_properties : desktop_properties,
+ 2,
+ -1, false
+ ),
+ strutSignalConnected( false ),
+ what( _what )
+ {
+ kapp->installX11EventFilter( this );
+ (void ) kapp->desktop(); //trigger desktop widget creation to select root window events
+ activate();
+ updateStackingOrder();
+ }
+ ~KWinModulePrivate()
+ {
+ }
+ QPtrList<KWinModule> modules;
+
+ QValueList<WId> windows;
+ QValueList<WId> stackingOrder;
+ QValueList<WId> systemTrayWindows;
+
+ struct StrutData
+ {
+ StrutData( WId window_, const NETStrut& strut_, int desktop_ )
+ : window( window_ ), strut( strut_ ), desktop( desktop_ ) {};
+ StrutData() {}; // for QValueList to be happy
+ WId window;
+ NETStrut strut;
+ int desktop;
+ };
+ QValueList<StrutData> strutWindows;
+ QValueList<WId> possibleStrutWindows;
+ bool strutSignalConnected;
+ int what;
+
+ void addClient(Window);
+ void removeClient(Window);
+ void addSystemTrayWin(Window);
+ void removeSystemTrayWin(Window);
+
+ bool x11Event( XEvent * ev );
+
+ void updateStackingOrder();
+ bool removeStrutWindow( WId );
+
+ QSize numberOfViewports(int desktop) const;
+ QPoint currentViewport(int desktop) const;
+};
+
+KWinModule::KWinModule( QObject* parent )
+ : QObject( parent, "kwin_module" )
+{
+ init(INFO_ALL);
+}
+
+KWinModule::KWinModule( QObject* parent, int what )
+ : QObject( parent, "kwin_module" )
+{
+ init(what);
+}
+
+void KWinModule::init(int what)
+{
+ if (what >= INFO_WINDOWS)
+ what = INFO_WINDOWS;
+ else
+ what = INFO_DESKTOP;
+
+ if ( !static_d )
+ {
+ static_d = new KWinModulePrivate(what);
+ }
+ else if (static_d->what < what)
+ {
+ QPtrList<KWinModule> modules = static_d->modules;
+ delete static_d;
+ static_d = new KWinModulePrivate(what);
+ static_d->modules = modules;
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ (*mit)->d = static_d;
+ }
+
+ d = static_d;
+ d->modules.append( this );
+}
+
+KWinModule::~KWinModule()
+{
+ d->modules.removeRef( this );
+ if ( d->modules.isEmpty() ) {
+ delete d;
+ static_d = 0;
+ }
+}
+
+const QValueList<WId>& KWinModule::windows() const
+{
+ return d->windows;
+}
+
+const QValueList<WId>& KWinModule::stackingOrder() const
+{
+ return d->stackingOrder;
+}
+
+
+bool KWinModule::hasWId(WId w) const
+{
+ return d->windows.findIndex( w ) != -1;
+}
+
+const QValueList<WId>& KWinModule::systemTrayWindows() const
+{
+ return d->systemTrayWindows;
+}
+
+QSize KWinModulePrivate::numberOfViewports(int desktop) const
+{
+ NETSize netdesktop = desktopGeometry(desktop);
+ QSize s(netdesktop.width / QApplication::desktop()->width(),
+ netdesktop.height / QApplication::desktop()->height());
+
+ // workaround some kwin bugs
+ if (s.width() < 1) s.setWidth(1);
+ if (s.height() < 1) s.setHeight(1);
+ return s;
+}
+
+QPoint KWinModulePrivate::currentViewport(int desktop) const
+{
+ NETPoint netviewport = desktopViewport(desktop);
+
+ return QPoint(1+(netviewport.x / QApplication::desktop()->width()),
+ 1+(netviewport.y / QApplication::desktop()->height()));
+}
+
+bool KWinModulePrivate::x11Event( XEvent * ev )
+{
+ if ( ev->xany.window == qt_xrootwin() ) {
+ int old_current_desktop = currentDesktop();
+ WId old_active_window = activeWindow();
+ int old_number_of_desktops = numberOfDesktops();
+ bool old_showing_desktop = showingDesktop();
+ unsigned long m[ 5 ];
+ NETRootInfo::event( ev, m, 5 );
+
+ if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->currentDesktopChanged( currentDesktop() );
+ if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->activeWindowChanged( activeWindow() );
+ if ( m[ PROTOCOLS ] & DesktopViewport ) {
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->currentDesktopViewportChanged(currentDesktop(),
+ currentViewport(currentDesktop()));
+ }
+ if ( m[ PROTOCOLS ] & DesktopGeometry ) {
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->desktopGeometryChanged(currentDesktop());
+ }
+ if ( m[ PROTOCOLS ] & DesktopNames )
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->desktopNamesChanged();
+ if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->numberOfDesktopsChanged( numberOfDesktops() );
+ if ( m[ PROTOCOLS ] & WorkArea )
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->workAreaChanged();
+ if ( m[ PROTOCOLS ] & ClientListStacking ) {
+ updateStackingOrder();
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->stackingOrderChanged();
+ }
+ if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->showingDesktopChanged( showingDesktop());
+ }
+ } else if ( windows.findIndex( ev->xany.window ) != -1 ){
+ NETWinInfo ni( qt_xdisplay(), ev->xany.window, qt_xrootwin(), 0 );
+ unsigned long dirty[ 2 ];
+ ni.event( ev, dirty, 2 );
+ if ( ev->type ==PropertyNotify ) {
+ if( ev->xproperty.atom == XA_WM_HINTS )
+ dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIcon; // support for old icons
+ else if( ev->xproperty.atom == XA_WM_NAME )
+ dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName; // support for old name
+ else if( ev->xproperty.atom == XA_WM_ICON_NAME )
+ dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName; // support for old iconic name
+ }
+ if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 ) {
+ removeStrutWindow( ev->xany.window );
+ if ( possibleStrutWindows.findIndex( ev->xany.window ) == -1 )
+ possibleStrutWindows.append( ev->xany.window );
+ }
+ if ( dirty[ NETWinInfo::PROTOCOLS ] || dirty[ NETWinInfo::PROTOCOLS2 ] ) {
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
+ emit (*mit)->windowChanged( ev->xany.window );
+ emit (*mit)->windowChanged( ev->xany.window, dirty );
+ emit (*mit)->windowChanged( ev->xany.window, dirty[ NETWinInfo::PROTOCOLS ] );
+ if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
+ emit (*mit)->strutChanged();
+ }
+ }
+ }
+
+ return false;
+}
+
+bool KWinModulePrivate::removeStrutWindow( WId w )
+{
+ for( QValueList< StrutData >::Iterator it = strutWindows.begin();
+ it != strutWindows.end();
+ ++it )
+ if( (*it).window == w ) {
+ strutWindows.remove( it );
+ return true;
+ }
+ return false;
+}
+
+void KWinModulePrivate::updateStackingOrder()
+{
+ stackingOrder.clear();
+ for ( int i = 0; i < clientListStackingCount(); i++ )
+ stackingOrder.append( clientListStacking()[i] );
+}
+
+void KWinModulePrivate::addClient(Window w)
+{
+ if ( (what >= KWinModule::INFO_WINDOWS) && !QWidget::find( w ) )
+ XSelectInput( qt_xdisplay(), w, PropertyChangeMask | StructureNotifyMask );
+ bool emit_strutChanged = false;
+ if( strutSignalConnected && modules.count() > 0 ) {
+ NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut | NET::WMDesktop );
+ NETStrut strut = info.strut();
+ if ( strut.left || strut.top || strut.right || strut.bottom ) {
+ strutWindows.append( StrutData( w, strut, info.desktop()));
+ emit_strutChanged = true;
+ }
+ } else
+ possibleStrutWindows.append( w );
+ windows.append( w );
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
+ emit (*mit)->windowAdded( w );
+ if ( emit_strutChanged )
+ emit (*mit)->strutChanged();
+ }
+}
+
+void KWinModulePrivate::removeClient(Window w)
+{
+ bool emit_strutChanged = removeStrutWindow( w );
+ if( strutSignalConnected && possibleStrutWindows.findIndex( w ) != -1 && modules.count() > 0 ) {
+ NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMStrut );
+ NETStrut strut = info.strut();
+ if ( strut.left || strut.top || strut.right || strut.bottom ) {
+ emit_strutChanged = true;
+ }
+ }
+ possibleStrutWindows.remove( w );
+ windows.remove( w );
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit ) {
+ emit (*mit)->windowRemoved( w );
+ if ( emit_strutChanged )
+ emit (*mit)->strutChanged();
+ }
+}
+
+void KWinModulePrivate::addSystemTrayWin(Window w)
+{
+ systemTrayWindows.append( w );
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->systemTrayWindowAdded( w );
+}
+
+void KWinModulePrivate::removeSystemTrayWin(Window w)
+{
+ systemTrayWindows.remove( w );
+ for ( QPtrListIterator<KWinModule> mit( modules ); mit.current(); ++mit )
+ emit (*mit)->systemTrayWindowRemoved( w );
+}
+
+int KWinModule::currentDesktop() const
+{
+ return d->currentDesktop();
+}
+
+int KWinModule::numberOfDesktops() const
+{
+ return d->numberOfDesktops();
+}
+
+QSize KWinModule::numberOfViewports(int desktop) const
+{
+ return d->numberOfViewports(desktop);
+}
+
+QPoint KWinModule::currentViewport(int desktop) const
+{
+ return d->currentViewport(desktop);
+}
+
+WId KWinModule::activeWindow() const
+{
+ return d->activeWindow();
+}
+
+bool KWinModule::showingDesktop() const
+{
+ return d->showingDesktop();
+}
+
+QRect KWinModule::workArea( int desktop ) const
+{
+ int desk = (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop();
+ if ( desk <= 0 )
+ return QApplication::desktop()->geometry();
+ NETRect r = d->workArea( desk );
+ if( r.size.width <= 0 || r.size.height <= 0 ) // not set
+ return QApplication::desktop()->geometry();
+ return QRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
+}
+
+QRect KWinModule::workArea( const QValueList<WId>& exclude, int desktop ) const
+{
+ QRect all = QApplication::desktop()->geometry();
+ QRect a = all;
+
+ if (desktop == -1)
+ desktop = d->currentDesktop();
+
+ QValueList<WId>::ConstIterator it1;
+ for( it1 = d->windows.begin(); it1 != d->windows.end(); ++it1 ) {
+
+ if(exclude.findIndex(*it1) != -1) continue;
+
+// Kicker (very) extensively calls this function, causing hundreds of roundtrips just
+// to repeatedly find out struts of all windows. Therefore strut values for strut
+// windows are cached here.
+ NETStrut strut;
+ QValueList< KWinModulePrivate::StrutData >::Iterator it2 = d->strutWindows.begin();
+ for( ;
+ it2 != d->strutWindows.end();
+ ++it2 )
+ if( (*it2).window == *it1 )
+ break;
+ if( it2 != d->strutWindows.end()) {
+ if(!((*it2).desktop == desktop || (*it2).desktop == NETWinInfo::OnAllDesktops ))
+ continue;
+ strut = (*it2).strut;
+ } else if( d->possibleStrutWindows.findIndex( *it1 ) != -1 ) {
+ NETWinInfo info( qt_xdisplay(), (*it1), qt_xrootwin(), NET::WMStrut | NET::WMDesktop);
+ strut = info.strut();
+ d->possibleStrutWindows.remove( *it1 );
+ d->strutWindows.append( KWinModulePrivate::StrutData( *it1, info.strut(), info.desktop()));
+ if(!(info.desktop() == desktop || info.desktop() == NETWinInfo::OnAllDesktops))
+ continue;
+ } else
+ continue; // not a strut window
+
+ QRect r = all;
+ if ( strut.left > 0 )
+ r.setLeft( r.left() + (int) strut.left );
+ if ( strut.top > 0 )
+ r.setTop( r.top() + (int) strut.top );
+ if ( strut.right > 0 )
+ r.setRight( r.right() - (int) strut.right );
+ if ( strut.bottom > 0 )
+ r.setBottom( r.bottom() - (int) strut.bottom );
+
+ a = a.intersect(r);
+ }
+ return a;
+}
+
+void KWinModule::connectNotify( const char* signal )
+{
+ if( !d->strutSignalConnected && qstrcmp( signal, SIGNAL(strutChanged())) == 0 )
+ d->strutSignalConnected = true;
+ QObject::connectNotify( signal );
+}
+
+QString KWinModule::desktopName( int desktop ) const
+{
+ const char* name = d->desktopName( (desktop > 0 && desktop <= (int) d->numberOfDesktops() ) ? desktop : currentDesktop() );
+ if ( name && name[0] )
+ return QString::fromUtf8( name );
+ return i18n("Desktop %1").arg( desktop );
+}
+
+void KWinModule::setDesktopName( int desktop, const QString& name )
+{
+ if (desktop <= 0 || desktop > (int) d->numberOfDesktops() )
+ desktop = currentDesktop();
+ d->setDesktopName( desktop, name.utf8().data() );
+}
+
+
+void KWinModule::doNotManage( const QString& title )
+{
+ if ( !kapp->dcopClient()->isAttached() )
+ kapp->dcopClient()->attach();
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << title;
+ kapp->dcopClient()->call("kwin", "", "doNotManage(QString)",
+ data, replyType, replyData);
+}
+
+#include "kwinmodule.moc"
+#endif
diff --git a/kdecore/kwinmodule.h b/kdecore/kwinmodule.h
new file mode 100644
index 000000000..d0e9624b9
--- /dev/null
+++ b/kdecore/kwinmodule.h
@@ -0,0 +1,358 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/*
+ * kwinmodule.h. Part of the KDE project.
+ */
+
+#ifndef KWINMODULE_H
+#define KWINMODULE_H
+
+#include <qobject.h>
+#include <qvaluelist.h>
+#include "kdelibs_export.h"
+
+#ifdef Q_OS_UNIX
+
+class KWinModulePrivate;
+
+/**
+ *
+ * The class KWinModule provides information about the state of the
+ * window manager as required by windowmanager modules. It informs a
+ * module about all currently managed windows and changes to them (via
+ * Qt signals).
+ *
+ * KWinModule uses NETRootInfo internally. Modules written with this
+ * class will work fine under any window manager that implements the
+ * NET_WM protocol.
+ *
+ * There are no methods to manipulate windows. Those are defined in
+ * the classes KWin, NETWinInfo and NETRootInfo.
+ *
+ *
+ * @short Base class for KDE Window Manager modules.
+ * @author Matthias Ettrich (ettrich@kde.org)
+ */
+class KDECORE_EXPORT KWinModule : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ enum { INFO_DESKTOP=1,
+ INFO_WINDOWS=2,
+ INFO_ALL=32767 };
+ /**
+ * Creates a KWinModule object and connects to the window
+ * manager.
+ * @param parent the parent for the QObject
+ * @param what The information you are interested in:
+ * INFO_DESKTOP: currentDesktop,
+ * numberOfDesktops,
+ * desktopName,
+ * currentDesktopChanged,
+ * numberOfDesktopsChanged,
+ * desktopNameChanged,
+ * activeWindow,
+ * activeWindowChanged,
+ * workArea(int desktop),
+ * workAreaChanged
+ *
+ * INFO_WINDOWS: windows,
+ * windowAdded,
+ * windowRemoved,
+ * stackingOrder,
+ * systemTrayWindows,
+ * systemTrayWindowAdded,
+ * systemTrayWindowRemoved,
+ * windowChanged,
+ * strutChanged,
+ * workArea(const QValueList<WId> &excludes, int desktop)
+ **/
+ KWinModule( QObject* parent, int what );
+ /**
+ * Creates a KWinModule object and connects to the window
+ * manager.
+ * @param parent the parent for the QObject
+ **/
+ KWinModule( QObject* parent = 0 );
+
+ /**
+ * Destructor. Internal cleanup, nothing fancy.
+ **/
+ ~KWinModule();
+
+ /**
+ * Returns the list of all toplevel windows currently managed by the
+ * window manager in the order of creation. Please do not rely on
+ * indexes of this list: Whenever you enter Qt's event loop in your
+ * application, it may happen that entries are removed or added.
+ * Your module should perhaps work on a copy of this list and verify a
+ * window with hasWId() before any operations.
+ *
+ * Iteration over this list can be done easily with
+ * \code
+ * QValueList<WId>::ConstIterator it;
+ * for ( it = module->windows().begin();
+ * it != modules->windows().end(); ++it ) {
+ * ... do something here, (*it) is the current WId.
+ * }
+ * \endcode
+ * @return the list of all toplevel windows
+ */
+ const QValueList<WId>& windows() const;
+
+ /**
+ * Returns the list of all toplevel windows currently managed by the
+ * window manager in the current stacking order (from lower to
+ * higher). May be useful for pagers.
+ * @return the list of all toplevel windows in stacking order
+ */
+ const QValueList<WId>& stackingOrder() const;
+
+ /**
+ * Test to see if @p id still managed at present.
+ * @param id the window id to test
+ * @return true if the window id is still managed
+ **/
+ bool hasWId(WId id) const;
+
+ /**
+ * Returns a list of the system tray windows.
+ * @return a list of all system tray windows
+ **/
+ const QValueList<WId>& systemTrayWindows() const;
+
+ /**
+ * Returns the current virtual desktop.
+ * @return the current virtual desktop
+ **/
+ int currentDesktop() const;
+
+ /**
+ * Returns the number of virtual desktops.
+ * @return the number of virtual desktops
+ **/
+ int numberOfDesktops() const;
+
+ /**
+ * Returns the number of viewports in x and y direction
+ * on the virtual desktop.
+ * @return the number of virtual desktops
+ * @since 3.5.5
+ **/
+ QSize numberOfViewports(int desktop) const;
+
+ /**
+ * Returns the current viewport on the given virtual desktop
+ * @return the number of virtual desktops
+ * @since 3.5.5
+ **/
+ QPoint currentViewport(int desktop) const;
+
+ /**
+ * Returns the currently active window, or 0 if no window is active.
+ * @return the window id of the active window, or 0 if no window is
+ * active
+ **/
+ WId activeWindow() const;
+
+ /**
+ * Returns the workarea for the specified desktop, or the current
+ * work area if no desktop has been specified.
+ * @param desktop the number of the desktop to check, -1 for the
+ * current desktop
+ * @return the size and position of the desktop
+ **/
+ QRect workArea( int desktop = - 1 ) const;
+
+
+ /**
+ * Returns the workarea for the specified desktop, or the current
+ * work area if no desktop has been specified. Excludes struts of
+ * clients in the exclude List.
+ *
+ * @param excludes the list of clients whose struts will be excluded
+ * @param desktop the number of the desktop to check, -1 for the
+ * current desktop
+ * @return the size and position of the desktop
+ **/
+ QRect workArea( const QValueList<WId> &excludes, int desktop = -1) const;
+
+ /**
+ * Returns the name of the specified desktop.
+ * @param desktop the number of the desktop
+ * @return the name of the desktop
+ **/
+ QString desktopName( int desktop ) const;
+
+ /**
+ * Sets the name of the specified desktop.
+ * @param desktop the number of the desktop
+ * @param name the new name for the desktop
+ **/
+ void setDesktopName( int desktop, const QString& name );
+
+ /**
+ * Returns the state of showing the desktop.
+ * @since 3.5
+ */
+ bool showingDesktop() const;
+
+ /**
+ * Informs kwin via dcop to not manage a window with the
+ * specified @p title.
+ *
+ * Useful for swallowing legacy applications, for example java
+ * applets.
+ *
+ * @param title the title of the window
+ */
+ void doNotManage( const QString& title );
+
+
+signals:
+
+ /**
+ * Switched to another virtual desktop.
+ * @param desktop the number of the new desktop
+ */
+ void currentDesktopChanged( int desktop);
+
+ /**
+ * A window has been added.
+ * @param id the id of the the window
+ */
+ void windowAdded(WId id);
+
+ /**
+ * A window has been removed.
+ * @param id the id of the window that has been removed
+ */
+ void windowRemoved(WId id);
+
+ /**
+ * Hint that \<Window> is active (= has focus) now.
+ * @param id the id of the window that is active
+ */
+ void activeWindowChanged(WId id);
+
+ /**
+ * Desktops have been renamed.
+ */
+ void desktopNamesChanged();
+
+ /**
+ * The number of desktops changed.
+ * @param num the new number of desktops
+ */
+ void numberOfDesktopsChanged(int num);
+
+ /**
+ * Emitted when a dock window has been added.
+ * @param id the id of the new system tray window
+ */
+ void systemTrayWindowAdded(WId id);
+
+ /**
+ * Emitted when a dock window has been removed.
+ * @param id the id of the former system tray window
+ */
+ void systemTrayWindowRemoved(WId id);
+
+ /**
+ * The workarea has changed.
+ */
+ void workAreaChanged();
+
+ /**
+ * Something changed with the struts, may or may not have changed
+ * the work area. Usually just using the workAreaChanged() signal
+ * is sufficient.
+ */
+ void strutChanged();
+
+ /**
+ * Emitted when the stacking order of the window changed. The new order
+ * can be obtained with stackingOrder().
+ */
+ void stackingOrderChanged();
+
+
+ /**
+ * The window changed.
+ *
+ * The properties parameter contains the NET properties that
+ * were modified (see netwm_def.h). First element are NET::Property
+ * values, second element are NET::Property2 values (i.e. the format
+ * is the same like for the NETWinInfo class constructor).
+ * @param id the id of the window
+ * @param properties the properties that were modified
+ */
+ void windowChanged(WId id, const unsigned long* properties );
+
+ /**
+ * @deprecated
+ * The window changed.
+ *
+ * The unsigned int parameter contains the NET properties that
+ * were modified (see netwm_def.h).
+ * @param id the id of the window
+ * @param properties the properties that were modified
+ */
+ void windowChanged(WId id, unsigned int properties);
+
+ /**
+ * The window changed somehow.
+ * @param id the id of the window
+ */
+ void windowChanged(WId id);
+
+ /**
+ * The state of showing the desktop has changed.
+ * @since 3.5
+ */
+ void showingDesktopChanged( bool showing );
+
+ /**
+ * The state of showing the desktop has changed.
+ * @since 3.5.5
+ */
+ void desktopGeometryChanged(int desktop);
+
+ /**
+ * The viewport position has changed
+ * @since 3.5
+ */
+ void currentDesktopViewportChanged(int desktop, const QPoint& viewport);
+
+protected:
+ virtual void connectNotify( const char* signal );
+
+private:
+ void init(int);
+
+ KWinModulePrivate* d;
+
+ friend class KWinModulePrivate;
+};
+
+#endif //Q_OS_UNIX
+
+#endif
diff --git a/kdecore/kxerrorhandler.cpp b/kdecore/kxerrorhandler.cpp
new file mode 100644
index 000000000..c632012d2
--- /dev/null
+++ b/kdecore/kxerrorhandler.cpp
@@ -0,0 +1,121 @@
+/*
+
+ Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
+
+ 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 OR COPYRIGHT HOLDERS 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.
+
+*/
+
+#include <qwidget.h>
+#ifdef Q_WS_X11 //FIXME
+
+#include "kxerrorhandler.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <netwm_def.h>
+
+KXErrorHandler** KXErrorHandler::handlers = NULL;
+int KXErrorHandler::pos = 0;
+int KXErrorHandler::size = 0;
+
+KXErrorHandler::KXErrorHandler( Display* dpy )
+ : user_handler1( NULL ),
+ user_handler2( NULL ),
+ old_handler( XSetErrorHandler( handler_wrapper )),
+ first_request( XNextRequest( dpy )),
+ display( dpy ),
+ was_error( false )
+ {
+ addHandler();
+ }
+
+KXErrorHandler::KXErrorHandler( bool (*handler)( int request, int error_code, unsigned long resource_id ), Display* dpy )
+ : user_handler1( handler ),
+ user_handler2( NULL ),
+ old_handler( XSetErrorHandler( handler_wrapper )),
+ first_request( XNextRequest( dpy )),
+ display( dpy ),
+ was_error( false )
+ {
+ addHandler();
+ }
+
+KXErrorHandler::KXErrorHandler( int (*handler)( Display*, XErrorEvent* ), Display* dpy )
+ : user_handler1( NULL ),
+ user_handler2( handler ),
+ old_handler( XSetErrorHandler( handler_wrapper )),
+ first_request( XNextRequest( dpy )),
+ display( dpy ),
+ was_error( false )
+ {
+ addHandler();
+ }
+
+KXErrorHandler::~KXErrorHandler()
+ {
+ XSetErrorHandler( old_handler );
+ assert( this == handlers[ pos - 1 ] ); // destroy in reverse order
+ --pos;
+ }
+
+void KXErrorHandler::addHandler()
+ {
+ if( size == pos )
+ {
+ size += 16;
+ handlers = static_cast< KXErrorHandler** >( realloc( handlers, size * sizeof( KXErrorHandler* )));
+ }
+ handlers[ pos++ ] = this;
+ }
+
+bool KXErrorHandler::error( bool sync ) const
+ {
+ if( sync )
+ XSync( display, False );
+ return was_error;
+ }
+
+int KXErrorHandler::handler_wrapper( Display* dpy, XErrorEvent* e )
+ {
+ --pos;
+ int ret = handlers[ pos ]->handle( dpy, e );
+ ++pos;
+ return ret;
+ }
+
+int KXErrorHandler::handle( Display* dpy, XErrorEvent* e )
+ {
+ if( dpy == display
+ // e->serial >= first_request , compare like X timestamps to handle wrapping
+ && NET::timestampCompare( e->serial, first_request ) >= 0 )
+ { // it's for us
+ //qDebug( "Handling: %p", static_cast< void* >( this ));
+ if( user_handler1 != NULL && user_handler1( e->request_code, e->error_code, e->resourceid ))
+ was_error = true;
+ if( user_handler2 != NULL && user_handler2( dpy, e ) != 0 )
+ was_error = true;
+ else // no handler set, simply set that there was an error
+ was_error = true;
+ return 0;
+ }
+ //qDebug( "Going deeper: %p", static_cast< void* >( this ));
+ return old_handler( dpy, e );
+ }
+
+#endif
diff --git a/kdecore/kxerrorhandler.h b/kdecore/kxerrorhandler.h
new file mode 100644
index 000000000..2140bbd44
--- /dev/null
+++ b/kdecore/kxerrorhandler.h
@@ -0,0 +1,104 @@
+/*
+
+ Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
+
+ 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 OR COPYRIGHT HOLDERS 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.
+
+*/
+
+#ifndef KXERRORHANDLER_H
+#define KXERRORHANDLER_H
+
+#include <qvaluelist.h>
+#include <qwindowdefs.h>
+#include <kdelibs_export.h>
+#include <X11/Xlib.h>
+
+/**
+ * This class simplifies handling of X errors. It shouldn't be necessary to use
+ * with Qt classes, as the toolkit should handle X errors itself, so this
+ * class will be mainly used with direct Xlib usage, and some lowlevel classes
+ * like NETWinInfo.
+ *
+ * The usual usage is to create a KXErrorHandler instance right before starting
+ * operations that might cause X errors, and checking if there was an error
+ * by calling error() after the operations are finished. The handlers
+ * may be nested, but must be destroyed in reverse order they were created.
+ *
+ * There's no need to do X sync before creating an instance, every instance
+ * will handle only errors for request issued after the instance was created.
+ * Errors for older requests will be passed to previous error handler.
+ * When checking for error by calling error() at the end, it is necessary
+ * to sync with X, to catch all errors that were caused by requests issued
+ * before the call to error(). This can be done by passing true to error()
+ * to cause explicit XSync(), however, if the last X request needed a roundtrip
+ * (e.g. XGetWindowAttributes(), XGetGeometry(), etc.), it is not required
+ * to do an explicit sync.
+ *
+ * @author Lubos Lunak <l.lunak@kde.org>
+ * @short Handler for X errors
+ */
+class KDECORE_EXPORT KXErrorHandler
+ {
+ public:
+ /**
+ * Creates error handler that will set error flag after encountering
+ * any X error.
+ */
+ KXErrorHandler( Display* dpy = qt_xdisplay());
+ /**
+ * This constructor takes pointer to a function that will get request number,
+ * error code number and resource id of the failed request, as provided
+ * by XErrorEvent. If the function returns true, the error flag will be set.
+ */
+ KXErrorHandler( bool (*handler)( int request, int error_code, unsigned long resource_id ), Display* dpy = qt_xdisplay());
+ /**
+ * This constructor takes pointer to a function whose prototype matches
+ * the one that's used with the XSetErrorHandler() Xlib function.
+ * NOTE: For the error flag to be set, the function must return non-zero
+ * value.
+ */
+ KXErrorHandler( int (*handler)( Display*, XErrorEvent* ), Display* dpy = qt_xdisplay());
+ /**
+ * This function returns true if the error flag is set (i.e. no custom handler
+ * function was used and there was any error, or the custom handler indicated
+ * an error by its return value).
+ *
+ * @param sync if true, and explicit XSync() will be done. Not necessary
+ * when the last X request required a roundtrip.
+ */
+ bool error( bool sync ) const;
+ ~KXErrorHandler();
+ private:
+ void addHandler();
+ int handle( Display* dpy, XErrorEvent* e );
+ bool (*user_handler1)( int request, int error_code, unsigned long resource_id );
+ int (*user_handler2)( Display*, XErrorEvent* );
+ int (*old_handler)( Display*, XErrorEvent* );
+ unsigned long first_request;
+ Display* display;
+ bool was_error;
+ static int handler_wrapper( Display*, XErrorEvent* );
+ static KXErrorHandler** handlers;
+ static int pos;
+ static int size;
+ class KXErrorHandlerPrivate* d;
+ };
+
+#endif
diff --git a/kdecore/kxmessages.cpp b/kdecore/kxmessages.cpp
new file mode 100644
index 000000000..b730c73a7
--- /dev/null
+++ b/kdecore/kxmessages.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+
+ $Id$
+
+ Copyright (C) 2001-2003 Lubos Lunak <l.lunak@kde.org>
+
+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 OR COPYRIGHT HOLDERS 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.
+
+****************************************************************************/
+
+#include "kxmessages.h"
+
+#include <kapplication.h>
+
+#ifdef Q_WS_X11 // FIXME(E): Figure out what parts we can/should emulate in QT/E
+
+#include <X11/Xlib.h>
+#include <kdebug.h>
+
+// for broadcasting
+const long BROADCAST_MASK = PropertyChangeMask;
+// CHECKME
+
+KXMessages::KXMessages( const char* accept_broadcast_P, QWidget* parent_P )
+ : QWidget( parent_P )
+ {
+ if( accept_broadcast_P != NULL )
+ {
+ ( void ) kapp->desktop(); //trigger desktop widget creation to select root window events
+ kapp->installX11EventFilter( this ); // i.e. PropertyChangeMask
+ accept_atom1 = XInternAtom( qt_xdisplay(), accept_broadcast_P, false );
+ accept_atom2 = accept_atom1;
+ }
+ else
+ {
+ accept_atom1 = accept_atom2 = None;
+ }
+ handle = new QWidget( this );
+ }
+
+KXMessages::KXMessages( const char* accept_broadcast_P, QWidget* parent_P, bool obsolete_P )
+ : QWidget( parent_P )
+ {
+ if( accept_broadcast_P != NULL )
+ {
+ ( void ) kapp->desktop(); //trigger desktop widget creation to select root window events
+ kapp->installX11EventFilter( this ); // i.e. PropertyChangeMask
+ accept_atom2 = XInternAtom( qt_xdisplay(), accept_broadcast_P, false );
+ accept_atom1 = obsolete_P ? accept_atom2
+ : XInternAtom( qt_xdisplay(), QCString( accept_broadcast_P ) + "_BEGIN", false );
+ }
+ else
+ {
+ accept_atom1 = accept_atom2 = None;
+ }
+ handle = new QWidget( this );
+ }
+
+KXMessages::~KXMessages()
+ {
+// delete d; no private data yet
+ }
+
+
+void KXMessages::broadcastMessage( const char* msg_type_P, const QString& message_P )
+ {
+ broadcastMessage( msg_type_P, message_P, -1, true );
+ }
+
+void KXMessages::broadcastMessage( const char* msg_type_P, const QString& message_P,
+ int screen_P, bool obsolete_P )
+ {
+ Atom a2 = XInternAtom( qt_xdisplay(), msg_type_P, false );
+ Atom a1 = obsolete_P ? a2 : XInternAtom( qt_xdisplay(), QCString( msg_type_P ) + "_BEGIN", false );
+ Window root = screen_P == -1 ? qt_xrootwin() : qt_xrootwin( screen_P );
+ send_message_internal( root, message_P, BROADCAST_MASK, qt_xdisplay(),
+ a1, a2, handle->winId());
+ }
+
+void KXMessages::sendMessage( WId w_P, const char* msg_type_P, const QString& message_P )
+ {
+ sendMessage( w_P, msg_type_P, message_P, true );
+ }
+
+void KXMessages::sendMessage( WId w_P, const char* msg_type_P, const QString& message_P,
+ bool obsolete_P )
+ {
+ Atom a2 = XInternAtom( qt_xdisplay(), msg_type_P, false );
+ Atom a1 = obsolete_P ? a2 : XInternAtom( qt_xdisplay(), QCString( msg_type_P ) + "_BEGIN", false );
+ send_message_internal( w_P, message_P, 0, qt_xdisplay(), a1, a2, handle->winId());
+ }
+
+bool KXMessages::broadcastMessageX( Display* disp, const char* msg_type_P,
+ const QString& message_P )
+ {
+ return broadcastMessageX( disp, msg_type_P, message_P, -1, true );
+ }
+
+bool KXMessages::broadcastMessageX( Display* disp, const char* msg_type_P,
+ const QString& message_P, int screen_P, bool obsolete_P )
+ {
+ if( disp == NULL )
+ return false;
+ Atom a2 = XInternAtom( disp, msg_type_P, false );
+ Atom a1 = obsolete_P ? a2 : XInternAtom( disp, QCString( msg_type_P ) + "_BEGIN", false );
+ Window root = screen_P == -1 ? DefaultRootWindow( disp ) : RootWindow( disp, screen_P );
+ Window win = XCreateSimpleWindow( disp, root, 0, 0, 1, 1,
+ 0, BlackPixel( disp, screen_P == -1 ? DefaultScreen( disp ) : screen_P ),
+ BlackPixel( disp, screen_P == -1 ? DefaultScreen( disp ) : screen_P ));
+ send_message_internal( root, message_P, BROADCAST_MASK, disp,
+ a1, a2, win );
+ XDestroyWindow( disp, win );
+ return true;
+ }
+
+bool KXMessages::sendMessageX( Display* disp, WId w_P, const char* msg_type_P,
+ const QString& message_P )
+ {
+ return sendMessageX( disp, w_P, msg_type_P, message_P, true );
+ }
+
+bool KXMessages::sendMessageX( Display* disp, WId w_P, const char* msg_type_P,
+ const QString& message_P, bool obsolete_P )
+ {
+ if( disp == NULL )
+ return false;
+ Atom a2 = XInternAtom( disp, msg_type_P, false );
+ Atom a1 = obsolete_P ? a2 : XInternAtom( disp, QCString( msg_type_P ) + "_BEGIN", false );
+ Window win = XCreateSimpleWindow( disp, DefaultRootWindow( disp ), 0, 0, 1, 1,
+ 0, BlackPixelOfScreen( DefaultScreenOfDisplay( disp )),
+ BlackPixelOfScreen( DefaultScreenOfDisplay( disp )));
+ send_message_internal( w_P, message_P, 0, disp, a1, a2, win );
+ XDestroyWindow( disp, win );
+ return true;
+ }
+
+void KXMessages::send_message_internal( WId w_P, const QString& msg_P, long mask_P,
+ Display* disp, Atom atom1_P, Atom atom2_P, Window handle_P )
+ {
+ unsigned int pos = 0;
+ QCString msg = msg_P.utf8();
+ unsigned int len = strlen( msg );
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = atom1_P; // leading message
+ e.xclient.display = disp;
+ e.xclient.window = handle_P;
+ e.xclient.format = 8;
+ do
+ {
+ unsigned int i;
+ for( i = 0;
+ i < 20 && i + pos <= len;
+ ++i )
+ e.xclient.data.b[ i ] = msg[ i + pos ];
+ XSendEvent( disp, w_P, false, mask_P, &e );
+ e.xclient.message_type = atom2_P; // following messages
+ pos += i;
+ } while( pos <= len );
+ XFlush( disp );
+ }
+
+bool KXMessages::x11Event( XEvent* ev_P )
+ {
+ if( ev_P->type != ClientMessage || ev_P->xclient.format != 8 )
+ return QWidget::x11Event( ev_P );
+ if( ev_P->xclient.message_type != accept_atom1 && ev_P->xclient.message_type != accept_atom2 )
+ return QWidget::x11Event( ev_P );
+ char buf[ 21 ]; // can't be longer
+ int i;
+ for( i = 0;
+ i < 20 && ev_P->xclient.data.b[ i ] != '\0';
+ ++i )
+ buf[ i ] = ev_P->xclient.data.b[ i ];
+ buf[ i ] = '\0';
+ if( incoming_messages.contains( ev_P->xclient.window ))
+ {
+ if( ev_P->xclient.message_type == accept_atom1 && accept_atom1 != accept_atom2 )
+ // two different messages on the same window at the same time shouldn't happen anyway
+ incoming_messages[ ev_P->xclient.window ] = QCString();
+ incoming_messages[ ev_P->xclient.window ] += buf;
+ }
+ else
+ {
+ if( ev_P->xclient.message_type == accept_atom2 && accept_atom1 != accept_atom2 )
+ return false; // middle of message, but we don't have the beginning
+ incoming_messages[ ev_P->xclient.window ] = buf;
+ }
+ if( i < 20 ) // last message fragment
+ {
+ emit gotMessage( QString::fromUtf8( incoming_messages[ ev_P->xclient.window ] ));
+ incoming_messages.remove( ev_P->xclient.window );
+ }
+ return false; // lets other KXMessages instances get the event too
+ }
+
+#include "kxmessages.moc"
+#endif
diff --git a/kdecore/kxmessages.h b/kdecore/kxmessages.h
new file mode 100644
index 000000000..9595ebde5
--- /dev/null
+++ b/kdecore/kxmessages.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+
+ Copyright (C) 2001-2003 Lubos Lunak <l.lunak@kde.org>
+
+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 OR COPYRIGHT HOLDERS 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.
+
+****************************************************************************/
+
+#ifndef __KXMESSAGES_H
+#define __KXMESSAGES_H
+
+#include <qwidget.h>
+#include <qcstring.h>
+#include <qmap.h>
+#include <kdelibs_export.h>
+#ifdef Q_WS_X11
+#include <X11/X.h>
+
+class QString;
+
+class KXMessagesPrivate;
+/**
+ * Sending string messages to other applications using the X Client Messages.
+ *
+ * Used internally by KStartupInfo. You usually don't want to use this, use DCOP
+ * instead.
+ *
+ * @author Lubos Lunak <l.lunak@kde.org>
+ */
+// KDE4 - make this internal for KStartupInfo only?
+class KDECORE_EXPORT KXMessages
+ : public QWidget
+ {
+ Q_OBJECT
+ public:
+ /**
+ * Creates an instance which will receive X messages.
+ *
+ * @param accept_broadcast if non-NULL, all broadcast messages with
+ * this message type will be received.
+ * @param parent the parent of this widget
+ * @param obsolete always set to false (needed for backwards compatibility
+ * with KDE3.1 and older)
+ */
+ KXMessages( const char* accept_broadcast, QWidget* parent, bool obsolete );
+ /**
+ * @deprecated
+ * This method is equivalent to the other constructor with obsolete = true.
+ */
+ KXMessages( const char* accept_broadcast = NULL, QWidget* parent = NULL );
+
+ virtual ~KXMessages();
+ /**
+ * Sends the given message with the given message type only to given
+ * window.
+ *
+ * @param w X11 handle for the destination window
+ * @param msg_type the type of the message
+ * @param message the message itself
+ * @param obsolete always set to false (needed for backwards compatibility
+ * with KDE3.1 and older)
+ */
+ void sendMessage( WId w, const char* msg_type, const QString& message,
+ bool obsolete );
+ /**
+ * @deprecated
+ * This method is equivalent to sendMessage() with obsolete = true.
+ */
+ void sendMessage( WId w, const char* msg_type, const QString& message );
+ /**
+ * Broadcasts the given message with the given message type.
+ * @param msg_type the type of the message
+ * @param message the message itself
+ * @param screen X11 screen to use, -1 for the default
+ * @param obsolete always set to false (needed for backwards compatibility
+ * with KDE3.1 and older)
+ */
+ void broadcastMessage( const char* msg_type, const QString& message,
+ int screen, bool obsolete );
+ /**
+ * @deprecated
+ * This method is equivalent to broadcastMessage() with obsolete = true.
+ */
+ void broadcastMessage( const char* msg_type, const QString& message );
+
+ /**
+ * Sends the given message with the given message type only to given
+ * window.
+ *
+ * @param disp X11 connection which will be used instead of
+ * qt_x11display()
+ * @param w X11 handle for the destination window
+ * @param msg_type the type of the message
+ * @param message the message itself
+ * @param obsolete always set to false (needed for backwards compatibility
+ * with KDE3.1 and older)
+ * @return false when an error occurred, true otherwise
+ */
+ static bool sendMessageX( Display* disp, WId w, const char* msg_type,
+ const QString& message, bool obsolete );
+ /**
+ * @deprecated
+ * This method is equivalent to sendMessageX() with obsolete = true.
+ */
+ static bool sendMessageX( Display* disp, WId w, const char* msg_type,
+ const QString& message );
+
+ /**
+ * Broadcasts the given message with the given message type.
+ *
+ * @param disp X11 connection which will be used instead of
+ * qt_x11display()
+ * @param msg_type the type of the message
+ * @param message the message itself
+ * @param screen X11 screen to use, -1 for the default
+ * @param obsolete always set to false (needed for backwards compatibility
+ * with KDE3.1 and older)
+ * @return false when an error occurred, true otherwise
+ */
+ static bool broadcastMessageX( Display* disp, const char* msg_type,
+ const QString& message, int screen, bool obsolete );
+ /**
+ * @deprecated
+ * This method is equivalent to broadcastMessageX() with obsolete = true.
+ */
+ static bool broadcastMessageX( Display* disp, const char* msg_type,
+ const QString& message );
+ signals:
+ /**
+ * Emitted when a message was received.
+ * @param message the message that has been received
+ */
+ void gotMessage( const QString& message );
+ protected:
+ /**
+ * @internal
+ */
+ virtual bool x11Event( XEvent* ev );
+ private:
+ static void send_message_internal( WId w_P, const QString& msg_P, long mask_P,
+ Display* disp, Atom atom1_P, Atom atom2_P, Window handle_P );
+ QWidget* handle;
+ Atom accept_atom2;
+ QCString cached_atom_name_; // KDE4 unused
+ Atom accept_atom1;
+ QMap< WId, QCString > incoming_messages;
+ KXMessagesPrivate* d;
+ };
+
+#endif
+#endif
diff --git a/kdecore/language.codes b/kdecore/language.codes
new file mode 100644
index 000000000..bb33f3456
--- /dev/null
+++ b/kdecore/language.codes
@@ -0,0 +1,3 @@
+[TwoLetterCodes]
+nb=nb,no
+nn=nn,no
diff --git a/kdecore/libintl.cpp b/kdecore/libintl.cpp
new file mode 100644
index 000000000..2b60302d3
--- /dev/null
+++ b/kdecore/libintl.cpp
@@ -0,0 +1,420 @@
+/* libintl.cpp -- gettext related functions from glibc-2.0.5
+ Copyright (C) 1995 Software Foundation, Inc.
+
+This file is part of the KDE libraries, but it's derived work out
+of glibc. The master sources can be found in
+
+ bindtextdom.c
+ dcgettext.c
+ dgettext.c
+ explodename.c
+ finddomain.c
+ gettext.c
+ gettext.h
+ gettextP.h
+ hash-string.h
+ l10nflist.c
+ libintl.h
+ loadinfo.h
+ loadmsgcat.c
+ localealias.c
+ textdomain.c
+
+which are part of glibc. The license is the same as in GLIBC, which
+is the GNU Library General Public License. See COPYING.LIB for more
+details.
+
+*/
+
+/* gettext.c -- implementation of gettext(3) function
+ Copyright (C) 1995 Software Foundation, Inc.
+
+This file is part of the GNU C Library. Its master source is NOT part of
+the C library, however. The master source lives in /gd/gnu/lib.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "kdelibs_export.h"
+#include "kde_file.h"
+#include <config.h>
+
+#include <qglobal.h>
+
+#include <stdlib.h>
+
+#if defined HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#if defined HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP)
+# include <sys/mman.h>
+#endif
+
+#ifndef W
+# define W(flag, data) ((flag) ? SWAP (data) : (data))
+#endif
+
+typedef Q_UINT32 nls_uint32;
+
+struct loaded_domain
+{
+ const char *data;
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
+ int use_mmap;
+ size_t mmap_size;
+#endif
+ int must_swap;
+ nls_uint32 nstrings;
+ struct string_desc *orig_tab;
+ struct string_desc *trans_tab;
+ nls_uint32 hash_size;
+ nls_uint32 *hash_tab;
+};
+
+struct kde_loaded_l10nfile
+{
+ const char *filename;
+ int decided;
+
+ const void *data;
+
+ kde_loaded_l10nfile() : filename(0), decided(0), data(0) {}
+};
+
+void k_nl_load_domain(struct kde_loaded_l10nfile *__domain);
+
+static inline nls_uint32
+SWAP (nls_uint32 i)
+{
+ return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+}
+
+/* @@ end of prolog @@ */
+
+/* The magic number of the GNU message catalog format. */
+#define _MAGIC 0x950412de
+#define _MAGIC_SWAPPED 0xde120495
+
+/* Revision number of the currently used .mo (binary) file format. */
+#define MO_REVISION_NUMBER 0
+
+
+/* Defines the so called `hashpjw' function by P.J. Weinberger
+ [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+ 1986, 1987 Bell Telephone Laboratories, Inc.] */
+static inline unsigned long hash_string (const char *__str_param);
+
+/* @@ end of prolog @@ */
+
+/* Header for binary .mo file format. */
+struct mo_file_header
+{
+ /* The magic number. */
+ nls_uint32 magic;
+ /* The revision number of the file format. */
+ nls_uint32 revision;
+ /* The number of strings pairs. */
+ nls_uint32 nstrings;
+ /* Offset of table with start offsets of original strings. */
+ nls_uint32 orig_tab_offset;
+ /* Offset of table with start offsets of translation strings. */
+ nls_uint32 trans_tab_offset;
+ /* Size of hashing table. */
+ nls_uint32 hash_tab_size;
+ /* Offset of first hashing entry. */
+ nls_uint32 hash_tab_offset;
+};
+
+struct string_desc
+{
+ /* Length of addressed string. */
+ nls_uint32 length;
+ /* Offset of string in file. */
+ nls_uint32 offset;
+};
+
+/* Prototypes for local functions. */
+char *k_nl_find_msg (struct kde_loaded_l10nfile *domain_file,
+ const char *msgid);
+
+char *
+k_nl_find_msg (struct kde_loaded_l10nfile *domain_file, const char *msgid)
+{
+ size_t top, act, bottom;
+ struct loaded_domain *domain;
+
+ if (domain_file->decided == 0)
+ k_nl_load_domain (domain_file);
+
+ if (domain_file->data == NULL)
+ return NULL;
+
+ domain = (struct loaded_domain *) domain_file->data;
+
+ /* Locate the MSGID and its translation. */
+ if (domain->hash_size > 2 && domain->hash_tab != NULL)
+ {
+ /* Use the hashing table. */
+ nls_uint32 len = strlen (msgid);
+ nls_uint32 hash_val = hash_string (msgid);
+ nls_uint32 idx = hash_val % domain->hash_size;
+ nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
+ nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
+
+ if (nstr == 0)
+ /* Hash table entry is empty. */
+ return NULL;
+
+ if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+ && strcmp (msgid,
+ domain->data + W (domain->must_swap,
+ domain->orig_tab[nstr - 1].offset)) == 0)
+ return (char *) domain->data + W (domain->must_swap,
+ domain->trans_tab[nstr - 1].offset);
+
+ while (1)
+ {
+ if (idx >= domain->hash_size - incr)
+ idx -= domain->hash_size - incr;
+ else
+ idx += incr;
+
+ nstr = W (domain->must_swap, domain->hash_tab[idx]);
+ if (nstr == 0)
+ /* Hash table entry is empty. */
+ return NULL;
+
+ if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+ && strcmp (msgid,
+ domain->data + W (domain->must_swap,
+ domain->orig_tab[nstr - 1].offset))
+ == 0)
+ return (char *) domain->data
+ + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
+ }
+ /* NOTREACHED */
+ }
+
+ /* Now we try the default method: binary search in the sorted
+ array of messages. */
+ bottom = 0;
+ top = domain->nstrings;
+ act = top;
+ while (bottom < top)
+ {
+ int cmp_val;
+
+ act = (bottom + top) / 2;
+ cmp_val = strcmp (msgid, domain->data
+ + W (domain->must_swap,
+ domain->orig_tab[act].offset));
+ if (cmp_val < 0)
+ top = act;
+ else if (cmp_val > 0)
+ bottom = act + 1;
+ else
+ break;
+ }
+
+ /* If an translation is found return this. */
+ return bottom >= top ? NULL : (char *) domain->data
+ + W (domain->must_swap,
+ domain->trans_tab[act].offset);
+}
+
+/* @@ begin of epilog @@ */
+/* We assume to have `unsigned long int' value with at least 32 bits. */
+#define HASHWORDBITS 32
+
+static inline unsigned long
+hash_string (const char *str_param)
+{
+ unsigned long int hval, g;
+ const char *str = str_param;
+
+ /* Compute the hash value for the given string. */
+ hval = 0;
+ while (*str != '\0')
+ {
+ hval <<= 4;
+ hval += (unsigned long) *str++;
+ g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4));
+ if (g != 0)
+ {
+ hval ^= g >> (HASHWORDBITS - 8);
+ hval ^= g;
+ }
+ }
+ return hval;
+}
+
+/* Load the message catalogs specified by FILENAME. If it is no valid
+ message catalog do nothing. */
+void
+k_nl_load_domain (struct kde_loaded_l10nfile *domain_file)
+{
+ int fd;
+ struct stat st;
+ struct mo_file_header *data = (struct mo_file_header *) -1;
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
+ int use_mmap = 0;
+#endif
+ struct loaded_domain *domain;
+
+ domain_file->decided = 1;
+ domain_file->data = NULL;
+
+ /* If the record does not represent a valid locale the FILENAME
+ might be NULL. This can happen when according to the given
+ specification the locale file name is different for XPG and CEN
+ syntax. */
+ if (domain_file->filename == NULL)
+ return;
+
+ /* Try to open the addressed file. */
+ fd = KDE_open (domain_file->filename, O_RDONLY);
+ if (fd == -1)
+ return;
+
+ /* We must know about the size of the file. */
+ if (fstat (fd, &st) != 0
+ || st.st_size < (off_t) sizeof (struct mo_file_header))
+ {
+ /* Something went wrong. */
+ close (fd);
+ return;
+ }
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
+ /* Now we are ready to load the file. If mmap() is available we try
+ this first. If not available or it failed we try to load it. */
+ data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ,
+ MAP_PRIVATE, fd, 0);
+
+ if (data != (struct mo_file_header *) -1)
+ {
+ /* mmap() call was successful. */
+ close (fd);
+ use_mmap = 1;
+ }
+#endif
+
+ /* If the data is not yet available (i.e. mmap'ed) we try to load
+ it manually. */
+ if (data == (struct mo_file_header *) -1)
+ {
+ off_t to_read;
+ char *read_ptr;
+
+ data = (struct mo_file_header *) malloc (st.st_size);
+ if (data == NULL)
+ return;
+
+ to_read = st.st_size;
+ read_ptr = (char *) data;
+ do
+ {
+ long int nb = (long int) read (fd, read_ptr, to_read);
+ if (nb == -1)
+ {
+ close (fd);
+ return;
+ }
+
+ read_ptr += nb;
+ to_read -= nb;
+ }
+ while (to_read > 0);
+
+ close (fd);
+ }
+
+ /* Using the magic number we can test whether it really is a message
+ catalog file. */
+ if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
+ {
+ /* The magic number is wrong: not a message catalog file. */
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
+ if (use_mmap)
+ munmap ((char *) data, st.st_size);
+ else
+#endif
+ free (data);
+ return;
+ }
+
+ domain_file->data
+ = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
+ if (domain_file->data == NULL)
+ return;
+
+ domain = (struct loaded_domain *) domain_file->data;
+ domain->data = (char *) data;
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
+ domain->use_mmap = use_mmap;
+ domain->mmap_size = st.st_size;
+#endif
+ domain->must_swap = data->magic != _MAGIC;
+
+ /* Fill in the information about the available tables. */
+ switch (W (domain->must_swap, data->revision))
+ {
+ case 0:
+ domain->nstrings = W (domain->must_swap, data->nstrings);
+ domain->orig_tab = (struct string_desc *)
+ ((char *) data + W (domain->must_swap, data->orig_tab_offset));
+ domain->trans_tab = (struct string_desc *)
+ ((char *) data + W (domain->must_swap, data->trans_tab_offset));
+ domain->hash_size = W (domain->must_swap, data->hash_tab_size);
+ domain->hash_tab = (nls_uint32 *)
+ ((char *) data + W (domain->must_swap, data->hash_tab_offset));
+ break;
+ default:
+ /* This is an illegal revision. */
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
+ if (use_mmap)
+ munmap ((char *) data, st.st_size);
+ else
+#endif
+ free (data);
+ free (domain);
+ domain_file->data = NULL;
+ return;
+ }
+}
+
+void
+k_nl_unload_domain (struct loaded_domain *domain)
+{
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
+ if (domain->use_mmap)
+ munmap ((caddr_t) domain->data, domain->mmap_size);
+ else
+# endif
+ free ((void *) domain->data);
+
+ free (domain);
+}
diff --git a/kdecore/libkdecore.nmcheck b/kdecore/libkdecore.nmcheck
new file mode 100644
index 000000000..b8057d350
--- /dev/null
+++ b/kdecore/libkdecore.nmcheck
@@ -0,0 +1,79 @@
+# KDE namespace check file
+
+# kdecore classes
+K*::*
+
+# these should preferably go in some namespace in KDE4
+NETRootInfo::*
+NETRootInfo2::*
+NETRootInfo3::*
+NETWinInfo::*
+NET::*
+kdbgstream::*
+kndbgstream::*
+kdDebug
+kndDebug
+kdWarning
+kdError
+kdFatal
+kdBacktrace
+kndBacktrace
+kdClearDebugConfig
+flush
+perror
+endl
+i18n
+DesktopIcon
+DesktopIconSet
+BarIcon
+BarIconSet
+SmallIcon
+SmallIconSet
+MainBarIcon
+MainBarIconSet
+UserIcon
+UserIconSet
+IconSize
+locate
+locateLocal
+checkAccess
+k_nl_*
+kde_*
+urlcmp
+operator>>
+operator<<
+qt_qclipboard_bailout_hack
+kasciistricmp
+
+# from libtldl
+lt_dl*
+
+# from kdefakes
+setenv
+unsetenv
+usleep
+random
+srandom
+seteuid
+mkstemps
+mkstemp
+revoke
+strlcpy
+strlcat
+vsnprintf
+snprintf
+
+# from malloc
+malloc
+free
+realloc
+calloc
+mallinfo
+mallopt
+cfree
+valloc
+pvalloc
+posix_memalign
+memalign
+kde_malloc_is_used
+kde_malloc_dummy_function
diff --git a/kdecore/libkdecore_weak.nmcheck b/kdecore/libkdecore_weak.nmcheck
new file mode 100644
index 000000000..43efca972
--- /dev/null
+++ b/kdecore/libkdecore_weak.nmcheck
@@ -0,0 +1,28 @@
+# KDE namespace check file
+
+# kdelibs classes
+KApplication::*
+
+# these should preferably go in some namespace in KDE4
+kDebugPrivate::*
+kMax
+kMin
+kAbs
+NETIcon::*
+NETPoint::*
+NETRect::*
+NETSize::*
+NETStrut::*
+NETRArray::*
+NETWinInfoPrivate::*
+NETRootInfoPrivate::*
+kdbgstream::*
+kndbgstream::*
+flush
+perror
+endl
+
+# from libc_nonshared
+stat
+lstat
+fstat
diff --git a/kdecore/libqt-mt.nmcheck b/kdecore/libqt-mt.nmcheck
new file mode 100644
index 000000000..77b200029
--- /dev/null
+++ b/kdecore/libqt-mt.nmcheck
@@ -0,0 +1,43 @@
+# KDE namespace check file
+
+# Qt classes
+Q*::*
+qt_*
+
+# these should preferably go in some namespace in Qt4
+qDebug
+qFatal
+qWarning
+qApp
+qAppName
+qVersion
+qSysInfo
+qObsolete
+bitBlt
+static_QUType_*
+TID_QUType_*
+operator>>
+operator<<
+operator==
+operator!=
+operator<=
+operator>=
+operator<
+operator>
+operator=
+operator++
+operator*
+operator!
+operator^
+operator&
+operator/
+ws
+bin
+dec
+oct
+hex
+endl
+
+# Xinerama
+Xinerama*
+XPanoramiX*
diff --git a/kdecore/libqt-mt_weak.nmcheck b/kdecore/libqt-mt_weak.nmcheck
new file mode 100644
index 000000000..d0b00eee4
--- /dev/null
+++ b/kdecore/libqt-mt_weak.nmcheck
@@ -0,0 +1,34 @@
+# KDE namespace check file
+
+# Qt classes
+Q*::*
+
+qstrcmp
+qstrcpy
+qstrlen
+qAlpha
+qRed
+qGreen
+qBlue
+qGray
+qRgba
+qRgb
+qSwap
+qCopy
+qHeapSort
+qHeapSortHelper
+qHeapSortPushDown
+qMakePair
+
+operator+
+operator-
+operator++
+operator--
+operator==
+operator!=
+operator<=
+operator>=
+operator>
+operator<
+operator>>
+operator<<
diff --git a/kdecore/malloc/Makefile.am b/kdecore/malloc/Makefile.am
new file mode 100644
index 000000000..60befbfa0
--- /dev/null
+++ b/kdecore/malloc/Makefile.am
@@ -0,0 +1,31 @@
+# This file is part of the KDE libraries
+#
+# $Id$
+#
+# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997 Stephan Kulow (coolo@kde.org)
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+
+# This library 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+INCLUDES = $(all_includes)
+
+AM_DEFS = $(KDE_FORCE_INLINE)
+
+noinst_LTLIBRARIES = libklmalloc.la
+
+libklmalloc_la_SOURCES = malloc.c
+
+EXTRA_DIST = x86.h glibc.h
diff --git a/kdecore/malloc/README b/kdecore/malloc/README
new file mode 100644
index 000000000..181c29764
--- /dev/null
+++ b/kdecore/malloc/README
@@ -0,0 +1,56 @@
+
+ This malloc is based on Doug Lea's malloc ( ftp://gee.cs.oswego.edu/pub/misc/ ), the changes
+are listed below. See http://lists.kde.org/?l=kde-core-devel&m=101351949010285&w=2 for details.
+Basically, it's here because for now it has better performance than both glibc-2.2.x and
+FreeBSD's libc.
+
+ There's a new configure switch, --enable-fast-malloc. By default it's turned off, disabling
+the system libc one and using this one. Using --enable-fast-malloc=full enables this
+malloc unconditionally, aiming for the maximum performance. By using only --enable-fast-malloc,
+it's possible to select both malloc implementations at runtime. When $KDE_MALLOC is set to 0,
+the system libc malloc is used, otherwise this malloc is used.
+
+ For now, the requirements are :
+ - x86 CPU (because of the spinlock implementation in assembler), it should be easy to add
+ new ones
+ - glibc (for --enable-fast-malloc=yes, =full doesn't need it), because it needs to refer
+ to the libc implementation of malloc (__libc_malloc etc.)
+ - gcc (for __inline__ , nothing else should depend on gcc)
+
+
+ If you have any problem with this malloc, try first using --enable-fast-malloc=debug and
+recompiling libkdecore, or use valgrind. This malloc seems to be more vulnerable to heap
+corruption, such as deleting a block twice, so faulty code may run without problems
+with standard malloc shipped with your libc, but it will crash with this malloc. In case
+you think there's any problem with this malloc, please mail me.
+
+changes (against malloc-2.7.0):
+
+#define USE_MALLOC_LOCK
+#define INLINE __inline__
+#define USE_MEMCPY 0
+#define MMAP_CLEARS 1
+made all functions INLINE
+added #ifdef KDE_MALLOC_DEBUG -> #define DEBUG
+reordered all functions in order to avoid 'warning: `XYZ' declared inline after being called'
+ especially moved the public_* ones at the end of the file
+commented out #including malloc.h
+added #include <config.h> at the top and enclosed whole file in #ifdef KDE_MALLOC
+taken posix_memalign() from glibc
+removed public icalloc(),icomalloc(),mtrim(),musable() (they don't exist everywhere anyway)
+enclosed the pthreads part by #if 0 and replaced it with spinlock from glibc CVS (in x86.h)
+ also added :
+----------
+static mutex_t spinlock = MUTEX_INITIALIZER;
+#define MALLOC_PREACTION lock( &spinlock )
+#define MALLOC_POSTACTION unlock( &spinlock )
+----------
+public functions call either functions in this malloc or in libc, depending on $KDE_MALLOC
+the kde_malloc_is_used hack
+
+
+TODO:
+malloc_set_state/malloc_get_state ?
+
+
+Lubos Lunak <l.lunak@kde.org>
diff --git a/kdecore/malloc/configure.in.in b/kdecore/malloc/configure.in.in
new file mode 100644
index 000000000..d669f8daa
--- /dev/null
+++ b/kdecore/malloc/configure.in.in
@@ -0,0 +1,134 @@
+dnl --enable-fast-malloc - depends on $KDE_MALLOC
+dnl --disable-fast-malloc - disabled
+dnl --enable-fast-malloc=full - enabled always
+dnl
+dnl gcc3.0 needs -finline-limit=100000 (large num)
+
+kde_fast_malloc=
+AC_ARG_ENABLE(fast-malloc,
+ [ --enable-fast-malloc Use own malloc implementation : yes,no,full,debug],
+ [
+ if test "$enableval" = "full"; then
+ kde_fast_malloc=full
+ elif test "$enableval" = "yes"; then
+ kde_fast_malloc=yes
+ elif test "$enableval" = "debug"; then
+ kde_fast_malloc=debug
+ else
+ kde_fast_malloc=no
+ fi
+ ],
+ [
+ kde_fast_malloc=notgiven
+ ])
+
+dnl gcc needed for __inline__
+if test "$kde_fast_malloc" != "no"; then
+ if test "$GCC" != "yes"; then
+ if test "$kde_fast_malloc" = "notgiven"; then
+ kde_fast_malloc=no
+ else
+ AC_MSG_ERROR([Fast malloc needs GCC.])
+ kde_fast_malloc=no
+ fi
+ fi
+fi
+
+if test "$kde_fast_malloc" != "no"; then
+dnl platforms for which there's a spinlock implementation
+ case $target_cpu in
+ i?86)
+ AC_DEFINE(KDE_MALLOC_X86, 1, [The platform is x86])
+ ;;
+ *)
+ if test "$kde_fast_malloc" = "notgiven"; then
+ kde_fast_malloc=no
+ else
+ AC_MSG_ERROR([Fast malloc is not supported on this platform (missing spinlock implementation).])
+ fi
+ ;;
+ esac
+dnl warn on untested platforms
+ case $target_os in
+ linux*) ;;
+ freebsd*) ;;
+ *)
+ if test "$kde_fast_malloc" = "notgiven"; then
+ kde_fast_malloc=no
+ else
+ AC_MSG_WARN([Fast malloc is not tested on this platform. The build may fail or the executables may crash.])
+ fi
+ ;;
+ esac
+fi
+
+if test "$kde_fast_malloc" = "yes" -o "$kde_fast_malloc" = "notgiven" -o "$kde_fast_malloc" = "debug"; then
+dnl $KDE_MALLOC needs glibc (__libc_malloc etc.)
+ AC_CACHE_CHECK([if the libc is glibc],kde_cv_libc_glibc,
+ [AC_TRY_COMPILE(
+ [#include<stdlib.h>],
+ [
+ #ifndef __GLIBC__
+ error no glibc
+ #endif
+ ],
+ [kde_cv_libc_glibc=yes],
+ [kde_cv_libc_glibc=no])
+ ])
+ if test "$kde_cv_libc_glibc" = "yes"; then
+ AC_DEFINE(KDE_MALLOC_GLIBC, 1, [The libc used is glibc])
+ else
+ if test "$kde_fast_malloc" = "notgiven"; then
+ kde_fast_malloc=notgiven_full
+ elif test "$enableval" = "debug"; then
+ AC_MSG_WARN([This libc is not supported for fast malloc. Runtime disabling won't work.])
+ kde_fast_malloc=debug_full
+ else
+ AC_MSG_ERROR([This libc is not supported for fast malloc. Either use --enable-fast-malloc=full, or don't use it at all.])
+ fi
+ fi
+fi
+
+if test "$kde_fast_malloc" = "notgiven"; then
+ #kde_fast_malloc=yes
+ kde_fast_malloc=no
+fi
+if test "$kde_fast_malloc" = "notgiven_full"; then
+ if test "$kde_use_debug_code" = "no"; then
+ #kde_fast_malloc=full
+ kde_fast_malloc=no
+ else
+ kde_fast_malloc=no
+ fi
+fi
+
+AC_MSG_CHECKING(whether to enable fast malloc)
+if test "$kde_fast_malloc" = "yes"; then
+ AC_MSG_RESULT(yes)
+elif test "$kde_fast_malloc" = "full"; then
+ AC_MSG_RESULT([yes(full)])
+elif test "$kde_fast_malloc" = "debug"; then
+ AC_MSG_RESULT([yes(debug)])
+elif test "$kde_fast_malloc" = "debug_full"; then
+ AC_MSG_RESULT([yes(full+debug)])
+else
+ AC_MSG_RESULT(no)
+fi
+
+if test "$kde_fast_malloc" != "no"; then
+ AC_DEFINE(KDE_MALLOC, 1, [Use own malloc implementation])
+fi
+
+if test "$kde_fast_malloc" = "debug" -o "$kde_fast_malloc" = "debug_full"; then
+ AC_DEFINE(KDE_MALLOC_DEBUG, 1, [Enable debugging in fast malloc])
+fi
+
+if test "$kde_fast_malloc" = "full" -o "$kde_fast_malloc" = "debug_full"; then
+ AC_DEFINE(KDE_MALLOC_FULL, 1, [Make alloc as fast as possible])
+fi
+
+dnl -finline-limit=<large num> is needed for gcc3 in order to inline large functions
+KDE_CHECK_COMPILER_FLAG(finline-limit=100000,
+ [KDE_FORCE_INLINE="-finline-limit=100000"],
+ [KDE_FORCE_INLINE= ])
+AC_SUBST(KDE_FORCE_INLINE)
diff --git a/kdecore/malloc/glibc.h b/kdecore/malloc/glibc.h
new file mode 100644
index 000000000..5951cb335
--- /dev/null
+++ b/kdecore/malloc/glibc.h
@@ -0,0 +1,31 @@
+#define libc_malloc __libc_malloc
+#define libc_free __libc_free
+#define libc_realloc __libc_realloc
+#define libc_memalign __libc_memalign
+#define libc_valloc __libc_valloc
+#define libc_pvalloc __libc_pvalloc
+#define libc_calloc __libc_calloc
+/* return libc_icalloc( n, elem_size, chunks );*/
+/* return libc_icommaloc( n, sizes, chunks );*/
+#define libc_cfree __libc_free
+/* return libc_mtrim( s );*/
+/* return libc_musable( m );*/
+/* libc_mstats();*/
+#define libc_mallinfo __libc_mallinfo
+#define libc_mallopt __libc_mallopt
+
+void* __libc_malloc(size_t);
+void __libc_free(void*);
+void* __libc_calloc(size_t, size_t);
+void* __libc_realloc(void*, size_t);
+void* __libc_memalign(size_t, size_t);
+void* __libc_valloc(size_t);
+/*void** independent_calloc(size_t, size_t, void**);*/
+/*void** independent_comalloc(size_t, size_t*, void**);*/
+void* __libc_pvalloc(size_t);
+void __libc_cfree(void*);
+/*int malloc_trim(size_t);*/
+/*size_t malloc_usable_size(void*);*/
+/*void malloc_stats();*/
+struct mallinfo __libc_mallinfo(void);
+int __libc_mallopt(int, int);
diff --git a/kdecore/malloc/malloc.c b/kdecore/malloc/malloc.c
new file mode 100644
index 000000000..dba0fdef0
--- /dev/null
+++ b/kdecore/malloc/malloc.c
@@ -0,0 +1,5758 @@
+#include <config.h>
+
+/* awful hack
+ This variable is set to 1 after a call to calloc() if this malloc
+ implementation is active. This is used in konqueror when calling
+ mallinfo(), which doesn't seem to be that much standardized :(.
+*/
+int kde_malloc_is_used = 0;
+
+#ifdef KDE_MALLOC
+
+#ifdef KDE_MALLOC_DEBUG
+#define DEBUG
+#endif
+
+#define USE_MALLOC_LOCK
+#define INLINE __inline__
+/*#define INLINE*/
+#define USE_MEMCPY 0
+#define MMAP_CLEARS 1
+
+/*
+ This is a version (aka dlmalloc) of malloc/free/realloc written by
+ Doug Lea and released to the public domain. Use, modify, and
+ redistribute this code without permission or acknowledgment in any
+ way you wish. Send questions, comments, complaints, performance
+ data, etc to dl@cs.oswego.edu
+
+* VERSION 2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Quickstart
+
+ This library is all in one file to simplify the most common usage:
+ ftp it, compile it (-O), and link it into another program. All
+ of the compile-time options default to reasonable values for use on
+ most unix platforms. Compile -DWIN32 for reasonable defaults on windows.
+ You might later want to step through various compile-time and dynamic
+ tuning options.
+
+ For convenience, an include file for code using this malloc is at:
+ ftp://gee.cs.oswego.edu/pub/misc/malloc-2.7.0.h
+ You don't really need this .h file unless you call functions not
+ defined in your system include files. The .h file contains only the
+ excerpts from this file needed for using this malloc on ANSI C/C++
+ systems, so long as you haven't changed compile-time options about
+ naming and tuning parameters. If you do, then you can create your
+ own malloc.h that does include all settings by cutting at the point
+ indicated below.
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator for malloc-intensive programs.
+
+ The main properties of the algorithms are:
+ * For large (>= 512 bytes) requests, it is a pure best-fit allocator,
+ with ties normally decided via FIFO (i.e. least recently used).
+ * For small (<= 64 bytes by default) requests, it is a caching
+ allocator, that maintains pools of quickly recycled chunks.
+ * In between, and for combinations of large and small requests, it does
+ the best it can trying to meet both goals at once.
+ * For very large requests (>= 128KB by default), it relies on system
+ memory mapping facilities, if supported.
+
+ For a longer but slightly out of date high-level description, see
+ http://gee.cs.oswego.edu/dl/html/malloc.html
+
+ You may already by default be using a C library containing a malloc
+ that is based on some version of this malloc (for example in
+ linux). You might still want to use the one in this file in order to
+ customize settings or to avoid overheads associated with library
+ versions.
+
+* Contents, described in more detail in "description of public routines" below.
+
+ Standard (ANSI/SVID/...) functions:
+ malloc(size_t n);
+ calloc(size_t n_elements, size_t element_size);
+ free(Void_t* p);
+ realloc(Void_t* p, size_t n);
+ memalign(size_t alignment, size_t n);
+ valloc(size_t n);
+ mallinfo()
+ mallopt(int parameter_number, int parameter_value)
+
+ Additional functions:
+ independent_calloc(size_t n_elements, size_t size, Void_t* chunks[]);
+ independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);
+ pvalloc(size_t n);
+ cfree(Void_t* p);
+ malloc_trim(size_t pad);
+ malloc_usable_size(Void_t* p);
+ malloc_stats();
+
+* Vital statistics:
+
+ Supported pointer representation: 4 or 8 bytes
+ Supported size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+ You can adjust this by defining INTERNAL_SIZE_T
+
+ Alignment: 2 * sizeof(size_t) (default)
+ (i.e., 8 byte alignment with 4byte size_t). This suffices for
+ nearly all current machines and C compilers. However, you can
+ define MALLOC_ALIGNMENT to be wider than this if necessary.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden word of overhead holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field and 8 (16) bytes for
+ free list pointers. Thus, the minimum allocatable size is
+ 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ The maximum overhead wastage (i.e., number of extra bytes
+ allocated than were requested in malloc) is less than or equal
+ to the minimum size, except for requests >= mmap_threshold that
+ are serviced via mmap(), where the worst case wastage is 2 *
+ sizeof(size_t) bytes plus the remainder from a system page (the
+ minimal mmap unit); typically 4096 or 8192 bytes.
+
+ Maximum allocated size: 4-byte size_t: 2^32 minus about two pages
+ 8-byte size_t: 2^64 minus about two pages
+
+ It is assumed that (possibly signed) size_t values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. The ISO C standard says that it must be
+ unsigned, but a few systems are known not to adhere to this.
+ Additionally, even when size_t is unsigned, sbrk (which is by
+ default used to obtain memory from system) accepts signed
+ arguments, and may not be able to handle size_t-wide arguments
+ with negative sign bit. Generally, values that would
+ appear as negative after accounting for overhead and alignment
+ are supported only via mmap(), which does not have this
+ limitation.
+
+ Requests for sizes outside the allowed range will perform an optional
+ failure action and then return null. (Requests may also
+ also fail because a system is out of memory.)
+
+ Thread-safety: NOT thread-safe unless USE_MALLOC_LOCK defined
+
+ When USE_MALLOC_LOCK is defined, wrappers are created to
+ surround every public call with either a pthread mutex or
+ a win32 spinlock (depending on WIN32). This is not
+ especially fast, and can be a major bottleneck.
+ It is designed only to provide minimal protection
+ in concurrent environments, and to provide a basis for
+ extensions. If you are using malloc in a concurrent program,
+ you would be far better off obtaining ptmalloc, which is
+ derived from a version of this malloc, and is well-tuned for
+ concurrent programs. (See http://www.malloc.de)
+
+ Compliance: I believe it is compliant with the 1997 Single Unix Specification
+ (See http://www.opennc.org). Also SVID/XPG, ANSI C, and probably
+ others as well.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People also report using it in stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. It is not
+ at all modular. (Sorry!) It uses a lot of macros. To be at all
+ usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O3) that can simplify expressions and control
+ paths. (FAQ: some macros import variables as arguments rather than
+ declare locals because people reported that some debuggers
+ otherwise get confused.)
+
+ OPTION DEFAULT VALUE
+
+ Compilation Environment options:
+
+ __STD_C derived from C compiler defines
+ WIN32 NOT defined
+ HAVE_MEMCPY defined
+ USE_MEMCPY 1 if HAVE_MEMCPY is defined
+ HAVE_MMAP defined as 1
+ MMAP_CLEARS 1
+ HAVE_MREMAP 0 unless linux defined
+ malloc_getpagesize derived from system #includes, or 4096 if not
+ HAVE_USR_INCLUDE_MALLOC_H NOT defined
+ LACKS_UNISTD_H NOT defined unless WIN32
+ LACKS_SYS_PARAM_H NOT defined unless WIN32
+ LACKS_SYS_MMAN_H NOT defined unless WIN32
+
+ Changing default word sizes:
+
+ INTERNAL_SIZE_T size_t
+ MALLOC_ALIGNMENT 2 * sizeof(INTERNAL_SIZE_T)
+
+ Configuration and functionality options:
+
+ USE_DL_PREFIX NOT defined
+ USE_PUBLIC_MALLOC_WRAPPERS NOT defined
+ USE_MALLOC_LOCK NOT defined
+ DEBUG NOT defined
+ REALLOC_ZERO_BYTES_FREES NOT defined
+ MALLOC_FAILURE_ACTION errno = ENOMEM, if __STD_C defined, else no-op
+ TRIM_FASTBINS 0
+
+ Options for customizing MORECORE:
+
+ MORECORE sbrk
+ MORECORE_CONTIGUOUS 1
+ MORECORE_CANNOT_TRIM NOT defined
+ MMAP_AS_MORECORE_SIZE (1024 * 1024)
+
+ Tuning options that are also dynamically changeable via mallopt:
+
+ DEFAULT_MXFAST 64
+ DEFAULT_TRIM_THRESHOLD 128 * 1024
+ DEFAULT_TOP_PAD 0
+ DEFAULT_MMAP_THRESHOLD 128 * 1024
+ DEFAULT_MMAP_MAX 65536
+
+ There are several other #defined constants and macros that you
+ probably don't want to touch unless you are extending or adapting malloc.
+*/
+
+/*
+ WIN32 sets up defaults for MS environment and compilers.
+ Otherwise defaults are for unix.
+*/
+
+/* #define WIN32 */
+
+#ifdef WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* Win32 doesn't supply or need the following headers */
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+
+/* Use the supplied emulation of sbrk */
+#define MORECORE sbrk
+#define MORECORE_CONTIGUOUS 1
+#define MORECORE_FAILURE ((void*)(-1))
+
+/* Use the supplied emulation of mmap and munmap */
+#define HAVE_MMAP 1
+#define MUNMAP_FAILURE (-1)
+#define MMAP_CLEARS 1
+
+/* These values don't really matter in windows mmap emulation */
+#define MAP_PRIVATE 1
+#define MAP_ANONYMOUS 2
+#define PROT_READ 1
+#define PROT_WRITE 2
+
+/* Emulation functions defined at the end of this file */
+
+/* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */
+#ifdef USE_MALLOC_LOCK
+static int slwait(int *sl);
+static int slrelease(int *sl);
+#endif
+
+static long getpagesize(void);
+static long getregionsize(void);
+static void *sbrk(long size);
+static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg);
+static long munmap(void *ptr, long size);
+
+static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed);
+static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user);
+
+#endif
+
+/*
+ __STD_C should be nonzero if using ANSI-standard C compiler, a C++
+ compiler, or a C compiler sufficiently close to ANSI to get away
+ with it.
+*/
+
+#ifndef __STD_C
+#if defined(__STDC__) || defined(_cplusplus)
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif
+#endif /*__STD_C*/
+
+
+/*
+ Void_t* is the pointer type that malloc should say it returns
+*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* define LACKS_UNISTD_H if your system does not have a <unistd.h>. */
+
+/* #define LACKS_UNISTD_H */
+
+#ifndef LACKS_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* define LACKS_SYS_PARAM_H if your system does not have a <sys/param.h>. */
+
+/* #define LACKS_SYS_PARAM_H */
+
+
+#include <stdio.h> /* needed for malloc_stats */
+#include <errno.h> /* needed for optional MALLOC_FAILURE_ACTION */
+
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with bookkeeping fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+ Setting DEBUG does NOT provide an automated mechanism for checking
+ that all accesses to malloced memory stay within their
+ bounds. However, there are several add-ons and adaptations of this
+ or other mallocs available that do this.
+*/
+
+#ifdef DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes.
+
+ The default version is the same as size_t.
+
+ While not strictly necessary, it is best to define this as an
+ unsigned type, even if size_t is a signed type. This may avoid some
+ artificial size limitations on some systems.
+
+ On a 64-bit machine, you may be able to reduce malloc overhead by
+ defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the
+ expense of not being able to handle more than 2^32 of malloced
+ space. If this limitation is acceptable, you are encouraged to set
+ this unless you are on a platform requiring 16byte alignments. In
+ this case the alignment requirements turn out to negate any
+ potential advantages of decreasing size_t word size.
+
+ Implementors: Beware of the possible combinations of:
+ - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits,
+ and might be the same width as int or as long
+ - size_t might have different width and signedness as INTERNAL_SIZE_T
+ - int and long might be 32 or 64 bits, and might be the same width
+ To deal with this, most comparisons and difference computations
+ among INTERNAL_SIZE_Ts should cast them to unsigned long, being
+ aware of the fact that casting an unsigned int to a wider long does
+ not sign-extend. (This also makes checking for negative numbers
+ awkward.) Some of these casts result in harmless compiler warnings
+ on some systems.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/* The corresponding word size */
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+
+
+/*
+ MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.
+ It must be a power of two at least 2 * SIZE_SZ, even on machines
+ for which smaller alignments would suffice. It may be defined as
+ larger than this though. Note however that code and data structures
+ are optimized for the case of 8-byte alignment.
+*/
+
+
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT (2 * SIZE_SZ)
+#endif
+
+/* The corresponding bit mask value */
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+
+
+
+/*
+ REALLOC_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+/* #define REALLOC_ZERO_BYTES_FREES */
+
+/*
+ TRIM_FASTBINS controls whether free() of a very small chunk can
+ immediately lead to trimming. Setting to true (1) can reduce memory
+ footprint, but will almost always slow down programs that use a lot
+ of small chunks.
+
+ Define this only if you are willing to give up some speed to more
+ aggressively reduce system-level memory footprint when releasing
+ memory in programs that use many small chunks. You can get
+ essentially the same effect by setting MXFAST to 0, but this can
+ lead to even greater slowdowns in programs using many small chunks.
+ TRIM_FASTBINS is an in-between compile-time option, that disables
+ only those chunks bordering topmost memory from being placed in
+ fastbins.
+*/
+
+#ifndef TRIM_FASTBINS
+#define TRIM_FASTBINS 0
+#endif
+
+
+/*
+ USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+ This is necessary when you only want to use this malloc in one part
+ of a program, using your regular system malloc elsewhere.
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+ USE_MALLOC_LOCK causes wrapper functions to surround each
+ callable routine with pthread mutex lock/unlock.
+
+ USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined
+*/
+
+
+/* #define USE_MALLOC_LOCK */
+
+
+/*
+ If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is
+ actually a wrapper function that first calls MALLOC_PREACTION, then
+ calls the internal routine, and follows it with
+ MALLOC_POSTACTION. This is needed for locking, but you can also use
+ this, without USE_MALLOC_LOCK, for purposes of interception,
+ instrumentation, etc. It is a sad fact that using wrappers often
+ noticeably degrades performance of malloc-intensive programs.
+*/
+
+#ifdef USE_MALLOC_LOCK
+#define USE_PUBLIC_MALLOC_WRAPPERS
+#else
+/* #define USE_PUBLIC_MALLOC_WRAPPERS */
+#endif
+
+
+/*
+ Two-phase name translation.
+ All of the actual routines are given mangled names.
+ When wrappers are used, they become the public callable versions.
+ When DL_PREFIX is used, the callable names are prefixed.
+*/
+
+#ifndef USE_PUBLIC_MALLOC_WRAPPERS
+#define cALLOc public_cALLOc
+#define fREe public_fREe
+#define cFREe public_cFREe
+#define mALLOc public_mALLOc
+#define mEMALIGn public_mEMALIGn
+#define rEALLOc public_rEALLOc
+#define vALLOc public_vALLOc
+#define pVALLOc public_pVALLOc
+#define mALLINFo public_mALLINFo
+#define mALLOPt public_mALLOPt
+#define mTRIm public_mTRIm
+#define mSTATs public_mSTATs
+#define mUSABLe public_mUSABLe
+#define iCALLOc public_iCALLOc
+#define iCOMALLOc public_iCOMALLOc
+#endif
+
+#ifdef USE_DL_PREFIX
+#define public_cALLOc dlcalloc
+#define public_fREe dlfree
+#define public_cFREe dlcfree
+#define public_mALLOc dlmalloc
+#define public_mEMALIGn dlmemalign
+#define public_rEALLOc dlrealloc
+#define public_vALLOc dlvalloc
+#define public_pVALLOc dlpvalloc
+#define public_mALLINFo dlmallinfo
+#define public_mALLOPt dlmallopt
+#define public_mTRIm dlmalloc_trim
+#define public_mSTATs dlmalloc_stats
+#define public_mUSABLe dlmalloc_usable_size
+#define public_iCALLOc dlindependent_calloc
+#define public_iCOMALLOc dlindependent_comalloc
+#else /* USE_DL_PREFIX */
+#define public_cALLOc calloc
+#define public_fREe free
+#define public_cFREe cfree
+#define public_mALLOc malloc
+#define public_mEMALIGn memalign
+#define public_rEALLOc realloc
+#define public_vALLOc valloc
+#define public_pVALLOc pvalloc
+#define public_mALLINFo mallinfo
+#define public_mALLOPt mallopt
+#define public_mTRIm malloc_trim
+#define public_mSTATs malloc_stats
+#define public_mUSABLe malloc_usable_size
+#define public_iCALLOc independent_calloc
+#define public_iCOMALLOc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+ HAVE_MEMCPY should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined below.
+
+ USE_MEMCPY should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are faster than libc versions on some systems.
+
+ Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks
+ (of <= 36 bytes) are manually unrolled in realloc and calloc.
+*/
+
+/* If it's available it's defined in config.h. */
+/* #define HAVE_MEMCPY */
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#ifdef WIN32
+/* On Win32 memset and memcpy are already declared in windows.h */
+#else
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+/*
+ MALLOC_FAILURE_ACTION is the action to take before "return 0" when
+ malloc fails to be able to return memory, either because memory is
+ exhausted or because of illegal arguments.
+
+ By default, sets errno if running on STD_C platform, else does nothing.
+*/
+
+#ifndef MALLOC_FAILURE_ACTION
+#if __STD_C
+#define MALLOC_FAILURE_ACTION \
+ errno = ENOMEM;
+
+#else
+#define MALLOC_FAILURE_ACTION
+#endif
+#endif
+
+/*
+ MORECORE-related declarations. By default, rely on sbrk
+*/
+
+
+#ifdef LACKS_UNISTD_H
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+#if __STD_C
+extern Void_t* sbrk(ptrdiff_t);
+#else
+extern Void_t* sbrk();
+#endif
+#endif
+#endif
+
+/*
+ MORECORE is the name of the routine to call to obtain more memory
+ from the system. See below for general guidance on writing
+ alternative MORECORE functions, as well as a version for WIN32 and a
+ sample version for pre-OSX macos.
+*/
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+/*
+ MORECORE_FAILURE is the value returned upon failure of MORECORE
+ as well as mmap. Since it cannot be an otherwise valid memory address,
+ and must reflect values of standard sys calls, you probably ought not
+ try to redefine it.
+*/
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE (-1)
+#endif
+
+/*
+ If MORECORE_CONTIGUOUS is true, take advantage of fact that
+ consecutive calls to MORECORE with positive arguments always return
+ contiguous increasing addresses. This is true of unix sbrk. Even
+ if not defined, when regions happen to be contiguous, malloc will
+ permit allocations spanning regions obtained from different
+ calls. But defining this when applicable enables some stronger
+ consistency checks and space efficiencies.
+*/
+
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif
+
+/*
+ Define MORECORE_CANNOT_TRIM if your version of MORECORE
+ cannot release space back to the system when given negative
+ arguments. This is generally necessary only if you are using
+ a hand-crafted MORECORE function that cannot handle negative arguments.
+*/
+
+/* #define MORECORE_CANNOT_TRIM */
+
+
+/*
+ Define HAVE_MMAP as true to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free(). Also, if mmap
+ is available, it is used as a backup strategy in cases where
+ MORECORE fails to provide space from system.
+
+ This malloc is best tuned to work with mmap for large requests.
+ If you do not have mmap, operations involving very large chunks (1MB
+ or so) may be slower than you'd like.
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+#if HAVE_MMAP
+/*
+ Standard unix mmap using /dev/zero clears memory so calloc doesn't
+ need to.
+*/
+
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif
+
+#else /* no mmap */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 0
+#endif
+#endif
+
+
+/*
+ MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if
+ sbrk fails, and mmap is used as a backup (which is done only if
+ HAVE_MMAP). The value must be a multiple of page size. This
+ backup strategy generally applies only when systems have "holes" in
+ address space, so sbrk cannot perform contiguous expansion, but
+ there is still space available on system. On systems for which
+ this is known to be useful (i.e. most linux kernels), this occurs
+ only when programs allocate huge amounts of memory. Between this,
+ and the fact that mmap regions tend to be limited, the size should
+ be large, to avoid too many mmap calls and thus avoid running out
+ of kernel resources.
+*/
+
+#ifndef MMAP_AS_MORECORE_SIZE
+#define MMAP_AS_MORECORE_SIZE (1024 * 1024)
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#if defined(linux) || defined(__linux__) || defined(__linux)
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+
+#endif /* HAVE_MMAP */
+
+
+/*
+ The system page size. To the extent possible, this malloc manages
+ memory from the system in page-size units. Note that this value is
+ cached during initialization into a field of malloc_state. So even
+ if malloc_getpagesize is a function, it is only called once.
+
+ The following mechanics for getpagesize were adapted from bsd/gnu
+ getpagesize.h. If none of the system-probes here apply, a value of
+ 4096 is used, which should be OK: If they don't apply, then using
+ the actual value probably doesn't impact performance.
+*/
+
+
+#ifndef malloc_getpagesize
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32 /* use supplied emulation of getpagesize */
+# define malloc_getpagesize getpagesize()
+# else
+# ifndef LACKS_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else /* just guess */
+# define malloc_getpagesize (4096)
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/*
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing usage properties and
+ statistics. It should work on any SVID/XPG compliant system that has
+ a /usr/include/malloc.h defining struct mallinfo. (If you'd like to
+ install such a thing yourself, cut out the preliminary declarations
+ as described above and below and save them in a malloc.h file. But
+ there's no compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of field that are not even meaningful in this version of
+ malloc. These fields are are instead filled by mallinfo() with
+ other numbers that might be of interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work. The original SVID version of this struct,
+ defined on most systems with mallinfo, declares all fields as
+ ints. But some others define as unsigned long. If your system
+ defines the fields using a type of different width than listed here,
+ you must #include your system version and #define
+ HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+/*#ifdef HAVE_USR_INCLUDE_MALLOC_H*/
+#if 0
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* non-mmapped space allocated from system */
+ int ordblks; /* number of free chunks */
+ int smblks; /* number of fastbin blocks */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* space in mmapped regions */
+ int usmblks; /* maximum total allocated space */
+ int fsmblks; /* space available in freed fastbin blocks */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total free space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/*
+ SVID/XPG defines four standard parameter numbers for mallopt,
+ normally defined in malloc.h. Only one of these (M_MXFAST) is used
+ in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+ so setting them has no effect. But this malloc also supports other
+ options in mallopt described below.
+*/
+#endif
+
+
+/* ---------- description of public routines ------------ */
+
+/*
+ malloc(size_t n)
+ Returns a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available. Additionally, on failure, errno is
+ set to ENOMEM on ANSI C systems.
+
+ If n is zero, malloc returns a minumum-sized chunk. (The minimum
+ size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
+ systems.) On most systems, size_t is an unsigned type, so calls
+ with negative arguments are interpreted as requests for huge amounts
+ of space, which will often fail. The maximum supported value of n
+ differs across systems, but is in all cases less than the maximum
+ representable value of a size_t.
+*/
+#if __STD_C
+Void_t* public_mALLOc(size_t);
+#else
+Void_t* public_mALLOc();
+#endif
+
+/*
+ free(Void_t* p)
+ Releases the chunk of memory pointed to by p, that had been previously
+ allocated using malloc or a related routine such as realloc.
+ It has no effect if p is null. It can have arbitrary (i.e., bad!)
+ effects if p has already been freed.
+
+ Unless disabled (using mallopt), freeing very large spaces will
+ when possible, automatically trigger operations that give
+ back unused memory to the system, thus reducing program footprint.
+*/
+#if __STD_C
+void public_fREe(Void_t*);
+#else
+void public_fREe();
+#endif
+
+/*
+ calloc(size_t n_elements, size_t element_size);
+ Returns a pointer to n_elements * element_size bytes, with all locations
+ set to zero.
+*/
+#if __STD_C
+Void_t* public_cALLOc(size_t, size_t);
+#else
+Void_t* public_cALLOc();
+#endif
+
+/*
+ realloc(Void_t* p, size_t n)
+ Returns a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available.
+
+ The returned pointer may or may not be the same as p. The algorithm
+ prefers extending p when possible, otherwise it employs the
+ equivalent of a malloc-copy-free sequence.
+
+ If p is null, realloc is equivalent to malloc.
+
+ If space is not available, realloc returns null, errno is set (if on
+ ANSI) and p is NOT freed.
+
+ if n is for fewer bytes than already held by p, the newly unused
+ space is lopped off and freed if possible. Unless the #define
+ REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of
+ zero (re)allocates a minimum-sized chunk.
+
+ Large chunks that were internally obtained via mmap will always
+ be reallocated using malloc-copy-free sequences unless
+ the system supports MREMAP (currently only linux).
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is not supported.
+*/
+#if __STD_C
+Void_t* public_rEALLOc(Void_t*, size_t);
+#else
+Void_t* public_rEALLOc();
+#endif
+
+/*
+ memalign(size_t alignment, size_t n);
+ Returns a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument.
+
+ The alignment argument should be a power of two. If the argument is
+ not a power of two, the nearest greater power is used.
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+#if __STD_C
+Void_t* public_mEMALIGn(size_t, size_t);
+#else
+Void_t* public_mEMALIGn();
+#endif
+
+/*
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system. If the pagesize is unknown, 4096 is used.
+*/
+#if __STD_C
+Void_t* public_vALLOc(size_t);
+#else
+Void_t* public_vALLOc();
+#endif
+
+
+
+/*
+ mallopt(int parameter_number, int parameter_value)
+ Sets tunable parameters The format is to provide a
+ (parameter-number, parameter-value) pair. mallopt then sets the
+ corresponding parameter to the argument value if it can (i.e., so
+ long as the value is meaningful), and returns 1 if successful else
+ 0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
+ normally defined in malloc.h. Only one of these (M_MXFAST) is used
+ in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+ so setting them has no effect. But this malloc also supports four
+ other options in mallopt. See below for details. Briefly, supported
+ parameters are as follows (listed defaults are for "typical"
+ configurations).
+
+ Symbol param # default allowed param values
+ M_MXFAST 1 64 0-80 (0 disables fastbins)
+ M_TRIM_THRESHOLD -1 128*1024 any (-1U disables trimming)
+ M_TOP_PAD -2 0 any
+ M_MMAP_THRESHOLD -3 128*1024 any (or 0 if no MMAP support)
+ M_MMAP_MAX -4 65536 any (0 disables use of mmap)
+*/
+#if __STD_C
+int public_mALLOPt(int, int);
+#else
+int public_mALLOPt();
+#endif
+
+
+/*
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics:
+
+ arena: current total non-mmapped bytes allocated from system
+ ordblks: the number of free chunks
+ smblks: the number of fastbin blocks (i.e., small chunks that
+ have been freed but not use resused or consolidated)
+ hblks: current number of mmapped regions
+ hblkhd: total bytes held in mmapped regions
+ usmblks: the maximum total allocated space. This will be greater
+ than current total if trimming has occurred.
+ fsmblks: total bytes held in fastbin blocks
+ uordblks: current total allocated space (normal or mmapped)
+ fordblks: total free space
+ keepcost: the maximum number of bytes that could ideally be released
+ back to system via malloc_trim. ("ideally" means that
+ it ignores page restrictions etc.)
+
+ Because these fields are ints, but internal bookkeeping may
+ be kept as longs, the reported values may wrap around zero and
+ thus be inaccurate.
+*/
+#if __STD_C
+struct mallinfo public_mALLINFo(void);
+#else
+struct mallinfo public_mALLINFo();
+#endif
+
+/*
+ independent_calloc(size_t n_elements, size_t element_size, Void_t* chunks[]);
+
+ independent_calloc is similar to calloc, but instead of returning a
+ single cleared space, it returns an array of pointers to n_elements
+ independent elements that can hold contents of size elem_size, each
+ of which starts out cleared, and can be independently freed,
+ realloc'ed etc. The elements are guaranteed to be adjacently
+ allocated (this is not guaranteed to occur with multiple callocs or
+ mallocs), which may also improve cache locality in some
+ applications.
+
+ The "chunks" argument is optional (i.e., may be null, which is
+ probably the most typical usage). If it is null, the returned array
+ is itself dynamically allocated and should also be freed when it is
+ no longer needed. Otherwise, the chunks array must be of at least
+ n_elements in length. It is filled in with the pointers to the
+ chunks.
+
+ In either case, independent_calloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and "chunks"
+ is null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use regular calloc and assign pointers into this
+ space to represent elements. (In this case though, you cannot
+ independently free elements.)
+
+ independent_calloc simplifies and speeds up implementations of many
+ kinds of pools. It may also be useful when constructing large data
+ structures that initially have a fixed number of fixed-sized nodes,
+ but the number is not known at compile time, and some of the nodes
+ may later need to be freed. For example:
+
+ struct Node { int item; struct Node* next; };
+
+ struct Node* build_list() {
+ struct Node** pool;
+ int n = read_number_of_nodes_needed();
+ if (n <= 0) return 0;
+ pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+ if (pool == 0) die();
+ // organize into a linked list...
+ struct Node* first = pool[0];
+ for (i = 0; i < n-1; ++i)
+ pool[i]->next = pool[i+1];
+ free(pool); // Can now free the array (or not, if it is needed later)
+ return first;
+ }
+*/
+#if __STD_C
+Void_t** public_iCALLOc(size_t, size_t, Void_t**);
+#else
+Void_t** public_iCALLOc();
+#endif
+
+/*
+ independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);
+
+ independent_comalloc allocates, all at once, a set of n_elements
+ chunks with sizes indicated in the "sizes" array. It returns
+ an array of pointers to these elements, each of which can be
+ independently freed, realloc'ed etc. The elements are guaranteed to
+ be adjacently allocated (this is not guaranteed to occur with
+ multiple callocs or mallocs), which may also improve cache locality
+ in some applications.
+
+ The "chunks" argument is optional (i.e., may be null). If it is null
+ the returned array is itself dynamically allocated and should also
+ be freed when it is no longer needed. Otherwise, the chunks array
+ must be of at least n_elements in length. It is filled in with the
+ pointers to the chunks.
+
+ In either case, independent_comalloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and chunks is
+ null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use a single regular malloc, and assign pointers at
+ particular offsets in the aggregate space. (In this case though, you
+ cannot independently free elements.)
+
+ independent_comallac differs from independent_calloc in that each
+ element may have a different size, and also that it does not
+ automatically clear elements.
+
+ independent_comalloc can be used to speed up allocation in cases
+ where several structs or objects must always be allocated at the
+ same time. For example:
+
+ struct Head { ... }
+ struct Foot { ... }
+
+ void send_message(char* msg) {
+ int msglen = strlen(msg);
+ size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+ void* chunks[3];
+ if (independent_comalloc(3, sizes, chunks) == 0)
+ die();
+ struct Head* head = (struct Head*)(chunks[0]);
+ char* body = (char*)(chunks[1]);
+ struct Foot* foot = (struct Foot*)(chunks[2]);
+ // ...
+ }
+
+ In general though, independent_comalloc is worth using only for
+ larger values of n_elements. For small values, you probably won't
+ detect enough difference from series of malloc calls to bother.
+
+ Overuse of independent_comalloc can increase overall memory usage,
+ since it cannot reuse existing noncontiguous small chunks that
+ might be available for some of the elements.
+*/
+#if __STD_C
+Void_t** public_iCOMALLOc(size_t, size_t*, Void_t**);
+#else
+Void_t** public_iCOMALLOc();
+#endif
+
+
+/*
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ */
+#if __STD_C
+Void_t* public_pVALLOc(size_t);
+#else
+Void_t* public_pVALLOc();
+#endif
+
+/*
+ cfree(Void_t* p);
+ Equivalent to free(p).
+
+ cfree is needed/defined on some systems that pair it with calloc,
+ for odd historical reasons (such as: cfree is used in example
+ code in the first edition of K&R).
+*/
+#if __STD_C
+void public_cFREe(Void_t*);
+#else
+void public_cFREe();
+#endif
+
+/*
+ malloc_trim(size_t pad);
+
+ If possible, gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+ On systems that do not support "negative sbrks", it will always
+ rreturn 0.
+*/
+#if __STD_C
+int public_mTRIm(size_t);
+#else
+int public_mTRIm();
+#endif
+
+/*
+ malloc_usable_size(Void_t* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. malloc_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = malloc(n);
+ assert(malloc_usable_size(p) >= 256);
+
+*/
+#if __STD_C
+size_t public_mUSABLe(Void_t*);
+#else
+size_t public_mUSABLe();
+#endif
+
+/*
+ malloc_stats();
+ Prints on stderr the amount of space obtained from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), and the current
+ number of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead. Because it includes
+ alignment wastage as being in use, this figure may be greater than
+ zero even when no user-level chunks are allocated.
+
+ The reported current and maximum system memory can be inaccurate if
+ a program makes other calls to system memory allocation functions
+ (normally sbrk) outside of malloc.
+
+ malloc_stats prints only the most commonly interesting statistics.
+ More information can be obtained by calling mallinfo.
+
+*/
+#if __STD_C
+void public_mSTATs();
+#else
+void public_mSTATs();
+#endif
+
+/* mallopt tuning options */
+
+/*
+ M_MXFAST is the maximum request size used for "fastbins", special bins
+ that hold returned chunks without consolidating their spaces. This
+ enables future requests for chunks of the same size to be handled
+ very quickly, but can increase fragmentation, and thus increase the
+ overall memory footprint of a program.
+
+ This malloc manages fastbins very conservatively yet still
+ efficiently, so fragmentation is rarely a problem for values less
+ than or equal to the default. The maximum supported value of MXFAST
+ is 80. You wouldn't want it any higher than this anyway. Fastbins
+ are designed especially for use with many small structs, objects or
+ strings -- the default handles structs/objects/arrays with sizes up
+ to 8 4byte fields, or small strings representing words, tokens,
+ etc. Using fastbins for larger objects normally worsens
+ fragmentation without improving speed.
+
+ M_MXFAST is set in REQUEST size units. It is internally used in
+ chunksize units, which adds padding and alignment. You can reduce
+ M_MXFAST to 0 to disable all use of fastbins. This causes the malloc
+ algorithm to be a closer approximation of fifo-best-fit in all cases,
+ not just for larger requests, but will generally cause it to be
+ slower.
+*/
+
+
+/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */
+#ifndef M_MXFAST
+#define M_MXFAST 1
+#endif
+
+#ifndef DEFAULT_MXFAST
+#define DEFAULT_MXFAST 64
+#endif
+
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing this much memory.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The trim value It must be greater than page size to have any useful
+ effect. To disable trimming completely, you can set to
+ (unsigned long)(-1)
+
+ Trim settings interact with fastbin (MXFAST) settings: Unless
+ TRIM_FASTBINS is defined, automatic trimming never takes place upon
+ freeing a chunk with size less than or equal to MXFAST. Trimming is
+ instead delayed until subsequent freeing of larger chunks. However,
+ you can still force an attempted trim by calling malloc_trim.
+
+ Also, trimming is not generally possible in cases where
+ the main arena is obtained via mmap.
+
+ Note that the trick some people use of mallocing a huge space and
+ then freeing it at program startup, in an attempt to reserve system
+ memory, doesn't have the intended effect under automatic trimming,
+ since that memory will immediately be returned to the system.
+*/
+
+#define M_TRIM_THRESHOLD -1
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+*/
+
+#define M_TOP_PAD -2
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefits that:
+
+ 1. Mmapped space can ALWAYS be individually released back
+ to the system, which helps keep the system level memory
+ demands of a long-lived program low.
+ 2. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ means that even trimming via malloc_trim would not release them.
+ 3. On some systems with "holes" in address spaces, mmap can obtain
+ memory that sbrk cannot.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ The advantages of mmap nearly always outweigh disadvantages for
+ "large" chunks, but the value of "large" varies across systems. The
+ default is an empirically derived value that works well in most
+ systems.
+*/
+
+#define M_MMAP_THRESHOLD -3
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because
+. Some systems have a limited number of internal tables for
+ use by mmap, and using more than a few of them may degrade
+ performance.
+
+ The default is set to a value that serves only as a safeguard.
+ Setting to 0 disables use of mmap for servicing large requests. If
+ HAVE_MMAP is not set, the default value is 0, and attempts to set it
+ to non-zero values in mallopt will fail.
+*/
+
+#define M_MMAP_MAX -4
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (65536)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/*
+ ========================================================================
+ To make a fully customizable malloc.h header file, cut everything
+ above this line, put into file malloc.h, edit to suit, and #include it
+ on the next line, as well as in programs that use this malloc.
+ ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/* --------------------- public wrappers ---------------------- */
+
+#ifdef USE_PUBLIC_MALLOC_WRAPPERS
+
+/* Declare all routines as internal */
+#if __STD_C
+static Void_t* mALLOc(size_t);
+static void fREe(Void_t*);
+static Void_t* rEALLOc(Void_t*, size_t);
+static Void_t* mEMALIGn(size_t, size_t);
+static Void_t* vALLOc(size_t);
+static Void_t* pVALLOc(size_t);
+static Void_t* cALLOc(size_t, size_t);
+static Void_t** iCALLOc(size_t, size_t, Void_t**);
+static Void_t** iCOMALLOc(size_t, size_t*, Void_t**);
+static void cFREe(Void_t*);
+static int mTRIm(size_t);
+static size_t mUSABLe(Void_t*);
+static void mSTATs();
+static int mALLOPt(int, int);
+static struct mallinfo mALLINFo(void);
+#else
+static Void_t* mALLOc();
+static void fREe();
+static Void_t* rEALLOc();
+static Void_t* mEMALIGn();
+static Void_t* vALLOc();
+static Void_t* pVALLOc();
+static Void_t* cALLOc();
+static Void_t** iCALLOc();
+static Void_t** iCOMALLOc();
+static void cFREe();
+static int mTRIm();
+static size_t mUSABLe();
+static void mSTATs();
+static int mALLOPt();
+static struct mallinfo mALLINFo();
+#endif
+
+/*
+ MALLOC_PREACTION and MALLOC_POSTACTION should be
+ defined to return 0 on success, and nonzero on failure.
+ The return value of MALLOC_POSTACTION is currently ignored
+ in wrapper functions since there is no reasonable default
+ action to take on failure.
+*/
+
+
+#ifdef USE_MALLOC_LOCK
+
+#ifdef WIN32
+
+static int mALLOC_MUTEx;
+#define MALLOC_PREACTION slwait(&mALLOC_MUTEx)
+#define MALLOC_POSTACTION slrelease(&mALLOC_MUTEx)
+
+#else
+
+#if 0
+#include <pthread.h>
+
+static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER;
+
+#define MALLOC_PREACTION pthread_mutex_lock(&mALLOC_MUTEx)
+#define MALLOC_POSTACTION pthread_mutex_unlock(&mALLOC_MUTEx)
+
+#else
+
+#ifdef KDE_MALLOC_X86
+#include "x86.h"
+#else
+#error Unknown spinlock implementation
+#endif
+
+static mutex_t spinlock = MUTEX_INITIALIZER;
+
+#define MALLOC_PREACTION lock( &spinlock )
+#define MALLOC_POSTACTION unlock( &spinlock )
+
+#endif
+
+#endif /* USE_MALLOC_LOCK */
+
+#else
+
+/* Substitute anything you like for these */
+
+#define MALLOC_PREACTION (0)
+#define MALLOC_POSTACTION (0)
+
+#endif
+
+#if 0
+Void_t* public_mALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = mALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+void public_fREe(Void_t* m) {
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ fREe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+}
+
+Void_t* public_rEALLOc(Void_t* m, size_t bytes) {
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = rEALLOc(m, bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t* public_mEMALIGn(size_t alignment, size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = mEMALIGn(alignment, bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t* public_vALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = vALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t* public_pVALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = pVALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t* public_cALLOc(size_t n, size_t elem_size) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = cALLOc(n, elem_size);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+
+Void_t** public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks) {
+ Void_t** m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = iCALLOc(n, elem_size, chunks);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t** public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks) {
+ Void_t** m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = iCOMALLOc(n, sizes, chunks);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+void public_cFREe(Void_t* m) {
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ cFREe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+}
+
+int public_mTRIm(size_t s) {
+ int result;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ result = mTRIm(s);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return result;
+}
+
+size_t public_mUSABLe(Void_t* m) {
+ size_t result;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ result = mUSABLe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return result;
+}
+
+void public_mSTATs() {
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ mSTATs();
+ if (MALLOC_POSTACTION != 0) {
+ }
+}
+
+struct mallinfo public_mALLINFo() {
+ struct mallinfo m;
+ if (MALLOC_PREACTION != 0) {
+ struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ return nm;
+ }
+ m = mALLINFo();
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+int public_mALLOPt(int p, int v) {
+ int result;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ result = mALLOPt(p, v);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return result;
+}
+#endif
+
+#endif
+
+
+
+/* ------------- Optional versions of memcopy ---------------- */
+
+
+#if USE_MEMCPY
+
+/*
+ Note: memcpy is ONLY invoked with non-overlapping regions,
+ so the (usually slower) memmove is not needed.
+*/
+
+#define MALLOC_COPY(dest, src, nbytes) memcpy(dest, src, nbytes)
+#define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ unsigned long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \
+ long mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ unsigned long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \
+ long mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+/* ------------------ MMAP support ------------------ */
+
+
+#if HAVE_MMAP
+
+#include <fcntl.h>
+#ifndef LACKS_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/*
+ Nearly all versions of mmap support MAP_ANONYMOUS,
+ so the following is unlikely to be needed, but is
+ supplied just in case.
+*/
+
+#ifndef MAP_ANONYMOUS
+
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+
+#define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \
+ (dev_zero_fd = open("/dev/zero", O_RDWR), \
+ mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \
+ mmap((addr), (size), (prot), (flags), dev_zero_fd, 0))
+
+#else
+
+#define MMAP(addr, size, prot, flags) \
+ (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0))
+
+#endif
+
+
+#endif /* HAVE_MMAP */
+
+
+/*
+ ----------------------- Chunk representations -----------------------
+*/
+
+
+/*
+ This struct declaration is misleading (but accurate and necessary).
+ It declares a "view" into memory allowing access to necessary
+ fields at known offsets from a given base. See explanation below.
+*/
+
+struct malloc_chunk {
+
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundaries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus at least double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory. If
+ prev_inuse is set for any given chunk, then you CANNOT determine
+ the size of the previous chunk, and might even get a memory
+ addressing fault when trying to do so.
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. This makes it easier to
+ deal with alignments etc but can be very confusing when trying
+ to extend or adapt this code.
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top' doesn't bother using the
+ trailing size field since there is no next contiguous chunk
+ that would have to index off it. After initialization, `top'
+ is forced to always exist. If it would become less than
+ MINSIZE bytes long, it is replenished.
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ allocated one-by-one, each must contain its own trailing size field.
+
+*/
+
+/*
+ ---------- Size and alignment checks and conversions ----------
+*/
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* The smallest possible chunk */
+#define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk))
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+
+#define MINSIZE \
+ (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+/*
+ Check if a request is so large that it would wrap around zero when
+ padded and aligned. To simplify some other code, the bound is made
+ low enough so that adding MINSIZE will also not wrap around zero.
+*/
+
+#define REQUEST_OUT_OF_RANGE(req) \
+ ((unsigned long)(req) >= \
+ (unsigned long)(INTERNAL_SIZE_T)(-2 * MINSIZE))
+
+/* pad request bytes into a usable size -- internal version */
+
+#define request2size(req) \
+ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
+ MINSIZE : \
+ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
+
+/* Same, except also perform argument check */
+
+#define checked_request2size(req, sz) \
+ if (REQUEST_OUT_OF_RANGE(req)) { \
+ MALLOC_FAILURE_ACTION; \
+ return 0; \
+ } \
+ (sz) = request2size(req);
+
+/*
+ --------------- Physical chunk operations ---------------
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+#define PREV_INUSE 0x1
+
+/* extract inuse bit of previous chunk */
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+#define IS_MMAPPED 0x2
+
+/* check for mmap()'ed chunk */
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/*
+ Bits to mask off when extracting size
+
+ Note: IS_MMAPPED is intentionally not masked off from size field in
+ macros for which mmapped chunks should never be seen. This should
+ cause helpful core dumps to occur if it is tried by accident by
+ people extending or adapting this malloc.
+*/
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+/* Get size, ignoring use bits */
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+
+/* Ptr to next physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+/* Treat space at ptr + offset as a chunk */
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+/* extract p's inuse bit */
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* set/clear chunk as being inuse without otherwise disturbing */
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+
+/* check/set/clear inuse bits in known places */
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+/* Set size at head, without disturbing its use bit */
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use field */
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+/*
+ -------------------- Internal data structures --------------------
+
+ All internal state is held in an instance of malloc_state defined
+ below. There are no other static variables, except in two optional
+ cases:
+ * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared above.
+ * If HAVE_MMAP is true, but mmap doesn't support
+ MAP_ANONYMOUS, a dummy file descriptor for mmap.
+
+ Beware of lots of tricks that minimize the total bookkeeping space
+ requirements. The result is a little over 1K bytes (for 4byte
+ pointers and size_t.)
+*/
+
+/*
+ Bins
+
+ An array of bin headers for free chunks. Each bin is doubly
+ linked. The bins are approximately proportionally (log) spaced.
+ There are a lot of these bins (128). This may look excessive, but
+ works very well in practice. Most bins hold sizes that are
+ unusual as malloc request sizes, but are more usual for fragments
+ and consolidated sets of chunks, which is what these bins hold, so
+ they can be found quickly. All procedures maintain the invariant
+ that no consolidated chunk physically borders another one, so each
+ chunk in a list is known to be preceded and followed by either
+ inuse chunks or the ends of memory.
+
+ Chunks in bins are kept in size order, with ties going to the
+ approximately least recently used chunk. Ordering isn't needed
+ for the small bins, which all contain the same-sized chunks, but
+ facilitates best-fit allocation for larger chunks. These lists
+ are just sequential. Keeping them in order almost never requires
+ enough traversal to warrant using fancier ordered data
+ structures.
+
+ Chunks of the same size are linked with the most
+ recently freed at the front, and allocations are taken from the
+ back. This results in LRU (FIFO) allocation order, which tends
+ to give each chunk an equal opportunity to be consolidated with
+ adjacent freed chunks, resulting in larger free chunks and less
+ fragmentation.
+
+ To simplify use in double-linked lists, each bin header acts
+ as a malloc_chunk. This avoids special-casing for headers.
+ But to conserve space and improve locality, we allocate
+ only the fd/bk pointers of bins, and then use repositioning tricks
+ to treat these as the fields of a malloc_chunk*.
+*/
+
+typedef struct malloc_chunk* mbinptr;
+
+/* addressing -- note that bin_at(0) does not exist */
+#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1)))
+
+/* analog of ++bin */
+#define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1)))
+
+/* Reminders about list directionality within bins */
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/* Take a chunk off a bin list */
+#define unlink(P, BK, FD) { \
+ FD = P->fd; \
+ BK = P->bk; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+}
+
+/*
+ Indexing
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically spaced:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The bins top out around 1MB because we expect to service large
+ requests via mmap.
+*/
+
+#define NBINS 128
+#define NSMALLBINS 64
+#define SMALLBIN_WIDTH 8
+#define MIN_LARGE_SIZE 512
+
+#define in_smallbin_range(sz) \
+ ((unsigned long)(sz) < (unsigned long)MIN_LARGE_SIZE)
+
+#define smallbin_index(sz) (((unsigned)(sz)) >> 3)
+
+#define largebin_index(sz) \
+(((((unsigned long)(sz)) >> 6) <= 32)? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20)? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 12) <= 10)? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 15) <= 4)? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 18) <= 2)? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+
+#define bin_index(sz) \
+ ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz))
+
+
+/*
+ Unsorted chunks
+
+ All remainders from chunk splits, as well as all returned chunks,
+ are first placed in the "unsorted" bin. They are then placed
+ in regular bins after malloc gives them ONE chance to be used before
+ binning. So, basically, the unsorted_chunks list acts as a queue,
+ with chunks being placed on it in free (and malloc_consolidate),
+ and taken off (to be either used or placed in bins) in malloc.
+*/
+
+/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
+#define unsorted_chunks(M) (bin_at(M, 1))
+
+/*
+ Top
+
+ The top-most available chunk (i.e., the one bordering the end of
+ available memory) is treated specially. It is never included in
+ any bin, is used only if no other chunk is available, and is
+ released back to the system if it is very large (see
+ M_TRIM_THRESHOLD). Because top initially
+ points to its own bin with initial zero size, thus forcing
+ extension on the first malloc request, we avoid having any special
+ code in malloc to check whether it even exists yet. But we still
+ need to do so when getting memory from system, so we make
+ initial_top treat the bin as a legal but unusable chunk during the
+ interval between initialization and the first call to
+ sYSMALLOc. (This is somewhat delicate, since it relies on
+ the 2 preceding words to be zero during this interval as well.)
+*/
+
+/* Conveniently, the unsorted bin can be used as dummy top on first call */
+#define initial_top(M) (unsorted_chunks(M))
+
+/*
+ Binmap
+
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binmap' is a
+ bitvector recording whether bins are definitely empty so they can
+ be skipped over during during traversals. The bits are NOT always
+ cleared as soon as bins are empty, but instead only
+ when they are noticed to be empty during traversal in malloc.
+*/
+
+/* Conservatively use 32 bits per map word, even if on 64bit system */
+#define BINMAPSHIFT 5
+#define BITSPERMAP (1U << BINMAPSHIFT)
+#define BINMAPSIZE (NBINS / BITSPERMAP)
+
+#define idx2block(i) ((i) >> BINMAPSHIFT)
+#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT)-1))))
+
+#define mark_bin(m,i) ((m)->binmap[idx2block(i)] |= idx2bit(i))
+#define unmark_bin(m,i) ((m)->binmap[idx2block(i)] &= ~(idx2bit(i)))
+#define get_binmap(m,i) ((m)->binmap[idx2block(i)] & idx2bit(i))
+
+/*
+ Fastbins
+
+ An array of lists holding recently freed small chunks. Fastbins
+ are not doubly linked. It is faster to single-link them, and
+ since chunks are never removed from the middles of these lists,
+ double linking is not necessary. Also, unlike regular bins, they
+ are not even processed in FIFO order (they use faster LIFO) since
+ ordering doesn't much matter in the transient contexts in which
+ fastbins are normally used.
+
+ Chunks in fastbins keep their inuse bit set, so they cannot
+ be consolidated with other free chunks. malloc_consolidate
+ releases all chunks in fastbins and consolidates them with
+ other free chunks.
+*/
+
+typedef struct malloc_chunk* mfastbinptr;
+
+/* offset 2 to use otherwise unindexable first 2 bins */
+#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2)
+
+/* The maximum fastbin request size we support */
+#define MAX_FAST_SIZE 80
+
+#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE))+1)
+
+/*
+ FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free()
+ that triggers automatic consolidation of possibly-surrounding
+ fastbin chunks. This is a heuristic, so the exact value should not
+ matter too much. It is defined at half the default trim threshold as a
+ compromise heuristic to only attempt consolidation if it is likely
+ to lead to trimming. However, it is not dynamically tunable, since
+ consolidation reduces fragmentation surrounding loarge chunks even
+ if trimming is not used.
+*/
+
+#define FASTBIN_CONSOLIDATION_THRESHOLD (65536UL)
+
+/*
+ Since the lowest 2 bits in max_fast don't matter in size comparisons,
+ they are used as flags.
+*/
+
+/*
+ FASTCHUNKS_BIT held in max_fast indicates that there are probably
+ some fastbin chunks. It is set true on entering a chunk into any
+ fastbin, and cleared only in malloc_consolidate.
+
+ The truth value is inverted so that have_fastchunks will be true
+ upon startup (since statics are zero-filled), simplifying
+ initialization checks.
+*/
+
+#define FASTCHUNKS_BIT (1U)
+
+#define have_fastchunks(M) (((M)->max_fast & FASTCHUNKS_BIT) == 0)
+#define clear_fastchunks(M) ((M)->max_fast |= FASTCHUNKS_BIT)
+#define set_fastchunks(M) ((M)->max_fast &= ~FASTCHUNKS_BIT)
+
+/*
+ NONCONTIGUOUS_BIT indicates that MORECORE does not return contiguous
+ regions. Otherwise, contiguity is exploited in merging together,
+ when possible, results from consecutive MORECORE calls.
+
+ The initial value comes from MORECORE_CONTIGUOUS, but is
+ changed dynamically if mmap is ever used as an sbrk substitute.
+*/
+
+#define NONCONTIGUOUS_BIT (2U)
+
+#define contiguous(M) (((M)->max_fast & NONCONTIGUOUS_BIT) == 0)
+#define noncontiguous(M) (((M)->max_fast & NONCONTIGUOUS_BIT) != 0)
+#define set_noncontiguous(M) ((M)->max_fast |= NONCONTIGUOUS_BIT)
+#define set_contiguous(M) ((M)->max_fast &= ~NONCONTIGUOUS_BIT)
+
+/*
+ Set value of max_fast.
+ Use impossibly small value if 0.
+ Precondition: there are no existing fastbin chunks.
+ Setting the value clears fastchunk bit but preserves noncontiguous bit.
+*/
+
+#define set_max_fast(M, s) \
+ (M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \
+ FASTCHUNKS_BIT | \
+ ((M)->max_fast & NONCONTIGUOUS_BIT)
+
+
+/*
+ ----------- Internal state representation and initialization -----------
+*/
+
+struct malloc_state {
+
+ /* The maximum chunk size to be eligible for fastbin */
+ INTERNAL_SIZE_T max_fast; /* low 2 bits used as flags */
+
+ /* Fastbins */
+ mfastbinptr fastbins[NFASTBINS];
+
+ /* Base of the topmost chunk -- not otherwise kept in a bin */
+ mchunkptr top;
+
+ /* The remainder from the most recent split of a small request */
+ mchunkptr last_remainder;
+
+ /* Normal bins packed as described above */
+ mchunkptr bins[NBINS * 2];
+
+ /* Bitmap of bins */
+ unsigned int binmap[BINMAPSIZE];
+
+ /* Tunable parameters */
+ unsigned long trim_threshold;
+ INTERNAL_SIZE_T top_pad;
+ INTERNAL_SIZE_T mmap_threshold;
+
+ /* Memory map support */
+ int n_mmaps;
+ int n_mmaps_max;
+ int max_n_mmaps;
+
+ /* Cache malloc_getpagesize */
+ unsigned int pagesize;
+
+ /* Statistics */
+ INTERNAL_SIZE_T mmapped_mem;
+ INTERNAL_SIZE_T sbrked_mem;
+ INTERNAL_SIZE_T max_sbrked_mem;
+ INTERNAL_SIZE_T max_mmapped_mem;
+ INTERNAL_SIZE_T max_total_mem;
+};
+
+typedef struct malloc_state *mstate;
+
+/*
+ There is exactly one instance of this struct in this malloc.
+ If you are adapting this malloc in a way that does NOT use a static
+ malloc_state, you MUST explicitly zero-fill it before using. This
+ malloc relies on the property that malloc_state is initialized to
+ all zeroes (as is true of C statics).
+*/
+
+static struct malloc_state av_; /* never directly referenced */
+
+/*
+ All uses of av_ are via get_malloc_state().
+ At most one "call" to get_malloc_state is made per invocation of
+ the public versions of malloc and free, but other routines
+ that in turn invoke malloc and/or free may call more then once.
+ Also, it is called in check* routines if DEBUG is set.
+*/
+
+#define get_malloc_state() (&(av_))
+
+/*
+ Initialize a malloc_state struct.
+
+ This is called only from within malloc_consolidate, which needs
+ be called in the same contexts anyway. It is never called directly
+ outside of malloc_consolidate because some optimizing compilers try
+ to inline it at all call points, which turns out not to be an
+ optimization at all. (Inlining it in malloc_consolidate is fine though.)
+*/
+
+#if __STD_C
+static void malloc_init_state(mstate av)
+#else
+static void malloc_init_state(av) mstate av;
+#endif
+{
+ int i;
+ mbinptr bin;
+
+ /* Establish circular links for normal bins */
+ for (i = 1; i < NBINS; ++i) {
+ bin = bin_at(av,i);
+ bin->fd = bin->bk = bin;
+ }
+
+ av->top_pad = DEFAULT_TOP_PAD;
+ av->n_mmaps_max = DEFAULT_MMAP_MAX;
+ av->mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+ av->trim_threshold = DEFAULT_TRIM_THRESHOLD;
+
+#if !MORECORE_CONTIGUOUS
+ set_noncontiguous(av);
+#endif
+
+ set_max_fast(av, DEFAULT_MXFAST);
+
+ av->top = initial_top(av);
+ av->pagesize = malloc_getpagesize;
+}
+
+/*
+ Other internal utilities operating on mstates
+*/
+
+#if __STD_C
+static Void_t* sYSMALLOc(INTERNAL_SIZE_T, mstate);
+static int sYSTRIm(size_t, mstate);
+static void malloc_consolidate(mstate);
+static Void_t** iALLOc(size_t, size_t*, int, Void_t**);
+#else
+static Void_t* sYSMALLOc();
+static int sYSTRIm();
+static void malloc_consolidate();
+static Void_t** iALLOc();
+#endif
+
+/*
+ Debugging support
+
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#ifndef DEBUG
+
+#define check_chunk(P)
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_remalloced_chunk(P,N)
+#define check_malloced_chunk(P,N)
+#define check_malloc_state()
+
+#else
+#define check_chunk(P) do_check_chunk(P)
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#define check_malloc_state() do_check_malloc_state()
+
+/*
+ Properties of all chunks
+*/
+
+INLINE
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ mstate av = get_malloc_state();
+ unsigned long sz = chunksize(p);
+ /* min and max possible addresses assuming contiguous allocation */
+ char* max_address = (char*)(av->top) + chunksize(av->top);
+ char* min_address = max_address - av->sbrked_mem;
+
+ if (!chunk_is_mmapped(p)) {
+
+ /* Has legal address ... */
+ if (p != av->top) {
+ if (contiguous(av)) {
+ assert(((char*)p) >= min_address);
+ assert(((char*)p + sz) <= ((char*)(av->top)));
+ }
+ }
+ else {
+ /* top size is always at least MINSIZE */
+ assert((unsigned long)(sz) >= MINSIZE);
+ /* top predecessor always marked inuse */
+ assert(prev_inuse(p));
+ }
+
+ }
+ else {
+#if HAVE_MMAP
+ /* address is outside main heap */
+ if (contiguous(av) && av->top != initial_top(av)) {
+ assert(((char*)p) < min_address || ((char*)p) > max_address);
+ }
+ /* chunk is page-aligned */
+ assert(((p->prev_size + sz) & (av->pagesize-1)) == 0);
+ /* mem is aligned */
+ assert(aligned_OK(chunk2mem(p)));
+#else
+ /* force an appropriate assert violation if debug set */
+ assert(!chunk_is_mmapped(p));
+#endif
+ }
+}
+
+/*
+ Properties of free chunks
+*/
+
+INLINE
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Chunk must claim to be free ... */
+ assert(!inuse(p));
+ assert (!chunk_is_mmapped(p));
+
+ /* Unless a special marker, must have OK fields */
+ if ((unsigned long)(sz) >= MINSIZE)
+ {
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(aligned_OK(chunk2mem(p)));
+ /* ... matching footer field */
+ assert(next->prev_size == sz);
+ /* ... and is fully consolidated */
+ assert(prev_inuse(p));
+ assert (next == av->top || inuse(next));
+
+ /* ... and has minimally sane links */
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ assert(sz == SIZE_SZ);
+}
+
+/*
+ Properties of inuse chunks
+*/
+
+INLINE
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mstate av = get_malloc_state();
+ mchunkptr next;
+ do_check_chunk(p);
+
+ if (chunk_is_mmapped(p))
+ return; /* mmapped chunks have no next/prev */
+
+ /* Check whether it claims to be in use ... */
+ assert(inuse(p));
+
+ next = next_chunk(p);
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p)) {
+ /* Note that we cannot even look at prev unless it is not inuse */
+ mchunkptr prv = prev_chunk(p);
+ assert(next_chunk(prv) == p);
+ do_check_free_chunk(prv);
+ }
+
+ if (next == av->top) {
+ assert(prev_inuse(next));
+ assert(chunksize(next) >= MINSIZE);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+}
+
+/*
+ Properties of chunks recycled from fastbins
+*/
+
+INLINE
+#if __STD_C
+static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_remalloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert((unsigned long)(sz) >= MINSIZE);
+ /* ... and alignment */
+ assert(aligned_OK(chunk2mem(p)));
+ /* chunk is less than MINSIZE more than request */
+ assert((long)(sz) - (long)(s) >= 0);
+ assert((long)(sz) - (long)(s + MINSIZE) < 0);
+}
+
+/*
+ Properties of nonrecycled chunks at the point they are malloced
+*/
+
+INLINE
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ /* same as recycled case ... */
+ do_check_remalloced_chunk(p, s);
+
+ /*
+ ... plus, must obey implementation invariant that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use
+ chunk, or the base of its memory arena. This is ensured
+ by making all allocations from the the `lowest' part of any found
+ chunk. This does not necessarily hold however for chunks
+ recycled via fastbins.
+ */
+
+ assert(prev_inuse(p));
+}
+
+
+/*
+ Properties of malloc_state.
+
+ This may be useful for debugging malloc, as well as detecting user
+ programmer errors that somehow write into malloc_state.
+
+ If you are extending or experimenting with this malloc, you can
+ probably figure out how to hack this routine to print out or
+ display chunk addresses, sizes, bins, and other instrumentation.
+*/
+
+static void do_check_malloc_state()
+{
+ mstate av = get_malloc_state();
+ int i;
+ mchunkptr p;
+ mchunkptr q;
+ mbinptr b;
+ unsigned int binbit;
+ int empty;
+ unsigned int idx;
+ INTERNAL_SIZE_T size;
+ unsigned long total = 0;
+ int max_fast_bin;
+
+ /* internal size_t must be no wider than pointer type */
+ assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*));
+
+ /* alignment is a power of 2 */
+ assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0);
+
+ /* cannot run remaining checks until fully initialized */
+ if (av->top == 0 || av->top == initial_top(av))
+ return;
+
+ /* pagesize is a power of 2 */
+ assert((av->pagesize & (av->pagesize-1)) == 0);
+
+ /* properties of fastbins */
+
+ /* max_fast is in allowed range */
+ assert((av->max_fast & ~1) <= request2size(MAX_FAST_SIZE));
+
+ max_fast_bin = fastbin_index(av->max_fast);
+
+ for (i = 0; i < NFASTBINS; ++i) {
+ p = av->fastbins[i];
+
+ /* all bins past max_fast are empty */
+ if (i > max_fast_bin)
+ assert(p == 0);
+
+ while (p != 0) {
+ /* each chunk claims to be inuse */
+ do_check_inuse_chunk(p);
+ total += chunksize(p);
+ /* chunk belongs in this bin */
+ assert(fastbin_index(chunksize(p)) == i);
+ p = p->fd;
+ }
+ }
+
+ if (total != 0)
+ assert(have_fastchunks(av));
+ else if (!have_fastchunks(av))
+ assert(total == 0);
+
+ /* check normal bins */
+ for (i = 1; i < NBINS; ++i) {
+ b = bin_at(av,i);
+
+ /* binmap is accurate (except for bin 1 == unsorted_chunks) */
+ if (i >= 2) {
+ binbit = get_binmap(av,i);
+ empty = last(b) == b;
+ if (!binbit)
+ assert(empty);
+ else if (!empty)
+ assert(binbit);
+ }
+
+ for (p = last(b); p != b; p = p->bk) {
+ /* each chunk claims to be free */
+ do_check_free_chunk(p);
+ size = chunksize(p);
+ total += size;
+ if (i >= 2) {
+ /* chunk belongs in bin */
+ idx = bin_index(size);
+ assert(idx == i);
+ /* lists are sorted */
+ assert(p->bk == b ||
+ (unsigned long)chunksize(p->bk) >= (unsigned long)chunksize(p));
+ }
+ /* chunk is followed by a legal chain of inuse chunks */
+ for (q = next_chunk(p);
+ (q != av->top && inuse(q) &&
+ (unsigned long)(chunksize(q)) >= MINSIZE);
+ q = next_chunk(q))
+ do_check_inuse_chunk(q);
+ }
+ }
+
+ /* top chunk is OK */
+ check_chunk(av->top);
+
+ /* sanity checks for statistics */
+
+ assert(total <= (unsigned long)(av->max_total_mem));
+ assert(av->n_mmaps >= 0);
+ assert(av->n_mmaps <= av->n_mmaps_max);
+ assert(av->n_mmaps <= av->max_n_mmaps);
+
+ assert((unsigned long)(av->sbrked_mem) <=
+ (unsigned long)(av->max_sbrked_mem));
+
+ assert((unsigned long)(av->mmapped_mem) <=
+ (unsigned long)(av->max_mmapped_mem));
+
+ assert((unsigned long)(av->max_total_mem) >=
+ (unsigned long)(av->mmapped_mem) + (unsigned long)(av->sbrked_mem));
+}
+#endif
+
+
+/* ----------- Routines dealing with system allocation -------------- */
+
+/*
+ sYSTRIm is an inverse of sorts to sYSMALLOc. It gives memory back
+ to the system (via negative arguments to sbrk) if there is unused
+ memory at the `high' end of the malloc pool. It is called
+ automatically by free() when top space exceeds the trim
+ threshold. It is also called by the public malloc_trim routine. It
+ returns 1 if it actually released any memory, else 0.
+*/
+
+INLINE
+#if __STD_C
+static int sYSTRIm(size_t pad, mstate av)
+#else
+static int sYSTRIm(pad, av) size_t pad; mstate av;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ long released; /* Amount actually released */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by post-check sbrk call */
+ size_t pagesz;
+
+ pagesz = av->pagesize;
+ top_size = chunksize(av->top);
+
+ /* Release in pagesize units, keeping at least one page */
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra > 0) {
+
+ /*
+ Only proceed if end of memory is where we last set it.
+ This avoids problems if there were foreign sbrk calls.
+ */
+ current_brk = (char*)(MORECORE(0));
+ if (current_brk == (char*)(av->top) + top_size) {
+
+ /*
+ Attempt to release memory. We ignore MORECORE return value,
+ and instead call again to find out where new end of memory is.
+ This avoids problems if first call releases less than we asked,
+ of if failure somehow altered brk value. (We could still
+ encounter problems if it altered brk in some very bad way,
+ but the only thing we can do is adjust anyway, which will cause
+ some downstream failure.)
+ */
+
+ MORECORE(-extra);
+ new_brk = (char*)(MORECORE(0));
+
+ if (new_brk != (char*)MORECORE_FAILURE) {
+ released = (long)(current_brk - new_brk);
+
+ if (released != 0) {
+ /* Success. Adjust top. */
+ av->sbrked_mem -= released;
+ set_head(av->top, (top_size - released) | PREV_INUSE);
+ check_malloc_state();
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ ------------------------- malloc_consolidate -------------------------
+
+ malloc_consolidate is a specialized version of free() that tears
+ down chunks held in fastbins. Free itself cannot be used for this
+ purpose since, among other things, it might place chunks back onto
+ fastbins. So, instead, we need to use a minor variant of the same
+ code.
+
+ Also, because this routine needs to be called the first time through
+ malloc anyway, it turns out to be the perfect place to trigger
+ initialization code.
+*/
+
+INLINE
+#if __STD_C
+static void malloc_consolidate(mstate av)
+#else
+static void malloc_consolidate(av) mstate av;
+#endif
+{
+ mfastbinptr* fb; /* current fastbin being consolidated */
+ mfastbinptr* maxfb; /* last fastbin (for loop control) */
+ mchunkptr p; /* current chunk being consolidated */
+ mchunkptr nextp; /* next chunk to consolidate */
+ mchunkptr unsorted_bin; /* bin header */
+ mchunkptr first_unsorted; /* chunk to link to */
+
+ /* These have same use as in free() */
+ mchunkptr nextchunk;
+ INTERNAL_SIZE_T size;
+ INTERNAL_SIZE_T nextsize;
+ INTERNAL_SIZE_T prevsize;
+ int nextinuse;
+ mchunkptr bck;
+ mchunkptr fwd;
+
+ /*
+ If max_fast is 0, we know that av hasn't
+ yet been initialized, in which case do so below
+ */
+
+ if (av->max_fast != 0) {
+ clear_fastchunks(av);
+
+ unsorted_bin = unsorted_chunks(av);
+
+ /*
+ Remove each chunk from fast bin and consolidate it, placing it
+ then in unsorted bin. Among other reasons for doing this,
+ placing in unsorted bin avoids needing to calculate actual bins
+ until malloc is sure that chunks aren't immediately going to be
+ reused anyway.
+ */
+
+ maxfb = &(av->fastbins[fastbin_index(av->max_fast)]);
+ fb = &(av->fastbins[0]);
+ do {
+ if ( (p = *fb) != 0) {
+ *fb = 0;
+
+ do {
+ check_inuse_chunk(p);
+ nextp = p->fd;
+
+ /* Slightly streamlined version of consolidation code in free() */
+ size = p->size & ~PREV_INUSE;
+ nextchunk = chunk_at_offset(p, size);
+ nextsize = chunksize(nextchunk);
+
+ if (!prev_inuse(p)) {
+ prevsize = p->prev_size;
+ size += prevsize;
+ p = chunk_at_offset(p, -((long) prevsize));
+ unlink(p, bck, fwd);
+ }
+
+ if (nextchunk != av->top) {
+ nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+ set_head(nextchunk, nextsize);
+
+ if (!nextinuse) {
+ size += nextsize;
+ unlink(nextchunk, bck, fwd);
+ }
+
+ first_unsorted = unsorted_bin->fd;
+ unsorted_bin->fd = p;
+ first_unsorted->bk = p;
+
+ set_head(p, size | PREV_INUSE);
+ p->bk = unsorted_bin;
+ p->fd = first_unsorted;
+ set_foot(p, size);
+ }
+
+ else {
+ size += nextsize;
+ set_head(p, size | PREV_INUSE);
+ av->top = p;
+ }
+
+ } while ( (p = nextp) != 0);
+
+ }
+ } while (fb++ != maxfb);
+ }
+ else {
+ malloc_init_state(av);
+ check_malloc_state();
+ }
+}
+
+/*
+ ------------------------------ free ------------------------------
+*/
+
+INLINE
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T size; /* its size */
+ mfastbinptr* fb; /* associated fastbin */
+ mchunkptr nextchunk; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsize; /* its size */
+ int nextinuse; /* true if nextchunk is used */
+ INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+
+ /* free(0) has no effect */
+ if (mem != 0) {
+ p = mem2chunk(mem);
+ size = chunksize(p);
+
+ check_inuse_chunk(p);
+
+ /*
+ If eligible, place chunk on a fastbin so it can be found
+ and used quickly in malloc.
+ */
+
+ if ((unsigned long)(size) <= (unsigned long)(av->max_fast)
+
+#if TRIM_FASTBINS
+ /*
+ If TRIM_FASTBINS set, don't place chunks
+ bordering top into fastbins
+ */
+ && (chunk_at_offset(p, size) != av->top)
+#endif
+ ) {
+
+ set_fastchunks(av);
+ fb = &(av->fastbins[fastbin_index(size)]);
+ p->fd = *fb;
+ *fb = p;
+ }
+
+ /*
+ Consolidate other non-mmapped chunks as they arrive.
+ */
+
+ else if (!chunk_is_mmapped(p)) {
+ nextchunk = chunk_at_offset(p, size);
+ nextsize = chunksize(nextchunk);
+
+ /* consolidate backward */
+ if (!prev_inuse(p)) {
+ prevsize = p->prev_size;
+ size += prevsize;
+ p = chunk_at_offset(p, -((long) prevsize));
+ unlink(p, bck, fwd);
+ }
+
+ if (nextchunk != av->top) {
+ /* get and clear inuse bit */
+ nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+ set_head(nextchunk, nextsize);
+
+ /* consolidate forward */
+ if (!nextinuse) {
+ unlink(nextchunk, bck, fwd);
+ size += nextsize;
+ }
+
+ /*
+ Place the chunk in unsorted chunk list. Chunks are
+ not placed into regular bins until after they have
+ been given one chance to be used in malloc.
+ */
+
+ bck = unsorted_chunks(av);
+ fwd = bck->fd;
+ p->bk = bck;
+ p->fd = fwd;
+ bck->fd = p;
+ fwd->bk = p;
+
+ set_head(p, size | PREV_INUSE);
+ set_foot(p, size);
+
+ check_free_chunk(p);
+ }
+
+ /*
+ If the chunk borders the current high end of memory,
+ consolidate into top
+ */
+
+ else {
+ size += nextsize;
+ set_head(p, size | PREV_INUSE);
+ av->top = p;
+ check_chunk(p);
+ }
+
+ /*
+ If freeing a large space, consolidate possibly-surrounding
+ chunks. Then, if the total unused topmost memory exceeds trim
+ threshold, ask malloc_trim to reduce top.
+
+ Unless max_fast is 0, we don't know if there are fastbins
+ bordering top, so we cannot tell for sure whether threshold
+ has been reached unless fastbins are consolidated. But we
+ don't want to consolidate on each free. As a compromise,
+ consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
+ is reached.
+ */
+
+ if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
+ if (have_fastchunks(av))
+ malloc_consolidate(av);
+
+#ifndef MORECORE_CANNOT_TRIM
+ if ((unsigned long)(chunksize(av->top)) >=
+ (unsigned long)(av->trim_threshold))
+ sYSTRIm(av->top_pad, av);
+#endif
+ }
+
+ }
+ /*
+ If the chunk was allocated via mmap, release via munmap()
+ Note that if HAVE_MMAP is false but chunk_is_mmapped is
+ true, then user must have overwritten memory. There's nothing
+ we can do to catch this error unless DEBUG is set, in which case
+ check_inuse_chunk (above) will have triggered error.
+ */
+
+ else {
+#if HAVE_MMAP
+ int ret;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ av->n_mmaps--;
+ av->mmapped_mem -= (size + offset);
+ ret = munmap((char*)p - offset, size + offset);
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+#endif
+ }
+ }
+}
+
+/*
+ sysmalloc handles malloc cases requiring more memory from the system.
+ On entry, it is assumed that av->top does not have enough
+ space to service request for nb bytes, thus requiring that av->top
+ be extended or replaced.
+*/
+
+INLINE
+#if __STD_C
+static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av)
+#else
+static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+#endif
+{
+ mchunkptr old_top; /* incoming value of av->top */
+ INTERNAL_SIZE_T old_size; /* its size */
+ char* old_end; /* its end address */
+
+ long size; /* arg to first MORECORE or mmap call */
+ char* brk; /* return value from MORECORE */
+
+ long correction; /* arg to 2nd MORECORE call */
+ char* snd_brk; /* 2nd return val */
+
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */
+ INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */
+ char* aligned_brk; /* aligned offset into brk */
+
+ mchunkptr p; /* the allocated/returned chunk */
+ mchunkptr remainder; /* remainder from allocation */
+ unsigned long remainder_size; /* its size */
+
+ unsigned long sum; /* for updating stats */
+
+ size_t pagemask = av->pagesize - 1;
+
+
+#if HAVE_MMAP
+
+ /*
+ If have mmap, and the request size meets the mmap threshold, and
+ the system supports mmap, and there are few enough currently
+ allocated mmapped regions, try to directly map this request
+ rather than expanding top.
+ */
+
+ if ((unsigned long)(nb) >= (unsigned long)(av->mmap_threshold) &&
+ (av->n_mmaps < av->n_mmaps_max)) {
+
+ char* mm; /* return value from mmap call*/
+
+ /*
+ Round up size to nearest page. For mmapped chunks, the overhead
+ is one SIZE_SZ unit larger than for normal chunks, because there
+ is no following chunk whose prev_size field could be used.
+ */
+ size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask;
+
+ /* Don't try if size wraps around 0 */
+ if ((unsigned long)(size) > (unsigned long)(nb)) {
+
+ mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+
+ if (mm != (char*)(MORECORE_FAILURE)) {
+
+ /*
+ The offset to the start of the mmapped region is stored
+ in the prev_size field of the chunk. This allows us to adjust
+ returned start address to meet alignment requirements here
+ and in memalign(), and still be able to compute proper
+ address argument for later munmap in free() and realloc().
+ */
+
+ front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0) {
+ correction = MALLOC_ALIGNMENT - front_misalign;
+ p = (mchunkptr)(mm + correction);
+ p->prev_size = correction;
+ set_head(p, (size - correction) |IS_MMAPPED);
+ }
+ else {
+ p = (mchunkptr)mm;
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+ }
+
+ /* update statistics */
+
+ if (++av->n_mmaps > av->max_n_mmaps)
+ av->max_n_mmaps = av->n_mmaps;
+
+ sum = av->mmapped_mem += size;
+ if (sum > (unsigned long)(av->max_mmapped_mem))
+ av->max_mmapped_mem = sum;
+ sum += av->sbrked_mem;
+ if (sum > (unsigned long)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ check_chunk(p);
+
+ return chunk2mem(p);
+ }
+ }
+ }
+#endif
+
+ /* Record incoming configuration of top */
+
+ old_top = av->top;
+ old_size = chunksize(old_top);
+ old_end = (char*)(chunk_at_offset(old_top, old_size));
+
+ brk = snd_brk = (char*)(MORECORE_FAILURE);
+
+ /*
+ If not the first time through, we require old_size to be
+ at least MINSIZE and to have prev_inuse set.
+ */
+
+ assert((old_top == initial_top(av) && old_size == 0) ||
+ ((unsigned long) (old_size) >= MINSIZE &&
+ prev_inuse(old_top)));
+
+ /* Precondition: not enough current space to satisfy nb request */
+ assert((unsigned long)(old_size) < (unsigned long)(nb + MINSIZE));
+
+ /* Precondition: all fastbins are consolidated */
+ assert(!have_fastchunks(av));
+
+
+ /* Request enough space for nb + pad + overhead */
+
+ size = nb + av->top_pad + MINSIZE;
+
+ /*
+ If contiguous, we can subtract out existing space that we hope to
+ combine with new space. We add it back later only if
+ we don't actually get contiguous space.
+ */
+
+ if (contiguous(av))
+ size -= old_size;
+
+ /*
+ Round to a multiple of page size.
+ If MORECORE is not contiguous, this ensures that we only call it
+ with whole-page arguments. And if MORECORE is contiguous and
+ this is not first time through, this preserves page-alignment of
+ previous calls. Otherwise, we correct to page-align below.
+ */
+
+ size = (size + pagemask) & ~pagemask;
+
+ /*
+ Don't try to call MORECORE if argument is so big as to appear
+ negative. Note that since mmap takes size_t arg, it may succeed
+ below even if we cannot call MORECORE.
+ */
+
+ if (size > 0)
+ brk = (char*)(MORECORE(size));
+
+ /*
+ If have mmap, try using it as a backup when MORECORE fails or
+ cannot be used. This is worth doing on systems that have "holes" in
+ address space, so sbrk cannot extend to give contiguous space, but
+ space is available elsewhere. Note that we ignore mmap max count
+ and threshold limits, since the space will not be used as a
+ segregated mmap region.
+ */
+
+#if HAVE_MMAP
+ if (brk == (char*)(MORECORE_FAILURE)) {
+
+ /* Cannot merge with old top, so add its size back in */
+ if (contiguous(av))
+ size = (size + old_size + pagemask) & ~pagemask;
+
+ /* If we are relying on mmap as backup, then use larger units */
+ if ((unsigned long)(size) < (unsigned long)(MMAP_AS_MORECORE_SIZE))
+ size = MMAP_AS_MORECORE_SIZE;
+
+ /* Don't try if size wraps around 0 */
+ if ((unsigned long)(size) > (unsigned long)(nb)) {
+
+ brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+
+ if (brk != (char*)(MORECORE_FAILURE)) {
+
+ /* We do not need, and cannot use, another sbrk call to find end */
+ snd_brk = brk + size;
+
+ /*
+ Record that we no longer have a contiguous sbrk region.
+ After the first time mmap is used as backup, we do not
+ ever rely on contiguous space since this could incorrectly
+ bridge regions.
+ */
+ set_noncontiguous(av);
+ }
+ }
+ }
+#endif
+
+ if (brk != (char*)(MORECORE_FAILURE)) {
+ av->sbrked_mem += size;
+
+ /*
+ If MORECORE extends previous space, we can likewise extend top size.
+ */
+
+ if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) {
+ set_head(old_top, (size + old_size) | PREV_INUSE);
+ }
+
+ /*
+ Otherwise, make adjustments:
+
+ * If the first time through or noncontiguous, we need to call sbrk
+ just to find out where the end of memory lies.
+
+ * We need to ensure that all returned chunks from malloc will meet
+ MALLOC_ALIGNMENT
+
+ * If there was an intervening foreign sbrk, we need to adjust sbrk
+ request size to account for fact that we will not be able to
+ combine new space with existing space in old_top.
+
+ * Almost all systems internally allocate whole pages at a time, in
+ which case we might as well use the whole last page of request.
+ So we allocate enough more memory to hit a page boundary now,
+ which in turn causes future contiguous calls to page-align.
+ */
+
+ else {
+ front_misalign = 0;
+ end_misalign = 0;
+ correction = 0;
+ aligned_brk = brk;
+
+ /* handle contiguous cases */
+ if (contiguous(av)) {
+
+ /* Guarantee alignment of first new chunk made from this space */
+
+ front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0) {
+
+ /*
+ Skip over some bytes to arrive at an aligned position.
+ We don't need to specially mark these wasted front bytes.
+ They will never be accessed anyway because
+ prev_inuse of av->top (and any chunk created from its start)
+ is always true after initialization.
+ */
+
+ correction = MALLOC_ALIGNMENT - front_misalign;
+ aligned_brk += correction;
+ }
+
+ /*
+ If this isn't adjacent to existing space, then we will not
+ be able to merge with old_top space, so must add to 2nd request.
+ */
+
+ correction += old_size;
+
+ /* Extend the end address to hit a page boundary */
+ end_misalign = (INTERNAL_SIZE_T)(brk + size + correction);
+ correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign;
+
+ assert(correction >= 0);
+ snd_brk = (char*)(MORECORE(correction));
+
+ /*
+ If can't allocate correction, try to at least find out current
+ brk. It might be enough to proceed without failing.
+
+ Note that if second sbrk did NOT fail, we assume that space
+ is contiguous with first sbrk. This is a safe assumption unless
+ program is multithreaded but doesn't use locks and a foreign sbrk
+ occurred between our first and second calls.
+ */
+
+ if (snd_brk == (char*)(MORECORE_FAILURE)) {
+ correction = 0;
+ snd_brk = (char*)(MORECORE(0));
+ }
+ }
+
+ /* handle non-contiguous cases */
+ else {
+ /* MORECORE/mmap must correctly align */
+ assert(((unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK) == 0);
+
+ /* Find out current end of memory */
+ if (snd_brk == (char*)(MORECORE_FAILURE)) {
+ snd_brk = (char*)(MORECORE(0));
+ }
+ }
+
+ /* Adjust top based on results of second sbrk */
+ if (snd_brk != (char*)(MORECORE_FAILURE)) {
+ av->top = (mchunkptr)aligned_brk;
+ set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE);
+ av->sbrked_mem += correction;
+
+ /*
+ If not the first time through, we either have a
+ gap due to foreign sbrk or a non-contiguous region. Insert a
+ double fencepost at old_top to prevent consolidation with space
+ we don't own. These fenceposts are artificial chunks that are
+ marked as inuse and are in any case too small to use. We need
+ two to make sizes and alignments work out.
+ */
+
+ if (old_size != 0) {
+ /*
+ Shrink old_top to insert fenceposts, keeping size a
+ multiple of MALLOC_ALIGNMENT. We know there is at least
+ enough space in old_top to do this.
+ */
+ old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head(old_top, old_size | PREV_INUSE);
+
+ /*
+ Note that the following assignments completely overwrite
+ old_top when old_size was previously MINSIZE. This is
+ intentional. We need the fencepost, even if old_top otherwise gets
+ lost.
+ */
+ chunk_at_offset(old_top, old_size )->size =
+ SIZE_SZ|PREV_INUSE;
+
+ chunk_at_offset(old_top, old_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+
+ /* If possible, release the rest. */
+ if (old_size >= MINSIZE) {
+ fREe(chunk2mem(old_top));
+ }
+
+ }
+ }
+ }
+
+ /* Update statistics */
+ sum = av->sbrked_mem;
+ if (sum > (unsigned long)(av->max_sbrked_mem))
+ av->max_sbrked_mem = sum;
+
+ sum += av->mmapped_mem;
+ if (sum > (unsigned long)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ check_malloc_state();
+
+ /* finally, do the allocation */
+ p = av->top;
+ size = chunksize(p);
+
+ /* check that one of the above allocation paths succeeded */
+ if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) {
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(p, nb);
+ av->top = remainder;
+ set_head(p, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ check_malloced_chunk(p, nb);
+ return chunk2mem(p);
+ }
+ }
+
+ /* catch all failure paths */
+ MALLOC_FAILURE_ACTION;
+ return 0;
+}
+
+
+/*
+ ------------------------------ malloc ------------------------------
+*/
+
+INLINE
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+ Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T nb; /* normalized request size */
+ unsigned int idx; /* associated bin index */
+ mbinptr bin; /* associated bin */
+ mfastbinptr* fb; /* associated fastbin */
+
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T size; /* its size */
+ int victim_index; /* its bin index */
+
+ mchunkptr remainder; /* remainder from a split */
+ unsigned long remainder_size; /* its size */
+
+ unsigned int block; /* bit map traverser */
+ unsigned int bit; /* bit map traverser */
+ unsigned int map; /* current word of binmap */
+
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+
+ /*
+ Convert request size to internal form by adding SIZE_SZ bytes
+ overhead plus possibly more to obtain necessary alignment and/or
+ to obtain a size of at least MINSIZE, the smallest allocatable
+ size. Also, checked_request2size traps (returning 0) request sizes
+ that are so large that they wrap around zero when padded and
+ aligned.
+ */
+
+ checked_request2size(bytes, nb);
+
+ /*
+ If the size qualifies as a fastbin, first check corresponding bin.
+ This code is safe to execute even if av is not yet initialized, so we
+ can try it without checking, which saves some time on this fast path.
+ */
+
+ if ((unsigned long)(nb) <= (unsigned long)(av->max_fast)) {
+ fb = &(av->fastbins[(fastbin_index(nb))]);
+ if ( (victim = *fb) != 0) {
+ *fb = victim->fd;
+ check_remalloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ /*
+ If a small request, check regular bin. Since these "smallbins"
+ hold one size each, no searching within bins is necessary.
+ (For a large request, we need to wait until unsorted chunks are
+ processed to find best fit. But for small ones, fits are exact
+ anyway, so we can check now, which is faster.)
+ */
+
+ if (in_smallbin_range(nb)) {
+ idx = smallbin_index(nb);
+ bin = bin_at(av,idx);
+
+ if ( (victim = last(bin)) != bin) {
+ if (victim == 0) /* initialization check */
+ malloc_consolidate(av);
+ else {
+ bck = victim->bk;
+ set_inuse_bit_at_offset(victim, nb);
+ bin->bk = bck;
+ bck->fd = bin;
+
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+ }
+
+ /*
+ If this is a large request, consolidate fastbins before continuing.
+ While it might look excessive to kill all fastbins before
+ even seeing if there is space available, this avoids
+ fragmentation problems normally associated with fastbins.
+ Also, in practice, programs tend to have runs of either small or
+ large requests, but less often mixtures, so consolidation is not
+ invoked all that often in most programs. And the programs that
+ it is called frequently in otherwise tend to fragment.
+ */
+
+ else {
+ idx = largebin_index(nb);
+ if (have_fastchunks(av))
+ malloc_consolidate(av);
+ }
+
+ /*
+ Process recently freed or remaindered chunks, taking one only if
+ it is exact fit, or, if this a small request, the chunk is remainder from
+ the most recent non-exact fit. Place other traversed chunks in
+ bins. Note that this step is the only place in any routine where
+ chunks are placed in bins.
+
+ The outer loop here is needed because we might not realize until
+ near the end of malloc that we should have consolidated, so must
+ do so and retry. This happens at most once, and only when we would
+ otherwise need to expand memory to service a "small" request.
+ */
+
+ for(;;) {
+
+ while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) {
+ bck = victim->bk;
+ size = chunksize(victim);
+
+ /*
+ If a small request, try to use last remainder if it is the
+ only chunk in unsorted bin. This helps promote locality for
+ runs of consecutive small requests. This is the only
+ exception to best-fit, and applies only when there is
+ no exact fit for a small chunk.
+ */
+
+ if (in_smallbin_range(nb) &&
+ bck == unsorted_chunks(av) &&
+ victim == av->last_remainder &&
+ (unsigned long)(size) > (unsigned long)(nb + MINSIZE)) {
+
+ /* split and reattach remainder */
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(victim, nb);
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ av->last_remainder = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* remove from unsorted list */
+ unsorted_chunks(av)->bk = bck;
+ bck->fd = unsorted_chunks(av);
+
+ /* Take now instead of binning if exact fit */
+
+ if (size == nb) {
+ set_inuse_bit_at_offset(victim, size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* place chunk in bin */
+
+ if (in_smallbin_range(size)) {
+ victim_index = smallbin_index(size);
+ bck = bin_at(av, victim_index);
+ fwd = bck->fd;
+ }
+ else {
+ victim_index = largebin_index(size);
+ bck = bin_at(av, victim_index);
+ fwd = bck->fd;
+
+ /* maintain large bins in sorted order */
+ if (fwd != bck) {
+ size |= PREV_INUSE; /* Or with inuse bit to speed comparisons */
+ /* if smaller than smallest, bypass loop below */
+ if ((unsigned long)(size) <= (unsigned long)(bck->bk->size)) {
+ fwd = bck;
+ bck = bck->bk;
+ }
+ else {
+ while ((unsigned long)(size) < (unsigned long)(fwd->size))
+ fwd = fwd->fd;
+ bck = fwd->bk;
+ }
+ }
+ }
+
+ mark_bin(av, victim_index);
+ victim->bk = bck;
+ victim->fd = fwd;
+ fwd->bk = victim;
+ bck->fd = victim;
+ }
+
+ /*
+ If a large request, scan through the chunks of current bin in
+ sorted order to find smallest that fits. This is the only step
+ where an unbounded number of chunks might be scanned without doing
+ anything useful with them. However the lists tend to be short.
+ */
+
+ if (!in_smallbin_range(nb)) {
+ bin = bin_at(av, idx);
+
+ /* skip scan if empty or largest chunk is too small */
+ if ((victim = last(bin)) != bin &&
+ (unsigned long)(first(bin)->size) >= (unsigned long)(nb)) {
+
+ while (((unsigned long)(size = chunksize(victim)) <
+ (unsigned long)(nb)))
+ victim = victim->bk;
+
+ remainder_size = size - nb;
+ unlink(victim, bck, fwd);
+
+ /* Exhaust */
+ if (remainder_size < MINSIZE) {
+ set_inuse_bit_at_offset(victim, size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ /* Split */
+ else {
+ remainder = chunk_at_offset(victim, nb);
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+ }
+
+ /*
+ Search for a chunk by scanning bins, starting with next largest
+ bin. This search is strictly by best-fit; i.e., the smallest
+ (with ties going to approximately the least recently used) chunk
+ that fits is selected.
+
+ The bitmap avoids needing to check that most blocks are nonempty.
+ The particular case of skipping all bins during warm-up phases
+ when no chunks have been returned yet is faster than it might look.
+ */
+
+ ++idx;
+ bin = bin_at(av,idx);
+ block = idx2block(idx);
+ map = av->binmap[block];
+ bit = idx2bit(idx);
+
+ for (;;) {
+
+ /* Skip rest of block if there are no more set bits in this block. */
+ if (bit > map || bit == 0) {
+ do {
+ if (++block >= BINMAPSIZE) /* out of bins */
+ goto use_top;
+ } while ( (map = av->binmap[block]) == 0);
+
+ bin = bin_at(av, (block << BINMAPSHIFT));
+ bit = 1;
+ }
+
+ /* Advance to bin with set bit. There must be one. */
+ while ((bit & map) == 0) {
+ bin = next_bin(bin);
+ bit <<= 1;
+ assert(bit != 0);
+ }
+
+ /* Inspect the bin. It is likely to be non-empty */
+ victim = last(bin);
+
+ /* If a false alarm (empty bin), clear the bit. */
+ if (victim == bin) {
+ av->binmap[block] = map &= ~bit; /* Write through */
+ bin = next_bin(bin);
+ bit <<= 1;
+ }
+
+ else {
+ size = chunksize(victim);
+
+ /* We know the first chunk in this bin is big enough to use. */
+ assert((unsigned long)(size) >= (unsigned long)(nb));
+
+ remainder_size = size - nb;
+
+ /* unlink */
+ bck = victim->bk;
+ bin->bk = bck;
+ bck->fd = bin;
+
+ /* Exhaust */
+ if (remainder_size < MINSIZE) {
+ set_inuse_bit_at_offset(victim, size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Split */
+ else {
+ remainder = chunk_at_offset(victim, nb);
+
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+ /* advertise as last remainder */
+ if (in_smallbin_range(nb))
+ av->last_remainder = remainder;
+
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+ }
+
+ use_top:
+ /*
+ If large enough, split off the chunk bordering the end of memory
+ (held in av->top). Note that this is in accord with the best-fit
+ search rule. In effect, av->top is treated as larger (and thus
+ less well fitting) than any other available chunk since it can
+ be extended to be as large as necessary (up to system
+ limitations).
+
+ We require that av->top always exists (i.e., has size >=
+ MINSIZE) after initialization, so if it would otherwise be
+ exhuasted by current request, it is replenished. (The main
+ reason for ensuring it exists is that we may need MINSIZE space
+ to put in fenceposts in sysmalloc.)
+ */
+
+ victim = av->top;
+ size = chunksize(victim);
+
+ if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) {
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(victim, nb);
+ av->top = remainder;
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /*
+ If there is space available in fastbins, consolidate and retry,
+ to possibly avoid expanding memory. This can occur only if nb is
+ in smallbin range so we didn't consolidate upon entry.
+ */
+
+ else if (have_fastchunks(av)) {
+ assert(in_smallbin_range(nb));
+ malloc_consolidate(av);
+ idx = smallbin_index(nb); /* restore original bin index */
+ }
+
+ /*
+ Otherwise, relay to handle system-dependent cases
+ */
+ else
+ return sYSMALLOc(nb, av);
+ }
+}
+
+/*
+ ------------------------------ realloc ------------------------------
+*/
+
+
+INLINE
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+
+ mchunkptr remainder; /* extra space at end of newp */
+ unsigned long remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+ unsigned long copysize; /* bytes to copy */
+ unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */
+ INTERNAL_SIZE_T* s; /* copy source */
+ INTERNAL_SIZE_T* d; /* copy destination */
+
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) {
+ fREe(oldmem);
+ return 0;
+ }
+#endif
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ checked_request2size(bytes, nb);
+
+ oldp = mem2chunk(oldmem);
+ oldsize = chunksize(oldp);
+
+ check_inuse_chunk(oldp);
+
+ if (!chunk_is_mmapped(oldp)) {
+
+ if ((unsigned long)(oldsize) >= (unsigned long)(nb)) {
+ /* already big enough; split below */
+ newp = oldp;
+ newsize = oldsize;
+ }
+
+ else {
+ next = chunk_at_offset(oldp, oldsize);
+
+ /* Try to expand forward into top */
+ if (next == av->top &&
+ (unsigned long)(newsize = oldsize + chunksize(next)) >=
+ (unsigned long)(nb + MINSIZE)) {
+ set_head_size(oldp, nb);
+ av->top = chunk_at_offset(oldp, nb);
+ set_head(av->top, (newsize - nb) | PREV_INUSE);
+ return chunk2mem(oldp);
+ }
+
+ /* Try to expand forward into next chunk; split off remainder below */
+ else if (next != av->top &&
+ !inuse(next) &&
+ (unsigned long)(newsize = oldsize + chunksize(next)) >=
+ (unsigned long)(nb)) {
+ newp = oldp;
+ unlink(next, bck, fwd);
+ }
+
+ /* allocate, copy, free */
+ else {
+ newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+ if (newmem == 0)
+ return 0; /* propagate failure */
+
+ newp = mem2chunk(newmem);
+ newsize = chunksize(newp);
+
+ /*
+ Avoid copy if newp is next chunk after oldp.
+ */
+ if (newp == next) {
+ newsize += oldsize;
+ newp = oldp;
+ }
+ else {
+ /*
+ Unroll copy of <= 36 bytes (72 if 8byte sizes)
+ We know that contents have an odd number of
+ INTERNAL_SIZE_T-sized words; minimally 3.
+ */
+
+ copysize = oldsize - SIZE_SZ;
+ s = (INTERNAL_SIZE_T*)(oldmem);
+ d = (INTERNAL_SIZE_T*)(newmem);
+ ncopies = copysize / sizeof(INTERNAL_SIZE_T);
+ assert(ncopies >= 3);
+
+ if (ncopies > 9)
+ MALLOC_COPY(d, s, copysize);
+
+ else {
+ *(d+0) = *(s+0);
+ *(d+1) = *(s+1);
+ *(d+2) = *(s+2);
+ if (ncopies > 4) {
+ *(d+3) = *(s+3);
+ *(d+4) = *(s+4);
+ if (ncopies > 6) {
+ *(d+5) = *(s+5);
+ *(d+6) = *(s+6);
+ if (ncopies > 8) {
+ *(d+7) = *(s+7);
+ *(d+8) = *(s+8);
+ }
+ }
+ }
+ }
+
+ fREe(oldmem);
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+ }
+ }
+ }
+
+ /* If possible, free extra space in old or extended chunk */
+
+ assert((unsigned long)(newsize) >= (unsigned long)(nb));
+
+ remainder_size = newsize - nb;
+
+ if (remainder_size < MINSIZE) { /* not enough extra to split off */
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+ else { /* split remainder */
+ remainder = chunk_at_offset(newp, nb);
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ /* Mark remainder as inuse so free() won't complain */
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ fREe(chunk2mem(remainder));
+ }
+
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+ }
+
+ /*
+ Handle mmap cases
+ */
+
+ else {
+#if HAVE_MMAP
+
+#if HAVE_MREMAP
+ INTERNAL_SIZE_T offset = oldp->prev_size;
+ size_t pagemask = av->pagesize - 1;
+ char *cp;
+ unsigned long sum;
+
+ /* Note the extra SIZE_SZ overhead */
+ newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask;
+
+ /* don't need to remap if still within same page */
+ if (oldsize == newsize - offset)
+ return oldmem;
+
+ cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1);
+
+ if (cp != (char*)MORECORE_FAILURE) {
+
+ newp = (mchunkptr)(cp + offset);
+ set_head(newp, (newsize - offset)|IS_MMAPPED);
+
+ assert(aligned_OK(chunk2mem(newp)));
+ assert((newp->prev_size == offset));
+
+ /* update statistics */
+ sum = av->mmapped_mem += newsize - oldsize;
+ if (sum > (unsigned long)(av->max_mmapped_mem))
+ av->max_mmapped_mem = sum;
+ sum += av->sbrked_mem;
+ if (sum > (unsigned long)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* Note the extra SIZE_SZ overhead. */
+ if ((unsigned long)(oldsize) >= (unsigned long)(nb + SIZE_SZ))
+ newmem = oldmem; /* do nothing */
+ else {
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+ if (newmem != 0) {
+ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ fREe(oldmem);
+ }
+ }
+ return newmem;
+
+#else
+ /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */
+ check_malloc_state();
+ MALLOC_FAILURE_ACTION;
+ return 0;
+#endif
+ }
+}
+
+/*
+ ------------------------------ memalign ------------------------------
+*/
+
+INLINE
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space before alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ unsigned long remainder_size; /* its size */
+ INTERNAL_SIZE_T size;
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Make sure alignment is power of 2 (in case MINSIZE is not). */
+ if ((alignment & (alignment - 1)) != 0) {
+ size_t a = MALLOC_ALIGNMENT * 2;
+ while ((unsigned long)a < (unsigned long)alignment) a <<= 1;
+ alignment = a;
+ }
+
+ checked_request2size(bytes, nb);
+
+ /*
+ Strategy: find a spot within that chunk that meets the alignment
+ request, and then possibly free the leading and trailing space.
+ */
+
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) != 0) { /* misaligned */
+
+ /*
+ Find an aligned spot inside chunk. Since we need to give back
+ leading space in a chunk of at least MINSIZE, if the first
+ calculation places us at a spot with less than MINSIZE leader,
+ we can move to the next aligned spot -- we've allocated enough
+ total room so that this is always possible.
+ */
+
+ brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) &
+ -((signed long) alignment));
+ if ((unsigned long)(brk - (char*)(p)) < MINSIZE)
+ brk += alignment;
+
+ newp = (mchunkptr)brk;
+ leadsize = brk - (char*)(p);
+ newsize = chunksize(p) - leadsize;
+
+ /* For mmapped chunks, just adjust offset */
+ if (chunk_is_mmapped(p)) {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ return chunk2mem(newp);
+ }
+
+ /* Otherwise, give back leader, use the rest */
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb &&
+ (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+ if (!chunk_is_mmapped(p)) {
+ size = chunksize(p);
+ if ((unsigned long)(size) > (unsigned long)(nb + MINSIZE)) {
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ fREe(chunk2mem(remainder));
+ }
+ }
+
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+}
+
+/*
+ ------------------------------ calloc ------------------------------
+*/
+
+INLINE
+#if __STD_C
+Void_t* cALLOc(size_t n_elements, size_t elem_size)
+#else
+Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ unsigned long clearsize;
+ unsigned long nclears;
+ INTERNAL_SIZE_T* d;
+
+ Void_t* mem = mALLOc(n_elements * elem_size);
+
+ /* hack */
+ kde_malloc_is_used = 1;
+
+ if (mem != 0) {
+ p = mem2chunk(mem);
+
+ if (!chunk_is_mmapped(p))
+ {
+ /*
+ Unroll clear of <= 36 bytes (72 if 8byte sizes)
+ We know that contents have an odd number of
+ INTERNAL_SIZE_T-sized words; minimally 3.
+ */
+
+ d = (INTERNAL_SIZE_T*)mem;
+ clearsize = chunksize(p) - SIZE_SZ;
+ nclears = clearsize / sizeof(INTERNAL_SIZE_T);
+ assert(nclears >= 3);
+
+ if (nclears > 9)
+ MALLOC_ZERO(d, clearsize);
+
+ else {
+ *(d+0) = 0;
+ *(d+1) = 0;
+ *(d+2) = 0;
+ if (nclears > 4) {
+ *(d+3) = 0;
+ *(d+4) = 0;
+ if (nclears > 6) {
+ *(d+5) = 0;
+ *(d+6) = 0;
+ if (nclears > 8) {
+ *(d+7) = 0;
+ *(d+8) = 0;
+ }
+ }
+ }
+ }
+ }
+#if ! MMAP_CLEARS
+ else
+ {
+ d = (INTERNAL_SIZE_T*)mem;
+ clearsize = chunksize(p) - 2 * SIZE_SZ;
+ MALLOC_ZERO(d, clearsize);
+ }
+#endif
+ }
+ return mem;
+}
+
+/*
+ ------------------------------ cfree ------------------------------
+*/
+
+INLINE
+#if __STD_C
+void cFREe(Void_t *mem)
+#else
+void cFREe(mem) Void_t *mem;
+#endif
+{
+ fREe(mem);
+}
+
+/*
+ ------------------------------ ialloc ------------------------------
+ ialloc provides common support for independent_X routines, handling all of
+ the combinations that can result.
+
+ The opts arg has:
+ bit 0 set if all elements are same size (using sizes[0])
+ bit 1 set if elements should be zeroed
+*/
+
+
+INLINE
+#if __STD_C
+static Void_t** iALLOc(size_t n_elements,
+ size_t* sizes,
+ int opts,
+ Void_t* chunks[])
+#else
+static Void_t** iALLOc(n_elements, sizes, opts, chunks) size_t n_elements; size_t* sizes; int opts; Void_t* chunks[];
+#endif
+{
+ mstate av = get_malloc_state();
+ INTERNAL_SIZE_T element_size; /* chunksize of each element, if all same */
+ INTERNAL_SIZE_T contents_size; /* total size of elements */
+ INTERNAL_SIZE_T array_size; /* request size of pointer array */
+ Void_t* mem; /* malloced aggregate space */
+ mchunkptr p; /* corresponding chunk */
+ INTERNAL_SIZE_T remainder_size; /* remaining bytes while splitting */
+ Void_t** marray; /* either "chunks" or malloced ptr array */
+ mchunkptr array_chunk; /* chunk for malloced ptr array */
+ int mmx; /* to disable mmap */
+ INTERNAL_SIZE_T size;
+ size_t i;
+
+ /* Ensure initialization/consolidation */
+ if (have_fastchunks(av)) malloc_consolidate(av);
+
+ /* compute array length, if needed */
+ if (chunks != 0) {
+ if (n_elements == 0)
+ return chunks; /* nothing to do */
+ marray = chunks;
+ array_size = 0;
+ }
+ else {
+ /* if empty req, must still return chunk representing empty array */
+ if (n_elements == 0)
+ return (Void_t**) mALLOc(0);
+ marray = 0;
+ array_size = request2size(n_elements * (sizeof(Void_t*)));
+ }
+
+ /* compute total element size */
+ if (opts & 0x1) { /* all-same-size */
+ element_size = request2size(*sizes);
+ contents_size = n_elements * element_size;
+ }
+ else { /* add up all the sizes */
+ element_size = 0;
+ contents_size = 0;
+ for (i = 0; i != n_elements; ++i)
+ contents_size += request2size(sizes[i]);
+ }
+
+ /* subtract out alignment bytes from total to minimize overallocation */
+ size = contents_size + array_size - MALLOC_ALIGN_MASK;
+
+ /*
+ Allocate the aggregate chunk.
+ But first disable mmap so malloc won't use it, since
+ we would not be able to later free/realloc space internal
+ to a segregated mmap region.
+ */
+ mmx = av->n_mmaps_max; /* disable mmap */
+ av->n_mmaps_max = 0;
+ mem = mALLOc(size);
+ av->n_mmaps_max = mmx; /* reset mmap */
+ if (mem == 0)
+ return 0;
+
+ p = mem2chunk(mem);
+ assert(!chunk_is_mmapped(p));
+ remainder_size = chunksize(p);
+
+ if (opts & 0x2) { /* optionally clear the elements */
+ MALLOC_ZERO(mem, remainder_size - SIZE_SZ - array_size);
+ }
+
+ /* If not provided, allocate the pointer array as final part of chunk */
+ if (marray == 0) {
+ array_chunk = chunk_at_offset(p, contents_size);
+ marray = (Void_t**) (chunk2mem(array_chunk));
+ set_head(array_chunk, (remainder_size - contents_size) | PREV_INUSE);
+ remainder_size = contents_size;
+ }
+
+ /* split out elements */
+ for (i = 0; ; ++i) {
+ marray[i] = chunk2mem(p);
+ if (i != n_elements-1) {
+ if (element_size != 0)
+ size = element_size;
+ else
+ size = request2size(sizes[i]);
+ remainder_size -= size;
+ set_head(p, size | PREV_INUSE);
+ p = chunk_at_offset(p, size);
+ }
+ else { /* the final element absorbs any overallocation slop */
+ set_head(p, remainder_size | PREV_INUSE);
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (marray != chunks) {
+ /* final element must have exactly exhausted chunk */
+ if (element_size != 0)
+ assert(remainder_size == element_size);
+ else
+ assert(remainder_size == request2size(sizes[i]));
+ check_inuse_chunk(mem2chunk(marray));
+ }
+
+ for (i = 0; i != n_elements; ++i)
+ check_inuse_chunk(mem2chunk(marray[i]));
+#endif
+
+ return marray;
+}
+
+
+/*
+ ------------------------- independent_calloc -------------------------
+*/
+
+INLINE
+#if __STD_C
+Void_t** iCALLOc(size_t n_elements, size_t elem_size, Void_t* chunks[])
+#else
+Void_t** iCALLOc(n_elements, elem_size, chunks) size_t n_elements; size_t elem_size; Void_t* chunks[];
+#endif
+{
+ size_t sz = elem_size; /* serves as 1-element array */
+ /* opts arg of 3 means all elements are same size, and should be cleared */
+ return iALLOc(n_elements, &sz, 3, chunks);
+}
+
+/*
+ ------------------------- independent_comalloc -------------------------
+*/
+
+INLINE
+#if __STD_C
+Void_t** iCOMALLOc(size_t n_elements, size_t sizes[], Void_t* chunks[])
+#else
+Void_t** iCOMALLOc(n_elements, sizes, chunks) size_t n_elements; size_t sizes[]; Void_t* chunks[];
+#endif
+{
+ return iALLOc(n_elements, sizes, 0, chunks);
+}
+
+
+/*
+ ------------------------------ valloc ------------------------------
+*/
+
+INLINE
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ /* Ensure initialization/consolidation */
+ mstate av = get_malloc_state();
+ if (have_fastchunks(av)) malloc_consolidate(av);
+ return mEMALIGn(av->pagesize, bytes);
+}
+
+/*
+ ------------------------------ pvalloc ------------------------------
+*/
+
+
+#if __STD_C
+Void_t* pVALLOc(size_t bytes)
+#else
+Void_t* pVALLOc(bytes) size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+ size_t pagesz;
+
+ /* Ensure initialization/consolidation */
+ if (have_fastchunks(av)) malloc_consolidate(av);
+ pagesz = av->pagesize;
+ return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));
+}
+
+
+/*
+ ------------------------------ malloc_trim ------------------------------
+*/
+
+INLINE
+#if __STD_C
+int mTRIm(size_t pad)
+#else
+int mTRIm(pad) size_t pad;
+#endif
+{
+ mstate av = get_malloc_state();
+ /* Ensure initialization/consolidation */
+ malloc_consolidate(av);
+
+#ifndef MORECORE_CANNOT_TRIM
+ return sYSTRIm(pad, av);
+#else
+ return 0;
+#endif
+}
+
+
+/*
+ ------------------------- malloc_usable_size -------------------------
+*/
+
+INLINE
+#if __STD_C
+size_t mUSABLe(Void_t* mem)
+#else
+size_t mUSABLe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem != 0) {
+ p = mem2chunk(mem);
+ if (chunk_is_mmapped(p))
+ return chunksize(p) - 2*SIZE_SZ;
+ else if (inuse(p))
+ return chunksize(p) - SIZE_SZ;
+ }
+ return 0;
+}
+
+/*
+ ------------------------------ mallinfo ------------------------------
+*/
+
+struct mallinfo mALLINFo()
+{
+ mstate av = get_malloc_state();
+ struct mallinfo mi;
+ unsigned int i;
+ mbinptr b;
+ mchunkptr p;
+ INTERNAL_SIZE_T avail;
+ INTERNAL_SIZE_T fastavail;
+ int nblocks;
+ int nfastblocks;
+
+ /* Ensure initialization */
+ if (av->top == 0) malloc_consolidate(av);
+
+ check_malloc_state();
+
+ /* Account for top */
+ avail = chunksize(av->top);
+ nblocks = 1; /* top always exists */
+
+ /* traverse fastbins */
+ nfastblocks = 0;
+ fastavail = 0;
+
+ for (i = 0; i < NFASTBINS; ++i) {
+ for (p = av->fastbins[i]; p != 0; p = p->fd) {
+ ++nfastblocks;
+ fastavail += chunksize(p);
+ }
+ }
+
+ avail += fastavail;
+
+ /* traverse regular bins */
+ for (i = 1; i < NBINS; ++i) {
+ b = bin_at(av, i);
+ for (p = last(b); p != b; p = p->bk) {
+ ++nblocks;
+ avail += chunksize(p);
+ }
+ }
+
+ mi.smblks = nfastblocks;
+ mi.ordblks = nblocks;
+ mi.fordblks = avail;
+ mi.uordblks = av->sbrked_mem - avail;
+ mi.arena = av->sbrked_mem;
+ mi.hblks = av->n_mmaps;
+ mi.hblkhd = av->mmapped_mem;
+ mi.fsmblks = fastavail;
+ mi.keepcost = chunksize(av->top);
+ mi.usmblks = av->max_total_mem;
+ return mi;
+}
+
+/*
+ ------------------------------ malloc_stats ------------------------------
+*/
+
+void mSTATs()
+{
+ struct mallinfo mi = mALLINFo();
+
+#ifdef WIN32
+ {
+ unsigned long free, reserved, committed;
+ vminfo (&free, &reserved, &committed);
+ fprintf(stderr, "free bytes = %10lu\n",
+ free);
+ fprintf(stderr, "reserved bytes = %10lu\n",
+ reserved);
+ fprintf(stderr, "committed bytes = %10lu\n",
+ committed);
+ }
+#endif
+
+
+ fprintf(stderr, "max system bytes = %10lu\n",
+ (unsigned long)(mi.usmblks));
+ fprintf(stderr, "system bytes = %10lu\n",
+ (unsigned long)(mi.arena + mi.hblkhd));
+ fprintf(stderr, "in use bytes = %10lu\n",
+ (unsigned long)(mi.uordblks + mi.hblkhd));
+
+
+#ifdef WIN32
+ {
+ unsigned long kernel, user;
+ if (cpuinfo (TRUE, &kernel, &user)) {
+ fprintf(stderr, "kernel ms = %10lu\n",
+ kernel);
+ fprintf(stderr, "user ms = %10lu\n",
+ user);
+ }
+ }
+#endif
+}
+
+
+/*
+ ------------------------------ mallopt ------------------------------
+*/
+
+INLINE
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ mstate av = get_malloc_state();
+ /* Ensure initialization/consolidation */
+ malloc_consolidate(av);
+
+ switch(param_number) {
+ case M_MXFAST:
+ if (value >= 0 && value <= MAX_FAST_SIZE) {
+ set_max_fast(av, value);
+ return 1;
+ }
+ else
+ return 0;
+
+ case M_TRIM_THRESHOLD:
+ av->trim_threshold = value;
+ return 1;
+
+ case M_TOP_PAD:
+ av->top_pad = value;
+ return 1;
+
+ case M_MMAP_THRESHOLD:
+ av->mmap_threshold = value;
+ return 1;
+
+ case M_MMAP_MAX:
+#if !HAVE_MMAP
+ if (value != 0)
+ return 0;
+#endif
+ av->n_mmaps_max = value;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ -------------------- Alternative MORECORE functions --------------------
+*/
+
+
+/*
+ General Requirements for MORECORE.
+
+ The MORECORE function must have the following properties:
+
+ If MORECORE_CONTIGUOUS is false:
+
+ * MORECORE must allocate in multiples of pagesize. It will
+ only be called with arguments that are multiples of pagesize.
+
+ * MORECORE(0) must return an address that is at least
+ MALLOC_ALIGNMENT aligned. (Page-aligning always suffices.)
+
+ else (i.e. If MORECORE_CONTIGUOUS is true):
+
+ * Consecutive calls to MORECORE with positive arguments
+ return increasing addresses, indicating that space has been
+ contiguously extended.
+
+ * MORECORE need not allocate in multiples of pagesize.
+ Calls to MORECORE need not have args of multiples of pagesize.
+
+ * MORECORE need not page-align.
+
+ In either case:
+
+ * MORECORE may allocate more memory than requested. (Or even less,
+ but this will generally result in a malloc failure.)
+
+ * MORECORE must not allocate memory when given argument zero, but
+ instead return one past the end address of memory from previous
+ nonzero call. This malloc does NOT call MORECORE(0)
+ until at least one call with positive arguments is made, so
+ the initial value returned is not important.
+
+ * Even though consecutive calls to MORECORE need not return contiguous
+ addresses, it must be OK for malloc'ed chunks to span multiple
+ regions in those cases where they do happen to be contiguous.
+
+ * MORECORE need not handle negative arguments -- it may instead
+ just return MORECORE_FAILURE when given negative arguments.
+ Negative arguments are always multiples of pagesize. MORECORE
+ must not misinterpret negative args as large positive unsigned
+ args. You can suppress all such calls from even occurring by defining
+ MORECORE_CANNOT_TRIM,
+
+ There is some variation across systems about the type of the
+ argument to sbrk/MORECORE. If size_t is unsigned, then it cannot
+ actually be size_t, because sbrk supports negative args, so it is
+ normally the signed type of the same width as size_t (sometimes
+ declared as "intptr_t", and sometimes "ptrdiff_t"). It doesn't much
+ matter though. Internally, we use "long" as arguments, which should
+ work across all reasonable possibilities.
+
+ Additionally, if MORECORE ever returns failure for a positive
+ request, and HAVE_MMAP is true, then mmap is used as a noncontiguous
+ system allocator. This is a useful backup strategy for systems with
+ holes in address spaces -- in this case sbrk cannot contiguously
+ expand the heap, but mmap may be able to map noncontiguous space.
+
+ If you'd like mmap to ALWAYS be used, you can define MORECORE to be
+ a function that always returns MORECORE_FAILURE.
+
+ If you are using this malloc with something other than sbrk (or its
+ emulation) to supply memory regions, you probably want to set
+ MORECORE_CONTIGUOUS as false. As an example, here is a custom
+ allocator kindly contributed for pre-OSX macOS. It uses virtually
+ but not necessarily physically contiguous non-paged memory (locked
+ in, present and won't get swapped out). You can use it by
+ uncommenting this section, adding some #includes, and setting up the
+ appropriate defines above:
+
+ #define MORECORE osMoreCore
+ #define MORECORE_CONTIGUOUS 0
+
+ There is also a shutdown routine that should somehow be called for
+ cleanup upon program exit.
+
+ #define MAX_POOL_ENTRIES 100
+ #define MINIMUM_MORECORE_SIZE (64 * 1024)
+ static int next_os_pool;
+ void *our_os_pools[MAX_POOL_ENTRIES];
+
+ void *osMoreCore(int size)
+ {
+ void *ptr = 0;
+ static void *sbrk_top = 0;
+
+ if (size > 0)
+ {
+ if (size < MINIMUM_MORECORE_SIZE)
+ size = MINIMUM_MORECORE_SIZE;
+ if (CurrentExecutionLevel() == kTaskLevel)
+ ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+ if (ptr == 0)
+ {
+ return (void *) MORECORE_FAILURE;
+ }
+ // save ptrs so they can be freed during cleanup
+ our_os_pools[next_os_pool] = ptr;
+ next_os_pool++;
+ ptr = (void *) ((((unsigned long) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+ sbrk_top = (char *) ptr + size;
+ return ptr;
+ }
+ else if (size < 0)
+ {
+ // we don't currently support shrink behavior
+ return (void *) MORECORE_FAILURE;
+ }
+ else
+ {
+ return sbrk_top;
+ }
+ }
+
+ // cleanup any allocated memory pools
+ // called as last thing before shutting down driver
+
+ void osCleanupMem(void)
+ {
+ void **ptr;
+
+ for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+ if (*ptr)
+ {
+ PoolDeallocate(*ptr);
+ *ptr = 0;
+ }
+ }
+
+*/
+
+
+/*
+ --------------------------------------------------------------
+
+ Emulation of sbrk for win32.
+ Donated by J. Walter <Walter@GeNeSys-e.de>.
+ For additional information about this code, and malloc on Win32, see
+ http://www.genesys-e.de/jwalter/
+*/
+
+
+#ifdef WIN32
+
+#ifdef _DEBUG
+/* #define TRACE */
+#endif
+
+/* Support for USE_MALLOC_LOCK */
+#ifdef USE_MALLOC_LOCK
+
+/* Wait for spin lock */
+static int slwait (int *sl) {
+ while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0)
+ Sleep (0);
+ return 0;
+}
+
+/* Release spin lock */
+static int slrelease (int *sl) {
+ InterlockedExchange (sl, 0);
+ return 0;
+}
+
+#ifdef NEEDED
+/* Spin lock for emulation code */
+static int g_sl;
+#endif
+
+#endif /* USE_MALLOC_LOCK */
+
+/* getpagesize for windows */
+static long getpagesize (void) {
+ static long g_pagesize = 0;
+ if (! g_pagesize) {
+ SYSTEM_INFO system_info;
+ GetSystemInfo (&system_info);
+ g_pagesize = system_info.dwPageSize;
+ }
+ return g_pagesize;
+}
+static long getregionsize (void) {
+ static long g_regionsize = 0;
+ if (! g_regionsize) {
+ SYSTEM_INFO system_info;
+ GetSystemInfo (&system_info);
+ g_regionsize = system_info.dwAllocationGranularity;
+ }
+ return g_regionsize;
+}
+
+/* A region list entry */
+typedef struct _region_list_entry {
+ void *top_allocated;
+ void *top_committed;
+ void *top_reserved;
+ long reserve_size;
+ struct _region_list_entry *previous;
+} region_list_entry;
+
+/* Allocate and link a region entry in the region list */
+static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) {
+ region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry));
+ if (! next)
+ return FALSE;
+ next->top_allocated = (char *) base_reserved;
+ next->top_committed = (char *) base_reserved;
+ next->top_reserved = (char *) base_reserved + reserve_size;
+ next->reserve_size = reserve_size;
+ next->previous = *last;
+ *last = next;
+ return TRUE;
+}
+/* Free and unlink the last region entry from the region list */
+static int region_list_remove (region_list_entry **last) {
+ region_list_entry *previous = (*last)->previous;
+ if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last))
+ return FALSE;
+ *last = previous;
+ return TRUE;
+}
+
+#define CEIL(size,to) (((size)+(to)-1)&~((to)-1))
+#define FLOOR(size,to) ((size)&~((to)-1))
+
+#define SBRK_SCALE 0
+/* #define SBRK_SCALE 1 */
+/* #define SBRK_SCALE 2 */
+/* #define SBRK_SCALE 4 */
+
+/* sbrk for windows */
+static void *sbrk (long size) {
+ static long g_pagesize, g_my_pagesize;
+ static long g_regionsize, g_my_regionsize;
+ static region_list_entry *g_last;
+ void *result = (void *) MORECORE_FAILURE;
+#ifdef TRACE
+ printf ("sbrk %d\n", size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Wait for spin lock */
+ slwait (&g_sl);
+#endif
+ /* First time initialization */
+ if (! g_pagesize) {
+ g_pagesize = getpagesize ();
+ g_my_pagesize = g_pagesize << SBRK_SCALE;
+ }
+ if (! g_regionsize) {
+ g_regionsize = getregionsize ();
+ g_my_regionsize = g_regionsize << SBRK_SCALE;
+ }
+ if (! g_last) {
+ if (! region_list_append (&g_last, 0, 0))
+ goto sbrk_exit;
+ }
+ /* Assert invariants */
+ assert (g_last);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&
+ g_last->top_allocated <= g_last->top_committed);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&
+ g_last->top_committed <= g_last->top_reserved &&
+ (unsigned) g_last->top_committed % g_pagesize == 0);
+ assert ((unsigned) g_last->top_reserved % g_regionsize == 0);
+ assert ((unsigned) g_last->reserve_size % g_regionsize == 0);
+ /* Allocation requested? */
+ if (size >= 0) {
+ /* Allocation size is the requested size */
+ long allocate_size = size;
+ /* Compute the size to commit */
+ long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+ /* Do we reach the commit limit? */
+ if (to_commit > 0) {
+ /* Round size to commit */
+ long commit_size = CEIL (to_commit, g_my_pagesize);
+ /* Compute the size to reserve */
+ long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved;
+ /* Do we reach the reserve limit? */
+ if (to_reserve > 0) {
+ /* Compute the remaining size to commit in the current region */
+ long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed;
+ if (remaining_commit_size > 0) {
+ /* Assert preconditions */
+ assert ((unsigned) g_last->top_committed % g_pagesize == 0);
+ assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); {
+ /* Commit this */
+ void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size,
+ MEM_COMMIT, PAGE_READWRITE);
+ /* Check returned pointer for consistency */
+ if (base_committed != g_last->top_committed)
+ goto sbrk_exit;
+ /* Assert postconditions */
+ assert ((unsigned) base_committed % g_pagesize == 0);
+#ifdef TRACE
+ printf ("Commit %p %d\n", base_committed, remaining_commit_size);
+#endif
+ /* Adjust the regions commit top */
+ g_last->top_committed = (char *) base_committed + remaining_commit_size;
+ }
+ } {
+ /* Now we are going to search and reserve. */
+ int contiguous = -1;
+ int found = FALSE;
+ MEMORY_BASIC_INFORMATION memory_info;
+ void *base_reserved;
+ long reserve_size;
+ do {
+ /* Assume contiguous memory */
+ contiguous = TRUE;
+ /* Round size to reserve */
+ reserve_size = CEIL (to_reserve, g_my_regionsize);
+ /* Start with the current region's top */
+ memory_info.BaseAddress = g_last->top_reserved;
+ /* Assert preconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+ assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+ while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {
+ /* Assert postconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+#ifdef TRACE
+ printf ("Query %p %d %s\n", memory_info.BaseAddress, memory_info.RegionSize,
+ memory_info.State == MEM_FREE ? "FREE":
+ (memory_info.State == MEM_RESERVE ? "RESERVED":
+ (memory_info.State == MEM_COMMIT ? "COMMITTED": "?")));
+#endif
+ /* Region is free, well aligned and big enough: we are done */
+ if (memory_info.State == MEM_FREE &&
+ (unsigned) memory_info.BaseAddress % g_regionsize == 0 &&
+ memory_info.RegionSize >= (unsigned) reserve_size) {
+ found = TRUE;
+ break;
+ }
+ /* From now on we can't get contiguous memory! */
+ contiguous = FALSE;
+ /* Recompute size to reserve */
+ reserve_size = CEIL (allocate_size, g_my_regionsize);
+ memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;
+ /* Assert preconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+ assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+ }
+ /* Search failed? */
+ if (! found)
+ goto sbrk_exit;
+ /* Assert preconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0);
+ assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+ /* Try to reserve this */
+ base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ if (! base_reserved) {
+ int rc = GetLastError ();
+ if (rc != ERROR_INVALID_ADDRESS)
+ goto sbrk_exit;
+ }
+ /* A null pointer signals (hopefully) a race condition with another thread. */
+ /* In this case, we try again. */
+ } while (! base_reserved);
+ /* Check returned pointer for consistency */
+ if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress)
+ goto sbrk_exit;
+ /* Assert postconditions */
+ assert ((unsigned) base_reserved % g_regionsize == 0);
+#ifdef TRACE
+ printf ("Reserve %p %d\n", base_reserved, reserve_size);
+#endif
+ /* Did we get contiguous memory? */
+ if (contiguous) {
+ long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated;
+ /* Adjust allocation size */
+ allocate_size -= start_size;
+ /* Adjust the regions allocation top */
+ g_last->top_allocated = g_last->top_committed;
+ /* Recompute the size to commit */
+ to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+ /* Round size to commit */
+ commit_size = CEIL (to_commit, g_my_pagesize);
+ }
+ /* Append the new region to the list */
+ if (! region_list_append (&g_last, base_reserved, reserve_size))
+ goto sbrk_exit;
+ /* Didn't we get contiguous memory? */
+ if (! contiguous) {
+ /* Recompute the size to commit */
+ to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+ /* Round size to commit */
+ commit_size = CEIL (to_commit, g_my_pagesize);
+ }
+ }
+ }
+ /* Assert preconditions */
+ assert ((unsigned) g_last->top_committed % g_pagesize == 0);
+ assert (0 < commit_size && commit_size % g_pagesize == 0); {
+ /* Commit this */
+ void *base_committed = VirtualAlloc (g_last->top_committed, commit_size,
+ MEM_COMMIT, PAGE_READWRITE);
+ /* Check returned pointer for consistency */
+ if (base_committed != g_last->top_committed)
+ goto sbrk_exit;
+ /* Assert postconditions */
+ assert ((unsigned) base_committed % g_pagesize == 0);
+#ifdef TRACE
+ printf ("Commit %p %d\n", base_committed, commit_size);
+#endif
+ /* Adjust the regions commit top */
+ g_last->top_committed = (char *) base_committed + commit_size;
+ }
+ }
+ /* Adjust the regions allocation top */
+ g_last->top_allocated = (char *) g_last->top_allocated + allocate_size;
+ result = (char *) g_last->top_allocated - size;
+ /* Deallocation requested? */
+ } else if (size < 0) {
+ long deallocate_size = - size;
+ /* As long as we have a region to release */
+ while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) {
+ /* Get the size to release */
+ long release_size = g_last->reserve_size;
+ /* Get the base address */
+ void *base_reserved = (char *) g_last->top_reserved - release_size;
+ /* Assert preconditions */
+ assert ((unsigned) base_reserved % g_regionsize == 0);
+ assert (0 < release_size && release_size % g_regionsize == 0); {
+ /* Release this */
+ int rc = VirtualFree (base_reserved, 0,
+ MEM_RELEASE);
+ /* Check returned code for consistency */
+ if (! rc)
+ goto sbrk_exit;
+#ifdef TRACE
+ printf ("Release %p %d\n", base_reserved, release_size);
+#endif
+ }
+ /* Adjust deallocation size */
+ deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved;
+ /* Remove the old region from the list */
+ if (! region_list_remove (&g_last))
+ goto sbrk_exit;
+ } {
+ /* Compute the size to decommit */
+ long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size);
+ if (to_decommit >= g_my_pagesize) {
+ /* Compute the size to decommit */
+ long decommit_size = FLOOR (to_decommit, g_my_pagesize);
+ /* Compute the base address */
+ void *base_committed = (char *) g_last->top_committed - decommit_size;
+ /* Assert preconditions */
+ assert ((unsigned) base_committed % g_pagesize == 0);
+ assert (0 < decommit_size && decommit_size % g_pagesize == 0); {
+ /* Decommit this */
+ int rc = VirtualFree ((char *) base_committed, decommit_size,
+ MEM_DECOMMIT);
+ /* Check returned code for consistency */
+ if (! rc)
+ goto sbrk_exit;
+#ifdef TRACE
+ printf ("Decommit %p %d\n", base_committed, decommit_size);
+#endif
+ }
+ /* Adjust deallocation size and regions commit and allocate top */
+ deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed;
+ g_last->top_committed = base_committed;
+ g_last->top_allocated = base_committed;
+ }
+ }
+ /* Adjust regions allocate top */
+ g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size;
+ /* Check for underflow */
+ if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated ||
+ g_last->top_allocated > g_last->top_committed) {
+ /* Adjust regions allocate top */
+ g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size;
+ goto sbrk_exit;
+ }
+ result = g_last->top_allocated;
+ }
+ /* Assert invariants */
+ assert (g_last);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&
+ g_last->top_allocated <= g_last->top_committed);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&
+ g_last->top_committed <= g_last->top_reserved &&
+ (unsigned) g_last->top_committed % g_pagesize == 0);
+ assert ((unsigned) g_last->top_reserved % g_regionsize == 0);
+ assert ((unsigned) g_last->reserve_size % g_regionsize == 0);
+
+sbrk_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Release spin lock */
+ slrelease (&g_sl);
+#endif
+ return result;
+}
+
+/* mmap for windows */
+static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) {
+ static long g_pagesize;
+ static long g_regionsize;
+#ifdef TRACE
+ printf ("mmap %d\n", size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Wait for spin lock */
+ slwait (&g_sl);
+#endif
+ /* First time initialization */
+ if (! g_pagesize)
+ g_pagesize = getpagesize ();
+ if (! g_regionsize)
+ g_regionsize = getregionsize ();
+ /* Assert preconditions */
+ assert ((unsigned) ptr % g_regionsize == 0);
+ assert (size % g_pagesize == 0);
+ /* Allocate this */
+ ptr = VirtualAlloc (ptr, size,
+ MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
+ if (! ptr) {
+ ptr = (void *) MORECORE_FAILURE;
+ goto mmap_exit;
+ }
+ /* Assert postconditions */
+ assert ((unsigned) ptr % g_regionsize == 0);
+#ifdef TRACE
+ printf ("Commit %p %d\n", ptr, size);
+#endif
+mmap_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Release spin lock */
+ slrelease (&g_sl);
+#endif
+ return ptr;
+}
+
+/* munmap for windows */
+static long munmap (void *ptr, long size) {
+ static long g_pagesize;
+ static long g_regionsize;
+ int rc = MUNMAP_FAILURE;
+#ifdef TRACE
+ printf ("munmap %p %d\n", ptr, size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Wait for spin lock */
+ slwait (&g_sl);
+#endif
+ /* First time initialization */
+ if (! g_pagesize)
+ g_pagesize = getpagesize ();
+ if (! g_regionsize)
+ g_regionsize = getregionsize ();
+ /* Assert preconditions */
+ assert ((unsigned) ptr % g_regionsize == 0);
+ assert (size % g_pagesize == 0);
+ /* Free this */
+ if (! VirtualFree (ptr, 0,
+ MEM_RELEASE))
+ goto munmap_exit;
+ rc = 0;
+#ifdef TRACE
+ printf ("Release %p %d\n", ptr, size);
+#endif
+munmap_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Release spin lock */
+ slrelease (&g_sl);
+#endif
+ return rc;
+}
+
+static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed) {
+ MEMORY_BASIC_INFORMATION memory_info;
+ memory_info.BaseAddress = 0;
+ *free = *reserved = *committed = 0;
+ while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {
+ switch (memory_info.State) {
+ case MEM_FREE:
+ *free += memory_info.RegionSize;
+ break;
+ case MEM_RESERVE:
+ *reserved += memory_info.RegionSize;
+ break;
+ case MEM_COMMIT:
+ *committed += memory_info.RegionSize;
+ break;
+ }
+ memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;
+ }
+}
+
+static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user) {
+ if (whole) {
+ __int64 creation64, exit64, kernel64, user64;
+ int rc = GetProcessTimes (GetCurrentProcess (),
+ (FILETIME *) &creation64,
+ (FILETIME *) &exit64,
+ (FILETIME *) &kernel64,
+ (FILETIME *) &user64);
+ if (! rc) {
+ *kernel = 0;
+ *user = 0;
+ return FALSE;
+ }
+ *kernel = (unsigned long) (kernel64 / 10000);
+ *user = (unsigned long) (user64 / 10000);
+ return TRUE;
+ } else {
+ __int64 creation64, exit64, kernel64, user64;
+ int rc = GetThreadTimes (GetCurrentThread (),
+ (FILETIME *) &creation64,
+ (FILETIME *) &exit64,
+ (FILETIME *) &kernel64,
+ (FILETIME *) &user64);
+ if (! rc) {
+ *kernel = 0;
+ *user = 0;
+ return FALSE;
+ }
+ *kernel = (unsigned long) (kernel64 / 10000);
+ *user = (unsigned long) (user64 / 10000);
+ return TRUE;
+ }
+}
+
+#endif /* WIN32 */
+
+/* ------------------------------------------------------------
+History:
+
+ V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
+ * Introduce independent_comalloc and independent_calloc.
+ Thanks to Michael Pachos for motivation and help.
+ * Make optional .h file available
+ * Allow > 2GB requests on 32bit systems.
+ * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
+ Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+ and Anonymous.
+ * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
+ helping test this.)
+ * memalign: check alignment arg
+ * realloc: don't try to shift chunks backwards, since this
+ leads to more fragmentation in some programs and doesn't
+ seem to help in any others.
+ * Collect all cases in malloc requiring system memory into sYSMALLOc
+ * Use mmap as backup to sbrk
+ * Place all internal state in malloc_state
+ * Introduce fastbins (although similar to 2.5.1)
+ * Many minor tunings and cosmetic improvements
+ * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
+ * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+ Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
+ * Include errno.h to support default failure action.
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occurring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
+
+#ifdef USE_PUBLIC_MALLOC_WRAPPERS
+
+#ifndef KDE_MALLOC_FULL
+
+#ifdef KDE_MALLOC_GLIBC
+#include "glibc.h"
+#else
+/* cannot use dlsym(RTLD_NEXT,...) here, it calls malloc()*/
+#error Unknown libc
+#endif
+
+/* 0 - uninitialized
+ 1 - this malloc
+ 2 - standard libc malloc*/
+extern char* getenv(const char*);
+static int malloc_type = 0;
+static void init_malloc_type(void)
+ {
+ const char* const env = getenv( "KDE_MALLOC" );
+ if( env == NULL )
+ malloc_type = 1;
+ else if( env[ 0 ] == '0' || env[ 0 ] == 'n' || env[ 0 ] == 'N' )
+ malloc_type = 2;
+ else
+ malloc_type = 1;
+ }
+
+#endif
+
+Void_t* public_mALLOc(size_t bytes) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = mALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_malloc( bytes );
+ init_malloc_type();
+ return public_mALLOc( bytes );
+#endif
+}
+
+void public_fREe(Void_t* m) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ fREe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+#ifndef KDE_MALLOC_FULL
+ return;
+ }
+ if( malloc_type == 2 )
+ {
+ libc_free( m );
+ return;
+ }
+ init_malloc_type();
+ public_fREe( m );
+#endif
+}
+
+Void_t* public_rEALLOc(Void_t* m, size_t bytes) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = rEALLOc(m, bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_realloc( m, bytes );
+ init_malloc_type();
+ return public_rEALLOc( m, bytes );
+#endif
+}
+
+Void_t* public_mEMALIGn(size_t alignment, size_t bytes) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = mEMALIGn(alignment, bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_memalign( alignment, bytes );
+ init_malloc_type();
+ return public_mEMALIGn( alignment, bytes );
+#endif
+}
+
+Void_t* public_vALLOc(size_t bytes) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = vALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_valloc( bytes );
+ init_malloc_type();
+ return public_vALLOc( bytes );
+#endif
+}
+
+Void_t* public_pVALLOc(size_t bytes) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = pVALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_pvalloc( bytes );
+ init_malloc_type();
+ return public_pVALLOc( bytes );
+#endif
+}
+
+Void_t* public_cALLOc(size_t n, size_t elem_size) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = cALLOc(n, elem_size);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_calloc( n, elem_size );
+ init_malloc_type();
+ return public_cALLOc( n, elem_size );
+#endif
+}
+
+void public_cFREe(Void_t* m) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ cFREe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+#ifndef KDE_MALLOC_FULL
+ return;
+ }
+ if( malloc_type == 2 )
+ {
+ libc_cfree( m );
+ return;
+ }
+ init_malloc_type();
+ public_cFREe( m );
+#endif
+}
+
+struct mallinfo public_mALLINFo() {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ struct mallinfo m;
+ if (MALLOC_PREACTION != 0) {
+ struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ return nm;
+ }
+ m = mALLINFo();
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_mallinfo();
+ init_malloc_type();
+ return public_mALLINFo();
+#endif
+}
+
+int public_mALLOPt(int p, int v) {
+#ifndef KDE_MALLOC_FULL
+ if( malloc_type == 1 )
+ {
+#endif
+ int result;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ result = mALLOPt(p, v);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return result;
+#ifndef KDE_MALLOC_FULL
+ }
+ if( malloc_type == 2 )
+ return libc_mallopt( p, v );
+ init_malloc_type();
+ return public_mALLOPt( p, v );
+#endif
+}
+#endif
+
+int
+posix_memalign (void **memptr, size_t alignment, size_t size)
+{
+ void *mem;
+
+ /* Test whether the SIZE argument is valid. It must be a power of
+ two multiple of sizeof (void *). */
+ if (size % sizeof (void *) != 0 || (size & (size - 1)) != 0)
+ return EINVAL;
+
+ mem = memalign (alignment, size);
+
+ if (mem != NULL) {
+ *memptr = mem;
+ return 0;
+ }
+
+ return ENOMEM;
+}
+
+#else
+/* Some linkers (Solaris 2.6) don't like empty archives, but for
+ easier Makefile's we want to link against libklmalloc.la every time,
+ so simply make it non-empty. */
+void kde_malloc_dummy_function ()
+{
+ return;
+}
+#endif
diff --git a/kdecore/malloc/x86.h b/kdecore/malloc/x86.h
new file mode 100644
index 000000000..b21517374
--- /dev/null
+++ b/kdecore/malloc/x86.h
@@ -0,0 +1,41 @@
+#include <sched.h>
+#include <time.h>
+
+typedef struct {
+ volatile unsigned int lock;
+ int pad0_;
+} mutex_t;
+
+#define MUTEX_INITIALIZER { 0, 0 }
+
+static __inline__ int lock(mutex_t *m) {
+ int cnt = 0, r;
+ struct timespec tm;
+
+ for(;;) {
+ __asm__ __volatile__
+ ("xchgl %0, %1"
+ : "=r"(r), "=m"(m->lock)
+ : "0"(1), "m"(m->lock)
+ : "memory");
+ if(!r)
+ return 0;
+#ifdef _POSIX_PRIORITY_SCHEDULING
+ if(cnt < 50) {
+ sched_yield();
+ cnt++;
+ } else
+#endif
+ {
+ tm.tv_sec = 0;
+ tm.tv_nsec = 2000001;
+ nanosleep(&tm, NULL);
+ cnt = 0;
+ }
+ }
+}
+
+static __inline__ int unlock(mutex_t *m) {
+ __asm __volatile ("movl $0,%0" : "=m" (m->lock));
+ return 0;
+}
diff --git a/kdecore/netsupp.cpp b/kdecore/netsupp.cpp
new file mode 100644
index 000000000..ee8ddad23
--- /dev/null
+++ b/kdecore/netsupp.cpp
@@ -0,0 +1,1237 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000,2001 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include <qglobal.h>
+
+// This is so that, if addrinfo is defined, it doesn't clobber our definition
+// It might be defined in the few cases in which we are replacing the system's
+// broken getaddrinfo
+#include <netdb.h>
+
+#include "config.h"
+#include "kdebug.h"
+#include "klocale.h"
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define NEED_IN6_TESTS
+#endif
+#undef CLOBBER_IN6
+#include "netsupp.h"
+
+#if defined(__hpux) || defined(_HPUX_SOURCE)
+extern int h_errno;
+#endif
+
+#include <kdemacros.h>
+
+#if !defined(kde_sockaddr_in6)
+/*
+ * kde_sockaddr_in6 might have got defined even though we #undef'ed
+ * CLOBBER_IN6. This happens when we are compiling under --enable-final.
+ * However, in that case, if it was defined, that's because ksockaddr.cpp
+ * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6
+ * exists and is our kde_sockaddr_in6
+ */
+# define sockaddr_in6 kde_sockaddr_in6
+# define in6_addr kde_in6_addr
+#endif
+
+#ifdef offsetof
+#undef offsetof
+#endif
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/*
+ * These constants tell the flags in KDE::resolverFlags
+ * The user could (but shouldn't) test the variable to know what kind of
+ * resolution is supported
+ */
+#define KRF_KNOWS_AF_INET6 0x01 /* if present, the code knows about AF_INET6 */
+#define KRF_USING_OWN_GETADDRINFO 0x02 /* if present, we are using our own getaddrinfo */
+#define KRF_USING_OWN_INET_NTOP 0x04 /* if present, we are using our own inet_ntop */
+#define KRF_USING_OWN_INET_PTON 0x08 /* if present, we are using our own inet_pton */
+#define KRF_CAN_RESOLVE_UNIX 0x100 /* if present, the resolver can resolve Unix sockets */
+#define KRF_CAN_RESOLVE_IPV4 0x200 /* if present, the resolver can resolve to IPv4 */
+#define KRF_CAN_RESOLVE_IPV6 0x400 /* if present, the resolver can resolve to IPv6 */
+
+
+static void dofreeaddrinfo(struct addrinfo *ai)
+{
+ while (ai)
+ {
+ struct addrinfo *ai2 = ai;
+ if (ai->ai_canonname != NULL)
+ free(ai->ai_canonname);
+
+ if (ai->ai_addr != NULL)
+ free(ai->ai_addr);
+
+ ai = ai->ai_next;
+ free(ai2);
+ }
+}
+
+void kde_freeaddrinfo(struct kde_addrinfo *ai)
+{
+ if (ai->origin == KAI_LOCALUNIX)
+ {
+ struct addrinfo *p, *last = NULL;
+ /* We've added one AF_UNIX socket in here, to the
+ * tail of the linked list. We have to find it */
+ for (p = ai->data; p; p = p->ai_next)
+ {
+ if (p->ai_family == AF_UNIX)
+ {
+ if (last)
+ {
+ last->ai_next = NULL;
+ freeaddrinfo(ai->data);
+ }
+ dofreeaddrinfo(p);
+ break;
+ }
+ last = p;
+ }
+ }
+ else
+ freeaddrinfo(ai->data);
+
+ free(ai);
+}
+
+static struct addrinfo*
+make_unix(const char *name, const char *serv)
+{
+ const char *buf;
+ struct addrinfo *p;
+ struct sockaddr_un *_sun;
+ int len;
+
+ p = (addrinfo*)malloc(sizeof(*p));
+ if (p == NULL)
+ return NULL;
+ memset(p, 0, sizeof(*p));
+
+ if (name != NULL)
+ buf = name;
+ else
+ buf = serv;
+
+ // Calculate length of the binary representation
+ len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1;
+ if (*buf != '/')
+ len += 5; // strlen("/tmp/");
+
+ _sun = (sockaddr_un*)malloc(len);
+ if (_sun == NULL)
+ {
+ // Oops
+ free(p);
+ return NULL;
+ }
+
+ _sun->sun_family = AF_UNIX;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _sun->sun_len = len;
+# endif
+ if (*buf == '/')
+ *_sun->sun_path = '\0'; // empty it
+ else
+ strcpy(_sun->sun_path, "/tmp/");
+ strcat(_sun->sun_path, buf);
+
+ // Set the addrinfo
+ p->ai_family = AF_UNIX;
+ p->ai_addrlen = len;
+ p->ai_addr = (sockaddr*)_sun;
+ p->ai_canonname = strdup(buf);
+
+ return p;
+}
+
+// Ugh. I hate #ifdefs
+// Anyways, here's what this does:
+// KDE_IPV6_LOOKUP_MODE != 1, this function doesn't exist
+// AF_INET6 not defined, we say there is no IPv6 stack
+// otherwise, we try to create a socket.
+// returns: 1 for IPv6 stack available, 2 for not available
+#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1
+static int check_ipv6_stack()
+{
+# ifndef AF_INET6
+ return 2; // how can we check?
+# else
+ if (getenv("KDE_NO_IPV6"))
+ return 2;
+ int fd = ::socket(AF_INET6, SOCK_STREAM, 0);
+ if (fd == -1)
+ return 2;
+
+ ::close(fd);
+ return 1;
+# endif
+}
+#endif
+
+
+/*
+ * Reason for using this function: kde_getaddrinfo
+ *
+ * I decided to add this wrapper function for getaddrinfo
+ * and have this be called by KExtendedSocket instead of
+ * the real getaddrinfo so that we can make sure that the
+ * behavior is the desired one.
+ *
+ * Currently, the only "undesired" behavior is getaddrinfo
+ * not returning PF_UNIX sockets in some implementations.
+ *
+ * getaddrinfo and family are defined in POSIX 1003.1g
+ * (Protocol Independent Interfaces) and in RFC 2553
+ * (Basic Socket Interface for IPv6). Whereas the RFC is ambiguosly
+ * vague whether this family of functions should return Internet
+ * sockets only or not, the name of the POSIX draft says
+ * otherwise: it should be independent of protocol.
+ *
+ * So, my interpretation is that they should return every
+ * kind of socket available and known and that's how I
+ * designed KExtendedSocket on top of it.
+ *
+ * That's why there's this wrapper, to make sure PF_UNIX
+ * sockets are returned when expected.
+ */
+
+int kde_getaddrinfo(const char *name, const char *service,
+ const struct addrinfo* hint,
+ struct kde_addrinfo** result)
+{
+ struct kde_addrinfo* res;
+ struct addrinfo* p;
+ int err = EAI_SERVICE;
+#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1
+ // mode 1: do a check on whether we have an IPv6 stack
+ static int ipv6_stack = 0; // 0: unknown, 1: yes, 2: no
+#endif
+
+ // allocate memory for results
+ res = (kde_addrinfo*)malloc(sizeof(*res));
+ if (res == NULL)
+ return EAI_MEMORY;
+ res->data = NULL;
+ res->origin = KAI_SYSTEM; // at first, it'll be only system data
+
+ struct addrinfo* last = NULL;
+
+ // Skip the getaddrinfo call and the ipv6 check for a UNIX socket.
+ if (hint && (hint->ai_family == PF_UNIX))
+ {
+ if (service == NULL || *service == '\0')
+ goto out; // can't be Unix if no service was requested
+
+ // Unix sockets must be localhost
+ // That is, either name is NULL or, if it's not, it must be empty,
+ // "*" or "localhost"
+ if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') ||
+ strcmp("localhost", name) == 0))
+ goto out; // isn't localhost
+
+ goto do_unix;
+ }
+
+#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 0
+# if KDE_IPV6_LOOKUP_MODE == 1
+ // mode 1: do a check on whether we have an IPv6 stack
+ if (ipv6_stack == 0)
+ ipv6_stack = check_ipv6_stack();
+
+ if (ipv6_stack == 2)
+ {
+# endif
+ // here we have modes 1 and 2 (no lookups)
+ // this is shared code
+ struct addrinfo our_hint;
+ if (hint != NULL)
+ {
+ memcpy(&our_hint, hint, sizeof(our_hint));
+ if (our_hint.ai_family == AF_UNSPEC)
+ our_hint.ai_family = AF_INET;
+ }
+ else
+ {
+ memset(&our_hint, 0, sizeof(our_hint));
+ our_hint.ai_family = AF_INET;
+ }
+
+ // do the actual resolution
+ err = getaddrinfo(name, service, &our_hint, &res->data);
+# if KDE_IPV6_LOOKUP_MODE == 1
+ }
+ else
+# endif
+#endif
+#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 2
+ // do the IPV6 resolution
+ err = getaddrinfo(name, service, hint, &res->data);
+#endif
+
+ // Now we have to check whether the user could want a Unix socket
+
+ if (service == NULL || *service == '\0')
+ goto out; // can't be Unix if no service was requested
+
+ // Unix sockets must be localhost
+ // That is, either name is NULL or, if it's not, it must be empty,
+ // "*" or "localhost"
+ if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') ||
+ strcmp("localhost", name) == 0))
+ goto out; // isn't localhost
+
+ // Unix sockets can only be returned if the user asked for a PF_UNSPEC
+ // or PF_UNIX socket type or gave us a NULL hint
+ if (hint != NULL && (hint->ai_family != PF_UNSPEC && hint->ai_family != PF_UNIX))
+ goto out; // user doesn't want Unix
+
+ // If we got here, then it means that the user might be expecting Unix
+ // sockets. The user wants a local socket, with a non-null service and
+ // has told us that they accept PF_UNIX sockets
+ // Check whether the system implementation returned Unix
+ if (err == 0)
+ for (p = res->data; p; p = p->ai_next)
+ {
+ last = p; // we have to find out which one is last anyways
+ if (p->ai_family == AF_UNIX)
+ // there is an Unix node
+ goto out;
+ }
+
+ do_unix:
+ // So, give the user a PF_UNIX socket
+ p = make_unix(NULL, service);
+ if (p == NULL)
+ {
+ err = EAI_MEMORY;
+ goto out;
+ }
+ if (hint != NULL)
+ p->ai_socktype = hint->ai_socktype;
+ if (p->ai_socktype == 0)
+ p->ai_socktype = SOCK_STREAM; // default
+
+ if (last)
+ last->ai_next = p;
+ else
+ res->data = p;
+ res->origin = KAI_LOCALUNIX;
+ *result = res;
+ return 0;
+
+ out:
+ if (res->data != NULL)
+ freeaddrinfo(res->data);
+ free(res);
+ return err;
+}
+
+#if defined(HAVE_GETADDRINFO) && !defined(HAVE_BROKEN_GETADDRINFO)
+
+#define KRF_getaddrinfo 0
+#define KRF_resolver 0
+
+#else // !defined(HAVE_GETADDRINFO) || defined(HAVE_BROKEN_GETADDRINFO)
+
+#define KRF_getaddrinfo KRF_USING_OWN_GETADDRINFO
+#define KRF_resolver KRF_CAN_RESOLVE_UNIX | KRF_CAN_RESOLVE_IPV4
+
+/*
+ * No getaddrinfo() in this system.
+ * We shall provide our own
+ */
+
+/** TODO
+ * Try and use gethostbyname2_r before gethostbyname2 and gethostbyname
+ */
+static int inet_lookup(const char *name, int portnum, int protonum,
+ struct addrinfo *p, const struct addrinfo *hint,
+ struct addrinfo** result)
+{
+ struct addrinfo *q;
+ struct hostent *h;
+ struct sockaddr **psa = NULL;
+ int len;
+
+ // TODO
+ // Currently, this never resolves IPv6 (need gethostbyname2, etc.)
+# ifdef AF_INET6
+ if (hint->ai_family == AF_INET6)
+ {
+ if (p != NULL)
+ {
+ *result = p;
+ return 0;
+ }
+ return EAI_FAIL;
+ }
+# endif
+
+ q = (addrinfo*)malloc(sizeof(*q));
+ if (q == NULL)
+ {
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+
+ h = gethostbyname(name);
+ if (h == NULL)
+ {
+ if (p != NULL)
+ {
+ // There already is a suitable result
+ *result = p;
+ return 0;
+ }
+
+ switch (h_errno)
+ {
+ case HOST_NOT_FOUND:
+ return EAI_NONAME;
+ case TRY_AGAIN:
+ return EAI_AGAIN;
+ case NO_RECOVERY:
+ return EAI_FAIL;
+ case NO_ADDRESS:
+ return EAI_NODATA;
+ default:
+ // EH!?
+ return EAI_FAIL;
+ }
+ }
+
+ // convert the hostent to addrinfo
+ if (h->h_addrtype == AF_INET && (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC))
+ len = sizeof(struct sockaddr_in);
+# ifdef AF_INET6
+ else if (h->h_addrtype == AF_INET6 && (hint->ai_family == AF_INET6 ||
+ hint->ai_family == AF_UNSPEC))
+ len = sizeof(struct sockaddr_in6);
+# endif
+ else
+ {
+ // We don't know what to do with these addresses
+ // Or gethostbyname returned information we don't want
+ if (p != NULL)
+ {
+ *result = p;
+ return 0;
+ }
+ return EAI_NODATA;
+ }
+
+ q->ai_flags = 0;
+ q->ai_family = h->h_addrtype;
+ q->ai_socktype = hint->ai_socktype;
+ q->ai_protocol = protonum;
+ q->ai_addrlen = len;
+
+ q->ai_addr = (sockaddr*)malloc(len);
+ if (q->ai_addr == NULL)
+ {
+ free(q);
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+ if (h->h_addrtype == AF_INET)
+ {
+ struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr;
+ sin->sin_family = AF_INET;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+# endif
+ sin->sin_port = portnum;
+ memcpy(&sin->sin_addr, h->h_addr, h->h_length);
+ }
+# ifdef AF_INET6
+ else if (h->h_addrtype == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr;
+ sin6->sin6_family = AF_INET6;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6->sin6_len = sizeof(*sin6);
+# endif
+ sin6->sin6_port = portnum;
+ sin6->sin6_flowinfo = 0;
+ memcpy(&sin6->sin6_addr, h->h_addr, h->h_length);
+ sin6->sin6_scope_id = 0;
+ }
+# endif
+
+ if (hint->ai_flags & AI_CANONNAME)
+ q->ai_canonname = strdup(h->h_name);
+ else
+ q->ai_canonname = NULL;
+
+ q->ai_next = p;
+ p = q;
+
+ // cycle through the rest of the hosts;
+ for (psa = (sockaddr**)h->h_addr_list + 1; *psa; psa++)
+ {
+ q = (addrinfo*)malloc(sizeof(*q));
+ if (q == NULL)
+ {
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+ memcpy(q, p, sizeof(*q));
+
+ q->ai_addr = (sockaddr*)malloc(h->h_length);
+ if (q->ai_addr == NULL)
+ {
+ freeaddrinfo(p);
+ free(q);
+ return EAI_MEMORY;
+ }
+ if (h->h_addrtype == AF_INET)
+ {
+ struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr;
+ sin->sin_family = AF_INET;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+# endif
+ sin->sin_port = portnum;
+ memcpy(&sin->sin_addr, *psa, h->h_length);
+ }
+# ifdef AF_INET6
+ else if (h->h_addrtype == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr;
+ sin6->sin6_family = AF_INET6;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6->sin6_len = sizeof(*sin6);
+# endif
+ sin6->sin6_port = portnum;
+ sin6->sin6_flowinfo = 0;
+ memcpy(&sin6->sin6_addr, *psa, h->h_length);
+ sin6->sin6_scope_id = 0;
+ }
+# endif
+
+ if (q->ai_canonname != NULL)
+ q->ai_canonname = strdup(q->ai_canonname);
+
+ q->ai_next = p;
+ p = q;
+ }
+
+ *result = p;
+ return 0; // Whew! Success!
+}
+
+static int make_inet(const char *name, int portnum, int protonum, struct addrinfo *p,
+ const struct addrinfo *hint, struct addrinfo** result)
+{
+ struct addrinfo *q;
+
+ do
+ {
+ // This 'do' is here just so that we can 'break' out of it
+
+ if (name != NULL)
+ {
+ // first, try to use inet_pton before resolving
+ // it will catch IP addresses given without having to go to lookup
+ struct sockaddr_in *sin;
+ struct in_addr in;
+# ifdef AF_INET6
+ struct sockaddr_in6 *sin6;
+ struct in6_addr in6;
+
+ if (hint->ai_family == AF_INET6 || (hint->ai_family == AF_UNSPEC &&
+ strchr(name, ':') != NULL))
+ {
+ // yes, this is IPv6
+ if (inet_pton(AF_INET6, name, &in6) != 1)
+ {
+ if (hint->ai_flags & AI_NUMERICHOST)
+ {
+ freeaddrinfo(p);
+ return EAI_FAIL;
+ }
+ break; // not a numeric host
+ }
+
+ sin6 = (sockaddr_in6*)malloc(sizeof(*sin6));
+ if (sin6 == NULL)
+ {
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+ memcpy(&sin6->sin6_addr, &in6, sizeof(in6));
+
+ if (strchr(name, '%') != NULL)
+ {
+ errno = 0;
+ sin6->sin6_scope_id = strtoul(strchr(name, '%') + 1, NULL, 10);
+ if (errno != 0)
+ sin6->sin6_scope_id = 0; // no interface
+ }
+
+ q = (addrinfo*)malloc(sizeof(*q));
+ if (q == NULL)
+ {
+ freeaddrinfo(p);
+ free(sin6);
+ return EAI_MEMORY;
+ }
+
+ sin6->sin6_family = AF_INET6;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6->sin6_len = sizeof(*sin6);
+# endif
+ sin6->sin6_port = portnum;
+ sin6->sin6_flowinfo = 0;
+
+ q->ai_flags = 0;
+ q->ai_family = AF_INET6;
+ q->ai_socktype = hint->ai_socktype;
+ q->ai_protocol = protonum;
+ q->ai_addrlen = sizeof(*sin6);
+ q->ai_canonname = NULL;
+ q->ai_addr = (sockaddr*)sin6;
+ q->ai_next = p;
+
+ *result = q;
+ return 0; // success!
+ }
+# endif // AF_INET6
+
+ if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)
+ {
+ // This has to be IPv4
+ if (inet_pton(AF_INET, name, &in) != 1)
+ {
+ if (hint->ai_flags & AI_NUMERICHOST)
+ {
+ freeaddrinfo(p);
+ return EAI_FAIL; // invalid, I guess
+ }
+ break; // not a numeric host, do lookup
+ }
+
+ sin = (sockaddr_in*)malloc(sizeof(*sin));
+ if (sin == NULL)
+ {
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+
+ q = (addrinfo*)malloc(sizeof(*q));
+ if (q == NULL)
+ {
+ freeaddrinfo(p);
+ free(sin);
+ return EAI_MEMORY;
+ }
+
+ sin->sin_family = AF_INET;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+# endif
+ sin->sin_port = portnum;
+ sin->sin_addr = in;
+
+ q->ai_flags = 0;
+ q->ai_family = AF_INET;
+ q->ai_socktype = hint->ai_socktype;
+ q->ai_protocol = protonum;
+ q->ai_addrlen = sizeof(*sin);
+ q->ai_canonname = NULL;
+ q->ai_addr = (sockaddr*)sin;
+ q->ai_next = p;
+ *result = q;
+ return 0;
+ }
+
+ // Eh, what!?
+ // One of the two above has to have matched
+ kdError() << "I wasn't supposed to get here!";
+ }
+ } while (false);
+
+ // This means localhost
+ if (name == NULL)
+ {
+ struct sockaddr_in *sin = (sockaddr_in*)malloc(sizeof(*sin));
+# ifdef AF_INET6
+ struct sockaddr_in6 *sin6;
+# endif
+
+ if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)
+ {
+ if (sin == NULL)
+ {
+ free(sin);
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+
+ // Do IPv4 first
+ q = (addrinfo*)malloc(sizeof(*q));
+ if (q == NULL)
+ {
+ free(sin);
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+
+ sin->sin_family = AF_INET;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+# endif
+ sin->sin_port = portnum;
+ if (hint->ai_flags & AI_PASSIVE)
+ *(Q_UINT32*)&sin->sin_addr = INADDR_ANY;
+ else
+ *(Q_UINT32*)&sin->sin_addr = htonl(INADDR_LOOPBACK);
+ q->ai_flags = 0;
+ q->ai_family = AF_INET;
+ q->ai_socktype = hint->ai_socktype;
+ q->ai_protocol = protonum;
+ q->ai_addrlen = sizeof(*sin);
+ q->ai_canonname = NULL;
+ q->ai_addr = (sockaddr*)sin;
+ q->ai_next = p;
+ p = q;
+ }
+
+# ifdef AF_INET6
+ // Try now IPv6
+
+ if (hint->ai_family == AF_INET6 || hint->ai_family == AF_UNSPEC)
+ {
+ sin6 = (sockaddr_in6*)malloc(sizeof(*sin6));
+ q = (addrinfo*)malloc(sizeof(*q));
+ if (q == NULL || sin6 == NULL)
+ {
+ free(sin6);
+ free(q);
+ freeaddrinfo(p);
+ return EAI_MEMORY;
+ }
+
+ sin6->sin6_family = AF_INET6;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6->sin6_len = sizeof(*sin6);
+# endif
+ sin6->sin6_port = portnum;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+
+ // We don't want to use in6addr_loopback and in6addr_any
+ memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
+ if ((hint->ai_flags & AI_PASSIVE) == 0)
+ ((char*)&sin6->sin6_addr)[15] = 1;
+
+ q->ai_flags = 0;
+ q->ai_family = AF_INET6;
+ q->ai_socktype = hint->ai_socktype;
+ q->ai_protocol = protonum;
+ q->ai_addrlen = sizeof(*sin6);
+ q->ai_canonname = NULL;
+ q->ai_addr = (sockaddr*)sin6;
+ q->ai_next = p;
+ p = q;
+ }
+
+# endif // AF_INET6
+
+ *result = p;
+ return 0; // success!
+ }
+
+ return inet_lookup(name, portnum, protonum, p, hint, result);
+}
+
+
+int getaddrinfo(const char *name, const char *serv,
+ const struct addrinfo* hint,
+ struct addrinfo** result)
+{
+ unsigned short portnum; // remember to store in network byte order
+ int protonum = IPPROTO_TCP;
+ const char *proto = "tcp";
+ struct addrinfo *p = NULL;
+
+ // Sanity checks:
+ if (hint == NULL || result == NULL)
+ return EAI_BADFLAGS;
+ if (hint->ai_family != AF_UNSPEC && hint->ai_family != AF_UNIX &&
+ hint->ai_family != AF_INET
+# ifdef AF_INET6
+ && hint->ai_family != AF_INET6
+# endif
+ )
+ return EAI_FAMILY;
+ if (hint->ai_socktype != 0 && hint->ai_socktype != SOCK_STREAM &&
+ hint->ai_socktype != SOCK_DGRAM)
+ return EAI_SOCKTYPE;
+
+ // Treat hostname of "*" as NULL, which means localhost
+ if (name != NULL && ((*name == '*' && name[1] == '\0') || *name == '\0'))
+ name = NULL;
+ // Treat service of "*" as NULL, which I guess means no port (0)
+ if (serv != NULL && ((*serv == '*' && serv[1] == '\0') || *serv == '\0'))
+ serv = NULL;
+
+ if (name == NULL && serv == NULL) // what the hell do you want?
+ return EAI_NONAME;
+
+ // This is just to make it easier
+ if (name != NULL && strcmp(name, "localhost") == 0)
+ name = NULL;
+
+ // First, check for a Unix socket
+ // family must be either AF_UNIX or AF_UNSPEC
+ // either of name or serv must be set, the other must be NULL or empty
+ if (hint->ai_family == AF_UNIX || hint->ai_family == AF_UNSPEC)
+ {
+ if (name != NULL && serv != NULL)
+ {
+ // This is not allowed
+ if (hint->ai_family == AF_UNIX)
+ return EAI_BADFLAGS;
+ }
+ else
+ {
+ p = make_unix(name, serv);
+ if (p == NULL)
+ return EAI_MEMORY;
+
+ p->ai_socktype = hint->ai_socktype;
+ // If the name/service started with a slash, then this *IS*
+ // only a Unix socket. Return.
+ if (hint->ai_family == AF_UNIX || ((name != NULL && *name == '/') ||
+ (serv != NULL && *serv == '/')))
+ {
+ *result = p;
+ return 0; // successful lookup
+ }
+ }
+ }
+
+ // Lookup the service name, if required
+ if (serv != NULL)
+ {
+ char *tail;
+ struct servent *sent;
+
+ portnum = htons((unsigned)strtoul(serv, &tail, 10));
+ if (*tail != '\0')
+ {
+ // not a number. We have to do the lookup
+ if (hint->ai_socktype == SOCK_DGRAM)
+ {
+ proto = "udp";
+ protonum = IPPROTO_UDP;
+ }
+
+ sent = getservbyname(serv, proto);
+ if (sent == NULL) // no service?
+ {
+ if (p == NULL)
+ return EAI_NONAME;
+ else
+ return 0; // a Unix socket available
+ }
+
+ portnum = sent->s_port;
+ }
+ }
+ else
+ portnum = 0; // no port number
+
+ return make_inet(name, portnum, protonum, p, hint, result);
+}
+
+void freeaddrinfo(struct addrinfo *p)
+{
+ dofreeaddrinfo(p);
+}
+
+char *gai_strerror(int errorcode)
+{
+ static const char * const messages[] =
+ {
+ I18N_NOOP("no error"), // 0
+ I18N_NOOP("address family for nodename not supported"), // EAI_ADDRFAMILY
+ I18N_NOOP("temporary failure in name resolution"), // EAI_AGAIN
+ I18N_NOOP("invalid value for 'ai_flags'"), // EAI_BADFLAGS
+ I18N_NOOP("non-recoverable failure in name resolution"), // EAI_FAIL
+ I18N_NOOP("'ai_family' not supported"), // EAI_FAMILY
+ I18N_NOOP("memory allocation failure"), // EAI_MEMORY
+ I18N_NOOP("no address associated with nodename"), // EAI_NODATA
+ I18N_NOOP("name or service not known"), // EAI_NONAME
+ I18N_NOOP("servname not supported for ai_socktype"), // EAI_SERVICE
+ I18N_NOOP("'ai_socktype' not supported"), // EAI_SOCKTYPE
+ I18N_NOOP("system error") // EAI_SYSTEM
+ };
+
+ if (errorcode > EAI_SYSTEM || errorcode < 0)
+ return NULL;
+
+ static char buffer[200];
+ strcpy(buffer, i18n(messages[errorcode]).local8Bit());
+ return buffer;
+}
+
+static void findport(unsigned short port, char *serv, size_t servlen, int flags)
+{
+ if (serv == NULL)
+ return;
+
+ if ((flags & NI_NUMERICSERV) == 0)
+ {
+ struct servent *sent;
+ sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp");
+ if (sent != NULL && servlen > strlen(sent->s_name))
+ {
+ strcpy(serv, sent->s_name);
+ return;
+ }
+ }
+
+ snprintf(serv, servlen, "%u", ntohs(port));
+}
+
+int getnameinfo(const struct sockaddr *sa, ksocklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen,
+ int flags)
+{
+ union
+ {
+ const sockaddr *sa;
+ const sockaddr_un *_sun;
+ const sockaddr_in *sin;
+ const sockaddr_in6 *sin6;
+ } s;
+
+ if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0))
+ return 1;
+
+ s.sa = sa;
+ if (s.sa->sa_family == AF_UNIX)
+ {
+ if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1)
+ return 1; // invalid socket
+
+ if (servlen && serv != NULL)
+ *serv = '\0';
+ if (host != NULL && hostlen > strlen(s._sun->sun_path))
+ strcpy(host, s._sun->sun_path);
+
+ return 0;
+ }
+ else if (s.sa->sa_family == AF_INET)
+ {
+ if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr))
+ return 1; // invalid socket
+
+ if (flags & NI_NUMERICHOST)
+ inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
+ else
+ {
+ // have to do lookup
+ struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
+ AF_INET);
+ if (h == NULL && flags & NI_NAMEREQD)
+ return 1;
+ else if (h == NULL)
+ inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
+ else if (host != NULL && hostlen > strlen(h->h_name))
+ strcpy(host, h->h_name);
+ else
+ return 1; // error
+ }
+
+ findport(s.sin->sin_port, serv, servlen, flags);
+ }
+# ifdef AF_INET6
+ else if (s.sa->sa_family == AF_INET6)
+ {
+ if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr))
+ return 1; // invalid socket
+
+ if (flags & NI_NUMERICHOST)
+ inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
+ else
+ {
+ // have to do lookup
+ struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
+ AF_INET6);
+ if (h == NULL && flags & NI_NAMEREQD)
+ return 1;
+ else if (h == NULL)
+ inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
+ else if (host != NULL && hostlen > strlen(h->h_name))
+ strcpy(host, h->h_name);
+ else
+ return 1; // error
+ }
+
+ findport(s.sin6->sin6_port, serv, servlen, flags);
+ }
+# endif // AF_INET6
+
+ return 1; // invalid family
+}
+
+#endif // HAVE_GETADDRINFO
+
+#ifndef HAVE_INET_NTOP
+
+#define KRF_inet_ntop KRF_USING_OWN_INET_NTOP
+
+static void add_dwords(char *buf, Q_UINT16 *dw, int count)
+{
+ int i = 1;
+ sprintf(buf + strlen(buf), "%x", ntohs(dw[0]));
+ while (--count)
+ sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++]));
+}
+
+const char* inet_ntop(int af, const void *cp, char *buf, size_t len)
+{
+ char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1];
+ Q_UINT8 *data = (Q_UINT8*)cp;
+
+ if (af == AF_INET)
+ {
+ sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]);
+
+ if (len > strlen(buf2))
+ {
+ strcpy(buf, buf2);
+ return buf;
+ }
+
+ errno = ENOSPC;
+ return NULL; // failed
+ }
+
+# ifdef AF_INET6
+ if (af == AF_INET6)
+ {
+ Q_UINT16 *p = (Q_UINT16*)data;
+ Q_UINT16 *longest = NULL, *cur = NULL;
+ int longest_length = 0, cur_length;
+ int i;
+
+ if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p))
+ sprintf(buf2, "::%s%u.%u.%u.%u",
+ KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "",
+ buf[12], buf[13], buf[14], buf[15]);
+ else
+ {
+ // find the longest sequence of zeroes
+ for (i = 0; i < 8; i++)
+ if (cur == NULL && p[i] == 0)
+ {
+ // a zero, start the sequence
+ cur = p + i;
+ cur_length = 1;
+ }
+ else if (cur != NULL && p[i] == 0)
+ // part of the sequence
+ cur_length++;
+ else if (cur != NULL && p[i] != 0)
+ {
+ // end of the sequence
+ if (cur_length > longest_length)
+ {
+ longest_length = cur_length;
+ longest = cur;
+ }
+ cur = NULL; // restart sequence
+ }
+ if (cur != NULL && cur_length > longest_length)
+ {
+ longest_length = cur_length;
+ longest = cur;
+ }
+
+ if (longest_length > 1)
+ {
+ // We have a candidate
+ buf2[0] = '\0';
+ if (longest != p)
+ add_dwords(buf2, p, longest - p);
+ strcat(buf2, "::");
+ if (longest + longest_length < p + 8)
+ add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length);
+ }
+ else
+ {
+ // Nope, no candidate
+ buf2[0] = '\0';
+ add_dwords(buf2, p, 8);
+ }
+ }
+
+ if (strlen(buf2) < len)
+ {
+ strcpy(buf, buf2);
+ return buf;
+ }
+
+ errno = ENOSPC;
+ return NULL;
+ }
+# endif
+
+ errno = EAFNOSUPPORT;
+ return NULL; // a family we don't know about
+}
+
+#else // HAVE_INET_NTOP
+
+#define KRF_inet_ntop 0
+
+#endif // HAVE_INET_NTOP
+
+#ifndef HAVE_INET_PTON
+
+#define KRF_inet_pton KRF_USING_OWN_INET_PTON
+int inet_pton(int af, const char *cp, void *buf)
+{
+ if (af == AF_INET)
+ {
+ // Piece of cake
+ unsigned p[4];
+ unsigned char *q = (unsigned char*)buf;
+ if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4)
+ return 0;
+
+ if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff)
+ return 0;
+
+ q[0] = p[0];
+ q[1] = p[1];
+ q[2] = p[2];
+ q[3] = p[3];
+
+ return 1;
+ }
+
+# ifdef AF_INET6
+ else if (af == AF_INET6)
+ {
+ Q_UINT16 addr[8];
+ const char *p = cp;
+ int n = 0, start = 8;
+ bool has_v4 = strchr(p, '.') != NULL;
+
+ memset(addr, 0, sizeof(addr));
+
+ if (*p == '\0' || p[1] == '\0')
+ return 0; // less than 2 chars is not valid
+
+ if (*p == ':' && p[1] == ':')
+ {
+ start = 0;
+ p += 2;
+ }
+ while (*p)
+ {
+ if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0)
+ {
+ // successful v4 convertion
+ addr[n] = ntohs(addr[n]);
+ n++;
+ addr[n] = ntohs(addr[n]);
+ n++;
+ break;
+ }
+ if (sscanf(p, "%hx", addr + n++) != 1)
+ return 0;
+
+ while (*p && *p != ':')
+ p++;
+ if (!*p)
+ break;
+ p++;
+
+ if (*p == ':') // another ':'?
+ {
+ if (start != 8)
+ return 0; // two :: were found
+ start = n;
+ p++;
+ }
+ }
+
+ // if start is not 8, then a "::" was found at word 'start'
+ // n is the number of converted words
+ // n == 8 means everything was converted and no moving is necessary
+ // n < 8 means that we have to move n - start words 8 - n words to the right
+ if (start == 8 && n != 8)
+ return 0; // bad conversion
+ memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(Q_UINT16));
+ memset(addr + start, 0, (8 - n) * sizeof(Q_UINT16));
+
+ // check the byte order
+ // The compiler should optimise this out in big endian machines
+ if (htons(0x1234) != 0x1234)
+ for (n = 0; n < 8; n++)
+ addr[n] = htons(addr[n]);
+
+ memcpy(buf, addr, sizeof(addr));
+ return 1;
+ }
+# endif
+
+ errno = EAFNOSUPPORT;
+ return -1; // unknown family
+}
+
+#else // HAVE_INET_PTON
+
+#define KRF_inet_pton 0
+
+#endif // HAVE_INET_PTON
+
+#ifdef AF_INET6
+# define KRF_afinet6 KRF_KNOWS_AF_INET6
+#else
+# define KRF_afinet6 0
+#endif
+
+namespace KDE
+{
+ /** @internal */
+ extern const int KDE_EXPORT resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton;
+}
diff --git a/kdecore/netsupp.h b/kdecore/netsupp.h
new file mode 100644
index 000000000..66435d24b
--- /dev/null
+++ b/kdecore/netsupp.h
@@ -0,0 +1,301 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2003 Thiago Macieira <thiago.macieira@kdemail.net>>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _NETSUPP_H_
+#define _NETSUPP_H_
+
+#include "kdelibs_export.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/socket.h>
+#include <netdb.h>
+//#include "ksockaddr.h"
+
+#ifdef __CYGWIN__
+typedef unsigned ksocklen_t;
+#endif
+
+/*
+ * Seems some systems don't know about AF_LOCAL
+ */
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#define PF_LOCAL PF_UNIX
+#endif
+
+#ifdef CLOBBER_IN6
+#define kde_in6_addr in6_addr
+#define kde_sockaddr_in6 sockaddr_in6
+#endif
+
+/*** IPv6 structures that might be missing from some implementations ***/
+
+/** @internal
+ * An IPv6 address.
+ * This is taken from RFC 2553
+ */
+struct kde_in6_addr
+{
+ unsigned char __u6_addr[16];
+};
+
+/** @internal
+ * An IPv6 socket address
+ * This is taken from RFC 2553.
+ */
+struct kde_sockaddr_in6
+{
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ Q_UINT8 sin6_len;
+ Q_UINT8 sin6_family;
+#else //HAVE_STRUCT_SOCKADDR_SA_LEN
+ Q_UINT16 sin6_family;
+#endif
+ unsigned short sin6_port; /* RFC says in_port_t */
+ Q_UINT32 sin6_flowinfo;
+ struct kde_in6_addr sin6_addr;
+ Q_UINT32 sin6_scope_id;
+};
+
+/* IPv6 test macros that could be missing from some implementations */
+
+#define KDE_IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((Q_UINT32 *) (a))[0] == 0 && ((Q_UINT32 *) (a))[1] == 0 && \
+ ((Q_UINT32 *) (a))[2] == 0 && ((Q_UINT32 *) (a))[3] == 0)
+
+#define KDE_IN6_IS_ADDR_LOOPBACK(a) \
+ (((Q_UINT32 *) (a))[0] == 0 && ((Q_UINT32 *) (a))[1] == 0 && \
+ ((Q_UINT32 *) (a))[2] == 0 && ((Q_UINT32 *) (a))[3] == htonl (1))
+
+#define KDE_IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff)
+
+#define KDE_IN6_IS_ADDR_LINKLOCAL(a) \
+ ((((Q_UINT32 *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000))
+
+#define KDE_IN6_IS_ADDR_SITELOCAL(a) \
+ ((((Q_UINT32 *) (a))[0] & htonl (0xffc00000)) == htonl (0xfec00000))
+
+#define KDE_IN6_IS_ADDR_V4MAPPED(a) \
+ ((((Q_UINT32 *) (a))[0] == 0) && (((Q_UINT32 *) (a))[1] == 0) && \
+ (((Q_UINT32 *) (a))[2] == htonl (0xffff)))
+
+#define KDE_IN6_IS_ADDR_V4COMPAT(a) \
+ ((((Q_UINT32 *) (a))[0] == 0) && (((Q_UINT32 *) (a))[1] == 0) && \
+ (((Q_UINT32 *) (a))[2] == 0) && (ntohl (((Q_UINT32 *) (a))[3]) > 1))
+
+#define KDE_IN6_ARE_ADDR_EQUAL(a,b) \
+ ((((Q_UINT32 *) (a))[0] == ((Q_UINT32 *) (b))[0]) && \
+ (((Q_UINT32 *) (a))[1] == ((Q_UINT32 *) (b))[1]) && \
+ (((Q_UINT32 *) (a))[2] == ((Q_UINT32 *) (b))[2]) && \
+ (((Q_UINT32 *) (a))[3] == ((Q_UINT32 *) (b))[3]))
+
+#define KDE_IN6_IS_ADDR_MC_NODELOCAL(a) \
+ (KDE_IN6_IS_ADDR_MULTICAST(a) && ((((Q_UINT8 *) (a))[1] & 0xf) == 0x1))
+
+#define KDE_IN6_IS_ADDR_MC_LINKLOCAL(a) \
+ (KDE_IN6_IS_ADDR_MULTICAST(a) && ((((Q_UINT8 *) (a))[1] & 0xf) == 0x2))
+
+#define KDE_IN6_IS_ADDR_MC_SITELOCAL(a) \
+ (KDE_IN6_IS_ADDR_MULTICAST(a) && ((((Q_UINT8 *) (a))[1] & 0xf) == 0x5))
+
+#define KDE_IN6_IS_ADDR_MC_ORGLOCAL(a) \
+ (KDE_IN6_IS_ADDR_MULTICAST(a) && ((((Q_UINT8 *) (a))[1] & 0xf) == 0x8))
+
+#define KDE_IN6_IS_ADDR_MC_GLOBAL(a) \
+ (KDE_IN6_IS_ADDR_MULTICAST(a) && ((((Q_UINT8 *) (a))[1] & 0xf) == 0xe))
+
+#ifdef NEED_IN6_TESTS
+# define IN6_IS_ADDR_UNSPECIFIED KDE_IN6_IS_ADDR_UNSPECIFIED
+# define IN6_IS_ADDR_LOOPBACK KDE_IN6_IS_ADDR_LOOPBACK
+# define IN6_IS_ADDR_MULTICAST KDE_IN6_IS_ADDR_MULTICAST
+# define IN6_IS_ADDR_LINKLOCAL KDE_IN6_IS_ADDR_LINKLOCAL
+# define IN6_IS_ADDR_SITELOCAL KDE_IN6_IS_ADDR_SITELOCAL
+# define IN6_IS_ADDR_V4MAPPED KDE_IN6_IS_ADDR_V4MAPPED
+# define IN6_IS_ADDR_V4COMPAT KDE_IN6_IS_ADDR_V4COMPAT
+# define IN6_ARE_ADDR_EQUAL KDE_IN6_ARE_ADDR_EQUAL
+# define IN6_IS_ADDR_MC_NODELOCAL KDE_IN6_IS_ADDR_MC_NODELOCAL
+# define IN6_IS_ADDR_MC_LINKLOCAL KDE_IN6_IS_ADDR_MC_LINKLOCAL
+# define IN6_IS_ADDR_MC_SITELOCAL KDE_IN6_IS_ADDR_MC_SITELOCAL
+# define IN6_IS_ADDR_MC_ORGLOCAL KDE_IN6_IS_ADDR_MC_ORGLOCAL
+# define IN6_IS_ADDR_MC_GLOBAL KDE_IN6_IS_ADDR_MC_GLOBAL
+#endif
+
+/* Special internal structure */
+
+#define KAI_SYSTEM 0 /* data is all-system */
+#define KAI_LOCALUNIX 1 /* data contains a Unix addrinfo allocated by us */
+#define KAI_QDNS 2 /* data contains data derived from QDns */
+
+struct addrinfo; /* forward declaration; this could be needed */
+
+/**
+ * @internal
+ * Special purpose structure, to return data from kde_getaddrinfo to the
+ * library functions. This defines an extra field to let us know how to
+ * process this better.
+ *
+ * Currently, we use it to determine how to deallocate this stuff
+ */
+struct kde_addrinfo
+{
+ struct addrinfo *data;
+ int origin;
+};
+
+extern KDECORE_EXPORT int kde_getaddrinfo(const char *name, const char *service,
+ const struct addrinfo* hint,
+ struct kde_addrinfo** result);
+extern KDECORE_EXPORT void kde_freeaddrinfo(struct kde_addrinfo *p);
+
+#if !defined(HAVE_GETADDRINFO) || defined(HAVE_BROKEN_GETADDRINFO)
+
+# ifndef HAVE_STRUCT_ADDRINFO
+/**
+ * @internal
+ */
+struct addrinfo
+{
+ int ai_flags; /**< Input flags. */
+ int ai_family; /**< Protocol family for socket. */
+ int ai_socktype; /**< Socket type. */
+ int ai_protocol; /**< Protocol for socket. */
+ int ai_addrlen; /**< Length of socket address. */
+ struct sockaddr *ai_addr; /**< Socket address for socket. */
+ char *ai_canonname; /**< Canonical name for service location. */
+ struct addrinfo *ai_next; /**< Pointer to next in list. */
+};
+# endif
+
+# ifdef AI_PASSIVE
+# undef AI_PASSIVE
+# undef AI_CANONNAME
+# undef AI_NUMERICHOST
+# endif
+
+/* Possible values for `ai_flags' field in `addrinfo' structure. */
+# define AI_PASSIVE 1 /* Socket address is intended for `bind'. */
+# define AI_CANONNAME 2 /* Request for canonical name. */
+# define AI_NUMERICHOST 4 /* Don't use name resolution. */
+
+# ifdef EAI_ADDRFAMILY
+# undef EAI_ADDRFAMILY
+# undef EAI_AGAIN
+# undef EAI_BADFLAGS
+# undef EAI_FAIL
+# undef EAI_FAMILY
+# undef EAI_MEMORY
+# undef EAI_NODATA
+# undef EAI_NONAME
+# undef EAI_SERVICE
+# undef EAI_SOCKTYPE
+# undef EAI_SYSTEM
+# endif
+
+/* Error values for `getaddrinfo' function. */
+# define EAI_ADDRFAMILY 1 /* Address family for NAME not supported. */
+# define EAI_AGAIN 2 /* Temporary failure in name resolution. */
+# define EAI_BADFLAGS 3 /* Invalid value for `ai_flags' field. */
+# define EAI_FAIL 4 /* Non-recoverable failure in name res. */
+# define EAI_FAMILY 5 /* `ai_family' not supported. */
+# define EAI_MEMORY 6 /* Memory allocation failure. */
+# define EAI_NODATA 7 /* No address associated with NAME. */
+# define EAI_NONAME 8 /* NAME or SERVICE is unknown. */
+# define EAI_SERVICE 9 /* SERVICE not supported for `ai_socktype'. */
+# define EAI_SOCKTYPE 10 /* `ai_socktype' not supported. */
+# define EAI_SYSTEM 11 /* System error returned in `errno'. */
+
+/*
+ * These are specified in the RFC
+ * We won't undefine them. If someone defined them to a different value
+ * the preprocessor will generate an error
+ */
+# define NI_MAXHOST 1025
+# define NI_MAXSERV 32
+
+# ifdef NI_NUMERICHOST
+# undef NI_NUMERICHOST
+# undef NI_NUMERICSERV
+# undef NI_NOFQDN
+# undef NI_NAMEREQD
+# undef NI_DGRAM
+# endif
+
+# define NI_NUMERICHOST 1 /* Don't try to look up hostname. */
+# define NI_NUMERICSERV 2 /* Don't convert port number to name. */
+# define NI_NOFQDN 4 /* Only return nodename portion. */
+# define NI_NAMEREQD 8 /* Don't return numeric addresses. */
+# define NI_DGRAM 16 /* Look up UDP service rather than TCP. */
+
+# ifdef getaddrinfo
+# undef getaddrinfo
+# endif
+
+namespace KDE
+{
+ /** \internal */
+ extern KDECORE_EXPORT int getaddrinfo(const char *name, const char *service,
+ const struct addrinfo* hint,
+ struct addrinfo** result);
+ /** \internal */
+ extern KDECORE_EXPORT void freeaddrinfo(struct addrinfo* ai);
+ /** \internal */
+ extern KDECORE_EXPORT char *gai_strerror(int errorcode);
+ /** \internal */
+ extern KDECORE_EXPORT int getnameinfo(const struct sockaddr *sa,
+ unsigned int salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags);
+}
+
+# define getaddrinfo KDE::getaddrinfo
+# define freeaddrinfo KDE::freeaddrinfo
+# define gai_strerror KDE::gai_strerror
+# define getnameinfo KDE::getnameinfo
+
+
+#endif
+
+#ifndef HAVE_INET_PTON
+
+namespace KDE
+{
+ /** \internal */
+ extern KDECORE_EXPORT int inet_pton(int af, const char *cp, void* buf);
+}
+
+# define inet_pton KDE::inet_pton
+#endif
+
+#ifndef HAVE_INET_NTOP
+
+namespace KDE
+{
+ /** \internal */
+ extern KDECORE_EXPORT const char* inet_ntop(int af, const void *cp, char *buf, size_t len);
+}
+
+# define inet_ntop KDE::inet_ntop
+#endif
+
+#endif
diff --git a/kdecore/netsupp_win32.cpp b/kdecore/netsupp_win32.cpp
new file mode 100644
index 000000000..316c5f4cd
--- /dev/null
+++ b/kdecore/netsupp_win32.cpp
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2003 Thiago Macieira <thiago.macieira@kdemail.net>>
+ *
+ * win32 version of netsupp.cpp
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+
+#include "netsupp.h"
+
+KDECORE_EXPORT void kde_freeaddrinfo(struct kde_addrinfo *ai)
+{
+ //TODO
+}
+
+KDECORE_EXPORT int kde_getaddrinfo(const char *name, const char *service,
+ const struct addrinfo* hint,
+ struct kde_addrinfo** result)
+{
+ //TODO
+ int err = EAI_SERVICE;
+ return err;
+}
+
+KDECORE_EXPORT char *gai_strerror(int errorcode)
+{
+ return 0;
+}
+int getnameinfo(const struct sockaddr *sa,
+ unsigned int salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags)
+{
+ //TODO
+ return -1;
+}
+
+KDECORE_EXPORT const char* inet_ntop(int af, const void *cp, char *buf, size_t len)
+{
+ //TODO
+ return 0;
+}
+
+KDECORE_EXPORT int inet_pton(int af, const char *cp, void *buf)
+{
+ //TODO
+ return -1;
+}
+
diff --git a/kdecore/netwm.cpp b/kdecore/netwm.cpp
new file mode 100644
index 000000000..e0685abc7
--- /dev/null
+++ b/kdecore/netwm.cpp
@@ -0,0 +1,4634 @@
+/*
+
+ Copyright (c) 2000 Troll Tech AS
+ Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
+
+ 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 OR COPYRIGHT HOLDERS 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.
+
+*/
+
+//#define NETWMDEBUG
+
+#include <qwidget.h>
+#ifdef Q_WS_X11 //FIXME
+
+#include "netwm.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <X11/Xmd.h>
+
+#include "netwm_p.h"
+
+// UTF-8 string
+static Atom UTF8_STRING = 0;
+
+// root window properties
+static Atom net_supported = 0;
+static Atom net_client_list = 0;
+static Atom net_client_list_stacking = 0;
+static Atom net_desktop_geometry = 0;
+static Atom net_desktop_viewport = 0;
+static Atom net_current_desktop = 0;
+static Atom net_desktop_names = 0;
+static Atom net_number_of_desktops = 0;
+static Atom net_active_window = 0;
+static Atom net_workarea = 0;
+static Atom net_supporting_wm_check = 0;
+static Atom net_virtual_roots = 0;
+static Atom net_showing_desktop = 0;
+static Atom net_desktop_layout = 0;
+
+// root window messages
+static Atom net_close_window = 0;
+static Atom net_restack_window = 0;
+static Atom net_wm_moveresize = 0;
+static Atom net_moveresize_window = 0;
+
+// application window properties
+static Atom net_wm_name = 0;
+static Atom net_wm_visible_name = 0;
+static Atom net_wm_icon_name = 0;
+static Atom net_wm_visible_icon_name = 0;
+static Atom net_wm_desktop = 0;
+static Atom net_wm_window_type = 0;
+static Atom net_wm_state = 0;
+static Atom net_wm_strut = 0;
+static Atom net_wm_extended_strut = 0; // the atom is called _NET_WM_STRUT_PARTIAL
+static Atom net_wm_icon_geometry = 0;
+static Atom net_wm_icon = 0;
+static Atom net_wm_pid = 0;
+static Atom net_wm_user_time = 0;
+static Atom net_wm_handled_icons = 0;
+static Atom net_startup_id = 0;
+static Atom net_wm_allowed_actions = 0;
+static Atom wm_window_role = 0;
+static Atom net_frame_extents = 0;
+
+// KDE extensions
+static Atom kde_net_system_tray_windows = 0;
+static Atom kde_net_wm_system_tray_window_for = 0;
+static Atom kde_net_wm_frame_strut = 0;
+static Atom kde_net_wm_window_type_override = 0;
+static Atom kde_net_wm_window_type_topmenu = 0;
+static Atom kde_net_wm_temporary_rules = 0;
+
+// application protocols
+static Atom wm_protocols = 0;
+static Atom net_wm_ping = 0;
+static Atom net_wm_take_activity = 0;
+
+// application window types
+static Atom net_wm_window_type_normal = 0;
+static Atom net_wm_window_type_desktop = 0;
+static Atom net_wm_window_type_dock = 0;
+static Atom net_wm_window_type_toolbar = 0;
+static Atom net_wm_window_type_menu = 0;
+static Atom net_wm_window_type_dialog = 0;
+static Atom net_wm_window_type_utility = 0;
+static Atom net_wm_window_type_splash = 0;
+static Atom net_wm_window_type_dropdown_menu = 0;
+static Atom net_wm_window_type_popup_menu = 0;
+static Atom net_wm_window_type_tooltip = 0;
+static Atom net_wm_window_type_notification = 0;
+static Atom net_wm_window_type_combobox = 0;
+static Atom net_wm_window_type_dnd = 0;
+
+// application window state
+static Atom net_wm_state_modal = 0;
+static Atom net_wm_state_sticky = 0;
+static Atom net_wm_state_max_vert = 0;
+static Atom net_wm_state_max_horiz = 0;
+static Atom net_wm_state_shaded = 0;
+static Atom net_wm_state_skip_taskbar = 0;
+static Atom net_wm_state_skip_pager = 0;
+static Atom net_wm_state_hidden = 0;
+static Atom net_wm_state_fullscreen = 0;
+static Atom net_wm_state_above = 0;
+static Atom net_wm_state_below = 0;
+static Atom net_wm_state_demands_attention = 0;
+
+// allowed actions
+static Atom net_wm_action_move = 0;
+static Atom net_wm_action_resize = 0;
+static Atom net_wm_action_minimize = 0;
+static Atom net_wm_action_shade = 0;
+static Atom net_wm_action_stick = 0;
+static Atom net_wm_action_max_vert = 0;
+static Atom net_wm_action_max_horiz = 0;
+static Atom net_wm_action_fullscreen = 0;
+static Atom net_wm_action_change_desk = 0;
+static Atom net_wm_action_close = 0;
+
+// KDE extension that's not in the specs - Replaced by state_above now?
+static Atom net_wm_state_stays_on_top = 0;
+
+// used to determine whether application window is managed or not
+static Atom xa_wm_state = 0;
+
+static Bool netwm_atoms_created = False;
+const unsigned long netwm_sendevent_mask = (SubstructureRedirectMask|
+ SubstructureNotifyMask);
+
+
+const long MAX_PROP_SIZE = 100000;
+
+static char *nstrdup(const char *s1) {
+ if (! s1) return (char *) 0;
+
+ int l = strlen(s1) + 1;
+ char *s2 = new char[l];
+ strncpy(s2, s1, l);
+ return s2;
+}
+
+
+static char *nstrndup(const char *s1, int l) {
+ if (! s1 || l == 0) return (char *) 0;
+
+ char *s2 = new char[l+1];
+ strncpy(s2, s1, l);
+ s2[l] = '\0';
+ return s2;
+}
+
+
+static Window *nwindup(Window *w1, int n) {
+ if (! w1 || n == 0) return (Window *) 0;
+
+ Window *w2 = new Window[n];
+ while (n--) w2[n] = w1[n];
+ return w2;
+}
+
+
+static void refdec_nri(NETRootInfoPrivate *p) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NET: decrementing NETRootInfoPrivate::ref (%d)\n", p->ref - 1);
+#endif
+
+ if (! --p->ref) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NET: \tno more references, deleting\n");
+#endif
+
+ delete [] p->name;
+ delete [] p->stacking;
+ delete [] p->clients;
+ delete [] p->virtual_roots;
+ delete [] p->kde_system_tray_windows;
+
+ int i;
+ for (i = 0; i < p->desktop_names.size(); i++)
+ delete [] p->desktop_names[i];
+ }
+}
+
+
+static void refdec_nwi(NETWinInfoPrivate *p) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NET: decrementing NETWinInfoPrivate::ref (%d)\n", p->ref - 1);
+#endif
+
+ if (! --p->ref) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NET: \tno more references, deleting\n");
+#endif
+
+ delete [] p->name;
+ delete [] p->visible_name;
+ delete [] p->icon_name;
+ delete [] p->visible_icon_name;
+ delete [] p->startup_id;
+
+ int i;
+ for (i = 0; i < p->icons.size(); i++)
+ delete [] p->icons[i].data;
+ }
+}
+
+
+static int wcmp(const void *a, const void *b) {
+ return *((Window *) a) - *((Window *) b);
+}
+
+
+static const int netAtomCount = 84;
+static void create_atoms(Display *d) {
+ static const char * const names[netAtomCount] =
+ {
+ "UTF8_STRING",
+ "_NET_SUPPORTED",
+ "_NET_SUPPORTING_WM_CHECK",
+ "_NET_CLIENT_LIST",
+ "_NET_CLIENT_LIST_STACKING",
+ "_NET_NUMBER_OF_DESKTOPS",
+ "_NET_DESKTOP_GEOMETRY",
+ "_NET_DESKTOP_VIEWPORT",
+ "_NET_CURRENT_DESKTOP",
+ "_NET_DESKTOP_NAMES",
+ "_NET_ACTIVE_WINDOW",
+ "_NET_WORKAREA",
+ "_NET_VIRTUAL_ROOTS",
+ "_NET_DESKTOP_LAYOUT",
+ "_NET_SHOWING_DESKTOP",
+ "_NET_CLOSE_WINDOW",
+ "_NET_RESTACK_WINDOW",
+
+ "_NET_WM_MOVERESIZE",
+ "_NET_MOVERESIZE_WINDOW",
+ "_NET_WM_NAME",
+ "_NET_WM_VISIBLE_NAME",
+ "_NET_WM_ICON_NAME",
+ "_NET_WM_VISIBLE_ICON_NAME",
+ "_NET_WM_DESKTOP",
+ "_NET_WM_WINDOW_TYPE",
+ "_NET_WM_STATE",
+ "_NET_WM_STRUT",
+ "_NET_WM_STRUT_PARTIAL",
+ "_NET_WM_ICON_GEOMETRY",
+ "_NET_WM_ICON",
+ "_NET_WM_PID",
+ "_NET_WM_USER_TIME",
+ "_NET_WM_HANDLED_ICONS",
+ "_NET_STARTUP_ID",
+ "_NET_WM_ALLOWED_ACTIONS",
+ "_NET_WM_PING",
+ "_NET_WM_TAKE_ACTIVITY",
+ "WM_WINDOW_ROLE",
+ "_NET_FRAME_EXTENTS",
+
+ "_NET_WM_WINDOW_TYPE_NORMAL",
+ "_NET_WM_WINDOW_TYPE_DESKTOP",
+ "_NET_WM_WINDOW_TYPE_DOCK",
+ "_NET_WM_WINDOW_TYPE_TOOLBAR",
+ "_NET_WM_WINDOW_TYPE_MENU",
+ "_NET_WM_WINDOW_TYPE_DIALOG",
+ "_NET_WM_WINDOW_TYPE_UTILITY",
+ "_NET_WM_WINDOW_TYPE_SPLASH",
+ "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
+ "_NET_WM_WINDOW_TYPE_POPUP_MENU",
+ "_NET_WM_WINDOW_TYPE_TOOLTIP",
+ "_NET_WM_WINDOW_TYPE_NOTIFICATION",
+ "_NET_WM_WINDOW_TYPE_COMBOBOX",
+ "_NET_WM_WINDOW_TYPE_DND",
+
+ "_NET_WM_STATE_MODAL",
+ "_NET_WM_STATE_STICKY",
+ "_NET_WM_STATE_MAXIMIZED_VERT",
+ "_NET_WM_STATE_MAXIMIZED_HORZ",
+ "_NET_WM_STATE_SHADED",
+ "_NET_WM_STATE_SKIP_TASKBAR",
+ "_NET_WM_STATE_SKIP_PAGER",
+ "_NET_WM_STATE_HIDDEN",
+ "_NET_WM_STATE_FULLSCREEN",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_BELOW",
+ "_NET_WM_STATE_DEMANDS_ATTENTION",
+
+ "_NET_WM_ACTION_MOVE",
+ "_NET_WM_ACTION_RESIZE",
+ "_NET_WM_ACTION_MINIMIZE",
+ "_NET_WM_ACTION_SHADE",
+ "_NET_WM_ACTION_STICK",
+ "_NET_WM_ACTION_MAXIMIZE_VERT",
+ "_NET_WM_ACTION_MAXIMIZE_HORZ",
+ "_NET_WM_ACTION_FULLSCREEN",
+ "_NET_WM_ACTION_CHANGE_DESKTOP",
+ "_NET_WM_ACTION_CLOSE",
+
+ "_NET_WM_STATE_STAYS_ON_TOP",
+
+ "_KDE_NET_SYSTEM_TRAY_WINDOWS",
+ "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
+ "_KDE_NET_WM_FRAME_STRUT",
+ "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE",
+ "_KDE_NET_WM_WINDOW_TYPE_TOPMENU",
+ "_KDE_NET_WM_TEMPORARY_RULES",
+
+ "WM_STATE",
+ "WM_PROTOCOLS"
+ };
+
+ Atom atoms[netAtomCount], *atomsp[netAtomCount] =
+ {
+ &UTF8_STRING,
+ &net_supported,
+ &net_supporting_wm_check,
+ &net_client_list,
+ &net_client_list_stacking,
+ &net_number_of_desktops,
+ &net_desktop_geometry,
+ &net_desktop_viewport,
+ &net_current_desktop,
+ &net_desktop_names,
+ &net_active_window,
+ &net_workarea,
+ &net_virtual_roots,
+ &net_desktop_layout,
+ &net_showing_desktop,
+ &net_close_window,
+ &net_restack_window,
+
+ &net_wm_moveresize,
+ &net_moveresize_window,
+ &net_wm_name,
+ &net_wm_visible_name,
+ &net_wm_icon_name,
+ &net_wm_visible_icon_name,
+ &net_wm_desktop,
+ &net_wm_window_type,
+ &net_wm_state,
+ &net_wm_strut,
+ &net_wm_extended_strut,
+ &net_wm_icon_geometry,
+ &net_wm_icon,
+ &net_wm_pid,
+ &net_wm_user_time,
+ &net_wm_handled_icons,
+ &net_startup_id,
+ &net_wm_allowed_actions,
+ &net_wm_ping,
+ &net_wm_take_activity,
+ &wm_window_role,
+ &net_frame_extents,
+
+ &net_wm_window_type_normal,
+ &net_wm_window_type_desktop,
+ &net_wm_window_type_dock,
+ &net_wm_window_type_toolbar,
+ &net_wm_window_type_menu,
+ &net_wm_window_type_dialog,
+ &net_wm_window_type_utility,
+ &net_wm_window_type_splash,
+ &net_wm_window_type_dropdown_menu,
+ &net_wm_window_type_popup_menu,
+ &net_wm_window_type_tooltip,
+ &net_wm_window_type_notification,
+ &net_wm_window_type_combobox,
+ &net_wm_window_type_dnd,
+
+ &net_wm_state_modal,
+ &net_wm_state_sticky,
+ &net_wm_state_max_vert,
+ &net_wm_state_max_horiz,
+ &net_wm_state_shaded,
+ &net_wm_state_skip_taskbar,
+ &net_wm_state_skip_pager,
+ &net_wm_state_hidden,
+ &net_wm_state_fullscreen,
+ &net_wm_state_above,
+ &net_wm_state_below,
+ &net_wm_state_demands_attention,
+
+ &net_wm_action_move,
+ &net_wm_action_resize,
+ &net_wm_action_minimize,
+ &net_wm_action_shade,
+ &net_wm_action_stick,
+ &net_wm_action_max_vert,
+ &net_wm_action_max_horiz,
+ &net_wm_action_fullscreen,
+ &net_wm_action_change_desk,
+ &net_wm_action_close,
+
+ &net_wm_state_stays_on_top,
+
+ &kde_net_system_tray_windows,
+ &kde_net_wm_system_tray_window_for,
+ &kde_net_wm_frame_strut,
+ &kde_net_wm_window_type_override,
+ &kde_net_wm_window_type_topmenu,
+ &kde_net_wm_temporary_rules,
+
+ &xa_wm_state,
+ &wm_protocols
+ };
+
+ assert( !netwm_atoms_created );
+
+ int i = netAtomCount;
+ while (i--)
+ atoms[i] = 0;
+
+ XInternAtoms(d, (char **) names, netAtomCount, False, atoms);
+
+ i = netAtomCount;
+ while (i--)
+ *atomsp[i] = atoms[i];
+
+ netwm_atoms_created = True;
+}
+
+
+static void readIcon(Display* display, Window window, Atom property, NETRArray<NETIcon>& icons, int& icon_count) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NET: readIcon\n");
+#endif
+
+ Atom type_ret;
+ int format_ret;
+ unsigned long nitems_ret = 0, after_ret = 0;
+ unsigned char *data_ret = 0;
+
+ // reset
+ for (int i = 0; i < icons.size(); i++)
+ delete [] icons[i].data;
+ icons.reset();
+ icon_count = 0;
+
+ // allocate buffers
+ unsigned char *buffer = 0;
+ unsigned long offset = 0;
+ unsigned long buffer_offset = 0;
+ unsigned long bufsize = 0;
+
+ // read data
+ do {
+ if (XGetWindowProperty(display, window, property, offset,
+ MAX_PROP_SIZE, False, XA_CARDINAL, &type_ret,
+ &format_ret, &nitems_ret, &after_ret, &data_ret)
+ == Success) {
+ if (!bufsize)
+ {
+ if (nitems_ret < 3 || type_ret != XA_CARDINAL ||
+ format_ret != 32) {
+ // either we didn't get the property, or the property has less than
+ // 3 elements in it
+ // NOTE: 3 is the ABSOLUTE minimum:
+ // width = 1, height = 1, length(data) = 1 (width * height)
+ if ( data_ret )
+ XFree(data_ret);
+ return;
+ }
+
+ bufsize = nitems_ret * sizeof(long) + after_ret;
+ buffer = (unsigned char *) malloc(bufsize);
+ }
+ else if (buffer_offset + nitems_ret*sizeof(long) > bufsize)
+ {
+fprintf(stderr, "NETWM: Warning readIcon() needs buffer adjustment!\n");
+ bufsize = buffer_offset + nitems_ret * sizeof(long) + after_ret;
+ buffer = (unsigned char *) realloc(buffer, bufsize);
+ }
+ memcpy((buffer + buffer_offset), data_ret, nitems_ret * sizeof(long));
+ buffer_offset += nitems_ret * sizeof(long);
+ offset += nitems_ret;
+
+ if ( data_ret )
+ XFree(data_ret);
+ } else {
+ if (buffer)
+ free(buffer);
+ return; // Some error occurred cq. property didn't exist.
+ }
+ }
+ while (after_ret > 0);
+
+ CARD32 *data32;
+ unsigned long i, j, k, sz, s;
+ unsigned long *d = (unsigned long *) buffer;
+ for (i = 0, j = 0; i < bufsize;) {
+ icons[j].size.width = *d++;
+ i += sizeof(long);
+ icons[j].size.height = *d++;
+ i += sizeof(long);
+
+ sz = icons[j].size.width * icons[j].size.height;
+ s = sz * sizeof(long);
+
+ if ( i + s - 1 > bufsize || sz == 0 || sz > 1024 * 1024 ) {
+ break;
+ }
+
+ delete [] icons[j].data;
+ data32 = new CARD32[sz];
+ icons[j].data = (unsigned char *) data32;
+ for (k = 0; k < sz; k++, i += sizeof(long)) {
+ *data32++ = (CARD32) *d++;
+ }
+ j++;
+ icon_count++;
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NET: readIcon got %d icons\n", icon_count);
+#endif
+
+ free(buffer);
+}
+
+
+template <class Z>
+NETRArray<Z>::NETRArray()
+ : sz(0), capacity(2)
+{
+ d = (Z*) calloc(capacity, sizeof(Z)); // allocate 2 elts and set to zero
+}
+
+
+template <class Z>
+NETRArray<Z>::~NETRArray() {
+ free(d);
+}
+
+
+template <class Z>
+void NETRArray<Z>::reset() {
+ sz = 0;
+ capacity = 2;
+ d = (Z*) realloc(d, sizeof(Z)*capacity);
+ memset( (void*) d, 0, sizeof(Z)*capacity );
+}
+
+template <class Z>
+Z &NETRArray<Z>::operator[](int index) {
+ if (index >= capacity) {
+ // allocate space for the new data
+ // open table has amortized O(1) access time
+ // when N elements appended consecutively -- exa
+ int newcapacity = 2*capacity > index+1 ? 2*capacity : index+1; // max
+ // copy into new larger memory block using realloc
+ d = (Z*) realloc(d, sizeof(Z)*newcapacity);
+ memset( (void*) &d[capacity], 0, sizeof(Z)*(newcapacity-capacity) );
+ capacity = newcapacity;
+ }
+ if (index >= sz) // at this point capacity>index
+ sz = index + 1;
+
+ return d[index];
+}
+
+
+// Construct a new NETRootInfo object.
+
+NETRootInfo::NETRootInfo(Display *display, Window supportWindow, const char *wmName,
+ const unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::NETRootInfo: using window manager constructor\n");
+#endif
+
+ p = new NETRootInfoPrivate;
+ p->ref = 1;
+
+ p->display = display;
+ p->name = nstrdup(wmName);
+
+ if (screen != -1) {
+ p->screen = screen;
+ } else {
+ p->screen = DefaultScreen(p->display);
+ }
+
+ p->root = RootWindow(p->display, p->screen);
+ p->supportwindow = supportWindow;
+ p->number_of_desktops = p->current_desktop = 0;
+ p->active = None;
+ p->clients = p->stacking = p->virtual_roots = (Window *) 0;
+ p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
+ p->kde_system_tray_windows = 0;
+ p->kde_system_tray_windows_count = 0;
+ p->showing_desktop = false;
+ p->desktop_layout_orientation = OrientationHorizontal;
+ p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
+ p->desktop_layout_columns = p->desktop_layout_rows = 0;
+ setDefaultProperties();
+ if( properties_size > PROPERTIES_SIZE ) {
+ fprintf( stderr, "NETRootInfo::NETRootInfo(): properties array too large\n");
+ properties_size = PROPERTIES_SIZE;
+ }
+ for( int i = 0; i < properties_size; ++i )
+ p->properties[ i ] = properties[ i ];
+ // force support for Supported and SupportingWMCheck for window managers
+ p->properties[ PROTOCOLS ] |= ( Supported | SupportingWMCheck );
+ p->client_properties[ PROTOCOLS ] = DesktopNames // the only thing that can be changed by clients
+ | WMPing; // or they can reply to this
+ p->client_properties[ PROTOCOLS2 ] = WM2TakeActivity | WM2DesktopLayout;
+
+ role = WindowManager;
+
+ if (! netwm_atoms_created) create_atoms(p->display);
+
+ if (doActivate) activate();
+}
+
+NETRootInfo::NETRootInfo(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties, int screen, bool doActivate)
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::NETRootInfo: using window manager constructor\n");
+#endif
+
+ p = new NETRootInfoPrivate;
+ p->ref = 1;
+
+ p->display = display;
+ p->name = nstrdup(wmName);
+
+ if (screen != -1) {
+ p->screen = screen;
+ } else {
+ p->screen = DefaultScreen(p->display);
+ }
+
+ p->root = RootWindow(p->display, p->screen);
+ p->supportwindow = supportWindow;
+ p->number_of_desktops = p->current_desktop = 0;
+ p->active = None;
+ p->clients = p->stacking = p->virtual_roots = (Window *) 0;
+ p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
+ p->kde_system_tray_windows = 0;
+ p->kde_system_tray_windows_count = 0;
+ p->showing_desktop = false;
+ setDefaultProperties();
+ p->properties[ PROTOCOLS ] = properties;
+ // force support for Supported and SupportingWMCheck for window managers
+ p->properties[ PROTOCOLS ] |= ( Supported | SupportingWMCheck );
+ p->client_properties[ PROTOCOLS ] = DesktopNames // the only thing that can be changed by clients
+ | WMPing; // or they can reply to this
+ p->client_properties[ PROTOCOLS2 ] = WM2TakeActivity;
+
+ role = WindowManager;
+
+ if (! netwm_atoms_created) create_atoms(p->display);
+
+ if (doActivate) activate();
+}
+
+
+NETRootInfo::NETRootInfo(Display *display, const unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::NETRootInfo: using Client constructor\n");
+#endif
+
+ p = new NETRootInfoPrivate;
+ p->ref = 1;
+
+ p->name = 0;
+
+ p->display = display;
+
+ if (screen != -1) {
+ p->screen = screen;
+ } else {
+ p->screen = DefaultScreen(p->display);
+ }
+
+ p->root = RootWindow(p->display, p->screen);
+ p->rootSize.width = WidthOfScreen(ScreenOfDisplay(p->display, p->screen));
+ p->rootSize.height = HeightOfScreen(ScreenOfDisplay(p->display, p->screen));
+
+ p->supportwindow = None;
+ p->number_of_desktops = p->current_desktop = 0;
+ p->active = None;
+ p->clients = p->stacking = p->virtual_roots = (Window *) 0;
+ p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
+ p->kde_system_tray_windows = 0;
+ p->kde_system_tray_windows_count = 0;
+ p->showing_desktop = false;
+ p->desktop_layout_orientation = OrientationHorizontal;
+ p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
+ p->desktop_layout_columns = p->desktop_layout_rows = 0;
+ setDefaultProperties();
+ if( properties_size > 2 ) {
+ fprintf( stderr, "NETWinInfo::NETWinInfo(): properties array too large\n");
+ properties_size = 2;
+ }
+ for( int i = 0; i < properties_size; ++i )
+ // remap from [0]=NET::Property,[1]=NET::Property2
+ switch( i ) {
+ case 0:
+ p->client_properties[ PROTOCOLS ] = properties[ i ];
+ break;
+ case 1:
+ p->client_properties[ PROTOCOLS2 ] = properties[ i ];
+ break;
+ }
+ for( int i = 0; i < PROPERTIES_SIZE; ++i )
+ p->properties[ i ] = 0;
+
+ role = Client;
+
+ if (! netwm_atoms_created) create_atoms(p->display);
+
+ if (doActivate) activate();
+}
+
+NETRootInfo::NETRootInfo(Display *display, unsigned long properties, int screen,
+ bool doActivate)
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::NETRootInfo: using Client constructor\n");
+#endif
+
+ p = new NETRootInfoPrivate;
+ p->ref = 1;
+
+ p->name = 0;
+
+ p->display = display;
+
+ if (screen != -1) {
+ p->screen = screen;
+ } else {
+ p->screen = DefaultScreen(p->display);
+ }
+
+ p->root = RootWindow(p->display, p->screen);
+ p->rootSize.width = WidthOfScreen(ScreenOfDisplay(p->display, p->screen));
+ p->rootSize.height = HeightOfScreen(ScreenOfDisplay(p->display, p->screen));
+
+ p->supportwindow = None;
+ p->number_of_desktops = p->current_desktop = 0;
+ p->active = None;
+ p->clients = p->stacking = p->virtual_roots = (Window *) 0;
+ p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
+ p->kde_system_tray_windows = 0;
+ p->kde_system_tray_windows_count = 0;
+ p->showing_desktop = false;
+ p->desktop_layout_orientation = OrientationHorizontal;
+ p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
+ p->desktop_layout_columns = p->desktop_layout_rows = 0;
+ setDefaultProperties();
+ p->client_properties[ PROTOCOLS ] = properties;
+ for( int i = 0; i < PROPERTIES_SIZE; ++i )
+ p->properties[ i ] = 0;
+
+ role = Client;
+
+ if (! netwm_atoms_created) create_atoms(p->display);
+
+ if (doActivate) activate();
+}
+
+
+NETRootInfo2::NETRootInfo2(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+ : NETRootInfo( display, supportWindow, wmName, properties, properties_size,
+ screen, doActivate )
+{
+}
+
+NETRootInfo2::NETRootInfo2(Display *display, const unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+ : NETRootInfo( display, properties, properties_size, screen, doActivate )
+{
+}
+
+NETRootInfo3::NETRootInfo3(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+ : NETRootInfo2( display, supportWindow, wmName, properties, properties_size,
+ screen, doActivate )
+{
+}
+
+NETRootInfo3::NETRootInfo3(Display *display, const unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+ : NETRootInfo2( display, properties, properties_size, screen, doActivate )
+{
+}
+
+NETRootInfo4::NETRootInfo4(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+ : NETRootInfo3( display, supportWindow, wmName, properties, properties_size,
+ screen, doActivate )
+{
+}
+
+NETRootInfo4::NETRootInfo4(Display *display, const unsigned long properties[], int properties_size,
+ int screen, bool doActivate)
+ : NETRootInfo3( display, properties, properties_size, screen, doActivate )
+{
+}
+
+// Copy an existing NETRootInfo object.
+
+NETRootInfo::NETRootInfo(const NETRootInfo &rootinfo) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::NETRootInfo: using copy constructor\n");
+#endif
+
+ p = rootinfo.p;
+ role = rootinfo.role;
+
+ p->ref++;
+}
+
+
+// Be gone with our NETRootInfo.
+
+NETRootInfo::~NETRootInfo() {
+ refdec_nri(p);
+
+ if (! p->ref) delete p;
+}
+
+
+void NETRootInfo::setDefaultProperties()
+{
+ p->properties[ PROTOCOLS ] = Supported | SupportingWMCheck;
+ p->properties[ WINDOW_TYPES ] = NormalMask | DesktopMask | DockMask
+ | ToolbarMask | MenuMask | DialogMask;
+ p->properties[ STATES ] = Modal | Sticky | MaxVert | MaxHoriz | Shaded
+ | SkipTaskbar | StaysOnTop;
+ p->properties[ PROTOCOLS2 ] = 0;
+ p->properties[ ACTIONS ] = 0;
+ p->client_properties[ PROTOCOLS ] = 0;
+ p->client_properties[ WINDOW_TYPES ] = 0; // these two actually don't
+ p->client_properties[ STATES ] = 0; // make sense in client_properties
+ p->client_properties[ PROTOCOLS2 ] = 0;
+ p->client_properties[ ACTIONS ] = 0;
+}
+
+void NETRootInfo::activate() {
+ if (role == WindowManager) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::activate: setting supported properties on root\n");
+#endif
+
+ setSupported();
+ update(p->client_properties);
+ } else {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::activate: updating client information\n");
+#endif
+
+ update(p->client_properties);
+ }
+}
+
+
+void NETRootInfo::setClientList(Window *windows, unsigned int count) {
+ if (role != WindowManager) return;
+
+ p->clients_count = count;
+
+ delete [] p->clients;
+ p->clients = nwindup(windows, count);
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setClientList: setting list with %ld windows\n",
+ p->clients_count);
+#endif
+
+ XChangeProperty(p->display, p->root, net_client_list, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)p->clients,
+ p->clients_count);
+}
+
+
+void NETRootInfo::setClientListStacking(Window *windows, unsigned int count) {
+ if (role != WindowManager) return;
+
+ p->stacking_count = count;
+ delete [] p->stacking;
+ p->stacking = nwindup(windows, count);
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::setClientListStacking: setting list with %ld windows\n",
+ p->clients_count);
+#endif
+
+ XChangeProperty(p->display, p->root, net_client_list_stacking, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) p->stacking,
+ p->stacking_count);
+}
+
+
+void NETRootInfo::setKDESystemTrayWindows(Window *windows, unsigned int count) {
+ if (role != WindowManager) return;
+
+ p->kde_system_tray_windows_count = count;
+ delete [] p->kde_system_tray_windows;
+ p->kde_system_tray_windows = nwindup(windows, count);
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::setKDESystemTrayWindows: setting list with %ld windows\n",
+ p->kde_system_tray_windows_count);
+#endif
+
+ XChangeProperty(p->display, p->root, kde_net_system_tray_windows, XA_WINDOW, 32,
+ PropModeReplace,
+ (unsigned char *) p->kde_system_tray_windows,
+ p->kde_system_tray_windows_count);
+}
+
+
+void NETRootInfo::setNumberOfDesktops(int numberOfDesktops) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::setNumberOfDesktops: setting desktop count to %d (%s)\n",
+ numberOfDesktops, (role == WindowManager) ? "WM" : "Client");
+#endif
+
+ if (role == WindowManager) {
+ p->number_of_desktops = numberOfDesktops;
+ long d = numberOfDesktops;
+ XChangeProperty(p->display, p->root, net_number_of_desktops, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &d, 1);
+ } else {
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_number_of_desktops;
+ e.xclient.display = p->display;
+ e.xclient.window = p->root;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = numberOfDesktops;
+ e.xclient.data.l[1] = 0l;
+ e.xclient.data.l[2] = 0l;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+}
+
+
+void NETRootInfo::setCurrentDesktop(int desktop) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::setCurrentDesktop: setting current desktop = %d (%s)\n",
+ desktop, (role == WindowManager) ? "WM" : "Client");
+#endif
+
+ if (role == WindowManager) {
+ p->current_desktop = desktop;
+ long d = p->current_desktop - 1;
+ XChangeProperty(p->display, p->root, net_current_desktop, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &d, 1);
+ } else {
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_current_desktop;
+ e.xclient.display = p->display;
+ e.xclient.window = p->root;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = desktop - 1;
+ e.xclient.data.l[1] = 0l;
+ e.xclient.data.l[2] = 0l;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+}
+
+
+void NETRootInfo::setDesktopName(int desktop, const char *desktopName) {
+ // allow setting desktop names even for non-existant desktops, see the spec, sect.3.7.
+ if (desktop < 1) return;
+
+ delete [] p->desktop_names[desktop - 1];
+ p->desktop_names[desktop - 1] = nstrdup(desktopName);
+
+ unsigned int i, proplen,
+ num = ((p->number_of_desktops > p->desktop_names.size()) ?
+ p->number_of_desktops : p->desktop_names.size());
+ for (i = 0, proplen = 0; i < num; i++)
+ proplen += (p->desktop_names[i] != 0 ? strlen(p->desktop_names[i])+1 : 1 );
+
+ char *prop = new char[proplen], *propp = prop;
+
+ for (i = 0; i < num; i++)
+ if (p->desktop_names[i]) {
+ strcpy(propp, p->desktop_names[i]);
+ propp += strlen(p->desktop_names[i]) + 1;
+ } else
+ *propp++ = '\0';
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::setDesktopName(%d, '%s')\n"
+ "NETRootInfo::setDesktopName: total property length = %d",
+ desktop, desktopName, proplen);
+#endif
+
+ XChangeProperty(p->display, p->root, net_desktop_names, UTF8_STRING, 8,
+ PropModeReplace, (unsigned char *) prop, proplen);
+
+ delete [] prop;
+}
+
+
+void NETRootInfo::setDesktopGeometry(int , const NETSize &geometry) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setDesktopGeometry( -- , { %d, %d }) (%s)\n",
+ geometry.width, geometry.height, (role == WindowManager) ? "WM" : "Client");
+#endif
+
+ if (role == WindowManager) {
+ p->geometry = geometry;
+
+ long data[2];
+ data[0] = p->geometry.width;
+ data[1] = p->geometry.height;
+
+ XChangeProperty(p->display, p->root, net_desktop_geometry, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) data, 2);
+ } else {
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_desktop_geometry;
+ e.xclient.display = p->display;
+ e.xclient.window = p->root;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = geometry.width;
+ e.xclient.data.l[1] = geometry.height;
+ e.xclient.data.l[2] = 0l;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+}
+
+
+void NETRootInfo::setDesktopViewport(int desktop, const NETPoint &viewport) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setDesktopViewport(%d, { %d, %d }) (%s)\n",
+ desktop, viewport.x, viewport.y, (role == WindowManager) ? "WM" : "Client");
+#endif
+
+ if (desktop < 1) return;
+
+ if (role == WindowManager) {
+ p->viewport[desktop - 1] = viewport;
+
+ int d, i, l;
+ l = p->number_of_desktops * 2;
+ long *data = new long[l];
+ for (d = 0, i = 0; d < p->number_of_desktops; d++) {
+ data[i++] = p->viewport[d].x;
+ data[i++] = p->viewport[d].y;
+ }
+
+ XChangeProperty(p->display, p->root, net_desktop_viewport, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) data, l);
+
+ delete [] data;
+ } else {
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_desktop_viewport;
+ e.xclient.display = p->display;
+ e.xclient.window = p->root;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = viewport.x;
+ e.xclient.data.l[1] = viewport.y;
+ e.xclient.data.l[2] = 0l;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+}
+
+
+void NETRootInfo::setSupported() {
+ if (role != WindowManager) {
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setSupported - role != WindowManager\n");
+#endif
+
+ return;
+ }
+
+ Atom atoms[netAtomCount];
+ int pnum = 2;
+
+ // Root window properties/messages
+ atoms[0] = net_supported;
+ atoms[1] = net_supporting_wm_check;
+
+ if (p->properties[ PROTOCOLS ] & ClientList)
+ atoms[pnum++] = net_client_list;
+
+ if (p->properties[ PROTOCOLS ] & ClientListStacking)
+ atoms[pnum++] = net_client_list_stacking;
+
+ if (p->properties[ PROTOCOLS ] & NumberOfDesktops)
+ atoms[pnum++] = net_number_of_desktops;
+
+ if (p->properties[ PROTOCOLS ] & DesktopGeometry)
+ atoms[pnum++] = net_desktop_geometry;
+
+ if (p->properties[ PROTOCOLS ] & DesktopViewport)
+ atoms[pnum++] = net_desktop_viewport;
+
+ if (p->properties[ PROTOCOLS ] & CurrentDesktop)
+ atoms[pnum++] = net_current_desktop;
+
+ if (p->properties[ PROTOCOLS ] & DesktopNames)
+ atoms[pnum++] = net_desktop_names;
+
+ if (p->properties[ PROTOCOLS ] & ActiveWindow)
+ atoms[pnum++] = net_active_window;
+
+ if (p->properties[ PROTOCOLS ] & WorkArea)
+ atoms[pnum++] = net_workarea;
+
+ if (p->properties[ PROTOCOLS ] & VirtualRoots)
+ atoms[pnum++] = net_virtual_roots;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2DesktopLayout)
+ atoms[pnum++] = net_desktop_layout;
+
+ if (p->properties[ PROTOCOLS ] & CloseWindow)
+ atoms[pnum++] = net_close_window;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2RestackWindow)
+ atoms[pnum++] = net_restack_window;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2ShowingDesktop)
+ atoms[pnum++] = net_showing_desktop;
+
+ // Application window properties/messages
+ if (p->properties[ PROTOCOLS ] & WMMoveResize)
+ atoms[pnum++] = net_wm_moveresize;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2MoveResizeWindow)
+ atoms[pnum++] = net_moveresize_window;
+
+ if (p->properties[ PROTOCOLS ] & WMName)
+ atoms[pnum++] = net_wm_name;
+
+ if (p->properties[ PROTOCOLS ] & WMVisibleName)
+ atoms[pnum++] = net_wm_visible_name;
+
+ if (p->properties[ PROTOCOLS ] & WMIconName)
+ atoms[pnum++] = net_wm_icon_name;
+
+ if (p->properties[ PROTOCOLS ] & WMVisibleIconName)
+ atoms[pnum++] = net_wm_visible_icon_name;
+
+ if (p->properties[ PROTOCOLS ] & WMDesktop)
+ atoms[pnum++] = net_wm_desktop;
+
+ if (p->properties[ PROTOCOLS ] & WMWindowType) {
+ atoms[pnum++] = net_wm_window_type;
+
+ // Application window types
+ if (p->properties[ WINDOW_TYPES ] & NormalMask)
+ atoms[pnum++] = net_wm_window_type_normal;
+ if (p->properties[ WINDOW_TYPES ] & DesktopMask)
+ atoms[pnum++] = net_wm_window_type_desktop;
+ if (p->properties[ WINDOW_TYPES ] & DockMask)
+ atoms[pnum++] = net_wm_window_type_dock;
+ if (p->properties[ WINDOW_TYPES ] & ToolbarMask)
+ atoms[pnum++] = net_wm_window_type_toolbar;
+ if (p->properties[ WINDOW_TYPES ] & MenuMask)
+ atoms[pnum++] = net_wm_window_type_menu;
+ if (p->properties[ WINDOW_TYPES ] & DialogMask)
+ atoms[pnum++] = net_wm_window_type_dialog;
+ if (p->properties[ WINDOW_TYPES ] & UtilityMask)
+ atoms[pnum++] = net_wm_window_type_utility;
+ if (p->properties[ WINDOW_TYPES ] & SplashMask)
+ atoms[pnum++] = net_wm_window_type_splash;
+ if (p->properties[ WINDOW_TYPES ] & DropdownMenuMask)
+ atoms[pnum++] = net_wm_window_type_dropdown_menu;
+ if (p->properties[ WINDOW_TYPES ] & PopupMenuMask)
+ atoms[pnum++] = net_wm_window_type_popup_menu;
+ if (p->properties[ WINDOW_TYPES ] & TooltipMask)
+ atoms[pnum++] = net_wm_window_type_tooltip;
+ if (p->properties[ WINDOW_TYPES ] & NotificationMask)
+ atoms[pnum++] = net_wm_window_type_notification;
+ if (p->properties[ WINDOW_TYPES ] & ComboBoxMask)
+ atoms[pnum++] = net_wm_window_type_combobox;
+ if (p->properties[ WINDOW_TYPES ] & DNDIconMask)
+ atoms[pnum++] = net_wm_window_type_dnd;
+ // KDE extensions
+ if (p->properties[ WINDOW_TYPES ] & OverrideMask)
+ atoms[pnum++] = kde_net_wm_window_type_override;
+ if (p->properties[ WINDOW_TYPES ] & TopMenuMask)
+ atoms[pnum++] = kde_net_wm_window_type_topmenu;
+ }
+
+ if (p->properties[ PROTOCOLS ] & WMState) {
+ atoms[pnum++] = net_wm_state;
+
+ // Application window states
+ if (p->properties[ STATES ] & Modal)
+ atoms[pnum++] = net_wm_state_modal;
+ if (p->properties[ STATES ] & Sticky)
+ atoms[pnum++] = net_wm_state_sticky;
+ if (p->properties[ STATES ] & MaxVert)
+ atoms[pnum++] = net_wm_state_max_vert;
+ if (p->properties[ STATES ] & MaxHoriz)
+ atoms[pnum++] = net_wm_state_max_horiz;
+ if (p->properties[ STATES ] & Shaded)
+ atoms[pnum++] = net_wm_state_shaded;
+ if (p->properties[ STATES ] & SkipTaskbar)
+ atoms[pnum++] = net_wm_state_skip_taskbar;
+ if (p->properties[ STATES ] & SkipPager)
+ atoms[pnum++] = net_wm_state_skip_pager;
+ if (p->properties[ STATES ] & Hidden)
+ atoms[pnum++] = net_wm_state_hidden;
+ if (p->properties[ STATES ] & FullScreen)
+ atoms[pnum++] = net_wm_state_fullscreen;
+ if (p->properties[ STATES ] & KeepAbove)
+ atoms[pnum++] = net_wm_state_above;
+ if (p->properties[ STATES ] & KeepBelow)
+ atoms[pnum++] = net_wm_state_below;
+ if (p->properties[ STATES ] & DemandsAttention)
+ atoms[pnum++] = net_wm_state_demands_attention;
+
+ if (p->properties[ STATES ] & StaysOnTop)
+ atoms[pnum++] = net_wm_state_stays_on_top;
+ }
+
+ if (p->properties[ PROTOCOLS ] & WMStrut)
+ atoms[pnum++] = net_wm_strut;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2ExtendedStrut)
+ atoms[pnum++] = net_wm_extended_strut;
+
+ if (p->properties[ PROTOCOLS ] & WMIconGeometry)
+ atoms[pnum++] = net_wm_icon_geometry;
+
+ if (p->properties[ PROTOCOLS ] & WMIcon)
+ atoms[pnum++] = net_wm_icon;
+
+ if (p->properties[ PROTOCOLS ] & WMPid)
+ atoms[pnum++] = net_wm_pid;
+
+ if (p->properties[ PROTOCOLS ] & WMHandledIcons)
+ atoms[pnum++] = net_wm_handled_icons;
+
+ if (p->properties[ PROTOCOLS ] & WMPing)
+ atoms[pnum++] = net_wm_ping;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2TakeActivity)
+ atoms[pnum++] = net_wm_take_activity;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2UserTime)
+ atoms[pnum++] = net_wm_user_time;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2StartupId)
+ atoms[pnum++] = net_startup_id;
+
+ if (p->properties[ PROTOCOLS2 ] & WM2AllowedActions) {
+ atoms[pnum++] = net_wm_allowed_actions;
+
+ // Actions
+ if (p->properties[ ACTIONS ] & ActionMove)
+ atoms[pnum++] = net_wm_action_move;
+ if (p->properties[ ACTIONS ] & ActionResize)
+ atoms[pnum++] = net_wm_action_resize;
+ if (p->properties[ ACTIONS ] & ActionMinimize)
+ atoms[pnum++] = net_wm_action_minimize;
+ if (p->properties[ ACTIONS ] & ActionShade)
+ atoms[pnum++] = net_wm_action_shade;
+ if (p->properties[ ACTIONS ] & ActionStick)
+ atoms[pnum++] = net_wm_action_stick;
+ if (p->properties[ ACTIONS ] & ActionMaxVert)
+ atoms[pnum++] = net_wm_action_max_vert;
+ if (p->properties[ ACTIONS ] & ActionMaxHoriz)
+ atoms[pnum++] = net_wm_action_max_horiz;
+ if (p->properties[ ACTIONS ] & ActionFullScreen)
+ atoms[pnum++] = net_wm_action_fullscreen;
+ if (p->properties[ ACTIONS ] & ActionChangeDesktop)
+ atoms[pnum++] = net_wm_action_change_desk;
+ if (p->properties[ ACTIONS ] & ActionClose)
+ atoms[pnum++] = net_wm_action_close;
+ }
+
+ // KDE specific extensions
+ if (p->properties[ PROTOCOLS ] & KDESystemTrayWindows)
+ atoms[pnum++] = kde_net_system_tray_windows;
+
+ if (p->properties[ PROTOCOLS ] & WMKDESystemTrayWinFor)
+ atoms[pnum++] = kde_net_wm_system_tray_window_for;
+
+ if (p->properties[ PROTOCOLS ] & WMFrameExtents) {
+ atoms[pnum++] = net_frame_extents;
+ atoms[pnum++] = kde_net_wm_frame_strut;
+ }
+
+ if (p->properties[ PROTOCOLS2 ] & WM2KDETemporaryRules)
+ atoms[pnum++] = kde_net_wm_temporary_rules;
+
+ XChangeProperty(p->display, p->root, net_supported, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) atoms, pnum);
+ XChangeProperty(p->display, p->root, net_supporting_wm_check, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &(p->supportwindow), 1);
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::setSupported: _NET_SUPPORTING_WM_CHECK = 0x%lx on 0x%lx\n"
+ " : _NET_WM_NAME = '%s' on 0x%lx\n",
+ p->supportwindow, p->supportwindow, p->name, p->supportwindow);
+#endif
+
+ XChangeProperty(p->display, p->supportwindow, net_supporting_wm_check,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(p->supportwindow), 1);
+ XChangeProperty(p->display, p->supportwindow, net_wm_name, UTF8_STRING, 8,
+ PropModeReplace, (unsigned char *) p->name,
+ strlen(p->name));
+}
+
+void NETRootInfo::updateSupportedProperties( Atom atom )
+{
+ if( atom == net_supported )
+ p->properties[ PROTOCOLS ] |= Supported;
+
+ else if( atom == net_supporting_wm_check )
+ p->properties[ PROTOCOLS ] |= SupportingWMCheck;
+
+ else if( atom == net_client_list )
+ p->properties[ PROTOCOLS ] |= ClientList;
+
+ else if( atom == net_client_list_stacking )
+ p->properties[ PROTOCOLS ] |= ClientListStacking;
+
+ else if( atom == net_number_of_desktops )
+ p->properties[ PROTOCOLS ] |= NumberOfDesktops;
+
+ else if( atom == net_desktop_geometry )
+ p->properties[ PROTOCOLS ] |= DesktopGeometry;
+
+ else if( atom == net_desktop_viewport )
+ p->properties[ PROTOCOLS ] |= DesktopViewport;
+
+ else if( atom == net_current_desktop )
+ p->properties[ PROTOCOLS ] |= CurrentDesktop;
+
+ else if( atom == net_desktop_names )
+ p->properties[ PROTOCOLS ] |= DesktopNames;
+
+ else if( atom == net_active_window )
+ p->properties[ PROTOCOLS ] |= ActiveWindow;
+
+ else if( atom == net_workarea )
+ p->properties[ PROTOCOLS ] |= WorkArea;
+
+ else if( atom == net_virtual_roots )
+ p->properties[ PROTOCOLS ] |= VirtualRoots;
+
+ else if( atom == net_desktop_layout )
+ p->properties[ PROTOCOLS2 ] |= WM2DesktopLayout;
+
+ else if( atom == net_close_window )
+ p->properties[ PROTOCOLS ] |= CloseWindow;
+
+ else if( atom == net_restack_window )
+ p->properties[ PROTOCOLS2 ] |= WM2RestackWindow;
+
+ else if( atom == net_showing_desktop )
+ p->properties[ PROTOCOLS2 ] |= WM2ShowingDesktop;
+
+ // Application window properties/messages
+ else if( atom == net_wm_moveresize )
+ p->properties[ PROTOCOLS ] |= WMMoveResize;
+
+ else if( atom == net_moveresize_window )
+ p->properties[ PROTOCOLS2 ] |= WM2MoveResizeWindow;
+
+ else if( atom == net_wm_name )
+ p->properties[ PROTOCOLS ] |= WMName;
+
+ else if( atom == net_wm_visible_name )
+ p->properties[ PROTOCOLS ] |= WMVisibleName;
+
+ else if( atom == net_wm_icon_name )
+ p->properties[ PROTOCOLS ] |= WMIconName;
+
+ else if( atom == net_wm_visible_icon_name )
+ p->properties[ PROTOCOLS ] |= WMVisibleIconName;
+
+ else if( atom == net_wm_desktop )
+ p->properties[ PROTOCOLS ] |= WMDesktop;
+
+ else if( atom == net_wm_window_type )
+ p->properties[ PROTOCOLS ] |= WMWindowType;
+
+ // Application window types
+ else if( atom == net_wm_window_type_normal )
+ p->properties[ WINDOW_TYPES ] |= NormalMask;
+ else if( atom == net_wm_window_type_desktop )
+ p->properties[ WINDOW_TYPES ] |= DesktopMask;
+ else if( atom == net_wm_window_type_dock )
+ p->properties[ WINDOW_TYPES ] |= DockMask;
+ else if( atom == net_wm_window_type_toolbar )
+ p->properties[ WINDOW_TYPES ] |= ToolbarMask;
+ else if( atom == net_wm_window_type_menu )
+ p->properties[ WINDOW_TYPES ] |= MenuMask;
+ else if( atom == net_wm_window_type_dialog )
+ p->properties[ WINDOW_TYPES ] |= DialogMask;
+ else if( atom == net_wm_window_type_utility )
+ p->properties[ WINDOW_TYPES ] |= UtilityMask;
+ else if( atom == net_wm_window_type_splash )
+ p->properties[ WINDOW_TYPES ] |= SplashMask;
+ else if( atom == net_wm_window_type_dropdown_menu )
+ p->properties[ WINDOW_TYPES ] |= DropdownMenuMask;
+ else if( atom == net_wm_window_type_popup_menu )
+ p->properties[ WINDOW_TYPES ] |= PopupMenuMask;
+ else if( atom == net_wm_window_type_tooltip )
+ p->properties[ WINDOW_TYPES ] |= TooltipMask;
+ else if( atom == net_wm_window_type_notification )
+ p->properties[ WINDOW_TYPES ] |= NotificationMask;
+ else if( atom == net_wm_window_type_combobox )
+ p->properties[ WINDOW_TYPES ] |= ComboBoxMask;
+ else if( atom == net_wm_window_type_dnd )
+ p->properties[ WINDOW_TYPES ] |= DNDIconMask;
+ // KDE extensions
+ else if( atom == kde_net_wm_window_type_override )
+ p->properties[ WINDOW_TYPES ] |= OverrideMask;
+ else if( atom == kde_net_wm_window_type_topmenu )
+ p->properties[ WINDOW_TYPES ] |= TopMenuMask;
+
+ else if( atom == net_wm_state )
+ p->properties[ PROTOCOLS ] |= WMState;
+
+ // Application window states
+ else if( atom == net_wm_state_modal )
+ p->properties[ STATES ] |= Modal;
+ else if( atom == net_wm_state_sticky )
+ p->properties[ STATES ] |= Sticky;
+ else if( atom == net_wm_state_max_vert )
+ p->properties[ STATES ] |= MaxVert;
+ else if( atom == net_wm_state_max_horiz )
+ p->properties[ STATES ] |= MaxHoriz;
+ else if( atom == net_wm_state_shaded )
+ p->properties[ STATES ] |= Shaded;
+ else if( atom == net_wm_state_skip_taskbar )
+ p->properties[ STATES ] |= SkipTaskbar;
+ else if( atom == net_wm_state_skip_pager )
+ p->properties[ STATES ] |= SkipPager;
+ else if( atom == net_wm_state_hidden )
+ p->properties[ STATES ] |= Hidden;
+ else if( atom == net_wm_state_fullscreen )
+ p->properties[ STATES ] |= FullScreen;
+ else if( atom == net_wm_state_above )
+ p->properties[ STATES ] |= KeepAbove;
+ else if( atom == net_wm_state_below )
+ p->properties[ STATES ] |= KeepBelow;
+ else if( atom == net_wm_state_demands_attention )
+ p->properties[ STATES ] |= DemandsAttention;
+
+ else if( atom == net_wm_state_stays_on_top )
+ p->properties[ STATES ] |= StaysOnTop;
+
+ else if( atom == net_wm_strut )
+ p->properties[ PROTOCOLS ] |= WMStrut;
+
+ else if( atom == net_wm_extended_strut )
+ p->properties[ PROTOCOLS2 ] |= WM2ExtendedStrut;
+
+ else if( atom == net_wm_icon_geometry )
+ p->properties[ PROTOCOLS ] |= WMIconGeometry;
+
+ else if( atom == net_wm_icon )
+ p->properties[ PROTOCOLS ] |= WMIcon;
+
+ else if( atom == net_wm_pid )
+ p->properties[ PROTOCOLS ] |= WMPid;
+
+ else if( atom == net_wm_handled_icons )
+ p->properties[ PROTOCOLS ] |= WMHandledIcons;
+
+ else if( atom == net_wm_ping )
+ p->properties[ PROTOCOLS ] |= WMPing;
+
+ else if( atom == net_wm_take_activity )
+ p->properties[ PROTOCOLS2 ] |= WM2TakeActivity;
+
+ else if( atom == net_wm_user_time )
+ p->properties[ PROTOCOLS2 ] |= WM2UserTime;
+
+ else if( atom == net_startup_id )
+ p->properties[ PROTOCOLS2 ] |= WM2StartupId;
+
+ else if( atom == net_wm_allowed_actions )
+ p->properties[ PROTOCOLS2 ] |= WM2AllowedActions;
+
+ // Actions
+ else if( atom == net_wm_action_move )
+ p->properties[ ACTIONS ] |= ActionMove;
+ else if( atom == net_wm_action_resize )
+ p->properties[ ACTIONS ] |= ActionResize;
+ else if( atom == net_wm_action_minimize )
+ p->properties[ ACTIONS ] |= ActionMinimize;
+ else if( atom == net_wm_action_shade )
+ p->properties[ ACTIONS ] |= ActionShade;
+ else if( atom == net_wm_action_stick )
+ p->properties[ ACTIONS ] |= ActionStick;
+ else if( atom == net_wm_action_max_vert )
+ p->properties[ ACTIONS ] |= ActionMaxVert;
+ else if( atom == net_wm_action_max_horiz )
+ p->properties[ ACTIONS ] |= ActionMaxHoriz;
+ else if( atom == net_wm_action_fullscreen )
+ p->properties[ ACTIONS ] |= ActionFullScreen;
+ else if( atom == net_wm_action_change_desk )
+ p->properties[ ACTIONS ] |= ActionChangeDesktop;
+ else if( atom == net_wm_action_close )
+ p->properties[ ACTIONS ] |= ActionClose;
+
+ // KDE specific extensions
+ else if( atom == kde_net_system_tray_windows )
+ p->properties[ PROTOCOLS ] |= KDESystemTrayWindows;
+
+ else if( atom == kde_net_wm_system_tray_window_for )
+ p->properties[ PROTOCOLS ] |= WMKDESystemTrayWinFor;
+
+ else if( atom == net_frame_extents )
+ p->properties[ PROTOCOLS ] |= WMFrameExtents;
+ else if( atom == kde_net_wm_frame_strut )
+ p->properties[ PROTOCOLS ] |= WMKDEFrameStrut;
+
+ else if( atom == kde_net_wm_temporary_rules )
+ p->properties[ PROTOCOLS2 ] |= WM2KDETemporaryRules;
+}
+
+extern Time qt_x_user_time;
+void NETRootInfo::setActiveWindow(Window window) {
+ setActiveWindow( window, FromUnknown, qt_x_user_time, None );
+}
+
+void NETRootInfo::setActiveWindow(Window window, NET::RequestSource src,
+ Time timestamp, Window active_window ) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setActiveWindow(0x%lx) (%s)\n",
+ window, (role == WindowManager) ? "WM" : "Client");
+#endif
+
+ if (role == WindowManager) {
+ p->active = window;
+ XChangeProperty(p->display, p->root, net_active_window, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &(p->active), 1);
+ } else {
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_active_window;
+ e.xclient.display = p->display;
+ e.xclient.window = window;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = src;
+ e.xclient.data.l[1] = timestamp;
+ e.xclient.data.l[2] = active_window;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+}
+
+
+void NETRootInfo::setWorkArea(int desktop, const NETRect &workarea) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setWorkArea(%d, { %d, %d, %d, %d }) (%s)\n",
+ desktop, workarea.pos.x, workarea.pos.y, workarea.size.width, workarea.size.height,
+ (role == WindowManager) ? "WM" : "Client");
+#endif
+
+ if (role != WindowManager || desktop < 1) return;
+
+ p->workarea[desktop - 1] = workarea;
+
+ long *wa = new long[p->number_of_desktops * 4];
+ int i, o;
+ for (i = 0, o = 0; i < p->number_of_desktops; i++) {
+ wa[o++] = p->workarea[i].pos.x;
+ wa[o++] = p->workarea[i].pos.y;
+ wa[o++] = p->workarea[i].size.width;
+ wa[o++] = p->workarea[i].size.height;
+ }
+
+ XChangeProperty(p->display, p->root, net_workarea, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) wa,
+ p->number_of_desktops * 4);
+
+ delete [] wa;
+}
+
+
+void NETRootInfo::setVirtualRoots(Window *windows, unsigned int count) {
+ if (role != WindowManager) return;
+
+ p->virtual_roots_count = count;
+ p->virtual_roots = windows;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setVirtualRoots: setting list with %ld windows\n",
+ p->virtual_roots_count);
+#endif
+
+ XChangeProperty(p->display, p->root, net_virtual_roots, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) p->virtual_roots,
+ p->virtual_roots_count);
+}
+
+
+void NETRootInfo::setDesktopLayout(NET::Orientation orientation, int columns, int rows,
+ NET::DesktopLayoutCorner corner)
+{
+ p->desktop_layout_orientation = orientation;
+ p->desktop_layout_columns = columns;
+ p->desktop_layout_rows = rows;
+ p->desktop_layout_corner = corner;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::setDesktopLayout: %d %d %d %d\n",
+ orientation, columns, rows, corner);
+#endif
+
+ long data[ 4 ];
+ data[ 0 ] = orientation;
+ data[ 1 ] = columns;
+ data[ 2 ] = rows;
+ data[ 3 ] = corner;
+ XChangeProperty(p->display, p->root, net_desktop_layout, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &data, 4);
+}
+
+
+void NETRootInfo::setShowingDesktop( bool showing ) {
+ if (role == WindowManager) {
+ long d = p->showing_desktop = showing;
+ XChangeProperty(p->display, p->root, net_showing_desktop, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &d, 1);
+ } else {
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_showing_desktop;
+ e.xclient.display = p->display;
+ e.xclient.window = 0;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = showing ? 1 : 0;
+ e.xclient.data.l[1] = 0;
+ e.xclient.data.l[2] = 0;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+}
+
+
+bool NETRootInfo::showingDesktop() const {
+ return p->showing_desktop;
+}
+
+
+void NETRootInfo::closeWindowRequest(Window window) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::closeWindowRequest: requesting close for 0x%lx\n",
+ window);
+#endif
+
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_close_window;
+ e.xclient.display = p->display;
+ e.xclient.window = window;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = 0l;
+ e.xclient.data.l[1] = 0l;
+ e.xclient.data.l[2] = 0l;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+}
+
+
+void NETRootInfo::moveResizeRequest(Window window, int x_root, int y_root,
+ Direction direction)
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::moveResizeRequest: requesting resize/move for 0x%lx (%d, %d, %d)\n",
+ window, x_root, y_root, direction);
+#endif
+
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_wm_moveresize;
+ e.xclient.display = p->display;
+ e.xclient.window = window,
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = x_root;
+ e.xclient.data.l[1] = y_root;
+ e.xclient.data.l[2] = direction;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+}
+
+void NETRootInfo::moveResizeWindowRequest(Window window, int flags, int x, int y, int width, int height )
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::moveResizeWindowRequest: resizing/moving 0x%lx (%d, %d, %d, %d, %d)\n",
+ window, flags, x, y, width, height);
+#endif
+
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_moveresize_window;
+ e.xclient.display = p->display;
+ e.xclient.window = window,
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = flags;
+ e.xclient.data.l[1] = x;
+ e.xclient.data.l[2] = y;
+ e.xclient.data.l[3] = width;
+ e.xclient.data.l[4] = height;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+}
+
+void NETRootInfo::restackRequest(Window window, Window above, int detail)
+{
+ restackRequest( window, FromTool, above, detail, qt_x_user_time );
+}
+
+void NETRootInfo::restackRequest(Window window, RequestSource src, Window above, int detail, Time timestamp )
+{
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::restackRequest: requesting restack for 0x%lx (%lx, %d)\n",
+ window, above, detail);
+#endif
+
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_restack_window;
+ e.xclient.display = p->display;
+ e.xclient.window = window,
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = src;
+ e.xclient.data.l[1] = above;
+ e.xclient.data.l[2] = detail;
+ e.xclient.data.l[3] = timestamp;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+}
+
+void NETRootInfo2::sendPing( Window window, Time timestamp )
+{
+ if (role != WindowManager) return;
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo2::setPing: window 0x%lx, timestamp %lu\n",
+ window, timestamp );
+#endif
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = wm_protocols;
+ e.xclient.display = p->display;
+ e.xclient.window = window,
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = net_wm_ping;
+ e.xclient.data.l[1] = timestamp;
+ e.xclient.data.l[2] = window;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+
+ XSendEvent(p->display, window, False, 0, &e);
+}
+
+void NETRootInfo3::takeActivity( Window window, Time timestamp, long flags )
+{
+ if (role != WindowManager) return;
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo2::takeActivity: window 0x%lx, timestamp %lu, flags 0x%lx\n",
+ window, timestamp, flags );
+#endif
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = wm_protocols;
+ e.xclient.display = p->display;
+ e.xclient.window = window,
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = net_wm_take_activity;
+ e.xclient.data.l[1] = timestamp;
+ e.xclient.data.l[2] = window;
+ e.xclient.data.l[3] = flags;
+ e.xclient.data.l[4] = 0;
+
+ XSendEvent(p->display, window, False, 0, &e);
+}
+
+
+
+// assignment operator
+
+const NETRootInfo &NETRootInfo::operator=(const NETRootInfo &rootinfo) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::operator=()\n");
+#endif
+
+ if (p != rootinfo.p) {
+ refdec_nri(p);
+
+ if (! p->ref) delete p;
+ }
+
+ p = rootinfo.p;
+ role = rootinfo.role;
+ p->ref++;
+
+ return *this;
+}
+
+unsigned long NETRootInfo::event(XEvent *ev )
+{
+ unsigned long props[ 1 ];
+ event( ev, props, 1 );
+ return props[ 0 ];
+}
+
+void NETRootInfo::event(XEvent *event, unsigned long* properties, int properties_size )
+{
+ unsigned long props[ PROPERTIES_SIZE ] = { 0, 0, 0, 0, 0 };
+ assert( PROPERTIES_SIZE == 5 ); // add elements above
+ unsigned long& dirty = props[ PROTOCOLS ];
+ unsigned long& dirty2 = props[ PROTOCOLS2 ];
+ bool do_update = false;
+
+ // the window manager will be interested in client messages... no other
+ // client should get these messages
+ if (role == WindowManager && event->type == ClientMessage &&
+ event->xclient.format == 32) {
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: handling ClientMessage event\n");
+#endif
+
+ if (event->xclient.message_type == net_number_of_desktops) {
+ dirty = NumberOfDesktops;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: changeNumberOfDesktops(%ld)\n",
+ event->xclient.data.l[0]);
+#endif
+
+ changeNumberOfDesktops(event->xclient.data.l[0]);
+ } else if (event->xclient.message_type == net_desktop_geometry) {
+ dirty = DesktopGeometry;
+
+ NETSize sz;
+ sz.width = event->xclient.data.l[0];
+ sz.height = event->xclient.data.l[1];
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: changeDesktopGeometry( -- , { %d, %d })\n",
+ sz.width, sz.height);
+#endif
+
+ changeDesktopGeometry(~0, sz);
+ } else if (event->xclient.message_type == net_desktop_viewport) {
+ dirty = DesktopViewport;
+
+ NETPoint pt;
+ pt.x = event->xclient.data.l[0];
+ pt.y = event->xclient.data.l[1];
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: changeDesktopViewport(%d, { %d, %d })\n",
+ p->current_desktop, pt.x, pt.y);
+#endif
+
+ changeDesktopViewport(p->current_desktop, pt);
+ } else if (event->xclient.message_type == net_current_desktop) {
+ dirty = CurrentDesktop;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: changeCurrentDesktop(%ld)\n",
+ event->xclient.data.l[0] + 1);
+#endif
+
+ changeCurrentDesktop(event->xclient.data.l[0] + 1);
+ } else if (event->xclient.message_type == net_active_window) {
+ dirty = ActiveWindow;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: changeActiveWindow(0x%lx)\n",
+ event->xclient.window);
+#endif
+
+ changeActiveWindow(event->xclient.window);
+ if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this ))
+ {
+ RequestSource src = FromUnknown;
+ Time timestamp = CurrentTime;
+ Window active_window = None;
+ // make sure there aren't unknown values
+ if( event->xclient.data.l[0] >= FromUnknown
+ && event->xclient.data.l[0] <= FromTool )
+ {
+ src = static_cast< RequestSource >( event->xclient.data.l[0] );
+ timestamp = event->xclient.data.l[1];
+ active_window = event->xclient.data.l[2];
+ }
+ this2->changeActiveWindow( event->xclient.window, src, timestamp, active_window );
+ }
+ } else if (event->xclient.message_type == net_wm_moveresize) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: moveResize(%ld, %ld, %ld, %ld)\n",
+ event->xclient.window,
+ event->xclient.data.l[0],
+ event->xclient.data.l[1],
+ event->xclient.data.l[2]
+ );
+#endif
+
+ moveResize(event->xclient.window,
+ event->xclient.data.l[0],
+ event->xclient.data.l[1],
+ event->xclient.data.l[2]);
+ } else if (event->xclient.message_type == net_moveresize_window) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: moveResizeWindow(%ld, %ld, %ld, %ld, %ld, %ld)\n",
+ event->xclient.window,
+ event->xclient.data.l[0],
+ event->xclient.data.l[1],
+ event->xclient.data.l[2],
+ event->xclient.data.l[3],
+ event->xclient.data.l[4]
+ );
+#endif
+
+ if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this ))
+ this2->moveResizeWindow(event->xclient.window,
+ event->xclient.data.l[0],
+ event->xclient.data.l[1],
+ event->xclient.data.l[2],
+ event->xclient.data.l[3],
+ event->xclient.data.l[4]);
+ } else if (event->xclient.message_type == net_close_window) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: closeWindow(0x%lx)\n",
+ event->xclient.window);
+#endif
+
+ closeWindow(event->xclient.window);
+ } else if (event->xclient.message_type == net_restack_window) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: restackWindow(0x%lx)\n",
+ event->xclient.window);
+#endif
+
+ if( NETRootInfo3* this3 = dynamic_cast< NETRootInfo3* >( this ))
+ {
+ RequestSource src = FromUnknown;
+ Time timestamp = CurrentTime;
+ // make sure there aren't unknown values
+ if( event->xclient.data.l[0] >= FromUnknown
+ && event->xclient.data.l[0] <= FromTool )
+ {
+ src = static_cast< RequestSource >( event->xclient.data.l[0] );
+ timestamp = event->xclient.data.l[3];
+ }
+ this3->restackWindow(event->xclient.window, src,
+ event->xclient.data.l[1], event->xclient.data.l[2], timestamp);
+ }
+ else if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this ))
+ this2->restackWindow(event->xclient.window,
+ event->xclient.data.l[1], event->xclient.data.l[2]);
+ } else if (event->xclient.message_type == wm_protocols
+ && (Atom)event->xclient.data.l[ 0 ] == net_wm_ping) {
+ dirty = WMPing;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo2::event: gotPing(0x%lx,%lu)\n",
+ event->xclient.window, event->xclient.data.l[1]);
+#endif
+ if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this ))
+ this2->gotPing( event->xclient.data.l[2], event->xclient.data.l[1]);
+ } else if (event->xclient.message_type == wm_protocols
+ && (Atom)event->xclient.data.l[ 0 ] == net_wm_take_activity) {
+ dirty2 = WM2TakeActivity;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo2::event: gotTakeActivity(0x%lx,%lu,0x%lx)\n",
+ event->xclient.window, event->xclient.data.l[1], event->xclient.data.l[3]);
+#endif
+ if( NETRootInfo3* this3 = dynamic_cast< NETRootInfo3* >( this ))
+ this3->gotTakeActivity( event->xclient.data.l[2], event->xclient.data.l[1],
+ event->xclient.data.l[3]);
+ } else if (event->xclient.message_type == net_showing_desktop) {
+ dirty2 = WM2ShowingDesktop;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: changeShowingDesktop(%ld)\n",
+ event->xclient.data.l[0]);
+#endif
+
+ if( NETRootInfo4* this4 = dynamic_cast< NETRootInfo4* >( this ))
+ this4->changeShowingDesktop(event->xclient.data.l[0]);
+ }
+ }
+
+ if (event->type == PropertyNotify) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: handling PropertyNotify event\n");
+#endif
+
+ XEvent pe = *event;
+
+ Bool done = False;
+ Bool compaction = False;
+ while (! done) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: loop fire\n");
+#endif
+
+ if (pe.xproperty.atom == net_client_list)
+ dirty |= ClientList;
+ else if (pe.xproperty.atom == net_client_list_stacking)
+ dirty |= ClientListStacking;
+ else if (pe.xproperty.atom == kde_net_system_tray_windows)
+ dirty |= KDESystemTrayWindows;
+ else if (pe.xproperty.atom == net_desktop_names)
+ dirty |= DesktopNames;
+ else if (pe.xproperty.atom == net_workarea)
+ dirty |= WorkArea;
+ else if (pe.xproperty.atom == net_number_of_desktops)
+ dirty |= NumberOfDesktops;
+ else if (pe.xproperty.atom == net_desktop_geometry)
+ dirty |= DesktopGeometry;
+ else if (pe.xproperty.atom == net_desktop_viewport)
+ dirty |= DesktopViewport;
+ else if (pe.xproperty.atom == net_current_desktop)
+ dirty |= CurrentDesktop;
+ else if (pe.xproperty.atom == net_active_window)
+ dirty |= ActiveWindow;
+ else if (pe.xproperty.atom == net_showing_desktop)
+ dirty2 |= WM2ShowingDesktop;
+// else if (pe.xproperty.atom == net_supported )
+// dirty |= Supported; // update here?
+ else if (pe.xproperty.atom == net_supporting_wm_check )
+ dirty |= SupportingWMCheck;
+ else if (pe.xproperty.atom == net_virtual_roots )
+ dirty |= VirtualRoots;
+ else if (pe.xproperty.atom == net_desktop_layout )
+ dirty2 |= WM2DesktopLayout;
+ else {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: putting back event and breaking\n");
+#endif
+
+ if ( compaction )
+ XPutBackEvent(p->display, &pe);
+ break;
+ }
+
+ if (XCheckTypedWindowEvent(p->display, p->root, PropertyNotify, &pe) )
+ compaction = True;
+ else
+ break;
+ }
+
+ do_update = true;
+ }
+
+ if( do_update )
+ update( props );
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::event: handled events, returning dirty = 0x%lx, 0x%lx\n",
+ dirty, dirty2);
+#endif
+
+ if( properties_size > PROPERTIES_SIZE )
+ properties_size = PROPERTIES_SIZE;
+ for( int i = 0;
+ i < properties_size;
+ ++i )
+ properties[ i ] = props[ i ];
+}
+
+
+// private functions to update the data we keep
+
+void NETRootInfo::update( const unsigned long dirty_props[] )
+{
+ Atom type_ret;
+ int format_ret;
+ unsigned char *data_ret;
+ unsigned long nitems_ret, unused;
+ unsigned long props[ PROPERTIES_SIZE ];
+ for( int i = 0;
+ i < PROPERTIES_SIZE;
+ ++i )
+ props[ i ] = dirty_props[ i ] & p->client_properties[ i ];
+ const unsigned long& dirty = props[ PROTOCOLS ];
+ const unsigned long& dirty2 = props[ PROTOCOLS2 ];
+
+ if (dirty & Supported ) {
+ // only in Client mode
+ for( int i = 0; i < PROPERTIES_SIZE; ++i )
+ p->properties[ i ] = 0;
+ if( XGetWindowProperty(p->display, p->root, net_supported,
+ 0l, MAX_PROP_SIZE, False, XA_ATOM, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success ) {
+ if( type_ret == XA_ATOM && format_ret == 32 ) {
+ Atom* atoms = (Atom*) data_ret;
+ for( unsigned int i = 0;
+ i < nitems_ret;
+ ++i )
+ updateSupportedProperties( atoms[ i ] );
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & ClientList) {
+ bool read_ok = false;
+ if (XGetWindowProperty(p->display, p->root, net_client_list,
+ 0l, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_WINDOW && format_ret == 32) {
+ Window *wins = (Window *) data_ret;
+
+ qsort(wins, nitems_ret, sizeof(Window), wcmp);
+
+ if (p->clients) {
+ if (role == Client) {
+ unsigned long new_index = 0, old_index = 0;
+ unsigned long new_count = nitems_ret,
+ old_count = p->clients_count;
+
+ while (old_index < old_count || new_index < new_count) {
+ if (old_index == old_count) {
+ addClient(wins[new_index++]);
+ } else if (new_index == new_count) {
+ removeClient(p->clients[old_index++]);
+ } else {
+ if (p->clients[old_index] <
+ wins[new_index]) {
+ removeClient(p->clients[old_index++]);
+ } else if (wins[new_index] <
+ p->clients[old_index]) {
+ addClient(wins[new_index++]);
+ } else {
+ new_index++;
+ old_index++;
+ }
+ }
+ }
+ }
+
+ delete [] p->clients;
+ } else {
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: client list null, creating\n");
+#endif
+
+ unsigned long n;
+ for (n = 0; n < nitems_ret; n++) {
+ addClient(wins[n]);
+ }
+ }
+
+ p->clients_count = nitems_ret;
+ p->clients = nwindup(wins, p->clients_count);
+ read_ok = true;
+ }
+
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ if( !read_ok ) {
+ for( unsigned int i = 0; i < p->clients_count; ++ i )
+ removeClient(p->clients[i]);
+ p->clients_count = 0;
+ delete[] p->clients;
+ p->clients = NULL;
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: client list updated (%ld clients)\n",
+ p->clients_count);
+#endif
+ }
+
+ if (dirty & KDESystemTrayWindows) {
+ bool read_ok = false;
+ if (XGetWindowProperty(p->display, p->root, kde_net_system_tray_windows,
+ 0l, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_WINDOW && format_ret == 32) {
+ Window *wins = (Window *) data_ret;
+
+ qsort(wins, nitems_ret, sizeof(Window), wcmp);
+
+ if (p->kde_system_tray_windows) {
+ if (role == Client) {
+ unsigned long new_index = 0, new_count = nitems_ret;
+ unsigned long old_index = 0,
+ old_count = p->kde_system_tray_windows_count;
+
+ while(old_index < old_count || new_index < new_count) {
+ if (old_index == old_count) {
+ addSystemTrayWin(wins[new_index++]);
+ } else if (new_index == new_count) {
+ removeSystemTrayWin(p->kde_system_tray_windows[old_index++]);
+ } else {
+ if (p->kde_system_tray_windows[old_index] <
+ wins[new_index]) {
+ removeSystemTrayWin(p->kde_system_tray_windows[old_index++]);
+ } else if (wins[new_index] <
+ p->kde_system_tray_windows[old_index]) {
+ addSystemTrayWin(wins[new_index++]);
+ } else {
+ new_index++;
+ old_index++;
+ }
+ }
+ }
+ }
+
+ } else {
+ unsigned long n;
+ for (n = 0; n < nitems_ret; n++) {
+ addSystemTrayWin(wins[n]);
+ }
+ }
+
+ p->kde_system_tray_windows_count = nitems_ret;
+ delete [] p->kde_system_tray_windows;
+ p->kde_system_tray_windows =
+ nwindup(wins, p->kde_system_tray_windows_count);
+ read_ok = true;
+ }
+
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ if( !read_ok ) {
+ for( unsigned int i = 0; i < p->kde_system_tray_windows_count; ++i )
+ removeSystemTrayWin(p->kde_system_tray_windows[i]);
+ p->kde_system_tray_windows_count = 0;
+ delete [] p->kde_system_tray_windows;
+ p->kde_system_tray_windows = NULL;
+ }
+ }
+
+ if (dirty & ClientListStacking) {
+ p->stacking_count = 0;
+ delete[] p->stacking;
+ p->stacking = NULL;
+ if (XGetWindowProperty(p->display, p->root, net_client_list_stacking,
+ 0, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_WINDOW && format_ret == 32) {
+ Window *wins = (Window *) data_ret;
+
+ p->stacking_count = nitems_ret;
+ p->stacking = nwindup(wins, p->stacking_count);
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,"NETRootInfo::update: client stacking updated (%ld clients)\n",
+ p->stacking_count);
+#endif
+
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & NumberOfDesktops) {
+ p->number_of_desktops = 0;
+
+ if (XGetWindowProperty(p->display, p->root, net_number_of_desktops,
+ 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) {
+ p->number_of_desktops = *((long *) data_ret);
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: number of desktops = %d\n",
+ p->number_of_desktops);
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & DesktopGeometry) {
+ p->geometry = p->rootSize;
+ if (XGetWindowProperty(p->display, p->root, net_desktop_geometry,
+ 0l, 2l, False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 &&
+ nitems_ret == 2) {
+ long *data = (long *) data_ret;
+
+ p->geometry.width = data[0];
+ p->geometry.height = data[1];
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: desktop geometry updated\n");
+#endif
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & DesktopViewport) {
+ for (int i = 0; i < p->viewport.size(); i++)
+ p->viewport[i].x = p->viewport[i].y = 0;
+ if (XGetWindowProperty(p->display, p->root, net_desktop_viewport,
+ 0l, 2l, False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 &&
+ nitems_ret == 2) {
+ long *data = (long *) data_ret;
+
+ int d, i, n;
+ n = nitems_ret / 2;
+ for (d = 0, i = 0; d < n; d++) {
+ p->viewport[d].x = data[i++];
+ p->viewport[d].y = data[i++];
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::update: desktop viewport array updated (%d entries)\n",
+ p->viewport.size());
+
+ if (nitems_ret % 2 != 0) {
+ fprintf(stderr,
+ "NETRootInfo::update(): desktop viewport array "
+ "size not a multiple of 2\n");
+ }
+#endif
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & CurrentDesktop) {
+ p->current_desktop = 0;
+ if (XGetWindowProperty(p->display, p->root, net_current_desktop,
+ 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) {
+ p->current_desktop = *((long *) data_ret) + 1;
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: current desktop = %d\n",
+ p->current_desktop);
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & DesktopNames) {
+ for( int i = 0; i < p->desktop_names.size(); ++i )
+ delete[] p->desktop_names[ i ];
+ p->desktop_names.reset();
+ if (XGetWindowProperty(p->display, p->root, net_desktop_names,
+ 0l, MAX_PROP_SIZE, False, UTF8_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == UTF8_STRING && format_ret == 8) {
+ const char *d = (const char *) data_ret;
+ unsigned int s, n, index;
+
+ for (s = 0, n = 0, index = 0; n < nitems_ret; n++) {
+ if (d[n] == '\0') {
+ delete [] p->desktop_names[index];
+ p->desktop_names[index++] = nstrndup((d + s), n - s + 1);
+ s = n + 1;
+ }
+ }
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: desktop names array updated (%d entries)\n",
+ p->desktop_names.size());
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & ActiveWindow) {
+ p->active = None;
+ if (XGetWindowProperty(p->display, p->root, net_active_window, 0l, 1l,
+ False, XA_WINDOW, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_WINDOW && format_ret == 32 && nitems_ret == 1) {
+ p->active = *((Window *) data_ret);
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: active window = 0x%lx\n",
+ p->active);
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WorkArea) {
+ p->workarea.reset();
+ if (XGetWindowProperty(p->display, p->root, net_workarea, 0l,
+ (p->number_of_desktops * 4), False, XA_CARDINAL,
+ &type_ret, &format_ret, &nitems_ret, &unused,
+ &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 &&
+ nitems_ret == (unsigned) (p->number_of_desktops * 4)) {
+ long *d = (long *) data_ret;
+ int i, j;
+ for (i = 0, j = 0; i < p->number_of_desktops; i++) {
+ p->workarea[i].pos.x = d[j++];
+ p->workarea[i].pos.y = d[j++];
+ p->workarea[i].size.width = d[j++];
+ p->workarea[i].size.height = d[j++];
+ }
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: work area array updated (%d entries)\n",
+ p->workarea.size());
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+
+ if (dirty & SupportingWMCheck) {
+ p->supportwindow = None;
+ delete[] p->name;
+ p->name = NULL;
+ if (XGetWindowProperty(p->display, p->root, net_supporting_wm_check,
+ 0l, 1l, False, XA_WINDOW, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_WINDOW && format_ret == 32 && nitems_ret == 1) {
+ p->supportwindow = *((Window *) data_ret);
+
+ unsigned char *name_ret;
+ if (XGetWindowProperty(p->display, p->supportwindow,
+ net_wm_name, 0l, MAX_PROP_SIZE, False,
+ UTF8_STRING, &type_ret, &format_ret,
+ &nitems_ret, &unused, &name_ret)
+ == Success) {
+ if (type_ret == UTF8_STRING && format_ret == 8)
+ p->name = nstrndup((const char *) name_ret, nitems_ret);
+
+ if ( name_ret )
+ XFree(name_ret);
+ }
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETRootInfo::update: supporting window manager = '%s'\n",
+ p->name);
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & VirtualRoots) {
+ p->virtual_roots_count = 0;
+ delete[] p->virtual_roots;
+ p->virtual_roots = NULL;
+ if (XGetWindowProperty(p->display, p->root, net_virtual_roots,
+ 0, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_WINDOW && format_ret == 32) {
+ Window *wins = (Window *) data_ret;
+
+ p->virtual_roots_count = nitems_ret;
+ p->virtual_roots = nwindup(wins, p->virtual_roots_count);
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::updated: virtual roots updated (%ld windows)\n",
+ p->virtual_roots_count);
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty2 & WM2DesktopLayout) {
+ p->desktop_layout_orientation = OrientationHorizontal;
+ p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
+ p->desktop_layout_columns = p->desktop_layout_rows = 0;
+ if (XGetWindowProperty(p->display, p->root, net_desktop_layout,
+ 0, MAX_PROP_SIZE, False, XA_CARDINAL, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32) {
+ long* data = (long*) data_ret;
+ if( nitems_ret >= 4 && data[ 3 ] >= 0 && data[ 3 ] <= 3 )
+ p->desktop_layout_corner = (NET::DesktopLayoutCorner)data[ 3 ];
+ if( nitems_ret >= 3 ) {
+ if( data[ 0 ] >= 0 && data[ 0 ] <= 1 )
+ p->desktop_layout_orientation = (NET::Orientation)data[ 0 ];
+ p->desktop_layout_columns = data[ 1 ];
+ p->desktop_layout_rows = data[ 2 ];
+ }
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::updated: desktop layout updated (%d %d %d %d)\n",
+ p->desktop_layout_orientation, p->desktop_layout_columns,
+ p->desktop_layout_rows, p->desktop_layout_corner );
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty2 & WM2ShowingDesktop) {
+ p->showing_desktop = false;
+ if (XGetWindowProperty(p->display, p->root, net_showing_desktop,
+ 0, MAX_PROP_SIZE, False, XA_CARDINAL, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) {
+ p->showing_desktop = *((long *) data_ret);
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETRootInfo::update: showing desktop = %d\n",
+ p->showing_desktop);
+#endif
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+}
+
+
+Display *NETRootInfo::x11Display() const {
+ return p->display;
+}
+
+
+Window NETRootInfo::rootWindow() const {
+ return p->root;
+}
+
+
+Window NETRootInfo::supportWindow() const {
+ return p->supportwindow;
+}
+
+
+const char *NETRootInfo::wmName() const {
+ return p->name; }
+
+
+int NETRootInfo::screenNumber() const {
+ return p->screen;
+}
+
+
+unsigned long NETRootInfo::supported() const {
+ return role == WindowManager
+ ? p->properties[ PROTOCOLS ]
+ : p->client_properties[ PROTOCOLS ];
+}
+
+const unsigned long* NETRootInfo::supportedProperties() const {
+ return p->properties;
+}
+
+const unsigned long* NETRootInfo::passedProperties() const {
+ return role == WindowManager
+ ? p->properties
+ : p->client_properties;
+}
+
+bool NETRootInfo::isSupported( NET::Property property ) const {
+ return p->properties[ PROTOCOLS ] & property;
+}
+
+bool NETRootInfo::isSupported( NET::Property2 property ) const {
+ return p->properties[ PROTOCOLS2 ] & property;
+}
+
+bool NETRootInfo::isSupported( NET::WindowType type ) const {
+ return p->properties[ WINDOW_TYPES ] & type;
+}
+
+bool NETRootInfo::isSupported( NET::State state ) const {
+ return p->properties[ STATES ] & state;
+}
+
+bool NETRootInfo::isSupported( NET::Action action ) const {
+ return p->properties[ ACTIONS ] & action;
+}
+
+const Window *NETRootInfo::clientList() const {
+ return p->clients;
+}
+
+
+int NETRootInfo::clientListCount() const {
+ return p->clients_count;
+}
+
+
+const Window *NETRootInfo::clientListStacking() const {
+ return p->stacking;
+}
+
+
+int NETRootInfo::clientListStackingCount() const {
+ return p->stacking_count;
+}
+
+
+const Window *NETRootInfo::kdeSystemTrayWindows() const {
+ return p->kde_system_tray_windows;
+}
+
+
+int NETRootInfo::kdeSystemTrayWindowsCount() const {
+ return p->kde_system_tray_windows_count;
+}
+
+
+NETSize NETRootInfo::desktopGeometry(int) const {
+ return p->geometry.width != 0 ? p->geometry : p->rootSize;
+}
+
+
+NETPoint NETRootInfo::desktopViewport(int desktop) const {
+ if (desktop < 1) {
+ NETPoint pt; // set to (0,0)
+ return pt;
+ }
+
+ return p->viewport[desktop - 1];
+}
+
+
+NETRect NETRootInfo::workArea(int desktop) const {
+ if (desktop < 1) {
+ NETRect rt;
+ return rt;
+ }
+
+ return p->workarea[desktop - 1];
+}
+
+
+const char *NETRootInfo::desktopName(int desktop) const {
+ if (desktop < 1) {
+ return 0;
+ }
+
+ return p->desktop_names[desktop - 1];
+}
+
+
+const Window *NETRootInfo::virtualRoots( ) const {
+ return p->virtual_roots;
+}
+
+
+int NETRootInfo::virtualRootsCount() const {
+ return p->virtual_roots_count;
+}
+
+
+NET::Orientation NETRootInfo::desktopLayoutOrientation() const {
+ return p->desktop_layout_orientation;
+}
+
+
+QSize NETRootInfo::desktopLayoutColumnsRows() const {
+ return QSize( p->desktop_layout_columns, p->desktop_layout_rows );
+}
+
+
+NET::DesktopLayoutCorner NETRootInfo::desktopLayoutCorner() const {
+ return p->desktop_layout_corner;
+}
+
+
+int NETRootInfo::numberOfDesktops() const {
+ return p->number_of_desktops == 0 ? 1 : p->number_of_desktops;
+}
+
+
+int NETRootInfo::currentDesktop() const {
+ return p->current_desktop == 0 ? 1 : p->current_desktop;
+}
+
+
+Window NETRootInfo::activeWindow() const {
+ return p->active;
+}
+
+
+// NETWinInfo stuffs
+
+const int NETWinInfo::OnAllDesktops = NET::OnAllDesktops;
+
+NETWinInfo::NETWinInfo(Display *display, Window window, Window rootWindow,
+ const unsigned long properties[], int properties_size,
+ Role role)
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::NETWinInfo: constructing object with role '%s'\n",
+ (role == WindowManager) ? "WindowManager" : "Client");
+#endif
+
+ p = new NETWinInfoPrivate;
+ p->ref = 1;
+
+ p->display = display;
+ p->window = window;
+ p->root = rootWindow;
+ p->mapping_state = Withdrawn;
+ p->mapping_state_dirty = True;
+ p->state = 0;
+ p->types[ 0 ] = Unknown;
+ p->name = (char *) 0;
+ p->visible_name = (char *) 0;
+ p->icon_name = (char *) 0;
+ p->visible_icon_name = (char *) 0;
+ p->desktop = p->pid = p->handled_icons = 0;
+ p->user_time = -1U;
+ p->startup_id = NULL;
+ p->transient_for = None;
+ p->window_group = None;
+ p->allowed_actions = 0;
+ p->has_net_support = false;
+ p->class_class = (char*) 0;
+ p->class_name = (char*) 0;
+ p->role = (char*) 0;
+ p->client_machine = (char*) 0;
+
+ // p->strut.left = p->strut.right = p->strut.top = p->strut.bottom = 0;
+ // p->frame_strut.left = p->frame_strut.right = p->frame_strut.top =
+ // p->frame_strut.bottom = 0;
+
+ p->kde_system_tray_win_for = 0;
+
+ for( int i = 0;
+ i < PROPERTIES_SIZE;
+ ++i )
+ p->properties[ i ] = 0;
+ if( properties_size > PROPERTIES_SIZE )
+ properties_size = PROPERTIES_SIZE;
+ for( int i = 0;
+ i < properties_size;
+ ++i )
+ p->properties[ i ] = properties[ i ];
+
+ p->icon_count = 0;
+
+ this->role = role;
+
+ if (! netwm_atoms_created) create_atoms(p->display);
+
+ update(p->properties);
+}
+
+
+NETWinInfo::NETWinInfo(Display *display, Window window, Window rootWindow,
+ unsigned long properties, Role role)
+{
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::NETWinInfo: constructing object with role '%s'\n",
+ (role == WindowManager) ? "WindowManager" : "Client");
+#endif
+
+ p = new NETWinInfoPrivate;
+ p->ref = 1;
+
+ p->display = display;
+ p->window = window;
+ p->root = rootWindow;
+ p->mapping_state = Withdrawn;
+ p->mapping_state_dirty = True;
+ p->state = 0;
+ p->types[ 0 ] = Unknown;
+ p->name = (char *) 0;
+ p->visible_name = (char *) 0;
+ p->icon_name = (char *) 0;
+ p->visible_icon_name = (char *) 0;
+ p->desktop = p->pid = p->handled_icons = 0;
+ p->user_time = -1U;
+ p->startup_id = NULL;
+ p->transient_for = None;
+ p->window_group = None;
+ p->allowed_actions = 0;
+ p->has_net_support = false;
+ p->class_class = (char*) 0;
+ p->class_name = (char*) 0;
+ p->role = (char*) 0;
+ p->client_machine = (char*) 0;
+
+ // p->strut.left = p->strut.right = p->strut.top = p->strut.bottom = 0;
+ // p->frame_strut.left = p->frame_strut.right = p->frame_strut.top =
+ // p->frame_strut.bottom = 0;
+
+ p->kde_system_tray_win_for = 0;
+
+ for( int i = 0;
+ i < PROPERTIES_SIZE;
+ ++i )
+ p->properties[ i ] = 0;
+ p->properties[ PROTOCOLS ] = properties;
+
+ p->icon_count = 0;
+
+ this->role = role;
+
+ if (! netwm_atoms_created) create_atoms(p->display);
+
+ update(p->properties);
+}
+
+
+NETWinInfo::NETWinInfo(const NETWinInfo &wininfo) {
+ p = wininfo.p;
+ p->ref++;
+}
+
+
+NETWinInfo::~NETWinInfo() {
+ refdec_nwi(p);
+
+ if (! p->ref) delete p;
+}
+
+
+// assignment operator
+
+const NETWinInfo &NETWinInfo::operator=(const NETWinInfo &wininfo) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::operator=()\n");
+#endif
+
+ if (p != wininfo.p) {
+ refdec_nwi(p);
+
+ if (! p->ref) delete p;
+ }
+
+ p = wininfo.p;
+ role = wininfo.role;
+ p->ref++;
+
+ return *this;
+}
+
+
+void NETWinInfo::setIcon(NETIcon icon, Bool replace) {
+ setIconInternal( p->icons, p->icon_count, net_wm_icon, icon, replace );
+}
+
+void NETWinInfo::setIconInternal(NETRArray<NETIcon>& icons, int& icon_count, Atom property, NETIcon icon, Bool replace) {
+ if (role != Client) return;
+
+ int proplen, i, sz, j;
+
+ if (replace) {
+
+ for (i = 0; i < icons.size(); i++) {
+ delete [] icons[i].data;
+ icons[i].data = 0;
+ icons[i].size.width = 0;
+ icons[i].size.height = 0;
+ }
+
+ icon_count = 0;
+ }
+
+ // assign icon
+ icons[icon_count] = icon;
+ icon_count++;
+
+ // do a deep copy, we want to own the data
+ NETIcon &ni = icons[icon_count - 1];
+ sz = ni.size.width * ni.size.height;
+ CARD32 *d = new CARD32[sz];
+ ni.data = (unsigned char *) d;
+ memcpy(d, icon.data, sz * sizeof(CARD32));
+
+ // compute property length
+ for (i = 0, proplen = 0; i < icon_count; i++) {
+ proplen += 2 + (icons[i].size.width *
+ icons[i].size.height);
+ }
+
+ CARD32 *d32;
+ long *prop = new long[proplen], *pprop = prop;
+ for (i = 0; i < icon_count; i++) {
+ // copy size into property
+ *pprop++ = icons[i].size.width;
+ *pprop++ = icons[i].size.height;
+
+ // copy data into property
+ sz = (icons[i].size.width * icons[i].size.height);
+ d32 = (CARD32 *) icons[i].data;
+ for (j = 0; j < sz; j++) *pprop++ = *d32++;
+ }
+
+ XChangeProperty(p->display, p->window, property, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) prop, proplen);
+
+ delete [] prop;
+}
+
+
+void NETWinInfo::setIconGeometry(NETRect geometry) {
+ if (role != Client) return;
+
+ p->icon_geom = geometry;
+
+ if( geometry.size.width == 0 ) // empty
+ XDeleteProperty(p->display, p->window, net_wm_icon_geometry);
+ else {
+ long data[4];
+ data[0] = geometry.pos.x;
+ data[1] = geometry.pos.y;
+ data[2] = geometry.size.width;
+ data[3] = geometry.size.height;
+
+ XChangeProperty(p->display, p->window, net_wm_icon_geometry, XA_CARDINAL,
+ 32, PropModeReplace, (unsigned char *) data, 4);
+ }
+}
+
+
+void NETWinInfo::setExtendedStrut(const NETExtendedStrut& extended_strut ) {
+ if (role != Client) return;
+
+ p->extended_strut = extended_strut;
+
+ long data[12];
+ data[0] = extended_strut.left_width;
+ data[1] = extended_strut.right_width;
+ data[2] = extended_strut.top_width;
+ data[3] = extended_strut.bottom_width;
+ data[4] = extended_strut.left_start;
+ data[5] = extended_strut.left_end;
+ data[6] = extended_strut.right_start;
+ data[7] = extended_strut.right_end;
+ data[8] = extended_strut.top_start;
+ data[9] = extended_strut.top_end;
+ data[10] = extended_strut.bottom_start;
+ data[11] = extended_strut.bottom_end;
+
+ XChangeProperty(p->display, p->window, net_wm_extended_strut, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) data, 12);
+}
+
+
+void NETWinInfo::setStrut(NETStrut strut) {
+ if (role != Client) return;
+
+ p->strut = strut;
+
+ long data[4];
+ data[0] = strut.left;
+ data[1] = strut.right;
+ data[2] = strut.top;
+ data[3] = strut.bottom;
+
+ XChangeProperty(p->display, p->window, net_wm_strut, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) data, 4);
+}
+
+
+void NETWinInfo::setState(unsigned long state, unsigned long mask) {
+ if (p->mapping_state_dirty)
+ updateWMState();
+
+ // setState() needs to know the current state, so read it even if not requested
+ if( ( p->properties[ PROTOCOLS ] & WMState ) == 0 ) {
+ p->properties[ PROTOCOLS ] |= WMState;
+ unsigned long props[ PROPERTIES_SIZE ] = { WMState, 0 };
+ assert( PROPERTIES_SIZE == 2 ); // add elements above
+ update( props );
+ p->properties[ PROTOCOLS ] &= ~WMState;
+ }
+
+ if (role == Client && p->mapping_state != Withdrawn) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::setState (0x%lx, 0x%lx) (Client)\n",
+ state, mask);
+#endif // NETWMDEBUG
+
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_wm_state;
+ e.xclient.display = p->display;
+ e.xclient.window = p->window;
+ e.xclient.format = 32;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ if ((mask & Modal) && ((p->state & Modal) != (state & Modal))) {
+ e.xclient.data.l[0] = (state & Modal) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_modal;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & Sticky) && ((p->state & Sticky) != (state & Sticky))) {
+ e.xclient.data.l[0] = (state & Sticky) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_sticky;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & Max) && (( (p->state&mask) & Max) != (state & Max))) {
+
+ unsigned long wishstate = (p->state & ~mask) | (state & mask);
+ if ( ( (wishstate & MaxHoriz) != (p->state & MaxHoriz) )
+ && ( (wishstate & MaxVert) != (p->state & MaxVert) ) ) {
+ if ( (wishstate & Max) == Max ) {
+ e.xclient.data.l[0] = 1;
+ e.xclient.data.l[1] = net_wm_state_max_horiz;
+ e.xclient.data.l[2] = net_wm_state_max_vert;
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ } else if ( (wishstate & Max) == 0 ) {
+ e.xclient.data.l[0] = 0;
+ e.xclient.data.l[1] = net_wm_state_max_horiz;
+ e.xclient.data.l[2] = net_wm_state_max_vert;
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ } else {
+ e.xclient.data.l[0] = ( wishstate & MaxHoriz ) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_max_horiz;
+ e.xclient.data.l[2] = 0;
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ e.xclient.data.l[0] = ( wishstate & MaxVert ) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_max_vert;
+ e.xclient.data.l[2] = 0;
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+ } else if ( (wishstate & MaxVert) != (p->state & MaxVert) ) {
+ e.xclient.data.l[0] = ( wishstate & MaxVert ) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_max_vert;
+ e.xclient.data.l[2] = 0;
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ } else if ( (wishstate & MaxHoriz) != (p->state & MaxHoriz) ) {
+ e.xclient.data.l[0] = ( wishstate & MaxHoriz ) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_max_horiz;
+ e.xclient.data.l[2] = 0;
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+ }
+
+ if ((mask & Shaded) && ((p->state & Shaded) != (state & Shaded))) {
+ e.xclient.data.l[0] = (state & Shaded) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_shaded;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & SkipTaskbar) &&
+ ((p->state & SkipTaskbar) != (state & SkipTaskbar))) {
+ e.xclient.data.l[0] = (state & SkipTaskbar) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_skip_taskbar;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & SkipPager) &&
+ ((p->state & SkipPager) != (state & SkipPager))) {
+ e.xclient.data.l[0] = (state & SkipPager) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_skip_pager;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & Hidden) &&
+ ((p->state & Hidden) != (state & Hidden))) {
+ e.xclient.data.l[0] = (state & Hidden) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_hidden;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & FullScreen) &&
+ ((p->state & FullScreen) != (state & FullScreen))) {
+ e.xclient.data.l[0] = (state & FullScreen) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_fullscreen;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & KeepAbove) &&
+ ((p->state & KeepAbove) != (state & KeepAbove))) {
+ e.xclient.data.l[0] = (state & KeepAbove) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_above;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & KeepBelow) &&
+ ((p->state & KeepBelow) != (state & KeepBelow))) {
+ e.xclient.data.l[0] = (state & KeepBelow) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_below;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & StaysOnTop) && ((p->state & StaysOnTop) != (state & StaysOnTop))) {
+ e.xclient.data.l[0] = (state & StaysOnTop) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_stays_on_top;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ if ((mask & DemandsAttention) &&
+ ((p->state & DemandsAttention) != (state & DemandsAttention))) {
+ e.xclient.data.l[0] = (state & DemandsAttention) ? 1 : 0;
+ e.xclient.data.l[1] = net_wm_state_demands_attention;
+ e.xclient.data.l[2] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ }
+
+ } else {
+ p->state &= ~mask;
+ p->state |= state;
+
+ long data[50];
+ int count = 0;
+
+ // hints
+ if (p->state & Modal) data[count++] = net_wm_state_modal;
+ if (p->state & MaxVert) data[count++] = net_wm_state_max_vert;
+ if (p->state & MaxHoriz) data[count++] = net_wm_state_max_horiz;
+ if (p->state & Shaded) data[count++] = net_wm_state_shaded;
+ if (p->state & Hidden) data[count++] = net_wm_state_hidden;
+ if (p->state & FullScreen) data[count++] = net_wm_state_fullscreen;
+ if (p->state & DemandsAttention) data[count++] = net_wm_state_demands_attention;
+
+ // policy
+ if (p->state & KeepAbove) data[count++] = net_wm_state_above;
+ if (p->state & KeepBelow) data[count++] = net_wm_state_below;
+ if (p->state & StaysOnTop) data[count++] = net_wm_state_stays_on_top;
+ if (p->state & Sticky) data[count++] = net_wm_state_sticky;
+ if (p->state & SkipTaskbar) data[count++] = net_wm_state_skip_taskbar;
+ if (p->state & SkipPager) data[count++] = net_wm_state_skip_pager;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::setState: setting state property (%d)\n", count);
+ for (int i = 0; i < count; i++) {
+ char* data_ret = XGetAtomName(p->display, (Atom) data[i]);
+ fprintf(stderr, "NETWinInfo::setState: state %ld '%s'\n",
+ data[i], data_ret);
+ if ( data_ret )
+ XFree( data_ret );
+ }
+
+#endif
+
+ XChangeProperty(p->display, p->window, net_wm_state, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) data, count);
+ }
+}
+
+
+void NETWinInfo::setWindowType(WindowType type) {
+ if (role != Client) return;
+
+ int len;
+ long data[2];
+
+ switch (type) {
+ case Override:
+ // spec extension: override window type. we must comply with the spec
+ // and provide a fall back (normal seems best)
+ data[0] = kde_net_wm_window_type_override;
+ data[1] = net_wm_window_type_normal;
+ len = 2;
+ break;
+
+ case Dialog:
+ data[0] = net_wm_window_type_dialog;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case Menu:
+ data[0] = net_wm_window_type_menu;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case TopMenu:
+ // spec extension: override window type. we must comply with the spec
+ // and provide a fall back (dock seems best)
+ data[0] = kde_net_wm_window_type_topmenu;
+ data[1] = net_wm_window_type_dock;
+ len = 2;
+ break;
+
+ case Tool:
+ data[0] = net_wm_window_type_toolbar;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case Dock:
+ data[0] = net_wm_window_type_dock;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case Desktop:
+ data[0] = net_wm_window_type_desktop;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case Utility:
+ data[0] = net_wm_window_type_utility;
+ data[1] = net_wm_window_type_dialog; // fallback for old netwm version
+ len = 2;
+ break;
+
+ case Splash:
+ data[0] = net_wm_window_type_splash;
+ data[1] = net_wm_window_type_dock; // fallback (dock seems best)
+ len = 2;
+ break;
+
+ case DropdownMenu:
+ data[0] = net_wm_window_type_dropdown_menu;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case PopupMenu:
+ data[0] = net_wm_window_type_popup_menu;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case Tooltip:
+ data[0] = net_wm_window_type_tooltip;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case Notification:
+ data[0] = net_wm_window_type_notification;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case ComboBox:
+ data[0] = net_wm_window_type_combobox;
+ data[1] = None;
+ len = 1;
+ break;
+
+ case DNDIcon:
+ data[0] = net_wm_window_type_dnd;
+ data[1] = None;
+ len = 1;
+ break;
+
+ default:
+ case Normal:
+ data[0] = net_wm_window_type_normal;
+ data[1] = None;
+ len = 1;
+ break;
+ }
+
+ XChangeProperty(p->display, p->window, net_wm_window_type, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) &data, len);
+}
+
+
+void NETWinInfo::setName(const char *name) {
+ if (role != Client) return;
+
+ delete [] p->name;
+ p->name = nstrdup(name);
+ if( p->name[ 0 ] != '\0' )
+ XChangeProperty(p->display, p->window, net_wm_name, UTF8_STRING, 8,
+ PropModeReplace, (unsigned char *) p->name,
+ strlen(p->name));
+ else
+ XDeleteProperty(p->display, p->window, net_wm_name);
+}
+
+
+void NETWinInfo::setVisibleName(const char *visibleName) {
+ if (role != WindowManager) return;
+
+ delete [] p->visible_name;
+ p->visible_name = nstrdup(visibleName);
+ if( p->visible_name[ 0 ] != '\0' )
+ XChangeProperty(p->display, p->window, net_wm_visible_name, UTF8_STRING, 8,
+ PropModeReplace, (unsigned char *) p->visible_name,
+ strlen(p->visible_name));
+ else
+ XDeleteProperty(p->display, p->window, net_wm_visible_name);
+}
+
+
+void NETWinInfo::setIconName(const char *iconName) {
+ if (role != Client) return;
+
+ delete [] p->icon_name;
+ p->icon_name = nstrdup(iconName);
+ if( p->icon_name[ 0 ] != '\0' )
+ XChangeProperty(p->display, p->window, net_wm_icon_name, UTF8_STRING, 8,
+ PropModeReplace, (unsigned char *) p->icon_name,
+ strlen(p->icon_name));
+ else
+ XDeleteProperty(p->display, p->window, net_wm_icon_name);
+}
+
+
+void NETWinInfo::setVisibleIconName(const char *visibleIconName) {
+ if (role != WindowManager) return;
+
+ delete [] p->visible_icon_name;
+ p->visible_icon_name = nstrdup(visibleIconName);
+ if( p->visible_icon_name[ 0 ] != '\0' )
+ XChangeProperty(p->display, p->window, net_wm_visible_icon_name, UTF8_STRING, 8,
+ PropModeReplace, (unsigned char *) p->visible_icon_name,
+ strlen(p->visible_icon_name));
+ else
+ XDeleteProperty(p->display, p->window, net_wm_visible_icon_name);
+}
+
+
+void NETWinInfo::setDesktop(int desktop) {
+ if (p->mapping_state_dirty)
+ updateWMState();
+
+ if (role == Client && p->mapping_state != Withdrawn) {
+ // we only send a ClientMessage if we are 1) a client and 2) managed
+
+ if ( desktop == 0 )
+ return; // we can't do that while being managed
+
+ XEvent e;
+
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = net_wm_desktop;
+ e.xclient.display = p->display;
+ e.xclient.window = p->window;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = desktop == OnAllDesktops ? OnAllDesktops : desktop - 1;
+ e.xclient.data.l[1] = 0l;
+ e.xclient.data.l[2] = 0l;
+ e.xclient.data.l[3] = 0l;
+ e.xclient.data.l[4] = 0l;
+
+ XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e);
+ } else {
+ // otherwise we just set or remove the property directly
+ p->desktop = desktop;
+ long d = desktop;
+
+ if ( d != OnAllDesktops ) {
+ if ( d == 0 ) {
+ XDeleteProperty( p->display, p->window, net_wm_desktop );
+ return;
+ }
+
+ d -= 1;
+ }
+
+ XChangeProperty(p->display, p->window, net_wm_desktop, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &d, 1);
+ }
+}
+
+
+void NETWinInfo::setPid(int pid) {
+ if (role != Client) return;
+
+ p->pid = pid;
+ long d = pid;
+ XChangeProperty(p->display, p->window, net_wm_pid, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &d, 1);
+}
+
+
+void NETWinInfo::setHandledIcons(Bool handled) {
+ if (role != Client) return;
+
+ p->handled_icons = handled;
+ long d = handled;
+ XChangeProperty(p->display, p->window, net_wm_handled_icons, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &d, 1);
+}
+
+void NETWinInfo::setStartupId(const char* id) {
+ if (role != Client) return;
+
+ delete[] p->startup_id;
+ p->startup_id = nstrdup(id);
+ XChangeProperty(p->display, p->window, net_startup_id, UTF8_STRING, 8,
+ PropModeReplace, reinterpret_cast< unsigned char* >( p->startup_id ),
+ strlen( p->startup_id ));
+}
+
+void NETWinInfo::setAllowedActions( unsigned long actions ) {
+ if( role != WindowManager )
+ return;
+ long data[50];
+ int count = 0;
+
+ p->allowed_actions = actions;
+ if (p->allowed_actions & ActionMove) data[count++] = net_wm_action_move;
+ if (p->allowed_actions & ActionResize) data[count++] = net_wm_action_resize;
+ if (p->allowed_actions & ActionMinimize) data[count++] = net_wm_action_minimize;
+ if (p->allowed_actions & ActionShade) data[count++] = net_wm_action_shade;
+ if (p->allowed_actions & ActionStick) data[count++] = net_wm_action_stick;
+ if (p->allowed_actions & ActionMaxVert) data[count++] = net_wm_action_max_vert;
+ if (p->allowed_actions & ActionMaxHoriz) data[count++] = net_wm_action_max_horiz;
+ if (p->allowed_actions & ActionFullScreen) data[count++] = net_wm_action_fullscreen;
+ if (p->allowed_actions & ActionChangeDesktop) data[count++] = net_wm_action_change_desk;
+ if (p->allowed_actions & ActionClose) data[count++] = net_wm_action_close;
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::setAllowedActions: setting property (%d)\n", count);
+ for (int i = 0; i < count; i++) {
+ char* data_ret = XGetAtomName(p->display, (Atom) data[i]);
+ fprintf(stderr, "NETWinInfo::setAllowedActions: action %ld '%s'\n",
+ data[i], data_ret);
+ if ( data_ret )
+ XFree(data_ret);
+ }
+#endif
+
+ XChangeProperty(p->display, p->window, net_wm_allowed_actions, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) data, count);
+}
+
+void NETWinInfo::setKDESystemTrayWinFor(Window window) {
+ if (role != Client) return;
+
+ p->kde_system_tray_win_for = window;
+ XChangeProperty(p->display, p->window, kde_net_wm_system_tray_window_for,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(p->kde_system_tray_win_for), 1);
+}
+
+
+void NETWinInfo::setKDEFrameStrut(NETStrut strut) {
+ setFrameExtents( strut );
+}
+
+void NETWinInfo::setFrameExtents(NETStrut strut) {
+ if (role != WindowManager) return;
+
+ p->frame_strut = strut;
+
+ long d[4];
+ d[0] = strut.left;
+ d[1] = strut.right;
+ d[2] = strut.top;
+ d[3] = strut.bottom;
+
+ XChangeProperty(p->display, p->window, net_frame_extents, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) d, 4);
+ XChangeProperty(p->display, p->window, kde_net_wm_frame_strut, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) d, 4);
+}
+
+
+void NETWinInfo::kdeGeometry(NETRect& frame, NETRect& window) {
+ if (p->win_geom.size.width == 0 || p->win_geom.size.height == 0) {
+ Window unused;
+ int x, y;
+ unsigned int w, h, junk;
+ XGetGeometry(p->display, p->window, &unused, &x, &y, &w, &h, &junk, &junk);
+ XTranslateCoordinates(p->display, p->window, p->root, 0, 0, &x, &y, &unused
+ );
+
+ p->win_geom.pos.x = x;
+ p->win_geom.pos.y = y;
+
+ p->win_geom.size.width = w;
+ p->win_geom.size.height = h;
+ }
+// TODO try to work also without _KDE_NET_WM_FRAME_STRUT
+ window = p->win_geom;
+
+ frame.pos.x = window.pos.x - p->frame_strut.left;
+ frame.pos.y = window.pos.y - p->frame_strut.top;
+ frame.size.width = window.size.width + p->frame_strut.left + p->frame_strut.right;
+ frame.size.height = window.size.height + p->frame_strut.top + p->frame_strut.bottom;
+}
+
+
+NETIcon NETWinInfo::icon(int width, int height) const {
+ return iconInternal( p->icons, p->icon_count, width, height );
+}
+
+NETIcon NETWinInfo::iconInternal(NETRArray<NETIcon>& icons, int icon_count, int width, int height) const {
+ NETIcon result;
+
+ if ( !icon_count ) {
+ result.size.width = 0;
+ result.size.height = 0;
+ result.data = 0;
+ return result;
+ }
+
+ // find the largest icon
+ result = icons[0];
+ for (int i = 1; i < icons.size(); i++) {
+ if( icons[i].size.width >= result.size.width &&
+ icons[i].size.height >= result.size.height )
+ result = icons[i];
+ }
+
+ // return the largest icon if w and h are -1
+ if (width == -1 && height == -1) return result;
+
+ // find the icon that's closest in size to w x h...
+ for (int i = 0; i < icons.size(); i++) {
+ if ((icons[i].size.width >= width &&
+ icons[i].size.width < result.size.width) &&
+ (icons[i].size.height >= height &&
+ icons[i].size.height < result.size.height))
+ result = icons[i];
+ }
+
+ return result;
+}
+
+void NETWinInfo::setUserTime( Time time ) {
+ if (role != Client) return;
+
+ p->user_time = time;
+ long d = time;
+ XChangeProperty(p->display, p->window, net_wm_user_time, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) &d, 1);
+}
+
+
+unsigned long NETWinInfo::event(XEvent *ev )
+{
+ unsigned long props[ 1 ];
+ event( ev, props, 1 );
+ return props[ 0 ];
+}
+
+void NETWinInfo::event(XEvent *event, unsigned long* properties, int properties_size ) {
+ unsigned long props[ PROPERTIES_SIZE ] = { 0, 0 };
+ assert( PROPERTIES_SIZE == 2 ); // add elements above
+ unsigned long& dirty = props[ PROTOCOLS ];
+ unsigned long& dirty2 = props[ PROTOCOLS2 ];
+ bool do_update = false;
+
+ if (role == WindowManager && event->type == ClientMessage &&
+ event->xclient.format == 32) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::event: handling ClientMessage event\n");
+#endif // NETWMDEBUG
+
+ if (event->xclient.message_type == net_wm_state) {
+ dirty = WMState;
+
+ // we need to generate a change mask
+
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETWinInfo::event: state client message, getting new state/mask\n");
+#endif
+
+ int i;
+ long state = 0, mask = 0;
+
+ for (i = 1; i < 3; i++) {
+#ifdef NETWMDEBUG
+ char* debug_txt = XGetAtomName(p->display, (Atom) event->xclient.data.l[i]);
+ fprintf(stderr, "NETWinInfo::event: message %ld '%s'\n",
+ event->xclient.data.l[i], debug_txt );
+ if ( debug_txt )
+ XFree( debug_txt );
+#endif
+
+ if ((Atom) event->xclient.data.l[i] == net_wm_state_modal)
+ mask |= Modal;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_sticky)
+ mask |= Sticky;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_max_vert)
+ mask |= MaxVert;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_max_horiz)
+ mask |= MaxHoriz;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_shaded)
+ mask |= Shaded;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_skip_taskbar)
+ mask |= SkipTaskbar;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_skip_pager)
+ mask |= SkipPager;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_hidden)
+ mask |= Hidden;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_fullscreen)
+ mask |= FullScreen;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_above)
+ mask |= KeepAbove;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_below)
+ mask |= KeepBelow;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_demands_attention)
+ mask |= DemandsAttention;
+ else if ((Atom) event->xclient.data.l[i] == net_wm_state_stays_on_top)
+ mask |= StaysOnTop;
+ }
+
+ // when removing, we just leave newstate == 0
+ switch (event->xclient.data.l[0]) {
+ case 1: // set
+ // to set... the change state should be the same as the mask
+ state = mask;
+ break;
+
+ case 2: // toggle
+ // to toggle, we need to xor the current state with the new state
+ state = (p->state & mask) ^ mask;
+ break;
+
+ default:
+ // to clear state, the new state should stay zero
+ ;
+ }
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::event: calling changeState(%lx, %lx)\n",
+ state, mask);
+#endif
+
+ changeState(state, mask);
+ } else if (event->xclient.message_type == net_wm_desktop) {
+ dirty = WMDesktop;
+
+ if( event->xclient.data.l[0] == OnAllDesktops )
+ changeDesktop( OnAllDesktops );
+ else
+ changeDesktop(event->xclient.data.l[0] + 1);
+ }
+ }
+
+ if (event->type == PropertyNotify) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::event: handling PropertyNotify event\n");
+#endif
+
+ XEvent pe = *event;
+
+ Bool done = False;
+ Bool compaction = False;
+ while (! done) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::event: loop fire\n");
+#endif
+
+ if (pe.xproperty.atom == net_wm_name)
+ dirty |= WMName;
+ else if (pe.xproperty.atom == net_wm_visible_name)
+ dirty |= WMVisibleName;
+ else if (pe.xproperty.atom == net_wm_desktop)
+ dirty |= WMDesktop;
+ else if (pe.xproperty.atom == net_wm_window_type)
+ dirty |=WMWindowType;
+ else if (pe.xproperty.atom == net_wm_state)
+ dirty |= WMState;
+ else if (pe.xproperty.atom == net_wm_strut)
+ dirty |= WMStrut;
+ else if (pe.xproperty.atom == net_wm_extended_strut)
+ dirty2 |= WM2ExtendedStrut;
+ else if (pe.xproperty.atom == net_wm_icon_geometry)
+ dirty |= WMIconGeometry;
+ else if (pe.xproperty.atom == net_wm_icon)
+ dirty |= WMIcon;
+ else if (pe.xproperty.atom == net_wm_pid)
+ dirty |= WMPid;
+ else if (pe.xproperty.atom == net_wm_handled_icons)
+ dirty |= WMHandledIcons;
+ else if (pe.xproperty.atom == net_startup_id)
+ dirty2 |= WM2StartupId;
+ else if (pe.xproperty.atom == net_wm_allowed_actions)
+ dirty2 |= WM2AllowedActions;
+ else if (pe.xproperty.atom == kde_net_wm_system_tray_window_for)
+ dirty |= WMKDESystemTrayWinFor;
+ else if (pe.xproperty.atom == xa_wm_state)
+ dirty |= XAWMState;
+ else if (pe.xproperty.atom == net_frame_extents)
+ dirty |= WMFrameExtents;
+ else if (pe.xproperty.atom == kde_net_wm_frame_strut)
+ dirty |= WMKDEFrameStrut;
+ else if (pe.xproperty.atom == net_wm_icon_name)
+ dirty |= WMIconName;
+ else if (pe.xproperty.atom == net_wm_visible_icon_name)
+ dirty |= WMVisibleIconName;
+ else if (pe.xproperty.atom == net_wm_user_time)
+ dirty2 |= WM2UserTime;
+ else if (pe.xproperty.atom == XA_WM_HINTS)
+ dirty2 |= WM2GroupLeader;
+ else if (pe.xproperty.atom == XA_WM_TRANSIENT_FOR)
+ dirty2 |= WM2TransientFor;
+ else if (pe.xproperty.atom == XA_WM_CLASS)
+ dirty2 |= WM2WindowClass;
+ else if (pe.xproperty.atom == wm_window_role)
+ dirty2 |= WM2WindowRole;
+ else if (pe.xproperty.atom == XA_WM_CLIENT_MACHINE)
+ dirty2 |= WM2ClientMachine;
+ else {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::event: putting back event and breaking\n");
+#endif
+
+ if ( compaction )
+ XPutBackEvent(p->display, &pe);
+ break;
+ }
+
+ if (XCheckTypedWindowEvent(p->display, p->window, PropertyNotify, &pe) )
+ compaction = True;
+ else
+ break;
+ }
+
+ do_update = true;
+ } else if (event->type == ConfigureNotify) {
+
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::event: handling ConfigureNotify event\n");
+#endif
+
+ dirty |= WMGeometry;
+
+ // update window geometry
+ p->win_geom.pos.x = event->xconfigure.x;
+ p->win_geom.pos.y = event->xconfigure.y;
+ p->win_geom.size.width = event->xconfigure.width;
+ p->win_geom.size.height = event->xconfigure.height;
+ }
+
+ if( do_update )
+ update( props );
+
+ if( properties_size > PROPERTIES_SIZE )
+ properties_size = PROPERTIES_SIZE;
+ for( int i = 0;
+ i < properties_size;
+ ++i )
+ properties[ i ] = props[ i ];
+}
+
+void NETWinInfo::updateWMState() {
+ unsigned long props[ PROPERTIES_SIZE ] = { XAWMState, 0 };
+ assert( PROPERTIES_SIZE == 2 ); // add elements above
+ update( props );
+}
+
+void NETWinInfo::update(const unsigned long dirty_props[]) {
+ Atom type_ret;
+ int format_ret;
+ unsigned long nitems_ret, unused;
+ unsigned char *data_ret;
+ unsigned long props[ PROPERTIES_SIZE ];
+ for( int i = 0;
+ i < PROPERTIES_SIZE;
+ ++i )
+ props[ i ] = dirty_props[ i ] & p->properties[ i ];
+ const unsigned long& dirty = props[ PROTOCOLS ];
+ const unsigned long& dirty2 = props[ PROTOCOLS2 ];
+
+ // we *always* want to update WM_STATE if set in dirty_props
+ if( dirty_props[ PROTOCOLS ] & XAWMState )
+ props[ PROTOCOLS ] |= XAWMState;
+
+ if (dirty & XAWMState) {
+ p->mapping_state = Withdrawn;
+ if (XGetWindowProperty(p->display, p->window, xa_wm_state, 0l, 1l,
+ False, xa_wm_state, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == xa_wm_state && format_ret == 32 &&
+ nitems_ret == 1) {
+ long *state = (long *) data_ret;
+
+ switch(*state) {
+ case IconicState:
+ p->mapping_state = Iconic;
+ break;
+ case NormalState:
+ p->mapping_state = Visible;
+ break;
+ case WithdrawnState:
+ default:
+ p->mapping_state = Withdrawn;
+ break;
+ }
+
+ p->mapping_state_dirty = False;
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMState) {
+ p->state = 0;
+ if (XGetWindowProperty(p->display, p->window, net_wm_state, 0l, 2048l,
+ False, XA_ATOM, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_ATOM && format_ret == 32 && nitems_ret > 0) {
+ // determine window state
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::update: updating window state (%ld)\n",
+ nitems_ret);
+#endif
+
+ long *states = (long *) data_ret;
+ unsigned long count;
+
+ for (count = 0; count < nitems_ret; count++) {
+#ifdef NETWMDEBUG
+ char* data_ret = XGetAtomName(p->display, (Atom) states[count]);
+ fprintf(stderr,
+ "NETWinInfo::update: adding window state %ld '%s'\n",
+ states[count], data_ret );
+ if ( data_ret )
+ XFree( data_ret );
+#endif
+
+ if ((Atom) states[count] == net_wm_state_modal)
+ p->state |= Modal;
+ else if ((Atom) states[count] == net_wm_state_sticky)
+ p->state |= Sticky;
+ else if ((Atom) states[count] == net_wm_state_max_vert)
+ p->state |= MaxVert;
+ else if ((Atom) states[count] == net_wm_state_max_horiz)
+ p->state |= MaxHoriz;
+ else if ((Atom) states[count] == net_wm_state_shaded)
+ p->state |= Shaded;
+ else if ((Atom) states[count] == net_wm_state_skip_taskbar)
+ p->state |= SkipTaskbar;
+ else if ((Atom) states[count] == net_wm_state_skip_pager)
+ p->state |= SkipPager;
+ else if ((Atom) states[count] == net_wm_state_hidden)
+ p->state |= Hidden;
+ else if ((Atom) states[count] == net_wm_state_fullscreen)
+ p->state |= FullScreen;
+ else if ((Atom) states[count] == net_wm_state_above)
+ p->state |= KeepAbove;
+ else if ((Atom) states[count] == net_wm_state_below)
+ p->state |= KeepBelow;
+ else if ((Atom) states[count] == net_wm_state_demands_attention)
+ p->state |= DemandsAttention;
+ else if ((Atom) states[count] == net_wm_state_stays_on_top)
+ p->state |= StaysOnTop;
+ }
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMDesktop) {
+ p->desktop = 0;
+ if (XGetWindowProperty(p->display, p->window, net_wm_desktop, 0l, 1l,
+ False, XA_CARDINAL, &type_ret,
+ &format_ret, &nitems_ret,
+ &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 &&
+ nitems_ret == 1) {
+ p->desktop = *((long *) data_ret);
+ if ((signed) p->desktop != OnAllDesktops)
+ p->desktop++;
+
+ if ( p->desktop == 0 )
+ p->desktop = OnAllDesktops;
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMName) {
+ delete[] p->name;
+ p->name = NULL;
+ if (XGetWindowProperty(p->display, p->window, net_wm_name, 0l,
+ MAX_PROP_SIZE, False, UTF8_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) {
+ p->name = nstrndup((const char *) data_ret, nitems_ret);
+ }
+
+ if( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMVisibleName) {
+ delete[] p->visible_name;
+ p->visible_name = NULL;
+ if (XGetWindowProperty(p->display, p->window, net_wm_visible_name, 0l,
+ MAX_PROP_SIZE, False, UTF8_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) {
+ p->visible_name = nstrndup((const char *) data_ret, nitems_ret);
+ }
+
+ if( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMIconName) {
+ delete[] p->icon_name;
+ p->icon_name = NULL;
+ if (XGetWindowProperty(p->display, p->window, net_wm_icon_name, 0l,
+ MAX_PROP_SIZE, False, UTF8_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) {
+ p->icon_name = nstrndup((const char *) data_ret, nitems_ret);
+ }
+
+ if( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMVisibleIconName)
+ {
+ delete[] p->visible_icon_name;
+ p->visible_icon_name = NULL;
+ if (XGetWindowProperty(p->display, p->window, net_wm_visible_icon_name, 0l,
+ MAX_PROP_SIZE, False, UTF8_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) {
+ p->visible_icon_name = nstrndup((const char *) data_ret, nitems_ret);
+ }
+
+ if( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMWindowType) {
+ p->types.reset();
+ p->types[ 0 ] = Unknown;
+ p->has_net_support = false;
+ if (XGetWindowProperty(p->display, p->window, net_wm_window_type, 0l, 2048l,
+ False, XA_ATOM, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_ATOM && format_ret == 32 && nitems_ret > 0) {
+ // determine the window type
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::update: getting window type (%ld)\n",
+ nitems_ret);
+#endif
+
+ p->has_net_support = true;
+
+ unsigned long count = 0;
+ long *types = (long *) data_ret;
+ int pos = 0;
+
+ while (count < nitems_ret) {
+ // remember all window types we know
+#ifdef NETWMDEBUG
+ char* debug_type = XGetAtomName(p->display, (Atom) types[count]);
+ fprintf(stderr,
+ "NETWinInfo::update: examining window type %ld %s\n",
+ types[count], debug_type );
+ if ( debug_type )
+ XFree( debug_type );
+#endif
+
+ if ((Atom) types[count] == net_wm_window_type_normal)
+ p->types[ pos++ ] = Normal;
+ else if ((Atom) types[count] == net_wm_window_type_desktop)
+ p->types[ pos++ ] = Desktop;
+ else if ((Atom) types[count] == net_wm_window_type_dock)
+ p->types[ pos++ ] = Dock;
+ else if ((Atom) types[count] == net_wm_window_type_toolbar)
+ p->types[ pos++ ] = Tool;
+ else if ((Atom) types[count] == net_wm_window_type_menu)
+ p->types[ pos++ ] = Menu;
+ else if ((Atom) types[count] == net_wm_window_type_dialog)
+ p->types[ pos++ ] = Dialog;
+ else if ((Atom) types[count] == net_wm_window_type_utility)
+ p->types[ pos++ ] = Utility;
+ else if ((Atom) types[count] == net_wm_window_type_splash)
+ p->types[ pos++ ] = Splash;
+ else if ((Atom) types[count] == net_wm_window_type_dropdown_menu)
+ p->types[ pos++ ] = DropdownMenu;
+ else if ((Atom) types[count] == net_wm_window_type_popup_menu)
+ p->types[ pos++ ] = PopupMenu;
+ else if ((Atom) types[count] == net_wm_window_type_tooltip)
+ p->types[ pos++ ] = Tooltip;
+ else if ((Atom) types[count] == net_wm_window_type_notification)
+ p->types[ pos++ ] = Notification;
+ else if ((Atom) types[count] == net_wm_window_type_combobox)
+ p->types[ pos++ ] = ComboBox;
+ else if ((Atom) types[count] == net_wm_window_type_dnd)
+ p->types[ pos++ ] = DNDIcon;
+ else if ((Atom) types[count] == kde_net_wm_window_type_override)
+ p->types[ pos++ ] = Override;
+ else if ((Atom) types[count] == kde_net_wm_window_type_topmenu)
+ p->types[ pos++ ] = TopMenu;
+
+ count++;
+ }
+ }
+
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMStrut) {
+ p->strut = NETStrut();
+ if (XGetWindowProperty(p->display, p->window, net_wm_strut, 0l, 4l,
+ False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 &&
+ nitems_ret == 4) {
+ long *d = (long *) data_ret;
+ p->strut.left = d[0];
+ p->strut.right = d[1];
+ p->strut.top = d[2];
+ p->strut.bottom = d[3];
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty2 & WM2ExtendedStrut) {
+ p->extended_strut = NETExtendedStrut();
+ if (XGetWindowProperty(p->display, p->window, net_wm_extended_strut, 0l, 12l,
+ False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 &&
+ nitems_ret == 12) {
+ long *d = (long *) data_ret;
+ p->extended_strut.left_width = d[0];
+ p->extended_strut.right_width = d[1];
+ p->extended_strut.top_width = d[2];
+ p->extended_strut.bottom_width = d[3];
+ p->extended_strut.left_start = d[4];
+ p->extended_strut.left_end = d[5];
+ p->extended_strut.right_start = d[6];
+ p->extended_strut.right_end = d[7];
+ p->extended_strut.top_start = d[8];
+ p->extended_strut.top_end = d[9];
+ p->extended_strut.bottom_start = d[10];
+ p->extended_strut.bottom_end = d[11];
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMIconGeometry) {
+ p->icon_geom = NETRect();
+ if (XGetWindowProperty(p->display, p->window, net_wm_icon_geometry, 0l, 4l,
+ False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 &&
+ nitems_ret == 4) {
+ long *d = (long *) data_ret;
+ p->icon_geom.pos.x = d[0];
+ p->icon_geom.pos.y = d[1];
+ p->icon_geom.size.width = d[2];
+ p->icon_geom.size.height = d[3];
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMIcon) {
+ readIcon(p->display,p->window,net_wm_icon,p->icons,p->icon_count);
+ }
+
+ if (dirty & WMKDESystemTrayWinFor) {
+ p->kde_system_tray_win_for = 0;
+ if (XGetWindowProperty(p->display, p->window, kde_net_wm_system_tray_window_for,
+ 0l, 1l, False, XA_WINDOW, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_WINDOW && format_ret == 32 &&
+ nitems_ret == 1) {
+ p->kde_system_tray_win_for = *((Window *) data_ret);
+ if ( p->kde_system_tray_win_for == 0 )
+ p->kde_system_tray_win_for = p->root;
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMFrameExtents) {
+ p->frame_strut = NETStrut();
+ bool ok = false;
+ if (XGetWindowProperty(p->display, p->window, net_frame_extents,
+ 0l, 4l, False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret) == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 4) {
+ ok = true;
+ long *d = (long *) data_ret;
+
+ p->frame_strut.left = d[0];
+ p->frame_strut.right = d[1];
+ p->frame_strut.top = d[2];
+ p->frame_strut.bottom = d[3];
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ if (!ok && XGetWindowProperty(p->display, p->window, kde_net_wm_frame_strut,
+ 0l, 4l, False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret) == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 4) {
+ ok = true;
+ long *d = (long *) data_ret;
+
+ p->frame_strut.left = d[0];
+ p->frame_strut.right = d[1];
+ p->frame_strut.top = d[2];
+ p->frame_strut.bottom = d[3];
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty & WMPid) {
+ p->pid = 0;
+ if (XGetWindowProperty(p->display, p->window, net_wm_pid, 0l, 1l,
+ False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret) == Success) {
+ if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) {
+ p->pid = *((long *) data_ret);
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty2 & WM2StartupId)
+ {
+ delete[] p->startup_id;
+ p->startup_id = NULL;
+ if (XGetWindowProperty(p->display, p->window, net_startup_id, 0l,
+ MAX_PROP_SIZE, False, UTF8_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) {
+ p->startup_id = nstrndup((const char *) data_ret, nitems_ret);
+ }
+
+ if( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if( dirty2 & WM2AllowedActions ) {
+ p->allowed_actions = 0;
+ if (XGetWindowProperty(p->display, p->window, net_wm_allowed_actions, 0l, 2048l,
+ False, XA_ATOM, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_ATOM && format_ret == 32 && nitems_ret > 0) {
+ // determine actions
+#ifdef NETWMDEBUG
+ fprintf(stderr, "NETWinInfo::update: updating allowed actions (%ld)\n",
+ nitems_ret);
+#endif
+
+ long *actions = (long *) data_ret;
+ unsigned long count;
+
+ for (count = 0; count < nitems_ret; count++) {
+#ifdef NETWMDEBUG
+ fprintf(stderr,
+ "NETWinInfo::update: adding allowed action %ld '%s'\n",
+ actions[count],
+ XGetAtomName(p->display, (Atom) actions[count]));
+#endif
+
+ if ((Atom) actions[count] == net_wm_action_move)
+ p->allowed_actions |= ActionMove;
+ if ((Atom) actions[count] == net_wm_action_resize)
+ p->allowed_actions |= ActionResize;
+ if ((Atom) actions[count] == net_wm_action_minimize)
+ p->allowed_actions |= ActionMinimize;
+ if ((Atom) actions[count] == net_wm_action_shade)
+ p->allowed_actions |= ActionShade;
+ if ((Atom) actions[count] == net_wm_action_stick)
+ p->allowed_actions |= ActionStick;
+ if ((Atom) actions[count] == net_wm_action_max_vert)
+ p->allowed_actions |= ActionMaxVert;
+ if ((Atom) actions[count] == net_wm_action_max_horiz)
+ p->allowed_actions |= ActionMaxHoriz;
+ if ((Atom) actions[count] == net_wm_action_fullscreen)
+ p->allowed_actions |= ActionFullScreen;
+ if ((Atom) actions[count] == net_wm_action_change_desk)
+ p->allowed_actions |= ActionChangeDesktop;
+ if ((Atom) actions[count] == net_wm_action_close)
+ p->allowed_actions |= ActionClose;
+ }
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty2 & WM2UserTime) {
+ p->user_time = -1U;
+ if (XGetWindowProperty(p->display, p->window, net_wm_user_time, 0l, 1l,
+ False, XA_CARDINAL, &type_ret, &format_ret,
+ &nitems_ret, &unused, &data_ret) == Success) {
+ // don't do nitems_ret check - Qt does PropModeAppend to avoid API call for it
+ if (type_ret == XA_CARDINAL && format_ret == 32 /*&& nitems_ret == 1*/) {
+ p->user_time = *((long *) data_ret);
+ }
+ if ( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if (dirty2 & WM2TransientFor) {
+ p->transient_for = None;
+ XGetTransientForHint(p->display, p->window, &p->transient_for);
+ }
+
+ if (dirty2 & WM2GroupLeader) {
+ XWMHints *hints = XGetWMHints(p->display, p->window);
+ p->window_group = None;
+ if ( hints )
+ {
+ if( hints->flags & WindowGroupHint )
+ p->window_group = hints->window_group;
+ XFree( reinterpret_cast< char* >( hints ));
+ }
+ }
+
+ if( dirty2 & WM2WindowClass ) {
+ delete[] p->class_class;
+ delete[] p->class_name;
+ p->class_class = NULL;
+ p->class_name = NULL;
+ XClassHint hint;
+ if( XGetClassHint( p->display, p->window, &hint )) {
+ p->class_class = strdup( hint.res_class );
+ p->class_name = strdup( hint.res_name );
+ XFree( hint.res_class );
+ XFree( hint.res_name );
+ }
+ }
+
+ if( dirty2 & WM2WindowRole ) {
+ delete[] p->role;
+ p->role = NULL;
+ if (XGetWindowProperty(p->display, p->window, wm_window_role, 0l,
+ MAX_PROP_SIZE, False, XA_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_STRING && format_ret == 8 && nitems_ret > 0) {
+ p->role = nstrndup((const char *) data_ret, nitems_ret);
+ }
+ if( data_ret )
+ XFree(data_ret);
+ }
+ }
+
+ if( dirty2 & WM2ClientMachine ) {
+ delete[] p->client_machine;
+ p->client_machine = NULL;
+ if (XGetWindowProperty(p->display, p->window, XA_WM_CLIENT_MACHINE, 0l,
+ MAX_PROP_SIZE, False, XA_STRING, &type_ret,
+ &format_ret, &nitems_ret, &unused, &data_ret)
+ == Success) {
+ if (type_ret == XA_STRING && format_ret == 8 && nitems_ret > 0) {
+ p->client_machine = nstrndup((const char *) data_ret, nitems_ret);
+ }
+ if( data_ret )
+ XFree(data_ret);
+ }
+ }
+}
+
+
+NETRect NETWinInfo::iconGeometry() const {
+ return p->icon_geom;
+}
+
+
+unsigned long NETWinInfo::state() const {
+ return p->state;
+}
+
+
+NETStrut NETWinInfo::strut() const {
+ return p->strut;
+}
+
+NETExtendedStrut NETWinInfo::extendedStrut() const {
+ return p->extended_strut;
+}
+
+bool NET::typeMatchesMask( WindowType type, unsigned long mask ) {
+ switch( type ) {
+#define CHECK_TYPE_MASK( type ) \
+ case type: \
+ if( mask & type##Mask ) \
+ return true; \
+ break;
+ CHECK_TYPE_MASK( Normal )
+ CHECK_TYPE_MASK( Desktop )
+ CHECK_TYPE_MASK( Dock )
+ CHECK_TYPE_MASK( Toolbar )
+ CHECK_TYPE_MASK( Menu )
+ CHECK_TYPE_MASK( Dialog )
+ CHECK_TYPE_MASK( Override )
+ CHECK_TYPE_MASK( TopMenu )
+ CHECK_TYPE_MASK( Utility )
+ CHECK_TYPE_MASK( Splash )
+ CHECK_TYPE_MASK( DropdownMenu )
+ CHECK_TYPE_MASK( PopupMenu )
+ CHECK_TYPE_MASK( Tooltip )
+ CHECK_TYPE_MASK( Notification )
+ CHECK_TYPE_MASK( ComboBox )
+ CHECK_TYPE_MASK( DNDIcon )
+#undef CHECK_TYPE_MASK
+ default:
+ break;
+ }
+ return false;
+}
+
+NET::WindowType NETWinInfo::windowType( unsigned long supported_types ) const {
+ for( int i = 0;
+ i < p->types.size();
+ ++i ) {
+ // return the type only if the application supports it
+ if( typeMatchesMask( p->types[ i ], supported_types ))
+ return p->types[ i ];
+ }
+ return Unknown;
+}
+
+NET::WindowType NETWinInfo::windowType() const {
+ return p->types[ 0 ];
+}
+
+
+const char *NETWinInfo::name() const {
+ return p->name;
+}
+
+
+const char *NETWinInfo::visibleName() const {
+ return p->visible_name;
+}
+
+
+const char *NETWinInfo::iconName() const {
+ return p->icon_name;
+}
+
+
+const char *NETWinInfo::visibleIconName() const {
+ return p->visible_icon_name;
+}
+
+
+int NETWinInfo::desktop() const {
+ return p->desktop;
+}
+
+int NETWinInfo::pid() const {
+ return p->pid;
+}
+
+Time NETWinInfo::userTime() const {
+ return p->user_time;
+}
+
+const char* NETWinInfo::startupId() const {
+ return p->startup_id;
+}
+
+unsigned long NETWinInfo::allowedActions() const {
+ return p->allowed_actions;
+}
+
+bool NETWinInfo::hasNETSupport() const {
+ return p->has_net_support;
+}
+
+Window NETWinInfo::transientFor() const {
+ return p->transient_for;
+}
+
+Window NETWinInfo::groupLeader() const {
+ return p->window_group;
+}
+
+const char* NETWinInfo::windowClassClass() const {
+ return p->class_class;
+}
+
+const char* NETWinInfo::windowClassName() const {
+ return p->class_name;
+}
+
+const char* NETWinInfo::windowRole() const {
+ return p->role;
+}
+
+const char* NETWinInfo::clientMachine() const {
+ return p->client_machine;
+}
+
+Bool NETWinInfo::handledIcons() const {
+ return p->handled_icons;
+}
+
+
+Window NETWinInfo::kdeSystemTrayWinFor() const {
+ return p->kde_system_tray_win_for;
+}
+
+const unsigned long* NETWinInfo::passedProperties() const {
+ return p->properties;
+}
+
+unsigned long NETWinInfo::properties() const {
+ return p->properties[ PROTOCOLS ];
+}
+
+
+NET::MappingState NETWinInfo::mappingState() const {
+ return p->mapping_state;
+}
+
+void NETRootInfo::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void NETWinInfo::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+// Functions for X timestamp comparing. For Time being 32bit they're fairly simple
+// (the #if 0 part), but on 64bit architectures Time is 64bit unsigned long,
+// so there special care needs to be taken to always use only the lower 32bits.
+#if 0
+int NET::timestampCompare( Time time1, Time time2 ) // like strcmp()
+ {
+ if( time1 == time2 )
+ return 0;
+ return ( time1 - time2 ) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
+ }
+
+Time NET::timestampDiff( Time time1, Time time2 ) // returns time2 - time1
+ { // no need to handle wrapping?
+ return time2 - time1;
+ }
+#else
+int NET::timestampCompare( unsigned long time1_, unsigned long time2_ ) // like strcmp()
+ {
+ Q_UINT32 time1 = time1_;
+ Q_UINT32 time2 = time2_;
+ if( time1 == time2 )
+ return 0;
+ return Q_UINT32( time1 - time2 ) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
+ }
+
+int NET::timestampDiff( unsigned long time1_, unsigned long time2_ ) // returns time2 - time1
+ { // no need to handle wrapping?
+ Q_UINT32 time1 = time1_;
+ Q_UINT32 time2 = time2_;
+ return Q_UINT32( time2 - time1 );
+ }
+#endif
+
+
+#endif
diff --git a/kdecore/netwm.h b/kdecore/netwm.h
new file mode 100644
index 000000000..b7ccfd351
--- /dev/null
+++ b/kdecore/netwm.h
@@ -0,0 +1,1471 @@
+/*
+
+ Copyright (c) 2000 Troll Tech AS
+ Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
+
+ 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 OR COPYRIGHT HOLDERS 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.
+
+*/
+
+
+#ifndef __net_wm_h
+#define __net_wm_h
+
+#include "kdelibs_export.h"
+#include <qwidget.h>
+#ifdef Q_WS_X11
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#include "netwm_def.h"
+
+// forward declaration
+struct NETRootInfoPrivate;
+struct NETWinInfoPrivate;
+template <class Z> class NETRArray;
+
+
+/**
+ Common API for root window properties/protocols.
+
+ The NETRootInfo class provides a common API for clients and window managers
+ to set/read/change properties on the root window as defined by the NET Window
+ Manager Specification..
+
+ @author Bradley T. Hughes <bhughes@trolltech.com>
+ @see NET
+ @see NETWinInfo
+ @see KWin
+ **/
+
+class KDECORE_EXPORT NETRootInfo : public NET {
+public:
+ /**
+ Indexes for the properties array.
+ @since 3.2
+ **/
+ // update also NETRootInfoPrivate::properties[] size when extending this
+ enum { PROTOCOLS, WINDOW_TYPES, STATES, PROTOCOLS2, ACTIONS,
+ PROPERTIES_SIZE };
+
+ /**
+ Window Managers should use this constructor to create a NETRootInfo object,
+ which will be used to set/update information stored on the rootWindow.
+ The application role is automatically set to WindowManager
+ when using this constructor.
+
+ @param display An X11 Display struct.
+
+ @param supportWindow The Window id of the supportWindow. The supportWindow
+ must be created by the window manager as a child of the rootWindow. The
+ supportWindow must not be destroyed until the Window Manager exits.
+
+ @param wmName A string which should be the window manager's name (ie. "KWin"
+ or "Blackbox").
+
+ @param properties An array of elements listing all properties and protocols
+ the window manager supports. The elements contain OR'ed values of constants
+ from the NET base class, in the following order: [0]= NET::Property,
+ [1]= NET::WindowTypeMask (not NET::WindowType!), [2]= NET::State,
+ [3]= NET::Property2, [4]= NET::Action.
+ In future versions, the list may be extended. In case you pass less elements,
+ the missing ones will be replaced with default values.
+
+ @param properties_size The number of elements in the properties array.
+
+ @param screen For Window Managers that support multiple screen (ie.
+ "multiheaded") displays, the screen number may be explicitly defined. If
+ this argument is omitted, the default screen will be used.
+
+ @param doActivate true to activate the window
+
+ @since 3.2
+ **/
+ NETRootInfo(Display *display, Window supportWindow, const char *wmName,
+ const unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+
+ /**
+ @deprecated
+ This constructor differs from the above one only in the way it accepts
+ the list of supported properties. The properties argument is equivalent
+ to the first element of the properties array in the above constructor.
+ **/
+ NETRootInfo(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties, int screen = -1, bool doActivate = true) KDE_DEPRECATED;
+
+ /**
+ Clients should use this constructor to create a NETRootInfo object, which
+ will be used to query information set on the root window. The application
+ role is automatically set to Client when using this constructor.
+
+ @param display An X11 Display struct.
+
+ @param properties An array of elements listing all protocols the client
+ is interested in. The elements contain OR'ed values of constants
+ from the NET base class, in the following order: [0]= NET::Property,
+ [1]= NET::Property2.
+
+ @param properties_size The number of elements in the properties array.
+
+ @param screen For Clients that support multiple screen (ie. "multiheaded")
+ displays, the screen number may be explicitly defined. If this argument is
+ omitted, the default screen will be used.
+
+ @param doActivate true to activate the window
+
+ @since 3.2
+ **/
+ NETRootInfo(Display *display, const unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+
+ /**
+ This constructor differs from the above one only in the way it accepts
+ the list of supported properties. The properties argument is equivalent
+ to the first element of the properties array in the above constructor,
+ and therefore you cannot read all root window properties using it.
+ **/
+ NETRootInfo(Display *display, unsigned long properties, int screen = -1,
+ bool doActivate = true);
+
+ /**
+ Creates a shared copy of the specified NETRootInfo object.
+
+ @param rootinfo the NETRootInfo object to copy
+ **/
+ NETRootInfo(const NETRootInfo &rootinfo);
+
+ /**
+ Destroys the NETRootInfo object.
+ **/
+ virtual ~NETRootInfo();
+
+ /**
+ Returns the X11 Display struct used.
+
+ @return the X11 Display
+ **/
+ Display *x11Display() const;
+
+ /**
+ Returns the Window id of the rootWindow.
+
+ @return the id of the root window
+ **/
+ Window rootWindow() const;
+
+ /**
+ Returns the Window id of the supportWindow.
+
+ @return the id of the support window
+ **/
+ Window supportWindow() const;
+
+ /**
+ Returns the name of the Window Manager.
+
+ @return the name of the window manager
+ **/
+ const char *wmName() const;
+
+ /**
+ Returns the screenNumber.
+
+ @return the screen number
+ **/
+ int screenNumber() const;
+
+ /**
+ Returns true if the given property is supported by the window
+ manager. Note that for Client mode, NET::Supported needs
+ to be passed in the properties argument for this to work.
+ @since 3.2
+ **/
+ bool isSupported( NET::Property property ) const;
+ /**
+ @overload
+ @since 3.2
+ **/
+ bool isSupported( NET::Property2 property ) const;
+ /**
+ @overload
+ @since 3.2
+ **/
+ bool isSupported( NET::WindowType type ) const;
+ /**
+ @overload
+ @since 3.2
+ **/
+ bool isSupported( NET::State state ) const;
+
+ /**
+ @overload
+ @since 3.2
+ **/
+ bool isSupported( NET::Action action ) const;
+
+ /**
+ In the Window Manager mode, this is equivalent to the properties
+ argument passed to the constructor. In the Client mode, if
+ NET::Supported was passed in the properties argument, the returned
+ value is array of all protocols and properties supported
+ by the Window Manager. The elements of the array are the same
+ as they would be passed to the Window Manager mode constructor,
+ the size is the maximum array size the constructor accepts.
+
+ @since 3.2
+ **/
+ const unsigned long* supportedProperties() const;
+
+ /**
+ Returns the properties argument passed to the constructor.
+ The size is the maximum array size the constructor accepts.
+
+ @since 3.2
+ **/
+ // KDE4 better name?
+ const unsigned long* passedProperties() const;
+
+ /**
+ @deprecated
+
+ Returns an OR'ed list of protocols passed to the constructor.
+ For the constructor used by Window Managers, this is equivalent
+ to the first element of the properties argument, for the constructor
+ for Clients, it's the properties argument.
+
+ Clients willing to find out all properties and protocols supported
+ by the WindowManager should use supportedProperties().
+
+ @return an OR'ed list of protocols
+
+ @see NET::Property
+ **/
+ unsigned long supported() const KDE_DEPRECATED;
+
+ /**
+ Returns an array of Window id's, which contain all managed windows.
+
+ @return the array of Window id's
+
+ @see clientListCount()
+ **/
+ const Window *clientList() const;
+
+ /**
+ Returns the number of managed windows in clientList array.
+
+ @return the number of managed windows in the clientList array
+
+ @see clientList()
+ **/
+ int clientListCount() const;
+
+ /**
+ Returns an array of Window id's, which contain all managed windows in
+ stacking order.
+
+ @return the array of Window id's in stacking order
+
+ @see clientListStackingCount()
+ **/
+ const Window *clientListStacking() const;
+
+ /**
+ Returns the number of managed windows in the clientListStacking array.
+
+ @return the number of Window id's in the client list
+
+ @see clientListStacking()
+ **/
+ int clientListStackingCount() const;
+
+ /**
+ Returns an array of Window id's, which contain all KDE system tray windows.
+
+ @return the array of Window id's of system tray windows
+
+ @see kdeSystemTrayWindowsCount()
+ **/
+ const Window *kdeSystemTrayWindows() const;
+
+ /**
+ Returns the number of windows in the kdeSystemTrayWindows array.
+
+ @return the number of Window id's in the system tray list
+
+ @see kdeSystemTrayWindows()
+ **/
+ int kdeSystemTrayWindowsCount() const;
+
+ /**
+ Returns the desktop geometry size.
+
+ The desktop argument is ignored. Early drafts of the NET WM
+ Specification were unclear about the semantics of this property.
+
+ @param desktop the number of the desktop
+
+ @return the size of the desktop
+ **/
+ NETSize desktopGeometry(int desktop) const;
+
+ /**
+ Returns the viewport of the specified desktop.
+
+ @param desktop the number of the desktop
+
+ @return the position of the desktop's viewport
+ **/
+ NETPoint desktopViewport(int desktop) const;
+
+ /**
+ Returns the workArea for the specified desktop.
+
+ @param desktop the number of the desktop
+
+ @return the size of the work area
+ **/
+ NETRect workArea(int desktop) const;
+
+ /**
+ Returns the name for the specified desktop.
+
+ @param desktop the number of the desktop
+
+ @return the name of the desktop
+ **/
+ const char *desktopName(int desktop) const;
+
+ /**
+ Returns an array of Window id's, which contain the virtual root windows.
+
+ @return the array of Window id's
+
+ @see virtualRootsCount()
+ **/
+ const Window *virtualRoots( ) const;
+
+ /**
+ Returns the number of window in the virtualRoots array.
+
+ @return the number of Window id's in the virtual root array
+
+ @see virtualRoots()
+ **/
+ int virtualRootsCount() const;
+
+ /**
+ Returns the desktop layout orientation.
+ **/
+ NET::Orientation desktopLayoutOrientation() const;
+
+ /**
+ Returns the desktop layout number of columns and rows. Note that
+ either may be 0 (see _NET_DESKTOP_LAYOUT).
+ **/
+ QSize desktopLayoutColumnsRows() const;
+
+ /**
+ Returns the desktop layout starting corner.
+ **/
+ NET::DesktopLayoutCorner desktopLayoutCorner() const;
+
+ /**
+ Returns the number of desktops.
+
+ @return the number of desktops
+ **/
+ int numberOfDesktops() const;
+
+ /**
+ Returns the current desktop.
+
+ @return the number of the current desktop
+ **/
+ int currentDesktop() const;
+
+ /**
+ Returns the active (focused) window.
+
+ @return the id of the active window
+ **/
+ Window activeWindow() const;
+
+ /**
+ Window Managers must call this after creating the NETRootInfo object, and
+ before using any other method in the class. This method sets initial data
+ on the root window and does other post-construction duties.
+
+ Clients must also call this after creating the object to do an initial
+ data read/update.
+ **/
+ void activate();
+
+ /**
+ Sets the list of managed windows on the Root/Desktop window.
+
+ @param windows The array of Window id's
+
+ @param count The number of windows in the array
+ **/
+ // KDE4 'const Window*', also in the others below
+ void setClientList(Window *windows, unsigned int count);
+
+ /**
+ Sets the list of managed windows in stacking order on the Root/Desktop
+ window.
+
+ @param windows The array of Window id's
+
+ @param count The number of windows in the array.
+ **/
+ void setClientListStacking(Window *windows, unsigned int count);
+
+ /**
+ Sets the list of KDE system tray windows on the root window.
+
+ @param windows The array of window id's
+
+ @param count The number of windows in the array.
+ **/
+ void setKDESystemTrayWindows(Window *windows, unsigned int count);
+
+ /**
+ Sets the current desktop to the specified desktop.
+
+ @param desktop the number of the desktop
+ **/
+ void setCurrentDesktop(int desktop);
+
+ /**
+ Sets the desktop geometry to the specified geometry.
+
+ The desktop argument is ignored. Early drafts of the NET WM
+ Specification were unclear about the semantics of this property.
+
+ @param desktop the number of the desktop
+
+ @param geometry the new size of the desktop
+ **/
+ void setDesktopGeometry(int desktop, const NETSize &geometry);
+
+ /**
+ Sets the viewport for the current desktop to the specified point.
+
+ @param desktop the number of the desktop
+
+ @param viewport the new position of the desktop's viewport
+ **/
+ void setDesktopViewport(int desktop, const NETPoint &viewport);
+
+ /**
+ Sets the number of desktops the the specified number.
+
+ @param numberOfDesktops the number of desktops
+ **/
+ void setNumberOfDesktops(int numberOfDesktops);
+
+ /**
+ Sets the name of the specified desktop.
+
+ @param desktop the number of the desktop
+
+ @param desktopName the new name of the desktop
+ **/
+ void setDesktopName(int desktop, const char *desktopName);
+
+ /**
+ Requests that the specified window becomes the active (focused) one.
+
+ @param window the id of the new active window
+ @param src whether the request comes from normal application
+ or from a pager or similar tool
+ @param timestamp X server timestamp of the user action that
+ caused the request
+ @param active_window active window of the requesting application, if any
+
+ @since 3.2
+ **/
+ void setActiveWindow(Window window, NET::RequestSource src,
+ Time timestamp, Window active_window);
+
+ /**
+ Sets the active (focused) window the specified window. This should
+ be used only in the window manager mode.
+
+ @param window the if of the new active window
+ **/
+ void setActiveWindow(Window window);
+
+ /**
+ Sets the workarea for the specified desktop
+
+ @param desktop the number of the desktop
+
+ @param workArea the new work area of the desktop
+ **/
+ void setWorkArea(int desktop, const NETRect &workArea);
+
+ /**
+ Sets the list of virtual root windows on the root window.
+
+ @param windows The array of Window id's
+
+ @param count The number of windows in the array.
+ **/
+ void setVirtualRoots(Window *windows, unsigned int count);
+
+ /**
+ Sets the desktop layout. This is set by the pager. When setting, the pager must
+ own the _NET_DESKTOP_LAYOUT_Sn manager selection. See _NET_DESKTOP_LAYOUT for details.
+ **/
+ void setDesktopLayout(NET::Orientation orientation, int columns, int rows,
+ NET::DesktopLayoutCorner corner);
+
+ /**
+ * Sets the _NET_SHOWING_DESKTOP status (whether desktop is being shown).
+ * @since 3.5
+ */
+ void setShowingDesktop( bool showing );
+ /**
+ * Returns the status of _NET_SHOWING_DESKTOP.
+ * @since 3.5
+ */
+ bool showingDesktop() const;
+
+ /**
+ Assignment operator. Ensures that the shared data reference counts are
+ correct.
+ **/
+ const NETRootInfo &operator=(const NETRootInfo &rootinfo);
+
+ /**
+ Clients (such as pagers/taskbars) that wish to close a window should call
+ this function. This will send a request to the Window Manager, which
+ usually can usually decide how to react to such requests.
+
+ @param window the id of the window to close
+ **/
+ void closeWindowRequest(Window window);
+
+ /**
+ Clients (such as pagers/taskbars) that wish to start a WMMoveResize
+ (where the window manager controls the resize/movement,
+ i.e. _NET_WM_MOVERESIZE) should call this function.
+ This will send a request to the Window Manager.
+
+ @param window The client window that would be resized/moved.
+
+ @param x_root X position of the cursor relative to the root window.
+
+ @param y_root Y position of the cursor relative to the root window.
+
+ @param direction One of NET::Direction (see base class documentation for
+ a description of the different directions).
+ **/
+ void moveResizeRequest(Window window, int x_root, int y_root,
+ Direction direction);
+
+ /**
+ Clients (such as pagers/taskbars) that wish to move/resize a window
+ using WM2MoveResizeWindow (_NET_MOVERESIZE_WINDOW) should call this function.
+ This will send a request to the Window Manager. See _NET_MOVERESIZE_WINDOW
+ description for details.
+
+ @param window The client window that would be resized/moved.
+ @param flags Flags specifying the operation (see _NET_MOVERESIZE_WINDOW description)
+ @param x Requested X position for the window
+ @param y Requested Y position for the window
+ @param width Requested width for the window
+ @param height Requested height for the window
+
+ @since 3.2
+ **/
+ void moveResizeWindowRequest(Window window, int flags, int x, int y, int width, int height );
+
+ /**
+ Sends the _NET_RESTACK_WINDOW request.
+ @since 3.3
+ **/
+ void restackRequest(Window window, RequestSource source, Window above, int detail, Time timestamp);
+ /**
+ @obsolete
+ @since 3.2
+ **/
+ void restackRequest(Window window, Window above, int detail);
+
+ /**
+ This function takes the passed XEvent and returns an OR'ed list of
+ NETRootInfo properties that have changed in the properties argument.
+ The new information will be read immediately by the class.
+ The elements of the properties argument are as they would be passed
+ to the constructor, if the array is not large enough,
+ changed properties that don't fit in it won't be listed there
+ (they'll be updated in the class though).
+
+ @param event the event
+ @param properties properties that changed
+ @param properties_size size of the passed properties array
+ @since 3.2
+
+ **/
+ void event( XEvent* event, unsigned long* properties, int properties_size );
+
+ /**
+ This function takes the passed XEvent and returns an OR'ed list of
+ NETRootInfo properties that have changed. The new information will be
+ read immediately by the class. This overloaded version returns
+ only a single mask, and therefore cannot check state of all properties
+ like the other variant.
+
+ @param event the event
+
+ @return the properties
+ **/
+ unsigned long event(XEvent *event);
+
+
+protected:
+ /**
+ A Client should subclass NETRootInfo and reimplement this function when
+ it wants to know when a window has been added.
+
+ @param window the id of the window to add
+ **/
+ virtual void addClient(Window window) { Q_UNUSED(window); }
+
+ /**
+ A Client should subclass NETRootInfo and reimplement this function when
+ it wants to know when a window has been removed.
+
+ @param window the id of the window to remove
+ **/
+ virtual void removeClient(Window window) { Q_UNUSED(window); }
+
+ /**
+ A Client should subclass NETRootInfo and reimplement this function when
+ it wants to know when a system tray window has been added. This is a KDE 2.0
+ extension.
+
+ @param window the id of the window to add
+ **/
+ virtual void addSystemTrayWin(Window window) { Q_UNUSED(window); }
+
+ /**
+ A Client should subclass NETRootInfo and reimplement this function when
+ it wants to know when a system tray window has been removed. This is a KDE 2.0
+ extension.
+
+ @param window the id of the window to remove
+ **/
+ virtual void removeSystemTrayWin(Window window) { Q_UNUSED(window); }
+
+ /**
+ A Window Manager should subclass NETRootInfo and reimplement this function
+ when it wants to know when a Client made a request to change the number
+ of desktops.
+
+ @param numberOfDesktops the new number of desktops
+ **/
+ virtual void changeNumberOfDesktops(int numberOfDesktops) { Q_UNUSED(numberOfDesktops); }
+
+ /**
+ A Window Manager should subclass NETRootInfo and reimplement this function
+ when it wants to know when a Client made a request to change the specified
+ desktop geometry.
+
+ @param desktop the number of the desktop
+
+ @param geom the new size
+ **/
+ virtual void changeDesktopGeometry(int desktop, const NETSize &geom) { Q_UNUSED(desktop); Q_UNUSED(geom); }
+
+ /**
+ A Window Manager should subclass NETRootInfo and reimplement this function
+ when it wants to know when a Client made a request to change the specified
+ desktop viewport.
+
+ @param desktop the number of the desktop
+
+ @param viewport the new position of the viewport
+ **/
+ virtual void changeDesktopViewport(int desktop, const NETPoint &viewport) { Q_UNUSED(desktop); Q_UNUSED(viewport); }
+
+ /**
+ A Window Manager should subclass NETRootInfo and reimplement this function
+ when it wants to know when a Client made a request to change the current
+ desktop.
+
+ @param desktop the number of the desktop
+ **/
+ virtual void changeCurrentDesktop(int desktop) { Q_UNUSED(desktop); }
+
+ /**
+ @deprecated Use NETRootInfo2::changeActiveWindow() instead.
+ A Window Manager should subclass NETRootInfo and reimplement this function
+ when it wants to know when a Client made a request to change the active
+ (focused) window. The changeActiveWindow() method in NETRootInfo2
+ should be used instead.
+
+ @param window the id of the window to activate
+ **/
+ virtual KDE_DEPRECATED void changeActiveWindow(Window window) { Q_UNUSED(window); }
+
+ /**
+ A Window Manager should subclass NETRootInfo and reimplement this function
+ when it wants to know when a Client made a request to close a window.
+
+ @param window the id of the window to close
+ **/
+ virtual void closeWindow(Window window) { Q_UNUSED(window); }
+
+ /**
+ A Window Manager should subclass NETRootInfo and reimplement this function
+ when it wants to know when a Client made a request to start a move/resize.
+
+ @param window The window that wants to move/resize
+
+ @param x_root X position of the cursor relative to the root window.
+
+ @param y_root Y position of the cursor relative to the root window.
+
+ @param direction One of NET::Direction (see base class documentation for
+ a description of the different directions).
+ **/
+ virtual void moveResize(Window window, int x_root, int y_root,
+ unsigned long direction) { Q_UNUSED(window); Q_UNUSED(x_root); Q_UNUSED(y_root); Q_UNUSED(direction); }
+
+
+private:
+ void update( const unsigned long[] );
+ void setSupported();
+ void setDefaultProperties();
+ void updateSupportedProperties( Atom atom );
+ Role role;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ NETRootInfoPrivate *p;
+ friend class NETRootInfo2;
+ friend class NETRootInfo3;
+};
+
+/**
+ This class is an extension of the NETRootInfo class, and exists solely
+ for binary compatibility reasons (adds new virtual methods). Simply
+ use it instead of NETRootInfo and override also the added virtual methods.
+ @since 3.2
+*/
+class KDECORE_EXPORT NETRootInfo2
+ : public NETRootInfo
+{
+public:
+ NETRootInfo2(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+ /**
+ * @since 3.5
+ */
+ NETRootInfo2(Display *display, const unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+ /**
+ Sends a ping with the given timestamp to the window, using
+ the _NET_WM_PING protocol.
+ */
+ void sendPing( Window window, Time timestamp );
+protected:
+ friend class NETRootInfo;
+ /**
+ A Window Manager should subclass NETRootInfo2 and reimplement this function
+ when it wants to receive replies to the _NET_WM_PING protocol.
+ @param window the window from which the reply came
+ @param timestamp timestamp of the ping
+ */
+ virtual void gotPing( Window window, Time timestamp ) { Q_UNUSED(window); Q_UNUSED(timestamp); }
+ /**
+ A Window Manager should subclass NETRootInfo2 and reimplement this function
+ when it wants to know when a Client made a request to change the active
+ (focused) window.
+
+ @param window the id of the window to activate
+ @param src the source from which the request came
+ @param timestamp the timestamp of the user action causing this request
+ @param active_window active window of the requesting application, if any
+ **/
+ virtual void changeActiveWindow(Window window,NET::RequestSource src,
+ Time timestamp, Window active_window ) { Q_UNUSED(window); Q_UNUSED(src); Q_UNUSED(timestamp); Q_UNUSED(active_window);}
+ /**
+ A Window Manager should subclass NETRootInfo2 and reimplement this function
+ when it wants to know when a Client made a request to restack a window.
+ See _NET_RESTACK_WINDOW for details.
+
+ @param window the id of the window to restack
+ @param above other window in the restack request
+ @param detail restack detail
+ **/
+ virtual void restackWindow(Window window, Window above, int detail) { Q_UNUSED(window); Q_UNUSED(above); Q_UNUSED(detail); }
+
+ /**
+ A Window Manager should subclass NETRootInfo2 and reimplement this function
+ when it wants to know when a pager made a request to move/resize a window.
+ See _NET_MOVERESIZE_WINDOW for details.
+
+ @param window the id of the window to more/resize
+ @param flags Flags specifying the operation (see _NET_MOVERESIZE_WINDOW description)
+ @param x Requested X position for the window
+ @param y Requested Y position for the window
+ @param width Requested width for the window
+ @param height Requested height for the window
+ **/
+ virtual void moveResizeWindow(Window window, int flags, int x, int y, int width, int height) { Q_UNUSED(window); Q_UNUSED(flags); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(width); Q_UNUSED(height); }
+
+// no private data, use NETRootInfoPrivate
+};
+
+/**
+ This class is an extension of the NETRootInfo class, and exists solely
+ for binary compatibility reasons (adds new virtual methods). Simply
+ use it instead of NETRootInfo and override also the added virtual methods.
+ @since 3.3
+*/
+class KDECORE_EXPORT NETRootInfo3
+ : public NETRootInfo2
+{
+public:
+ NETRootInfo3(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+ /**
+ * @since 3.5
+ */
+ NETRootInfo3(Display *display, const unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+ /**
+ Sends a take activity message with the given timestamp to the window, using
+ the _NET_WM_TAKE_ACTIVITY protocol (see the WM spec for details).
+ @param window the window to which the message should be sent
+ @param timestamp timestamp of the message
+ @param flags arbitrary flags
+ */
+ void takeActivity( Window window, Time timestamp, long flags );
+protected:
+ friend class NETRootInfo;
+ /**
+ A Window Manager should subclass NETRootInfo3 and reimplement this function
+ when it wants to know when a Client made a request to restack a window.
+ See _NET_RESTACK_WINDOW for details.
+
+ @param window the id of the window to restack
+ @param source the source of the request
+ @param above other window in the restack request
+ @param detail restack detail
+ @param timestamp the timestamp of the request
+ **/
+ virtual void restackWindow(Window window, RequestSource source,
+ Window above, int detail, Time timestamp) { Q_UNUSED(window); Q_UNUSED(source); Q_UNUSED(above); Q_UNUSED(detail); Q_UNUSED(timestamp); }
+ /**
+ A Window Manager should subclass NETRootInfo3 and reimplement this function
+ when it wants to receive replies to the _NET_WM_TAKE_ACTIVITY protocol.
+ @param window the window from which the reply came
+ @param timestamp timestamp of the ping
+ @param flags flags passed in the original message
+ */
+ virtual void gotTakeActivity(Window window, Time timestamp, long flags ) { Q_UNUSED(window); Q_UNUSED(timestamp); Q_UNUSED(flags); }
+// no private data, use NETRootInfoPrivate
+};
+
+/**
+ This class is an extension of the NETRootInfo class, and exists solely
+ for binary compatibility reasons (adds new virtual methods). Simply
+ use it instead of NETRootInfo and override also the added virtual methods.
+ @since 3.5
+*/
+class KDECORE_EXPORT NETRootInfo4
+ : public NETRootInfo3
+{
+public:
+ NETRootInfo4(Display *display, Window supportWindow, const char *wmName,
+ unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+ NETRootInfo4(Display *display, const unsigned long properties[], int properties_size,
+ int screen = -1, bool doActivate = true);
+
+protected:
+ friend class NETRootInfo;
+ /**
+ A Window Manager should subclass NETRootInfo2 and reimplement this function
+ when it wants to know when a pager made a request to change showing the desktop.
+ See _NET_SHOWING_DESKTOP for details.
+
+ @param showing whether to activate the showing desktop mode
+ **/
+ virtual void changeShowingDesktop(bool showing) { Q_UNUSED(showing); }
+// no private data, use NETRootInfoPrivate
+};
+
+/**
+ Common API for application window properties/protocols.
+
+ The NETWinInfo class provides a common API for clients and window managers to
+ set/read/change properties on an application window as defined by the NET
+ Window Manager Specification.
+
+ @author Bradley T. Hughes <bhughes@trolltech.com>
+ @see NET
+ @see NETRootInfo
+ @see KWin
+ @see http://www.freedesktop.org/standards/wm-spec/
+ **/
+
+class KDECORE_EXPORT NETWinInfo : public NET {
+public:
+ /**
+ Indexes for the properties array.
+ @since 3.2
+ **/
+ // update also NETWinInfoPrivate::properties[] size when extending this
+ enum { PROTOCOLS, PROTOCOLS2,
+ PROPERTIES_SIZE };
+ /**
+ Create a NETWinInfo object, which will be used to set/read/change
+ information stored on an application window.
+
+ @param display An X11 Display struct.
+
+ @param window The Window id of the application window.
+
+ @param rootWindow The Window id of the root window.
+
+ @param properties An array of elements listing all properties the client
+ is interested in.The elements contain OR'ed values of constants
+ from the NET base class, in the following order: [0]= NET::Property,
+ [1]= NET::Property2.
+ In future versions, the list may be extended. In case you pass less elements,
+ the missing ones will be replaced with default values.
+
+ @param properties_size The number of elements in the properties array.
+
+ @param role Select the application role. If this argument is omitted,
+ the role will default to Client.
+
+ @since 3.2
+ **/
+ NETWinInfo(Display *display, Window window, Window rootWindow,
+ const unsigned long properties[], int properties_size,
+ Role role = Client);
+
+ /**
+ This constructor differs from the above one only in the way it accepts
+ the list of properties the client is interested in. The properties argument
+ is equivalent to the first element of the properties array
+ in the above constructor.
+ **/
+ NETWinInfo(Display *display, Window window,
+ Window rootWindow, unsigned long properties,
+ Role role = Client);
+
+ /**
+ Creates a shared copy of the specified NETWinInfo object.
+
+ @param wininfo the NETWinInfo to copy
+ **/
+ NETWinInfo(const NETWinInfo & wininfo);
+
+ /**
+ Destroys the NETWinInfo object.
+ **/
+ virtual ~NETWinInfo();
+
+ /**
+ Assignment operator. Ensures that the shared data reference counts are
+ correct.
+ **/
+ const NETWinInfo &operator=(const NETWinInfo &wintinfo);
+
+ /**
+ Returns true if the window has any window type set, even if the type
+ itself is not known to this implementation. Presence of a window type
+ as specified by the NETWM spec is considered as the window supporting
+ this specification.
+ @since 3.2
+ @return true if the window has support for the NETWM spec
+ **/
+ bool hasNETSupport() const;
+
+ /**
+ Returns the properties argument passed to the constructor.
+ The size is the maximum array size the constructor accepts.
+
+ @since 3.2
+ **/
+ // KDE4 better name?
+ const unsigned long* passedProperties() const;
+
+ /**
+ @deprecated
+
+ Returns an OR'ed list of protocols passed to the constructor.
+
+ @return an OR'ed list of protocols
+
+ @see NET::Property
+ **/
+ unsigned long properties() const KDE_DEPRECATED;
+
+ /**
+ Returns the icon geometry.
+
+ @return the geometry of the icon
+ **/
+ NETRect iconGeometry() const;
+
+ /**
+ Returns the state of the window (see the NET base class documentation for a
+ description of the various states).
+
+ @return the state of the window
+ **/
+ unsigned long state() const;
+
+ /**
+ Returns the extended (partial) strut specified by this client.
+ See _NET_WM_STRUT_PARTIAL in the spec.
+ **/
+ NETExtendedStrut extendedStrut() const;
+
+ /**
+ @deprecated use strutPartial()
+ Returns the strut specified by this client.
+
+ @return the strut of the window
+ **/
+ NETStrut strut() const;
+
+ /**
+ Returns the window type for this client (see the NET base class
+ documentation for a description of the various window types).
+ Since clients may specify several windows types for a window
+ in order to support backwards compatibility and extensions
+ not available in the NETWM spec, you should specify all
+ window types you application supports (see the NET::WindowTypeMask
+ mask values for various window types). This method will
+ return the first window type that is listed in the supported types,
+ or NET::Unknown if none of the window types is supported.
+
+ @return the type of the window
+ @since 3.2
+ **/
+ WindowType windowType( unsigned long supported_types ) const;
+
+ /**
+ @deprecated
+ Returns the window type for this client (see the NET base class
+ documentation for a description of the various window types).
+
+ @return the type of the window
+ **/
+ WindowType windowType() const KDE_DEPRECATED;
+
+ /**
+ Returns the name of the window in UTF-8 format.
+
+ @return the name of the window
+ **/
+ const char *name() const;
+
+ /**
+ Returns the visible name as set by the window manager in UTF-8 format.
+
+ @return the visible name of the window
+ **/
+ const char *visibleName() const;
+
+ /**
+ Returns the iconic name of the window in UTF-8 format. Note that this has
+ nothing to do with icons, but it's for "iconic"
+ representations of the window (taskbars etc.), that should be shown
+ when the window is in iconic state. See description of _NET_WM_ICON_NAME
+ for details.
+
+ @return the iconic name
+ **/
+ const char *iconName() const;
+
+ /**
+ Returns the visible iconic name as set by the window manager in UTF-8 format.
+ Note that this has nothing to do with icons, but it's for "iconic"
+ representations of the window (taskbars etc.), that should be shown
+ when the window is in iconic state. See description of _NET_WM_VISIBLE_ICON_NAME
+ for details.
+
+ @return the visible iconic name
+ **/
+ const char *visibleIconName() const;
+
+ /**
+ Returns the desktop where the window is residing.
+
+ @return the number of the window's desktop
+
+ @see OnAllDesktops()
+ **/
+ int desktop() const;
+
+ /**
+ Returns the process id for the client window.
+
+ @return the process id of the window
+ **/
+ int pid() const;
+
+ /**
+ Returns whether or not this client handles icons.
+
+ @return true if this client handles icons, false otherwise
+ **/
+ Bool handledIcons() const;
+
+ /**
+ Returns a Window id, telling the window manager which window we are
+ representing.
+
+ @return the window id
+ **/
+ Window kdeSystemTrayWinFor() const;
+
+ /**
+ Returns the mapping state for the window (see the NET base class
+ documentation for a description of mapping state).
+
+ @return the mapping state
+ **/
+ MappingState mappingState() const;
+
+ /**
+ Set icons for the application window. If replace is True, then
+ the specified icon is defined to be the only icon. If replace is False,
+ then the specified icon is added to a list of icons.
+
+ @param icon the new icon
+
+ @param replace true to replace, false to append to the list of icons
+ **/
+ void setIcon(NETIcon icon, Bool replace = True);
+
+ /**
+ Set the icon geometry for the application window.
+
+ @param geometry the new icon geometry
+ **/
+ void setIconGeometry(NETRect geometry);
+
+ /**
+ Set the extended (partial) strut for the application window.
+
+ @param extended_strut the new strut
+ **/
+ void setExtendedStrut(const NETExtendedStrut& extended_strut );
+
+ /**
+ @deprecated use setExtendedStrut()
+ Set the strut for the application window.
+
+ @param strut the new strut
+ **/
+ void setStrut(NETStrut strut);
+
+ /**
+ Set the state for the application window (see the NET base class documentation
+ for a description of window state). Note that the constructor needs to be
+ passed NET::WMState in properties even if it's only used for setting the state
+ without reading it.
+
+ @param state the name state
+
+ @param mask the mask for the state
+ **/
+ void setState(unsigned long state, unsigned long mask);
+
+ /**
+ Sets the window type for this client (see the NET base class
+ documentation for a description of the various window types).
+
+ @param type the window type
+ **/
+ void setWindowType(WindowType type);
+
+ /**
+ Sets the name for the application window.
+
+ @param name the new name of the window
+ **/
+ void setName(const char *name);
+
+ /**
+ For Window Managers only: set the visible name ( i.e. xterm, xterm <2>,
+ xterm <3>, ... )
+
+ @param visibleName the new visible name
+ **/
+ void setVisibleName(const char *visibleName);
+
+ /**
+ Sets the iconic name for the application window.
+
+ @param name the new iconic name
+ **/
+ void setIconName(const char *name);
+
+ /**
+ For Window Managers only: set the visible iconic name ( i.e. xterm, xterm <2>,
+ xterm <3>, ... )
+
+ @param name the new visible iconic name
+ **/
+ void setVisibleIconName(const char *name);
+
+ /**
+ Set which window the desktop is (should be) on.
+
+ @param desktop the number of the new desktop
+
+ @see OnAllDesktops()
+ **/
+ void setDesktop(int desktop);
+
+ /**
+ Set the application window's process id.
+
+ @param pid the window's process id
+ **/
+ void setPid(int pid);
+
+ /**
+ Set whether this application window handles icons.
+
+ @param handled true if the window handles icons, false otherwise
+ **/
+ void setHandledIcons(Bool handled);
+
+ /**
+ Set which window we are representing as a system tray window.
+
+ @param window the window that is represented by the system tray icon
+ **/
+ void setKDESystemTrayWinFor(Window window);
+
+ /**
+ Set the frame decoration strut, i.e. the width of the decoration borders.
+
+ @param strut the new strut
+ @since 3.5
+ **/
+ void setFrameExtents(NETStrut strut);
+
+ /**
+ Set the frame decoration strut. This is a KDE 2.0 extension to aid in
+ writing pager applications.
+
+ @param strut the new strut
+ **/
+ void setKDEFrameStrut(NETStrut strut);
+
+ /**
+ Returns an icon. If width and height are passed, the icon returned will be
+ the closest it can find (the next biggest). If width and height are omitted,
+ then the largest icon in the list is returned.
+
+ @param width the preferred width for the icon, -1 to ignore
+
+ @param height the preferred height for the icon, -1 to ignore
+
+ @return the icon
+ **/
+ NETIcon icon(int width = -1, int height = -1) const;
+
+ /*
+ * Sets user timestamp @p time on the window (property _NET_WM_USER_TIME).
+ * The timestamp is expressed as XServer time. If a window
+ * is shown with user timestamp older than the time of the last
+ * user action, it won't be activated after being shown, with the special
+ * value 0 meaning not to activate the window after being shown.
+ * @since 3.2
+ */
+ void setUserTime( Time time );
+
+ /**
+ * Returns the time of last user action on the window, or -1 if not set.
+ * @since 3.2
+ */
+ Time userTime() const;
+
+ /*
+ * Sets the startup notification id @p id on the window.
+ * @since 3.2
+ */
+ void setStartupId( const char* startup_id );
+
+ /**
+ * Returns the startup notification id of the window.
+ * @since 3.2
+ */
+ const char* startupId() const;
+
+ /**
+ * Sets actions that the window manager allows for the window.
+ * @since 3.2
+ */
+ void setAllowedActions( unsigned long actions );
+
+ /**
+ * Returns actions that the window manager allows for the window.
+ * @since 3.2
+ */
+ unsigned long allowedActions() const;
+
+ /*
+ * Returns the WM_TRANSIENT_FOR property for the window, i.e. the mainwindow
+ * for this window.
+ * @since 3.2
+ */
+ Window transientFor() const;
+
+ /**
+ * Returns the leader window for the group the window is in, if any.
+ * @since 3.2
+ */
+ Window groupLeader() const;
+
+ /**
+ * Returns the class component of the window class for the window
+ * (i.e. WM_CLASS property).
+ * @since 3.3
+ */
+ const char* windowClassClass() const;
+
+ /**
+ * Returns the name component of the window class for the window
+ * (i.e. WM_CLASS property).
+ * @since 3.3
+ */
+ const char* windowClassName() const;
+
+ /**
+ * Returns the window role for the window (i.e. WM_WINDOW_ROLE property).
+ * @since 3.3
+ */
+ const char* windowRole() const;
+
+ /**
+ * Returns the client machine for the window (i.e. WM_CLIENT_MACHINE property).
+ * @since 3.3
+ */
+ const char* clientMachine() const;
+
+ /**
+ Places the window frame geometry in frame, and the application window
+ geometry in window. Both geometries are relative to the root window.
+
+ @param frame the geometry for the frame
+
+ @param window the geometry for the window
+ **/
+ void kdeGeometry(NETRect &frame, NETRect &window);
+
+ /**
+ This function takes the passed XEvent and returns an OR'ed list of
+ NETWinInfo properties that have changed in the properties argument.
+ The new information will be read immediately by the class.
+ The elements of the properties argument are as they would be passed
+ to the constructor, if the array is not large enough,
+ changed properties that don't fit in it won't be listed there
+ (they'll be updated in the class though).
+
+ @param event the event
+ @param properties properties that changed
+ @param properties_size size of the passed properties array
+ @since 3.2
+
+ **/
+ void event( XEvent* event, unsigned long* properties, int properties_size );
+
+ /**
+ This function takes the pass XEvent and returns an OR'ed list of NETWinInfo
+ properties that have changed. The new information will be read
+ immediately by the class. This overloaded version returns
+ only a single mask, and therefore cannot check state of all properties
+ like the other variant.
+
+ @param event the event
+
+ @return the properties
+ **/
+ unsigned long event(XEvent *event);
+
+ /**
+ Sentinel value to indicate that the client wishes to be visible on
+ all desktops.
+
+ @return the value to be on all desktops
+ **/
+ static const int OnAllDesktops;
+
+
+protected:
+ /**
+ A Window Manager should subclass NETWinInfo and reimplement this function when
+ it wants to know when a Client made a request to change desktops (ie. move to
+ another desktop).
+
+ @param desktop the number of the desktop
+ **/
+ virtual void changeDesktop(int desktop) { Q_UNUSED(desktop); }
+
+ /**
+ A Window Manager should subclass NETWinInfo and reimplement this function when
+ it wants to know when a Client made a request to change state (ie. to
+ Shade / Unshade).
+
+ @param state the new state
+
+ @param mask the mask for the state
+ **/
+ virtual void changeState(unsigned long state, unsigned long mask) { Q_UNUSED(state); Q_UNUSED(mask); }
+
+private:
+ void update( const unsigned long[] );
+ void updateWMState();
+ void setIconInternal(NETRArray<NETIcon>& icons, int& icon_count, Atom property, NETIcon icon, Bool replace);
+ NETIcon iconInternal(NETRArray<NETIcon>& icons, int icon_count, int width, int height) const;
+ Role role;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ NETWinInfoPrivate *p;
+};
+
+
+//#define KWIN_FOCUS
+
+#endif
+#endif // __net_wm_h
diff --git a/kdecore/netwm_def.h b/kdecore/netwm_def.h
new file mode 100644
index 000000000..f2e11505d
--- /dev/null
+++ b/kdecore/netwm_def.h
@@ -0,0 +1,670 @@
+/*
+
+ Copyright (c) 2000 Troll Tech AS
+ Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
+
+ 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 OR COPYRIGHT HOLDERS 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.
+
+*/
+
+#ifndef __netwm_def_h
+#define __netwm_def_h
+
+#include <kdelibs_export.h>
+
+/**
+ Simple point class for NET classes.
+
+ This class is a convenience class defining a point x, y. The existence of
+ this class is to keep the implementation from being dependant on a
+ separate framework/library.
+
+ NETPoint is only used by the NET API. Usually QPoint is the
+ appropriate class for representing a point.
+
+ @author Bradley T. Hughes <bhughes@trolltech.com>
+**/
+
+struct NETPoint {
+ /**
+ Constructor to initialize this point to 0,0.
+ **/
+ NETPoint() : x(0), y(0) { }
+
+ /*
+ Public data member.
+ **/
+ int x, ///< x coordinate.
+ y; ///< y coordinate
+};
+
+
+/**
+ Simple size class for NET classes.
+
+ This class is a convenience class defining a size width by height. The
+ existence of this class is to keep the implementation from being dependant
+ on a separate framework/library.
+
+ NETSize is only used by the NET API. Usually QSize is the
+ appropriate class for representing a size.
+
+ @author Bradley T. Hughes <bhughes@trolltech.com>
+**/
+
+struct NETSize {
+ /**
+ Constructor to initialize this size to 0x0
+ **/
+ NETSize() : width(0), height(0) { }
+
+ /*
+ Public data member.
+ **/
+ int width, ///< Width.
+ height; ///< Height.
+};
+
+/**
+ Simple rectangle class for NET classes.
+
+ This class is a convenience class defining a rectangle as a point x,y with a
+ size width by height. The existence of this class is to keep the implementation
+ from being dependant on a separate framework/library;
+
+ NETRect is only used by the NET API. Usually QRect is the
+ appropriate class for representing a rectangle.
+**/
+struct NETRect {
+ /**
+ Position of the rectangle.
+
+ @see NETPoint
+ **/
+ NETPoint pos;
+
+ /**
+ Size of the rectangle.
+
+ @see NETSize
+ **/
+ NETSize size;
+};
+
+
+/**
+ Simple icon class for NET classes.
+
+ This class is a convenience class defining an icon of size width by height.
+ The existence of this class is to keep the implementation from being
+ dependant on a separate framework/library.
+
+ NETIcon is only used by the NET API. Usually QIcon is the
+ appropriate class for representing an icon.
+**/
+
+struct NETIcon {
+ /**
+ Constructor to initialize this icon to 0x0 with data=0
+ **/
+ NETIcon() : data(0) { }
+
+ /**
+ Size of the icon.
+
+ @see NETSize
+ **/
+ NETSize size;
+
+ /**
+ Image data for the icon. This is an array of 32bit packed CARDINAL ARGB
+ with high byte being A, low byte being B. First two bytes are width, height.
+ Data is in rows, left to right and top to bottom.
+ **/
+ unsigned char *data;
+};
+
+
+/**
+ Partial strut class for NET classes.
+
+ This class is a convenience class defining a strut with left, right, top and
+ bottom border values, and ranges for them. The existence of this class is to
+ keep the implementation from being dependant on a separate framework/library.
+ See the _NET_WM_STRUT_PARTIAL property in the NETWM spec.
+**/
+
+struct NETExtendedStrut {
+ /**
+ Constructor to initialize this struct to 0,0,0,0
+ **/
+ NETExtendedStrut() : left_width(0), left_start(0), left_end(0),
+ right_width(0), right_start(0), right_end(0), top_width(0), top_start(0), top_end(0),
+ bottom_width(0), bottom_start(0), bottom_end(0) {}
+
+ /**
+ Left border of the strut, width and range.
+ **/
+ int left_width, left_start, left_end;
+
+ /**
+ Right border of the strut, width and range.
+ **/
+ int right_width, right_start, right_end;
+
+ /**
+ Top border of the strut, width and range.
+ **/
+ int top_width, top_start, top_end;
+
+ /**
+ Bottom border of the strut, width and range.
+ **/
+ int bottom_width, bottom_start, bottom_end;
+
+};
+
+
+/**
+ @deprecated use NETExtendedStrut
+
+ Simple strut class for NET classes.
+
+ This class is a convenience class defining a strut with left, right, top and
+ bottom border values. The existence of this class is to keep the implementation
+ from being dependant on a separate framework/library. See the _NET_WM_STRUT
+ property in the NETWM spec.
+**/
+
+struct NETStrut {
+ /**
+ Constructor to initialize this struct to 0,0,0,0
+ **/
+ NETStrut() : left(0), right(0), top(0), bottom(0) { }
+
+ /**
+ Left border of the strut.
+ **/
+ int left;
+
+ /**
+ Right border of the strut.
+ **/
+ int right;
+
+ /**
+ Top border of the strut.
+ **/
+ int top;
+
+ /**
+ Bottom border of the strut.
+ **/
+ int bottom;
+};
+
+
+/**
+ Base namespace class.
+
+ The NET API is an implementation of the NET Window Manager Specification.
+
+ This class is the base class for the NETRootInfo and NETWinInfo classes, which
+ are used to retrieve and modify the properties of windows. To keep
+ the namespace relatively clean, all enums are defined here.
+
+ @see http://www.freedesktop.org/standards/wm-spec/
+ **/
+
+class KDECORE_EXPORT NET {
+public:
+ /**
+ Application role. This is used internally to determine how several action
+ should be performed (if at all).
+
+ @li Client indicates that the application is a client application.
+
+ @li WindowManager indicates that the application is a window manager
+ application.
+ **/
+
+ enum Role {
+ Client,
+ WindowManager
+ };
+
+ /**
+ Window type.
+
+ @li Unknown indicates that the window did not define a window type.
+
+ @li Normal indicates that this is a normal, top-level window. Windows with
+ Unknown window type or WM_TRANSIENT_FOR unset must be taken as this type.
+
+ @li Desktop indicates a desktop feature. This can include a single window
+ containing desktop icons with the same dimensions as the screen, allowing
+ the desktop environment to have full control of the desktop, without the
+ need for proxying root window clicks.
+
+ @li Dock indicates a dock or panel feature. Typically a window manager would
+ keep such windows on top of all other windows.
+
+ @li Toolbar and Menu indicate toolbar and pinnable menu windows, respectively.
+
+ @li Dialog indicates that this is a dialog window. If _NET_WM_WINDOW_TYPE is
+ not set, then windows with WM_TRANSIENT_FOR set must be taken as this type.
+
+ @li Override - deprecated, has unclear meaning and is KDE-only.
+
+ @li TopMenu indicates a toplevel menu (AKA macmenu). This is a KDE extension to the
+ _NET_WM_WINDOW_TYPE mechanism.
+
+ @li DropdownMenu - dropdown menu (from a menubar typically)
+
+ @li PopupMenu - a popup menu (a context menu typically)
+
+ @li Tooltip - a tooltip window
+
+ @li Notification - a notification window
+
+ @li ComboBox - a list window for a combobox
+
+ @li DNDIcon - a window that represents the dragged object during DND operation
+
+ Note that some window types are typically used only on override-redirect
+ windows (WX11BypassWM flag).
+ **/
+
+ enum WindowType {
+ Unknown = -1,
+ Normal = 0,
+ Desktop = 1,
+ Dock = 2,
+ Toolbar = 3,
+ Menu = 4,
+ Dialog = 5,
+ Override = 6, ///< @deprecated
+ TopMenu = 7, // NON STANDARD
+ Tool = Toolbar, // This will go away soon, COMPAT (How soon? :)
+ Utility = 8, ///< @since 3.2
+ Splash = 9, ///< @since 3.2
+ DropdownMenu = 10, ///< @since 3.5.7
+ PopupMenu = 11, ///< @since 3.5.7
+ Tooltip = 12, ///< @since 3.5.7
+ Notification = 13, ///< @since 3.5.7
+ ComboBox = 14, ///< @since 3.5.7
+ DNDIcon = 15 ///< @since 3.5.7
+ };
+
+ /**
+ Values for WindowType when they should be OR'ed together, e.g.
+ for the properties argument of the NETRootInfo constructor.
+ @since 3.2
+ **/
+ enum WindowTypeMask {
+ NormalMask = 1<<0,
+ DesktopMask = 1<<1,
+ DockMask = 1<<2,
+ ToolbarMask = 1<<3,
+ MenuMask = 1<<4,
+ DialogMask = 1<<5,
+ OverrideMask = 1<<6,
+ TopMenuMask = 1<<7,
+ UtilityMask = 1<<8,
+ SplashMask = 1<<9,
+ DropdownMenuMask = 1<<10, ///< @since 3.5.7
+ PopupMenuMask = 1<<11, ///< @since 3.5.7
+ TooltipMask = 1<<12, ///< @since 3.5.7
+ NotificationMask = 1<<13, ///< @since 3.5.7
+ ComboBoxMask = 1<<14, ///< @since 3.5.7
+ DNDIconMask = 1<<15 ///< @since 3.5.7
+ };
+
+ // KDE4 move to WindowTypeMask
+ enum { AllTypesMask = 0LU-1 };
+
+ /**
+ * Returns true if the given window type matches the mask given
+ * using WindowTypeMask flags.
+ */
+ static bool typeMatchesMask( WindowType type, unsigned long mask );
+
+ /**
+ Window state.
+
+ @li Modal ndicates that this is a modal dialog box. The WM_TRANSIENT_FOR hint
+ MUST be set to indicate which window the dialog is a modal for, or set to
+ the root window if the dialog is a modal for its window group.
+
+ @li Sticky indicates that the Window Manager SHOULD keep the window's position
+ fixed on the screen, even when the virtual desktop scrolls. Note that this is
+ different from being kept on all desktops.
+
+ @li Max{Vert,Horiz} indicates that the window is {vertically,horizontally}
+ maximized.
+
+ @li Max is more convenient than MaxVert | MaxHoriz.
+
+ @li Shaded indicates that the window is shaded (rolled-up).
+
+ @li SkipTaskbar indicates that a window should not be included on a taskbar.
+
+ @li SkipPager indicates that a window should not be included on a pager.
+
+ @li Hidden indicates that a window should not be visible on the screen (e.g. when minimised).
+ Only the window manager is allowed to change it.
+
+ @li FullScreen indicates that a window should fill the entire screen and have no window decorations.
+
+ @li KeepAbove indicates that a window should on top of most windows (but below fullscreen windows).
+
+ @li KeepBelow indicates that a window should be below most windows (but above any desktop windows).
+
+ @li StaysOnTop is an obsolete name for KeepAbove.
+
+ @li DemandsAttention there was an attempt to activate this window, but the window manager prevented
+ this. E.g. taskbar should mark such window specially to bring user's attention to this window.
+ Only the window manager is allowed to change it.
+
+ Note that KeepAbove (StaysOnTop) and KeepBelow are meant as user preference and applications
+ should avoid setting these states themselves.
+ **/
+
+ enum State {
+ Modal = 1<<0,
+ Sticky = 1<<1,
+ MaxVert = 1<<2,
+ MaxHoriz = 1<<3,
+ Max = MaxVert | MaxHoriz,
+ Shaded = 1<<4,
+ SkipTaskbar = 1<<5,
+ KeepAbove = 1<<6, ///< @since 3.2
+ StaysOnTop = KeepAbove, // NOT STANDARD
+ SkipPager = 1<<7,
+ Hidden = 1<<8, ///< @since 3.2
+ FullScreen = 1<<9, ///< @since 3.2
+ KeepBelow = 1<<10, ///< @since 3.2
+ DemandsAttention = 1<<11 ///< @since 3.2
+ };
+
+ /**
+ Direction for WMMoveResize.
+
+ When a client wants the Window Manager to start a WMMoveResize, it should
+ specify one of:
+
+ @li TopLeft
+ @li Top
+ @li TopRight
+ @li Right
+ @li BottomRight
+ @li Bottom
+ @li BottomLeft
+ @li Left
+ @li Move (for movement only)
+ @li KeyboardSize (resizing via keyboard)
+ @li KeyboardMove (movement via keyboard)
+ **/
+
+ enum Direction {
+ TopLeft = 0,
+ Top = 1,
+ TopRight = 2,
+ Right = 3,
+ BottomRight = 4,
+ Bottom = 5,
+ BottomLeft = 6,
+ Left = 7,
+ Move = 8, // movement only
+ /**
+ @since 3.2
+ **/
+ KeyboardSize = 9, // size via keyboard
+ /**
+ @since 3.2
+ **/
+ KeyboardMove = 10, // move via keyboard
+ /**
+ @since 3.5.1
+ **/
+ MoveResizeCancel = 11 // to ask the WM to stop moving a window
+ };
+
+ /**
+ Client window mapping state. The class automatically watches the mapping
+ state of the client windows, and uses the mapping state to determine how
+ to set/change different properties.
+
+ @li Visible indicates the client window is visible to the user.
+
+ @li Withdrawn indicates that neither the client window nor its icon is visible.
+
+ @li Iconic indicates that the client window is not visible, but its icon is.
+ This can be when the window is minimized or when it's on a different
+ virtual desktop. See also NET::Hidden.
+ **/
+
+ // KDE4 aaarghl, this doesn't map correctly to Xlib #defines
+ enum MappingState {
+ Visible, // ie. NormalState
+ Withdrawn,
+ Iconic
+ };
+
+ /**
+ Actions that can be done with a window (_NET_WM_ALLOWED_ACTIONS).
+ @since 3.2
+ **/
+ enum Action {
+ ActionMove = 1<<0,
+ ActionResize = 1<<1,
+ ActionMinimize = 1<<2,
+ ActionShade = 1<<3,
+ ActionStick = 1<<4,
+ ActionMaxVert = 1<<5,
+ ActionMaxHoriz = 1<<6,
+ ActionMax = ActionMaxVert | ActionMaxHoriz,
+ ActionFullScreen = 1<<7,
+ ActionChangeDesktop = 1<<8,
+ ActionClose = 1<<9
+ };
+
+ /**
+ Supported properties. Clients and Window Managers must define which
+ properties/protocols it wants to support.
+
+ Root/Desktop window properties and protocols:
+
+ @li Supported
+ @li ClientList
+ @li ClientListStacking
+ @li NumberOfDesktops
+ @li DesktopGeometry
+ @li DesktopViewport
+ @li CurrentDesktop
+ @li DesktopNames
+ @li ActiveWindow
+ @li WorkArea
+ @li SupportingWMCheck
+ @li VirtualRoots
+ @li CloseWindow
+ @li WMMoveResize
+
+ Client window properties and protocols:
+
+ @li WMName
+ @li WMVisibleName
+ @li WMDesktop
+ @li WMWindowType
+ @li WMState
+ @li WMStrut (obsoleted by WM2ExtendedStrut)
+ @li WMIconGeometry
+ @li WMIcon
+ @li WMPid
+ @li WMVisibleIconName
+ @li WMIconName
+
+ ICCCM properties (provided for convenience):
+
+ @li XAWMState
+
+ Extended KDE protocols and properties (NOT STANDARD):
+
+ @li KDESystemTrayWindows
+ @li WMKDESystemTrayWinFor
+ @li WMKDEFrameStrut
+ **/
+
+ enum Property {
+ // root
+ Supported = 1<<0,
+ ClientList = 1<<1,
+ ClientListStacking = 1<<2,
+ NumberOfDesktops = 1<<3,
+ DesktopGeometry = 1<<4,
+ DesktopViewport = 1<<5,
+ CurrentDesktop = 1<<6,
+ DesktopNames = 1<<7,
+ ActiveWindow = 1<<8,
+ WorkArea = 1<<9,
+ SupportingWMCheck = 1<<10,
+ VirtualRoots = 1<<11,
+ KDESystemTrayWindows = 1<<12, // NOT STANDARD
+ CloseWindow = 1<<13,
+ WMMoveResize = 1<<14,
+
+ // window
+ WMName = 1<<15,
+ WMVisibleName = 1<<16,
+ WMDesktop = 1<<17,
+ WMWindowType = 1<<18,
+ WMState = 1<<19,
+ WMStrut = 1<<20,
+ WMIconGeometry = 1<<21,
+ WMIcon = 1<<22,
+ WMPid = 1<<23,
+ WMHandledIcons = 1<<24,
+ WMPing = 1<<25,
+ WMKDESystemTrayWinFor = 1<<26, // NOT STANDARD
+ XAWMState = 1<<27, // NOT STANDARD
+ WMFrameExtents = 1<<28, ///< @since 3.5
+ WMKDEFrameStrut = WMFrameExtents, // NOT STANDARD
+
+ // Need to be reordered
+ WMIconName = 1<<29,
+ WMVisibleIconName = 1<<30,
+ WMGeometry = 1<<31
+ };
+
+ /**
+ Supported properties. This enum is an extension to NET::Property,
+ because them enum is limited only to 32 bits.
+
+ Client window properties and protocols:
+
+ @li WM2UserTime
+ @li WM2StartupId
+ @li WM2TransientFor mainwindow for the window (WM_TRANSIENT_FOR)
+ @li WM2GroupLeader group leader (window_group in WM_HINTS)
+ @li WM2AllowedActions
+ @li WM2RestackWindow
+ @li WM2MoveResizeWindow
+ @li WM2ExtendedStrut
+ @li WM2TemporaryRules internal, for kstart
+ @li WM2WindowClass WM_CLASS
+ @li WM2WindowRole WM_WINDOW_ROLE
+ @li WM2ClientMachine WM_CLIENT_MACHINE
+ @li WM2DesktopLayout _NET_DESKTOP_LAYOUT
+
+ @since 3.2
+
+ **/
+ enum Property2 {
+ WM2UserTime = 1<<0,
+ WM2StartupId = 1<<1,
+ WM2TransientFor = 1<<2,
+ WM2GroupLeader = 1<<3,
+ WM2AllowedActions = 1<<4,
+ WM2RestackWindow = 1<<5,
+ WM2MoveResizeWindow = 1<<6,
+ WM2ExtendedStrut = 1<<7,
+ WM2TakeActivity = 1<<8,
+ WM2KDETemporaryRules = 1<<9, // NOT STANDARD
+ WM2WindowClass = 1<<10, ///< @since 3.3
+ WM2WindowRole = 1<<11, ///< @since 3.3
+ WM2ClientMachine = 1<<12, ///< @since 3.3
+ WM2ShowingDesktop = 1<<13, ///< @since 3.5
+ WM2DesktopLayout = 1<<15 ///< @since 3.5.8
+ };
+
+ /**
+ Sentinel value to indicate that the client wishes to be visible on
+ all desktops.
+ @since 3.2
+ **/
+ enum { OnAllDesktops = -1 };
+
+ /**
+ Source of the request.
+ @li FromApplication the request comes from a normal application
+ @li FromTool the request comes from pager or similar tool
+ @since 3.2
+ **/
+ // must match the values for data.l[0] field in _NET_ACTIVE_WINDOW message
+ enum RequestSource {
+ FromUnknown, // internal
+ FromApplication,
+ FromTool
+ };
+
+ /**
+ Orientation.
+ **/
+ enum Orientation {
+ OrientationHorizontal = 0,
+ OrientationVertical = 1
+ };
+
+ /**
+ Starting corner for desktop layout.
+ **/
+ enum DesktopLayoutCorner {
+ DesktopLayoutCornerTopLeft = 0,
+ DesktopLayoutCornerTopRight = 1,
+ DesktopLayoutCornerBottomLeft = 2,
+ DesktopLayoutCornerBottomRight = 3
+ };
+
+ /**
+ Compares two X timestamps, taking into account wrapping and 64bit architectures.
+ Return value is like with strcmp(), 0 for equal, -1 for time1 < time2, 1 for time1 > time2.
+ @since 3.5.3
+ */
+ static int timestampCompare( unsigned long time1, unsigned long time2 );
+ /**
+ Returns a difference of two X timestamps, time2 - time1, where time2 must be later than time1,
+ as returned by timestampCompare().
+ @since 3.5.3
+ */
+ static int timestampDiff( unsigned long time1_, unsigned long time2_ );
+
+};
+
+
+#endif // __netwm_def_h
diff --git a/kdecore/netwm_p.h b/kdecore/netwm_p.h
new file mode 100644
index 000000000..a2395c4ac
--- /dev/null
+++ b/kdecore/netwm_p.h
@@ -0,0 +1,155 @@
+/*
+
+ Copyright (c) 2000 Troll Tech AS
+ Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
+
+ 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 OR COPYRIGHT HOLDERS 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.
+
+*/
+
+
+#ifndef __net_wm_p_h
+#define __net_wm_p_h
+
+/**
+ Resizable array class.
+
+ This resizable array is used to simplify the implementation. The existence of
+ this class is to keep the implementation from depending on a separate
+ framework/library.
+ @internal
+**/
+
+template <class Z> class NETRArray {
+public:
+ /**
+ Constructs an empty (size == 0) array.
+ **/
+
+ NETRArray();
+
+ /**
+ Resizable array destructor.
+ **/
+
+ ~NETRArray();
+
+ /**
+ The [] operator does the work. If the index is larger than the current
+ size of the array, it is resized.
+ **/
+
+ Z &operator[](int);
+
+ /**
+ Returns the size of the array.
+ **/
+
+ int size() const { return sz; }
+
+ /**
+ Resets the array (size == 0).
+ **/
+ void reset();
+
+private:
+ int sz;
+ int capacity;
+ Z *d;
+};
+
+
+/**
+ Private data for the NETRootInfo class.
+ @internal
+**/
+
+struct NETRootInfoPrivate {
+ // information about the X server
+ Display *display;
+ NETSize rootSize;
+ Window root;
+ Window supportwindow;
+ const char *name;
+ int screen;
+
+ // data that changes (either by the window manager or by a client)
+ // and requires updates
+ NETRArray<NETPoint> viewport;
+ NETRArray<NETRect> workarea;
+ NETSize geometry;
+ Window active;
+ Window *clients, *stacking, *virtual_roots, *kde_system_tray_windows;
+ NETRArray<const char *> desktop_names;
+ int number_of_desktops;
+ int current_desktop;
+
+ unsigned long clients_count, stacking_count, virtual_roots_count,
+ kde_system_tray_windows_count;
+ bool showing_desktop;
+ NET::Orientation desktop_layout_orientation;
+ NET::DesktopLayoutCorner desktop_layout_corner;
+ int desktop_layout_columns, desktop_layout_rows;
+
+ unsigned long properties[ 5 ];
+ unsigned long client_properties[ 5 ]; // properties the client is interested in
+
+ int ref;
+};
+
+
+/**
+ Private data for the NETWinInfo class.
+ @internal
+**/
+
+struct NETWinInfoPrivate {
+ Display *display;
+ Window window, root;
+ NET::MappingState mapping_state;
+ Bool mapping_state_dirty;
+
+ NETRArray<NETIcon> icons;
+ int icon_count;
+
+ NETRect icon_geom, win_geom;
+ unsigned long state;
+ NETExtendedStrut extended_strut;
+ NETStrut strut;
+ NETStrut frame_strut; // strut?
+ NETRArray<NET::WindowType> types;
+ char *name, *visible_name, *icon_name, *visible_icon_name;
+ int desktop;
+ int pid;
+ int handled_icons;
+ Window kde_system_tray_win_for;
+ Time user_time;
+ char* startup_id;
+ Window transient_for, window_group;
+ unsigned long allowed_actions;
+ char* class_class, *class_name, *role, *client_machine;
+
+ unsigned long properties[ 2 ];
+ bool has_net_support;
+
+ int ref;
+};
+
+
+#endif // __net_wm_p_h
diff --git a/kdecore/network/Makefile.am b/kdecore/network/Makefile.am
new file mode 100644
index 000000000..71ed013d9
--- /dev/null
+++ b/kdecore/network/Makefile.am
@@ -0,0 +1,59 @@
+## Makefile.am for libqt-addon
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+noinst_LTLIBRARIES = libkdecorenetwork.la
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# the library search path.
+# convenience lib - no LDFLAGS or LIBADD !
+# Note:
+# ksocketdevice.cpp must appear before any inclusion of ksocketdevice.h
+libkdecorenetwork_la_SOURCES = kresolver.cpp \
+ kresolvermanager.cpp \
+ kresolverworkerbase.cpp \
+ ksocketaddress.cpp \
+ kresolverstandardworkers.cpp \
+ kreverseresolver.cpp \
+ ksocketdevice.cpp \
+ ksocketbase.cpp \
+ kclientsocketbase.cpp \
+ kstreamsocket.cpp \
+ kserversocket.cpp \
+ kdatagramsocket.cpp \
+ khttpproxysocketdevice.cpp \
+ ksockssocketdevice.cpp \
+ kbufferedsocket.cpp \
+ ksocketbuffer.cpp \
+ ksrvresolverworker.cpp
+
+include_HEADERS = kresolver.h \
+ kreverseresolver.h \
+ ksocketaddress.h \
+ ksocketbase.h \
+ ksocketdevice.h \
+ kclientsocketbase.h \
+ kstreamsocket.h \
+ kserversocket.h \
+ kdatagramsocket.h \
+ kmulticastsocketdevice.h \
+ kmulticastsocket.h \
+ knetworkinterface.h \
+ khttpproxysocketdevice.h \
+ ksockssocketdevice.h \
+ kbufferedsocket.h \
+ kiobuffer.h
+noinst_HEADERS = kresolver_p.h \
+ kresolverworkerbase.h \
+ kresolverstandardworkers_p.h \
+ ksocketbuffer_p.h \
+ ksrvresolverworker_p.h \
+ syssocket.h
+
+configdir = $(kde_confdir)
+config_DATA = ipv6blacklist
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
diff --git a/kdecore/network/ipv6blacklist b/kdecore/network/ipv6blacklist
new file mode 100644
index 000000000..f4d4d1252
--- /dev/null
+++ b/kdecore/network/ipv6blacklist
@@ -0,0 +1,3 @@
+.doubleclick.net
+.linebourse.fr
+.banquepopulaire.fr
diff --git a/kdecore/network/kbufferedsocket.cpp b/kdecore/network/kbufferedsocket.cpp
new file mode 100644
index 000000000..7207a9c4f
--- /dev/null
+++ b/kdecore/network/kbufferedsocket.cpp
@@ -0,0 +1,414 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <qmutex.h>
+#include <qtimer.h>
+
+#include "ksocketdevice.h"
+#include "ksocketaddress.h"
+#include "ksocketbuffer_p.h"
+#include "kbufferedsocket.h"
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+class KNetwork::KBufferedSocketPrivate
+{
+public:
+ mutable KSocketBuffer *input, *output;
+
+ KBufferedSocketPrivate()
+ {
+ input = 0L;
+ output = 0L;
+ }
+};
+
+KBufferedSocket::KBufferedSocket(const QString& host, const QString& service,
+ QObject *parent, const char *name)
+ : KStreamSocket(host, service, parent, name),
+ d(new KBufferedSocketPrivate)
+{
+ setInputBuffering(true);
+ setOutputBuffering(true);
+}
+
+KBufferedSocket::~KBufferedSocket()
+{
+ closeNow();
+ delete d->input;
+ delete d->output;
+ delete d;
+}
+
+void KBufferedSocket::setSocketDevice(KSocketDevice* device)
+{
+ KStreamSocket::setSocketDevice(device);
+ device->setBlocking(false);
+}
+
+bool KBufferedSocket::setSocketOptions(int opts)
+{
+ if (opts == Blocking)
+ return false;
+
+ opts &= ~Blocking;
+ return KStreamSocket::setSocketOptions(opts);
+}
+
+void KBufferedSocket::close()
+{
+ if (!d->output || d->output->isEmpty())
+ closeNow();
+ else
+ {
+ setState(Closing);
+ QSocketNotifier *n = socketDevice()->readNotifier();
+ if (n)
+ n->setEnabled(false);
+ emit stateChanged(Closing);
+ }
+}
+
+Q_LONG KBufferedSocket::bytesAvailable() const
+{
+ if (!d->input)
+ return KStreamSocket::bytesAvailable();
+
+ return d->input->length();
+}
+
+Q_LONG KBufferedSocket::waitForMore(int msecs, bool *timeout)
+{
+ Q_LONG retval = KStreamSocket::waitForMore(msecs, timeout);
+ if (d->input)
+ {
+ resetError();
+ slotReadActivity();
+ return bytesAvailable();
+ }
+ return retval;
+}
+
+Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen)
+{
+ if (d->input)
+ {
+ if (d->input->isEmpty())
+ {
+ setError(IO_ReadError, WouldBlock);
+ emit gotError(WouldBlock);
+ return -1;
+ }
+ resetError();
+ return d->input->consumeBuffer(data, maxlen);
+ }
+ return KStreamSocket::readBlock(data, maxlen);
+}
+
+Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
+{
+ from = peerAddress();
+ return readBlock(data, maxlen);
+}
+
+Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen)
+{
+ if (d->input)
+ {
+ if (d->input->isEmpty())
+ {
+ setError(IO_ReadError, WouldBlock);
+ emit gotError(WouldBlock);
+ return -1;
+ }
+ resetError();
+ return d->input->consumeBuffer(data, maxlen, false);
+ }
+ return KStreamSocket::peekBlock(data, maxlen);
+}
+
+Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
+{
+ from = peerAddress();
+ return peekBlock(data, maxlen);
+}
+
+Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG len)
+{
+ if (state() != Connected)
+ {
+ // cannot write now!
+ setError(IO_WriteError, NotConnected);
+ return -1;
+ }
+
+ if (d->output)
+ {
+ if (d->output->isFull())
+ {
+ setError(IO_WriteError, WouldBlock);
+ emit gotError(WouldBlock);
+ return -1;
+ }
+ resetError();
+
+ // enable notifier to send data
+ QSocketNotifier *n = socketDevice()->writeNotifier();
+ if (n)
+ n->setEnabled(true);
+
+ return d->output->feedBuffer(data, len);
+ }
+
+ return KStreamSocket::writeBlock(data, len);
+}
+
+Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG maxlen,
+ const KSocketAddress&)
+{
+ // ignore the third parameter
+ return writeBlock(data, maxlen);
+}
+
+void KBufferedSocket::enableRead(bool enable)
+{
+ KStreamSocket::enableRead(enable);
+ if (!enable && d->input)
+ {
+ // reenable it
+ QSocketNotifier *n = socketDevice()->readNotifier();
+ if (n)
+ n->setEnabled(true);
+ }
+
+ if (enable && state() != Connected && d->input && !d->input->isEmpty())
+ // this means the buffer is still dirty
+ // allow the signal to be emitted
+ QTimer::singleShot(0, this, SLOT(slotReadActivity()));
+}
+
+void KBufferedSocket::enableWrite(bool enable)
+{
+ KStreamSocket::enableWrite(enable);
+ if (!enable && d->output && !d->output->isEmpty())
+ {
+ // reenable it
+ QSocketNotifier *n = socketDevice()->writeNotifier();
+ if (n)
+ n->setEnabled(true);
+ }
+}
+
+void KBufferedSocket::stateChanging(SocketState newState)
+{
+ if (newState == Connecting || newState == Connected)
+ {
+ // we're going to connect
+ // make sure the buffers are clean
+ if (d->input)
+ d->input->clear();
+ if (d->output)
+ d->output->clear();
+
+ // also, turn on notifiers
+ enableRead(emitsReadyRead());
+ enableWrite(emitsReadyWrite());
+ }
+ KStreamSocket::stateChanging(newState);
+}
+
+void KBufferedSocket::setInputBuffering(bool enable)
+{
+ QMutexLocker locker(mutex());
+ if (!enable)
+ {
+ delete d->input;
+ d->input = 0L;
+ }
+ else if (d->input == 0L)
+ {
+ d->input = new KSocketBuffer;
+ }
+}
+
+KIOBufferBase* KBufferedSocket::inputBuffer()
+{
+ return d->input;
+}
+
+void KBufferedSocket::setOutputBuffering(bool enable)
+{
+ QMutexLocker locker(mutex());
+ if (!enable)
+ {
+ delete d->output;
+ d->output = 0L;
+ }
+ else if (d->output == 0L)
+ {
+ d->output = new KSocketBuffer;
+ }
+}
+
+KIOBufferBase* KBufferedSocket::outputBuffer()
+{
+ return d->output;
+}
+
+Q_ULONG KBufferedSocket::bytesToWrite() const
+{
+ if (!d->output)
+ return 0;
+
+ return d->output->length();
+}
+
+void KBufferedSocket::closeNow()
+{
+ KStreamSocket::close();
+ if (d->output)
+ d->output->clear();
+}
+
+bool KBufferedSocket::canReadLine() const
+{
+ if (!d->input)
+ return false;
+
+ return d->input->canReadLine();
+}
+
+QCString KBufferedSocket::readLine()
+{
+ return d->input->readLine();
+}
+
+void KBufferedSocket::waitForConnect()
+{
+ if (state() != Connecting)
+ return; // nothing to be waited on
+
+ KStreamSocket::setSocketOptions(socketOptions() | Blocking);
+ connectionEvent();
+ KStreamSocket::setSocketOptions(socketOptions() & ~Blocking);
+}
+
+void KBufferedSocket::slotReadActivity()
+{
+ if (d->input && state() == Connected)
+ {
+ mutex()->lock();
+ Q_LONG len = d->input->receiveFrom(socketDevice());
+
+ if (len == -1)
+ {
+ if (socketDevice()->error() != WouldBlock)
+ {
+ // nope, another error!
+ copyError();
+ mutex()->unlock();
+ emit gotError(error());
+ closeNow(); // emits closed
+ return;
+ }
+ }
+ else if (len == 0)
+ {
+ // remotely closed
+ setError(IO_ReadError, RemotelyDisconnected);
+ mutex()->unlock();
+ emit gotError(error());
+ closeNow(); // emits closed
+ return;
+ }
+
+ // no error
+ mutex()->unlock();
+ }
+
+ if (state() == Connected)
+ KStreamSocket::slotReadActivity(); // this emits readyRead
+ else if (emitsReadyRead()) // state() != Connected
+ {
+ if (d->input && !d->input->isEmpty())
+ {
+ // buffer isn't empty
+ // keep emitting signals till it is
+ QTimer::singleShot(0, this, SLOT(slotReadActivity()));
+ emit readyRead();
+ }
+ }
+}
+
+void KBufferedSocket::slotWriteActivity()
+{
+ if (d->output && !d->output->isEmpty() &&
+ (state() == Connected || state() == Closing))
+ {
+ mutex()->lock();
+ Q_LONG len = d->output->sendTo(socketDevice());
+
+ if (len == -1)
+ {
+ if (socketDevice()->error() != WouldBlock)
+ {
+ // nope, another error!
+ copyError();
+ mutex()->unlock();
+ emit gotError(error());
+ closeNow();
+ return;
+ }
+ }
+ else if (len == 0)
+ {
+ // remotely closed
+ setError(IO_ReadError, RemotelyDisconnected);
+ mutex()->unlock();
+ emit gotError(error());
+ closeNow();
+ return;
+ }
+
+ if (d->output->isEmpty())
+ // deactivate the notifier until we have something to send
+ // writeNotifier can't return NULL here
+ socketDevice()->writeNotifier()->setEnabled(false);
+
+ mutex()->unlock();
+ emit bytesWritten(len);
+ }
+
+ if (state() != Closing)
+ KStreamSocket::slotWriteActivity();
+ else if (d->output && d->output->isEmpty() && state() == Closing)
+ {
+ KStreamSocket::close(); // finished sending data
+ }
+}
+
+#include "kbufferedsocket.moc"
diff --git a/kdecore/network/kbufferedsocket.h b/kdecore/network/kbufferedsocket.h
new file mode 100644
index 000000000..b0b99f8d1
--- /dev/null
+++ b/kdecore/network/kbufferedsocket.h
@@ -0,0 +1,253 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago@kde.org>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KBUFFEREDSOCKET_H
+#define KBUFFEREDSOCKET_H
+
+#include <qobject.h>
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include "kstreamsocket.h"
+#include <kdelibs_export.h>
+
+class KIOBufferBase;
+
+namespace KNetwork {
+
+class KBufferedSocketPrivate;
+/** @class KBufferedSocket kbufferedsocket.h kbufferedsocket.h
+ * @brief Buffered stream sockets.
+ *
+ * This class allows the user to create and operate buffered stream sockets
+ * such as those used in most Internet connections. This class is
+ * also the one that resembles the most to the old @ref QSocket
+ * implementation.
+ *
+ * Objects of this type operate only in non-blocking mode. A call to
+ * setBlocking(true) will result in an error.
+ *
+ * @note Buffered sockets only make sense if you're using them from
+ * the main (event-loop) thread. This is actually a restriction
+ * imposed by Qt's QSocketNotifier. If you want to use a socket
+ * in an auxiliary thread, please use KStreamSocket.
+ *
+ * @see KNetwork::KStreamSocket, KNetwork::KServerSocket
+ * @author Thiago Macieira <thiago@kde.org>
+ */
+class KDECORE_EXPORT KBufferedSocket: public KStreamSocket
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor.
+ *
+ * @param node destination host
+ * @param service destination service to connect to
+ * @param parent the parent object for this object
+ * @param name the internal name for this object
+ */
+ KBufferedSocket(const QString& node = QString::null, const QString& service = QString::null,
+ QObject* parent = 0L, const char *name = 0L);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KBufferedSocket();
+
+ /**
+ * Be sure to catch new devices.
+ */
+ virtual void setSocketDevice(KSocketDevice* device);
+
+protected:
+ /**
+ * Buffered sockets can only operate in non-blocking mode.
+ */
+ virtual bool setSocketOptions(int opts);
+
+public:
+ /**
+ * Closes the socket for new data, but allow data that had been buffered
+ * for output with @ref writeBlock to be still be written.
+ *
+ * @sa closeNow
+ */
+ virtual void close();
+
+ /**
+ * Make use of the buffers.
+ */
+ virtual Q_LONG bytesAvailable() const;
+
+ /**
+ * Make use of buffers.
+ */
+ virtual Q_LONG waitForMore(int msecs, bool *timeout = 0L);
+
+ /**
+ * Reads data from the socket. Make use of buffers.
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen);
+
+ /**
+ * @overload
+ * Reads data from a socket.
+ *
+ * The @p from parameter is always set to @ref peerAddress()
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from);
+
+ /**
+ * Peeks data from the socket.
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen);
+
+ /**
+ * @overload
+ * Peeks data from the socket.
+ *
+ * The @p from parameter is always set to @ref peerAddress()
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen, KSocketAddress &from);
+
+ /**
+ * Writes data to the socket.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len);
+
+ /**
+ * @overload
+ * Writes data to the socket.
+ *
+ * The @p to parameter is discarded.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to);
+
+ /**
+ * Catch changes.
+ */
+ virtual void enableRead(bool enable);
+
+ /**
+ * Catch changes.
+ */
+ virtual void enableWrite(bool enable);
+
+ /**
+ * Sets the use of input buffering.
+ */
+ void setInputBuffering(bool enable);
+
+ /**
+ * Retrieves the input buffer object.
+ */
+ KIOBufferBase* inputBuffer();
+
+ /**
+ * Sets the use of output buffering.
+ */
+ void setOutputBuffering(bool enable);
+
+ /**
+ * Retrieves the output buffer object.
+ */
+ KIOBufferBase* outputBuffer();
+
+ /**
+ * Returns the length of the output buffer.
+ */
+ virtual Q_ULONG bytesToWrite() const;
+
+ /**
+ * Closes the socket and discards any output data that had been buffered
+ * with @ref writeBlock but that had not yet been written.
+ *
+ * @sa close
+ */
+ virtual void closeNow();
+
+ /**
+ * Returns true if a line can be read with @ref readLine
+ */
+ bool canReadLine() const;
+
+ /**
+ * Reads a line of data from the socket buffers.
+ */
+ QCString readLine();
+
+ // KDE4: make virtual, add timeout to match the Qt4 signature
+ // and move to another class up the hierarchy
+ /**
+ * Blocks until the connection is either established, or completely
+ * failed.
+ */
+ void waitForConnect();
+
+protected:
+ /**
+ * Catch connection to clear the buffers
+ */
+ virtual void stateChanging(SocketState newState);
+
+protected slots:
+ /**
+ * Slot called when there's read activity.
+ */
+ virtual void slotReadActivity();
+
+ /**
+ * Slot called when there's write activity.
+ */
+ virtual void slotWriteActivity();
+
+signals:
+ /**
+ * This signal is emitted whenever data is written.
+ */
+ void bytesWritten(int bytes);
+
+private:
+ KBufferedSocket(const KBufferedSocket&);
+ KBufferedSocket& operator=(const KBufferedSocket&);
+
+ KBufferedSocketPrivate *d;
+
+public:
+ // KDE4: remove this function
+ /**
+ * @deprecated
+ * Closes the socket.
+ *
+ * This function is provided to ease porting from KExtendedSocket,
+ * which required a call to reset() in order to be able to connect again
+ * using the same device. This is not necessary in KBufferedSocket any more.
+ */
+ inline void reset()
+ { closeNow(); }
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/kclientsocketbase.cpp b/kdecore/network/kclientsocketbase.cpp
new file mode 100644
index 000000000..b777dc8de
--- /dev/null
+++ b/kdecore/network/kclientsocketbase.cpp
@@ -0,0 +1,477 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003,2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <qsocketnotifier.h>
+#include <qtimer.h>
+#include <qmutex.h>
+
+#include "ksocketaddress.h"
+#include "kresolver.h"
+#include "ksocketbase.h"
+#include "ksocketdevice.h"
+#include "kclientsocketbase.h"
+
+using namespace KNetwork;
+
+class KNetwork::KClientSocketBasePrivate
+{
+public:
+ int state;
+
+ KResolver localResolver, peerResolver;
+ KResolverResults localResults, peerResults;
+
+ bool enableRead : 1, enableWrite : 1;
+};
+
+KClientSocketBase::KClientSocketBase(QObject *parent, const char *name)
+ : QObject(parent, name), d(new KClientSocketBasePrivate)
+{
+ d->state = Idle;
+ d->enableRead = true;
+ d->enableWrite = false;
+}
+
+KClientSocketBase::~KClientSocketBase()
+{
+ close();
+ delete d;
+}
+
+KClientSocketBase::SocketState KClientSocketBase::state() const
+{
+ return static_cast<SocketState>(d->state);
+}
+
+void KClientSocketBase::setState(SocketState state)
+{
+ d->state = state;
+ stateChanging(state);
+}
+
+bool KClientSocketBase::setSocketOptions(int opts)
+{
+ QMutexLocker locker(mutex());
+ KSocketBase::setSocketOptions(opts); // call parent
+
+ // don't create the device unnecessarily
+ if (hasDevice())
+ {
+ bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
+ copyError();
+ return result;
+ }
+
+ return true;
+}
+
+KResolver& KClientSocketBase::peerResolver() const
+{
+ return d->peerResolver;
+}
+
+const KResolverResults& KClientSocketBase::peerResults() const
+{
+ return d->peerResults;
+}
+
+KResolver& KClientSocketBase::localResolver() const
+{
+ return d->localResolver;
+}
+
+const KResolverResults& KClientSocketBase::localResults() const
+{
+ return d->localResults;
+}
+
+void KClientSocketBase::setResolutionEnabled(bool enable)
+{
+ if (enable)
+ {
+ d->localResolver.setFlags(d->localResolver.flags() & ~KResolver::NoResolve);
+ d->peerResolver.setFlags(d->peerResolver.flags() & ~KResolver::NoResolve);
+ }
+ else
+ {
+ d->localResolver.setFlags(d->localResolver.flags() | KResolver::NoResolve);
+ d->peerResolver.setFlags(d->peerResolver.flags() | KResolver::NoResolve);
+ }
+}
+
+void KClientSocketBase::setFamily(int families)
+{
+ d->localResolver.setFamily(families);
+ d->peerResolver.setFamily(families);
+}
+
+bool KClientSocketBase::lookup()
+{
+ if (state() == HostLookup && !blocking())
+ return true; // already doing lookup
+
+ if (state() > HostLookup)
+ return true; // results are already available
+
+ if (state() < HostLookup)
+ {
+ if (d->localResolver.serviceName().isNull() &&
+ !d->localResolver.nodeName().isNull())
+ d->localResolver.setServiceName(QString::fromLatin1(""));
+
+ // don't restart the lookups if they had succeeded and
+ // the input values weren't changed
+ QObject::connect(&d->peerResolver, SIGNAL(finished(KResolverResults)),
+ this, SLOT(lookupFinishedSlot()));
+ QObject::connect(&d->localResolver, SIGNAL(finished(KResolverResults)),
+ this, SLOT(lookupFinishedSlot()));
+
+ if (d->localResolver.status() <= 0)
+ d->localResolver.start();
+ if (d->peerResolver.status() <= 0)
+ d->peerResolver.start();
+
+ setState(HostLookup);
+ emit stateChanged(HostLookup);
+
+ if (!d->localResolver.isRunning() && !d->peerResolver.isRunning())
+ {
+ // if nothing is running, then the lookup results are still valid
+ // pretend we had done lookup
+ if (blocking())
+ lookupFinishedSlot();
+ else
+ QTimer::singleShot(0, this, SLOT(lookupFinishedSlot()));
+ }
+ else
+ {
+ d->localResults = d->peerResults = KResolverResults();
+ }
+ }
+
+ if (blocking())
+ {
+ // we're in blocking mode operation
+ // wait for the results
+
+ localResolver().wait();
+ peerResolver().wait();
+
+ // lookupFinishedSlot has been called
+ }
+
+ return true;
+}
+
+bool KClientSocketBase::bind(const KResolverEntry& address)
+{
+ if (state() == HostLookup || state() > Connecting)
+ return false;
+
+ if (socketDevice()->bind(address))
+ {
+ resetError();
+
+ // don't set the state or emit signals if we are in a higher state
+ if (state() < Bound)
+ {
+ setState(Bound);
+ emit stateChanged(Bound);
+ emit bound(address);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool KClientSocketBase::connect(const KResolverEntry& address)
+{
+ if (state() == Connected)
+ return true; // to be compliant with the other classes
+ if (state() == HostLookup || state() > Connecting)
+ return false;
+
+ bool ok = socketDevice()->connect(address);
+ copyError();
+
+ if (ok)
+ {
+ SocketState newstate;
+ if (error() == InProgress)
+ newstate = Connecting;
+ else
+ newstate = Connected;
+
+ if (state() < newstate)
+ {
+ setState(newstate);
+ emit stateChanged(newstate);
+ if (error() == NoError)
+ {
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+ emit connected(address);
+ }
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool KClientSocketBase::disconnect()
+{
+ if (state() != Connected)
+ return false;
+
+ bool ok = socketDevice()->disconnect();
+ copyError();
+
+ if (ok)
+ {
+ setState(Unconnected);
+ emit stateChanged(Unconnected);
+ return true;
+ }
+ return false;
+}
+
+void KClientSocketBase::close()
+{
+ if (state() == Idle)
+ return; // nothing to do
+
+ if (state() == HostLookup)
+ {
+ d->peerResolver.cancel(false);
+ d->localResolver.cancel(false);
+ }
+
+ d->localResults = d->peerResults = KResolverResults();
+
+ socketDevice()->close();
+ setState(Idle);
+ emit stateChanged(Idle);
+ emit closed();
+}
+
+// This function is unlike all the others because it is const
+Q_LONG KClientSocketBase::bytesAvailable() const
+{
+ return socketDevice()->bytesAvailable();
+}
+
+// All the functions below look really alike
+// Should I use a macro to define them?
+
+Q_LONG KClientSocketBase::waitForMore(int msecs, bool *timeout)
+{
+ resetError();
+ Q_LONG retval = socketDevice()->waitForMore(msecs, timeout);
+ if (retval == -1)
+ {
+ copyError();
+ emit gotError(error());
+ }
+ return retval;
+}
+
+Q_LONG KClientSocketBase::readBlock(char *data, Q_ULONG maxlen)
+{
+ resetError();
+ Q_LONG retval = socketDevice()->readBlock(data, maxlen);
+ if (retval == -1)
+ {
+ copyError();
+ emit gotError(error());
+ }
+ return retval;
+}
+
+Q_LONG KClientSocketBase::readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
+{
+ resetError();
+ Q_LONG retval = socketDevice()->readBlock(data, maxlen, from);
+ if (retval == -1)
+ {
+ copyError();
+ emit gotError(error());
+ }
+ return retval;
+}
+
+Q_LONG KClientSocketBase::peekBlock(char *data, Q_ULONG maxlen)
+{
+ resetError();
+ Q_LONG retval = socketDevice()->peekBlock(data, maxlen);
+ if (retval == -1)
+ {
+ copyError();
+ emit gotError(error());
+ }
+ return retval;
+}
+
+Q_LONG KClientSocketBase::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
+{
+ resetError();
+ Q_LONG retval = socketDevice()->peekBlock(data, maxlen, from);
+ if (retval == -1)
+ {
+ copyError();
+ emit gotError(error());
+ }
+ return retval;
+}
+
+Q_LONG KClientSocketBase::writeBlock(const char *data, Q_ULONG len)
+{
+ resetError();
+ Q_LONG retval = socketDevice()->writeBlock(data, len);
+ if (retval == -1)
+ {
+ copyError();
+ emit gotError(error());
+ }
+ return retval;
+}
+
+Q_LONG KClientSocketBase::writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to)
+{
+ resetError();
+ Q_LONG retval = socketDevice()->writeBlock(data, len, to);
+ if (retval == -1)
+ {
+ copyError();
+ emit gotError(error());
+ }
+ return retval;
+}
+
+KSocketAddress KClientSocketBase::localAddress() const
+{
+ return socketDevice()->localAddress();
+}
+
+KSocketAddress KClientSocketBase::peerAddress() const
+{
+ return socketDevice()->peerAddress();
+}
+
+bool KClientSocketBase::emitsReadyRead() const
+{
+ return d->enableRead;
+}
+
+void KClientSocketBase::enableRead(bool enable)
+{
+ QMutexLocker locker(mutex());
+
+ d->enableRead = enable;
+ QSocketNotifier *n = socketDevice()->readNotifier();
+ if (n)
+ n->setEnabled(enable);
+}
+
+bool KClientSocketBase::emitsReadyWrite() const
+{
+ return d->enableWrite;
+}
+
+void KClientSocketBase::enableWrite(bool enable)
+{
+ QMutexLocker locker(mutex());
+
+ d->enableWrite = enable;
+ QSocketNotifier *n = socketDevice()->writeNotifier();
+ if (n)
+ n->setEnabled(enable);
+}
+
+void KClientSocketBase::slotReadActivity()
+{
+ if (d->enableRead)
+ emit readyRead();
+}
+
+void KClientSocketBase::slotWriteActivity()
+{
+ if (d->enableWrite)
+ emit readyWrite();
+}
+
+void KClientSocketBase::lookupFinishedSlot()
+{
+ if (d->peerResolver.isRunning() || d->localResolver.isRunning() || state() != HostLookup)
+ return;
+
+ QObject::disconnect(&d->peerResolver, 0L, this, SLOT(lookupFinishedSlot()));
+ QObject::disconnect(&d->localResolver, 0L, this, SLOT(lookupFinishedSlot()));
+ if (d->peerResolver.status() < 0 || d->localResolver.status() < 0)
+ {
+ setState(Idle); // backtrack
+ setError(IO_LookupError, LookupFailure);
+ emit stateChanged(Idle);
+ emit gotError(LookupFailure);
+ return;
+ }
+
+ d->localResults = d->localResolver.results();
+ d->peerResults = d->peerResolver.results();
+ setState(HostFound);
+ emit stateChanged(HostFound);
+ emit hostFound();
+}
+
+void KClientSocketBase::stateChanging(SocketState newState)
+{
+ if (newState == Connected && socketDevice())
+ {
+ QSocketNotifier *n = socketDevice()->readNotifier();
+ if (n)
+ {
+ n->setEnabled(d->enableRead);
+ QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
+ }
+ else
+ return;
+
+ n = socketDevice()->writeNotifier();
+ if (n)
+ {
+ n->setEnabled(d->enableWrite);
+ QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
+ }
+ else
+ return;
+ }
+}
+
+void KClientSocketBase::copyError()
+{
+ setError(socketDevice()->status(), socketDevice()->error());
+}
+
+#include "kclientsocketbase.moc"
diff --git a/kdecore/network/kclientsocketbase.h b/kdecore/network/kclientsocketbase.h
new file mode 100644
index 000000000..ccd94994a
--- /dev/null
+++ b/kdecore/network/kclientsocketbase.h
@@ -0,0 +1,517 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KCLIENTSOCKETBASE_H
+#define KCLIENTSOCKETBASE_H
+
+#include <qobject.h>
+#include <qstring.h>
+
+#include "ksocketbase.h"
+#include "kresolver.h"
+#include <kdelibs_export.h>
+
+namespace KNetwork {
+
+class KClientSocketBasePrivate;
+/** @class KClientSocketBase kclientsocketbase.h kclientsocketbase.h
+ * @brief Abstract client socket class.
+ *
+ * This class provides the base functionality for client sockets,
+ * such as, and especially, name resolution and signals.
+ *
+ * @note This class is abstract. If you're looking for a normal,
+ * client socket class, see @ref KStreamSocket and KBufferedSocket
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KClientSocketBase : public QObject, public KActiveSocketBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Socket states.
+ *
+ * These are the possible states for a KClientSocketBase:
+ * - Idle: socket is not connected
+ * - HostLookup: socket is doing host lookup prior to connecting
+ * - HostFound: name lookup is complete
+ * - Bound: the socket is locally bound
+ * - Connecting: socket is attempting connection
+ * - Open: socket is open
+ * - Connected (=Open): socket is connected
+ * - Connection (=Open): yet another name for a connected socket
+ * - Closing: socket is shutting down
+ *
+ * Whenever the socket state changes, the @ref stateChanged(int) signal
+ * will be emitted.
+ */
+ enum SocketState
+ {
+ Idle,
+ HostLookup,
+ HostFound,
+ Bound,
+ Connecting,
+ Open,
+ Closing,
+
+ Unconnected = Bound,
+ Connected = Open,
+ Connection = Open
+ };
+
+public:
+ /**
+ * Default constructor.
+ *
+ * @param parent the parent QObject object
+ * @param name the name of this object
+ */
+ KClientSocketBase(QObject* parent, const char *name);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KClientSocketBase();
+
+ /**
+ * Returns the current state for this socket.
+ * @see SocketState
+ */
+ SocketState state() const;
+
+protected:
+ /**
+ * Sets the socket options. Reimplemented from KSocketBase.
+ */
+ virtual bool setSocketOptions(int opts);
+
+public:
+ /**
+ * Returns the internal KResolver object used for
+ * looking up the peer host name and service.
+ *
+ * This can be used to set extra options to the
+ * lookup process other than the default values, as well
+ * as obtaining the error codes in case of lookup failure.
+ */
+ KResolver& peerResolver() const;
+
+ /**
+ * Returns the internal list of resolved results for the peer address.
+ */
+ const KResolverResults& peerResults() const;
+
+ /**
+ * Returns the internal KResolver object used for
+ * looking up the local host name and service.
+ *
+ * This can be used to set extra options to the
+ * lookup process other than the default values, as well
+ * as obtaining the error codes in case of lookup failure.
+ */
+ KResolver& localResolver() const;
+
+ /**
+ * Returns the internal list of resolved results for the local address.
+ */
+ const KResolverResults& localResults() const;
+
+ /**
+ * Enables or disables name resolution. If this flag is set to true,
+ * @ref bind and @ref connect operations will trigger name lookup
+ * operations (i.e., converting a hostname into its binary form).
+ * If the flag is set to false, those operations will instead
+ * try to convert a string representation of an address without
+ * attempting name resolution.
+ *
+ * This is useful, for instance, when IP addresses are in
+ * their string representation (such as "1.2.3.4") or come
+ * from other sources like @ref KSocketAddress.
+ *
+ * @param enable whether to enable
+ */
+ void setResolutionEnabled(bool enable);
+
+ /**
+ * Sets the allowed families for the resolutions.
+ *
+ * @param families the families that we want/accept
+ * @see KResolver::SocketFamilies for possible values
+ */
+ void setFamily(int families);
+
+ /**
+ * Starts the lookup for peer and local hostnames as
+ * well as their services.
+ *
+ * If the blocking mode for this object is on, this function will
+ * wait for the lookup results to be available (by calling the
+ * @ref KResolver::wait method on the resolver objects).
+ *
+ * When the lookup is done, the signal @ref hostFound will be
+ * emitted (only once, even if we're doing a double lookup).
+ * If the lookup failed (for any of the two lookups) the
+ * @ref gotError signal will be emitted with the appropriate
+ * error condition (see @ref KSocketBase::SocketError).
+ *
+ * This function returns true on success and false on error. Note that
+ * this is not the lookup result!
+ */
+ virtual bool lookup();
+
+ /**
+ * Binds this socket to the given nodename and service,
+ * or use the default ones if none are given.
+ *
+ * Upon successful binding, the @ref bound signal will be
+ * emitted. If an error is found, the @ref gotError
+ * signal will be emitted.
+ *
+ * @note Due to the internals of the name lookup and binding
+ * mechanism, some (if not most) implementations of this function
+ * do not actually bind the socket until the connection
+ * is requested (see @ref connect). They only set the values
+ * for future reference.
+ *
+ * This function returns true on success.
+ *
+ * @param node the nodename
+ * @param service the service
+ */
+ virtual bool bind(const QString& node = QString::null,
+ const QString& service = QString::null) = 0;
+
+ /**
+ * Reimplemented from KSocketBase. Connect this socket to this
+ * specific address.
+ *
+ * Unlike @ref bind(const QString&, const QString&) above, this function
+ * really does bind the socket. No lookup is performed. The @ref bound
+ * signal will be emitted.
+ */
+ virtual bool bind(const KResolverEntry& address);
+
+ /**
+ * Attempts to connect to the these hostname and service,
+ * or use the default ones if none are given. If a connection attempt
+ * is already in progress, check on its state and set the error status
+ * (NoError or InProgress).
+ *
+ * If the blocking mode for this object is on, this function will only
+ * return when all the resolved peer addresses have been tried or when
+ * a connection is established.
+ *
+ * Upon successfully connecting, the @ref connected signal
+ * will be emitted. If an error is found, the @ref gotError
+ * signal will be emitted.
+ *
+ * @par Note for derived classes:
+ * Derived classes must implement this function. The implementation
+ * will set the parameters for the lookup (using the peer KResolver
+ * object) and call @ref lookup to start it.
+ *
+ * @par
+ * The implementation should use the @ref hostFound
+ * signal to be notified of the completion of the lookup process and
+ * then proceed to start the connection itself. Care should be taken
+ * regarding the value of @ref blocking flag.
+ *
+ * @param node the nodename
+ * @param service the service
+ */
+ virtual bool connect(const QString& node = QString::null,
+ const QString& service = QString::null) = 0;
+
+ /**
+ * @overload
+ * Reimplemented from KSocketBase.
+ */
+ virtual bool connect(const KResolverEntry& address);
+
+ /**
+ * @deprecated
+ * This is a convenience function provided to ease migrating from
+ * Qt 3.x's QSocket class.
+ */
+ inline void connectToHost(const QString& host, Q_UINT16 port)
+ { connect(host, QString::number(port)); }
+
+ /**
+ * Disconnects the socket.
+ * Note that not all socket types can disconnect.
+ */
+ virtual bool disconnect();
+
+ /**
+ * Opens the socket. Reimplemented from QIODevice.
+ *
+ * You should not call this function; instead, use @ref connect
+ */
+ virtual inline bool open(int)
+ { return connect(); }
+
+ /**
+ * Closes the socket. Reimplemented from QIODevice.
+ *
+ * The closing of the socket causes the emission of the
+ * signal @ref closed.
+ */
+ virtual void close();
+
+ /**
+ * This call is not supported on sockets. Reimplemented from QIODevice.
+ */
+ virtual void flush()
+ { }
+
+ /**
+ * Returns the number of bytes available on this socket.
+ * Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG bytesAvailable() const;
+
+ /**
+ * Waits for more data. Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG waitForMore(int msecs, bool *timeout = 0L);
+
+ /**
+ * Reads data from a socket. Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen);
+
+ /**
+ * @overload
+ * Reads data from a socket. Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from);
+
+ /**
+ * Peeks data from the socket. Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen);
+
+ /**
+ * @overload
+ * Peeks data from the socket. Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen, KSocketAddress &from);
+
+ /**
+ * Writes data to the socket. Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len);
+
+ /**
+ * @overload
+ * Writes data to the socket. Reimplemented from KSocketBase.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to);
+
+ /**
+ * Returns the local socket address. Reimplemented from KSocketBase.
+ */
+ virtual KSocketAddress localAddress() const;
+
+ /**
+ * Returns the peer socket address. Reimplemented from KSocketBase.
+ */
+ virtual KSocketAddress peerAddress() const;
+
+ /**
+ * Returns true if the readyRead signal is set to be emitted.
+ */
+ bool emitsReadyRead() const;
+
+ /**
+ * Enables the emission of the readyRead signal.
+ * By default, this signal is enabled.
+ *
+ * @param enable whether to enable the signal
+ */
+ virtual void enableRead(bool enable);
+
+ /**
+ * Returns true if the readyWrite signal is set to be emitted.
+ */
+ bool emitsReadyWrite() const;
+
+ /**
+ * Enables the emission of the readyWrite signal.
+ * By default, this signal is disabled.
+ *
+ * @param enable whether to enable the signal
+ */
+ virtual void enableWrite(bool enable);
+
+protected slots:
+ // protected slots
+
+ /**
+ * This slot is connected to the read notifier's signal meaning
+ * the socket can read more data.
+ *
+ * The default implementation only emits the readyRead signal.
+ *
+ * Override if your class requires processing of incoming
+ * data.
+ */
+ virtual void slotReadActivity();
+
+ /**
+ * This slot is connected to the write notifier's signal
+ * meaning the socket can write more data.
+ *
+ * The default implementation only emits the readyWrite signal.
+ *
+ * Override if your class writes data from another source
+ * (like a buffer).
+ */
+ virtual void slotWriteActivity();
+
+private slots:
+ void lookupFinishedSlot();
+
+signals:
+ /**
+ * This signal is emitted whenever the socket state changes.
+ *
+ * Note: do not delete this object inside the slot called by this
+ * signal.
+ *
+ * @param newstate the new state of the socket object
+ */
+ void stateChanged(int newstate);
+
+ /**
+ * This signal is emitted when this object finds an error.
+ * The @p code parameter contains the error code that can
+ * also be found by calling @ref error.
+ */
+ void gotError(int code);
+
+ /**
+ * This signal is emitted when the lookup is successfully completed.
+ */
+ void hostFound();
+
+ /**
+ * This signal is emitted when the socket successfully binds
+ * to an address.
+ *
+ * @param local the local address we bound to
+ */
+ void bound(const KResolverEntry& local);
+
+ /**
+ * This signal is emitted when the socket is about to connect
+ * to an address (but before doing so).
+ *
+ * The @p skip parameter can be used to make the loop skip this address.
+ * Its value is initially false: change it to true if you want to
+ * skip the current address (as given by @p remote).
+ *
+ * This function is also useful if one wants to reset the timeout.
+ *
+ * @param remote the address we're about to connect to
+ * @param skip set to true if you want to skip this address
+ * @note if the connection is successful, the @ref connected signal will be
+ * emitted.
+ */
+ void aboutToConnect(const KResolverEntry& remote, bool& skip);
+
+ /**
+ * This socket is emitted when the socket successfully connects
+ * to a remote address.
+ *
+ * @param remote the remote address we did connect to
+ */
+ void connected(const KResolverEntry& remote);
+
+ /**
+ * This signal is emitted when the socket completes the
+ * closing/shut down process.
+ */
+ void closed();
+
+ /**
+ * This signal is emitted whenever the socket is ready for
+ * reading -- i.e., there is data to be read in the buffers.
+ * The subsequent read operation is guaranteed to be non-blocking.
+ *
+ * You can toggle the emission of this signal with the @ref enableRead
+ * function. This signal is by default enabled.
+ */
+ void readyRead();
+
+ /**
+ * This signal is emitted whenever the socket is ready for
+ * writing -- i.e., whenever there's space available in the buffers
+ * to receive more data. The subsequent write operation is
+ * guaranteed to be non-blocking.
+ *
+ * You can toggle the emission of this signal with the @ref enableWrite
+ * function. This signal is by default disabled. You will
+ * want to disable this signal after the first reception, since
+ * it'll probably fire at every event loop.
+ */
+ void readyWrite();
+
+protected:
+ /**
+ * Sets the socket state to @p state. This function does not
+ * emit the @ref stateChanged signal.
+ */
+ void setState(SocketState state);
+
+ /**
+ * This function is called by @ref setState whenever the state
+ * changes. You should override it if you need to specify any
+ * actions to be done when the state changes.
+ *
+ * The default implementation acts for these states only:
+ * - Connected: it sets up the socket notifiers to fire readyRead and
+ * readyWrite signals.
+ */
+ virtual void stateChanging(SocketState newState);
+
+ /**
+ * Convenience function to set this object's error code to match
+ * that of the socket device.
+ */
+ void copyError();
+
+private:
+ KClientSocketBase(const KClientSocketBase&);
+ KClientSocketBase& operator=(const KClientSocketBase&);
+
+ KClientSocketBasePrivate *d;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/kdatagramsocket.cpp b/kdecore/network/kdatagramsocket.cpp
new file mode 100644
index 000000000..a0d3bc05d
--- /dev/null
+++ b/kdecore/network/kdatagramsocket.cpp
@@ -0,0 +1,283 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003,2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "ksocketaddress.h"
+#include "kresolver.h"
+#include "ksocketdevice.h"
+#include "kdatagramsocket.h"
+
+using namespace KNetwork;
+
+/*
+ * TODO:
+ *
+ * don't use signals and slots to track state changes: use stateChanging
+ *
+ */
+
+KDatagramSocket::KDatagramSocket(QObject* parent, const char *name)
+ : KClientSocketBase(parent, name), d(0L)
+{
+ peerResolver().setFamily(KResolver::KnownFamily);
+ localResolver().setFamily(KResolver::KnownFamily);
+
+ peerResolver().setSocketType(SOCK_DGRAM);
+ localResolver().setSocketType(SOCK_DGRAM);
+
+ localResolver().setFlags(KResolver::Passive);
+
+ // QObject::connect(localResolver(), SIGNAL(finished(KResolverResults)),
+ // this, SLOT(lookupFinishedLocal()));
+ QObject::connect(&peerResolver(), SIGNAL(finished(KResolverResults)),
+ this, SLOT(lookupFinishedPeer()));
+ QObject::connect(this, SIGNAL(hostFound()), this, SLOT(lookupFinishedLocal()));
+}
+
+KDatagramSocket::~KDatagramSocket()
+{
+ // KClientSocketBase's destructor closes the socket
+
+ //delete d;
+}
+
+bool KDatagramSocket::bind(const QString& node, const QString& service)
+{
+ if (state() >= Bound)
+ return false;
+
+ if (localResolver().isRunning())
+ localResolver().cancel(false);
+
+ // no, we must do a host lookup
+ localResolver().setAddress(node, service);
+
+ if (!lookup())
+ return false;
+
+ // see if lookup has finished already
+ // this also catches blocking mode, since lookup has to finish
+ // its processing if we're in blocking mode
+ if (state() > HostLookup)
+ return doBind();
+
+ return true;
+}
+
+bool KDatagramSocket::connect(const QString& node, const QString& service)
+{
+ if (state() >= Connected)
+ return true; // already connected
+
+ if (peerResolver().nodeName() != node ||
+ peerResolver().serviceName() != service)
+ peerResolver().setAddress(node, service); // this resets the resolver's state
+
+ // KClientSocketBase::lookup only works if the state is Idle or HostLookup
+ // therefore, we store the old state, call the lookup routine and then set
+ // it back.
+ SocketState s = state();
+ setState(s == Connecting ? HostLookup : Idle);
+ bool ok = lookup();
+ if (!ok)
+ {
+ setState(s); // go back
+ return false;
+ }
+
+ // check if lookup is finished
+ // if we're in blocking mode, then the lookup has to be finished
+ if (state() == HostLookup)
+ {
+ // it hasn't finished
+ setState(Connecting);
+ emit stateChanged(Connecting);
+ return true;
+ }
+
+ // it has to be finished here
+ if (state() != Connected)
+ {
+ setState(Connecting);
+ emit stateChanged(Connecting);
+ lookupFinishedPeer();
+ }
+
+ return state() == Connected;
+}
+
+KDatagramPacket KDatagramSocket::receive()
+{
+ Q_LONG size = bytesAvailable();
+ if (size == 0)
+ {
+ // nothing available yet to read
+ // wait for data if we're not blocking
+ if (blocking())
+ socketDevice()->waitForMore(-1); // wait forever
+ else
+ {
+ // mimic error
+ setError(IO_ReadError, WouldBlock);
+ emit gotError(WouldBlock);
+ return KDatagramPacket();
+ }
+
+ // try again
+ size = bytesAvailable();
+ }
+
+ QByteArray data(size);
+ KSocketAddress address;
+
+ // now do the reading
+ size = readBlock(data.data(), size, address);
+ if (size < 0)
+ // error has been set
+ return KDatagramPacket();
+
+ data.resize(size); // just to be sure
+ return KDatagramPacket(data, address);
+}
+
+Q_LONG KDatagramSocket::send(const KDatagramPacket& packet)
+{
+ return writeBlock(packet.data(), packet.size(), packet.address());
+}
+
+Q_LONG KDatagramSocket::writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to)
+{
+ if (to.family() != AF_UNSPEC)
+ {
+ // make sure the socket is open at this point
+ if (!socketDevice()->isOpen())
+ // error handling will happen below
+ socketDevice()->create(to.family(), SOCK_DGRAM, 0);
+ }
+ return KClientSocketBase::writeBlock(data, len, to);
+}
+
+void KDatagramSocket::lookupFinishedLocal()
+{
+ // bind lookup has finished and succeeded
+ // state() == HostFound
+
+ if (!doBind())
+ return; // failed binding
+
+ if (peerResults().count() > 0)
+ {
+ setState(Connecting);
+ emit stateChanged(Connecting);
+
+ lookupFinishedPeer();
+ }
+}
+
+void KDatagramSocket::lookupFinishedPeer()
+{
+ // this function is called by lookupFinishedLocal above
+ // and is also connected to a signal
+ // so it might be called twice.
+
+ if (state() != Connecting)
+ return;
+
+ if (peerResults().count() == 0)
+ {
+ setState(Unconnected);
+ emit stateChanged(Unconnected);
+ return;
+ }
+
+ KResolverResults::ConstIterator it = peerResults().begin();
+ for ( ; it != peerResults().end(); ++it)
+ if (connect(*it))
+ {
+ // weee, we connected
+
+ setState(Connected); // this sets up signals
+ //setupSignals(); // setState sets up the signals
+
+ emit stateChanged(Connected);
+ emit connected(*it);
+ return;
+ }
+
+ // no connection
+ copyError();
+ setState(Unconnected);
+ emit stateChanged(Unconnected);
+ emit gotError(error());
+}
+
+bool KDatagramSocket::doBind()
+{
+ if (localResults().count() == 0)
+ return true;
+ if (state() >= Bound)
+ return true; // already bound
+
+ KResolverResults::ConstIterator it = localResults().begin();
+ for ( ; it != localResults().end(); ++it)
+ if (bind(*it))
+ {
+ // bound
+ setupSignals();
+ return true;
+ }
+
+ // not bound
+ // no need to set state since it can only be HostFound already
+ copyError();
+ emit gotError(error());
+ return false;
+}
+
+void KDatagramSocket::setupSignals()
+{
+ QSocketNotifier *n = socketDevice()->readNotifier();
+ if (n)
+ {
+ n->setEnabled(emitsReadyRead());
+ QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
+ }
+ else
+ return;
+
+ n = socketDevice()->writeNotifier();
+ if (n)
+ {
+ n->setEnabled(emitsReadyWrite());
+ QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
+ }
+ else
+ return;
+}
+
+#include "kdatagramsocket.moc"
diff --git a/kdecore/network/kdatagramsocket.h b/kdecore/network/kdatagramsocket.h
new file mode 100644
index 000000000..31ccf9af7
--- /dev/null
+++ b/kdecore/network/kdatagramsocket.h
@@ -0,0 +1,278 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KDATAGRAMSOCKET_H
+#define KDATAGRAMSOCKET_H
+
+#include <qcstring.h>
+
+#include "ksocketaddress.h"
+#include "kclientsocketbase.h"
+
+namespace KNetwork {
+
+class KResolverEntry;
+
+/**
+ * @class KDatagramPacket kdatagramsocket.h kdatagramsocket.h
+ * @brief one datagram
+ *
+ * This object represents one datagram of data sent or received through
+ * a datagram socket (as @ref KDatagramSocket or derived classes). A datagram
+ * consists of data as well as a network address associated (whither to send
+ * the data or whence it came).
+ *
+ * This is a lightweight class. Data is stored in a @ref QByteArray, which means
+ * that it is explicitly shared.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KDatagramPacket
+{
+ QByteArray m_data;
+ KSocketAddress m_address;
+
+public:
+ /**
+ * Default constructor.
+ */
+ KDatagramPacket()
+ { }
+
+ /**
+ * Constructs the datagram with the specified content.
+ */
+ KDatagramPacket(const QByteArray& content)
+ : m_data(content)
+ { }
+
+ /**
+ * Constructs the datagram with the specified content.
+ *
+ * @see setData for information on data sharing.
+ */
+ KDatagramPacket(const char* content, uint length)
+ { setData(content, length); }
+
+ /**
+ * Constructs the datagram with the specified content and address.
+ */
+ KDatagramPacket(const QByteArray& content, const KSocketAddress& addr)
+ : m_data(content), m_address(addr)
+ { }
+
+ /**
+ * Constructs the datagram with the specified content and address.
+ */
+ KDatagramPacket(const char *content, uint length, const KSocketAddress& addr)
+ : m_address(addr)
+ { setData(content, length); }
+
+ /**
+ * Copy constructor. Note that data is explicitly shared.
+ */
+ KDatagramPacket(const KDatagramPacket& other)
+ { *this = other; }
+
+ /**
+ * Destructor. Non-virtual.
+ */
+ ~KDatagramPacket()
+ { }
+
+ /**
+ * Returns the data.
+ */
+ const QByteArray& data() const
+ { return m_data; }
+
+ /**
+ * Returns the data length.
+ */
+ uint length() const
+ { return m_data.size(); }
+
+ /**
+ * Returns the data length.
+ */
+ uint size() const
+ { return m_data.size(); }
+
+ /**
+ * Returns true if this object is empty.
+ */
+ bool isEmpty() const
+ { return m_data.isEmpty(); }
+
+ /**
+ * Returns true if this object is null.
+ */
+ bool isNull() const
+ { return m_data.isNull(); }
+
+ /**
+ * Returns the socket address
+ */
+ const KSocketAddress& address() const
+ { return m_address; }
+
+ /**
+ * Sets the address stored to the given value.
+ */
+ void setAddress(const KSocketAddress& addr)
+ { m_address = addr; }
+
+ /**
+ * Detaches our data from a shared pool.
+ * @see QByteArray::detach
+ */
+ void detach()
+ { m_data.detach(); }
+
+ /**
+ * Sets the data to the given value. Data is explicitly shared.
+ */
+ void setData(const QByteArray& data)
+ { m_data = data; }
+
+ /**
+ * Sets the data to the given buffer and size.
+ */
+ void setData(const char* data, uint length)
+ { m_data.duplicate(data, length); }
+};
+
+class KDatagramSocketPrivate;
+/**
+ * @class KDatagramSocket kdatagramsocket.h kdatagramsocket.h
+ * @brief A socket that operates on datagrams.
+ *
+ * Unlike @ref KStreamSocket, which operates on a connection-based stream
+ * socket (generally TCP), this class and its descendants operates on datagrams,
+ * which are normally connectionless.
+ *
+ * This class in specific provides easy access to the system's connectionless
+ * SOCK_DGRAM sockets.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KDatagramSocket: public KClientSocketBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Default constructor.
+ */
+ KDatagramSocket(QObject* parent = 0L, const char *name = 0L);
+
+ /**
+ * Destructor. This closes the socket.
+ */
+ virtual ~KDatagramSocket();
+
+ /**
+ * Performs host lookups.
+ */
+ // virtual bool lookup();
+
+ /**
+ * Binds this socket to the given address. If the socket is blocking,
+ * the socket will be bound when this function returns.
+ *
+ * Note that binding a socket is not necessary to be able to send datagrams.
+ * Some protocol families will use anonymous source addresses, while others
+ * will allocate an address automatically.
+ */
+ virtual bool bind(const QString& node = QString::null,
+ const QString& service = QString::null);
+
+ /**
+ * @overload
+ * Binds this socket to the given address.
+ */
+ virtual bool bind(const KResolverEntry& entry)
+ { return KClientSocketBase::bind(entry); }
+
+ /**
+ * "Connects" this socket to the given address. Note that connecting
+ * a datagram socket normally does not establish a permanent connection
+ * with the peer nor normally returns an error in case of failure.
+ *
+ * Connecting means only to designate the given address as the default
+ * destination address for datagrams sent without destination addresses
+ * ( writeBlock(const char *, Q_ULONG) ).
+ *
+ * @note Calling connect will not cause the socket to be bound. You have
+ * to call @ref bind explicitly.
+ */
+ virtual bool connect(const QString& node = QString::null,
+ const QString& service = QString::null);
+
+ /**
+ * @overload
+ * "Connects" this socket to the given address.
+ */
+ virtual bool connect(const KResolverEntry& entry)
+ { return KClientSocketBase::connect(entry); }
+
+ /**
+ * Writes data to the socket. Reimplemented from KClientSocketBase.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to);
+
+ /**
+ * Receives one datagram from the stream. The reading process is guaranteed
+ * to be atomical and not lose data from the packet.
+ *
+ * If nothing could be read, a null object will be returned.
+ */
+ virtual KDatagramPacket receive();
+
+ /**
+ * Sends one datagram into the stream. The destination address must be
+ * set if this socket has not been connected (see @ref connect).
+ *
+ * The data in this packet will be sent only in one single datagram. If the
+ * system cannot send it like that, this function will fail. So, please take
+ * into consideration the datagram size limits.
+ *
+ * @returns the number of bytes written or -1 in case of error.
+ */
+ virtual Q_LONG send(const KDatagramPacket& packet);
+
+private slots:
+ void lookupFinishedLocal();
+ void lookupFinishedPeer();
+
+private:
+ bool doBind();
+ void setupSignals();
+
+ KDatagramSocketPrivate *d;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/khttpproxysocketdevice.cpp b/kdecore/network/khttpproxysocketdevice.cpp
new file mode 100644
index 000000000..73e433a2e
--- /dev/null
+++ b/kdecore/network/khttpproxysocketdevice.cpp
@@ -0,0 +1,281 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <qsocketnotifier.h>
+#include <qcstring.h>
+
+#include "kresolver.h"
+#include "ksocketaddress.h"
+#include "ksocketdevice.h"
+#include "khttpproxysocketdevice.h"
+
+using namespace KNetwork;
+
+KResolverEntry KHttpProxySocketDevice::defaultProxy;
+
+class KNetwork::KHttpProxySocketDevicePrivate
+{
+public:
+ KResolverEntry proxy;
+ QCString request;
+ QCString reply;
+ KSocketAddress peer;
+
+ KHttpProxySocketDevicePrivate()
+ : proxy(KHttpProxySocketDevice::defaultProxy)
+ { }
+};
+
+KHttpProxySocketDevice::KHttpProxySocketDevice(const KSocketBase* parent)
+ : KSocketDevice(parent), d(new KHttpProxySocketDevicePrivate)
+{
+}
+
+KHttpProxySocketDevice::KHttpProxySocketDevice(const KResolverEntry& proxy)
+ : d(new KHttpProxySocketDevicePrivate)
+{
+ d->proxy = proxy;
+}
+
+KHttpProxySocketDevice::~KHttpProxySocketDevice()
+{
+ // nothing special to be done during closing
+ // KSocketDevice::~KSocketDevice closes the socket
+
+ delete d;
+}
+
+int KHttpProxySocketDevice::capabilities() const
+{
+ return CanConnectString | CanNotBind | CanNotListen | CanNotUseDatagrams;
+}
+
+const KResolverEntry&
+KHttpProxySocketDevice::proxyServer() const
+{
+ return d->proxy;
+}
+
+void KHttpProxySocketDevice::setProxyServer(const KResolverEntry& proxy)
+{
+ d->proxy = proxy;
+}
+
+void KHttpProxySocketDevice::close()
+{
+ d->reply = d->request = QCString();
+ d->peer = KSocketAddress();
+ KSocketDevice::close();
+}
+
+KSocketAddress KHttpProxySocketDevice::peerAddress() const
+{
+ if (isOpen())
+ return d->peer;
+ return KSocketAddress();
+}
+
+KSocketAddress KHttpProxySocketDevice::externalAddress() const
+{
+ return KSocketAddress();
+}
+
+bool KHttpProxySocketDevice::connect(const KResolverEntry& address)
+{
+ if (d->proxy.family() == AF_UNSPEC)
+ // no proxy server set !
+ return KSocketDevice::connect(address);
+
+ if (isOpen())
+ {
+ // socket is already open
+ resetError();
+ return true;
+ }
+
+ if (m_sockfd == -1)
+ // socket isn't created yet
+ return connect(address.address().nodeName(),
+ address.address().serviceName());
+
+ d->peer = address.address();
+ return parseServerReply();
+}
+
+bool KHttpProxySocketDevice::connect(const QString& node, const QString& service)
+{
+ // same safety checks as above
+ if (m_sockfd == -1 && (d->proxy.family() == AF_UNSPEC ||
+ node.isEmpty() || service.isEmpty()))
+ {
+ // no proxy server set !
+ setError(IO_ConnectError, NotSupported);
+ return false;
+ }
+
+ if (isOpen())
+ {
+ // socket is already open
+ return true;
+ }
+
+ if (m_sockfd == -1)
+ {
+ // must create the socket
+ if (!KSocketDevice::connect(d->proxy))
+ return false; // also unable to contact proxy server
+ setState(0); // unset open flag
+
+ // prepare the request
+ QString request = QString::fromLatin1("CONNECT %1:%2 HTTP/1.1\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Host: \r\n"
+ "\r\n");
+ QString node2 = node;
+ if (node.contains(':'))
+ node2 = '[' + node + ']';
+
+ d->request = request.arg(node2).arg(service).latin1();
+ }
+
+ return parseServerReply();
+}
+
+bool KHttpProxySocketDevice::parseServerReply()
+{
+ // make sure we're connected
+ if (!KSocketDevice::connect(d->proxy))
+ if (error() == InProgress)
+ return true;
+ else if (error() != NoError)
+ return false;
+
+ if (!d->request.isEmpty())
+ {
+ // send request
+ Q_LONG written = writeBlock(d->request, d->request.length());
+ if (written < 0)
+ {
+ qDebug("KHttpProxySocketDevice: would block writing request!");
+ if (error() == WouldBlock)
+ setError(IO_ConnectError, InProgress);
+ return error() == WouldBlock; // error
+ }
+ qDebug("KHttpProxySocketDevice: request written");
+
+ d->request.remove(0, written);
+
+ if (!d->request.isEmpty())
+ {
+ setError(IO_ConnectError, InProgress);
+ return true; // still in progress
+ }
+ }
+
+ // request header is sent
+ // must parse reply, but must also be careful not to read too much
+ // from the buffer
+
+ int index;
+ if (!blocking())
+ {
+ Q_LONG avail = bytesAvailable();
+ qDebug("KHttpProxySocketDevice: %ld bytes available", avail);
+ setState(0);
+ if (avail == 0)
+ {
+ setError(IO_ConnectError, InProgress);
+ return true;
+ }
+ else if (avail < 0)
+ return false; // error!
+
+ QByteArray buf(avail);
+ if (peekBlock(buf.data(), avail) < 0)
+ return false; // error!
+
+ QCString fullHeaders = d->reply + buf.data();
+ // search for the end of the headers
+ index = fullHeaders.find("\r\n\r\n");
+ if (index == -1)
+ {
+ // no, headers not yet finished...
+ // consume data from socket
+ readBlock(buf.data(), avail);
+ d->reply += buf.data();
+ setError(IO_ConnectError, InProgress);
+ return true;
+ }
+
+ // headers are finished
+ index -= d->reply.length();
+ d->reply += fullHeaders.mid(d->reply.length(), index + 4);
+
+ // consume from socket
+ readBlock(buf.data(), index + 4);
+ }
+ else
+ {
+ int state = 0;
+ if (d->reply.right(3) == "\r\n\r")
+ state = 3;
+ else if (d->reply.right(2) == "\r\n")
+ state = 2;
+ else if (d->reply.right(1) == "\r")
+ state = 1;
+ while (state != 4)
+ {
+ char c = getch();
+ d->reply += c;
+
+ if ((state == 3 && c == '\n') ||
+ (state == 1 && c == '\n') ||
+ c == '\r')
+ ++state;
+ else
+ state = 0;
+ }
+ }
+
+ // now really parse the reply
+ qDebug("KHttpProxySocketDevice: get reply: %s\n",
+ d->reply.left(d->reply.find('\r')).data());
+ if (d->reply.left(7) != "HTTP/1." ||
+ (index = d->reply.find(' ')) == -1 ||
+ d->reply[index + 1] != '2')
+ {
+ setError(IO_ConnectError, NetFailure);
+ return false;
+ }
+
+ // we've got it
+ resetError();
+ setState(IO_Open);
+ return true;
+}
diff --git a/kdecore/network/khttpproxysocketdevice.h b/kdecore/network/khttpproxysocketdevice.h
new file mode 100644
index 000000000..ed4f1d60c
--- /dev/null
+++ b/kdecore/network/khttpproxysocketdevice.h
@@ -0,0 +1,122 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KHTTPPROXYSOCKETDEVICE_H
+#define KHTTPPROXYSOCKETDEVICE_H
+
+#include "ksocketdevice.h"
+
+namespace KNetwork {
+
+class KHttpProxySocketDevicePrivate;
+
+/**
+ * @class KHttpProxySocketDevice khttpproxysocketdevice.h khttproxysocketdevice.h
+ * @brief The low-level backend for HTTP proxying.
+ *
+ * This class derives from @ref KSocketDevice and implements the necessary
+ * calls to make a connection through an HTTP proxy.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KHttpProxySocketDevice: public KSocketDevice
+{
+public:
+ /**
+ * Constructor.
+ */
+ KHttpProxySocketDevice(const KSocketBase* = 0L);
+
+ /**
+ * Constructor with proxy server's address.
+ */
+ KHttpProxySocketDevice(const KResolverEntry& proxy);
+
+ /**
+ * Destructor
+ */
+ virtual ~KHttpProxySocketDevice();
+
+ /**
+ * Sets our capabilities.
+ */
+ virtual int capabilities() const;
+
+ /**
+ * Retrieves the proxy server address.
+ */
+ const KResolverEntry& proxyServer() const;
+
+ /**
+ * Sets the proxy server address.
+ */
+ void setProxyServer(const KResolverEntry& proxy);
+
+ /**
+ * Closes the socket.
+ */
+ virtual void close();
+
+ /**
+ * Overrides connection.
+ */
+ virtual bool connect(const KResolverEntry& address);
+
+ /**
+ * Name-based connection.
+ * We can tell the HTTP proxy server the full name.
+ */
+ virtual bool connect(const QString& name, const QString& service);
+
+ /**
+ * Return the peer address.
+ */
+ virtual KSocketAddress peerAddress() const;
+
+ /**
+ * Return the externally visible address. We can't tell what that address is,
+ * so this function always returns an empty object.
+ */
+ virtual KSocketAddress externalAddress() const;
+
+private:
+ /**
+ * Parses the server reply after sending the connect command.
+ * Returns true on success and false on failure.
+ */
+ bool parseServerReply();
+ KHttpProxySocketDevicePrivate *d;
+
+public:
+ /**
+ * This is the default proxy server to be used.
+ * Applications may want to set this value so that calling @ref setProxyServer
+ * is unnecessary.
+ */
+ static KResolverEntry defaultProxy;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/kiobuffer.h b/kdecore/network/kiobuffer.h
new file mode 100644
index 000000000..4da5ecb43
--- /dev/null
+++ b/kdecore/network/kiobuffer.h
@@ -0,0 +1,144 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KIOBUFFER_H
+#define KIOBUFFER_H
+
+#include <qcstring.h>
+
+#include <kdelibs_export.h>
+
+class QIODevice;
+
+/**
+ * @class KIOBufferBase kiobuffer.h kiobuffer.h
+ * @brief base for I/O buffer implementation
+ *
+ * This class declares the base methods to interface with an I/O buffer.
+ * Most applications will not need to access this class directly, since
+ * it is all handled by @ref KNetwork::KBufferedSocket and other buffering
+ * classes.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KIOBufferBase
+{
+public:
+ /**
+ * Default constructor. Does nothing.
+ */
+ KIOBufferBase()
+ { }
+
+ /**
+ * Copy constructor. Does nothing here.
+ */
+ KIOBufferBase(const KIOBufferBase& )
+ { }
+
+ /**
+ * Virtual destructor. Does nothing.
+ */
+ virtual ~KIOBufferBase()
+ { }
+
+ /**
+ * Assignment operator. Does nothing.
+ */
+ KIOBufferBase& operator=(const KIOBufferBase& )
+ { return *this; }
+
+ /**
+ * Returns true if a line can be read from the buffer.
+ */
+ virtual bool canReadLine() const = 0;
+
+ /**
+ * Reads a line from the buffer and discards it.
+ */
+ virtual QCString readLine() = 0;
+
+ /**
+ * Returns the number of bytes in the buffer. Note that this is not
+ * the size of the buffer.
+ *
+ * @sa size
+ */
+ virtual Q_LONG length() const = 0;
+
+ /**
+ * Returns true if the buffer is empty of data.
+ */
+ inline bool isEmpty() const
+ { return length() == 0; }
+
+ /**
+ * Retrieves the buffer size. The value of -1 indicates that
+ * the buffer has no defined upper limit.
+ *
+ * @sa length for the length of the data stored
+ */
+ virtual Q_LONG size() const = 0;
+
+ /**
+ * Returns true if the buffer is full (i.e., cannot receive more data)
+ */
+ inline bool isFull() const
+ { return size() != -1 && size() == length(); }
+
+ /**
+ * Sets the size of the buffer, if allowed.
+ *
+ * @param size the maximum size, use -1 for unlimited.
+ * @returns true on success, false if an error occurred.
+ * @note if the new size is less than length(), the buffer will be truncated
+ */
+ virtual bool setSize(Q_LONG size) = 0;
+
+ /**
+ * Adds data to the end of the buffer.
+ *
+ * @param data the data to be added
+ * @param len the data length, in bytes
+ * @returns the number of bytes added to the end of the buffer.
+ */
+ virtual Q_LONG feedBuffer(const char *data, Q_LONG len) = 0;
+
+ /**
+ * Consumes data from the beginning of the buffer.
+ *
+ * @param data where to copy the data to
+ * @param maxlen the maximum length to copy, in bytes
+ * @param discard if true, the bytes copied will be discarded
+ * @returns the number of bytes copied from the buffer
+ */
+ virtual Q_LONG consumeBuffer(char *data, Q_LONG maxlen, bool discard = true) = 0;
+
+ /**
+ * Clears the buffer.
+ */
+ virtual void clear() = 0;
+};
+
+#endif
diff --git a/kdecore/network/kmulticastsocket.h b/kdecore/network/kmulticastsocket.h
new file mode 100644
index 000000000..80c2f6990
--- /dev/null
+++ b/kdecore/network/kmulticastsocket.h
@@ -0,0 +1,113 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KMULTICASTSOCKET_H
+#define KMULTICASTSOCKET_H
+
+#include "kdatagramsocket.h"
+#include "kmulticastsocketdevice.h"
+
+namespace KNetwork {
+
+class KMulticastSocketPrivate;
+/**
+ * @class KMulticastSocket kmulticastsocket.h kmulticastsocket.h
+ * @brief A multicast-capable datagram socket class
+ *
+ * This class derives from @ref KDatagramSocket adding methods to it to
+ * allow better control over the multicast functionality. In special,
+ * the join and leave group functions are added.
+ *
+ * Other more low-level options on multicast sockets can be accessed
+ * directly with the @ref KMulticastSocketImpl class returned by
+ * @ref multicastSocketDevice.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KMulticastSocket: public KDatagramSocket
+{
+ // Q_add-it-here_OBJECT
+public:
+ /**
+ * Constructor.
+ */
+ KMulticastSocket(QObject* parent = 0L, const char *name = 0L);
+
+ /**
+ * Destructor.
+ */
+ ~KMulticastSocket();
+
+ /**
+ * Returns the multicast socket device in use by this object.
+ *
+ * @note The returned object can be null.
+ */
+ KMulticastSocketImpl* multicastSocketDevice();
+
+ /**
+ * @overload
+ */
+ const KMulticastSocketImpl* multicastSocketDevice() const;
+
+ /**
+ * Joins a multicast group. The group to be joined is identified by the
+ * @p group parameter.
+ *
+ * @param group the multicast group to join
+ * @returns true on success
+ */
+ virtual bool joinGroup(const KSocketAddress& group);
+
+ /**
+ * @overload
+ * Joins a multicast group. This function also specifies the network interface
+ * to be used.
+ */
+ virtual bool joinGroup(const KSocketAddress& group,
+ const KNetworkInterface& iface);
+
+ /**
+ * Leaves a multicast group. The group being left is given by its address in the
+ * @p group parameter.
+ *
+ * @param group the group to leave
+ * @returns true on successful leaving the group
+ */
+ virtual bool leaveGroup(const KSocketAddress& group);
+
+ /**
+ * @overload
+ * Leaves a multicast group.
+ */
+ virtual bool leaveGroup(const KSocketAddress& group,
+ const KNetworkInterface& iface);
+
+private:
+ KMulticastSocketPrivate *d;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/kmulticastsocketdevice.h b/kdecore/network/kmulticastsocketdevice.h
new file mode 100644
index 000000000..7710fe5c1
--- /dev/null
+++ b/kdecore/network/kmulticastsocketdevice.h
@@ -0,0 +1,151 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KMULTICASTSOCKETDEVICE_H
+#define KMULTICASTSOCKETDEVICE_H
+
+#include "ksocketdevice.h"
+#include "knetworkinterface.h"
+#include "ksocketaddress.h"
+
+namespace KNetwork {
+
+class KMulticastSocketImplPrivate;
+
+/**
+ * @class KMulticastSocketImpl kmulticastsocketdevice.h kmulticastsocketdevice.h
+ * @brief The low-level backend for multicasting sockets.
+ *
+ * This class is an interface providing methods for handling multicast
+ * operations.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KMulticastSocketImpl: public KSocketDevice
+{
+public:
+ /**
+ * Constructor.
+ */
+ KMulticastSocketImpl(const KSocketBase* = 0L);
+
+ /**
+ * Destructor
+ */
+ virtual ~KMulticastSocketImpl();
+
+ /**
+ * Sets our capabilities.
+ */
+ virtual int capabilities() const;
+
+ /**
+ * Overrides the socket creation.
+ */
+ virtual bool create(int family, int type, int protocol);
+
+ /**
+ * Overrides connection. Multicast sockets may not connect.
+ */
+ virtual bool connect(const KResolverEntry& address);
+
+ /**
+ * Retrieves the time-to-live/hop count value on multicast packets being sent.
+ */
+ virtual int timeToLive() const;
+
+ /**
+ * Sets the time-to-live/hop count for outgoing multicast packets.
+ *
+ * @param ttl the hop count, from 0 to 255
+ * @returns true if setting the value was successful.
+ */
+ virtual bool setTimeToLive(int ttl);
+
+ /**
+ * Retrieves the flag indicating if sent packets will be echoed back
+ * to sender.
+ */
+ virtual bool multicastLoop() const;
+
+ /**
+ * Sets the flag indicating the loopback of packets to the sender.
+ *
+ * @param enable if true, will echo back
+ * @returns true if setting the value was successful.
+ */
+ virtual bool setMulticastLoop(bool enable);
+
+ /**
+ * Retrieves the network interface this socket is associated to.
+ */
+ virtual KNetworkInterface networkInterface();
+
+ /**
+ * Sets the network interface on which this socket should work.
+ *
+ * @param iface the interface to associate with
+ * @return true if setting the value was successful.
+ */
+ virtual bool setNetworkInterface(const KNetworkInterface& iface);
+
+ /**
+ * Joins a multicast group. The group to be joined is identified by the
+ * @p group parameter.
+ *
+ * @param group the multicast group to join
+ * @returns true on success
+ */
+ virtual bool joinGroup(const KSocketAddress& group);
+
+ /**
+ * @overload
+ * Joins a multicast group. This function also specifies the network interface
+ * to be used.
+ */
+ virtual bool joinGroup(const KSocketAddress& group,
+ const KNetworkInterface& iface);
+
+ /**
+ * Leaves a multicast group. The group being left is given by its address in the
+ * @p group parameter.
+ *
+ * @param group the group to leave
+ * @returns true on successful leaving the group
+ */
+ virtual bool leaveGroup(const KSocketAddress& group);
+
+ /**
+ * @overload
+ * Leaves a multicast group.
+ */
+ virtual bool leaveGroup(const KSocketAddress& group,
+ const KNetworkInterface& iface);
+private:
+ KMulticastSocketImplPrivate *d;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/knetworkinterface.h b/kdecore/network/knetworkinterface.h
new file mode 100644
index 000000000..74fd52d55
--- /dev/null
+++ b/kdecore/network/knetworkinterface.h
@@ -0,0 +1,46 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+#ifndef KNETWORKINTERFACE_H
+#define KNETWORKINTERFACE_H
+
+#include <kdelibs_export.h>
+
+namespace KNetwork {
+
+/**
+ * A place-holder class for a future network interface class.
+ * This class is to be replaced with a more powerful version, inspired
+ * by:
+ * - KInetInterface (kdenetwork/krfb/srvloc)
+ * - NWInterface (kdenonbeta/knot/lib)
+ * - java.net.NetworkInterface
+ */
+class KNetworkInterface
+{
+};
+
+} // namespace KNetwork
+
+#endif
+
diff --git a/kdecore/network/kresolver.cpp b/kdecore/network/kresolver.cpp
new file mode 100644
index 000000000..915288123
--- /dev/null
+++ b/kdecore/network/kresolver.cpp
@@ -0,0 +1,1164 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "config.h"
+
+// System includes
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// Qt includes
+#include <qapplication.h>
+#include <qstring.h>
+#include <qcstring.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qshared.h>
+#include <qdatetime.h>
+#include <qtimer.h>
+#include <qmutex.h>
+#include <qguardedptr.h>
+
+// IDN
+#ifdef HAVE_IDNA_H
+# include <idna.h>
+#endif
+
+// KDE
+#include <klocale.h>
+
+// Us
+#include "kresolver.h"
+#include "kresolver_p.h"
+#include "ksocketaddress.h"
+
+#ifdef NEED_MUTEX
+#warning "mutex"
+QMutex getXXbyYYmutex;
+#endif
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+/////////////////////////////////////////////
+// class KResolverEntry
+
+class KNetwork::KResolverEntryPrivate: public QShared
+{
+public:
+ KSocketAddress addr;
+ int socktype;
+ int protocol;
+ QString canonName;
+ QCString encodedName;
+
+ inline KResolverEntryPrivate() :
+ socktype(0), protocol(0)
+ { }
+};
+
+// default constructor
+KResolverEntry::KResolverEntry() :
+ d(0L)
+{
+}
+
+// constructor with stuff
+KResolverEntry::KResolverEntry(const KSocketAddress& addr, int socktype, int protocol,
+ const QString& canonName, const QCString& encodedName) :
+ d(new KResolverEntryPrivate)
+{
+ d->addr = addr;
+ d->socktype = socktype;
+ d->protocol = protocol;
+ d->canonName = canonName;
+ d->encodedName = encodedName;
+}
+
+// constructor with even more stuff
+KResolverEntry::KResolverEntry(const struct sockaddr* sa, Q_UINT16 salen, int socktype,
+ int protocol, const QString& canonName,
+ const QCString& encodedName) :
+ d(new KResolverEntryPrivate)
+{
+ d->addr = KSocketAddress(sa, salen);
+ d->socktype = socktype;
+ d->protocol = protocol;
+ d->canonName = canonName;
+ d->encodedName = encodedName;
+}
+
+// copy constructor
+KResolverEntry::KResolverEntry(const KResolverEntry& that) :
+ d(0L)
+{
+ *this = that;
+}
+
+// destructor
+KResolverEntry::~KResolverEntry()
+{
+ if (d == 0L)
+ return;
+
+ if (d->deref())
+ delete d;
+}
+
+// returns the socket address
+KSocketAddress KResolverEntry::address() const
+{
+ return d ? d->addr : KSocketAddress();
+}
+
+// returns the length
+Q_UINT16 KResolverEntry::length() const
+{
+ return d ? d->addr.length() : 0;
+}
+
+// returns the family
+int KResolverEntry::family() const
+{
+ return d ? d->addr.family() : AF_UNSPEC;
+}
+
+// returns the canonical name
+QString KResolverEntry::canonicalName() const
+{
+ return d ? d->canonName : QString::null;
+}
+
+// returns the encoded name
+QCString KResolverEntry::encodedName() const
+{
+ return d ? d->encodedName : QCString();
+}
+
+// returns the socket type
+int KResolverEntry::socketType() const
+{
+ return d ? d->socktype : 0;
+}
+
+// returns the protocol
+int KResolverEntry::protocol() const
+{
+ return d ? d->protocol : 0;
+}
+
+// assignment operator
+KResolverEntry& KResolverEntry::operator= (const KResolverEntry& that)
+{
+ // copy the data
+ if (that.d)
+ that.d->ref();
+
+ if (d && d->deref())
+ delete d;
+
+ d = that.d;
+ return *this;
+}
+
+/////////////////////////////////////////////
+// class KResolverResults
+
+class KNetwork::KResolverResultsPrivate
+{
+public:
+ QString node, service;
+ int errorcode, syserror;
+
+ KResolverResultsPrivate() :
+ errorcode(0), syserror(0)
+ { }
+};
+
+// default constructor
+KResolverResults::KResolverResults()
+ : d(new KResolverResultsPrivate)
+{
+}
+
+// copy constructor
+KResolverResults::KResolverResults(const KResolverResults& other)
+ : QValueList<KResolverEntry>(other), d(new KResolverResultsPrivate)
+{
+ *d = *other.d;
+}
+
+// destructor
+KResolverResults::~KResolverResults()
+{
+ delete d;
+}
+
+// assignment operator
+KResolverResults&
+KResolverResults::operator= (const KResolverResults& other)
+{
+ if (this == &other)
+ return *this;
+
+ // copy over the other data
+ *d = *other.d;
+
+ // now let QValueList do the rest of the work
+ QValueList<KResolverEntry>::operator =(other);
+
+ return *this;
+}
+
+// gets the error code
+int KResolverResults::error() const
+{
+ return d->errorcode;
+}
+
+// gets the system errno
+int KResolverResults::systemError() const
+{
+ return d->syserror;
+}
+
+// sets the error codes
+void KResolverResults::setError(int errorcode, int systemerror)
+{
+ d->errorcode = errorcode;
+ d->syserror = systemerror;
+}
+
+// gets the hostname
+QString KResolverResults::nodeName() const
+{
+ return d->node;
+}
+
+// gets the service name
+QString KResolverResults::serviceName() const
+{
+ return d->service;
+}
+
+// sets the address
+void KResolverResults::setAddress(const QString& node,
+ const QString& service)
+{
+ d->node = node;
+ d->service = service;
+}
+
+void KResolverResults::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+
+///////////////////////
+// class KResolver
+
+QStringList *KResolver::idnDomains = 0;
+
+
+// default constructor
+KResolver::KResolver(QObject *parent, const char *name)
+ : QObject(parent, name), d(new KResolverPrivate(this))
+{
+}
+
+// constructor with host and service
+KResolver::KResolver(const QString& nodename, const QString& servicename,
+ QObject *parent, const char *name)
+ : QObject(parent, name), d(new KResolverPrivate(this, nodename, servicename))
+{
+}
+
+// destructor
+KResolver::~KResolver()
+{
+ cancel(false);
+ delete d;
+}
+
+// get the status
+int KResolver::status() const
+{
+ return d->status;
+}
+
+// get the error code
+int KResolver::error() const
+{
+ return d->errorcode;
+}
+
+// get the errno
+int KResolver::systemError() const
+{
+ return d->syserror;
+}
+
+// are we running?
+bool KResolver::isRunning() const
+{
+ return d->status > 0 && d->status < Success;
+}
+
+// get the hostname
+QString KResolver::nodeName() const
+{
+ return d->input.node;
+}
+
+// get the service
+QString KResolver::serviceName() const
+{
+ return d->input.service;
+}
+
+// sets the hostname
+void KResolver::setNodeName(const QString& nodename)
+{
+ // don't touch those values if we're working!
+ if (!isRunning())
+ {
+ d->input.node = nodename;
+ d->status = Idle;
+ d->results.setAddress(nodename, d->input.service);
+ }
+}
+
+// sets the service
+void KResolver::setServiceName(const QString& service)
+{
+ // don't change if running
+ if (!isRunning())
+ {
+ d->input.service = service;
+ d->status = Idle;
+ d->results.setAddress(d->input.node, service);
+ }
+}
+
+// sets the address
+void KResolver::setAddress(const QString& nodename, const QString& service)
+{
+ setNodeName(nodename);
+ setServiceName(service);
+}
+
+// get the flags
+int KResolver::flags() const
+{
+ return d->input.flags;
+}
+
+// sets the flags
+int KResolver::setFlags(int flags)
+{
+ int oldflags = d->input.flags;
+ if (!isRunning())
+ {
+ d->input.flags = flags;
+ d->status = Idle;
+ }
+ return oldflags;
+}
+
+// sets the family mask
+void KResolver::setFamily(int families)
+{
+ if (!isRunning())
+ {
+ d->input.familyMask = families;
+ d->status = Idle;
+ }
+}
+
+// sets the socket type
+void KResolver::setSocketType(int type)
+{
+ if (!isRunning())
+ {
+ d->input.socktype = type;
+ d->status = Idle;
+ }
+}
+
+// sets the protocol
+void KResolver::setProtocol(int protonum, const char *name)
+{
+ if (isRunning())
+ return; // can't change now
+
+ // we copy the given protocol name. If it isn't an empty string
+ // and the protocol number was 0, we will look it up in /etc/protocols
+ // we also leave the error reporting to the actual lookup routines, in
+ // case the given protocol name doesn't exist
+
+ d->input.protocolName = name;
+ if (protonum == 0 && name != 0L && *name != '\0')
+ {
+ // must look up the protocol number
+ d->input.protocol = KResolver::protocolNumber(name);
+ }
+ else
+ d->input.protocol = protonum;
+ d->status = Idle;
+}
+
+bool KResolver::start()
+{
+ if (!isRunning())
+ {
+ d->results.empty();
+
+ // is there anything to be queued?
+ if (d->input.node.isEmpty() && d->input.service.isEmpty())
+ {
+ d->status = KResolver::Success;
+ emitFinished();
+ }
+ else
+ KResolverManager::manager()->enqueue(this, 0L);
+ }
+
+ return true;
+}
+
+bool KResolver::wait(int msec)
+{
+ if (!isRunning())
+ {
+ emitFinished();
+ return true;
+ }
+
+ QMutexLocker locker(&d->mutex);
+
+ if (!isRunning())
+ {
+ // it was running and no longer is?
+ // That means the manager has finished its processing and has posted
+ // an event for the signal to be emitted already. This means the signal
+ // will be emitted twice!
+
+ emitFinished();
+ return true;
+ }
+ else
+ {
+ QTime t;
+ t.start();
+
+ while (!msec || t.elapsed() < msec)
+ {
+ // wait on the manager to broadcast completion
+ d->waiting = true;
+ if (msec)
+ KResolverManager::manager()->notifyWaiters.wait(&d->mutex, msec - t.elapsed());
+ else
+ KResolverManager::manager()->notifyWaiters.wait(&d->mutex);
+
+ // the manager has processed
+ // see if this object is done
+ if (!isRunning())
+ {
+ // it's done
+ d->waiting = false;
+ emitFinished();
+ return true;
+ }
+ }
+
+ // if we've got here, we've timed out
+ d->waiting = false;
+ return false;
+ }
+}
+
+void KResolver::cancel(bool emitSignal)
+{
+ KResolverManager::manager()->dequeue(this);
+ if (emitSignal)
+ emitFinished();
+}
+
+KResolverResults
+KResolver::results() const
+{
+ if (!isRunning())
+ return d->results;
+
+ // return a dummy, empty result
+ KResolverResults r;
+ r.setAddress(d->input.node, d->input.service);
+ r.setError(d->errorcode, d->syserror);
+ return r;
+}
+
+bool KResolver::event(QEvent* e)
+{
+ if (static_cast<int>(e->type()) == KResolverManager::ResolutionCompleted)
+ {
+ emitFinished();
+ return true;
+ }
+
+ return false;
+}
+
+void KResolver::emitFinished()
+{
+ if (isRunning())
+ d->status = KResolver::Success;
+
+ QGuardedPtr<QObject> p = this; // guard against deletion
+
+ emit finished(d->results);
+
+ if (p && d->deleteWhenDone)
+ deleteLater(); // in QObject
+}
+
+QString KResolver::errorString(int errorcode, int syserror)
+{
+ // no i18n now...
+ static const char * const messages[] =
+ {
+ I18N_NOOP("no error"), // NoError
+ I18N_NOOP("requested family not supported for this host name"), // AddrFamily
+ I18N_NOOP("temporary failure in name resolution"), // TryAgain
+ I18N_NOOP("non-recoverable failure in name resolution"), // NonRecoverable
+ I18N_NOOP("invalid flags"), // BadFlags
+ I18N_NOOP("memory allocation failure"), // Memory
+ I18N_NOOP("name or service not known"), // NoName
+ I18N_NOOP("requested family not supported"), // UnsupportedFamily
+ I18N_NOOP("requested service not supported for this socket type"), // UnsupportedService
+ I18N_NOOP("requested socket type not supported"), // UnsupportedSocketType
+ I18N_NOOP("unknown error"), // UnknownError
+ I18N_NOOP2("1: the i18n'ed system error code, from errno",
+ "system error: %1") // SystemError
+ };
+
+ // handle the special value
+ if (errorcode == Canceled)
+ return i18n("request was canceled");
+
+ if (errorcode > 0 || errorcode < SystemError)
+ return QString::null;
+
+ QString msg = i18n(messages[-errorcode]);
+ if (errorcode == SystemError)
+ msg.arg(QString::fromLocal8Bit(strerror(syserror)));
+
+ return msg;
+}
+
+KResolverResults
+KResolver::resolve(const QString& host, const QString& service, int flags,
+ int families)
+{
+ KResolver qres(host, service, qApp, "synchronous KResolver");
+ qres.setFlags(flags);
+ qres.setFamily(families);
+ qres.start();
+ qres.wait();
+ return qres.results();
+}
+
+bool KResolver::resolveAsync(QObject* userObj, const char *userSlot,
+ const QString& host, const QString& service,
+ int flags, int families)
+{
+ KResolver* qres = new KResolver(host, service, qApp, "asynchronous KResolver");
+ QObject::connect(qres, SIGNAL(finished(KResolverResults)), userObj, userSlot);
+ qres->setFlags(flags);
+ qres->setFamily(families);
+ qres->d->deleteWhenDone = true; // this is the only difference from the example code
+ return qres->start();
+}
+
+QStrList KResolver::protocolName(int protonum)
+{
+ struct protoent *pe = 0L;
+#ifndef HAVE_GETPROTOBYNAME_R
+ QMutexLocker locker(&getXXbyYYmutex);
+
+ pe = getprotobynumber(protonum);
+
+#else
+ size_t buflen = 1024;
+ struct protoent protobuf;
+ char *buf;
+ do
+ {
+ buf = new char[buflen];
+# ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobynumber_r which returns struct *protoent or NULL
+ if ((pe = getprotobynumber_r(protonum, &protobuf, buf, buflen)) && (errno == ERANGE))
+# else
+ if (getprotobynumber_r(protonum, &protobuf, buf, buflen, &pe) == ERANGE)
+# endif
+ {
+ pe = 0L;
+ buflen += 1024;
+ delete [] buf;
+ }
+ else
+ break;
+ }
+ while (pe == 0L);
+#endif
+
+ // Do common processing
+ QStrList lst(true); // use deep copies
+ if (pe != NULL)
+ {
+ lst.append(pe->p_name);
+ for (char **p = pe->p_aliases; *p; p++)
+ lst.append(*p);
+ }
+
+#ifdef HAVE_GETPROTOBYNAME_R
+ delete [] buf;
+#endif
+
+ return lst;
+}
+
+QStrList KResolver::protocolName(const char *protoname)
+{
+ struct protoent *pe = 0L;
+#ifndef HAVE_GETPROTOBYNAME_R
+ QMutexLocker locker(&getXXbyYYmutex);
+
+ pe = getprotobyname(protoname);
+
+#else
+ size_t buflen = 1024;
+ struct protoent protobuf;
+ char *buf;
+ do
+ {
+ buf = new char[buflen];
+# ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
+ if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
+# else
+ if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
+# endif
+ {
+ pe = 0L;
+ buflen += 1024;
+ delete [] buf;
+ }
+ else
+ break;
+ }
+ while (pe == 0L);
+#endif
+
+ // Do common processing
+ QStrList lst(true); // use deep copies
+ if (pe != NULL)
+ {
+ lst.append(pe->p_name);
+ for (char **p = pe->p_aliases; *p; p++)
+ lst.append(*p);
+ }
+
+#ifdef HAVE_GETPROTOBYNAME_R
+ delete [] buf;
+#endif
+
+ return lst;
+}
+
+int KResolver::protocolNumber(const char *protoname)
+{
+ struct protoent *pe = 0L;
+#ifndef HAVE_GETPROTOBYNAME_R
+ QMutexLocker locker(&getXXbyYYmutex);
+
+ pe = getprotobyname(protoname);
+
+#else
+ size_t buflen = 1024;
+ struct protoent protobuf;
+ char *buf;
+ do
+ {
+ buf = new char[buflen];
+# ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
+ if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
+# else
+ if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
+# endif
+ {
+ pe = 0L;
+ buflen += 1024;
+ delete [] buf;
+ }
+ else
+ break;
+ }
+ while (pe == 0L);
+#endif
+
+ // Do common processing
+ int protonum = -1;
+ if (pe != NULL)
+ protonum = pe->p_proto;
+
+#ifdef HAVE_GETPROTOBYNAME_R
+ delete [] buf;
+#endif
+
+ return protonum;
+}
+
+int KResolver::servicePort(const char *servname, const char *protoname)
+{
+ struct servent *se = 0L;
+#ifndef HAVE_GETSERVBYNAME_R
+ QMutexLocker locker(&getXXbyYYmutex);
+
+ se = getservbyname(servname, protoname);
+
+#else
+ size_t buflen = 1024;
+ struct servent servbuf;
+ char *buf;
+ do
+ {
+ buf = new char[buflen];
+# ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
+ if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
+# else
+ if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
+# endif
+ {
+ se = 0L;
+ buflen += 1024;
+ delete [] buf;
+ }
+ else
+ break;
+ }
+ while (se == 0L);
+#endif
+
+ // Do common processing
+ int servport = -1;
+ if (se != NULL)
+ servport = ntohs(se->s_port);
+
+#ifdef HAVE_GETSERVBYNAME_R
+ delete [] buf;
+#endif
+
+ return servport;
+}
+
+QStrList KResolver::serviceName(const char* servname, const char *protoname)
+{
+ struct servent *se = 0L;
+#ifndef HAVE_GETSERVBYNAME_R
+ QMutexLocker locker(&getXXbyYYmutex);
+
+ se = getservbyname(servname, protoname);
+
+#else
+ size_t buflen = 1024;
+ struct servent servbuf;
+ char *buf;
+ do
+ {
+ buf = new char[buflen];
+# ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
+ if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
+# else
+ if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
+# endif
+ {
+ se = 0L;
+ buflen += 1024;
+ delete [] buf;
+ }
+ else
+ break;
+ }
+ while (se == 0L);
+#endif
+
+ // Do common processing
+ QStrList lst(true); // use deep copies
+ if (se != NULL)
+ {
+ lst.append(se->s_name);
+ for (char **p = se->s_aliases; *p; p++)
+ lst.append(*p);
+ }
+
+#ifdef HAVE_GETSERVBYNAME_R
+ delete [] buf;
+#endif
+
+ return lst;
+}
+
+QStrList KResolver::serviceName(int port, const char *protoname)
+{
+ struct servent *se = 0L;
+#ifndef HAVE_GETSERVBYPORT_R
+ QMutexLocker locker(&getXXbyYYmutex);
+
+ se = getservbyport(port, protoname);
+
+#else
+ size_t buflen = 1024;
+ struct servent servbuf;
+ char *buf;
+ do
+ {
+ buf = new char[buflen];
+# ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyport_r which returns struct *servent or NULL
+ if ((se = getservbyport_r(port, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
+# else
+ if (getservbyport_r(port, protoname, &servbuf, buf, buflen, &se) == ERANGE)
+# endif
+ {
+ se = 0L;
+ buflen += 1024;
+ delete [] buf;
+ }
+ else
+ break;
+ }
+ while (se == 0L);
+#endif
+
+ // Do common processing
+ QStrList lst(true); // use deep copies
+ if (se != NULL)
+ {
+ lst.append(se->s_name);
+ for (char **p = se->s_aliases; *p; p++)
+ lst.append(*p);
+ }
+
+#ifdef HAVE_GETSERVBYPORT_R
+ delete [] buf;
+#endif
+
+ return lst;
+}
+
+QString KResolver::localHostName()
+{
+ QCString name;
+ int len;
+
+#ifdef MAXHOSTNAMELEN
+ len = MAXHOSTNAMELEN;
+#else
+ len = 256;
+#endif
+
+ while (true)
+ {
+ name.resize(len);
+
+ if (gethostname(name.data(), len - 1) == 0)
+ {
+ // Call succeeded, but it's not guaranteed to be NUL-terminated
+ // Note that some systems return success even if they did truncation
+ name[len - 1] = '\0';
+ break;
+ }
+
+ // Call failed
+ if (errno == ENAMETOOLONG || errno == EINVAL)
+ len += 256;
+ else
+ {
+ // Oops! Unknown error!
+ name = QCString();
+ }
+ }
+
+ if (name.isEmpty())
+ return QString::fromLatin1("localhost");
+
+ if (name.find('.') == -1)
+ {
+ // not fully qualified
+ // must resolve
+ KResolverResults results = resolve(name, "0", CanonName);
+ if (results.isEmpty())
+ // cannot find a valid hostname!
+ return QString::fromLatin1("localhost");
+ else
+ return results.first().canonicalName();
+ }
+
+ return domainToUnicode(name);
+}
+
+
+// forward declaration
+static QStringList splitLabels(const QString& unicodeDomain);
+static QCString ToASCII(const QString& label);
+static QString ToUnicode(const QString& label);
+
+static QStringList *KResolver_initIdnDomains()
+{
+ const char *kde_use_idn = getenv("KDE_USE_IDN");
+ if (!kde_use_idn)
+ kde_use_idn = "ac:at:br:cat:ch:cl:cn:de:dk:fi:gr:hu:info:io:is:jp:kr:li:lt:museum:org:no:se:sh:th:tm:tw:vn";
+ return new QStringList(QStringList::split(':', QString::fromLatin1(kde_use_idn).lower()));
+}
+
+// implement the ToAscii function, as described by IDN documents
+QCString KResolver::domainToAscii(const QString& unicodeDomain)
+{
+ if (!idnDomains)
+ idnDomains = KResolver_initIdnDomains();
+
+ QCString retval;
+ // RFC 3490, section 4 describes the operation:
+ // 1) this is a query, so don't allow unassigned
+
+ // 2) split the domain into individual labels, without
+ // separators.
+ QStringList input = splitLabels(unicodeDomain);
+
+ // Do we allow IDN names for this TLD?
+ if (input.count() && !idnDomains->contains(input[input.count()-1].lower()))
+ return input.join(".").lower().latin1(); // No IDN allowed for this TLD
+
+ // 3) decide whether to enforce the STD3 rules for chars < 0x7F
+ // we don't enforce
+
+ // 4) for each label, apply ToASCII
+ QStringList::Iterator it = input.begin();
+ const QStringList::Iterator end = input.end();
+ for ( ; it != end; ++it)
+ {
+ QCString cs = ToASCII(*it);
+ if (cs.isNull())
+ return QCString(); // error!
+
+ // no, all is Ok.
+ if (!retval.isEmpty())
+ retval += '.';
+ retval += cs;
+ }
+
+ return retval;
+}
+
+QString KResolver::domainToUnicode(const QCString& asciiDomain)
+{
+ return domainToUnicode(QString::fromLatin1(asciiDomain));
+}
+
+// implement the ToUnicode function, as described by IDN documents
+QString KResolver::domainToUnicode(const QString& asciiDomain)
+{
+ if (asciiDomain.isEmpty())
+ return asciiDomain;
+ if (!idnDomains)
+ idnDomains = KResolver_initIdnDomains();
+
+ QString retval;
+
+ // draft-idn-idna-14.txt, section 4 describes the operation:
+ // 1) this is a query, so don't allow unassigned
+ // besides, input is ASCII
+
+ // 2) split the domain into individual labels, without
+ // separators.
+ QStringList input = splitLabels(asciiDomain);
+
+ // Do we allow IDN names for this TLD?
+ if (input.count() && !idnDomains->contains(input[input.count()-1].lower()))
+ return asciiDomain.lower(); // No TLDs allowed
+
+ // 3) decide whether to enforce the STD3 rules for chars < 0x7F
+ // we don't enforce
+
+ // 4) for each label, apply ToUnicode
+ QStringList::Iterator it;
+ const QStringList::Iterator end = input.end();
+ for (it = input.begin(); it != end; ++it)
+ {
+ QString label = ToUnicode(*it).lower();
+
+ // ToUnicode can't fail
+ if (!retval.isEmpty())
+ retval += '.';
+ retval += label;
+ }
+
+ return retval;
+}
+
+QString KResolver::normalizeDomain(const QString& domain)
+{
+ return domainToUnicode(domainToAscii(domain));
+}
+
+void KResolver::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+// here follows IDN functions
+// all IDN functions conform to the following documents:
+// RFC 3454 - Preparation of Internationalized Strings
+// RFC 3490 - Internationalizing Domain Names in Applications (IDNA)
+// RFC 3491 - Nameprep: A Stringprep Profile for
+// Internationalized Domain Names (IDN
+// RFC 3492 - Punycode: A Bootstring encoding of Unicode
+// for Internationalized Domain Names in Applications (IDNA)
+
+static QStringList splitLabels(const QString& unicodeDomain)
+{
+ // From RFC 3490 section 3.1:
+ // "Whenever dots are used as label separators, the following characters
+ // MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full
+ // stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full
+ // stop)."
+ static const unsigned int separators[] = { 0x002E, 0x3002, 0xFF0E, 0xFF61 };
+
+ QStringList lst;
+ int start = 0;
+ uint i;
+ for (i = 0; i < unicodeDomain.length(); i++)
+ {
+ unsigned int c = unicodeDomain[i].unicode();
+
+ if (c == separators[0] ||
+ c == separators[1] ||
+ c == separators[2] ||
+ c == separators[3])
+ {
+ // found a separator!
+ lst << unicodeDomain.mid(start, i - start);
+ start = i + 1;
+ }
+ }
+ if ((long)i >= start)
+ // there is still one left
+ lst << unicodeDomain.mid(start, i - start);
+
+ return lst;
+}
+
+static QCString ToASCII(const QString& label)
+{
+#ifdef HAVE_IDNA_H
+ // We have idna.h, so we can use the idna_to_ascii
+ // function :)
+
+ if (label.length() > 64)
+ return (char*)0L; // invalid label
+
+ if (label.length() == 0)
+ // this is allowed
+ return QCString(""); // empty, not null
+
+ QCString retval;
+ char buf[65];
+
+ Q_UINT32* ucs4 = new Q_UINT32[label.length() + 1];
+
+ uint i;
+ for (i = 0; i < label.length(); i++)
+ ucs4[i] = (unsigned long)label[i].unicode();
+ ucs4[i] = 0; // terminate with NUL, just to be on the safe side
+
+ if (idna_to_ascii_4i(ucs4, label.length(), buf, 0) == IDNA_SUCCESS)
+ // success!
+ retval = buf;
+
+ delete [] ucs4;
+ return retval;
+#else
+ return label.latin1();
+#endif
+}
+
+static QString ToUnicode(const QString& label)
+{
+#ifdef HAVE_IDNA_H
+ // We have idna.h, so we can use the idna_to_unicode
+ // function :)
+
+ Q_UINT32 *ucs4_input, *ucs4_output;
+ size_t outlen;
+
+ ucs4_input = new Q_UINT32[label.length() + 1];
+ for (uint i = 0; i < label.length(); i++)
+ ucs4_input[i] = (unsigned long)label[i].unicode();
+
+ // try the same length for output
+ ucs4_output = new Q_UINT32[outlen = label.length()];
+
+ idna_to_unicode_44i(ucs4_input, label.length(),
+ ucs4_output, &outlen,
+ 0);
+
+ if (outlen > label.length())
+ {
+ // it must have failed
+ delete [] ucs4_output;
+ ucs4_output = new Q_UINT32[outlen];
+
+ idna_to_unicode_44i(ucs4_input, label.length(),
+ ucs4_output, &outlen,
+ 0);
+ }
+
+ // now set the answer
+ QString result;
+ result.setLength(outlen);
+ for (uint i = 0; i < outlen; i++)
+ result[i] = (unsigned int)ucs4_output[i];
+
+ delete [] ucs4_input;
+ delete [] ucs4_output;
+
+ return result;
+#else
+ return label;
+#endif
+}
+
+#include "kresolver.moc"
diff --git a/kdecore/network/kresolver.h b/kdecore/network/kresolver.h
new file mode 100644
index 000000000..b4e4334be
--- /dev/null
+++ b/kdecore/network/kresolver.h
@@ -0,0 +1,945 @@
+/* -*- mode: C++; coding: utf-8; -*-
+ * Copyright (C) 2003,2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KRESOLVER_H
+#define KRESOLVER_H
+
+//////////////////
+// Needed includes
+#include <qvaluelist.h>
+#include <qobject.h>
+#include "ksocketaddress.h"
+
+
+////////////////////////
+// Forward declarations
+struct sockaddr;
+class QString;
+class QCString;
+class QStrList;
+
+//////////////////
+// Our definitions
+
+namespace KNetwork {
+
+ namespace Internal { class KResolverManager; }
+
+class KResolverEntryPrivate;
+/** @class KResolverEntry kresolver.h kresolver.h
+ * @brief One resolution entry.
+ *
+ * This class is one element in the resolution results list.
+ * It contains the socket address for connecting, as well as
+ * a bit more of information: the socket type, address family
+ * and protocol numbers.
+ *
+ * This class contains all the information required for creating,
+ * binding and connecting a socket.
+ *
+ * KResolverEntry objects implicitly share data, so copying them
+ * is quite efficient.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KResolverEntry
+{
+public:
+ /**
+ * Default constructor
+ *
+ */
+ KResolverEntry();
+
+ /**
+ * Constructs a new KResolverEntry from a KSocketAddress
+ * and other data.
+ *
+ * The KSocketAddress @p addr parameter will be deep-copied.
+ *
+ * @param addr the address that was resolved
+ * @param socktype the socket type of the resolved address
+ * @param protocol the protocol of the resolved address
+ * @param canonName the canonical name of the resolved hostname
+ * @param encodedName the ASCII-compatible encoding of the hostname
+ */
+ KResolverEntry(const KSocketAddress& addr, int socktype, int protocol,
+ const QString& canonName = QString::null,
+ const QCString& encodedName = QCString());
+
+ /**
+ * Constructs a new KResolverEntry from raw forms of
+ * socket addresses and other data.
+ *
+ * This constructor instead creates an internal KSocketAddress object.
+ *
+ * @param sa the sockaddr structure containing the raw address
+ * @param salen the length of the sockaddr structure
+ * @param socktype the socket type of the resolved address
+ * @param protocol the protocol of the resolved address
+ * @param canonName the canonical name of the resolved hostname
+ * @param encodedName the ASCII-compatible encoding of the hostname
+ */
+ KResolverEntry(const struct sockaddr *sa, Q_UINT16 salen, int socktype,
+ int protocol, const QString& canonName = QString::null,
+ const QCString& encodedName = QCString());
+
+ /**
+ * Copy constructor.
+ *
+ * This constructor performs a shallow-copy of the other object.
+ */
+ KResolverEntry(const KResolverEntry &other);
+
+ /**
+ * Destructor.
+ *
+ * The destructor frees associated resources with this object. It does
+ * not destroy shared data.
+ */
+ ~KResolverEntry();
+
+ /**
+ * Retrieves the socket address associated with this entry.
+ */
+ KSocketAddress address() const;
+
+ /**
+ * Retrieves the length of the socket address structure.
+ */
+ Q_UINT16 length() const;
+
+ /**
+ * Retrieves the family associated with this socket address.
+ */
+ int family() const;
+
+ /**
+ * Retrieves the canonical name associated with this entry, if there is any.
+ * If the canonical name was not found, this function returns QString::null.
+ */
+ QString canonicalName() const;
+
+ /**
+ * Retrieves the encoded domain name associated with this entry, if there is
+ * any. If this domain has been resolved through DNS, this will be the
+ * the ACE-encoded hostname.
+ *
+ * Returns a null QCString if such information is not available.
+ *
+ * Please note that this information is NOT to be presented to the user,
+ * unless requested.
+ */
+ QCString encodedName() const;
+
+ /**
+ * Retrieves the socket type associated with this entry.
+ */
+ int socketType() const;
+
+ /**
+ * Retrieves the protocol associated with this entry.
+ */
+ int protocol() const;
+
+ /**
+ * Assignment operator
+ *
+ * This function copies the contents of the other object into this one.
+ * Data will be shared between the two of them.
+ */
+ KResolverEntry& operator=(const KResolverEntry& other);
+
+private:
+ KResolverEntryPrivate* d;
+};
+
+class KResolverResultsPrivate;
+/**
+ * @class KResolverResults kresolver.h kresolver.h
+ * @brief Name and service resolution results.
+ *
+ * This object contains the results of a name and service resolution, as
+ * those performed by @ref KResolver. It is also a descendant of QValueList, so
+ * you may use all its member functions here to access the elements.
+ *
+ * A KResolverResults object is associated with a resolution, so, in addition
+ * to the resolved elements, you can also retrieve information about the
+ * resolution process itself, like the nodename that was resolved or an error
+ * code.
+ *
+ * Note Resolver also uses KResolverResults objects to indicate failure, so
+ * you should test for failure.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KResolverResults: public QValueList<KResolverEntry>
+{
+public:
+ /**
+ * Default constructor.
+ *
+ * Constructs an empty list.
+ */
+ KResolverResults();
+
+ /**
+ * Copy constructor
+ *
+ * Creates a new object with the contents of the other one. Data will be
+ * shared by the two objects, like QValueList
+ */
+ KResolverResults(const KResolverResults& other);
+
+ /**
+ * Destructor
+ *
+ * Destroys the object and frees associated resources.
+ */
+ virtual ~KResolverResults();
+
+ /**
+ * Assignment operator
+ *
+ * Copies the contents of the other container into this one, discarding
+ * our current values.
+ */
+ KResolverResults& operator=(const KResolverResults& other);
+
+ /**
+ * Retrieves the error code associated with this resolution. The values
+ * here are the same as in @ref KResolver::ErrorCodes.
+ */
+ int error() const;
+
+ /**
+ * Retrieves the system error code, if any.
+ * @see KResolver::systemError for more information
+ */
+ int systemError() const;
+
+ /**
+ * Sets the error codes
+ *
+ * @param errorcode the error code in @ref KResolver::ErrorCodes
+ * @param systemerror the system error code associated, if any
+ */
+ void setError(int errorcode, int systemerror = 0);
+
+ /**
+ * The nodename to which the resolution was performed.
+ */
+ QString nodeName() const;
+
+ /**
+ * The service name to which the resolution was performed.
+ */
+ QString serviceName() const;
+
+ /**
+ * Sets the new nodename and service name
+ */
+ void setAddress(const QString& host, const QString& service);
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KResolverResultsPrivate* d;
+};
+
+class KResolverPrivate;
+/**
+ * @class KResolver kresolver.h kresolver.h
+ * @brief Name and service resolution class.
+ *
+ * This class provides support for doing name-to-binary resolution
+ * for nodenames and service ports. You should use this class if you
+ * need specific resolution techniques when creating a socket or if you
+ * want to inspect the results before calling the socket functions.
+ *
+ * You can either create an object and set the options you want in it
+ * or you can simply call the static member functions, which will create
+ * standard Resolver objects and dispatch the resolution for you. Normally,
+ * the static functions will be used, except in cases where specific options
+ * must be set.
+ *
+ * A Resolver object defaults to the following:
+ * @li address family: any address family
+ * @li socket type: streaming socket
+ * @li protocol: implementation-defined. Generally, TCP
+ * @li host and service: unset
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KResolver: public QObject
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Address family selection types
+ *
+ * These values can be OR-ed together to form a composite family selection.
+ *
+ * @li UnknownFamily: a family that is unknown to the current implementation
+ * @li KnownFamily: a family that is known to the implementation (the exact
+ * opposite of UnknownFamily)
+ * @li AnyFamilies: any address family is acceptable
+ * @li InternetFamily: an address for connecting to the Internet
+ * @li InetFamily: alias for InternetFamily
+ * @li IPv6Family: an IPv6 address only
+ * @li IPv4Family: an IPv4 address only
+ * @li UnixFamily: an address for the local Unix namespace (i.e., Unix sockets)
+ * @li LocalFamily: alias for UnixFamily
+ */
+ enum SocketFamilies
+ {
+ UnknownFamily = 0x0001,
+
+ UnixFamily = 0x0002,
+ LocalFamily = UnixFamily,
+
+ IPv4Family = 0x0004,
+ IPv6Family = 0x0008,
+ InternetFamily = IPv4Family | IPv6Family,
+ InetFamily = InternetFamily,
+
+ KnownFamily = ~UnknownFamily,
+ AnyFamily = KnownFamily | UnknownFamily
+ };
+
+ /**
+ * Flags for the resolution.
+ *
+ * These flags are used for setting the resolution behaviour for this
+ * object:
+ * @li Passive: resolve to a passive socket (i.e., one that can be used for
+ * binding to a local interface)
+ * @li CanonName: request that the canonical name for the given nodename
+ * be found and recorded
+ * @li NoResolve: request that no external resolution be performed. The given
+ * nodename and servicename will be resolved locally only.
+ * @li NoSrv: don't try to use SRV-based name-resolution. (deprecated)
+ * @li UseSrv: use SRV-based name resolution.
+ * @li Multiport: the port/service argument is a list of port numbers and
+ * ranges. (future extension)
+ *
+ * @note SRV-based lookup and Multiport are not implemented yet.
+ */
+ enum Flags
+ {
+ Passive = 0x01,
+ CanonName = 0x02,
+ NoResolve = 0x04,
+ NoSrv = 0x08,
+ Multiport = 0x10,
+ UseSrv = 0x20
+ };
+
+ /**
+ * Error codes
+ *
+ * These are the possible error values that objects of this class
+ * may return. See \ref errorString() for getting a string representation
+ * for these errors.
+ *
+ * @li AddrFamily: Address family for the given nodename is not supported.
+ * @li TryAgain: Temporary failure in name resolution. You should try again.
+ * @li NonRecoverable: Non-recoverable failure in name resolution.
+ * @li BadFlags: Invalid flags were given.
+ * @li Memory: Memory allocation failure.
+ * @li NoName: The specified name or service doesn't exist.
+ * @li UnsupportedFamily: The requested socket family is not supported.
+ * @li UnsupportedService: The requested service is not supported for this
+ * socket type (i.e., a datagram service in a streaming socket).
+ * @li UnsupportedSocketType: The requested socket type is not supported.
+ * @li UnknownError: An unknown, unexpected error occurred.
+ * @li SystemError: A system error occurred. See @ref systemError.
+ * @li Canceled: This request was cancelled by the user.
+ */
+ enum ErrorCodes
+ {
+ // note: if you change this enum, take a look at KResolver::errorString
+ NoError = 0,
+ AddrFamily = -1,
+ TryAgain = -2,
+ NonRecoverable = -3,
+ BadFlags = -4,
+ Memory = -5,
+ NoName = -6,
+ UnsupportedFamily = -7,
+ UnsupportedService = -8,
+ UnsupportedSocketType = -9,
+ UnknownError = -10,
+ SystemError = -11,
+ Canceled = -100
+ };
+
+ /**
+ * Status codes.
+ *
+ * These are the possible status for a Resolver object. A value
+ * greater than zero indicates normal behaviour, while negative
+ * values either indicate failure or error.
+ *
+ * @li Idle: resolution has not yet been started.
+ * @li Queued: resolution is queued but not yet in progress.
+ * @li InProgress: resolution is in progress.
+ * @li PostProcessing: resolution is in progress.
+ * @li Success: resolution is done; you can retrieve the results.
+ * @li Canceled: request cancelled by the user.
+ * @li Failed: resolution is done, but failed.
+ *
+ * Note: the status Canceled and the error code Canceled are the same.
+ *
+ * Note 2: the status Queued and InProgress might not be distinguishable.
+ * Some implementations might not differentiate one from the other.
+ */
+ enum StatusCodes
+ {
+ Idle = 0,
+ Queued = 1,
+ InProgress = 5,
+ PostProcessing = 6,
+ Success = 10,
+ //Canceled = -100, // already defined above
+ Failed = -101
+ };
+
+ /**
+ * Default constructor.
+ *
+ * Creates an empty Resolver object. You should set the wanted
+ * names and flags using the member functions before starting
+ * the name resolution.
+ */
+ KResolver(QObject * = 0L, const char * = 0L);
+
+ /**
+ * Constructor with host and service names.
+ *
+ * Creates a Resolver object with the given host and
+ * service names. Flags are initialised to 0 and any address family
+ * will be accepted.
+ *
+ * @param nodename The host name we want resolved.
+ * @param servicename The service name associated, like "http".
+ */
+ KResolver(const QString& nodename, const QString& servicename = QString::null,
+ QObject * = 0L, const char * = 0L);
+
+ /**
+ * Destructor.
+ *
+ * When this object is deleted, it'll destroy all associated
+ * resources. If the resolution is still in progress, it will be
+ * cancelled and the signal will \b not be emitted.
+ */
+ virtual ~KResolver();
+
+ /**
+ * Retrieve the current status of this object.
+ *
+ * @see StatusCodes for the possible status codes.
+ */
+ int status() const;
+
+ /**
+ * Retrieve the error code in this object.
+ *
+ * This function will return NoError if we are not in
+ * an error condition. See @ref status and @ref StatusCodes to
+ * find out what the current status is.
+ *
+ * @see errorString for getting a textual representation of
+ * this error
+ */
+ int error() const;
+
+ /**
+ * Retrieve the associated system error code in this object.
+ *
+ * Many resolution operations may generate an extra error code
+ * as given by the C errno variable. That value is stored in the
+ * object and can be retrieved by this function.
+ */
+ int systemError() const;
+
+ /**
+ * Returns the textual representation of the error in this object.
+ */
+ inline QString errorString() const
+ { return errorString(error(), systemError()); }
+
+ /**
+ * Returns true if this object is currently running
+ */
+ bool isRunning() const;
+
+ /**
+ * The nodename to which the resolution was/is to be performed.
+ */
+ QString nodeName() const;
+
+ /**
+ * The service name to which the resolution was/is to be performed.
+ */
+ QString serviceName() const;
+
+ /**
+ * Sets the nodename for the resolution.
+ *
+ * Set the nodename to QString::null to unset it.
+ * @param nodename The nodename to be resolved.
+ */
+ void setNodeName(const QString& nodename);
+
+ /**
+ * Sets the service name to be resolved.
+ *
+ * Set it to QString::null to unset it.
+ * @param service The service to be resolved.
+ */
+ void setServiceName(const QString& service);
+
+ /**
+ * Sets both the host and the service names.
+ *
+ * Setting either value to QString::null will unset them.
+ * @param node The nodename
+ * @param service The service name
+ */
+ void setAddress(const QString& node, const QString& service);
+
+ /**
+ * Retrieves the flags set for the resolution.
+ *
+ * @see Flags for an explanation on what flags are possible
+ */
+ int flags() const;
+
+ /**
+ * Sets the flags.
+ *
+ * @param flags the new flags
+ * @return the old flags
+ * @see Flags for an explanation on the flags
+ */
+ int setFlags(int flags);
+
+ /**
+ * Sets the allowed socket families.
+ *
+ * @param families the families that we want/accept
+ * @see SocketFamilies for possible values
+ */
+ void setFamily(int families);
+
+ /**
+ * Sets the socket type we want.
+ *
+ * The values for the @p type parameter are the SOCK_*
+ * constants, defined in <sys/socket.h>. The most common
+ * values are:
+ * @li SOCK_STREAM streaming socket (= reliable, sequenced,
+ * connection-based)
+ * @li SOCK_DGRAM datagram socket (= unreliable, connectionless)
+ * @li SOCK_RAW raw socket, with direct access to the
+ * container protocol (such as IP)
+ *
+ * These three are the only values to which it is guaranteed that
+ * resolution will work. Some systems may define other constants (such as
+ * SOCK_RDM for reliable datagrams), but support is implementation-defined.
+ *
+ * @param type the wanted socket type (SOCK_* constants). Set
+ * 0 to use the default.
+ */
+ void setSocketType(int type);
+
+ /**
+ * Sets the protocol we want.
+ *
+ * Protocols are dependant on the selected address family, so you should know
+ * what you are doing if you use this function. Besides, protocols generally
+ * are either stream-based or datagram-based, so the value of the socket
+ * type is also important. The resolution will fail if these values don't match.
+ *
+ * When using an Internet socket, the values for the protocol are the
+ * IPPROTO_* constants, defined in <netinet/in.h>.
+ *
+ * You may choose to set the protocol either by its number or by its name, or
+ * by both. If you set:
+ * @li the number and the name: both values will be stored internally; you
+ * may set the name to an empty value, if wanted
+ * @li the number only (name = NULL): the name will be searched in the
+ * protocols database
+ * @li the name only (number = 0): the number will be searched in the
+ * database
+ * @li neither name nor number: reset to default behaviour
+ *
+ * @param protonum the protocol number we want
+ * @param name the protocol name
+ */
+ void setProtocol(int protonum, const char *name = 0L);
+
+ /**
+ * Starts the name resolution asynchronously.
+ *
+ * This function will queue this object for resolution
+ * and will return immediately. The status upon exit will either be
+ * Queued or InProgress or Failed.
+ *
+ * This function does nothing if the object is already queued. But if
+ * it had already succeeded or failed, this function will re-start it.
+ *
+ * Note: if both the nodename and the servicename are unset, this function
+ * will not queue, but will set a success state and emit the signal. Also
+ * note that in this case and maybe others, the signal @ref finished might
+ * be emitted before this function returns.
+ *
+ * @return true if this request was successfully queued for asynchronous
+ * resolution
+ */
+ bool start();
+
+ /**
+ * Waits for a request to finish resolving.
+ *
+ * This function will wait on a running request for its termination. The
+ * status upon exit will either be Success or Failed or Canceled.
+ *
+ * This function may be called from any thread, even one that is not the
+ * GUI thread or the one that started the resolution process. But note this
+ * function is not thread-safe nor reentrant: i.e., only one thread can be
+ * waiting on one given object.
+ *
+ * Also note that this function ensures that the @ref finished signal is
+ * emitted before it returns. That means that, as a side-effect, whenever
+ * wait() is called, the signal is emitted on the thread calling wait().
+ *
+ * @param msec the time to wait, in milliseconds or 0 to
+ * wait forever
+ * @return true if the resolution has finished processing, even when it
+ * failed or was canceled. False means the wait timed out and
+ * the resolution is still running.
+ */
+ bool wait(int msec = 0);
+
+ /**
+ * Cancels a running request
+ *
+ * This function will cancel a running request. If the request is not
+ * currently running or queued, this function does nothing.
+ *
+ * Note: if you tell the signal to be emitted, be aware that it might
+ * or might not be emitted before this function returns.
+ *
+ * @param emitSignal whether to emit the @ref finished signal or not
+ */
+ void cancel(bool emitSignal = true);
+
+ /**
+ * Retrieves the results of this resolution
+ *
+ * Use this function to retrieve the results of the resolution. If no
+ * data was resolved (yet) or if we failed, this function will return
+ * an empty object.
+ *
+ * @return the resolved data
+ * @see status for information on finding out if the resolution was successful
+ */
+ KResolverResults results() const;
+
+ /**
+ * Handles events. Reimplemented from QObject.
+ *
+ * This function handles the events generated by the manager indicating that
+ * this object has finished processing.
+ *
+ * Do not post events to this object.
+ */
+ virtual bool event(QEvent*);
+
+signals:
+ // signals
+
+ /**
+ * This signal is emitted whenever the resolution is finished, one
+ * way or another (success or failure). The @p results parameter
+ * will contain the resolved data.
+ *
+ * Note: if you are doing multiple resolutions, you can use the
+ * QObject::sender() function to distinguish one Resolver object from
+ * another.
+ *
+ * @param results the resolved data; might be empty if the resolution
+ * failed
+ * @see results for information on what the results are
+ *
+ * @note This signal is @b always delivered in the GUI event thread, even for
+ * resolutions that were started in secondary threads.
+ */
+ void finished(KResolverResults results);
+
+private:
+ void emitFinished();
+
+public:
+ // Static functions
+
+ /**
+ * Returns the string representation of this error code.
+ *
+ * @param errorcode the error code. See @ref ErrorCodes.
+ * @param syserror the system error code associated.
+ * @return the string representation. This is already
+ * i18n'ed.
+ */
+ static QString errorString(int errorcode, int syserror = 0);
+
+ /**
+ * Resolve the nodename and service name synchronously
+ *
+ * This static function is provided as convenience for simplifying
+ * name resolution. It resolves the given host and service names synchronously
+ * and returns the results it found. It is equivalent to the following code:
+ *
+ * \code
+ * KResolver qres(host, service);
+ * qres.setFlags(flags);
+ * qres.setFamily(families)
+ * qres.start();
+ * qres.wait();
+ * return qres.results();
+ * \endcode
+ *
+ * @param host the nodename to resolve
+ * @param service the service to resolve
+ * @param flags flags to be used
+ * @param families the families to be searched
+ * @return a KResolverResults object containing the results
+ * @see KResolverResults for information on how to obtain the error code
+ */
+ static KResolverResults resolve(const QString& host, const QString& service,
+ int flags = 0, int families = KResolver::InternetFamily);
+
+ /**
+ * Start an asynchronous name resolution
+ *
+ * This function is provided as a convenience to simplify the resolution
+ * process. It creates an internal KResolver object, connects the
+ * @ref finished signal to the given slot and starts the resolution
+ * asynchronously. It is more or less equivalent to the following code:
+ *
+ * \b Note: this function may trigger the signal before it returns, so
+ * your code must be prepared for this situation.
+ *
+ * \code
+ * KResolver* qres = new KResolver(host, service);
+ * QObject::connect(qres, SIGNAL(finished(KResolverResults)),
+ * userObj, userSlot);
+ * qres->setFlags(flags);
+ * qres->setFamily(families);
+ * return qres->start();
+ * \endcode
+ *
+ * You should use it like this in your code:
+ * \code
+ * KResolver::resolveAsync(myObj, SLOT(mySlot(KResolverResults)), host, service);
+ * \endcode
+ *
+ * @param userObj the object whose slot @p userSlot we will connect
+ * @param userSlot the slot to which we'll connect
+ * @param host the nodename to resolve
+ * @param service the service to resolve
+ * @param flags flags to be used
+ * @param families families to be searcheed
+ * @return true if the queueing was successful, false if not
+ * @see KResolverResults for information on how to obtain the error code
+ */
+ static bool resolveAsync(QObject* userObj, const char *userSlot,
+ const QString& host, const QString& service,
+ int flags = 0, int families = KResolver::InternetFamily);
+
+ /**
+ * Returns the domain name in an ASCII Compatible Encoding form, suitable
+ * for DNS lookups. This is the base for International Domain Name support
+ * over the Internet.
+ *
+ * Note this function may fail, in which case it'll return a null
+ * QCString. Reasons for failure include use of unknown code
+ * points (Unicode characters).
+ *
+ * Note that the encoding is illegible and, thus, should not be presented
+ * to the user, except if requested.
+ *
+ * @param unicodeDomain the domain name to be encoded
+ * @return the ACE-encoded suitable for DNS queries if successful, a null
+ * QCString if failure.
+ */
+ static QCString domainToAscii(const QString& unicodeDomain);
+
+ /**
+ * Does the inverse of @ref domainToAscii and return an Unicode domain
+ * name from the given ACE-encoded domain.
+ *
+ * This function may fail if the given domain cannot be successfully
+ * converted back to Unicode. Reasons for failure include a malformed
+ * domain name or good ones whose reencoding back to ACE don't match
+ * the form given here (e.g., ACE-encoding of an already
+ * ASCII-compatible domain).
+ *
+ * It is, however, guaranteed that domains returned
+ * by @ref domainToAscii will work.
+ *
+ * @param asciiDomain the ACE-encoded domain name to be decoded
+ * @return the Unicode representation of the given domain name
+ * if successful, the original string if not
+ * @note ACE = ASCII-Compatible Encoding, i.e., 7-bit
+ */
+ static QString domainToUnicode(const QCString& asciiDomain);
+
+ /**
+ * The same as above, but taking a QString argument.
+ *
+ * @param asciiDomain the ACE-encoded domain name to be decoded
+ * @return the Unicode representation of the given domain name
+ * if successful, QString::null if not.
+ */
+ static QString domainToUnicode(const QString& asciiDomain);
+
+ /**
+ * Normalise a domain name.
+ *
+ * In order to prevent simple mistakes in International Domain
+ * Names (IDN), it has been decided that certain code points
+ * (characters in Unicode) would be instead converted to others.
+ * This includes turning them all to lower case, as well certain
+ * other specific operations, as specified in the documents.
+ *
+ * For instance, the German 'ß' will be changed into 'ss', while
+ * the micro symbol 'µ' will be changed to the Greek mu 'μ'.
+ *
+ * Two equivalent domains have the same normalised form. And the
+ * normalised form of a normalised domain is itself (i.e., if
+ * d is normalised, the following is true: d == normalizeDomain(d) )
+ *
+ * This operation is equivalent to encoding and the decoding a Unicode
+ * hostname.
+ *
+ * @param domain a domain to be normalised
+ * @return the normalised domain, or QString::null if the domain is
+ * invalid.
+ */
+ static QString normalizeDomain(const QString& domain);
+
+ /**
+ * Resolves a protocol number to its names
+ *
+ * Note: the returned QStrList operates on deep-copies.
+ *
+ * @param protonum the protocol number to be looked for
+ * @return all the protocol names in a list. The first is the "proper"
+ * name.
+ */
+ static QStrList protocolName(int protonum);
+
+ /**
+ * Finds all aliases for a given protocol name
+ *
+ * @param protoname the protocol name to be looked for
+ * @return all the protocol names in a list. The first is the "proper"
+ * name.
+ */
+ static QStrList protocolName(const char *protoname);
+
+ /**
+ * Resolves a protocol name to its number
+ *
+ * @param protoname the protocol name to be looked for
+ * @return the protocol number or -1 if we couldn't locate it
+ */
+ static int protocolNumber(const char *protoname);
+
+ /**
+ * Resolves a service name to its port number
+ *
+ * @param servname the service name to be looked for
+ * @param protoname the protocol it is associated with
+ * @return the port number in host byte-order or -1 in case of error
+ */
+ static int servicePort(const char *servname, const char *protoname);
+
+ /**
+ * Finds all the aliases for a given service name
+ *
+ * Note: the returned QStrList operates on deep-copies.
+ *
+ * @param servname the service alias to be looked for
+ * @param protoname the protocol it is associated with
+ * @return all the service names in a list. The first is the "proper"
+ * name.
+ */
+ static QStrList serviceName(const char *servname, const char *protoname);
+
+ /**
+ * Resolves a port number to its names
+ *
+ * Note: the returned QStrList operates on deep copies.
+ *
+ * @param port the port number, in host byte-order
+ * @param protoname the protocol it is associated with
+ * @return all the service names in a list. The first is the "proper"
+ * name.
+ */
+ static QStrList serviceName(int port, const char *protoname);
+
+ /**
+ * Returns this machine's local hostname.
+ *
+ * @return this machine's local hostname
+ * @since 3.5
+ */
+ static QString localHostName();
+
+protected:
+
+ /**
+ * Sets the error codes
+ */
+ void setError(int errorcode, int systemerror = 0);
+
+ virtual void virtual_hook( int id, void* data );
+private:
+ KResolverPrivate* d;
+ friend class KResolverResults;
+ friend class ::KNetwork::Internal::KResolverManager;
+
+ static QStringList *idnDomains;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/kresolver_p.h b/kdecore/network/kresolver_p.h
new file mode 100644
index 000000000..2fac7eb45
--- /dev/null
+++ b/kdecore/network/kresolver_p.h
@@ -0,0 +1,353 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KRESOLVER_P_H
+#define KRESOLVER_P_H
+
+#include <config.h>
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include <qptrlist.h>
+#include <qptrqueue.h>
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+#include <qsemaphore.h>
+#include <qevent.h>
+
+#include "kresolver.h"
+
+/* decide whether we need a mutex */
+#if !defined(HAVE_GETPROTOBYNAME_R) || !defined(HAVE_GETSERVBYNAME_R) || !defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETSERVBYPORT_R)
+# define NEED_MUTEX
+extern QMutex getXXbyYYmutex;
+#endif
+
+/* some systems have the functions, but don't declare them */
+#if defined(HAVE_GETSERVBYNAME_R) && !HAVE_DECL_GETSERVBYNAME_R
+extern "C" {
+ struct servent;
+ extern int getservbyname_r(const char* serv, const char* proto,
+ struct servent* servbuf,
+ char* buf, size_t buflen,
+ struct servent** result);
+ extern int getservbyport_r(int port, const char* proto,
+ struct servent* servbuf,
+ char* buf, size_t buflen,
+ struct servent** result);
+
+ struct protoent;
+ extern int getprotobyname_r(const char* proto, struct protoent* protobuf,
+ char *buf, size_t buflen,
+ struct protoent** result);
+ extern int getprotobynumber_r(int proto, struct protoent* protobuf,
+ char *buf, size_t buflen,
+ struct protoent** result);
+}
+#endif
+
+/* decide whether res_init is thread-safe or not */
+#if defined(__GLIBC__)
+# undef RES_INIT_THREADSAFE
+#endif
+
+namespace KNetwork
+{
+ // defined in network/qresolverworkerbase.h
+ class KResolverWorkerBase;
+ class KResolverWorkerFactoryBase;
+ class KResolverPrivate;
+
+ namespace Internal
+ {
+ class KResolverManager;
+ class KResolverThread;
+ struct RequestData;
+
+ struct InputData
+ {
+ QString node, service;
+ QCString protocolName;
+ int flags;
+ int familyMask;
+ int socktype;
+ int protocol;
+ };
+ }
+
+ class KResolverPrivate
+ {
+ public:
+ // parent class. Should never be changed!
+ KResolver* parent;
+ bool deleteWhenDone : 1;
+ bool waiting : 1;
+
+ // class status. Should not be changed by worker threads!
+ volatile int status;
+ volatile int errorcode, syserror;
+
+ // input data. Should not be changed by worker threads!
+ Internal::InputData input;
+
+ // mutex
+ QMutex mutex;
+
+ // output data
+ KResolverResults results;
+
+ KResolverPrivate(KResolver* _parent,
+ const QString& _node = QString::null,
+ const QString& _service = QString::null)
+ : parent(_parent), deleteWhenDone(false), waiting(false),
+ status(0), errorcode(0), syserror(0)
+ {
+ input.node = _node;
+ input.service = _service;
+ input.flags = 0;
+ input.familyMask = KResolver::AnyFamily;
+ input.socktype = 0;
+ input.protocol = 0;
+
+ results.setAddress(_node, _service);
+ }
+ };
+
+ namespace Internal
+ {
+ struct RequestData
+ {
+ // worker threads should not change values in the input data
+ KNetwork::KResolverPrivate *obj;
+ const KNetwork::Internal::InputData *input;
+ KNetwork::KResolverWorkerBase *worker; // worker class
+ RequestData *requestor; // class that requested us
+
+ volatile int nRequests; // how many requests that we made we still have left
+ };
+
+ /*
+ * @internal
+ * This class is the resolver manager
+ */
+ class KResolverManager
+ {
+ public:
+ enum EventTypes
+ { ResolutionCompleted = 1576 }; // arbitrary value;
+
+ /*
+ * This wait condition is used to notify wait states (KResolver::wait) that
+ * the resolver manager has finished processing one or more objects. All
+ * objects in wait state will be woken up and will check if they are done.
+ * If they aren't, they will go back to sleeping.
+ */
+ QWaitCondition notifyWaiters;
+
+ private:
+ /*
+ * This variable is used to count the number of threads that are running
+ */
+ volatile unsigned short runningThreads;
+
+ /*
+ * This variable is used to count the number of threads that are currently
+ * waiting for data.
+ */
+ unsigned short availableThreads;
+
+ /*
+ * This wait condition is used to notify worker threads that there is new
+ * data available that has to be processed. All worker threads wait on this
+ * waitcond for a limited amount of time.
+ */
+ QWaitCondition feedWorkers;
+
+ // this mutex protects the data in this object
+ QMutex mutex;
+
+ // hold a list of all the current threads we have
+ QPtrList<KResolverThread> workers;
+
+ // hold a list of all the new requests we have
+ QPtrList<RequestData> newRequests;
+
+ // hold a list of all the requests in progress we have
+ QPtrList<RequestData> currentRequests;
+
+ // hold a list of all the workers we have
+ QPtrList<KNetwork::KResolverWorkerFactoryBase> workerFactories;
+
+ // private constructor
+ KResolverManager();
+
+ public:
+ static KResolverManager* manager() KDE_NO_EXPORT; // creates and returns the global manager
+
+ // destructor
+ ~KResolverManager();
+
+ /*
+ * Register this thread in the pool
+ */
+ void registerThread(KResolverThread* id);
+
+ /*
+ * Unregister this thread from the pool
+ */
+ void unregisterThread(KResolverThread* id);
+
+ /*
+ * Requests new data to work on.
+ *
+ * This function should only be called from a worker thread. This function
+ * is thread-safe.
+ *
+ * If there is data to be worked on, this function will return it. If there is
+ * none, this function will return a null pointer.
+ */
+ RequestData* requestData(KResolverThread* id, int maxWaitTime);
+
+ /*
+ * Releases the resources and returns the resolved data.
+ *
+ * This function should only be called from a worker thread. It is
+ * thread-safe. It does not post the event to the manager.
+ */
+ void releaseData(KResolverThread *id, RequestData* data);
+
+ /*
+ * Registers a new worker class by way of its factory.
+ *
+ * This function is NOT thread-safe.
+ */
+ void registerNewWorker(KNetwork::KResolverWorkerFactoryBase *factory);
+
+ /*
+ * Enqueues new resolutions.
+ */
+ void enqueue(KNetwork::KResolver *obj, RequestData* requestor);
+
+ /*
+ * Dispatch a new request
+ */
+ void dispatch(RequestData* data);
+
+ /*
+ * Dequeues a resolution.
+ */
+ void dequeue(KNetwork::KResolver *obj);
+
+ /*
+ * Notifies the manager that the given resolution is about to
+ * be deleted. This function should only be called by the
+ * KResolver destructor.
+ */
+ void aboutToBeDeleted(KNetwork::KResolver *obj);
+
+ /*
+ * Notifies the manager that new events are ready.
+ */
+ void newEvent();
+
+ /*
+ * This function is called by the manager to receive a new event. It operates
+ * on the @ref eventSemaphore semaphore, which means it will block till there
+ * is at least one event to go.
+ */
+ void receiveEvent();
+
+ private:
+ /*
+ * finds a suitable worker for this request
+ */
+ KNetwork::KResolverWorkerBase *findWorker(KNetwork::KResolverPrivate *p);
+
+ /*
+ * finds data for this request
+ */
+ RequestData* findData(KResolverThread*);
+
+ /*
+ * Handle completed requests.
+ *
+ * This function is called by releaseData above
+ */
+ void handleFinished();
+
+ /*
+ * Handle one completed request.
+ *
+ * This function is called by handleFinished above.
+ */
+ bool handleFinishedItem(RequestData* item);
+
+ /*
+ * Notifies the parent class that this request is done.
+ *
+ * This function deletes the request
+ */
+ void doNotifying(RequestData *p);
+
+ /*
+ * Dequeues and notifies an object that is in Queued state
+ * Returns true if the object is no longer queued; false if it could not
+ * be dequeued (i.e., it's running)
+ */
+ bool dequeueNew(KNetwork::KResolver* obj);
+ };
+
+ /*
+ * @internal
+ * This class is a worker thread in the resolver system.
+ * This class must be thread-safe.
+ */
+ class KResolverThread: public QThread
+ {
+ private:
+ // private constructor. Only the manager can create worker threads
+ KResolverThread();
+ RequestData* data;
+
+ protected:
+ virtual void run(); // here the thread starts
+
+ friend class KNetwork::Internal::KResolverManager;
+ friend class KNetwork::KResolverWorkerBase;
+
+ public:
+ bool checkResolver(); // see KResolverWorkerBase::checkResolver
+ void acquireResolver(); // see KResolverWorkerBase::acquireResolver
+ void releaseResolver(); // see KResolverWorkerBase::releaseResolver
+ };
+
+ } // namespace Internal
+
+} // namespace KNetwork
+
+
+#endif
diff --git a/kdecore/network/kresolvermanager.cpp b/kdecore/network/kresolvermanager.cpp
new file mode 100644
index 000000000..204031915
--- /dev/null
+++ b/kdecore/network/kresolvermanager.cpp
@@ -0,0 +1,822 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <limits.h>
+#include <unistd.h> // only needed for pid_t
+
+#ifdef HAVE_RES_INIT
+# include <sys/stat.h>
+extern "C" {
+# include <arpa/nameser.h>
+}
+# include <time.h>
+# include <resolv.h>
+#endif
+
+#include <qapplication.h>
+#include <qstring.h>
+#include <qcstring.h>
+#include <qptrlist.h>
+#include <qtimer.h>
+#include <qmutex.h>
+#include <qthread.h>
+#include <qwaitcondition.h>
+#include <qsemaphore.h>
+
+#include <kde_file.h>
+#include <kdebug.h>
+#include "kresolver.h"
+#include "kresolver_p.h"
+#include "kresolverworkerbase.h"
+
+namespace KNetwork
+{
+ namespace Internal
+ {
+ void initSrvWorker();
+ void initStandardWorkers();
+ }
+}
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+/*
+ * Explanation on how the resolver system works
+
+ When KResolver::start is called, it calls KResolverManager::enqueue to add
+ an entry to the queue. KResolverManager::enqueue will verify the availability
+ of a worker thread: if one is available, it will dispatch the request to it.
+ If no threads are available, it will then decide whether to launch a thread
+ or to queue for the future.
+
+ (This process is achieved by always queueing the new request, starting a
+ new thread if necessary and then notifying of the availability of data
+ to all worker threads).
+
+ * Worker thread
+ A new thread, when started, will enter its event loop
+ immediately. That is, it'll first try to acquire new data to
+ process, which means it will lock and unlock the manager mutex in
+ the process.
+
+ If it finds no new data, it'll wait on the feedWorkers condition
+ for a certain maximum time. If that time expires and there's still
+ no data, the thread will exit, in order to save system resources.
+
+ If it finds data, however, it'll set up and call the worker class
+ that has been selected by the manager. Once that worker is done,
+ the thread releases the data through KResolverManager::releaseData.
+
+ * Data requesting/releasing
+ A worker thread always calls upon functions on the resolver manager
+ in order to acquire and release data.
+
+ When data is being requested, the KResolverManager::requestData
+ function will look the currentRequests list and return the first
+ Queued request it finds, while marking it to be InProgress.
+
+ When the worker class has returned, the worker thread will release
+ that data through the KResolverManager::releaseData function. If the
+ worker class has requested no further data (nRequests == 0), the
+ request's status is marked to be Done. It'll then look at the
+ requestor for that data: if it was requested by another worker,
+ it'll decrement the requests count for that one and add the results
+ to a list. And, finally, if the requests count for the requestor
+ becomes 0, it'll repeat this process for the requestor as well
+ (change status to Done, check for a requestor).
+ */
+
+namespace
+{
+
+/*
+ * This class is used to control the access to the
+ * system's resolver API.
+ *
+ * It is necessary to periodically poll /etc/resolv.conf and reload
+ * it if any changes are noticed. This class does exactly that.
+ *
+ * However, there's also the problem of reloading the structure while
+ * some threads are in progress. Therefore, we keep a usage reference count.
+ */
+class ResInitUsage
+{
+public:
+
+#ifdef HAVE_RES_INIT
+ time_t mTime;
+ int useCount;
+
+# ifndef RES_INIT_THREADSAFE
+ QWaitCondition cond;
+ QMutex mutex;
+# endif
+
+ bool shouldResInit()
+ {
+ // check if /etc/resolv.conf has changed
+ KDE_struct_stat st;
+ if (KDE_stat("/etc/resolv.conf", &st) != 0)
+ return false;
+
+ if (mTime != st.st_mtime)
+ {
+ kdDebug(179) << "shouldResInit: /etc/resolv.conf updated" << endl;
+ return true;
+ }
+ return false;
+ }
+
+ void callResInit()
+ {
+ if (mTime != 0)
+ {
+ // don't call it the first time
+ // let it be initialised naturally
+ kdDebug(179) << "callResInit: calling res_init()" << endl;
+ res_init();
+ }
+
+ KDE_struct_stat st;
+ if (KDE_stat("/etc/resolv.conf", &st) == 0)
+ mTime = st.st_mtime;
+ }
+
+ ResInitUsage()
+ : mTime(0), useCount(0)
+ { }
+
+ /*
+ * Marks the end of usage to the resolver tools
+ */
+ void release()
+ {
+# ifndef RES_INIT_THREADSAFE
+ QMutexLocker locker(&mutex);
+ if (--useCount == 0)
+ {
+ if (shouldResInit())
+ callResInit();
+
+ // we've reached 0, wake up anyone that's waiting to call res_init
+ cond.wakeAll();
+ }
+# else
+ // do nothing
+# endif
+ }
+
+ /*
+ * Marks the beginning of usage of the resolver API
+ */
+ void acquire()
+ {
+# ifndef RES_INIT_THREADSAFE
+ mutex.lock();
+
+ if (shouldResInit())
+ {
+ if (useCount)
+ {
+ // other threads are already using the API, so wait till
+ // it's all clear
+ // the thread that emits this condition will also call res_init
+ //qDebug("ResInitUsage: waiting for libresolv to be clear");
+ cond.wait(&mutex);
+ }
+ else
+ // we're clear
+ callResInit();
+ }
+ useCount++;
+ mutex.unlock();
+
+# else
+ if (shouldResInit())
+ callResInit();
+
+# endif
+ }
+
+#else
+ ResInitUsage()
+ { }
+
+ bool shouldResInit()
+ { return false; }
+
+ void acquire()
+ { }
+
+ void release()
+ { }
+#endif
+
+} resInit;
+
+} // anonymous namespace
+
+/*
+ * parameters
+ */
+// a thread will try maxThreadRetries to get data, waiting at most
+// maxThreadWaitTime milliseconds between each attempt. After that, it'll
+// exit
+static const int maxThreadWaitTime = 2000; // 2 seconds
+static const int maxThreads = 5;
+
+static pid_t pid; // FIXME -- disable when everything is ok
+
+KResolverThread::KResolverThread()
+ : data(0L)
+{
+}
+
+// remember! This function runs in a separate thread!
+void KResolverThread::run()
+{
+ // initialisation
+ // enter the loop already
+
+ //qDebug("KResolverThread(thread %u/%p): started", pid, (void*)QThread::currentThread());
+ KResolverManager::manager()->registerThread(this);
+ while (true)
+ {
+ data = KResolverManager::manager()->requestData(this, ::maxThreadWaitTime);
+ //qDebug("KResolverThread(thread %u/%p) got data %p", KResolverManager::pid,
+ // (void*)QThread::currentThread(), (void*)data);
+ if (data)
+ {
+ // yes, we got data
+ // process it!
+
+ // 1) set up
+ ;
+
+ // 2) run it
+ data->worker->run();
+
+ // 3) release data
+ KResolverManager::manager()->releaseData(this, data);
+
+ // now go back to the loop
+ }
+ else
+ break;
+ }
+
+ KResolverManager::manager()->unregisterThread(this);
+ //qDebug("KResolverThread(thread %u/%p): exiting", pid, (void*)QThread::currentThread());
+}
+
+bool KResolverThread::checkResolver()
+{
+ return resInit.shouldResInit();
+}
+
+void KResolverThread::acquireResolver()
+{
+#if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
+ getXXbyYYmutex.lock();
+#endif
+
+ resInit.acquire();
+}
+
+void KResolverThread::releaseResolver()
+{
+#if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
+ getXXbyYYmutex.unlock();
+#endif
+
+ resInit.release();
+}
+
+static KResolverManager *globalManager;
+
+KResolverManager* KResolverManager::manager()
+{
+ if (globalManager == 0L)
+ new KResolverManager();
+ return globalManager;
+}
+
+KResolverManager::KResolverManager()
+ : runningThreads(0), availableThreads(0)
+{
+ globalManager = this;
+ workers.setAutoDelete(true);
+ currentRequests.setAutoDelete(true);
+ initSrvWorker();
+ initStandardWorkers();
+
+ pid = getpid();
+}
+
+KResolverManager::~KResolverManager()
+{
+ // this should never be called
+
+ // kill off running threads
+ for (workers.first(); workers.current(); workers.next())
+ workers.current()->terminate();
+}
+
+void KResolverManager::registerThread(KResolverThread* )
+{
+}
+
+void KResolverManager::unregisterThread(KResolverThread*)
+{
+ runningThreads--;
+}
+
+// this function is called by KResolverThread::run
+RequestData* KResolverManager::requestData(KResolverThread *th, int maxWaitTime)
+{
+ /////
+ // This function is called in a worker thread!!
+ /////
+
+ // lock the mutex, so that the manager thread or other threads won't
+ // interfere.
+ QMutexLocker locker(&mutex);
+ RequestData *data = findData(th);
+
+ if (data)
+ // it found something, that's good
+ return data;
+
+ // nope, nothing found; sleep for a while
+ availableThreads++;
+ feedWorkers.wait(&mutex, maxWaitTime);
+ availableThreads--;
+
+ data = findData(th);
+ return data;
+}
+
+RequestData* KResolverManager::findData(KResolverThread* th)
+{
+ /////
+ // This function is called by @ref requestData above and must
+ // always be called with a locked mutex
+ /////
+
+ // now find data to be processed
+ for (RequestData *curr = newRequests.first(); curr; curr = newRequests.next())
+ if (!curr->worker->m_finished)
+ {
+ // found one
+ if (curr->obj)
+ curr->obj->status = KResolver::InProgress;
+ curr->worker->th = th;
+
+ // move it to the currentRequests list
+ currentRequests.append(newRequests.take());
+
+ return curr;
+ }
+
+ // found nothing!
+ return 0L;
+}
+
+// this function is called by KResolverThread::run
+void KResolverManager::releaseData(KResolverThread *, RequestData* data)
+{
+ /////
+ // This function is called in a worker thread!!
+ /////
+
+ //qDebug("KResolverManager::releaseData(%u/%p): %p has been released", pid,
+// (void*)QThread::currentThread(), (void*)data);
+
+ if (data->obj)
+ {
+ data->obj->status = KResolver::PostProcessing;
+ }
+
+ data->worker->m_finished = true;
+ data->worker->th = 0L; // this releases the object
+
+ // handle finished requests
+ handleFinished();
+}
+
+// this function is called by KResolverManager::releaseData above
+void KResolverManager::handleFinished()
+{
+ bool redo = false;
+ QPtrQueue<RequestData> doneRequests;
+
+ mutex.lock();
+
+ // loop over all items on the currently running list
+ // we loop from the last to the first so that we catch requests with "requestors" before
+ // we catch the requestor itself.
+ RequestData *curr = currentRequests.last();
+ while (curr)
+ {
+ if (curr->worker->th == 0L)
+ {
+ if (handleFinishedItem(curr))
+ {
+ doneRequests.enqueue(currentRequests.take());
+ if (curr->requestor &&
+ curr->requestor->nRequests == 0 &&
+ curr->requestor->worker->m_finished)
+ // there's a requestor that is now finished
+ redo = true;
+ }
+ }
+
+ curr = currentRequests.prev();
+ }
+
+ //qDebug("KResolverManager::handleFinished(%u): %d requests to notify", pid, doneRequests.count());
+ while (RequestData *d = doneRequests.dequeue())
+ doNotifying(d);
+
+ mutex.unlock();
+
+ if (redo)
+ {
+ //qDebug("KResolverManager::handleFinished(%u): restarting processing to catch requestor",
+ // pid);
+ handleFinished();
+ }
+}
+
+// This function is called by KResolverManager::handleFinished above
+bool KResolverManager::handleFinishedItem(RequestData* curr)
+
+{
+ // for all items that aren't currently running, remove from the list
+ // this includes all finished or cancelled requests
+
+ if (curr->worker->m_finished && curr->nRequests == 0)
+ {
+ // this one has finished
+ if (curr->obj)
+ curr->obj->status = KResolver::PostProcessing; // post-processing is run in doNotifying()
+
+ if (curr->requestor)
+ --curr->requestor->nRequests;
+
+ //qDebug("KResolverManager::handleFinishedItem(%u): removing %p since it's done",
+ // pid, (void*)curr);
+ return true;
+ }
+ return false;
+}
+
+
+
+void KResolverManager::registerNewWorker(KResolverWorkerFactoryBase *factory)
+{
+ workerFactories.append(factory);
+}
+
+KResolverWorkerBase* KResolverManager::findWorker(KResolverPrivate* p)
+{
+ /////
+ // this function can be called on any user thread
+ /////
+
+ // this function is called with an unlocked mutex and it's expected to be
+ // thread-safe!
+ // but the factory list is expected not to be changed asynchronously
+
+ // This function is responsible for finding a suitable worker for the given
+ // input. That means we have to do a costly operation to create each worker
+ // class and call their preprocessing functions. The first one that
+ // says they can process (i.e., preprocess() returns true) will get the job.
+
+ KResolverWorkerBase *worker;
+ for (KResolverWorkerFactoryBase *factory = workerFactories.first(); factory;
+ factory = workerFactories.next())
+ {
+ worker = factory->create();
+
+ // set up the data the worker needs to preprocess
+ worker->input = &p->input;
+
+ if (worker->preprocess())
+ {
+ // good, this one says it can process
+ if (worker->m_finished)
+ p->status = KResolver::PostProcessing;
+ else
+ p->status = KResolver::Queued;
+ return worker;
+ }
+
+ // no, try again
+ delete worker;
+ }
+
+ // found no worker
+ return 0L;
+}
+
+void KResolverManager::doNotifying(RequestData *p)
+{
+ /////
+ // This function may be called on any thread
+ // any thread at all: user threads, GUI thread, manager thread or worker thread
+ /////
+
+ // Notification and finalisation
+ //
+ // Once a request has finished the normal processing, we call the
+ // post processing function.
+ //
+ // After that is done, we will consolidate all results in the object's
+ // KResolverResults and then post an event indicating that the signal
+ // be emitted
+ //
+ // In case we detect that the object is waiting for completion, we do not
+ // post the event, for KResolver::wait will take care of emitting the
+ // signal.
+ //
+ // Once we release the mutex on the object, we may no longer reference it
+ // for it might have been deleted.
+
+ // "User" objects are those that are not created by the manager. Note that
+ // objects created by worker threads are considered "user" objects. Objects
+ // created by the manager are those created for KResolver::resolveAsync.
+ // We should delete them.
+
+ if (p->obj)
+ {
+ // lock the object
+ p->obj->mutex.lock();
+ KResolver* parent = p->obj->parent; // is 0 for non-"user" objects
+ KResolverResults& r = p->obj->results;
+
+ if (p->obj->status == KResolver::Canceled)
+ {
+ p->obj->status = KResolver::Canceled;
+ p->obj->errorcode = KResolver::Canceled;
+ p->obj->syserror = 0;
+ r.setError(KResolver::Canceled, 0);
+ }
+ else if (p->worker)
+ {
+ // post processing
+ p->worker->postprocess(); // ignore the result
+
+ // copy the results from the worker thread to the final
+ // object
+ r = p->worker->results;
+
+ // reset address
+ r.setAddress(p->input->node, p->input->service);
+
+ //qDebug("KResolverManager::doNotifying(%u/%p): for %p whose status is %d and has %d results",
+ //pid, (void*)QThread::currentThread(), (void*)p, p->obj->status, r.count());
+
+ p->obj->errorcode = r.error();
+ p->obj->syserror = r.systemError();
+ p->obj->status = !r.isEmpty() ?
+ KResolver::Success : KResolver::Failed;
+ }
+ else
+ {
+ r.empty();
+ r.setError(p->obj->errorcode, p->obj->syserror);
+ }
+
+ // check whether there's someone waiting
+ if (!p->obj->waiting && parent)
+ // no, so we must post an event requesting that the signal be emitted
+ // sorry for the C-style cast, but neither static nor reintepret cast work
+ // here; I'd have to do two casts
+ QApplication::postEvent(parent, new QEvent((QEvent::Type)(ResolutionCompleted)));
+
+ // release the mutex
+ p->obj->mutex.unlock();
+ }
+ else
+ {
+ // there's no object!
+ if (p->worker)
+ p->worker->postprocess();
+ }
+
+ delete p->worker;
+
+ // ignore p->requestor and p->nRequests
+ // they have been dealt with by the main loop
+
+ delete p;
+
+ // notify any objects waiting in KResolver::wait
+ notifyWaiters.wakeAll();
+}
+
+// enqueue a new request
+// this function is called from KResolver::start and
+// from KResolverWorkerBase::enqueue
+void KResolverManager::enqueue(KResolver *obj, RequestData *requestor)
+{
+ RequestData *newrequest = new RequestData;
+ newrequest->nRequests = 0;
+ newrequest->obj = obj->d;
+ newrequest->input = &obj->d->input;
+ newrequest->requestor = requestor;
+
+ // when processing a new request, find the most
+ // suitable worker
+ if ((newrequest->worker = findWorker(obj->d)) == 0L)
+ {
+ // oops, problem
+ // cannot find a worker class for this guy
+ obj->d->status = KResolver::Failed;
+ obj->d->errorcode = KResolver::UnsupportedFamily;
+ obj->d->syserror = 0;
+
+ doNotifying(newrequest);
+ return;
+ }
+
+ // no, queue it
+ // p->status was set in findWorker!
+ if (requestor)
+ requestor->nRequests++;
+
+ if (!newrequest->worker->m_finished)
+ dispatch(newrequest);
+ else if (newrequest->nRequests > 0)
+ {
+ mutex.lock();
+ currentRequests.append(newrequest);
+ mutex.unlock();
+ }
+ else
+ // already done
+ doNotifying(newrequest);
+}
+
+// a new request has been created
+// dispatch it
+void KResolverManager::dispatch(RequestData *data)
+{
+ // As stated in the beginning of the file, this function
+ // is supposed to verify the availability of threads, start
+ // any if necessary
+
+ QMutexLocker locker(&mutex);
+
+ // add to the queue
+ newRequests.append(data);
+
+ // check if we need to start a new thread
+ //
+ // we depend on the variables availableThreads and runningThreads to
+ // know if we are supposed to start any threads:
+ // - if availableThreads > 0, then there is at least one thread waiting,
+ // blocked in KResolverManager::requestData. It can't unblock
+ // while we are holding the mutex locked, therefore we are sure that
+ // our event will be handled
+ // - if availableThreads == 0:
+ // - if runningThreads < maxThreads
+ // we will start a new thread, which will certainly block in
+ // KResolverManager::requestData because we are holding the mutex locked
+ // - if runningThreads == maxThreads
+ // This situation generally means that we have already maxThreads running
+ // and that all of them are processing. We will not start any new threads,
+ // but will instead wait for one to finish processing and request new data
+ //
+ // There's a possible race condition here, which goes unhandled: if one of
+ // threads has timed out waiting for new data and is in the process of
+ // exiting. In that case, availableThreads == 0 and runningThreads will not
+ // have decremented yet. This means that we will not start a new thread
+ // that we could have. However, since there are other threads working, our
+ // event should be handled soon.
+ // It won't be handled if and only if ALL threads are in the process of
+ // exiting. That situation is EXTREMELY unlikely and is not handled either.
+ //
+ if (availableThreads == 0 && runningThreads < maxThreads)
+ {
+ // yes, a new thread should be started
+
+ // find if there's a finished one
+ KResolverThread *th = workers.first();
+ while (th && th->running())
+ th = workers.next();
+
+ if (th == 0L)
+ // no, create one
+ th = new KResolverThread;
+ else
+ workers.take();
+
+ th->start();
+ workers.append(th);
+ runningThreads++;
+ }
+
+ feedWorkers.wakeAll();
+
+ // clean up idle threads
+ workers.first();
+ while (workers.current())
+ {
+ if (!workers.current()->running())
+ workers.remove();
+ else
+ workers.next();
+ }
+}
+
+// this function is called by KResolverManager::dequeue
+bool KResolverManager::dequeueNew(KResolver* obj)
+{
+ // This function must be called with a locked mutex
+ // Deadlock warning:
+ // always lock the global mutex first if both mutexes must be locked
+
+ KResolverPrivate *d = obj->d;
+
+ // check if it's in the new request list
+ RequestData *curr = newRequests.first();
+ while (curr)
+ if (curr->obj == d)
+ {
+ // yes, this object is still in the list
+ // but it has never been processed
+ d->status = KResolver::Canceled;
+ d->errorcode = KResolver::Canceled;
+ d->syserror = 0;
+ newRequests.take();
+
+ delete curr->worker;
+ delete curr;
+
+ return true;
+ }
+ else
+ curr = newRequests.next();
+
+ // check if it's running
+ curr = currentRequests.first();
+ while (curr)
+ if (curr->obj == d)
+ {
+ // it's running. We cannot simply take it out of the list.
+ // it will be handled when the thread that is working on it finishes
+ d->mutex.lock();
+
+ d->status = KResolver::Canceled;
+ d->errorcode = KResolver::Canceled;
+ d->syserror = 0;
+
+ // disengage from the running threads
+ curr->obj = 0L;
+ curr->input = 0L;
+ if (curr->worker)
+ curr->worker->input = 0L;
+
+ d->mutex.unlock();
+ }
+ else
+ curr = currentRequests.next();
+
+ return false;
+}
+
+// this function is called by KResolver::cancel
+// it's expected to be thread-safe
+void KResolverManager::dequeue(KResolver *obj)
+{
+ QMutexLocker locker(&mutex);
+ dequeueNew(obj);
+}
diff --git a/kdecore/network/kresolverstandardworkers.cpp b/kdecore/network/kresolverstandardworkers.cpp
new file mode 100644
index 000000000..93c706306
--- /dev/null
+++ b/kdecore/network/kresolverstandardworkers.cpp
@@ -0,0 +1,1028 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003,2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#include <qthread.h>
+#include <qmutex.h>
+#include <qstrlist.h>
+#include <qfile.h>
+
+#include "kdebug.h"
+#include "kglobal.h"
+#include "kstandarddirs.h"
+#include "kapplication.h"
+
+#include "kresolver.h"
+#include "ksocketaddress.h"
+#include "kresolverstandardworkers_p.h"
+
+struct hostent;
+struct addrinfo;
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+static bool hasIPv6()
+{
+#ifndef AF_INET6
+ return false;
+#else
+ if (getenv("KDE_NO_IPV6") != 0L)
+ return false;
+
+ int fd = ::socket(AF_INET6, SOCK_STREAM, 0);
+ if (fd == -1)
+ return false;
+
+ ::close(fd);
+ return true;
+#endif
+}
+
+// blacklist management
+static QMutex blacklistMutex; // KDE4: change to a QReadWriteLock
+QStringList KBlacklistWorker::blacklist;
+
+void KBlacklistWorker::init()
+{
+ // HACK!
+ // FIXME KDE4: How do I detect there is an instance, without triggering
+ // its creation or an assertion fault?
+ if (!KGlobal::_instance)
+ return;
+
+ static bool beenhere = false;
+
+ if (beenhere)
+ return;
+
+ beenhere = true;
+ loadBlacklist();
+}
+
+void KBlacklistWorker::loadBlacklist()
+{
+ QMutexLocker locker(&blacklistMutex);
+ QStringList filelist = KGlobal::dirs()->findAllResources("config", "ipv6blacklist");
+
+ QStringList::ConstIterator it = filelist.constBegin(),
+ end = filelist.constEnd();
+ for ( ; it != end; ++it)
+ {
+ // for each file, each line is a domainname to be blacklisted
+ QFile f(*it);
+ if (!f.open(IO_ReadOnly))
+ continue;
+
+ QTextStream stream(&f);
+ stream.setEncoding(QTextStream::Latin1);
+ for (QString line = stream.readLine(); !line.isNull();
+ line = stream.readLine())
+ {
+ if (line.isEmpty())
+ continue;
+
+ // make sure there are no surrounding whitespaces
+ // and that it starts with .
+ line = line.stripWhiteSpace();
+ if (line[0] != '.')
+ line.prepend('.');
+
+ blacklist.append(line.lower());
+ }
+ }
+}
+
+// checks the blacklist to see if the domain is listed
+// it matches the domain ending part
+bool KBlacklistWorker::isBlacklisted(const QString& host)
+{
+ KBlacklistWorker::init();
+
+ // empty hostnames cannot be blacklisted
+ if (host.isEmpty())
+ return false;
+
+ // KDE4: QLatin1String
+ QString ascii = QString::fromLatin1(KResolver::domainToAscii(host));
+
+ QMutexLocker locker(&blacklistMutex);
+
+ // now find out if this hostname is present
+ QStringList::ConstIterator it = blacklist.constBegin(),
+ end = blacklist.constEnd();
+ for ( ; it != end; ++it)
+ if (ascii.endsWith(*it))
+ return true;
+
+ // no match:
+ return false;
+}
+
+bool KBlacklistWorker::preprocess()
+{
+ if (isBlacklisted(nodeName()))
+ {
+ results.setError(KResolver::NoName);
+ finished();
+ return true;
+ }
+ return false;
+}
+
+bool KBlacklistWorker::run()
+{
+ results.setError(KResolver::NoName);
+ finished();
+ return false; // resolution failure
+}
+
+namespace
+{
+ /*
+ * Note on the use of the system resolver functions:
+ *
+ * In all cases, we prefer to use the new getaddrinfo(3) call. That means
+ * it will always be used if it is found.
+ *
+ * If it's not found, we have the option to use gethostbyname2_r,
+ * gethostbyname_r, gethostbyname2 and gethostbyname. If gethostbyname2_r
+ * is defined, we will use it.
+ *
+ * If it's not defined, we have to choose between the non-reentrant
+ * gethostbyname2 and the reentrant but IPv4-only gethostbyname_r:
+ * we will choose gethostbyname2 if AF_INET6 is defined.
+ *
+ * Lastly, gethostbyname will be used if nothing else is present.
+ */
+
+#ifndef HAVE_GETADDRINFO
+
+# if defined(HAVE_GETHOSTBYNAME2_R)
+# define USE_GETHOSTBYNAME2_R
+# elif defined(HAVE_GETHOSTBYNAME_R) && (!defined(AF_INET6) || !defined(HAVE_GETHOSTBYNAME2))
+# define USE_GETHOSTBYNAME_R
+# elif defined(HAVE_GETHOSTBYNAME2)
+# define USE_GETHOSTBYNAME2)
+# else
+# define USE_GETHOSTBYNAME
+# endif
+
+ class GetHostByNameThread: public KResolverWorkerBase
+ {
+ public:
+ QCString m_hostname; // might be different!
+ Q_UINT16 m_port;
+ int m_scopeid;
+ int m_af;
+ KResolverResults& results;
+
+ GetHostByNameThread(const char * hostname, Q_UINT16 port,
+ int scopeid, int af, KResolverResults* res) :
+ m_hostname(hostname), m_port(port), m_scopeid(scopeid), m_af(af),
+ results(*res)
+ { }
+
+ ~GetHostByNameThread()
+ { }
+
+ virtual bool preprocess()
+ { return true; }
+
+ virtual bool run();
+
+ void processResults(hostent* he, int my_h_errno);
+ };
+
+ bool GetHostByNameThread::run()
+ {
+
+ hostent *resultptr;
+ hostent my_results;
+ unsigned buflen = 1024;
+ int res;
+ int my_h_errno;
+ char *buf = 0L;
+
+ // qDebug("ResolveThread::run(): started threaded gethostbyname for %s (af = %d)",
+ // m_hostname.data(), m_af);
+
+ ResolverLocker resLock( this );
+ do
+ {
+ res = 0;
+ my_h_errno = HOST_NOT_FOUND;
+
+ // check blacklist
+ if (m_af != AF_INET &&
+ KBlacklistWorker::isBlacklisted(QString::fromLatin1(m_hostname)))
+ break;
+
+# ifdef USE_GETHOSTBYNAME2_R
+ buf = new char[buflen];
+ res = gethostbyname2_r(m_hostname, m_af, &my_results, buf, buflen,
+ &resultptr, &my_h_errno);
+
+# elif defined(USE_GETHOSTBYNAME_R)
+ if (m_af == AF_INET)
+ {
+ buf = new char[buflen];
+ res = gethostbyname_r(m_hostname, &my_results, buf, buflen,
+ &resultptr, &my_h_errno);
+ }
+ else
+ resultptr = 0; // signal error
+
+# elif defined(USE_GETHOSTBYNAME2)
+ // must lock mutex
+ resultptr = gethostbyname2(m_hostname, m_af);
+ my_h_errno = h_errno;
+
+# else
+ if (m_af == AF_INET)
+ {
+ // must lock mutex
+ resultptr = gethostbyname(m_hostname);
+ my_h_errno = h_errno;
+ }
+ else
+ resultptr = 0;
+# endif
+
+ if (resultptr != 0L)
+ my_h_errno = 0;
+ // qDebug("GetHostByNameThread::run(): gethostbyname for %s (af = %d) returned: %d",
+ // m_hostname.data(), m_af, my_h_errno);
+
+ if (res == ERANGE)
+ {
+ // Enlarge the buffer
+ buflen += 1024;
+ delete [] buf;
+ buf = new char[buflen];
+ }
+
+ if ((res == ERANGE || my_h_errno != 0) && checkResolver())
+ {
+ // resolver needs updating, so we might as well do it now
+ resLock.openClose();
+ }
+ }
+ while (res == ERANGE);
+ processResults(resultptr, my_h_errno);
+
+ delete [] buf;
+
+ finished();
+ return results.error() == KResolver::NoError;
+ }
+
+ void GetHostByNameThread::processResults(hostent *he, int herrno)
+ {
+ if (herrno)
+ {
+ qDebug("KStandardWorker::processResults: got error %d", herrno);
+ switch (herrno)
+ {
+ case HOST_NOT_FOUND:
+ results.setError(KResolver::NoName);
+ return;
+
+ case TRY_AGAIN:
+ results.setError(KResolver::TryAgain);
+ return;
+
+ case NO_RECOVERY:
+ results.setError(KResolver::NonRecoverable);
+ return;
+
+ case NO_ADDRESS:
+ results.setError(KResolver::NoName);
+ return;
+
+ default:
+ results.setError(KResolver::UnknownError);
+ return;
+ }
+ }
+ else if (he == 0L)
+ {
+ results.setError(KResolver::NoName);
+ return; // this was an error
+ }
+
+ // clear any errors
+ setError(KResolver::NoError);
+ results.setError(KResolver::NoError);
+
+ // we process results in the reverse order
+ // that is, we prepend each result to the list of results
+ int proto = protocol();
+ int socktype = socketType();
+ if (socktype == 0)
+ socktype = SOCK_STREAM; // default
+
+ QString canon = KResolver::domainToUnicode(QString::fromLatin1(he->h_name));
+ KInetSocketAddress sa;
+ sa.setPort(m_port);
+ if (he->h_addrtype != AF_INET)
+ sa.setScopeId(m_scopeid); // this will also change the socket into IPv6
+
+ for (int i = 0; he->h_addr_list[i]; i++)
+ {
+ sa.setHost(KIpAddress(he->h_addr_list[i], he->h_addrtype == AF_INET ? 4 : 6));
+ results.prepend(KResolverEntry(sa, socktype, proto, canon, m_hostname));
+ // qDebug("KStandardWorker::processResults: adding %s", sa.toString().latin1());
+ }
+ // qDebug("KStandardWorker::processResults: added %d entries", i);
+ }
+
+#else // HAVE_GETADDRINFO
+
+ class GetAddrInfoThread: public KResolverWorkerBase
+ {
+ public:
+ QCString m_node;
+ QCString m_serv;
+ int m_af;
+ int m_flags;
+ KResolverResults& results;
+
+ GetAddrInfoThread(const char* node, const char* serv, int af, int flags,
+ KResolverResults* res) :
+ m_node(node), m_serv(serv), m_af(af), m_flags(flags), results(*res)
+ { }
+
+ ~GetAddrInfoThread()
+ { }
+
+ virtual bool preprocess()
+ { return true; }
+
+ virtual bool run();
+
+ void processResults(addrinfo* ai, int ret_code, KResolverResults& rr);
+ };
+
+ bool GetAddrInfoThread::run()
+ {
+ // check blacklist
+ if ((m_af != AF_INET && m_af != AF_UNSPEC) &&
+ KBlacklistWorker::isBlacklisted(QString::fromLatin1(m_node)))
+ {
+ results.setError(KResolver::NoName);
+ finished();
+ return false; // failed
+ }
+
+ do
+ {
+ ResolverLocker resLock( this );
+
+ // process hints
+ addrinfo hint;
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = m_af;
+ hint.ai_socktype = socketType();
+ hint.ai_protocol = protocol();
+
+ if (hint.ai_socktype == 0)
+ hint.ai_socktype = SOCK_STREAM; // default
+
+ if (m_flags & KResolver::Passive)
+ hint.ai_flags |= AI_PASSIVE;
+ if (m_flags & KResolver::CanonName)
+ hint.ai_flags |= AI_CANONNAME;
+# ifdef AI_NUMERICHOST
+ if (m_flags & KResolver::NoResolve)
+ hint.ai_flags |= AI_NUMERICHOST;
+# endif
+# ifdef AI_ADDRCONFIG
+ hint.ai_flags |= AI_ADDRCONFIG;
+# endif
+
+ // now we do the blocking processing
+ if (m_node.isEmpty())
+ m_node = "*";
+
+ addrinfo *result;
+ int res = getaddrinfo(m_node, m_serv, &hint, &result);
+ // kdDebug(179) << k_funcinfo << "getaddrinfo(\""
+ // << m_node << "\", \"" << m_serv << "\", af="
+ // << m_af << ") returned " << res << endl;
+
+ if (res != 0)
+ {
+ if (checkResolver())
+ {
+ // resolver requires reinitialisation
+ resLock.openClose();
+ continue;
+ }
+
+ switch (res)
+ {
+ case EAI_BADFLAGS:
+ results.setError(KResolver::BadFlags);
+ break;
+
+#ifdef EAI_NODATA
+ // In some systems, EAI_NODATA was #define'd to EAI_NONAME which would break this case.
+#if EAI_NODATA != EAI_NONAME
+ case EAI_NODATA: // it was removed in RFC 3493
+#endif
+#endif
+ case EAI_NONAME:
+ results.setError(KResolver::NoName);
+ break;
+
+ case EAI_AGAIN:
+ results.setError(KResolver::TryAgain);
+ break;
+
+ case EAI_FAIL:
+ results.setError(KResolver::NonRecoverable);
+ break;
+
+ case EAI_FAMILY:
+ results.setError(KResolver::UnsupportedFamily);
+ break;
+
+ case EAI_SOCKTYPE:
+ results.setError(KResolver::UnsupportedSocketType);
+ break;
+
+ case EAI_SERVICE:
+ results.setError(KResolver::UnsupportedService);
+ break;
+
+ case EAI_MEMORY:
+ results.setError(KResolver::Memory);
+ break;
+
+ case EAI_SYSTEM:
+ results.setError(KResolver::SystemError, errno);
+ break;
+
+ default:
+ results.setError(KResolver::UnknownError, errno);
+ break;
+ }
+
+ finished();
+ return false; // failed
+ }
+
+ // if we are here, lookup succeeded
+ QString canon;
+ const char *previous_canon = 0L;
+
+ for (addrinfo* p = result; p; p = p->ai_next)
+ {
+ // cache the last canon name to avoid doing the ToUnicode processing unnecessarily
+ if ((previous_canon && !p->ai_canonname) ||
+ (!previous_canon && p->ai_canonname) ||
+ (p->ai_canonname != previous_canon &&
+ strcmp(p->ai_canonname, previous_canon) != 0))
+ {
+ canon = KResolver::domainToUnicode(QString::fromAscii(p->ai_canonname));
+ previous_canon = p->ai_canonname;
+ }
+
+ results.append(KResolverEntry(p->ai_addr, p->ai_addrlen, p->ai_socktype,
+ p->ai_protocol, canon, m_node));
+ }
+
+ freeaddrinfo(result);
+ results.setError(KResolver::NoError);
+ finished();
+ return results.error() == KResolver::NoError;
+ }
+ while (true);
+ }
+
+#endif // HAVE_GETADDRINFO
+} // namespace
+
+bool KStandardWorker::sanityCheck()
+{
+ // check that the requested values are sensible
+
+ if (!nodeName().isEmpty())
+ {
+ QString node = nodeName();
+ if (node.find('%') != -1)
+ node.truncate(node.find('%'));
+
+ if (node.isEmpty() || node == QString::fromLatin1("*") ||
+ node == QString::fromLatin1("localhost"))
+ m_encodedName.truncate(0);
+ else
+ {
+ m_encodedName = KResolver::domainToAscii(node);
+
+ if (m_encodedName.isNull())
+ {
+ qDebug("could not encode hostname '%s' (UTF-8)", node.utf8().data());
+ setError(KResolver::NoName);
+ return false; // invalid hostname!
+ }
+
+ // qDebug("Using encoded hostname '%s' for '%s' (UTF-8)", m_encodedName.data(),
+ // node.utf8().data());
+ }
+ }
+ else
+ m_encodedName.truncate(0); // just to be sure, but it should be clear already
+
+ if (protocol() == -1)
+ {
+ setError(KResolver::NonRecoverable);
+ return false; // user passed invalid protocol name
+ }
+
+ return true; // it's sane
+}
+
+bool KStandardWorker::resolveScopeId()
+{
+ // we must test the original name, not the encoded one
+ scopeid = 0;
+ int pos = nodeName().findRev('%');
+ if (pos == -1)
+ return true;
+
+ QString scopename = nodeName().mid(pos + 1);
+
+ bool ok;
+ scopeid = scopename.toInt(&ok);
+ if (!ok)
+ {
+ // it's not a number
+ // therefore, it's an interface name
+#ifdef HAVE_IF_NAMETOINDEX
+ scopeid = if_nametoindex(scopename.latin1());
+#else
+ scopeid = 0;
+#endif
+ }
+
+ return true;
+}
+
+bool KStandardWorker::resolveService()
+{
+ // find the service first
+ bool ok;
+ port = serviceName().toUInt(&ok);
+ if (!ok)
+ {
+ // service name does not contain a port number
+ // must be a name
+
+ if (serviceName().isEmpty() || serviceName().compare(QString::fromLatin1("*")) == 0)
+ port = 0;
+ else
+ {
+ // it's a name. We need the protocol name in order to lookup.
+ QCString protoname = protocolName();
+
+ if (protoname.isEmpty() && protocol())
+ {
+ protoname = KResolver::protocolName(protocol()).first();
+
+ // if it's still empty...
+ if (protoname.isEmpty())
+ {
+ // lookup failed!
+ setError(KResolver::NoName);
+ return false;
+ }
+ }
+ else
+ protoname = "tcp";
+
+ // it's not, so we can do a port lookup
+ int result = KResolver::servicePort(serviceName().latin1(), protoname);
+ if (result == -1)
+ {
+ // lookup failed!
+ setError(KResolver::NoName);
+ return false;
+ }
+
+ // it worked, we have a port number
+ port = (Q_UINT16)result;
+ }
+ }
+
+ // we found a port
+ return true;
+}
+
+KResolver::ErrorCodes KStandardWorker::addUnix()
+{
+ // before trying to add, see if the user wants Unix sockets
+ if ((familyMask() & KResolver::UnixFamily) == 0)
+ // no, Unix sockets are not wanted
+ return KResolver::UnsupportedFamily;
+
+ // now check if the requested data are good for a Unix socket
+ if (!m_encodedName.isEmpty())
+ return KResolver::AddrFamily; // non local hostname
+
+ if (protocol() || protocolName())
+ return KResolver::BadFlags; // cannot have Unix sockets with protocols
+
+ QString pathname = serviceName();
+ if (pathname.isEmpty())
+ return KResolver::NoName;; // no path?
+
+ if (pathname[0] != '/')
+ // non absolute pathname
+ // put it in /tmp
+ pathname.prepend("/tmp/");
+
+ // qDebug("QNoResolveWorker::addUnix(): adding Unix socket for %s", pathname.local8Bit().data());
+ KUnixSocketAddress sa(pathname);
+ int socktype = socketType();
+ if (socktype == 0)
+ socktype = SOCK_STREAM; // default
+
+ results.append(KResolverEntry(sa, socktype, 0));
+ setError(KResolver::NoError);
+
+ return KResolver::NoError;
+}
+
+bool KStandardWorker::resolveNumerically()
+{
+ // if the NoResolve flag is active, our result from this point forward
+ // will always be true, even if the resolution failed.
+ // that indicates that our result is authoritative.
+
+ bool wantV4 = familyMask() & KResolver::IPv4Family,
+ wantV6 = familyMask() & KResolver::IPv6Family;
+
+ if (!wantV6 && !wantV4)
+ // no Internet address is wanted!
+ return (flags() & KResolver::NoResolve);
+
+ // now try to find results
+ if (!resolveScopeId() || !resolveService())
+ return (flags() & KResolver::NoResolve);
+
+ // we have scope IDs and port numbers
+ // now try to resolve the hostname numerically
+ KInetSocketAddress sa;
+ setError(KResolver::NoError);
+ sa.setHost(KIpAddress(QString::fromLatin1(m_encodedName)));
+
+ // if it failed, the length was reset to 0
+ bool ok = sa.length() != 0;
+
+ sa.setPort(port);
+ if (sa.ipVersion() == 6)
+ sa.setScopeId(scopeid);
+ int proto = protocol();
+ int socktype = socketType();
+ if (socktype == 0)
+ socktype = SOCK_STREAM;
+
+ if (ok)
+ {
+ // the given hostname was successfully converted to an IP address
+ // check if the user wanted this kind of address
+
+ if ((sa.ipVersion() == 4 && wantV4) ||
+ (sa.ipVersion() == 6 && wantV6))
+ results.append(KResolverEntry(sa, socktype, proto));
+ else
+ {
+ // Note: the address *IS* a numeric IP
+ // but it's not of the kind the user asked for
+ //
+ // that means that it cannot be a Unix socket (because it's an IP)
+ // and that means that no resolution will tell us otherwise
+ //
+ // This is a failed resolution
+
+ setError(KResolver::AddrFamily);
+ return true;
+ }
+ }
+ else if (m_encodedName.isEmpty())
+ {
+ // user wanted localhost
+ if (flags() & KResolver::Passive)
+ {
+ if (wantV6)
+ {
+ sa.setHost(KIpAddress::anyhostV6);
+ results.append(KResolverEntry(sa, socktype, proto));
+ }
+
+ if (wantV4)
+ {
+ sa.setHost(KIpAddress::anyhostV4);
+ results.append(KResolverEntry(sa, socktype, proto));
+ }
+ }
+ else
+ {
+ if (wantV6)
+ {
+ sa.setHost(KIpAddress::localhostV6);
+ results.append(KResolverEntry(sa, socktype, proto));
+ }
+
+ if (wantV4)
+ {
+ sa.setHost(KIpAddress::localhostV4);
+ results.append(KResolverEntry(sa, socktype, proto));
+ }
+ }
+
+ ok = true;
+ }
+ else
+ {
+ // probably bad flags, since the address is not convertible without
+ // resolution
+
+ setError(KResolver::BadFlags);
+ ok = false;
+ }
+
+ return ok || (flags() & KResolver::NoResolve);
+}
+
+bool KStandardWorker::preprocess()
+{
+ // check sanity
+ if (!sanityCheck())
+ return false;
+
+ // this worker class can only handle known families
+ if (familyMask() & KResolver::UnknownFamily)
+ {
+ setError(KResolver::UnsupportedFamily);
+ return false; // we don't know about this
+ }
+
+ // check the socket types
+ if (socketType() != SOCK_STREAM && socketType() != SOCK_DGRAM && socketType() != 0)
+ {
+ setError(KResolver::UnsupportedSocketType);
+ return false;
+ }
+
+ // check if we can resolve all numerically
+ // resolveNumerically always returns true if the NoResolve flag is set
+ if (resolveNumerically() || m_encodedName.isEmpty())
+ {
+ // indeed, we have resolved numerically
+ setError(addUnix());
+ if (results.count())
+ setError(KResolver::NoError);
+ finished();
+ return true;
+ }
+
+ // check if the user wants something we know about
+#ifdef AF_INET6
+# define mask (KResolver::IPv6Family | KResolver::IPv4Family | KResolver::UnixFamily)
+#else
+# define mask (KResolver::IPv4Family | KResolver::UnixFamily)
+#endif
+
+ if ((familyMask() & mask) == 0)
+ // errr... nothing we know about
+ return false;
+
+#undef mask
+
+ return true; // it's ok
+}
+
+bool KStandardWorker::run()
+{
+#ifndef HAVE_GETADDRINFO
+ // check the scope id first
+ // since most of the resolutions won't have a scope id, this should be fast
+ // and we won't have wasted time on services if this fails
+ if (!resolveScopeId())
+ return false;
+
+ // resolve the service now, before entering the blocking operation
+ if (!resolveService())
+ return false;
+#endif
+
+ // good
+ // now we need the hostname
+ setError(KResolver::NoName);
+
+ // these are the family types that we know of
+ struct
+ {
+ KResolver::SocketFamilies mask;
+ int af;
+ } families[] = { { KResolver::IPv4Family, AF_INET }
+#ifdef AF_INET6
+ , { KResolver::IPv6Family, AF_INET6 }
+#endif
+ };
+ int familyCount = sizeof(families)/sizeof(families[0]);
+ bool skipIPv6 = !hasIPv6();
+ resultList.setAutoDelete(true);
+
+ for (int i = 0; i < familyCount; i++)
+ if (familyMask() & families[i].mask)
+ {
+#ifdef AF_INET6
+ if (skipIPv6 && families[i].af == AF_INET6)
+ continue;
+#endif
+
+ KResolverWorkerBase *worker;
+ KResolverResults *res = new KResolverResults;
+ resultList.append(res);
+#ifdef HAVE_GETADDRINFO
+ worker = new GetAddrInfoThread(m_encodedName,
+ serviceName().latin1(),
+ families[i].af, flags(), res);
+#else
+ worker = new GetHostByNameThread(m_encodedName, port, scopeid,
+ families[i].af, res);
+#endif
+
+ enqueue(worker);
+ }
+
+ // not finished
+ return true;
+}
+
+bool KStandardWorker::postprocess()
+{
+ if (results.count())
+ return true; // no need
+ // now copy over what we need from the underlying results
+
+ // start backwards because IPv6 was launched later (if at all)
+ if (resultList.isEmpty())
+ {
+ results.setError(KResolver::NoName);
+ return true;
+ }
+
+ KResolverResults *rr = resultList.last();
+ while (rr)
+ {
+ if (!rr->isEmpty())
+ {
+ results.setError(KResolver::NoError);
+ KResolverResults::Iterator it = rr->begin();
+ for ( ; it != rr->end(); ++it)
+ results.append(*it);
+ }
+ else if (results.isEmpty())
+ // this generated an error
+ // copy the error code over
+ setError(rr->error(), rr->systemError());
+
+ rr = resultList.prev();
+ }
+
+ resultList.clear();
+ return true;
+}
+
+#ifdef HAVE_GETADDRINFO
+KGetAddrinfoWorker::~KGetAddrinfoWorker()
+{
+}
+
+bool KGetAddrinfoWorker::preprocess()
+{
+ // getaddrinfo(3) can always handle any kind of request that makes sense
+ if (!sanityCheck())
+ return false;
+
+ if (flags() & KResolver::NoResolve)
+ // oops, numeric resolution?
+ return run();
+
+ return true;
+}
+
+bool KGetAddrinfoWorker::run()
+{
+ // make an AF_UNSPEC getaddrinfo(3) call
+ GetAddrInfoThread worker(m_encodedName, serviceName().latin1(),
+ AF_UNSPEC, flags(), &results);
+
+ if (!worker.run())
+ {
+ if (wantThis(AF_UNIX))
+ {
+ if (addUnix() == KResolver::NoError)
+ setError(KResolver::NoError);
+ }
+ else
+ setError(worker.results.error(), worker.results.systemError());
+
+ return false;
+ }
+
+ // The worker has finished working
+ // now copy over only what we may want
+ // keep track of any Unix-domain sockets
+
+ bool seen_unix = false;
+ KResolverResults::Iterator it = results.begin();
+ for ( ; it != results.end(); )
+ {
+ if ((*it).family() == AF_UNIX)
+ seen_unix = true;
+ if (!wantThis((*it).family()))
+ it = results.remove(it);
+ else
+ ++it;
+ }
+
+ if (!seen_unix)
+ addUnix();
+
+ finished();
+ return true;
+}
+
+bool KGetAddrinfoWorker::wantThis(int family)
+{
+ // tells us if the user wants a socket of this family
+
+#ifdef AF_INET6
+ if (family == AF_INET6 && familyMask() & KResolver::IPv6Family)
+ return true;
+#endif
+ if (family == AF_INET && familyMask() & KResolver::IPv4Family)
+ return true;
+ if (family == AF_UNIX && familyMask() & KResolver::UnixFamily)
+ return true;
+
+ // it's not a family we know about...
+ if (familyMask() & KResolver::UnknownFamily)
+ return true;
+
+ return false;
+}
+
+#endif
+
+void KNetwork::Internal::initStandardWorkers()
+{
+ //KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KBlacklistWorker>);
+ KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KStandardWorker>);
+
+#ifdef HAVE_GETADDRINFO
+ KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KGetAddrinfoWorker>);
+#endif
+}
diff --git a/kdecore/network/kresolverstandardworkers_p.h b/kdecore/network/kresolverstandardworkers_p.h
new file mode 100644
index 000000000..30c8f3c1e
--- /dev/null
+++ b/kdecore/network/kresolverstandardworkers_p.h
@@ -0,0 +1,111 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KRESOLVERSTANDARDWORKERS_P_H
+#define KRESOLVERSTANDARDWORKERS_P_H
+
+#include <sys/types.h>
+#include <netdb.h>
+
+#include <qptrlist.h>
+#include <qcstring.h>
+#include <qstringlist.h>
+
+#include "kresolver.h"
+#include "kresolverworkerbase.h"
+
+#include <config.h>
+
+namespace KNetwork { namespace Internal
+{
+ extern void initStandardWorkers() KDE_NO_EXPORT;
+
+ /**
+ * @internal
+ * The blacklist worker.
+ */
+ class KBlacklistWorker: public KNetwork::KResolverWorkerBase
+ {
+ public:
+ static QStringList blacklist;
+
+ static void loadBlacklist();
+ static void init();
+ static bool isBlacklisted(const QString&);
+
+ virtual bool preprocess();
+ virtual bool run();
+ virtual bool postprocess() { return true; }
+ };
+
+ /** @internal
+ * Standard worker.
+ */
+ class KStandardWorker: public KNetwork::KResolverWorkerBase
+ {
+ protected:
+ mutable QCString m_encodedName;
+ Q_UINT16 port;
+ int scopeid;
+ QPtrList<KNetwork::KResolverResults> resultList;
+
+ public:
+ bool sanityCheck();
+
+ virtual bool preprocess();
+ virtual bool run();
+ virtual bool postprocess();
+
+ bool resolveScopeId();
+ bool resolveService();
+ bool resolveNumerically();
+
+ KNetwork::KResolver::ErrorCodes addUnix();
+ };
+
+#if defined(HAVE_GETADDRINFO)
+ /** @internal
+ * Worker class based on getaddrinfo(3).
+ *
+ * This class does not do post-processing.
+ */
+ class KGetAddrinfoWorker: public KStandardWorker
+ {
+ public:
+ KGetAddrinfoWorker()
+ { }
+
+ virtual ~KGetAddrinfoWorker();
+ virtual bool preprocess();
+ virtual bool run();
+ virtual bool postprocess() { return true; }
+
+ bool wantThis(int family);
+ };
+#endif // HAVE_GETADDRINFO
+
+} } // namespace KNetwork::Internal
+
+
+#endif
diff --git a/kdecore/network/kresolverworkerbase.cpp b/kdecore/network/kresolverworkerbase.cpp
new file mode 100644
index 000000000..32a32da2a
--- /dev/null
+++ b/kdecore/network/kresolverworkerbase.cpp
@@ -0,0 +1,150 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003,2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+
+#include <qcstring.h>
+#include <qstring.h>
+
+#include "kresolver.h"
+#include "kresolver_p.h"
+#include "kresolverworkerbase.h"
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+KResolverWorkerBase::KResolverWorkerBase()
+ : th(0L), input(0L), m_finished(0), m_reserved(0)
+{
+}
+
+KResolverWorkerBase::~KResolverWorkerBase()
+{
+}
+
+QString KResolverWorkerBase::nodeName() const
+{
+ if (input)
+ return input->node;
+ return QString::null;
+}
+
+QString KResolverWorkerBase::serviceName() const
+{
+ if (input)
+ return input->service;
+ return QString::null;
+}
+
+int KResolverWorkerBase::flags() const
+{
+ if (input)
+ return input->flags;
+ return 0;
+}
+
+int KResolverWorkerBase::familyMask() const
+{
+ if (input)
+ return input->familyMask;
+ return 0;
+}
+
+int KResolverWorkerBase::socketType() const
+{
+ if (input)
+ return input->socktype;
+ return 0;
+}
+
+int KResolverWorkerBase::protocol() const
+{
+ if (input)
+ return input->protocol;
+ return 0;
+}
+
+QCString KResolverWorkerBase::protocolName() const
+{
+ QCString res;
+ if (input)
+ res = input->protocolName;
+ return res;
+}
+
+void KResolverWorkerBase::finished()
+{
+ m_finished = true;
+}
+
+bool KResolverWorkerBase::postprocess()
+{
+ return true; // no post-processing is a always successful postprocessing
+}
+
+bool KResolverWorkerBase::enqueue(KResolver* res)
+{
+ KResolverManager::manager()->enqueue(res, th->data);
+ return true;
+}
+
+bool KResolverWorkerBase::enqueue(KResolverWorkerBase* worker)
+{
+ RequestData *myself = th->data;
+ RequestData *newrequest = new RequestData;
+ newrequest->obj = 0;
+ newrequest->input = input; // same input
+ newrequest->requestor = myself;
+ newrequest->nRequests = 0;
+ newrequest->worker = worker;
+ myself->nRequests++;
+ KResolverManager::manager()->dispatch(newrequest);
+ return true;
+}
+
+bool KResolverWorkerBase::checkResolver()
+{
+ assert(th != 0L);
+ return th->checkResolver();
+}
+
+void KResolverWorkerBase::acquireResolver()
+{
+ assert(th != 0L);
+ th->acquireResolver();
+}
+
+void KResolverWorkerBase::releaseResolver()
+{
+ assert(th != 0L);
+ th->releaseResolver();
+}
+
+void KResolverWorkerFactoryBase::registerNewWorker(KResolverWorkerFactoryBase* factory)
+{
+ KResolverManager::manager()->registerNewWorker(factory);
+}
+
diff --git a/kdecore/network/kresolverworkerbase.h b/kdecore/network/kresolverworkerbase.h
new file mode 100644
index 000000000..8776e9142
--- /dev/null
+++ b/kdecore/network/kresolverworkerbase.h
@@ -0,0 +1,317 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003,2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KRESOLVERWORKERBASE_H
+#define KRESOLVERWORKERBASE_H
+
+#include "kresolver.h"
+
+// forward declarations
+class QString;
+template <class T> class QValueList;
+
+namespace KNetwork {
+
+ namespace Internal
+ {
+ class KResolverThread;
+ struct InputData;
+ }
+
+/** @internal
+ * This class is the base functionality for a resolver worker. That is,
+ * the class that does the actual work.
+ *
+ * In the future, this class might be exposed to allow plug-ins. So, try and
+ * make it binary compatible.
+ *
+ * Note that hostnames are still encoded in Unicode at this point. It's up to
+ * the worker class to decide which encoding to use. In the case of DNS,
+ * an ASCII Compatible Encoding (ACE) must be used.
+ * See @ref KResolver::domainToAscii.
+ *
+ * Also specially note that the run method in this class is called in a
+ * thread that is not the program's main thread. So do not do anything there
+ * that you shouldn't!
+ *
+ * @class KResolverWorkerBase kresolverworkerbase.h kresolverworkerbase.h
+ */
+class KResolverWorkerBase
+{
+public:
+
+ /**
+ * Helper class for locking the resolver subsystem.
+ * Similar to QMutexLocker.
+ *
+ * @author Luís Pedro Coelho
+ * @since 3.4
+ */
+ class ResolverLocker
+ {
+ public:
+ /**
+ * Constructor. Acquires a lock.
+ */
+ ResolverLocker(KResolverWorkerBase* parent)
+ : parent( parent )
+ {
+ parent->acquireResolver();
+ }
+
+ /**
+ * Destructor. Releases the lock.
+ */
+ ~ResolverLocker()
+ {
+ parent->releaseResolver();
+ }
+
+ /**
+ * Releases the lock and then reacquires it.
+ * It may be necessary to call this if the resolving function
+ * decides to retry.
+ */
+ void openClose()
+ {
+ parent->releaseResolver();
+ parent->acquireResolver();
+ }
+
+ private:
+ /// @internal
+ KResolverWorkerBase* parent;
+ };
+private:
+ // this will be like our d pointer
+ KNetwork::Internal::KResolverThread *th;
+ const KNetwork::Internal::InputData *input;
+ friend class KNetwork::Internal::KResolverThread;
+ friend class KNetwork::Internal::KResolverManager;
+ friend class KResolverWorkerBase::ResolverLocker;
+
+ int m_finished : 1;
+ int m_reserved : 31; // reserved
+
+public:
+ /**
+ * Derived classes will put their resolved data in this list, or will
+ * leave it empty in case of error.
+ *
+ * Status and error codes should also be stored in this object (the
+ * @ref setError function does that).
+ */
+ KResolverResults results;
+
+public:
+ // default constructor
+ KResolverWorkerBase();
+
+ // virtual destructor
+ virtual ~KResolverWorkerBase();
+
+ /**
+ * This is the hostname to be looked for
+ */
+ QString nodeName() const;
+
+ /**
+ * And this is the service name
+ */
+ QString serviceName() const;
+
+ /**
+ * gets the flags
+ */
+ int flags() const;
+
+ /**
+ * gets the family mask
+ */
+ int familyMask() const;
+
+ /**
+ * gets the socket type
+ */
+ int socketType() const;
+
+ /**
+ * gets the protocol number
+ */
+ int protocol() const;
+
+ /**
+ * gets the protocol name, if applicable
+ */
+ QCString protocolName() const;
+
+ /**
+ * Call this function to indicate that processing
+ * has finished. This is useful in the preprocessing
+ * stage, to indicate that @ref run doesn't have to be
+ * called.
+ */
+ void finished();
+
+protected:
+ // like a QThread
+ /**
+ * This is the function that should be overriden in derived classes.
+ *
+ * Derived classes will do their blocking job in this function and return
+ * either success or failure to work (not the lookup). That is, whether the
+ * lookup result was a domain found or not, if we got our answer, we should
+ * indicate success. The error itself must be set with @ref setError.
+ *
+ * \b Important: this function gets called in a separate thread!
+ *
+ * @return true on success
+ */
+ virtual bool run() = 0;
+
+ /**
+ * This function gets called during pre processing for this class and you must
+ * override it.
+ *
+ * \b Important: this function gets called in the main event thread. And it MUST
+ * NOT block.
+ *
+ * This function can be used for an object to determine if it will be able
+ * to resolve the given data or not even before launching into a blocking
+ * operation. This function should return true if the object is capable of
+ * handling this kind of data; false otherwise. Note that the return value
+ * of 'true' means that the object's blocking answer will be considered authoritative.
+ *
+ * This function MUST NOT queue further requests. Leave that to @ref run.
+ *
+ * This function is pure virtual; you must override it.
+ *
+ * @return true on success
+ */
+ virtual bool preprocess() = 0;
+
+ /**
+ * This function gets called during post processing for this class.
+ *
+ * \b Important: this function gets called in the main event thread. And it MUST
+ * NOT block.
+ *
+ * @returns true on success
+ */
+ virtual bool postprocess();
+
+ /**
+ * Sets the error
+ */
+ inline void setError(int errorcode, int syserror = 0)
+ { results.setError(errorcode, syserror); }
+
+ /**
+ * Enqueue the given resolver for post-processing.
+ *
+ * Use this function to make the manager call for another resolution.
+ * This is suitable for workers that do post-processing.
+ *
+ * The manager will make sure that any requests enqueued by this function
+ * are done before calling the postprocessing function, which you should
+ * override.
+ *
+ * \b Important: do use KResolver's own enqueueing functions (i.e., @ref KResolver::start).
+ * Instead, use this function.
+ *
+ * @returns true on successful queueing or false if a problem ocurred
+ */
+ bool enqueue(KResolver* other);
+
+ /**
+ * @overload
+ */
+ bool enqueue(KResolverWorkerBase* worker);
+
+ /**
+ * Checks the resolver subsystem status.
+ * @returns true if the resolver subsystem changed, false otherwise.
+ * If this function returns true, it might be necessary to
+ * restart the resolution altogether.
+ * @since 3.4
+ */
+ bool checkResolver();
+
+ /**
+ * This function has to be called from the resolver workers that require
+ * use of the DNS resolver code (i.e., res_* functions, generally in
+ * libresolv). It indicates that the function is starting a resolution
+ * and that the resolver backend shouldn't change asynchronously.
+ *
+ * If any pending res_init's are required, they will be performed before
+ * this function returns.
+ *
+ * @since 3.4
+ */
+ void acquireResolver();
+
+ /**
+ * This function is the counterpart for @ref acquireResolver: the worker
+ * thread indicates that it's done with the resolver.
+ *
+ * @since 3.4
+ */
+ void releaseResolver();
+
+};
+
+/** @internal
+ * This class provides functionality for creating and registering worker classes.
+ *
+ * @class KResolverWorkerFactoryBase kresolverworkerbase.h kresolverworkerbase.h
+ */
+class KResolverWorkerFactoryBase
+{
+public:
+ virtual KResolverWorkerBase* create() const = 0;
+
+ /**
+ * Wrapper call to register workers
+ *
+ * It is NOT thread-safe!
+ */
+ static void registerNewWorker(KResolverWorkerFactoryBase* factory);
+};
+
+/** @internal
+ * This class provides functionality for creating and registering worker classes.
+ *
+ * @class KResolverWorkerFactory kresolverworkerbase.h kresolverworkerbase.h
+ */
+template<class Worker>
+class KResolverWorkerFactory: public KResolverWorkerFactoryBase
+{
+public:
+ virtual KResolverWorkerBase* create() const
+ { return new Worker; }
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/kreverseresolver.cpp b/kdecore/network/kreverseresolver.cpp
new file mode 100644
index 000000000..dbcc23d79
--- /dev/null
+++ b/kdecore/network/kreverseresolver.cpp
@@ -0,0 +1,263 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "config.h"
+
+// System includes
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <signal.h>
+
+// Qt
+#include <qevent.h>
+#include <qmutex.h>
+#include <qapplication.h>
+
+// Us
+#include "kreverseresolver.h"
+#include "kresolver_p.h"
+#include "kresolverworkerbase.h"
+#include "ksocketaddress.h"
+
+#ifndef HAVE_GETNAMEINFO
+// FIXME KDE4:
+// move to syssocket or adapt
+# include "netsupp.h"
+#endif
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+namespace
+{
+ class ReverseThread: public KResolverWorkerBase
+ {
+ public:
+ ReverseThread(const KSocketAddress& addr, int flags)
+ : m_addr(addr), m_flags(flags), m_parent(0L)
+ { }
+
+ virtual ~ReverseThread()
+ { }
+
+ virtual bool preprocess()
+ { return true; }
+ virtual bool run();
+ virtual bool postprocess();
+
+ // input:
+ KSocketAddress m_addr;
+ int m_flags;
+ KReverseResolver *m_parent;
+
+ // output:
+ QString node;
+ QString service;
+ bool success;
+ };
+
+ class KReverseResolverEvent: public QEvent
+ {
+ public:
+ static const int myType = QEvent::User + 63; // arbitrary value
+ QString node;
+ QString service;
+ bool success;
+
+ KReverseResolverEvent(const QString& _node, const QString& _service,
+ bool _success)
+ : QEvent((Type)myType), node(_node),
+ service(_service), success(_success)
+ { }
+ };
+}
+
+class KNetwork::KReverseResolverPrivate
+{
+public:
+ QString node;
+ QString service;
+ KSocketAddress addr;
+ int flags;
+
+ ReverseThread* worker;
+ bool success;
+
+ inline KReverseResolverPrivate(const KSocketAddress& _addr)
+ : addr(_addr), worker(0L), success(false)
+ { }
+};
+
+KReverseResolver::KReverseResolver(const KSocketAddress& addr, int flags,
+ QObject *parent, const char* name)
+ : QObject(parent, name), d(new KReverseResolverPrivate(addr))
+{
+ d->flags = flags;
+}
+
+KReverseResolver::~KReverseResolver()
+{
+ if (d->worker)
+ d->worker->m_parent = 0L;
+}
+
+bool KReverseResolver::isRunning() const
+{
+ return d->worker != 0L;
+}
+
+bool KReverseResolver::success() const
+{
+ return !isRunning() && d->success;
+}
+
+bool KReverseResolver::failure() const
+{
+ return !isRunning() && !d->success;
+}
+
+QString KReverseResolver::node() const
+{
+ return d->node;
+}
+
+QString KReverseResolver::service() const
+{
+ return d->service;
+}
+
+const KSocketAddress& KReverseResolver::address() const
+{
+ return d->addr;
+}
+
+bool KReverseResolver::start()
+{
+ if (d->worker != 0L)
+ return true; // already started
+
+ d->worker = new ReverseThread(d->addr, d->flags);
+ d->worker->m_parent = this;
+
+ RequestData *req = new RequestData;
+ req->obj = 0L;
+ req->input = 0L;
+ req->requestor = 0L;
+ req->worker = d->worker;
+ KResolverManager::manager()->dispatch(req);
+ return true;
+}
+
+bool KReverseResolver::event(QEvent *e)
+{
+ if (e->type() != KReverseResolverEvent::myType)
+ return QObject::event(e); // call parent
+
+ KReverseResolverEvent *re = static_cast<KReverseResolverEvent*>(e);
+ d->node = re->node;
+ d->service = re->service;
+ d->success = re->success;
+
+ // don't delete d->worker!
+ // KResolverManager::doNotifying takes care of that, if it hasn't already
+ d->worker = 0L;
+
+ // emit signal
+ emit finished(*this);
+
+ return true;
+}
+
+bool KReverseResolver::resolve(const KSocketAddress& addr, QString& node,
+ QString& serv, int flags)
+{
+ ReverseThread th(addr, flags);
+ if (th.run())
+ {
+ node = th.node;
+ serv = th.service;
+ return true;
+ }
+ return false;
+}
+
+bool KReverseResolver::resolve(const struct sockaddr* sa, Q_UINT16 salen,
+ QString& node, QString& serv, int flags)
+{
+ return resolve(KSocketAddress(sa, salen), node, serv, flags);
+}
+
+bool ReverseThread::run()
+{
+ int err;
+ char h[NI_MAXHOST], s[NI_MAXSERV];
+ int niflags = 0;
+
+ h[0] = s[0] = '\0';
+
+ if (m_flags & KReverseResolver::NumericHost)
+ niflags |= NI_NUMERICHOST;
+ if (m_flags & KReverseResolver::NumericService)
+ niflags |= NI_NUMERICSERV;
+ if (m_flags & KReverseResolver::NodeNameOnly)
+ niflags |= NI_NOFQDN;
+ if (m_flags & KReverseResolver::Datagram)
+ niflags |= NI_DGRAM;
+ if (m_flags & KReverseResolver::ResolutionRequired)
+ niflags |= NI_NAMEREQD;
+
+ {
+#ifdef NEED_MUTEX
+ QMutexLocker locker(&::getXXbyYYmutex);
+#endif
+ err = ::getnameinfo(m_addr, m_addr.length(),
+ h, sizeof(h) - 1, s, sizeof(s) - 1, niflags);
+ }
+
+ if (err == 0)
+ {
+ node = KResolver::domainToUnicode(QString::fromLatin1(h));
+ service = QString::fromLatin1(s);
+ success = true;
+ }
+ else
+ {
+ node = service = QString::null;
+ success = false;
+ }
+
+ return success;
+}
+
+bool ReverseThread::postprocess()
+{
+ // post an event
+ if (m_parent)
+ QApplication::postEvent(m_parent,
+ new KReverseResolverEvent(node, service, success));
+ return true;
+}
+
+#include "kreverseresolver.moc"
diff --git a/kdecore/network/kreverseresolver.h b/kdecore/network/kreverseresolver.h
new file mode 100644
index 000000000..325d97d82
--- /dev/null
+++ b/kdecore/network/kreverseresolver.h
@@ -0,0 +1,195 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KREVERSERESOLVER_H
+#define KREVERSERESOLVER_H
+
+//////////////////
+// Needed includes
+#include <qobject.h>
+#include <qstring.h>
+
+#include "ksocketaddress.h"
+
+namespace KNetwork {
+
+class KReverseResolverPrivate;
+/** @class KReverseResolver kreverseresolver.h kreverseresolver.h
+ * @brief Run a reverse-resolution on a socket address.
+ *
+ * This class is provided as a counterpart to KResolver in such a way
+ * as it produces a reverse resolution: it resolves a socket address
+ * from its binary representations into a textual representation.
+ *
+ * Most users will use the static functions @ref resolve, which work
+ * both synchronously (blocking) and asynchronously (non-blocking).
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KReverseResolver: public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Flags for the reverse resolution.
+ *
+ * These flags are used by the reverse resolution functions for
+ * setting resolution parameters. The possible values are:
+ * @li NumericHost: don't try to resolve the host address to a text form.
+ * Instead, convert the address to its numeric textual representation.
+ * @li NumericService: the same as NumericHost, but for the service name
+ * @li NodeNameOnly: returns the node name only (i.e., not the Fully
+ * Qualified Domain Name)
+ * @li Datagram: in case of ambiguity in the service name, prefer the
+ * name associated with the datagram protocol
+ * @li NumericScope: for those addresses which have the concept of scope,
+ * resolve using the numeric value instead of the proper scope name.
+ * @li ResolutionRequired: normally, when resolving, if the name resolution
+ * fails, the process normally converts the numeric address into its
+ * presentation forms. This flag causes the function to return
+ * with error instead.
+ */
+ enum Flags
+ {
+ NumericHost = 0x01,
+ NumericService = 0x02,
+ NodeNameOnly = 0x04,
+ Datagram = 0x08,
+ NumericScope = 0x10,
+ ResolutionRequired = 0x20
+ };
+
+ /**
+ * Constructs this object to resolve the given socket address.
+ *
+ * @param addr the address to resolve
+ * @param flags the flags to use, see @ref Flags
+ */
+ KReverseResolver(const KSocketAddress& addr, int flags = 0,
+ QObject * = 0L, const char * = 0L);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KReverseResolver();
+
+ /**
+ * This function returns 'true' if the processing is still running.
+ */
+ bool isRunning() const;
+
+ /**
+ * This function returns true if the processing has finished with
+ * success, false if it's still running or failed.
+ */
+ bool success() const;
+
+ /**
+ * This function returns true if the processing has finished with
+ * failure, false if it's still running or succeeded.
+ */
+ bool failure() const;
+
+ /**
+ * Returns the resolved node name, if the resolution has finished
+ * successfully, or QString::null otherwise.
+ */
+ QString node() const;
+
+ /**
+ * Returns the resolved service name, if the resolution has finished
+ * successfully, or QString::null otherwise.
+ */
+ QString service() const;
+
+ /**
+ * Returns the socket address which was subject to resolution.
+ */
+ const KSocketAddress& address() const;
+
+ /**
+ * Starts the resolution. This function returns 'true'
+ * if the resolution has started successfully.
+ */
+ bool start();
+
+ /**
+ * Overrides event handling
+ */
+ virtual bool event(QEvent* );
+
+signals:
+ /**
+ * This signal is emitted when the resolution has finished.
+ *
+ * @param obj this class, which contains the results
+ */
+ void finished(const KReverseResolver& obj);
+
+public:
+ /**
+ * Resolves a socket address to its textual representation
+ *
+ * FIXME!! How can we do this in a non-blocking manner!?
+ *
+ * This function is used to resolve a socket address from its
+ * binary representation to a textual form, even if numeric only.
+ *
+ * @param addr the socket address to be resolved
+ * @param node the QString where we will store the resolved node
+ * @param serv the QString where we will store the resolved service
+ * @param flags flags to be used for this resolution.
+ * @return true if the resolution succeeded, false if not
+ * @see ReverseFlags for the possible values for @p flags
+ */
+ static bool resolve(const KSocketAddress& addr, QString& node,
+ QString& serv, int flags = 0);
+
+ /**
+ * Resolves a socket address to its textual representation
+ *
+ * FIXME!! How can we do this in a non-blocking manner!?
+ *
+ * This function behaves just like the above one, except it takes
+ * a sockaddr structure and its size as parameters.
+ *
+ * @param sa the sockaddr structure containing the address to be resolved
+ * @param salen the length of the sockaddr structure
+ * @param node the QString where we will store the resolved node
+ * @param serv the QString where we will store the resolved service
+ * @param flags flags to be used for this resolution.
+ * @return true if the resolution succeeded, false if not
+ * @see ReverseFlags for the possible values for @p flags
+ */
+ static bool resolve(const struct sockaddr* sa, Q_UINT16 salen,
+ QString& node, QString& serv, int flags = 0);
+
+private:
+ KReverseResolverPrivate* d;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/kserversocket.cpp b/kdecore/network/kserversocket.cpp
new file mode 100644
index 000000000..9f32b4119
--- /dev/null
+++ b/kdecore/network/kserversocket.cpp
@@ -0,0 +1,413 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <qsocketnotifier.h>
+#include <qmutex.h>
+
+#include "ksocketaddress.h"
+#include "kresolver.h"
+#include "ksocketbase.h"
+#include "ksocketdevice.h"
+#include "kstreamsocket.h"
+#include "kbufferedsocket.h"
+#include "kserversocket.h"
+
+using namespace KNetwork;
+
+class KNetwork::KServerSocketPrivate
+{
+public:
+ KResolver resolver;
+ KResolverResults resolverResults;
+
+ enum { None, LookupDone, Bound, Listening } state;
+ int backlog;
+ int timeout;
+
+ bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1;
+
+ KServerSocketPrivate()
+ : state(None), timeout(0), bindWhenFound(false), listenWhenBound(false),
+ useKBufferedSocket(true)
+ {
+ resolver.setFlags(KResolver::Passive);
+ resolver.setFamily(KResolver::KnownFamily);
+ }
+};
+
+KServerSocket::KServerSocket(QObject* parent, const char *name)
+ : QObject(parent, name), d(new KServerSocketPrivate)
+{
+ QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)),
+ this, SLOT(lookupFinishedSlot()));
+}
+
+KServerSocket::KServerSocket(const QString& service, QObject* parent, const char *name)
+ : QObject(parent, name), d(new KServerSocketPrivate)
+{
+ QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)),
+ this, SLOT(lookupFinishedSlot()));
+ d->resolver.setServiceName(service);
+}
+
+KServerSocket::KServerSocket(const QString& node, const QString& service,
+ QObject* parent, const char* name)
+ : QObject(parent, name), d(new KServerSocketPrivate)
+{
+ QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)),
+ this, SLOT(lookupFinishedSlot()));
+ setAddress(node, service);
+}
+
+KServerSocket::~KServerSocket()
+{
+ close();
+ delete d;
+}
+
+bool KServerSocket::setSocketOptions(int opts)
+{
+ QMutexLocker locker(mutex());
+ KSocketBase::setSocketOptions(opts); // call parent
+ bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
+ copyError();
+ return result;
+}
+
+KResolver& KServerSocket::resolver() const
+{
+ return d->resolver;
+}
+
+const KResolverResults& KServerSocket::resolverResults() const
+{
+ return d->resolverResults;
+}
+
+void KServerSocket::setResolutionEnabled(bool enable)
+{
+ if (enable)
+ d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve);
+ else
+ d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve);
+}
+
+void KServerSocket::setFamily(int families)
+{
+ d->resolver.setFamily(families);
+}
+
+void KServerSocket::setAddress(const QString& service)
+{
+ d->resolver.setNodeName(QString::null);
+ d->resolver.setServiceName(service);
+ d->resolverResults.empty();
+ if (d->state <= KServerSocketPrivate::LookupDone)
+ d->state = KServerSocketPrivate::None;
+}
+
+void KServerSocket::setAddress(const QString& node, const QString& service)
+{
+ d->resolver.setNodeName(node);
+ d->resolver.setServiceName(service);
+ d->resolverResults.empty();
+ if (d->state <= KServerSocketPrivate::LookupDone)
+ d->state = KServerSocketPrivate::None;
+}
+
+void KServerSocket::setTimeout(int msec)
+{
+ d->timeout = msec;
+}
+
+bool KServerSocket::lookup()
+{
+ setError(NoError);
+ if (d->resolver.isRunning() && !blocking())
+ return true; // already doing lookup
+
+ if (d->state >= KServerSocketPrivate::LookupDone)
+ return true; // results are already available
+
+ // make sure we have at least one parameter for lookup
+ if (d->resolver.serviceName().isNull() &&
+ !d->resolver.nodeName().isNull())
+ d->resolver.setServiceName(QString::fromLatin1(""));
+
+ // don't restart the lookups if they had succeeded and
+ // the input values weren't changed
+
+ // reset results
+ d->resolverResults = KResolverResults();
+
+ if (d->resolver.status() <= 0)
+ // if it's already running, there's no harm in calling again
+ d->resolver.start(); // signal may emit
+
+ if (blocking())
+ {
+ // we're in blocking mode operation
+ // wait for the results
+
+ d->resolver.wait(); // signal may be emitted again
+ // lookupFinishedSlot has been called
+ }
+
+ return true;
+}
+
+bool KServerSocket::bind(const KResolverEntry& address)
+{
+ if (socketDevice()->bind(address))
+ {
+ setError(NoError);
+
+ d->state = KServerSocketPrivate::Bound;
+ emit bound(address);
+ return true;
+ }
+ copyError();
+ return false;
+}
+
+bool KServerSocket::bind(const QString& node, const QString& service)
+{
+ setAddress(node, service);
+ return bind();
+}
+
+bool KServerSocket::bind(const QString& service)
+{
+ setAddress(service);
+ return bind();
+}
+
+bool KServerSocket::bind()
+{
+ if (d->state >= KServerSocketPrivate::Bound)
+ return true;
+
+ if (d->state < KServerSocketPrivate::LookupDone)
+ {
+ if (!blocking())
+ {
+ d->bindWhenFound = true;
+ bool ok = lookup(); // will call doBind
+ if (d->state >= KServerSocketPrivate::Bound)
+ d->bindWhenFound = false;
+ return ok;
+ }
+
+ // not blocking
+ if (!lookup())
+ return false;
+ }
+
+ return doBind();
+}
+
+bool KServerSocket::listen(int backlog)
+{
+ // WARNING
+ // this function has to be reentrant
+ // due to the mechanisms used for binding, this function might
+ // end up calling itself
+
+ if (d->state == KServerSocketPrivate::Listening)
+ return true; // already listening
+
+ d->backlog = backlog;
+
+ if (d->state < KServerSocketPrivate::Bound)
+ {
+ // we must bind
+ // note that we can end up calling ourselves here
+ d->listenWhenBound = true;
+ if (!bind())
+ {
+ d->listenWhenBound = false;
+ return false;
+ }
+
+ if (d->state < KServerSocketPrivate::Bound)
+ // asynchronous lookup in progress...
+ // we can't be blocking here anyways
+ return true;
+
+ d->listenWhenBound = false;
+ }
+
+ if (d->state < KServerSocketPrivate::Listening)
+ return doListen();
+
+ return true;
+}
+
+void KServerSocket::close()
+{
+ socketDevice()->close();
+ if (d->resolver.isRunning())
+ d->resolver.cancel(false);
+ d->state = KServerSocketPrivate::None;
+ emit closed();
+}
+
+void KServerSocket::setAcceptBuffered(bool enable)
+{
+ d->useKBufferedSocket = enable;
+}
+
+KActiveSocketBase* KServerSocket::accept()
+{
+ if (d->state < KServerSocketPrivate::Listening)
+ {
+ if (!blocking())
+ {
+ listen();
+ setError(WouldBlock);
+ return NULL;
+ }
+ else if (!listen())
+ // error happened during listen
+ return false;
+ }
+
+ // check to see if we're doing a timeout
+ if (blocking() && d->timeout > 0)
+ {
+ bool timedout;
+ if (!socketDevice()->poll(d->timeout, &timedout))
+ {
+ copyError();
+ return NULL;
+ }
+
+ if (timedout)
+ return 0L;
+ }
+
+ // we're listening here
+ KSocketDevice* accepted = socketDevice()->accept();
+ if (!accepted)
+ {
+ // error happened during accept
+ copyError();
+ return NULL;
+ }
+
+ KStreamSocket* streamsocket;
+ if (d->useKBufferedSocket)
+ streamsocket = new KBufferedSocket();
+ else
+ streamsocket = new KStreamSocket();
+ streamsocket->setSocketDevice(accepted);
+
+ // FIXME!
+ // when KStreamSocket can find out the state of the socket passed through
+ // setSocketDevice, this will probably be unnecessary:
+ streamsocket->setState(KStreamSocket::Connected);
+ streamsocket->setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+
+ return streamsocket;
+}
+
+KSocketAddress KServerSocket::localAddress() const
+{
+ return socketDevice()->localAddress();
+}
+
+KSocketAddress KServerSocket::externalAddress() const
+{
+ return socketDevice()->externalAddress();
+}
+
+void KServerSocket::lookupFinishedSlot()
+{
+ if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone)
+ return;
+
+ if (d->resolver.status() < 0)
+ {
+ setError(LookupFailure);
+ emit gotError(LookupFailure);
+ d->bindWhenFound = d->listenWhenBound = false;
+ d->state = KServerSocketPrivate::None;
+ return;
+ }
+
+ // lookup succeeded
+ d->resolverResults = d->resolver.results();
+ d->state = KServerSocketPrivate::LookupDone;
+ emit hostFound();
+
+ if (d->bindWhenFound)
+ doBind();
+}
+
+void KServerSocket::copyError()
+{
+ setError(socketDevice()->error());
+}
+
+bool KServerSocket::doBind()
+{
+ d->bindWhenFound = false;
+ // loop through the results and bind to the first that works
+
+ KResolverResults::ConstIterator it = d->resolverResults.begin();
+ for ( ; it != d->resolverResults.end(); ++it)
+ if (bind(*it))
+ {
+ if (d->listenWhenBound)
+ return doListen();
+ return true;
+ }
+ else
+ socketDevice()->close(); // didn't work, try again
+
+ // failed to bind
+ emit gotError(error());
+ return false;
+}
+
+bool KServerSocket::doListen()
+{
+ if (!socketDevice()->listen(d->backlog))
+ {
+ copyError();
+ emit gotError(error());
+ return false; // failed to listen
+ }
+
+ // set up ready accept signal
+ QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)),
+ this, SIGNAL(readyAccept()));
+ d->state = KServerSocketPrivate::Listening;
+ return true;
+}
+
+
+#include "kserversocket.moc"
diff --git a/kdecore/network/kserversocket.h b/kdecore/network/kserversocket.h
new file mode 100644
index 000000000..27b3df1cc
--- /dev/null
+++ b/kdecore/network/kserversocket.h
@@ -0,0 +1,435 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago@kde.org>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KSERVERSOCKET_H
+#define KSERVERSOCKET_H
+
+#include <qobject.h>
+#include "ksocketbase.h"
+
+namespace KNetwork {
+
+class KSocketDevice;
+class KStreamSocket;
+class KResolver;
+class KResolverResults;
+
+class KServerSocketPrivate;
+/**
+ * @class KServerSocket kserversocket.h kserversocket.h
+ * @brief A server socket for accepting connections.
+ *
+ * This class provides functionality for creating a socket to
+ * listen for incoming connections and subsequently accept them.
+ *
+ * To use this class, you must first set the parameters for the listening
+ * socket's address, then place it in listening mode.
+ *
+ * A typical example would look like:
+ * \code
+ * QString service = "http";
+ * KServerSocket *ss = new KServerSocket(service);
+ * connect(ss, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept()));
+ * connect(ss, SIGNAL(gotError(int)), this, SLOT(slotSocketError(int)));
+ * ss->listen();
+ * \endcode
+ *
+ * In this case, this class will place the socket into listening mode on the
+ * service pointed to by @p service and will emit the @ref readyAccept signal
+ * when a connection is ready for accepting. The called slot is responsible for
+ * calling @ref accept.
+ *
+ * The location of the services file (where @p service is looked up)
+ * is defined by _PATH_SERVICES in /usr/include/netdb.h. This is
+ * usually set to /etc/services.
+ * See RFC 1700 for more information on services.
+ * You can specify @p service as a port number directly, rather than as a service
+ * name. This is discouraged as it prevents the end user from easily modifying
+ * the port number.
+ *
+ * For another example of usage, this below code attempts to make a connection on any port within a range:
+ * \code
+ * KServerSocket *ss = new KServerSocket();
+ * ss->setFamily(KResolver::InetFamily);
+ * bool found = false;
+ * for( unsigned int port = firstport; port <= lastport; ++port) {
+ * ss->setAddress( QString::number( port ) );
+ * bool success = ss->listen();
+ * if( found = ( success && ss->error() ==
+ * KSocketBase::NoError ) )
+ * break;
+ * ss->close();
+ * }
+ * if( !found ) {
+ * // Couldn't connect to any port.
+ * } else {
+ * connect(ss, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept()));
+ * connect(ss, SIGNAL(gotError(int)), this, SLOT(slotSocketError(int)));
+ * ss->listen();
+ * }
+ * \endcode
+ *
+ * The called slot slotReadyAccept() is responsible for calling
+ * @ref accept.
+ *
+ * It is important to note that @ref accept can return either an
+ * object of type KNetwork::KStreamSocket or
+ * KNetwork::KBufferedSocket (default). If you want to accept a
+ * non-buffered socket, you must first call setAcceptBuffered.
+ *
+ * @warning If you use KServerSocket in an auxiliary (non-GUI) thread,
+ * you need to accept only KNetwork::KStreamSocket objects.
+ *
+ * @see KNetwork::KStreamSocket, KNetwork::KBufferedSocket
+ * @author Thiago Macieira <thiago@kde.org>
+ */
+class KDECORE_EXPORT KServerSocket: public QObject, public KPassiveSocketBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor.
+ *
+ * If the binding address isn't changed by setAddress, this socket will
+ * bind to all interfaces on this node and the port will be selected by the
+ * operating system.
+ *
+ * @param parent the parent QObject object
+ * @param name the name of this object
+ */
+ KServerSocket(QObject* parent = 0L, const char *name = 0L);
+
+ /**
+ * Construct this object specifying the service to listen on.
+ *
+ * If the binding address isn't changed by setAddress, this socket will
+ * bind to all interfaces and will listen on the port specified by
+ * @p service. This is either a service name (e.g. 'www') or a port
+ * number (e.g. '80').
+ *
+ * The location of the services file (where @p service is looked up)
+ * is defined by _PATH_SERVICES in /usr/include/netdb.h. This is
+ * usually set to /etc/services.
+ * See RFC 1700 for more information on services.
+ *
+ * @param service the service name to listen on
+ * @param parent the parent QObject object
+ * @param name the name of this object
+ */
+ KServerSocket(const QString& service, QObject* parent = 0L, const char *name = 0L);
+
+ /**
+ * Construct this object specifying the node and service names to listen on.
+ *
+ * If the binding address isn't changed by setAddress, this socket will
+ * bind to the interface specified by @p node and the port specified by
+ * @p service. This is either a service name (e.g. 'www') or a port
+ * number (e.g. '80').
+ *
+ * The location of the services file (where @p service is looked up)
+ * is defined by _PATH_SERVICES in /usr/include/netdb.h. This is
+ * usually set to /etc/services.
+ * See RFC 1700 for more information on services.
+ *
+ * @param node the node to bind to
+ * @param service the service port to listen on
+ * @param parent the parent QObject object
+ * @param name the name of this object
+ */
+ KServerSocket(const QString& node, const QString& service,
+ QObject* parent = 0L, const char *name = 0L);
+
+ /**
+ * Destructor. This will close the socket, if open.
+ *
+ * Note, however, that accepted sockets do not get closed when this
+ * object closes.
+ */
+ ~KServerSocket();
+
+protected:
+ /**
+ * Sets the socket options. Reimplemented from KSocketBase.
+ */
+ virtual bool setSocketOptions(int opts);
+
+public:
+ /**
+ * Returns the internal KResolver object used for
+ * looking up the host name and service.
+ *
+ * This can be used to set extra options to the
+ * lookup process other than the default values, as well
+ * as obtaining the error codes in case of lookup failure.
+ */
+ KResolver& resolver() const;
+
+ /**
+ * Returns the internal list of resolved results for the binding address.
+ */
+ const KResolverResults& resolverResults() const;
+
+ /**
+ * Enables or disables name resolution. If this flag is set to true,
+ * the @ref bind operation will trigger name lookup
+ * operations (i.e., converting a hostname into its binary form).
+ * If the flag is set to false, those operations will instead
+ * try to convert a string representation of an address without
+ * attempting name resolution.
+ *
+ * This is useful, for instance, when IP addresses are in
+ * their string representation (such as "1.2.3.4") or come
+ * from other sources like @ref KSocketAddress.
+ *
+ * @param enable whether to enable
+ */
+ void setResolutionEnabled(bool enable);
+
+ /**
+ * Sets the allowed families for the resolutions.
+ *
+ * @param families the families that we want/accept
+ * @see KResolver::SocketFamilies for possible values
+ */
+ void setFamily(int families);
+
+ /**
+ * Sets the address on which we will listen. The port to listen on is given by
+ * @p service, and we will bind to all interfaces. To let the operating system choose a
+ * port, set the service to "0". @p service can either be a service name
+ * (e.g. 'www') or a port number (e.g. '80').
+ *
+ * The location of the services file (where @p service is looked up)
+ * is defined by _PATH_SERVICES in /usr/include/netdb.h. This is
+ * usually set to /etc/services.
+ * See RFC 1700 for more information on services.
+ *
+ * @param service the service name to listen on
+ */
+ void setAddress(const QString& service);
+
+ /**
+ * @overload
+ * Sets the address on which we will listen. This will cause the socket to listen
+ * only on the interface given by @p node and on the port given by @p service.
+ * @p service can either be a service name (e.g. 'www') or a port number
+ * (e.g. '80').
+ *
+ * The location of the services file (where @p service is looked up)
+ * is defined by _PATH_SERVICES in /usr/include/netdb.h. This is
+ * usually set to /etc/services.
+ * See RFC 1700 for more information on services.
+ *
+ * @param node the node to bind to
+ * @param service the service port to listen on
+ */
+ void setAddress(const QString& node, const QString& service);
+
+ /**
+ * Sets the timeout for accepting. When you call @ref accept,
+ * it will wait at most @p msecs milliseconds or return with an error
+ * (returning a NULL object).
+ *
+ * @param msecs the time in milliseconds to wait, 0 to wait forever
+ */
+ void setTimeout(int msecs);
+
+ /**
+ * Starts the lookup for peer and local hostnames as
+ * well as their services.
+ *
+ * If the blocking mode for this object is on, this function will
+ * wait for the lookup results to be available (by calling the
+ * @ref KResolver::wait method on the resolver objects).
+ *
+ * When the lookup is done, the signal @ref hostFound will be
+ * emitted (only once, even if we're doing a double lookup).
+ * If the lookup failed (for any of the two lookups) the
+ * @ref gotError signal will be emitted with the appropriate
+ * error condition (see @ref KSocketBase::SocketError).
+ *
+ * This function returns true on success and false on error. Note that
+ * this is not the lookup result!
+ */
+ virtual bool lookup();
+
+ /**
+ * Binds this socket to the given nodename and service,
+ * or use the default ones if none are given.
+ *
+ * Upon successful binding, the @ref bound signal will be
+ * emitted. If an error is found, the @ref gotError
+ * signal will be emitted.
+ *
+ * This function returns true on success.
+ *
+ * @param node the nodename
+ * @param service the service
+ */
+ virtual bool bind(const QString& node, const QString& service);
+
+ /**
+ * Binds the socket to the given service name.
+ * @overload
+ *
+ * @param service the service
+ */
+ virtual bool bind(const QString& service);
+
+ /**
+ * Binds the socket to the addresses previously set with @ref setAddress.
+ * @overload
+ *
+ */
+ virtual bool bind();
+
+ /**
+ * Connect this socket to this specific address. Reimplemented from KSocketBase.
+ *
+ * Unlike @ref bind(const QString&, const QString&) above, this function
+ * really does bind the socket. No lookup is performed. The @ref bound signal
+ * will be emitted.
+ */
+ virtual bool bind(const KResolverEntry& address);
+
+ /**
+ * Puts this socket into listening mode. Reimplemented from @ref KPassiveSocketBase.
+ *
+ * Placing a socket into listening mode means it will be able to receive incoming
+ * connections through the @ref accept method.
+ *
+ * If you do not call this method but call @ref accept directly, the socket will
+ * be placed into listening mode automatically.
+ *
+ * @param backlog the number of connection the system is to
+ * queue without @ref accept being called
+ * @returns true if the socket is now in listening mode.
+ */
+ virtual bool listen(int backlog = 5); // 5 is arbitrary
+
+ /**
+ * Closes this socket.
+ */
+ virtual void close();
+
+ /**
+ * Toggles whether the accepted socket will be buffered or not.
+ * That is, the @ref accept function will always return a KStreamSocket
+ * object or descended from it. If buffering is enabled, the class
+ * to be returned will be KBufferedSocket.
+ *
+ * By default, this flag is set to true.
+ *
+ * @param enable whether to set the accepted socket to
+ * buffered mode
+ */
+ void setAcceptBuffered(bool enable);
+
+ /**
+ * Accepts one incoming connection and return the associated, open
+ * socket.
+ *
+ * If this function cannot accept a new connection, it will return NULL.
+ * The specific object class returned by this function may vary according
+ * to the implementation: derived classes may return specialised objects
+ * descended from KStreamSocket.
+ *
+ * @note This function should return a KStreamSocket object, but compiler
+ * deficiencies prevent such an adjustment. Therefore, we return
+ * the base class for active sockets, but it is guaranteed
+ * that the object will be a KStreamSocket or derived from it.
+ *
+ * @sa KBufferedSocket
+ * @sa setAcceptBuffered
+ */
+ virtual KActiveSocketBase* accept();
+
+ /**
+ * Returns this socket's local address.
+ */
+ virtual KSocketAddress localAddress() const;
+
+ /**
+ * Returns this socket's externally-visible address if know.
+ */
+ virtual KSocketAddress externalAddress() const;
+
+private slots:
+ void lookupFinishedSlot();
+
+signals:
+ /**
+ * This signal is emitted when this object finds an error.
+ * The @p code parameter contains the error code that can
+ * also be found by calling @ref error.
+ */
+ void gotError(int code);
+
+ /**
+ * This signal is emitted when the lookup is successfully completed.
+ */
+ void hostFound();
+
+ /**
+ * This signal is emitted when the socket successfully binds
+ * to an address.
+ *
+ * @param local the local address we bound to
+ */
+ void bound(const KResolverEntry& local);
+
+ /**
+ * This signal is emitted when the socket completes the
+ * closing/shut down process.
+ */
+ void closed();
+
+ /**
+ * This signal is emitted whenever the socket is ready for
+ * accepting -- i.e., there is at least one connection waiting to
+ * be accepted.
+ */
+ void readyAccept();
+
+protected:
+ /**
+ * Convenience function to set this object's error code to match
+ * that of the socket device.
+ */
+ void copyError();
+
+private:
+ bool doBind();
+ bool doListen();
+
+private:
+ KServerSocket(const KServerSocket&);
+ KServerSocket& operator=(const KServerSocket&);
+
+ KServerSocketPrivate *d;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/ksocketaddress.cpp b/kdecore/network/ksocketaddress.cpp
new file mode 100644
index 000000000..6c1316e94
--- /dev/null
+++ b/kdecore/network/ksocketaddress.cpp
@@ -0,0 +1,957 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qobject.h>
+
+#include "klocale.h"
+#include "ksocketaddress.h"
+
+#include "netsupp.h"
+
+using namespace KNetwork;
+
+#if 0
+class KIpAddress_localhostV4 : public KIpAddress
+{
+public:
+ KIpAddress_localhostV4()
+ {
+ *m_data = htonl(0x7f000001);
+ m_version = 4;
+ }
+};
+
+class KIpAddress_localhostV6 : public KIpAddress
+{
+public:
+ KIpAddress_localhostV6()
+ : KIpAddress(0L, 6)
+ {
+ m_data[3] = htonl(1);
+ }
+};
+#endif
+
+static const char localhostV4_data[] = { 127, 0, 0, 1 };
+static const char localhostV6_data[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1 };
+
+const KIpAddress KIpAddress::localhostV4(&localhostV4_data, 4);
+const KIpAddress KIpAddress::localhostV6(&localhostV6_data, 6);
+const KIpAddress KIpAddress::anyhostV4(0L, 4);
+const KIpAddress KIpAddress::anyhostV6(0L, 6);
+
+// helper function to test if an IPv6 v4-mapped address is equal to its IPv4 counterpart
+static bool check_v4mapped(const Q_UINT32* v6addr, Q_UINT32 v4addr)
+{
+ // check that the v6 is a v4-mapped address
+ if (!(v6addr[0] == 0 && v6addr[1] == 0 && v6addr[2] == htonl(0x0000ffff)))
+ return false; // not a v4-mapped address
+
+ return v6addr[3] == v4addr;
+}
+
+// copy operator
+KIpAddress& KIpAddress::operator =(const KIpAddress& other)
+{
+ m_version = other.m_version;
+ if (m_version == 4 || m_version == 6)
+ memcpy(m_data, other.m_data, sizeof(m_data));
+ return *this;
+}
+
+// comparison
+bool KIpAddress::compare(const KIpAddress& other, bool checkMapped) const
+{
+ if (m_version == other.m_version)
+ switch (m_version)
+ {
+ case 0:
+ // both objects are empty
+ return true;
+
+ case 4:
+ // IPv4 address
+ return *m_data == *other.m_data;
+
+ case 6:
+ // IPv6 address
+ // they are 128-bit long, that is, 16 bytes
+ return memcmp(m_data, other.m_data, 16) == 0;
+ }
+
+ if (checkMapped)
+ {
+ // check the possibility of a v4-mapped address being compared to an IPv4 one
+ if (m_version == 6 && other.m_version == 4 && check_v4mapped(m_data, *other.m_data))
+ return true;
+
+ if (other.m_version == 6 && m_version == 4 && check_v4mapped(other.m_data, *m_data))
+ return true;
+ }
+
+ return false;
+}
+
+// sets the address to the given address
+bool KIpAddress::setAddress(const QString& address)
+{
+ m_version = 0;
+
+ // try to guess the address version
+ if (address.find(':') != -1)
+ {
+#ifdef AF_INET6
+ // guessing IPv6
+
+ Q_UINT32 buf[4];
+ if (inet_pton(AF_INET6, address.latin1(), buf))
+ {
+ memcpy(m_data, buf, sizeof(m_data));
+ m_version = 6;
+ return true;
+ }
+#endif
+
+ return false;
+ }
+ else
+ {
+ Q_UINT32 buf;
+ if (inet_pton(AF_INET, address.latin1(), &buf))
+ {
+ *m_data = buf;
+ m_version = 4;
+ return true;
+ }
+
+ return false;
+ }
+
+ return false; // can never happen!
+}
+
+bool KIpAddress::setAddress(const char* address)
+{
+ return setAddress(QString::fromLatin1(address));
+}
+
+// set from binary data
+bool KIpAddress::setAddress(const void* raw, int version)
+{
+ // this always succeeds
+ // except if version is invalid
+ if (version != 4 && version != 6)
+ return false;
+
+ m_version = version;
+ if (raw != 0L)
+ memcpy(m_data, raw, version == 4 ? 4 : 16);
+ else
+ memset(m_data, 0, 16);
+
+ return true;
+}
+
+// presentation form
+QString KIpAddress::toString() const
+{
+ char buf[sizeof "1111:2222:3333:4444:5555:6666:255.255.255.255" + 2];
+ buf[0] = '\0';
+ switch (m_version)
+ {
+ case 4:
+ inet_ntop(AF_INET, m_data, buf, sizeof(buf) - 1);
+ return QString::fromLatin1(buf);
+
+ case 6:
+#ifdef AF_INET6
+ inet_ntop(AF_INET6, m_data, buf, sizeof(buf) - 1);
+#endif
+ return QString::fromLatin1(buf);
+ }
+
+ return QString::null;
+}
+
+Q_UINT32 KIpAddress::hostIPv4Addr(bool convertMapped) const
+{
+ Q_UINT32 addr = IPv4Addr(convertMapped);
+ return ntohl(addr);
+}
+
+/*
+ * An IPv6 socket address
+ * This is taken from RFC 2553.
+ */
+struct our_sockaddr_in6
+{
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ Q_UINT8 sin6_len;
+ Q_UINT8 sin6_family;
+# else //!HAVE_STRUCT_SOCKADDR_SA_LEN
+ Q_UINT16 sin6_family;
+# endif
+ Q_UINT16 sin6_port; /* RFC says in_port_t */
+ Q_UINT32 sin6_flowinfo;
+ Q_UINT8 sin6_addr[16]; // 24 bytes up to here
+ Q_UINT32 sin6_scope_id; // 28 bytes total
+};
+
+// useful definitions
+#define MIN_SOCKADDR_LEN sizeof(Q_UINT16)
+#define SOCKADDR_IN_LEN sizeof(sockaddr_in)
+#define MIN_SOCKADDR_IN6_LEN ((unsigned long) &(((our_sockaddr_in6*)0)->sin6_scope_id))
+#define SOCKADDR_IN6_LEN sizeof(our_sockaddr_in6)
+#define MIN_SOCKADDR_UN_LEN (sizeof(Q_UINT16) + sizeof(char))
+
+
+class KNetwork::KSocketAddressData
+{
+public:
+ /*
+ * Note: maybe this should be virtual
+ * But since the data is shared via the d pointer, it doesn't really matter
+ * what one class sees, so will the other
+ */
+ class QMixSocketAddressRef : public KInetSocketAddress, public KUnixSocketAddress
+ {
+ public:
+ QMixSocketAddressRef(KSocketAddressData* d)
+ : KInetSocketAddress(d), KUnixSocketAddress(d)
+ {
+ }
+ };
+ QMixSocketAddressRef ref;
+
+ union
+ {
+ struct sockaddr *generic;
+ struct sockaddr_in *in;
+ struct our_sockaddr_in6 *in6;
+ struct sockaddr_un *un;
+ } addr;
+ Q_UINT16 curlen, reallen;
+
+ KSocketAddressData()
+ : ref(this)
+ {
+ addr.generic = 0L;
+ curlen = 0;
+ invalidate();
+ }
+
+ ~KSocketAddressData()
+ {
+ if (addr.generic != 0L)
+ free(addr.generic);
+ }
+
+ inline bool invalid() const
+ { return reallen == 0; }
+
+ inline void invalidate()
+ { reallen = 0; }
+
+ void dup(const sockaddr* sa, Q_UINT16 len, bool clear = true);
+
+ void makeipv4()
+ {
+ short oldport = 0;
+ if (!invalid())
+ switch (addr.generic->sa_family)
+ {
+ case AF_INET:
+ return; // nothing to do here
+#ifdef AF_INET6
+ case AF_INET6:
+ oldport = addr.in6->sin6_port;
+ break;
+#endif
+ }
+
+ // create new space
+ dup(0L, SOCKADDR_IN_LEN);
+
+ addr.in->sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ addr.in->sin_len = SOCKADDR_IN_LEN;
+#endif
+ addr.in->sin_port = oldport;
+ }
+
+ void makeipv6()
+ {
+ short oldport = 0;
+ if (!invalid())
+ switch (addr.generic->sa_family)
+ {
+ case AF_INET:
+ oldport = addr.in->sin_port;
+ break;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ return; // nothing to do here
+#endif
+ }
+
+ // make room
+ dup(0L, SOCKADDR_IN6_LEN);
+#ifdef AF_INET6
+ addr.in6->sin6_family = AF_INET6;
+#endif
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ addr.in6->sin6_len = SOCKADDR_IN6_LEN;
+#endif
+ addr.in6->sin6_port = oldport;
+ // sin6_scope_id and sin6_flowid are zero
+ }
+
+};
+
+// create duplicates of
+void KSocketAddressData::dup(const sockaddr* sa, Q_UINT16 len, bool clear)
+{
+ if (len < MIN_SOCKADDR_LEN)
+ {
+ // certainly invalid
+ invalidate();
+ return;
+ }
+
+ if (sa && ((sa->sa_family == AF_INET && len < SOCKADDR_IN_LEN) ||
+#ifdef AF_INET6
+ (sa->sa_family == AF_INET6 && len < MIN_SOCKADDR_IN6_LEN) ||
+#endif
+ (sa->sa_family == AF_UNIX && len < MIN_SOCKADDR_UN_LEN)))
+ {
+ // also invalid
+ invalidate();
+ return;
+ }
+
+ // good
+ reallen = len;
+ if (len > curlen)
+ {
+ if (len < 32)
+ curlen = 32; // big enough for sockaddr_in and sockaddr_in6
+ else
+ curlen = len;
+ addr.generic = (sockaddr*)realloc(addr.generic, curlen);
+ }
+
+ if (sa != 0L)
+ {
+ memcpy(addr.generic, sa, len); // copy
+
+ // now, normalise the data
+ if (addr.generic->sa_family == AF_INET)
+ reallen = SOCKADDR_IN_LEN; // no need to be larger
+#ifdef AF_INET6
+ else if (addr.generic->sa_family == AF_INET6)
+ {
+ // set the extra field (sin6_scope_id)
+
+ // the buffer is never smaller than 32 bytes, so this is always
+ // allowed
+ if (reallen < SOCKADDR_IN6_LEN)
+ addr.in6->sin6_scope_id = 0;
+
+ reallen = SOCKADDR_IN6_LEN;
+ }
+#endif
+ else if (addr.generic->sa_family == AF_UNIX)
+ reallen = MIN_SOCKADDR_UN_LEN + strlen(addr.un->sun_path);
+ }
+ else if (clear)
+ {
+ memset(addr.generic, 0, len);
+ addr.generic->sa_family = AF_UNSPEC;
+ }
+}
+
+// default constructor
+KSocketAddress::KSocketAddress()
+ : d(new KSocketAddressData)
+{
+}
+
+// constructor from binary data
+KSocketAddress::KSocketAddress(const sockaddr *sa, Q_UINT16 len)
+ : d(new KSocketAddressData)
+{
+ setAddress(sa, len);
+}
+
+KSocketAddress::KSocketAddress(const KSocketAddress& other)
+ : d(new(KSocketAddressData))
+{
+ *this = other;
+}
+
+KSocketAddress::KSocketAddress(KSocketAddressData *d2)
+ : d(d2)
+{
+}
+
+KSocketAddress::~KSocketAddress()
+{
+ // prevent double-deletion, since we're already being deleted
+ if (d)
+ {
+ d->ref.KInetSocketAddress::d = 0L;
+ d->ref.KUnixSocketAddress::d = 0L;
+ delete d;
+ }
+}
+
+KSocketAddress& KSocketAddress::operator =(const KSocketAddress& other)
+{
+ if (other.d && !other.d->invalid())
+ d->dup(other.d->addr.generic, other.d->reallen);
+ else
+ d->invalidate();
+ return *this;
+}
+
+const sockaddr* KSocketAddress::address() const
+{
+ if (d->invalid())
+ return 0L;
+ return d->addr.generic;
+}
+
+sockaddr* KSocketAddress::address()
+{
+ if (d->invalid())
+ return 0L;
+ return d->addr.generic;
+}
+
+KSocketAddress& KSocketAddress::setAddress(const sockaddr* sa, Q_UINT16 len)
+{
+ if (sa != 0L && len >= MIN_SOCKADDR_LEN)
+ d->dup(sa, len);
+ else
+ d->invalidate();
+
+ return *this;
+}
+
+Q_UINT16 KSocketAddress::length() const
+{
+ if (d->invalid())
+ return 0;
+ return d->reallen;
+}
+
+KSocketAddress& KSocketAddress::setLength(Q_UINT16 len)
+{
+ d->dup((sockaddr*)0L, len, false);
+
+ return *this;
+}
+
+int KSocketAddress::family() const
+{
+ if (d->invalid())
+ return AF_UNSPEC;
+ return d->addr.generic->sa_family;
+}
+
+KSocketAddress& KSocketAddress::setFamily(int family)
+{
+ if (d->invalid())
+ d->dup((sockaddr*)0L, MIN_SOCKADDR_LEN);
+ d->addr.generic->sa_family = family;
+
+ return *this;
+}
+
+bool KSocketAddress::operator ==(const KSocketAddress& other) const
+{
+ // if this is invalid, it's only equal if the other one is invalid as well
+ if (d->invalid())
+ return other.d->invalid();
+
+ // check the family to make sure we don't do unnecessary comparison
+ if (d->addr.generic->sa_family != other.d->addr.generic->sa_family)
+ return false; // not the same family, not equal
+
+ // same family then
+ // check the ones we know already
+ switch (d->addr.generic->sa_family)
+ {
+ case AF_INET:
+ Q_ASSERT(d->reallen == SOCKADDR_IN_LEN);
+ Q_ASSERT(other.d->reallen == SOCKADDR_IN_LEN);
+ return memcmp(d->addr.in, other.d->addr.in, SOCKADDR_IN_LEN) == 0;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ Q_ASSERT(d->reallen >= MIN_SOCKADDR_IN6_LEN);
+ Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_IN6_LEN);
+
+# if !defined(HAVE_STRUCT_SOCKADDR_IN6) || defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ // check for the case where sin6_scope_id isn't present
+ if (d->reallen != other.d->reallen)
+ {
+ if (memcmp(d->addr.in6, other.d->addr.in6, MIN_SOCKADDR_IN6_LEN) != 0)
+ return false; // not equal
+ if (d->reallen > other.d->reallen)
+ return d->addr.in6->sin6_scope_id == 0;
+ else
+ return other.d->addr.in6->sin6_scope_id == 0;
+ }
+# endif
+
+ return memcmp(d->addr.in6, other.d->addr.in6, d->reallen) == 0;
+#endif
+
+ case AF_UNIX:
+ Q_ASSERT(d->reallen >= MIN_SOCKADDR_UN_LEN);
+ Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_UN_LEN);
+
+ // do a string comparison here
+ return strcmp(d->addr.un->sun_path, other.d->addr.un->sun_path) == 0;
+
+ default:
+ // something else we don't know about
+ // they are equal if and only if they are exactly equal
+ if (d->reallen == other.d->reallen)
+ return memcmp(d->addr.generic, other.d->addr.generic, d->reallen) == 0;
+ }
+
+ return false; // not equal in any other case
+}
+
+QString KSocketAddress::nodeName() const
+{
+ if (d->invalid())
+ return QString::null;
+
+ switch (d->addr.generic->sa_family)
+ {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+
+ QString scopeid("%");
+ if (d->addr.generic->sa_family == AF_INET6 && d->addr.in6->sin6_scope_id)
+ scopeid += QString::number(d->addr.in6->sin6_scope_id);
+ else
+ scopeid.truncate(0);
+ return d->ref.ipAddress().toString() + scopeid;
+#else
+ return d->ref.ipAddress().toString();
+#endif
+ }
+
+ // any other case, including AF_UNIX
+ return QString::null;
+}
+
+QString KSocketAddress::serviceName() const
+{
+ if (d->invalid())
+ return QString::null;
+
+ switch (d->addr.generic->sa_family)
+ {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ return QString::number(d->ref.port());
+
+ case AF_UNIX:
+ return d->ref.pathname();
+ }
+
+ return QString::null;
+}
+
+QString KSocketAddress::toString() const
+{
+ if (d->invalid())
+ return QString::null;
+
+ QString fmt;
+
+ if (d->addr.generic->sa_family == AF_INET)
+ fmt = "%1:%2";
+#ifdef AF_INET6
+ else if (d->addr.generic->sa_family == AF_INET6)
+ fmt = "[%1]:%2";
+#endif
+ else if (d->addr.generic->sa_family == AF_UNIX)
+ return QString::fromLatin1("unix:%1").arg(serviceName());
+ else
+ return i18n("1: the unknown socket address family number",
+ "Unknown family %1").arg(d->addr.generic->sa_family);
+
+ return fmt.arg(nodeName()).arg(serviceName());
+}
+
+KInetSocketAddress& KSocketAddress::asInet()
+{
+ return d->ref;
+}
+
+KInetSocketAddress KSocketAddress::asInet() const
+{
+ return d->ref;
+}
+
+KUnixSocketAddress& KSocketAddress::asUnix()
+{
+ return d->ref;
+}
+
+KUnixSocketAddress KSocketAddress::asUnix() const
+{
+ return d->ref;
+}
+
+int KSocketAddress::ianaFamily(int af)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return 1;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ return 2;
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+int KSocketAddress::fromIanaFamily(int iana)
+{
+ switch (iana)
+ {
+ case 1:
+ return AF_INET;
+
+#ifdef AF_INET6
+ case 2:
+ return AF_INET6;
+#endif
+
+ default:
+ return AF_UNSPEC;
+ }
+}
+
+// default constructor
+KInetSocketAddress::KInetSocketAddress()
+{
+}
+
+// binary data constructor
+KInetSocketAddress::KInetSocketAddress(const sockaddr* sa, Q_UINT16 len)
+ : KSocketAddress(sa, len)
+{
+ if (!d->invalid())
+ update();
+}
+
+// create from IP and port
+KInetSocketAddress::KInetSocketAddress(const KIpAddress& host, Q_UINT16 port)
+{
+ setHost(host);
+ setPort(port);
+}
+
+// copy constructor
+KInetSocketAddress::KInetSocketAddress(const KInetSocketAddress& other)
+ : KSocketAddress(other)
+{
+}
+
+// special copy constructor
+KInetSocketAddress::KInetSocketAddress(const KSocketAddress& other)
+ : KSocketAddress(other)
+{
+ if (!d->invalid())
+ update();
+}
+
+// special constructor
+KInetSocketAddress::KInetSocketAddress(KSocketAddressData *d)
+ : KSocketAddress(d)
+{
+}
+
+// destructor
+KInetSocketAddress::~KInetSocketAddress()
+{
+ /* nothing to do */
+}
+
+// copy operator
+KInetSocketAddress& KInetSocketAddress::operator =(const KInetSocketAddress& other)
+{
+ KSocketAddress::operator =(other);
+ return *this;
+}
+
+// IP version
+int KInetSocketAddress::ipVersion() const
+{
+ if (d->invalid())
+ return 0;
+
+ switch (d->addr.generic->sa_family)
+ {
+ case AF_INET:
+ return 4;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ return 6;
+#endif
+ }
+
+ return 0; // for all other cases
+}
+
+KIpAddress KInetSocketAddress::ipAddress() const
+{
+ if (d->invalid())
+ return KIpAddress(); // return an empty address as well
+
+ switch (d->addr.generic->sa_family)
+ {
+ case AF_INET:
+ return KIpAddress(&d->addr.in->sin_addr, 4);
+#ifdef AF_INET6
+ case AF_INET6:
+ return KIpAddress(&d->addr.in6->sin6_addr, 6);
+#endif
+ }
+
+ return KIpAddress(); // empty in all other cases
+}
+
+KInetSocketAddress& KInetSocketAddress::setHost(const KIpAddress& ip)
+{
+ switch (ip.version())
+ {
+ case 4:
+ makeIPv4();
+ memcpy(&d->addr.in->sin_addr, ip.addr(), sizeof(d->addr.in->sin_addr));
+ break;
+
+ case 6:
+ makeIPv6();
+ memcpy(&d->addr.in6->sin6_addr, ip.addr(), sizeof(d->addr.in6->sin6_addr));
+ break;
+
+ default:
+ // empty
+ d->invalidate();
+ }
+
+ return *this;
+}
+
+// returns the port
+Q_UINT16 KInetSocketAddress::port() const
+{
+ if (d->invalid())
+ return 0;
+
+ switch (d->addr.generic->sa_family)
+ {
+ case AF_INET:
+ return ntohs(d->addr.in->sin_port);
+
+#ifdef AF_INET6
+ case AF_INET6:
+ return ntohs(d->addr.in6->sin6_port);
+#endif
+ }
+
+ return 0;
+}
+
+KInetSocketAddress& KInetSocketAddress::setPort(Q_UINT16 port)
+{
+ if (d->invalid())
+ makeIPv4();
+
+ switch (d->addr.generic->sa_family)
+ {
+ case AF_INET:
+ d->addr.in->sin_port = htons(port);
+ break;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ d->addr.in6->sin6_port = htons(port);
+ break;
+#endif
+
+ default:
+ d->invalidate(); // setting the port on something else
+ }
+
+ return *this;
+}
+
+KInetSocketAddress& KInetSocketAddress::makeIPv4()
+{
+ d->makeipv4();
+ return *this;
+}
+
+KInetSocketAddress& KInetSocketAddress::makeIPv6()
+{
+ d->makeipv6();
+ return *this;
+}
+
+Q_UINT32 KInetSocketAddress::flowinfo() const
+{
+#ifndef AF_INET6
+ return 0;
+#else
+
+ if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6)
+ return d->addr.in6->sin6_flowinfo;
+ return 0;
+#endif
+}
+
+KInetSocketAddress& KInetSocketAddress::setFlowinfo(Q_UINT32 flowinfo)
+{
+ makeIPv6(); // must set here
+ d->addr.in6->sin6_flowinfo = flowinfo;
+ return *this;
+}
+
+int KInetSocketAddress::scopeId() const
+{
+#ifndef AF_INET6
+ return 0;
+#else
+
+ if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6)
+ return d->addr.in6->sin6_scope_id;
+ return 0;
+#endif
+}
+
+KInetSocketAddress& KInetSocketAddress::setScopeId(int scopeid)
+{
+ makeIPv6(); // must set here
+ d->addr.in6->sin6_scope_id = scopeid;
+ return *this;
+}
+
+void KInetSocketAddress::update()
+{
+ if (d->addr.generic->sa_family == AF_INET)
+ return;
+#ifdef AF_INET6
+ else if (d->addr.generic->sa_family == AF_INET6)
+ return;
+#endif
+ else
+ d->invalidate();
+}
+
+KUnixSocketAddress::KUnixSocketAddress()
+{
+}
+
+KUnixSocketAddress::KUnixSocketAddress(const sockaddr* sa, Q_UINT16 len)
+ : KSocketAddress(sa, len)
+{
+ if (!d->invalid() && d->addr.un->sun_family != AF_UNIX)
+ d->invalidate();
+}
+
+KUnixSocketAddress::KUnixSocketAddress(const KUnixSocketAddress& other)
+ : KSocketAddress(other)
+{
+}
+
+KUnixSocketAddress::KUnixSocketAddress(const QString& pathname)
+{
+ setPathname(pathname);
+}
+
+KUnixSocketAddress::KUnixSocketAddress(KSocketAddressData* d)
+ : KSocketAddress(d)
+{
+}
+
+KUnixSocketAddress::~KUnixSocketAddress()
+{
+}
+
+KUnixSocketAddress& KUnixSocketAddress::operator =(const KUnixSocketAddress& other)
+{
+ KSocketAddress::operator =(other);
+ return *this;
+}
+
+QString KUnixSocketAddress::pathname() const
+{
+ if (!d->invalid() && d->addr.un->sun_family == AF_UNIX)
+ return QFile::decodeName(d->addr.un->sun_path);
+ return QString::null;
+}
+
+KUnixSocketAddress& KUnixSocketAddress::setPathname(const QString& path)
+{
+ d->dup(0L, MIN_SOCKADDR_UN_LEN + path.length());
+ d->addr.un->sun_family = AF_UNIX;
+ strcpy(d->addr.un->sun_path, QFile::encodeName(path));
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ d->addr.un->sun_len = d->reallen;
+#endif
+
+ return *this;
+}
diff --git a/kdecore/network/ksocketaddress.h b/kdecore/network/ksocketaddress.h
new file mode 100644
index 000000000..456422f9f
--- /dev/null
+++ b/kdecore/network/ksocketaddress.h
@@ -0,0 +1,912 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KSOCKETADDRESS_H
+#define KSOCKETADDRESS_H
+
+#include <qstring.h>
+#include <qcstring.h>
+
+#include <kdelibs_export.h>
+
+struct sockaddr;
+struct sockaddr_in;
+struct sockaddr_in6;
+struct sockaddr_un;
+
+namespace KNetwork {
+
+class KIpAddress;
+class KSocketAddress;
+class KInetSocketAddress;
+class KUnixSocketAddress;
+
+/** @class KIpAddress ksocketaddress.h ksocketaddress.h
+ * @brief An IP address.
+ *
+ * This class represents one IP address, version 4 or 6. This is only
+ * the address, not including port information or other data.
+ *
+ * It is not a good programming practice to create address from objects
+ * like this. Instead, prefer a more thorough function like
+ * @ref KResolver::resolve, which also handle extra information like scope
+ * ids.
+ *
+ * This is a light-weight class. Most of the member functions are inlined and
+ * there are no virtual functions. This object's size should be less than 20
+ * bytes. Also note that there is no sharing of data.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KIpAddress
+{
+public:
+ /**
+ * Default constructor. Creates an empty address.
+ * It defaults to IP version 4.
+ */
+ inline KIpAddress() : m_version(0)
+ { }
+
+ /**
+ * Copy constructor. Copies the data from the other
+ * object.
+ *
+ * Data is not shared.
+ *
+ * @param other the other
+ */
+ inline KIpAddress(const KIpAddress& other)
+ { *this = other; }
+
+ /**
+ * Creates an object from the given string representation.
+ *
+ * The IP version is guessed from the address format.
+ *
+ * @param addr the address
+ */
+ inline KIpAddress(const QString& addr)
+ { setAddress(addr); }
+
+ /**
+ * Creates an object from the given string representation.
+ *
+ * The IP version is guessed from the address format.
+ *
+ * @param addr the address
+ */
+ inline KIpAddress(const char* addr)
+ { setAddress(addr); }
+
+ /**
+ * Creates an object from the given raw data and IP version.
+ *
+ * @param addr the raw data
+ * @param version the IP version (4 or 6)
+ */
+ inline KIpAddress(const void* addr, int version = 4)
+ { setAddress(addr, version); }
+
+ /**
+ * This is a convenience constructor. Constructs an object
+ * from the given IPv4 address in the form of an integer.
+ *
+ * Note: do not write code to depend on IPv4 addresses being
+ * integer types. Instead, treat them as a special type, like
+ * a KIpAddress or the system's in_addr.
+ *
+ * @param ip4addr the IPv4 address
+ */
+ inline KIpAddress(Q_UINT32 ip4addr)
+ { setAddress(&ip4addr, 4); }
+
+ /**
+ * Destructor. This frees resources associated with this object.
+ *
+ * Note: destructor is non-virtual. The compiler will happily optimise it
+ * out of the way.
+ */
+ inline ~KIpAddress()
+ { }
+
+ /**
+ * Copy operator.
+ *
+ * Copies the data from the other object into this one.
+ *
+ * @param other the object to copy
+ */
+ KIpAddress& operator =(const KIpAddress& other);
+
+ /**
+ * Returns true if the two addresses match.
+ * This function performs a v4-mapped check.
+ * @see compare
+ */
+ inline bool operator ==(const KIpAddress& other) const
+ { return compare(other, true); }
+
+ /**
+ * Compares this address against the other, supplied one and return
+ * true if they match. The @p checkMapped parameter controls whether
+ * a check for an IPv6 v4-mapped address will be performed.
+ *
+ * An IPv6 v4-mapped address is an IPv6 address that is, for all purposes,
+ * equivalent to an IPv4 one. The default behaviour of this function
+ * is to take that into account. If you want a strict matching,
+ * pass @b false to the @p checkMapped parameter.
+ *
+ * @param other the other IP address
+ * @param checkMapped whether v4-mapped addresses will be taken into account
+ */
+ bool compare(const KIpAddress& other, bool checkMapped = true) const;
+
+ /**
+ * Retrieves the IP version in this object.
+ *
+ * @returns the version: 4 or 6
+ */
+ inline int version() const
+ { return m_version; }
+
+ /**
+ * Returns true if this is an IPv4 address.
+ */
+ inline bool isIPv4Addr() const
+ { return version() == 4; }
+
+ /**
+ * Returns true if this is an IPv6 address.
+ */
+ inline bool isIPv6Addr() const
+ { return version() == 6; }
+
+ /**
+ * Sets the address to the given string representation.
+ *
+ * @return true if the address was successfully parsed; otherwise returns
+ * false and leaves the object unchanged.
+ */
+ bool setAddress(const QString& address);
+
+ /**
+ * Sets the address to the given string representation.
+ *
+ * @return true if the address was successfully parsed; otherwise returns
+ * false and leaves the object unchanged.
+ */
+ bool setAddress(const char* address);
+
+ /**
+ * Sets the address to the given raw binary representation.
+ *
+ * @param raw a pointer to the raw binary data
+ * @param version the IP version
+ * @return true if the address was successfully parsed; otherwise returns
+ * false and leaves the object unchanged.
+ */
+ bool setAddress(const void* raw, int version = 4);
+
+ /**
+ * Returns the address as a string.
+ */
+ QString toString() const;
+
+ /**
+ * Returns a pointer to binary raw data representing the address.
+ */
+ inline const void *addr() const
+ { return m_data; }
+
+ /**
+ * This is a convenience function. Returns the IPv4 address in a
+ * 32-bit integer. The result is only valid if @ref isIPv4Addr returns
+ * true. Alternatively, if the contained IPv6 address is a v4-mapped one
+ * and the @p convertMapped parameter is true, the result will also be
+ * valid. The address returned is in network byte order.
+ *
+ * Note: you should not treat IP addresses as integers. Instead,
+ * use types defined for that purpose, such as KIpAddress or the
+ * system's in_addr type.
+ *
+ */
+ inline Q_UINT32 IPv4Addr(bool convertMapped = true) const
+ {
+ return (convertMapped && isV4Mapped()) ? m_data[3] : m_data[0];
+ }
+
+ /**
+ * This is a convenience function. Returns the IPv4 address in a
+ * 32-bit integer. The result is only valid if @ref isIPv4Addr returns
+ * true. Alternatively, if the contained IPv6 address is a v4-mapped one
+ * and the @p convertMapped parameter is true, the result will also be
+ * valid. The address returned is in host byte order.
+ *
+ */
+ Q_UINT32 hostIPv4Addr(bool convertMapped = true) const;
+
+public:
+ /*-- tests --*/
+
+ /**
+ * Returns true if this is the IPv4 or IPv6 unspecified address.
+ */
+ inline bool isUnspecified() const
+ { return version() == 0 ? true : (*this == anyhostV4 || *this == anyhostV6); }
+
+ /**
+ * Returns true if this is either the IPv4 or the IPv6 localhost address.
+ */
+ inline bool isLocalhost() const
+ { return version() == 0 ? false : (*this == localhostV4 || *this == localhostV6); }
+
+ /**
+ * This is an alias for @ref isLocalhost.
+ */
+ inline bool isLoopback() const
+ { return isLocalhost(); }
+
+ /**
+ * Returns true if this is an IPv4 class A address, i.e.,
+ * from 0.0.0.0 to 127.255.255.255.
+ *
+ * This function does not test for v4-mapped addresses.
+ */
+ inline bool isClassA() const
+ { return version() != 4 ? false : (hostIPv4Addr() & 0x80000000) == 0; }
+
+ /**
+ * Returns true if this is an IPv4 class B address, i.e., one from
+ * 128.0.0.0 to 191.255.255.255.
+ *
+ * This function does not test for v4-mapped addresses.
+ */
+ inline bool isClassB() const
+ { return version() != 4 ? false : (hostIPv4Addr() & 0xc0000000) == 0x80000000; }
+
+ /**
+ * Returns true if this is an IPv4 class C address, i.e., one from
+ * 192.0.0.0 to 223.255.255.255.
+ *
+ * This function does not test for v4-mapped addresses.
+ */
+ inline bool isClassC() const
+ { return version() != 4 ? false : (hostIPv4Addr() & 0xe0000000) == 0xc0000000; }
+
+ /**
+ * Returns true if this is an IPv4 class D (a.k.a. multicast) address.
+ *
+ * Note: this function is not the same as @ref isMulticast. isMulticast also
+ * tests for IPv6 multicast addresses.
+ */
+ inline bool isClassD() const
+ { return version() != 4 ? false : (hostIPv4Addr() & 0xf0000000) == 0xe0000000; }
+
+ /**
+ * Returns true if this is a multicast address, be it IPv4 or IPv6.
+ */
+ inline bool isMulticast() const
+ {
+ if (version() == 4) return isClassD();
+ if (version() == 6) return ((Q_UINT8*)addr())[0] == 0xff;
+ return false;
+ }
+
+ /**
+ * Returns true if this is an IPv6 link-local address.
+ */
+ inline bool isLinkLocal() const
+ {
+ if (version() != 6) return false;
+ Q_UINT8* addr = (Q_UINT8*)this->addr();
+ return (addr[0] & 0xff) == 0xfe &&
+ (addr[1] & 0xc0) == 0x80;
+ }
+
+ /**
+ * Returns true if this is an IPv6 site-local address.
+ */
+ inline bool isSiteLocal() const
+ {
+ if (version() != 6) return false;
+ Q_UINT8* addr = (Q_UINT8*)this->addr();
+ return (addr[0] & 0xff) == 0xfe &&
+ (addr[1] & 0xc0) == 0xc0;
+ }
+
+ /**
+ * Returns true if this is a global IPv6 address.
+ */
+ inline bool isGlobal() const
+ { return version() != 6 ? false : !(isMulticast() || isLinkLocal() || isSiteLocal()); }
+
+ /**
+ * Returns true if this is a v4-mapped IPv6 address.
+ */
+ inline bool isV4Mapped() const
+ {
+ if (version() != 6) return false;
+ Q_UINT32* addr = (Q_UINT32*)this->addr();
+ return addr[0] == 0 && addr[1] == 0 &&
+ ((Q_UINT16*)&addr[2])[0] == 0 &&
+ ((Q_UINT16*)&addr[2])[1] == 0xffff;
+ }
+
+ /**
+ * Returns true if this is a v4-compat IPv6 address.
+ */
+ inline bool isV4Compat() const
+ {
+ if (version() != 6 || isLocalhost()) return false;
+ Q_UINT32* addr = (Q_UINT32*)this->addr();
+ return addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] != 0;
+ }
+
+ /**
+ * Returns true if this is an IPv6 node-local multicast address.
+ */
+ inline bool isMulticastNodeLocal() const
+ { return version() == 6 && isMulticast() && (((Q_UINT32*)addr())[0] & 0xf) == 0x1; }
+
+ /**
+ * Returns true if this is an IPv6 link-local multicast address.
+ */
+ inline bool isMulticastLinkLocal() const
+ { return version() == 6 && isMulticast() && (((Q_UINT32*)addr())[0] & 0xf) == 0x2; }
+
+ /**
+ * Returns true if this is an IPv6 site-local multicast address.
+ */
+ inline bool isMulticastSiteLocal() const
+ { return version() == 6 && isMulticast() && (((Q_UINT32*)addr())[0] & 0xf) == 0x5; }
+
+ /**
+ * Returns true if this is an IPv6 organisational-local multicast address.
+ */
+ inline bool isMulticastOrgLocal() const
+ { return version() == 6 && isMulticast() && (((Q_UINT32*)addr())[0] & 0xf) == 0x8; }
+
+ /**
+ * Returns true if this is an IPv6 global multicast address.
+ */
+ inline bool isMulticastGlobal() const
+ { return version() == 6 && isMulticast() && (((Q_UINT32*)addr())[0] & 0xf) == 0xe; }
+
+protected:
+ Q_UINT32 m_data[4]; // 16 bytes, needed for an IPv6 address
+
+ char m_version;
+
+public:
+ /// localhost in IPv4 (127.0.0.1)
+ static const KIpAddress localhostV4;
+ /// the any host or undefined address in IPv4 (0.0.0.0)
+ static const KIpAddress anyhostV4;
+
+ /// localhost in IPv6 (::1)
+ static const KIpAddress localhostV6;
+ /// the any host or undefined address in IPv6 (::)
+ static const KIpAddress anyhostV6;
+};
+
+
+class KSocketAddressData;
+/** @class KSocketAddress ksocketaddress.h ksocketaddress.h
+ * @brief A generic socket address.
+ *
+ * This class holds one generic socket address.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KSocketAddress
+{
+public:
+ /**
+ * Default constructor.
+ *
+ * Creates an empty object
+ */
+ KSocketAddress();
+
+ /**
+ * Creates this object with the given data.
+ * The raw socket address is copied into this object.
+ *
+ * @param sa the socket address structure
+ * @param len the socket address length
+ */
+ KSocketAddress(const sockaddr* sa, Q_UINT16 len);
+
+ /**
+ * Copy constructor. This creates a copy of the other
+ * object.
+ *
+ * Data is not shared.
+ *
+ * @param other the object to copy from
+ */
+ KSocketAddress(const KSocketAddress& other);
+
+ /**
+ * Destructor. Frees any associated resources.
+ */
+ virtual ~KSocketAddress();
+
+ /**
+ * Performs a shallow copy of the other object into this one.
+ * Data will be copied.
+ *
+ * @param other the object to copy from
+ */
+ KSocketAddress& operator =(const KSocketAddress& other);
+
+ /**
+ * Returns the socket address structure, to be passed down to
+ * low level functions.
+ *
+ * Note that this function returns NULL for invalid or empty sockets,
+ * so you may use to to test for validity.
+ */
+ const sockaddr* address() const;
+
+ /**
+ * Returns the socket address structure, to be passed down to
+ * low level functions.
+ *
+ * Note that this function returns NULL for invalid or empty sockets,
+ * so you may use to to test for validity.
+ *
+ * The returned value, if not NULL, is an internal buffer which is guaranteed
+ * to be at least @ref length() bytes long.
+ */
+ sockaddr* address();
+
+ /**
+ * Sets the address to the given address.
+ * The raw socket address is copied into this object.
+ *
+ * @param sa the socket address structure
+ * @param len the socket address length
+ */
+ KSocketAddress& setAddress(const sockaddr *sa, Q_UINT16 len);
+
+ /**
+ * Returns the socket address structure, to be passed down to
+ * low level functions.
+ */
+ inline operator const sockaddr*() const
+ { return address(); }
+
+ /**
+ * Returns the length of this socket address structure.
+ */
+ Q_UINT16 length() const;
+
+ /**
+ * Sets the length of this socket structure.
+ *
+ * Use this function with care. It allows you to resize the internal
+ * buffer to fit needs. This function should not be used except for handling
+ * unknown socket address structures.
+ *
+ * Also note that this function may invalidate the socket if a known
+ * family is set (Internet or Unix socket) and the new length would be
+ * too small to hold the system's sockaddr_* structure. If unsure, reset
+ * the family:
+ *
+ * \code
+ * KSocketAddress qsa;
+ * [...]
+ * qsa.setFamily(AF_UNSPEC).setLength(newlen);
+ * \endcode
+ *
+ * @param len the new length
+ */
+ KSocketAddress& setLength(Q_UINT16 len);
+
+ /**
+ * Returns the family of this address.
+ * @return the family of this address, AF_UNSPEC if it's undefined
+ */
+ int family() const;
+
+ /**
+ * Sets the family of this object.
+ *
+ * Note: setting the family will probably invalidate any address data
+ * contained in this object. Use this function with care.
+ *
+ * @param family the new family to set
+ */
+ virtual KSocketAddress& setFamily(int family);
+
+ /**
+ * Returns the IANA family number of this address.
+ * @return the IANA family number of this address (1 for AF_INET.
+ * 2 for AF_INET6, otherwise 0)
+ */
+ inline int ianaFamily() const
+ { return ianaFamily(family()); }
+
+ /**
+ * Returns true if this equals the other socket.
+ *
+ * Socket addresses are considered matching if and only if all data is the same.
+ *
+ * @param other the other socket
+ * @return true if both sockets are equal
+ */
+ bool operator ==(const KSocketAddress& other) const;
+
+ /**
+ * Returns the node name of this socket.
+ *
+ * In the case of Internet sockets, this is string representation of the IP address.
+ * The default implementation returns QString::null.
+ *
+ * @return the node name, can be QString::null
+ * @bug use KResolver to resolve unknown families
+ */
+ virtual QString nodeName() const;
+
+ /**
+ * Returns the service name for this socket.
+ *
+ * In the case of Internet sockets, this is the port number.
+ * The default implementation returns QString::null.
+ *
+ * @return the service name, can be QString::null
+ * @bug use KResolver to resolve unknown families
+ */
+ virtual QString serviceName() const;
+
+ /**
+ * Returns this socket address as a string suitable for
+ * printing. Family, node and service are part of this address.
+ *
+ * @bug use KResolver to resolve unknown families
+ */
+ virtual QString toString() const;
+
+ /**
+ * Returns an object reference that can be used to manipulate this socket
+ * as an Internet socket address. Both objects share the same data.
+ */
+ KInetSocketAddress& asInet();
+
+ /**
+ * Returns an object is equal to this object's data, but they don't share it.
+ */
+ KInetSocketAddress asInet() const;
+
+ /**
+ * Returns an object reference that can be used to manipulate this socket
+ * as a Unix socket address. Both objects share the same data.
+ */
+ KUnixSocketAddress& asUnix();
+
+ /**
+ * Returns an object is equal to this object's data, but they don't share it.
+ */
+ KUnixSocketAddress asUnix() const;
+
+protected:
+ /// @internal
+ /// private data
+ KSocketAddressData *d;
+
+ /// @internal
+ /// extra constructor
+ KSocketAddress(KSocketAddressData* d);
+
+public: // static
+ /**
+ * Returns the IANA family number of the given address family.
+ * Returns 0 if there is no corresponding IANA family number.
+ * @param af the address family, in AF_* constants
+ * @return the IANA family number of this address (1 for AF_INET.
+ * 2 for AF_INET6, otherwise 0)
+ */
+ static int ianaFamily(int af);
+
+ /**
+ * Returns the address family of the given IANA family number.
+ * @return the address family, AF_UNSPEC for unknown IANA family numbers
+ */
+ static int fromIanaFamily(int iana);
+};
+
+
+/** @class KInetSocketAddress ksocketaddress.h ksocketaddress.h
+ * @brief an Internet socket address
+ *
+ * An Inet (IPv4 or IPv6) socket address
+ *
+ * This is an IPv4 or IPv6 address of the Internet.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KInetSocketAddress: public KSocketAddress
+{
+ friend class KSocketAddress;
+public:
+ /**
+ * Public constructor. Creates an empty object.
+ */
+ KInetSocketAddress();
+
+ /**
+ * Creates an object from raw data.
+ *
+ * Note: if the socket address @p sa does not contain a valid Internet
+ * socket (IPv4 or IPv6), this object will be empty.
+ *
+ * @param sa the sockaddr structure
+ * @param len the structure's length
+ */
+ KInetSocketAddress(const sockaddr* sa, Q_UINT16 len);
+
+ /**
+ * Creates an object from an IP address and port.
+ *
+ * @param host the IP address
+ * @param port the port number
+ */
+ KInetSocketAddress(const KIpAddress& host, Q_UINT16 port);
+
+ /**
+ * Copy constructor.
+ *
+ * Data is not shared.
+ *
+ * @param other the other object
+ */
+ KInetSocketAddress(const KInetSocketAddress& other);
+
+ /**
+ * Copy constructor.
+ *
+ * If the other, generic socket address contains an Internet address,
+ * it will be copied. Otherwise, this object will be empty.
+ *
+ * @param other the other object
+ */
+ KInetSocketAddress(const KSocketAddress& other);
+
+ /**
+ * Destroys this object.
+ */
+ virtual ~KInetSocketAddress();
+
+ /**
+ * Copy operator.
+ *
+ * Copies the other object into this one.
+ *
+ * @param other the other object
+ */
+ KInetSocketAddress& operator =(const KInetSocketAddress& other);
+
+ /**
+ * Cast operator to sockaddr_in.
+ */
+ inline operator const sockaddr_in*() const
+ { return (const sockaddr_in*)address(); }
+
+ /**
+ * Cast operator to sockaddr_in6.
+ */
+ inline operator const sockaddr_in6*() const
+ { return (const sockaddr_in6*)address(); }
+
+ /**
+ * Returns the IP version of the address this object holds.
+ *
+ * @return 4 or 6, if IPv4 or IPv6, respectively; 0 if this object is empty
+ */
+ int ipVersion() const;
+
+ /**
+ * Returns the IP address component.
+ */
+ KIpAddress ipAddress() const;
+
+ /**
+ * Sets the IP address to the given raw address.
+ *
+ * This call will preserve port numbers accross IP versions, but will lose
+ * IPv6 specific data if the address is set to IPv4.
+ *
+ * @param addr the address to set to
+ * @return a reference to itself
+ */
+ KInetSocketAddress& setHost(const KIpAddress& addr);
+
+ /**
+ * Retrieves the port number stored in this object.
+ *
+ * @return a port number in the range 0 to 65535, inclusive. An empty or
+ * invalid object will have a port number of 0.
+ */
+ Q_UINT16 port() const;
+
+ /**
+ * Sets the port number. If this object is empty, this function will default to
+ * creating an IPv4 address.
+ *
+ * @param port the port number to set
+ * @return a reference to itself
+ */
+ KInetSocketAddress& setPort(Q_UINT16 port);
+
+ /**
+ * Converts this object to an IPv4 socket address. It has no effect if the object
+ * is already an IPv4 socket address.
+ *
+ * If this object is an IPv6 address, the port number is preserved. All other information
+ * is lost.
+ *
+ * @return a reference to itself
+ */
+ KInetSocketAddress& makeIPv4();
+
+ /**
+ * Converts this object to an IPv6 socket address. It has no effect if the object
+ * is already an IPv6 socket address.
+ *
+ * If this object is an IPv4 address, the port number is preserved.
+ *
+ * @return a reference to itself
+ */
+ KInetSocketAddress& makeIPv6();
+
+ /**
+ * Returns the flowinfo information from the IPv6 socket address.
+ *
+ * @return the flowinfo information or 0 if this object is empty or IPv4
+ */
+ Q_UINT32 flowinfo() const;
+
+ /**
+ * Sets the flowinfo information for an IPv6 socket address. If this is not
+ * an IPv6 socket address, this function converts it to one. See makeIPv6.
+ *
+ * @param flowinfo the flowinfo to set
+ * @return a reference to itself
+ */
+ KInetSocketAddress& setFlowinfo(Q_UINT32 flowinfo);
+
+ /**
+ * Returns the scope id this IPv6 socket is bound to.
+ *
+ * @return the scope id, or 0 if this is not an IPv6 object
+ */
+ int scopeId() const;
+
+ /**
+ * Sets the scope id for this IPv6 object. If this is not an IPv6 socket
+ * address, this function converts it to one. See makeIPv6
+ *
+ * @param scopeid the scopeid to set
+ * @return a reference to itself
+ */
+ KInetSocketAddress& setScopeId(int scopeid);
+
+protected:
+ /// @internal
+ /// extra constructor
+ KInetSocketAddress(KSocketAddressData* d);
+
+private:
+ void update();
+};
+
+/*
+ * External definition
+ */
+
+/** @class KUnixSocketAddress ksocketaddress.h ksocketaddress.h
+ * @brief A Unix (local) socket address.
+ *
+ * This is a Unix socket address.
+ *
+ * Note that this class uses QStrings to represent filenames, which means
+ * the proper encoding is used to translate into valid filesystem file names.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KUnixSocketAddress: public KSocketAddress
+{
+ friend class KSocketAddress;
+public:
+ /**
+ * Default constructor. Creates an empty object.
+ */
+ KUnixSocketAddress();
+
+ /**
+ * Creates this object with the given raw data. If
+ * the sockaddr structure does not contain a Local namespace
+ * (Unix) socket, this object will be created empty.
+ *
+ * @param sa the socket address structure
+ * @param len the structure's length
+ */
+ KUnixSocketAddress(const sockaddr* sa, Q_UINT16 len);
+
+ /**
+ * Copy constructor. Creates a copy of the other object,
+ * sharing the data explicitly.
+ *
+ * @param other the other object
+ */
+ KUnixSocketAddress(const KUnixSocketAddress& other);
+
+ /**
+ * Constructs an object from the given pathname.
+ */
+ KUnixSocketAddress(const QString& pathname);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KUnixSocketAddress();
+
+ /**
+ * Copy operator. Copies the contents of the other object into
+ * this one. Data is explicitly shared.
+ *
+ * @param other the other
+ */
+ KUnixSocketAddress& operator =(const KUnixSocketAddress& other);
+
+ /**
+ * Cast operator to sockaddr_un.
+ */
+ inline operator const sockaddr_un*() const
+ { return (const sockaddr_un*)address(); }
+
+ /**
+ * Returns the pathname associated with this object. Will return
+ * QString::null if this object is empty.
+ */
+ QString pathname() const;
+
+ /**
+ * Sets the pathname for the object.
+ *
+ * @return a reference to itself
+ */
+ KUnixSocketAddress& setPathname(const QString& path);
+
+protected:
+ /// @internal
+ /// extra constructor
+ KUnixSocketAddress(KSocketAddressData* d);
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/ksocketbase.cpp b/kdecore/network/ksocketbase.cpp
new file mode 100644
index 000000000..f3bfa766c
--- /dev/null
+++ b/kdecore/network/ksocketbase.cpp
@@ -0,0 +1,327 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+#include <qmutex.h>
+#include "klocale.h"
+
+#include "ksocketbase.h"
+#include "ksocketdevice.h"
+
+using namespace KNetwork;
+
+class KNetwork::KSocketBasePrivate
+{
+public:
+ int socketOptions;
+ int socketError;
+ int capabilities;
+
+ mutable KSocketDevice* device;
+
+ QMutex mutex;
+
+ KSocketBasePrivate()
+ : mutex(true) // create recursive
+ { }
+};
+
+KSocketBase::KSocketBase()
+ : d(new KSocketBasePrivate)
+{
+ d->socketOptions = Blocking;
+ d->socketError = 0;
+ d->device = 0L;
+ d->capabilities = 0;
+}
+
+KSocketBase::~KSocketBase()
+{
+ delete d->device;
+ delete d;
+}
+
+bool KSocketBase::setSocketOptions(int opts)
+{
+ d->socketOptions = opts;
+ return true;
+}
+
+int KSocketBase::socketOptions() const
+{
+ return d->socketOptions;
+}
+
+bool KSocketBase::setBlocking(bool enable)
+{
+ return setSocketOptions((socketOptions() & ~Blocking) | (enable ? Blocking : 0));
+}
+
+bool KSocketBase::blocking() const
+{
+ return socketOptions() & Blocking;
+}
+
+bool KSocketBase::setAddressReuseable(bool enable)
+{
+ return setSocketOptions((socketOptions() & ~AddressReuseable) | (enable ? AddressReuseable : 0));
+}
+
+bool KSocketBase::addressReuseable() const
+{
+ return socketOptions() & AddressReuseable;
+}
+
+bool KSocketBase::setIPv6Only(bool enable)
+{
+ return setSocketOptions((socketOptions() & ~IPv6Only) | (enable ? IPv6Only : 0));
+}
+
+bool KSocketBase::isIPv6Only() const
+{
+ return socketOptions() & IPv6Only;
+}
+
+bool KSocketBase::setBroadcast(bool enable)
+{
+ return setSocketOptions((socketOptions() & ~Broadcast) | (enable ? Broadcast : 0));
+}
+
+bool KSocketBase::broadcast() const
+{
+ return socketOptions() & Broadcast;
+}
+
+KSocketDevice* KSocketBase::socketDevice() const
+{
+ if (d->device)
+ return d->device;
+
+ // it doesn't exist, so create it
+ QMutexLocker locker(mutex());
+ if (d->device)
+ return d->device;
+
+ KSocketBase* that = const_cast<KSocketBase*>(this);
+ KSocketDevice* dev = 0;
+ if (d->capabilities)
+ dev = KSocketDevice::createDefault(that, d->capabilities);
+ if (!dev)
+ dev = KSocketDevice::createDefault(that);
+ that->setSocketDevice(dev);
+ return d->device;
+}
+
+void KSocketBase::setSocketDevice(KSocketDevice* device)
+{
+ QMutexLocker locker(mutex());
+ if (d->device == 0L)
+ d->device = device;
+}
+
+int KSocketBase::setRequestedCapabilities(int add, int remove)
+{
+ d->capabilities |= add;
+ d->capabilities &= ~remove;
+ return d->capabilities;
+}
+
+bool KSocketBase::hasDevice() const
+{
+ return d->device != 0L;
+}
+
+void KSocketBase::setError(SocketError error)
+{
+ d->socketError = error;
+}
+
+KSocketBase::SocketError KSocketBase::error() const
+{
+ return static_cast<KSocketBase::SocketError>(d->socketError);
+}
+
+// static
+QString KSocketBase::errorString(KSocketBase::SocketError code)
+{
+ QString reason;
+ switch (code)
+ {
+ case NoError:
+ reason = i18n("Socket error code NoError", "no error");
+ break;
+
+ case LookupFailure:
+ reason = i18n("Socket error code LookupFailure",
+ "name lookup has failed");
+ break;
+
+ case AddressInUse:
+ reason = i18n("Socket error code AddressInUse",
+ "address already in use");
+ break;
+
+ case AlreadyBound:
+ reason = i18n("Socket error code AlreadyBound",
+ "socket is already bound");
+ break;
+
+ case AlreadyCreated:
+ reason = i18n("Socket error code AlreadyCreated",
+ "socket is already created");
+ break;
+
+ case NotBound:
+ reason = i18n("Socket error code NotBound",
+ "socket is not bound");
+ break;
+
+ case NotCreated:
+ reason = i18n("Socket error code NotCreated",
+ "socket has not been created");
+ break;
+
+ case WouldBlock:
+ reason = i18n("Socket error code WouldBlock",
+ "operation would block");
+ break;
+
+ case ConnectionRefused:
+ reason = i18n("Socket error code ConnectionRefused",
+ "connection actively refused");
+ break;
+
+ case ConnectionTimedOut:
+ reason = i18n("Socket error code ConnectionTimedOut",
+ "connection timed out");
+ break;
+
+ case InProgress:
+ reason = i18n("Socket error code InProgress",
+ "operation is already in progress");
+ break;
+
+ case NetFailure:
+ reason = i18n("Socket error code NetFailure",
+ "network failure occurred");
+ break;
+
+ case NotSupported:
+ reason = i18n("Socket error code NotSupported",
+ "operation is not supported");
+ break;
+
+ case Timeout:
+ reason = i18n("Socket error code Timeout",
+ "timed operation timed out");
+ break;
+
+ case UnknownError:
+ reason = i18n("Socket error code UnknownError",
+ "an unknown/unexpected error has happened");
+ break;
+
+ case RemotelyDisconnected:
+ reason = i18n("Socket error code RemotelyDisconnected",
+ "remote host closed connection");
+ break;
+
+ default:
+ reason = QString::null;
+ break;
+ }
+
+ return reason;
+}
+
+// static
+bool KSocketBase::isFatalError(int code)
+{
+ switch (code)
+ {
+ case WouldBlock:
+ case InProgress:
+ case NoError:
+ case RemotelyDisconnected:
+ return false;
+ }
+
+ return true;
+}
+
+void KSocketBase::unsetSocketDevice()
+{
+ d->device = 0L;
+}
+
+QMutex* KSocketBase::mutex() const
+{
+ return &d->mutex;
+}
+
+KActiveSocketBase::KActiveSocketBase()
+{
+}
+
+KActiveSocketBase::~KActiveSocketBase()
+{
+}
+
+int KActiveSocketBase::getch()
+{
+ unsigned char c;
+ if (readBlock((char*)&c, 1) != 1)
+ return -1;
+
+ return c;
+}
+
+int KActiveSocketBase::putch(int ch)
+{
+ unsigned char c = (unsigned char)ch;
+ if (writeBlock((char*)&c, 1) != 1)
+ return -1;
+
+ return c;
+}
+
+void KActiveSocketBase::setError(int status, SocketError error)
+{
+ KSocketBase::setError(error);
+ setStatus(status);
+}
+
+void KActiveSocketBase::resetError()
+{
+ KSocketBase::setError(NoError);
+ resetStatus();
+}
+
+KPassiveSocketBase::KPassiveSocketBase()
+{
+}
+
+KPassiveSocketBase::~KPassiveSocketBase()
+{
+}
diff --git a/kdecore/network/ksocketbase.h b/kdecore/network/ksocketbase.h
new file mode 100644
index 000000000..acbbdf9b9
--- /dev/null
+++ b/kdecore/network/ksocketbase.h
@@ -0,0 +1,762 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003,2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+/*
+ * Even before our #ifdef, clean up the namespace
+ */
+#ifdef socket
+#undef socket
+#endif
+
+#ifdef bind
+#undef bind
+#endif
+
+#ifdef listen
+#undef listen
+#endif
+
+#ifdef connect
+#undef connect
+#endif
+
+#ifdef accept
+#undef accept
+#endif
+
+#ifdef getpeername
+#undef getpeername
+#endif
+
+#ifdef getsockname
+#undef getsockname
+#endif
+
+#ifndef KSOCKETBASE_H
+#define KSOCKETBASE_H
+
+#include <qiodevice.h>
+#include <qstring.h>
+
+#include "ksocketaddress.h"
+#include <kdelibs_export.h>
+
+/*
+ * This is extending QIODevice's error codes
+ *
+ * According to qiodevice.h, the last error is IO_UnspecifiedError
+ * These errors will never occur in functions declared in QIODevice
+ * (except open, but you shouldn't call open)
+ */
+#define IO_ListenError (IO_UnspecifiedError+1)
+#define IO_AcceptError (IO_UnspecifiedError+2)
+#define IO_LookupError (IO_UnspecifiedError+3)
+#define IO_SocketCreateError (IO_UnspecifiedError+4)
+#define IO_BindError (IO_UnspecifiedError+5)
+
+class QMutex;
+
+namespace KNetwork {
+
+class KResolverEntry;
+class KSocketDevice;
+
+class KSocketBasePrivate;
+/** @class KSocketBase ksocketbase.h ksocketbase.h
+ * @brief Basic socket functionality.
+ *
+ * This class provides the basic socket functionlity for descended classes.
+ * Socket classes are thread-safe and provide a recursive mutex should it be
+ * needed.
+ *
+ * @note This class is abstract.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KSocketBase
+{
+public:
+ /**
+ * Possible socket options.
+ *
+ * These are the options that may be set on a socket:
+ * - Blocking: whether the socket shall operate in blocking
+ * or non-blocking mode. This flag defaults to on.
+ * See @ref setBlocking.
+ * - AddressReusable: whether the address used by this socket will
+ * be available for reuse by other sockets. This flag defaults to off.
+ * See @ref setAddressReuseable.
+ * - IPv6Only: whether an IPv6 socket will accept IPv4 connections
+ * through a mapped address. This flag defaults to off.
+ * See @ref setIPv6Only.
+ * - KeepAlive: whether TCP should send keepalive probes when a connection
+ * has gone idle for far too long.
+ * - Broadcast: whether this socket is allowed to send broadcast packets
+ * and will receive packets sent to broadcast.
+ */
+ enum SocketOptions
+ {
+ Blocking = 0x01,
+ AddressReuseable = 0x02,
+ IPv6Only = 0x04,
+ Keepalive = 0x08,
+ Broadcast = 0x10
+ };
+
+ /**
+ * Possible socket error codes.
+ *
+ * This is a list of possible error conditions that socket classes may
+ * be expected to find.
+ *
+ * - NoError: no error has been detected
+ * - LookupFailure: if a name lookup has failed
+ * - AddressInUse: address is already in use
+ * - AlreadyBound: cannot bind again
+ * - AlreadyCreated: cannot recreate the socket
+ * - NotBound: operation required socket to be bound and it isn't
+ * - NotCreated: operation required socket to exist and it doesn't
+ * - WouldBlock: requested I/O operation would block
+ * - ConnectionRefused: connection actively refused
+ * - ConnectionTimedOut: connection timed out
+ * - InProgress: operation (connection) is already in progress
+ * - NetFailure: a network failure occurred (no route, host down, host unreachable or similar)
+ * - NotSupported: requested operation is not supported
+ * - Timeout: a timed operation timed out
+ * - UnknownError: an unknown/unexpected error has happened
+ * - RemotelyDisconnected: when a connection is disconnected by the other end (since 3.4)
+ *
+ * @sa error, errorString
+ */
+ enum SocketError
+ {
+ NoError = 0,
+ LookupFailure,
+ AddressInUse,
+ AlreadyCreated,
+ AlreadyBound,
+ AlreadyConnected,
+ NotConnected,
+ NotBound,
+ NotCreated,
+ WouldBlock,
+ ConnectionRefused,
+ ConnectionTimedOut,
+ InProgress,
+ NetFailure,
+ NotSupported,
+ Timeout,
+ UnknownError,
+ RemotelyDisconnected
+ };
+
+public:
+ /**
+ * Default constructor.
+ */
+ KSocketBase();
+
+ /**
+ * Destructor.
+ */
+ virtual ~KSocketBase();
+
+ /*
+ * The following functions are shared by all descended classes and will have
+ * to be reimplemented.
+ */
+
+protected:
+ /**
+ * Set the given socket options.
+ *
+ * The default implementation does nothing but store the mask internally.
+ * Descended classes must override this function to achieve functionality and
+ * must also call this implementation.
+ *
+ * @param opts a mask of @ref SocketOptions or-ed bits of options to set
+ * or unset
+ * @returns true on success
+ * @note this function sets the options corresponding to the bits enabled in @p opts
+ * but will also unset the optiosn corresponding to the bits not set.
+ */
+ virtual bool setSocketOptions(int opts);
+
+ /**
+ * Retrieves the socket options that have been set.
+ *
+ * The default implementation just retrieves the mask from an internal variable.
+ * Descended classes may choose to override this function to read the values
+ * from the operating system.
+ *
+ * @returns the mask of the options set
+ */
+ virtual int socketOptions() const;
+
+public:
+ /**
+ * Sets this socket's blocking mode.
+ *
+ * In blocking operation, all I/O functions are susceptible to blocking --
+ * i.e., will not return unless the I/O can be satisfied. In non-blocking
+ * operation, if the I/O would block, the function will return an error
+ * and set the corresponding error code.
+ *
+ * The default implementation toggles the Blocking flag with the current
+ * socket options and calls @ref setSocketOptions.
+ *
+ * @param enable whether to set this socket to blocking mode
+ * @returns whether setting this value was successful; it is NOT the
+ * final blocking mode.
+ */
+ virtual bool setBlocking(bool enable);
+
+ /**
+ * Retrieves this socket's blocking mode.
+ *
+ * @returns true if this socket is/will be operated in blocking mode,
+ * false if non-blocking.
+ */
+ bool blocking() const;
+
+ /**
+ * Sets this socket's address reuseable flag.
+ *
+ * When the address reuseable flag is active, the address used by
+ * this socket is left reuseable for other sockets to bind. If
+ * the flag is not active, no other sockets may reuse the same
+ * address.
+ *
+ * The default implementation toggles the AddressReuseable flag with the current
+ * socket options and calls @ref setSocketOptions.
+ *
+ * @param enable whether to set the flag on or off
+ * @returns true if setting this flag was successful
+ */
+ virtual bool setAddressReuseable(bool enable);
+
+ /**
+ * Retrieves this socket's address reuseability flag.
+ *
+ * @returns true if this socket's address can be reused,
+ * false if it can't.
+ */
+ bool addressReuseable() const;
+
+ /**
+ * Sets this socket's IPv6 Only flag.
+ *
+ * When this flag is on, an IPv6 socket will only accept, connect, send to or
+ * receive from IPv6 addresses. When it is off, it will also talk to
+ * IPv4 addresses through v4-mapped addresses.
+ *
+ * This option has no effect on non-IPv6 sockets.
+ *
+ * The default implementation toggles the IPv6Only flag with the current
+ * socket options and calls @ref setSocketOptions.
+ *
+ * @param enable whether to set the flag on or off
+ * @returns true if setting this flag was successful
+ */
+ virtual bool setIPv6Only(bool enable);
+
+ /**
+ * Retrieves this socket's IPv6 Only flag.
+ *
+ * @returns true if this socket will ignore IPv4-compatible and IPv4-mapped
+ * addresses, false if it will accept them.
+ */
+ bool isIPv6Only() const;
+
+ /**
+ * Sets this socket Broadcast flag.
+ *
+ * Datagram-oriented sockets cannot normally send packets to broadcast
+ * addresses, nor will they receive packets that were sent to a broadcast
+ * address. To do so, you need to enable the Broadcast flag.
+ *
+ * This option has no effect on stream-oriented sockets.
+ *
+ * @returns true if setting this flag was successful.
+ */
+ virtual bool setBroadcast(bool enable);
+
+ /**
+ * Retrieves this socket's Broadcast flag.
+ *
+ * @returns true if this socket can send and receive broadcast packets,
+ * false if it can't.
+ */
+ bool broadcast() const;
+
+ /**
+ * Retrieves the socket implementation used on this socket.
+ *
+ * This function creates the device if none has been set
+ * using the default factory.
+ */
+ KSocketDevice* socketDevice() const;
+
+ /**
+ * Sets the socket implementation to be used on this socket.
+ *
+ * Note: it is an error to set this if the socket device has
+ * already been set once.
+ *
+ * This function is provided virtual so that derived classes can catch
+ * the setting of a device and properly set their own states and internal
+ * variables. The parent class must be called.
+ *
+ * This function is called by @ref socketDevice above when the socket is
+ * first created.
+ */
+ virtual void setSocketDevice(KSocketDevice* device);
+
+ /**
+ * Sets the internally requested capabilities for a socket device.
+ *
+ * Most socket classes can use any back-end implementation. However, a few
+ * may require specific capabilities not provided in the default
+ * implementation. By using this function, derived classes can request
+ * that a backend with those capabilities be created when necessary.
+ *
+ * For the possible flags, see @ref KSocketDevice::Capabilities. However, note
+ * that only the Can* flags make sense in this context.
+ *
+ * @note Since socketDevice must always return a valid backend object, it
+ * is is possible that the created device does not conform to all
+ * requirements requested. Implementations sensitive to this fact
+ * should test the object returned by @ref socketDevice (through
+ * @ref KSocketDevice::capabilities, for instance) the availability.
+ *
+ * @param add mask of @ref KSocketDevice::Capabilities to add
+ * @param remove mask of bits to remove from the requirements
+ * @return the current mask of requested capabilities
+ */
+ int setRequestedCapabilities(int add, int remove = 0);
+
+protected:
+ /**
+ * Returns true if the socket device has been initialised in this
+ * object, either by calling @ref socketDevice() or @ref setSocketDevice
+ */
+ bool hasDevice() const;
+
+ /**
+ * Sets the socket's error code.
+ *
+ * @param error the error code
+ */
+ void setError(SocketError error);
+
+public:
+ /**
+ * Retrieves the socket error code.
+ * @sa errorString
+ */
+ SocketError error() const;
+
+ /**
+ * Returns the error string corresponding to this error condition.
+ */
+ inline QString errorString() const
+ { return errorString(error()); }
+
+ /**
+ * Returns the internal mutex for this class.
+ *
+ * Note on multithreaded use of sockets:
+ * the socket classes are thread-safe by design, but you should be aware of
+ * problems regarding socket creation, connection and destruction in
+ * multi-threaded programs. The classes are guaranteed to work while
+ * the socket exists, but it's not wise to call connect in multiple
+ * threads.
+ *
+ * Also, this mutex must be unlocked before the object is destroyed, which
+ * means you cannot use it to guard against other threads accessing the object
+ * while destroying it. You must ensure there are no further references to this
+ * object when deleting it.
+ */
+ QMutex* mutex() const;
+
+public:
+ /**
+ * Returns the string describing the given error code, i18n'ed.
+ *
+ * @param code the error code
+ */
+ static QString errorString(SocketError code);
+
+ /**
+ * Returns true if the given error code is a fatal one, false
+ * otherwise. The parameter here is of type int so that
+ * casting isn't necessary when using the parameter to signal
+ * QClientSocketBase::gotError.
+ *
+ * @param code the code to test
+ */
+ static bool isFatalError(int code);
+
+private:
+ /// @internal
+ /// called by KSocketDevice
+ void unsetSocketDevice();
+
+ KSocketBase(const KSocketBase&);
+ KSocketBase& operator =(const KSocketBase&);
+
+ KSocketBasePrivate *d;
+
+ friend class KSocketDevice;
+};
+
+/**
+ * @class KActiveSocketBase ksocketbase.h ksocketbase.h
+ * @brief Abstract class for active sockets
+ *
+ * This class provides the standard interfaces for active sockets, i.e.,
+ * sockets that are used to connect to external addresses.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KActiveSocketBase: public QIODevice, virtual public KSocketBase
+{
+public:
+ /**
+ * Constructor.
+ */
+ KActiveSocketBase();
+
+ /**
+ * Destructor.
+ */
+ virtual ~KActiveSocketBase();
+
+ /**
+ * Binds this socket to the given address.
+ *
+ * The socket will be constructed with the address family,
+ * socket type and protocol as those given in the
+ * @p address object.
+ *
+ * @param address the address to bind to
+ * @returns true if the binding was successful, false otherwise
+ */
+ virtual bool bind(const KResolverEntry& address) = 0;
+
+ /**
+ * Connect to a remote host.
+ *
+ * This will make this socket try to connect to the remote host.
+ * If the socket is not yet created, it will be created using the
+ * address family, socket type and protocol specified in the
+ * @p address object.
+ *
+ * If this function returns with error InProgress, calling it
+ * again with the same address after a time will cause it to test
+ * if the connection has succeeded in the mean time.
+ *
+ * @param address the address to connect to
+ * @returns true if the connection was successful or has been successfully
+ * queued; false if an error occurred.
+ */
+ virtual bool connect(const KResolverEntry& address) = 0;
+
+ /**
+ * Disconnects this socket from a connection, if possible.
+ *
+ * If this socket was connected to an endpoint, the connection
+ * is severed, but the socket is not closed. If the socket wasn't
+ * connected, this function does nothing.
+ *
+ * If the socket hadn't yet been created, this function does nothing
+ * either.
+ *
+ * Not all socket types can disconnect. Most notably, only
+ * connectionless datagram protocols such as UDP support this operation.
+ *
+ * @return true if the socket is now disconnected or false on error.
+ */
+ virtual bool disconnect() = 0;
+
+ /**
+ * This call is not supported on sockets. Reimplemented from QIODevice.
+ * This will always return 0.
+ */
+ virtual Offset size() const
+ { return 0; }
+
+ /**
+ * This call is not supported on sockets. Reimplemented from QIODevice.
+ * This will always return 0.
+ */
+ virtual Offset at() const
+ { return 0; }
+
+ /**
+ * This call is not supported on sockets. Reimplemented from QIODevice.
+ * This will always return false.
+ */
+ virtual bool at(Offset)
+ { return false; }
+
+ /**
+ * This call is not supported on sockets. Reimplemented from QIODevice.
+ * This will always return true.
+ */
+ virtual bool atEnd() const
+ { return true; }
+
+ /**
+ * Returns the number of bytes available for reading without
+ * blocking.
+ */
+ virtual Q_LONG bytesAvailable() const = 0;
+
+ /**
+ * Waits up to @p msecs for more data to be available on this socket.
+ *
+ * If msecs is -1, this call will block indefinetely until more data
+ * is indeed available; if it's 0, this function returns immediately.
+ *
+ * If @p timeout is not NULL, this function will set it to indicate
+ * if a timeout occurred.
+ *
+ * @returns the number of bytes available
+ */
+ virtual Q_LONG waitForMore(int msecs, bool *timeout = 0L) = 0;
+
+ /**
+ * Reads data from the socket.
+ *
+ * Reimplemented from QIODevice. See QIODevice::readBlock for
+ * more information.
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG len) = 0;
+
+ /** @overload
+ * Receives data and the source address.
+ *
+ * This call will read data in the socket and will also
+ * place the sender's address in @p from object.
+ *
+ * @param data where to write the read data to
+ * @param maxlen the maximum number of bytes to read
+ * @param from the address of the sender will be stored here
+ * @returns the actual number of bytes read
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) = 0;
+
+ /**
+ * Peeks the data in the socket.
+ *
+ * This call will allow you to peek the data to be received without actually
+ * receiving it -- that is, it will be available for further peekings and
+ * for the next read call.
+ *
+ * @param data where to write the peeked data to
+ * @param maxlen the maximum number of bytes to peek
+ * @returns the actual number of bytes copied into @p data
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen) = 0;
+
+ /** @overload
+ * Peeks the data in the socket and the source address.
+ *
+ * This call will allow you to peek the data to be received without actually
+ * receiving it -- that is, it will be available for further peekings and
+ * for the next read call.
+ *
+ * @param data where to write the peeked data to
+ * @param maxlen the maximum number of bytes to peek
+ * @param from the address of the sender will be stored here
+ * @returns the actual number of bytes copied into @p data
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) = 0;
+
+ /**
+ * Writes the given data to the socket.
+ *
+ * Reimplemented from QIODevice. See QIODevice::writeBlock for
+ * more information.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len) = 0;
+
+ /** @overload
+ * Writes the given data to the destination address.
+ *
+ * Note that not all socket connections allow sending data to different
+ * addresses than the one the socket is connected to.
+ *
+ * @param data the data to write
+ * @param len the length of the data
+ * @param to the address to send to
+ * @returns the number of bytes actually sent
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to) = 0;
+
+ /**
+ * Reads one character from the socket.
+ * Reimplementation from QIODevice. See QIODevice::getch for more information.
+ */
+ virtual int getch();
+
+ /**
+ * Writes one character to the socket.
+ * Reimplementation from QIODevice. See QIODevice::putch for more information.
+ */
+ virtual int putch(int ch);
+
+ /**
+ * This call is not supported on sockets. Reimplemented from QIODevice.
+ * This will always return -1;
+ */
+ virtual int ungetch(int)
+ { return -1; }
+
+ /**
+ * Returns this socket's local address.
+ */
+ virtual KSocketAddress localAddress() const = 0;
+
+ /**
+ * Return this socket's peer address, if we are connected.
+ * If the address cannot be retrieved, the returned object will contain
+ * an invalid address.
+ */
+ virtual KSocketAddress peerAddress() const = 0;
+
+ // FIXME KDE 4.0:
+ // enable this function
+#if 0
+ /**
+ * Returns this socket's externally-visible address, if known.
+ */
+ virtual KSocketAddress externalAddress() const = 0;
+#endif
+
+protected:
+ /**
+ * Sets the socket's error code and the I/O Device's status.
+ *
+ * @param status the I/O Device status
+ * @param error the error code
+ */
+ void setError(int status, SocketError error);
+
+ /**
+ * Resets the socket error code and the I/O Device's status.
+ */
+ void resetError();
+};
+
+/**
+ * @class KPassiveSocketBase ksocketbase.h ksocketbase.h
+ * @brief Abstract base class for passive sockets.
+ *
+ * This socket provides the initial functionality for passive sockets,
+ * i.e., sockets that accept incoming connections.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KPassiveSocketBase: virtual public KSocketBase
+{
+public:
+ /**
+ * Constructor
+ */
+ KPassiveSocketBase();
+
+ /**
+ * Destructor
+ */
+ virtual ~KPassiveSocketBase();
+
+ /**
+ * Binds this socket to the given address.
+ *
+ * The socket will be constructed with the address family,
+ * socket type and protocol as those given in the
+ * @p address object.
+ *
+ * @param address the address to bind to
+ * @returns true if the binding was successful, false otherwise
+ */
+ virtual bool bind(const KResolverEntry& address) = 0;
+
+ /**
+ * Puts this socket into listening mode.
+ *
+ * Placing a socket in listening mode means that it will
+ * be allowed to receive incoming connections from
+ * remote hosts.
+ *
+ * Note that some socket types or protocols cannot be
+ * put in listening mode.
+ *
+ * @param backlog the number of accepted connections to
+ * hold before starting to refuse
+ * @returns true if the socket is now in listening mode
+ */
+ virtual bool listen(int backlog) = 0;
+
+ /**
+ * Closes this socket. All resources used are freed. Note that closing
+ * a passive socket does not close the connections accepted with it.
+ */
+ virtual void close() = 0;
+
+ /**
+ * Accepts a new incoming connection.
+ *
+ * If this socket was in listening mode, you can call this
+ * function to accept an incoming connection.
+ *
+ * If this function cannot accept a new connection (either
+ * because it is not listening for one or because the operation
+ * would block), it will return NULL.
+ *
+ * Also note that descended classes will override this function
+ * to return specialised socket classes.
+ */
+ virtual KActiveSocketBase* accept() = 0;
+
+ /**
+ * Returns this socket's local address.
+ */
+ virtual KSocketAddress localAddress() const = 0;
+
+ /**
+ * Returns this socket's externally-visible address if known.
+ */
+ virtual KSocketAddress externalAddress() const = 0;
+
+private:
+ KPassiveSocketBase(const KPassiveSocketBase&);
+ KPassiveSocketBase& operator = (const KPassiveSocketBase&);
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/ksocketbuffer.cpp b/kdecore/network/ksocketbuffer.cpp
new file mode 100644
index 000000000..d458a4f15
--- /dev/null
+++ b/kdecore/network/ksocketbuffer.cpp
@@ -0,0 +1,329 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include "ksocketbase.h"
+#include "ksocketbuffer_p.h"
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+KSocketBuffer::KSocketBuffer(Q_LONG size)
+ : m_mutex(true), m_offset(0), m_size(size), m_length(0)
+{
+}
+
+KSocketBuffer::KSocketBuffer(const KSocketBuffer& other)
+ : KIOBufferBase(other), m_mutex(true)
+{
+ *this = other;
+}
+
+KSocketBuffer::~KSocketBuffer()
+{
+ // QValueList takes care of deallocating memory
+}
+
+KSocketBuffer& KSocketBuffer::operator=(const KSocketBuffer& other)
+{
+ QMutexLocker locker1(&m_mutex);
+ QMutexLocker locker2(&other.m_mutex);
+
+ KIOBufferBase::operator=(other);
+
+ m_list = other.m_list; // copy-on-write
+ m_offset = other.m_offset;
+ m_size = other.m_size;
+ m_length = other.m_length;
+
+ return *this;
+}
+
+bool KSocketBuffer::canReadLine() const
+{
+ QMutexLocker locker(&m_mutex);
+
+ QValueListConstIterator<QByteArray> it = m_list.constBegin(),
+ end = m_list.constEnd();
+ QIODevice::Offset offset = m_offset;
+
+ // walk the buffer
+ for ( ; it != end; ++it)
+ {
+ if ((*it).find('\n', offset) != -1)
+ return true;
+ if ((*it).find('\r', offset) != -1)
+ return true;
+ offset = 0;
+ }
+
+ return false; // not found
+}
+
+QCString KSocketBuffer::readLine()
+{
+ if (!canReadLine())
+ return QCString(); // empty
+
+ QMutexLocker locker(&m_mutex);
+
+ // find the offset of the newline in the buffer
+ int newline = 0;
+ QValueListConstIterator<QByteArray> it = m_list.constBegin(),
+ end = m_list.constEnd();
+ QIODevice::Offset offset = m_offset;
+
+ // walk the buffer
+ for ( ; it != end; ++it)
+ {
+ int posnl = (*it).find('\n', offset);
+ if (posnl == -1)
+ {
+ // not found in this one
+ newline += (*it).size();
+ offset = 0;
+ continue;
+ }
+
+ // we found it
+ newline += posnl;
+ break;
+ }
+
+ QCString result(newline + 2 - m_offset);
+ consumeBuffer(result.data(), newline + 1 - m_offset);
+ return result;
+}
+
+Q_LONG KSocketBuffer::length() const
+{
+ return m_length;
+}
+
+Q_LONG KSocketBuffer::size() const
+{
+ return m_size;
+}
+
+bool KSocketBuffer::setSize(Q_LONG size)
+{
+ m_size = size;
+ if (size == -1 || m_length < m_size)
+ return true;
+
+ // size is now smaller than length
+ QMutexLocker locker(&m_mutex);
+
+ // repeat the test
+ if (m_length < m_size)
+ return true;
+
+ // discard from the beginning
+ return (m_length - m_size) == consumeBuffer(0L, m_length - m_size, true);
+}
+
+Q_LONG KSocketBuffer::feedBuffer(const char *data, Q_LONG len)
+{
+ if (data == 0L || len == 0)
+ return 0; // nothing to write
+ if (isFull())
+ return -1; // can't write
+
+ QMutexLocker locker(&m_mutex);
+
+ // verify if we can add len bytes
+ if (m_size != -1 && (m_size - m_length) < len)
+ len = m_size - m_length;
+
+ QByteArray a(len);
+ a.duplicate(data, len);
+ m_list.append(a);
+
+ m_length += len;
+ return len;
+}
+
+Q_LONG KSocketBuffer::consumeBuffer(char *destbuffer, Q_LONG maxlen, bool discard)
+{
+ if (maxlen == 0 || isEmpty())
+ return 0;
+
+ QValueListIterator<QByteArray> it = m_list.begin(),
+ end = m_list.end();
+ QIODevice::Offset offset = m_offset;
+ Q_LONG copied = 0;
+
+ // walk the buffer
+ while (it != end && maxlen)
+ {
+ // calculate how much we'll copy
+ size_t to_copy = (*it).size() - offset;
+ if (to_copy > maxlen)
+ to_copy = maxlen;
+
+ // do the copying
+ if (destbuffer)
+ memcpy(destbuffer + copied, (*it).data() + offset, to_copy);
+ maxlen -= to_copy;
+ copied += to_copy;
+
+ if ((*it).size() - offset > to_copy)
+ {
+ // we did not copy everything
+ offset += to_copy;
+ break;
+ }
+ else
+ {
+ // we copied everything
+ // discard this element;
+ offset = 0;
+ if (discard)
+ it = m_list.remove(it);
+ else
+ ++it;
+ }
+ }
+
+ if (discard)
+ {
+ m_offset = offset;
+ m_length -= copied;
+ assert(m_length >= 0);
+ }
+
+ return copied;
+}
+
+void KSocketBuffer::clear()
+{
+ QMutexLocker locker(&m_mutex);
+ m_list.clear();
+ m_offset = 0;
+ m_length = 0;
+}
+
+Q_LONG KSocketBuffer::sendTo(KActiveSocketBase* dev, Q_LONG len)
+{
+ if (len == 0 || isEmpty())
+ return 0;
+
+ QMutexLocker locker(&m_mutex);
+
+ QValueListIterator<QByteArray> it = m_list.begin(),
+ end = m_list.end();
+ QIODevice::Offset offset = m_offset;
+ Q_LONG written = 0;
+
+ // walk the buffer
+ while (it != end && (len || len == -1))
+ {
+ // we have to write each element up to len bytes
+ // but since we can have several very small buffers, we can make things
+ // better by concatenating a few of them into a big buffer
+ // question is: how big should that buffer be? 2 kB should be enough
+
+ Q_ULONG bufsize = 1460;
+ if (len != -1 && len < bufsize)
+ bufsize = len;
+ QByteArray buf(bufsize);
+ Q_LONG count = 0;
+
+ while (it != end && count + ((*it).size() - offset) <= bufsize)
+ {
+ memcpy(buf.data() + count, (*it).data() + offset, (*it).size() - offset);
+ count += (*it).size() - offset;
+ offset = 0;
+ ++it;
+ }
+
+ // see if we can still fit more
+ if (count < bufsize && it != end)
+ {
+ // getting here means this buffer (*it) is larger than
+ // (bufsize - count) (even for count == 0).
+ memcpy(buf.data() + count, (*it).data() + offset, bufsize - count);
+ offset += bufsize - count;
+ count = bufsize;
+ }
+
+ // now try to write those bytes
+ Q_LONG wrote = dev->writeBlock(buf, count);
+
+ if (wrote == -1)
+ // error?
+ break;
+
+ written += wrote;
+ if (wrote != count)
+ // can't fit more?
+ break;
+ }
+
+ // discard data that has been written
+ // this updates m_length too
+ if (written)
+ consumeBuffer(0L, written);
+
+ return written;
+}
+
+Q_LONG KSocketBuffer::receiveFrom(KActiveSocketBase* dev, Q_LONG len)
+{
+ if (len == 0 || isFull())
+ return 0;
+
+ QMutexLocker locker(&m_mutex);
+
+ if (len == -1)
+ len = dev->bytesAvailable();
+ if (len <= 0)
+ // error or closing socket
+ return len;
+
+ // see if we can read that much
+ if (m_size != -1 && len > (m_size - m_length))
+ len = m_size - m_length;
+
+ // here, len contains just as many bytes as we're supposed to read
+
+ // now do the reading
+ QByteArray a(len);
+ len = dev->readBlock(a.data(), len);
+
+ if (len == -1)
+ // error?
+ return -1;
+
+ // success
+ // resize the buffer and add it
+ a.truncate(len);
+ m_list.append(a);
+ m_length += len;
+ return len;
+}
diff --git a/kdecore/network/ksocketbuffer_p.h b/kdecore/network/ksocketbuffer_p.h
new file mode 100644
index 000000000..ddcc692bd
--- /dev/null
+++ b/kdecore/network/ksocketbuffer_p.h
@@ -0,0 +1,164 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KSOCKETBUFFER_P_H
+#define KSOCKETBUFFER_P_H
+
+#include <qmutex.h>
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include "kiobuffer.h"
+
+namespace KNetwork {
+
+class KActiveSocketBase;
+
+ namespace Internal {
+
+/**
+ * @internal
+ * @class KSocketBuffer ksocketbuffer_p.h ksocketbuffer_p.h
+ * @brief generic socket buffering code
+ *
+ * This class implements generic buffering used by @ref KBufferedSocket.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KSocketBuffer: public KIOBufferBase
+{
+public:
+ /**
+ * Default constructor.
+ *
+ * @param size the maximum size of the buffer
+ */
+ KSocketBuffer(Q_LONG size = -1);
+
+ /**
+ * Copy constructor.
+ */
+ KSocketBuffer(const KSocketBuffer& other);
+
+ /**
+ * Virtual destructor. Frees the buffer and discards its contents.
+ */
+ virtual ~KSocketBuffer();
+
+ /**
+ * Assignment operator.
+ */
+ KSocketBuffer& operator=(const KSocketBuffer& other);
+
+ /**
+ * Returns true if a line can be read from the buffer.
+ */
+ virtual bool canReadLine() const;
+
+ /**
+ * Reads a line from the buffer and discard it from the buffer.
+ */
+ virtual QCString readLine();
+
+ /**
+ * Returns the number of bytes in the buffer. Note that this is not
+ * the size of the buffer.
+ *
+ * @sa size
+ */
+ virtual Q_LONG length() const;
+
+ /**
+ * Retrieves the buffer size. The value of -1 indicates that
+ * the buffer has no defined upper limit.
+ *
+ * @sa length for the length of the data stored
+ */
+ virtual Q_LONG size() const;
+
+ /**
+ * Sets the size of the buffer, if allowed.
+ *
+ * @param size the maximum size, use -1 for unlimited.
+ * @returns true on success, false if an error occurred.
+ * @note if the new size is less than length(), the buffer will be truncated
+ */
+ virtual bool setSize(Q_LONG size);
+
+ /**
+ * Adds data to the end of the buffer.
+ *
+ * @param data the data to be added
+ * @param len the data length, in bytes
+ * @returns the number of bytes added to the end of the buffer.
+ */
+ virtual Q_LONG feedBuffer(const char *data, Q_LONG len);
+
+ /**
+ * Clears the buffer.
+ */
+ virtual void clear();
+
+ /**
+ * Consumes data from the beginning of the buffer.
+ *
+ * @param data where to copy the data to
+ * @param maxlen the maximum length to copy, in bytes
+ * @param discard if true, the bytes copied will be discarded
+ * @returns the number of bytes copied from the buffer
+ */
+ virtual Q_LONG consumeBuffer(char *data, Q_LONG maxlen, bool discard = true);
+
+ /**
+ * Sends at most @p len bytes of data to the I/O Device.
+ *
+ * @param device the device to which to send data
+ * @param len the amount of data to send; -1 to send everything
+ * @returns the number of bytes sent and discarded from the buffer, -1
+ * indicates an error.
+ */
+ virtual Q_LONG sendTo(KActiveSocketBase* device, Q_LONG len = -1);
+
+ /**
+ * Tries to receive @p len bytes of data from the I/O device.
+ *
+ * @param device the device to receive from
+ * @param len the number of bytes to receive; -1 to read as much
+ * as possible
+ * @returns the number of bytes received and copied into the buffer,
+ * -1 indicates an error.
+ */
+ virtual Q_LONG receiveFrom(KActiveSocketBase* device, Q_LONG len = -1);
+
+protected:
+ mutable QMutex m_mutex;
+ QValueList<QByteArray> m_list;
+ QIODevice::Offset m_offset; ///< offset of the start of data in the first element
+
+ Q_LONG m_size; ///< the maximum length of the buffer
+ mutable Q_LONG m_length;
+};
+
+} } // namespace KNetwork::Internal
+
+#endif
diff --git a/kdecore/network/ksocketdevice.cpp b/kdecore/network/ksocketdevice.cpp
new file mode 100644
index 000000000..b3004ccc2
--- /dev/null
+++ b/kdecore/network/ksocketdevice.cpp
@@ -0,0 +1,886 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003,2005 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <qmap.h>
+
+#ifdef USE_SOLARIS
+# include <sys/filio.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#ifdef HAVE_POLL
+# include <sys/poll.h>
+#else
+# ifdef HAVE_SYS_SELECT
+# include <sys/select.h>
+# endif
+#endif
+
+// Include syssocket before our local includes
+#include "syssocket.h"
+
+#include <qmutex.h>
+#include <qsocketnotifier.h>
+
+#include "kresolver.h"
+#include "ksocketaddress.h"
+#include "ksocketbase.h"
+#include "ksocketdevice.h"
+#include "ksockssocketdevice.h"
+
+using namespace KNetwork;
+
+class KNetwork::KSocketDevicePrivate
+{
+public:
+ mutable QSocketNotifier *input, *output, *exception;
+ KSocketAddress local, peer;
+ int af;
+
+ inline KSocketDevicePrivate()
+ {
+ input = output = exception = 0L;
+ af = 0;
+ }
+};
+
+
+KSocketDevice::KSocketDevice(const KSocketBase* parent)
+ : m_sockfd(-1), d(new KSocketDevicePrivate)
+{
+ setSocketDevice(this);
+ if (parent)
+ setSocketOptions(parent->socketOptions());
+}
+
+KSocketDevice::KSocketDevice(int fd)
+ : m_sockfd(fd), d(new KSocketDevicePrivate)
+{
+ setState(IO_Open);
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite);
+ setSocketDevice(this);
+ d->af = localAddress().family();
+}
+
+KSocketDevice::KSocketDevice(bool, const KSocketBase* parent)
+ : m_sockfd(-1), d(new KSocketDevicePrivate)
+{
+ // do not set parent
+ if (parent)
+ setSocketOptions(parent->socketOptions());
+}
+
+KSocketDevice::~KSocketDevice()
+{
+ close(); // deletes the notifiers
+ unsetSocketDevice(); // prevent double deletion
+ delete d;
+}
+
+bool KSocketDevice::setSocketOptions(int opts)
+{
+ // must call parent
+ QMutexLocker locker(mutex());
+ KSocketBase::setSocketOptions(opts);
+
+ if (m_sockfd == -1)
+ return true; // flags are stored
+
+ {
+ int fdflags = fcntl(m_sockfd, F_GETFL, 0);
+ if (fdflags == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false; // error
+ }
+
+ if (opts & Blocking)
+ fdflags &= ~O_NONBLOCK;
+ else
+ fdflags |= O_NONBLOCK;
+
+ if (fcntl(m_sockfd, F_SETFL, fdflags) == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false; // error
+ }
+ }
+
+ {
+ int on = opts & AddressReuseable ? 1 : 0;
+ if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false; // error
+ }
+ }
+
+#if defined(IPV6_V6ONLY) && defined(AF_INET6)
+ if (d->af == AF_INET6)
+ {
+ // don't try this on non-IPv6 sockets, or we'll get an error
+
+ int on = opts & IPv6Only ? 1 : 0;
+ if (setsockopt(m_sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&on, sizeof(on)) == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false; // error
+ }
+ }
+#endif
+
+ {
+ int on = opts & Broadcast ? 1 : 0;
+ if (setsockopt(m_sockfd, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on)) == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false; // error
+ }
+ }
+
+ return true; // all went well
+}
+
+bool KSocketDevice::open(int)
+{
+ resetError();
+ return false;
+}
+
+void KSocketDevice::close()
+{
+ resetError();
+ if (m_sockfd != -1)
+ {
+ delete d->input;
+ delete d->output;
+ delete d->exception;
+
+ d->input = d->output = d->exception = 0L;
+
+ d->local.setFamily(AF_UNSPEC);
+ d->peer.setFamily(AF_UNSPEC);
+
+ ::close(m_sockfd);
+ }
+ setState(0);
+
+ m_sockfd = -1;
+}
+
+bool KSocketDevice::create(int family, int type, int protocol)
+{
+ resetError();
+
+ if (m_sockfd != -1)
+ {
+ // it's already created!
+ setError(IO_SocketCreateError, AlreadyCreated);
+ return false;
+ }
+
+ // no socket yet; we have to create it
+ m_sockfd = kde_socket(family, type, protocol);
+
+ if (m_sockfd == -1)
+ {
+ setError(IO_SocketCreateError, NotSupported);
+ return false;
+ }
+
+ d->af = family;
+ setSocketOptions(socketOptions());
+ setState(IO_Open);
+ return true; // successfully created
+}
+
+bool KSocketDevice::create(const KResolverEntry& address)
+{
+ return create(address.family(), address.socketType(), address.protocol());
+}
+
+bool KSocketDevice::bind(const KResolverEntry& address)
+{
+ resetError();
+
+ if (m_sockfd == -1 && !create(address))
+ return false; // failed creating
+
+ // we have a socket, so try and bind
+ if (kde_bind(m_sockfd, address.address(), address.length()) == -1)
+ {
+ if (errno == EADDRINUSE)
+ setError(IO_BindError, AddressInUse);
+ else if (errno == EINVAL)
+ setError(IO_BindError, AlreadyBound);
+ else
+ // assume the address is the cause
+ setError(IO_BindError, NotSupported);
+ return false;
+ }
+
+ return true;
+}
+
+bool KSocketDevice::listen(int backlog)
+{
+ if (m_sockfd != -1)
+ {
+ if (kde_listen(m_sockfd, backlog) == -1)
+ {
+ setError(IO_ListenError, NotSupported);
+ return false;
+ }
+
+ resetError();
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite);
+ return true;
+ }
+
+ // we don't have a socket
+ // can't listen
+ setError(IO_ListenError, NotCreated);
+ return false;
+}
+
+bool KSocketDevice::connect(const KResolverEntry& address)
+{
+ resetError();
+
+ if (m_sockfd == -1 && !create(address))
+ return false; // failed creating!
+
+ if (kde_connect(m_sockfd, address.address(), address.length()) == -1)
+ {
+ if (errno == EISCONN)
+ return true; // we're already connected
+ else if (errno == EALREADY || errno == EINPROGRESS)
+ {
+ setError(IO_ConnectError, InProgress);
+ return true;
+ }
+ else if (errno == ECONNREFUSED)
+ setError(IO_ConnectError, ConnectionRefused);
+ else if (errno == ENETDOWN || errno == ENETUNREACH ||
+ errno == ENETRESET || errno == ECONNABORTED ||
+ errno == ECONNRESET || errno == EHOSTDOWN ||
+ errno == EHOSTUNREACH)
+ setError(IO_ConnectError, NetFailure);
+ else
+ setError(IO_ConnectError, NotSupported);
+
+ return false;
+ }
+
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite);
+ return true; // all is well
+}
+
+KSocketDevice* KSocketDevice::accept()
+{
+ if (m_sockfd == -1)
+ {
+ // can't accept without a socket
+ setError(IO_AcceptError, NotCreated);
+ return 0L;
+ }
+
+ struct sockaddr sa;
+ socklen_t len = sizeof(sa);
+ int newfd = kde_accept(m_sockfd, &sa, &len);
+ if (newfd == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ setError(IO_AcceptError, WouldBlock);
+ else
+ setError(IO_AcceptError, UnknownError);
+ return NULL;
+ }
+
+ return new KSocketDevice(newfd);
+}
+
+bool KSocketDevice::disconnect()
+{
+ resetError();
+
+ if (m_sockfd == -1)
+ return false; // can't create
+
+ KSocketAddress address;
+ address.setFamily(AF_UNSPEC);
+ if (kde_connect(m_sockfd, address.address(), address.length()) == -1)
+ {
+ if (errno == EALREADY || errno == EINPROGRESS)
+ {
+ setError(IO_ConnectError, InProgress);
+ return false;
+ }
+ else if (errno == ECONNREFUSED)
+ setError(IO_ConnectError, ConnectionRefused);
+ else if (errno == ENETDOWN || errno == ENETUNREACH ||
+ errno == ENETRESET || errno == ECONNABORTED ||
+ errno == ECONNRESET || errno == EHOSTDOWN ||
+ errno == EHOSTUNREACH)
+ setError(IO_ConnectError, NetFailure);
+ else
+ setError(IO_ConnectError, NotSupported);
+
+ return false;
+ }
+
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite);
+ setState(IO_Open);
+ return true; // all is well
+}
+
+Q_LONG KSocketDevice::bytesAvailable() const
+{
+ if (m_sockfd == -1)
+ return -1; // there's nothing to read in a closed socket
+
+ int nchars;
+ if (ioctl(m_sockfd, FIONREAD, &nchars) == -1)
+ return -1; // error!
+
+ return nchars;
+}
+
+Q_LONG KSocketDevice::waitForMore(int msecs, bool *timeout)
+{
+ if (m_sockfd == -1)
+ return -1; // there won't ever be anything to read...
+
+ bool input;
+ if (!poll(&input, 0, 0, msecs, timeout))
+ return -1; // failed polling
+
+ return bytesAvailable();
+}
+
+static int do_read_common(int sockfd, char *data, Q_ULONG maxlen, KSocketAddress* from, ssize_t &retval, bool peek = false)
+{
+ socklen_t len;
+ if (from)
+ {
+ from->setLength(len = 128); // arbitrary length
+ retval = ::recvfrom(sockfd, data, maxlen, peek ? MSG_PEEK : 0, from->address(), &len);
+ }
+ else
+ retval = ::recvfrom(sockfd, data, maxlen, peek ? MSG_PEEK : 0, NULL, NULL);
+
+ if (retval == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return KSocketDevice::WouldBlock;
+ else
+ return KSocketDevice::UnknownError;
+ }
+ if (retval == 0)
+ return KSocketDevice::RemotelyDisconnected;
+
+ if (from)
+ from->setLength(len);
+ return 0;
+}
+
+Q_LONG KSocketDevice::readBlock(char *data, Q_ULONG maxlen)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1;
+
+ if (maxlen == 0 || data == 0L)
+ return 0; // can't read
+
+ ssize_t retval;
+ int err = do_read_common(m_sockfd, data, maxlen, 0L, retval);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocketDevice::readBlock(char *data, Q_ULONG maxlen, KSocketAddress &from)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1; // nothing to do here
+
+ if (data == 0L || maxlen == 0)
+ return 0; // user doesn't want to read
+
+ ssize_t retval;
+ int err = do_read_common(m_sockfd, data, maxlen, &from, retval);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocketDevice::peekBlock(char *data, Q_ULONG maxlen)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1;
+
+ if (maxlen == 0 || data == 0L)
+ return 0; // can't read
+
+ ssize_t retval;
+ int err = do_read_common(m_sockfd, data, maxlen, 0L, retval, true);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocketDevice::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1; // nothing to do here
+
+ if (data == 0L || maxlen == 0)
+ return 0; // user doesn't want to read
+
+ ssize_t retval;
+ int err = do_read_common(m_sockfd, data, maxlen, &from, retval, true);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocketDevice::writeBlock(const char *data, Q_ULONG len)
+{
+ return writeBlock(data, len, KSocketAddress());
+}
+
+Q_LONG KSocketDevice::writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1; // can't write to unopen socket
+
+ if (data == 0L || len == 0)
+ return 0; // nothing to be written
+
+ ssize_t retval = ::sendto(m_sockfd, data, len, 0, to.address(), to.length());
+ if (retval == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ setError(IO_WriteError, WouldBlock);
+ else
+ setError(IO_WriteError, UnknownError);
+ return -1; // nothing written
+ }
+ else if (retval == 0)
+ setError(IO_WriteError, RemotelyDisconnected);
+
+ return retval;
+}
+
+KSocketAddress KSocketDevice::localAddress() const
+{
+ if (m_sockfd == -1)
+ return KSocketAddress(); // not open, empty value
+
+ if (d->local.family() != AF_UNSPEC)
+ return d->local;
+
+ socklen_t len;
+ KSocketAddress localAddress;
+ localAddress.setLength(len = 32); // arbitrary value
+ if (kde_getsockname(m_sockfd, localAddress.address(), &len) == -1)
+ // error!
+ return d->local = KSocketAddress();
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ len = localAddress.address()->sa_len;
+#endif
+
+ if (len <= localAddress.length())
+ {
+ // it has fit already
+ localAddress.setLength(len);
+ return d->local = localAddress;
+ }
+
+ // no, the socket address is actually larger than we had anticipated
+ // call again
+ localAddress.setLength(len);
+ if (kde_getsockname(m_sockfd, localAddress.address(), &len) == -1)
+ // error!
+ return d->local = KSocketAddress();
+
+ return d->local = localAddress;
+}
+
+KSocketAddress KSocketDevice::peerAddress() const
+{
+ if (m_sockfd == -1)
+ return KSocketAddress(); // not open, empty value
+
+ if (d->peer.family() != AF_UNSPEC)
+ return d->peer;
+
+ socklen_t len;
+ KSocketAddress peerAddress;
+ peerAddress.setLength(len = 32); // arbitrary value
+ if (kde_getpeername(m_sockfd, peerAddress.address(), &len) == -1)
+ // error!
+ return d->peer = KSocketAddress();
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ len = peerAddress.address()->sa_len;
+#endif
+
+ if (len <= peerAddress.length())
+ {
+ // it has fit already
+ peerAddress.setLength(len);
+ return d->peer = peerAddress;
+ }
+
+ // no, the socket address is actually larger than we had anticipated
+ // call again
+ peerAddress.setLength(len);
+ if (kde_getpeername(m_sockfd, peerAddress.address(), &len) == -1)
+ // error!
+ return d->peer = KSocketAddress();
+
+ return d->peer = peerAddress;
+}
+
+KSocketAddress KSocketDevice::externalAddress() const
+{
+ // for normal sockets, the externally visible address is the same
+ // as the local address
+ return localAddress();
+}
+
+QSocketNotifier* KSocketDevice::readNotifier() const
+{
+ if (d->input)
+ return d->input;
+
+ QMutexLocker locker(mutex());
+ if (d->input)
+ return d->input;
+
+ if (m_sockfd == -1)
+ {
+ // socket doesn't exist; can't create notifier
+ return 0L;
+ }
+
+ return d->input = createNotifier(QSocketNotifier::Read);
+}
+
+QSocketNotifier* KSocketDevice::writeNotifier() const
+{
+ if (d->output)
+ return d->output;
+
+ QMutexLocker locker(mutex());
+ if (d->output)
+ return d->output;
+
+ if (m_sockfd == -1)
+ {
+ // socket doesn't exist; can't create notifier
+ return 0L;
+ }
+
+ return d->output = createNotifier(QSocketNotifier::Write);
+}
+
+QSocketNotifier* KSocketDevice::exceptionNotifier() const
+{
+ if (d->exception)
+ return d->exception;
+
+ QMutexLocker locker(mutex());
+ if (d->exception)
+ return d->exception;
+
+ if (m_sockfd == -1)
+ {
+ // socket doesn't exist; can't create notifier
+ return 0L;
+ }
+
+ return d->exception = createNotifier(QSocketNotifier::Exception);
+}
+
+bool KSocketDevice::poll(bool *input, bool *output, bool *exception,
+ int timeout, bool* timedout)
+{
+ if (m_sockfd == -1)
+ {
+ setError(IO_UnspecifiedError, NotCreated);
+ return false;
+ }
+
+ resetError();
+#ifdef HAVE_POLL
+ struct pollfd fds;
+ fds.fd = m_sockfd;
+ fds.events = 0;
+
+ if (input)
+ {
+ fds.events |= POLLIN;
+ *input = false;
+ }
+ if (output)
+ {
+ fds.events |= POLLOUT;
+ *output = false;
+ }
+ if (exception)
+ {
+ fds.events |= POLLPRI;
+ *exception = false;
+ }
+
+ int retval = ::poll(&fds, 1, timeout);
+ if (retval == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false;
+ }
+ if (retval == 0)
+ {
+ // timeout
+ if (timedout)
+ *timedout = true;
+ return true;
+ }
+
+ if (input && fds.revents & POLLIN)
+ *input = true;
+ if (output && fds.revents & POLLOUT)
+ *output = true;
+ if (exception && fds.revents & POLLPRI)
+ *exception = true;
+ if (timedout)
+ *timedout = false;
+
+ return true;
+#else
+ /*
+ * We don't have poll(2). We'll have to make do with select(2).
+ */
+
+ fd_set readfds, writefds, exceptfds;
+ fd_set *preadfds = 0L, *pwritefds = 0L, *pexceptfds = 0L;
+
+ if (input)
+ {
+ preadfds = &readfds;
+ FD_ZERO(preadfds);
+ FD_SET(m_sockfd, preadfds);
+ *input = false;
+ }
+ if (output)
+ {
+ pwritefds = &writefds;
+ FD_ZERO(pwritefds);
+ FD_SET(m_sockfd, pwritefds);
+ *output = false;
+ }
+ if (exception)
+ {
+ pexceptfds = &exceptfds;
+ FD_ZERO(pexceptfds);
+ FD_SET(m_sockfd, pexceptfds);
+ *exception = false;
+ }
+
+ int retval;
+ if (timeout < 0)
+ retval = select(m_sockfd + 1, preadfds, pwritefds, pexceptfds, 0L);
+ else
+ {
+ // convert the milliseconds to timeval
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = timeout % 1000 * 1000;
+
+ retval = select(m_sockfd + 1, preadfds, pwritefds, pexceptfds, &tv);
+ }
+
+ if (retval == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false;
+ }
+ if (retval == 0)
+ {
+ // timeout
+ if (timedout)
+ *timedout = true;
+ return true;
+ }
+
+ if (input && FD_ISSET(m_sockfd, preadfds))
+ *input = true;
+ if (output && FD_ISSET(m_sockfd, pwritefds))
+ *output = true;
+ if (exception && FD_ISSET(m_sockfd, pexceptfds))
+ *exception = true;
+
+ return true;
+#endif
+}
+
+bool KSocketDevice::poll(int timeout, bool *timedout)
+{
+ bool input, output, exception;
+ return poll(&input, &output, &exception, timeout, timedout);
+}
+
+QSocketNotifier* KSocketDevice::createNotifier(QSocketNotifier::Type type) const
+{
+ if (m_sockfd == -1)
+ return 0L;
+
+ return new QSocketNotifier(m_sockfd, type);
+}
+
+namespace
+{
+ // simple class to avoid pointer stuff
+ template<class T> class ptr
+ {
+ typedef T type;
+ type* obj;
+ public:
+ ptr() : obj(0)
+ { }
+
+ ptr(const ptr<T>& other) : obj(other.obj)
+ { }
+
+ ptr(type* _obj) : obj(_obj)
+ { }
+
+ ~ptr()
+ { }
+
+ ptr<T>& operator=(const ptr<T>& other)
+ { obj = other.obj; return *this; }
+
+ ptr<T>& operator=(T* _obj)
+ { obj = _obj; return *this; }
+
+ type* operator->() const { return obj; }
+
+ operator T*() const { return obj; }
+
+ bool isNull() const
+ { return obj == 0; }
+ };
+}
+
+static KSocketDeviceFactoryBase* defaultImplFactory;
+static QMutex defaultImplFactoryMutex;
+typedef QMap<int, KSocketDeviceFactoryBase* > factoryMap;
+static factoryMap factories;
+
+KSocketDevice* KSocketDevice::createDefault(KSocketBase* parent)
+{
+ KSocketDevice* device = dynamic_cast<KSocketDevice*>(parent);
+ if (device != 0L)
+ return device;
+
+ KSocksSocketDevice::initSocks();
+
+ if (defaultImplFactory)
+ return defaultImplFactory->create(parent);
+
+ // the really default
+ return new KSocketDevice(parent);
+}
+
+KSocketDevice* KSocketDevice::createDefault(KSocketBase* parent, int capabilities)
+{
+ KSocketDevice* device = dynamic_cast<KSocketDevice*>(parent);
+ if (device != 0L)
+ return device;
+
+ QMutexLocker locker(&defaultImplFactoryMutex);
+ factoryMap::ConstIterator it = factories.constBegin();
+ for ( ; it != factories.constEnd(); ++it)
+ if ((it.key() & capabilities) == capabilities)
+ // found a match
+ return it.data()->create(parent);
+
+ return 0L; // no default
+}
+
+KSocketDeviceFactoryBase*
+KSocketDevice::setDefaultImpl(KSocketDeviceFactoryBase* factory)
+{
+ QMutexLocker locker(&defaultImplFactoryMutex);
+ KSocketDeviceFactoryBase* old = defaultImplFactory;
+ defaultImplFactory = factory;
+ return old;
+}
+
+void KSocketDevice::addNewImpl(KSocketDeviceFactoryBase* factory, int capabilities)
+{
+ QMutexLocker locker(&defaultImplFactoryMutex);
+ if (factories.contains(capabilities))
+ delete factories[capabilities];
+ factories.insert(capabilities, factory);
+}
+
diff --git a/kdecore/network/ksocketdevice.h b/kdecore/network/ksocketdevice.h
new file mode 100644
index 000000000..301bc2b07
--- /dev/null
+++ b/kdecore/network/ksocketdevice.h
@@ -0,0 +1,428 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KSOCKETDEVICE_H
+#define KSOCKETDEVICE_H
+
+#include <qsocketnotifier.h>
+#include "ksocketbase.h"
+
+namespace KNetwork {
+
+class KSocketDevice;
+class KSocketDeviceFactoryBase;
+
+class KSocketDevicePrivate;
+/** @class KSocketDevice ksocketdevice.h ksocketdevice.h
+ * @brief Low-level socket functionality.
+ *
+ * This class provides low-level socket functionality.
+ *
+ * Most users will prefer "cooked" interfaces like those of @ref KStreamSocket or
+ * @ref KServerSocket.
+ *
+ * Descended classes from this one provide some other kinds of socket functionality,
+ * like proxying or specific socket types.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ */
+class KDECORE_EXPORT KSocketDevice: public KActiveSocketBase, public KPassiveSocketBase
+{
+public:
+ /**
+ * Capabilities for the socket implementation.
+ *
+ * KSocketDevice-derived classes can implement certain capabilities that are not
+ * available in the default class. These capabilities are described by these flags.
+ * The default KSocketDevice class has none of these capabilities.
+ *
+ * For the negative capabilities (inabilities, the CanNot* forms), when a capability
+ * is not present, the implementation will default to the original behaviour.
+ */
+ enum Capabilities
+ {
+ /** Can connect to hostnames.
+ * If this flag is present, the string form of @ref connect can be used. */
+ CanConnectString = 0x01,
+
+ /** Can bind to hostnames.
+ * If this flag is present, the string form of @ref bind can be used */
+ CanBindString = 0x02,
+
+ /** Can not bind.
+ * If this flag is present, this implementation cannot bind */
+ CanNotBind = 0x04,
+
+ /** Can not listen.
+ * If this flag is present, this implementation cannot listen */
+ CanNotListen = 0x08,
+
+ /**
+ * Can send multicast as well as join/leave multicast groups.
+ */
+ CanMulticast = 0x10,
+
+ /**
+ * Can not use datagrams.
+ * Note that this implies multicast capability not being available either.
+ */
+ CanNotUseDatagrams = 0x20
+ };
+protected:
+ /// The socket file descriptor. It is used throughout the implementation
+ /// and subclasses.
+ int m_sockfd;
+
+public:
+ /**
+ * Default constructor.
+ *
+ * The parameter is used to specify which socket this object is used as
+ * a device for.
+ */
+ explicit KSocketDevice(const KSocketBase* = 0L);
+
+ /**
+ * Constructs a new object around an already-open socket.
+ *
+ * Note: you should write programs that create sockets through
+ * the classes whenever possible.
+ */
+ explicit KSocketDevice(int fd);
+
+ /**
+ * Destructor. This closes the socket if it's open.
+ */
+ virtual ~KSocketDevice();
+
+ /**
+ * Returns the file descriptor for this socket.
+ */
+ inline int socket() const
+ { return m_sockfd; }
+
+ /**
+ * Returns the set of capabilities this socket class implements.
+ * The set of capabilities is defined as an OR-ed mask of
+ * @ref Capabilities bits.
+ *
+ * The default implementation is guaranteed to always return 0. That
+ * is, derived implementations always return bits where they differ
+ * from the system standard sockets.
+ */
+ virtual int capabilities() const
+ { return 0; }
+
+ /**
+ * This implementation sets the options on the socket.
+ */
+ virtual bool setSocketOptions(int opts);
+
+ /**
+ * Reimplementation from QIODevice. You should not call this function in sockets.
+ */
+ virtual bool open(int mode);
+
+ /**
+ * Closes the socket. Reimplemented from QIODevice.
+ *
+ * Use this function to close the socket this object is holding open.
+ */
+ virtual void close();
+
+ /**
+ * This call is not supported on sockets. Reimplemented from QIODevice.
+ */
+ virtual void flush()
+ { }
+
+ /**
+ * Creates a socket but don't connect or bind anywhere.
+ * This function is the equivalent of the system call socket(2).
+ */
+ virtual bool create(int family, int type, int protocol);
+
+ /**
+ * @overload
+ * Creates a socket but don't connect or bind anywhere.
+ */
+ bool create(const KResolverEntry& address);
+
+ /**
+ * Binds this socket to the given address.
+ */
+ virtual bool bind(const KResolverEntry& address);
+
+ /**
+ * Puts this socket into listening mode.
+ */
+ virtual bool listen(int backlog = 5); // 5 is arbitrary
+
+ /**
+ * Connect to a remote host.
+ */
+ virtual bool connect(const KResolverEntry& address);
+
+ /**
+ * Accepts a new incoming connection.
+ * Note: this function returns a socket of type KSocketDevice.
+ */
+ virtual KSocketDevice* accept();
+
+ /**
+ * Disconnects this socket.
+ */
+ virtual bool disconnect();
+
+ /**
+ * Returns the number of bytes available for reading without blocking.
+ */
+ virtual Q_LONG bytesAvailable() const;
+
+ /**
+ * Waits up to @p msecs for more data to be available on this socket.
+ *
+ * This function is a wrapper against @ref poll. This function will wait
+ * for any read events.
+ */
+ virtual Q_LONG waitForMore(int msecs, bool *timeout = 0L);
+
+ /**
+ * Reads data from this socket.
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen);
+
+ /**
+ * Reads data and the source address from this socket.
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from);
+
+ /**
+ * Peeks data in the socket.
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen);
+
+ /**
+ * Peeks the data in the socket and the source address.
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from);
+
+ /**
+ * Writes data to the socket.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len);
+
+ /**
+ * Writes the given data to the given destination address.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to);
+
+ /**
+ * Returns this socket's local address.
+ */
+ virtual KSocketAddress localAddress() const;
+
+ /**
+ * Returns this socket's peer address. If this implementation does proxying
+ * of some sort, this is the real external address, not the proxy's address.
+ */
+ virtual KSocketAddress peerAddress() const;
+
+ /**
+ * Returns this socket's externally visible local address.
+ *
+ * If this socket has a local address visible externally different
+ * from the normal local address (as returned by @ref localAddress), then
+ * return it.
+ *
+ * Certain implementations will use proxies and thus have externally visible
+ * addresses different from the local socket values. The default implementation
+ * returns the same value as @ref localAddress.
+ *
+ * @note This function may return an empty KSocketAddress. In that case, the
+ * externally visible address could/can not be determined.
+ */
+ virtual KSocketAddress externalAddress() const;
+
+ /**
+ * Returns a socket notifier for input on this socket.
+ * The notifier is created only when requested. Whether
+ * it is enabled or not depends on the implementation.
+ *
+ * This function might return NULL.
+ */
+ QSocketNotifier* readNotifier() const;
+
+ /**
+ * Returns a socket notifier for output on this socket.
+ * The is created only when requested.
+ *
+ * This function might return NULL.
+ */
+ QSocketNotifier* writeNotifier() const;
+
+ /**
+ * Returns a socket notifier for exceptional events on this socket.
+ * The is created only when requested.
+ *
+ * This function might return NULL.
+ */
+ QSocketNotifier* exceptionNotifier() const;
+
+ /**
+ * Executes a poll in the socket, via select(2) or poll(2).
+ * The events polled are returned in the parameters pointers.
+ * Set any of them to NULL to disable polling of that event.
+ *
+ * On exit, @p input, @p output and @p exception will contain
+ * true if an event of that kind is waiting on the socket or false
+ * if not. If a timeout occurred, set @p timedout to true (all other
+ * parameters are necessarily set to false).
+ *
+ * @param input if set, turns on polling for input events
+ * @param output if set, turns on polling for output events
+ * @param exception if set, turns on polling for exceptional events
+ * @param timeout the time in milliseconds to wait for an event;
+ * 0 for no wait and any negative value to wait forever
+ * @param timedout on exit, will contain true if the polling timed out
+ * @return true if the poll call succeeded and false if an error occurred
+ */
+ virtual bool poll(bool* input, bool* output, bool* exception = 0L,
+ int timeout = -1, bool* timedout = 0L);
+
+ /**
+ * Shorter version to poll for any events in a socket. This call
+ * polls for input, output and exceptional events in a socket but
+ * does not return their states. This is useful if you need to wait for
+ * any event, but don't need to know which; or for timeouts.
+ *
+ * @param timeout the time in milliseconds to wait for an event;
+ * 0 for no wait and any negative value to wait forever
+ * @param timedout on exit, will contain true if the polling timed out
+ * @return true if the poll call succeeded and false if an error occurred
+ */
+ bool poll(int timeout = -1, bool* timedout = 0L);
+
+protected:
+ /**
+ * Special constructor. This constructor will cause the internal
+ * socket device NOT to be set. Use this if your socket device class
+ * takes another underlying socket device.
+ *
+ * @param parent the parent, if any
+ */
+ KSocketDevice(bool, const KSocketBase* parent = 0L);
+
+ /**
+ * Creates a socket notifier of the given type.
+ *
+ * This function is called by @ref readNotifier, @ref writeNotifier and
+ * @ref exceptionNotifier when they need to create a socket notifier
+ * (i.e., the first call to those functions after the socket is open).
+ * After that call, those functions cache the socket notifier and will
+ * not need to call this function again.
+ *
+ * Reimplement this function in your derived class if your socket type
+ * requires a different kind of QSocketNotifier. The return value should
+ * be deleteable with delete. (@ref close deletes them).
+ *
+ * @param type the socket notifier type
+ */
+ virtual QSocketNotifier* createNotifier(QSocketNotifier::Type type) const;
+
+public:
+ /**
+ * Creates a new default KSocketDevice object given
+ * the parent object.
+ *
+ * The capabilities flag indicates the desired capabilities the object being
+ * created should possess. Those capabilities are not guaranteed: if no factory
+ * can provide such an object, a default object will be created.
+ *
+ * @param parent the KSocketBase parent
+ */
+ static KSocketDevice* createDefault(KSocketBase* parent);
+
+ /**
+ * @overload
+ *
+ * This will create an object only if the requested capabilities match.
+ *
+ * @param parent the parent
+ * @param capabilities the requested capabilities
+ */
+ static KSocketDevice* createDefault(KSocketBase* parent, int capabilities);
+
+ /**
+ * Sets the default KSocketDevice implementation to use and
+ * return the old factory.
+ *
+ * @param factory the factory object for the implementation
+ */
+ static KSocketDeviceFactoryBase* setDefaultImpl(KSocketDeviceFactoryBase* factory);
+
+ /**
+ * Adds a factory of KSocketDevice objects to the list, along with its
+ * capabilities flag.
+ */
+ static void addNewImpl(KSocketDeviceFactoryBase* factory, int capabilities);
+
+private:
+ KSocketDevice(const KSocketDevice&);
+ KSocketDevice& operator=(const KSocketDevice&);
+
+ KSocketDevicePrivate *d;
+};
+
+/** @internal
+ * This class provides functionality for creating and registering
+ * socket implementations.
+ */
+class KSocketDeviceFactoryBase
+{
+public:
+ KSocketDeviceFactoryBase() {}
+ virtual ~KSocketDeviceFactoryBase() {}
+
+ virtual KSocketDevice* create(KSocketBase*) const = 0;
+};
+
+/**
+ * This class provides functionality for creating and registering
+ * socket implementations.
+ */
+template<class Impl>
+class KSocketDeviceFactory: public KSocketDeviceFactoryBase
+{
+public:
+ KSocketDeviceFactory() {}
+ virtual ~KSocketDeviceFactory() {}
+
+ virtual KSocketDevice* create(KSocketBase* parent) const
+ { return new Impl(parent); }
+};
+
+} // namespaces
+
+#endif
diff --git a/kdecore/network/ksockssocketdevice.cpp b/kdecore/network/ksockssocketdevice.cpp
new file mode 100644
index 000000000..f67b90bc9
--- /dev/null
+++ b/kdecore/network/ksockssocketdevice.cpp
@@ -0,0 +1,487 @@
+/* -*- C++ -*-
+ * Copyright (C) 2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#ifdef __CYGWIN__
+#undef kde_socklen_t
+#define kde_socklen_t ksocklen_t
+#endif
+
+#include "kapplication.h"
+
+#include "ksocks.h"
+#include "ksocketaddress.h"
+#include "kresolver.h"
+#include "ksockssocketdevice.h"
+
+using namespace KNetwork;
+
+// constructor
+// nothing to do
+KSocksSocketDevice::KSocksSocketDevice(const KSocketBase* obj)
+ : KSocketDevice(obj)
+{
+}
+
+// constructor with argument
+// nothing to do
+KSocksSocketDevice::KSocksSocketDevice(int fd)
+ : KSocketDevice(fd)
+{
+}
+
+// destructor
+// also nothing to do
+KSocksSocketDevice::~KSocksSocketDevice()
+{
+}
+
+// returns the capabilities
+int KSocksSocketDevice::capabilities() const
+{
+ return 0; // can do everything!
+}
+
+// From here on, the code is almost exactly a copy of KSocketDevice
+// the differences are the use of KSocks where appropriate
+
+bool KSocksSocketDevice::bind(const KResolverEntry& address)
+{
+ resetError();
+
+ if (m_sockfd == -1 && !create(address))
+ return false; // failed creating
+
+ // we have a socket, so try and bind
+ if (KSocks::self()->bind(m_sockfd, address.address(), address.length()) == -1)
+ {
+ if (errno == EADDRINUSE)
+ setError(IO_BindError, AddressInUse);
+ else if (errno == EINVAL)
+ setError(IO_BindError, AlreadyBound);
+ else
+ // assume the address is the cause
+ setError(IO_BindError, NotSupported);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool KSocksSocketDevice::listen(int backlog)
+{
+ if (m_sockfd != -1)
+ {
+ if (KSocks::self()->listen(m_sockfd, backlog) == -1)
+ {
+ setError(IO_ListenError, NotSupported);
+ return false;
+ }
+
+ resetError();
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite);
+ setState(IO_Open);
+ return true;
+ }
+
+ // we don't have a socket
+ // can't listen
+ setError(IO_ListenError, NotCreated);
+ return false;
+}
+
+bool KSocksSocketDevice::connect(const KResolverEntry& address)
+{
+ resetError();
+
+ if (m_sockfd == -1 && !create(address))
+ return false; // failed creating!
+
+ int retval;
+ if (KSocks::self()->hasWorkingAsyncConnect())
+ retval = KSocks::self()->connect(m_sockfd, address.address(),
+ address.length());
+ else
+ {
+ // work around some SOCKS implementation bugs
+ // we will do a *synchronous* connection here!
+ // FIXME: KDE4, write a proper SOCKS implementation
+ bool isBlocking = blocking();
+ setBlocking(true);
+ retval = KSocks::self()->connect(m_sockfd, address.address(),
+ address.length());
+ setBlocking(isBlocking);
+ }
+
+ if (retval == -1)
+ {
+ if (errno == EISCONN)
+ return true; // we're already connected
+ else if (errno == EALREADY || errno == EINPROGRESS)
+ {
+ setError(IO_ConnectError, InProgress);
+ return true;
+ }
+ else if (errno == ECONNREFUSED)
+ setError(IO_ConnectError, ConnectionRefused);
+ else if (errno == ENETDOWN || errno == ENETUNREACH ||
+ errno == ENETRESET || errno == ECONNABORTED ||
+ errno == ECONNRESET || errno == EHOSTDOWN ||
+ errno == EHOSTUNREACH)
+ setError(IO_ConnectError, NetFailure);
+ else
+ setError(IO_ConnectError, NotSupported);
+
+ return false;
+ }
+
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite);
+ setState(IO_Open);
+ return true; // all is well
+}
+
+KSocksSocketDevice* KSocksSocketDevice::accept()
+{
+ if (m_sockfd == -1)
+ {
+ // can't accept without a socket
+ setError(IO_AcceptError, NotCreated);
+ return 0L;
+ }
+
+ struct sockaddr sa;
+ kde_socklen_t len = sizeof(sa);
+ int newfd = KSocks::self()->accept(m_sockfd, &sa, &len);
+ if (newfd == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ setError(IO_AcceptError, WouldBlock);
+ else
+ setError(IO_AcceptError, UnknownError);
+ return NULL;
+ }
+
+ return new KSocksSocketDevice(newfd);
+}
+
+static int socks_read_common(int sockfd, char *data, Q_ULONG maxlen, KSocketAddress* from, ssize_t &retval, bool peek = false)
+{
+ kde_socklen_t len;
+ if (from)
+ {
+ from->setLength(len = 128); // arbitrary length
+ retval = KSocks::self()->recvfrom(sockfd, data, maxlen, peek ? MSG_PEEK : 0, from->address(), &len);
+ }
+ else
+ retval = KSocks::self()->recvfrom(sockfd, data, maxlen, peek ? MSG_PEEK : 0, NULL, NULL);
+
+ if (retval == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return KSocketDevice::WouldBlock;
+ else
+ return KSocketDevice::UnknownError;
+ }
+
+ if (from)
+ from->setLength(len);
+ return 0;
+}
+
+Q_LONG KSocksSocketDevice::readBlock(char *data, Q_ULONG maxlen)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1;
+
+ if (maxlen == 0 || data == 0L)
+ return 0; // can't read
+
+ ssize_t retval;
+ int err = socks_read_common(m_sockfd, data, maxlen, 0L, retval);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocksSocketDevice::readBlock(char *data, Q_ULONG maxlen, KSocketAddress &from)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1; // nothing to do here
+
+ if (data == 0L || maxlen == 0)
+ return 0; // user doesn't want to read
+
+ ssize_t retval;
+ int err = socks_read_common(m_sockfd, data, maxlen, &from, retval);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocksSocketDevice::peekBlock(char *data, Q_ULONG maxlen)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1;
+
+ if (maxlen == 0 || data == 0L)
+ return 0; // can't read
+
+ ssize_t retval;
+ int err = socks_read_common(m_sockfd, data, maxlen, 0L, retval, true);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocksSocketDevice::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1; // nothing to do here
+
+ if (data == 0L || maxlen == 0)
+ return 0; // user doesn't want to read
+
+ ssize_t retval;
+ int err = socks_read_common(m_sockfd, data, maxlen, &from, retval, true);
+
+ if (err)
+ {
+ setError(IO_ReadError, static_cast<SocketError>(err));
+ return -1;
+ }
+
+ return retval;
+}
+
+Q_LONG KSocksSocketDevice::writeBlock(const char *data, Q_ULONG len)
+{
+ return writeBlock(data, len, KSocketAddress());
+}
+
+Q_LONG KSocksSocketDevice::writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to)
+{
+ resetError();
+ if (m_sockfd == -1)
+ return -1; // can't write to unopen socket
+
+ if (data == 0L || len == 0)
+ return 0; // nothing to be written
+
+ ssize_t retval = KSocks::self()->sendto(m_sockfd, data, len, 0, to.address(), to.length());
+ if (retval == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ setError(IO_WriteError, WouldBlock);
+ else
+ setError(IO_WriteError, UnknownError);
+ return -1; // nothing written
+ }
+
+ return retval;
+}
+
+KSocketAddress KSocksSocketDevice::localAddress() const
+{
+ if (m_sockfd == -1)
+ return KSocketAddress(); // not open, empty value
+
+ kde_socklen_t len;
+ KSocketAddress localAddress;
+ localAddress.setLength(len = 32); // arbitrary value
+ if (KSocks::self()->getsockname(m_sockfd, localAddress.address(), &len) == -1)
+ // error!
+ return KSocketAddress();
+
+ if (len <= localAddress.length())
+ {
+ // it has fit already
+ localAddress.setLength(len);
+ return localAddress;
+ }
+
+ // no, the socket address is actually larger than we had anticipated
+ // call again
+ localAddress.setLength(len);
+ if (KSocks::self()->getsockname(m_sockfd, localAddress.address(), &len) == -1)
+ // error!
+ return KSocketAddress();
+
+ return localAddress;
+}
+
+KSocketAddress KSocksSocketDevice::peerAddress() const
+{
+ if (m_sockfd == -1)
+ return KSocketAddress(); // not open, empty value
+
+ kde_socklen_t len;
+ KSocketAddress peerAddress;
+ peerAddress.setLength(len = 32); // arbitrary value
+ if (KSocks::self()->getpeername(m_sockfd, peerAddress.address(), &len) == -1)
+ // error!
+ return KSocketAddress();
+
+ if (len <= peerAddress.length())
+ {
+ // it has fit already
+ peerAddress.setLength(len);
+ return peerAddress;
+ }
+
+ // no, the socket address is actually larger than we had anticipated
+ // call again
+ peerAddress.setLength(len);
+ if (KSocks::self()->getpeername(m_sockfd, peerAddress.address(), &len) == -1)
+ // error!
+ return KSocketAddress();
+
+ return peerAddress;
+}
+
+KSocketAddress KSocksSocketDevice::externalAddress() const
+{
+ // return empty, indicating unknown external address
+ return KSocketAddress();
+}
+
+bool KSocksSocketDevice::poll(bool *input, bool *output, bool *exception,
+ int timeout, bool *timedout)
+{
+ if (m_sockfd == -1)
+ {
+ setError(IO_UnspecifiedError, NotCreated);
+ return false;
+ }
+
+ resetError();
+ fd_set readfds, writefds, exceptfds;
+ fd_set *preadfds = 0L, *pwritefds = 0L, *pexceptfds = 0L;
+
+ if (input)
+ {
+ preadfds = &readfds;
+ FD_ZERO(preadfds);
+ FD_SET(m_sockfd, preadfds);
+ *input = false;
+ }
+ if (output)
+ {
+ pwritefds = &writefds;
+ FD_ZERO(pwritefds);
+ FD_SET(m_sockfd, pwritefds);
+ *output = false;
+ }
+ if (exception)
+ {
+ pexceptfds = &exceptfds;
+ FD_ZERO(pexceptfds);
+ FD_SET(m_sockfd, pexceptfds);
+ *exception = false;
+ }
+
+ int retval;
+ if (timeout < 0)
+ retval = KSocks::self()->select(m_sockfd + 1, preadfds, pwritefds, pexceptfds, 0L);
+ else
+ {
+ // convert the milliseconds to timeval
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = timeout % 1000 * 1000;
+
+ retval = select(m_sockfd + 1, preadfds, pwritefds, pexceptfds, &tv);
+ }
+
+ if (retval == -1)
+ {
+ setError(IO_UnspecifiedError, UnknownError);
+ return false;
+ }
+ if (retval == 0)
+ {
+ // timeout
+ if (timedout)
+ *timedout = true;
+ return true;
+ }
+
+ if (input && FD_ISSET(m_sockfd, preadfds))
+ *input = true;
+ if (output && FD_ISSET(m_sockfd, pwritefds))
+ *output = true;
+ if (exception && FD_ISSET(m_sockfd, pexceptfds))
+ *exception = true;
+
+ return true;
+}
+
+void KSocksSocketDevice::initSocks()
+{
+ static bool init = false;
+
+ if (init)
+ return;
+
+ if (kapp == 0L)
+ return; // no KApplication, so don't initialise
+ // this should, however, test for KInstance
+
+ init = true;
+
+ if (KSocks::self()->hasSocks())
+ delete KSocketDevice::setDefaultImpl(new KSocketDeviceFactory<KSocksSocketDevice>);
+}
+
+#if 0
+static bool register()
+{
+ KSocketDevice::addNewImpl(new KSocketDeviceFactory<KSocksSocketDevice>, 0);
+}
+
+static bool register = registered();
+#endif
diff --git a/kdecore/network/ksockssocketdevice.h b/kdecore/network/ksockssocketdevice.h
new file mode 100644
index 000000000..62de23f05
--- /dev/null
+++ b/kdecore/network/ksockssocketdevice.h
@@ -0,0 +1,129 @@
+/* -*- C++ -*-
+ * Copyright (C) 2004 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KSOCKSSOCKETDEVICE_H
+#define KSOCKSSOCKETDEVICE_H
+
+#include "ksocketdevice.h"
+
+namespace KNetwork {
+
+/**
+ * @class KSocksSocketDevice ksockssocketdevice.h ksockssocketdevice.h
+ * @brief The low-level class for SOCKS proxying.
+ *
+ * This class reimplements several functions from @ref KSocketDevice in order
+ * to implement SOCKS support.
+ *
+ * This works by using KSocks.
+ *
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * @warning This code is untested!
+ */
+class KDECORE_EXPORT KSocksSocketDevice: public KSocketDevice
+{
+public:
+ /**
+ * Constructor.
+ */
+ KSocksSocketDevice(const KSocketBase* = 0L);
+
+ /**
+ * Construct from a file descriptor.
+ */
+ explicit KSocksSocketDevice(int fd);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KSocksSocketDevice();
+
+ /**
+ * Sets our capabilities.
+ */
+ virtual int capabilities() const;
+
+ /**
+ * Overrides binding.
+ */
+ virtual bool bind(const KResolverEntry& address);
+
+ /**
+ * Overrides listening.
+ */
+ virtual bool listen(int backlog);
+
+ /**
+ * Overrides connection.
+ */
+ virtual bool connect(const KResolverEntry& address);
+
+ /**
+ * Overrides accepting. The return type is specialised.
+ */
+ virtual KSocksSocketDevice* accept();
+
+ /**
+ * Overrides reading.
+ */
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen);
+ virtual Q_LONG readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from);
+
+ /**
+ * Overrides peeking.
+ */
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen);
+ virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from);
+
+ /**
+ * Overrides writing.
+ */
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len);
+ virtual Q_LONG writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to);
+
+ /**
+ * Overrides getting socket address.
+ */
+ virtual KSocketAddress localAddress() const;
+
+ /**
+ * Overrides getting peer address.
+ */
+ virtual KSocketAddress peerAddress() const;
+
+ /**
+ * Overrides getting external address.
+ */
+ virtual KSocketAddress externalAddress() const;
+
+ /**
+ * Overrides polling.
+ */
+ virtual bool poll(bool* input, bool* output, bool* exception = 0L,
+ int timeout = -1, bool* timedout = 0L);
+
+private:
+ static void initSocks();
+ friend class KSocketDevice;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/ksrvresolverworker.cpp b/kdecore/network/ksrvresolverworker.cpp
new file mode 100644
index 000000000..bcfee405c
--- /dev/null
+++ b/kdecore/network/ksrvresolverworker.cpp
@@ -0,0 +1,257 @@
+/* -*- C++ -*-
+ * Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include "ksrvresolverworker_p.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+
+#include <qapplication.h>
+#include <qevent.h>
+
+using namespace KNetwork;
+using namespace KNetwork::Internal;
+
+namespace
+{
+ struct KSrvStartEvent: public QCustomEvent
+ {
+ inline KSrvStartEvent() : QCustomEvent(QEvent::User) { }
+ };
+}
+
+static void sortPriorityClass(KSrvResolverWorker::PriorityClass&)
+{
+ // do nothing
+}
+
+bool KSrvResolverWorker::preprocess()
+{
+ // check if the resolver flags mention SRV-based lookup
+ if ((flags() & (KResolver::NoSrv | KResolver::UseSrv)) != KResolver::UseSrv)
+ return false;
+
+ QString node = nodeName();
+ if (node.find('%') != -1)
+ node.truncate(node.find('%'));
+
+ if (node.isEmpty() || node == QString::fromLatin1("*") ||
+ node == QString::fromLatin1("localhost"))
+ return false; // empty == localhost
+
+ encodedName = KResolver::domainToAscii(node);
+ if (encodedName.isNull())
+ return false;
+
+ // we only work with Internet-based families
+ if ((familyMask() & KResolver::InternetFamily) == 0)
+ return false;
+
+ // SRV-based resolution only works if the service isn't numeric
+ bool ok;
+ serviceName().toUInt(&ok);
+ if (ok)
+ return false; // it is numeric
+
+ // check the protocol for something we know
+ QCString protoname;
+ int sockettype = socketType();
+ if (!protocolName().isEmpty())
+ protoname = protocolName();
+ else if (protocol() != 0)
+ {
+ QStrList names = KResolver::protocolName(protocol());
+ names.setAutoDelete(true);
+ if (names.isEmpty())
+ return false;
+
+ protoname = "_";
+ protoname += names.at(0);
+ }
+ else if (sockettype == SOCK_STREAM || sockettype == 0)
+ protoname = "_tcp";
+ else if (sockettype == SOCK_DGRAM)
+ protoname = "_udp";
+ else
+ return false; // unknown protocol and socket type
+
+ encodedName.prepend(".");
+ encodedName.prepend(protoname);
+ encodedName.prepend(".");
+ encodedName.prepend(serviceName().latin1());
+ encodedName.prepend("_");
+
+ // looks like something we could process
+ return true;
+}
+
+bool KSrvResolverWorker::run()
+{
+ sem = new QSemaphore(1);
+ // zero out
+ sem->tryAccess(sem->available());
+
+ QApplication::postEvent(this, new KSrvStartEvent);
+
+ // block
+ (*sem)++;
+ delete sem;
+ sem = 0L;
+
+ if (rawResults.isEmpty())
+ {
+ // normal lookup
+ KResolver *r = new KResolver(nodeName(), serviceName());
+ r->setFlags(flags() | KResolver::NoSrv);
+ r->setFamily(familyMask());
+ r->setSocketType(socketType());
+ r->setProtocol(protocol(), protocolName());
+
+ enqueue(r);
+
+ Entry e;
+ PriorityClass cl;
+ e.resolver = r;
+ cl.entries.append(e);
+ myResults[0] = cl;
+
+ return true;
+ }
+ else if (rawResults.count() == 1 && rawResults.first().name == ".")
+ {
+ // no name
+ setError(KResolver::NoName);
+ finished();
+ return true;
+ }
+ else
+ {
+ // now process the results
+ QValueList<QDns::Server>::ConstIterator it = rawResults.begin();
+ while (it != rawResults.end())
+ {
+ const QDns::Server& srv = *it;
+ PriorityClass& r = myResults[srv.priority];
+ r.totalWeight += srv.weight;
+
+ Entry e;
+ e.name = srv.name;
+ e.port = srv.port;
+ e.weight = srv.weight;
+ e.resolver = 0L;
+ r.entries.append(e);
+
+ ++it;
+ }
+ rawResults.clear(); // free memory
+
+ Results::Iterator mapit;
+ for (mapit = myResults.begin(); mapit != myResults.end(); ++mapit)
+ {
+ // sort the priority
+ sortPriorityClass(*mapit);
+
+ QValueList<Entry>& entries = (*mapit).entries;
+
+ // start the resolvers
+ for (QValueList<Entry>::Iterator it = entries.begin();
+ it != entries.end(); ++it)
+ {
+ Entry &e = *it;
+
+ KResolver* r = new KResolver(e.name, QString::number(e.port));
+ r->setFlags(flags() | KResolver::NoSrv);
+ r->setFamily(familyMask());
+ r->setSocketType(socketType());
+ r->setProtocol(protocol(), protocolName());
+
+ enqueue(r);
+ e.resolver = r;
+ }
+ }
+
+ return true;
+ }
+}
+
+bool KSrvResolverWorker::postprocess()
+{
+ setError(KResolver::NoName);
+ if (myResults.isEmpty())
+ return false;
+
+ Results::Iterator mapit, mapend;
+ for (mapit = myResults.begin(), mapend = myResults.end();
+ mapit != mapend; ++mapit)
+ {
+ QValueList<Entry>::Iterator it = (*mapit).entries.begin(),
+ end = (*mapit).entries.end();
+ for ( ; it != end; ++it)
+ {
+ Entry &e = *it;
+ KResolverResults r = e.resolver->results();
+ if (r.isEmpty() && results.isEmpty())
+ setError(r.error(), r.systemError());
+ else
+ {
+ setError(KResolver::NoError);
+ results += r;
+ }
+ }
+ }
+
+ finished();
+ return true;
+}
+
+void KSrvResolverWorker::customEvent(QCustomEvent*)
+{
+ dns = new QDns(QString::fromLatin1(encodedName), QDns::Srv);
+ QObject::connect(dns, SIGNAL(resultsReady()), this, SLOT(dnsResultsReady()));
+}
+
+void KSrvResolverWorker::dnsResultsReady()
+{
+ (*sem)--;
+ rawResults = dns->servers();
+ dns->deleteLater();
+ dns = 0L;
+}
+
+namespace KNetwork
+{
+ namespace Internal
+ {
+
+ void initSrvWorker() KDE_NO_EXPORT;
+ void initSrvWorker()
+ {
+ if (getenv("KDE_NO_SRV") != NULL)
+ return;
+
+ KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KSrvResolverWorker>);
+ }
+
+ }
+}
+
+#include "ksrvresolverworker_p.moc"
diff --git a/kdecore/network/ksrvresolverworker_p.h b/kdecore/network/ksrvresolverworker_p.h
new file mode 100644
index 000000000..143fb0d4b
--- /dev/null
+++ b/kdecore/network/ksrvresolverworker_p.h
@@ -0,0 +1,85 @@
+/* -*- C++ -*-
+ * Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KSRVRESOLVERWORKER_P_H
+#define KSRVRESOLVERWORKER_P_H
+
+#include <qobject.h>
+#include <qdns.h>
+#include <qsemaphore.h>
+#include <qvaluelist.h>
+#include <qdict.h>
+#include "kresolver.h"
+#include "kresolverworkerbase.h"
+
+class QCustomEvent;
+
+namespace KNetwork
+{
+ namespace Internal
+ {
+ /**
+ * @internal
+ * This class implements SRV-based resolution
+ */
+ class KSrvResolverWorker: public QObject,
+ public KNetwork::KResolverWorkerBase
+ {
+ Q_OBJECT
+
+ public:
+ struct Entry
+ {
+ QString name;
+ Q_UINT16 port;
+ Q_UINT16 weight;
+ KNetwork::KResolver* resolver;
+ };
+
+ struct PriorityClass
+ {
+ PriorityClass() : totalWeight(0) { }
+
+ QValueList<Entry> entries;
+ Q_UINT16 totalWeight;
+ };
+
+ private:
+ QDns *dns;
+ QValueList<QDns::Server> rawResults;
+ QCString encodedName;
+ QSemaphore *sem;
+
+ typedef QMap<Q_UINT16, PriorityClass> Results;
+ Results myResults;
+
+ public:
+ virtual bool preprocess();
+ virtual bool run();
+ virtual bool postprocess();
+
+ virtual void customEvent(QCustomEvent*);
+
+ public slots:
+ void dnsResultsReady();
+ };
+ }
+}
+
+#endif
diff --git a/kdecore/network/kstreamsocket.cpp b/kdecore/network/kstreamsocket.cpp
new file mode 100644
index 000000000..93c423804
--- /dev/null
+++ b/kdecore/network/kstreamsocket.cpp
@@ -0,0 +1,368 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <qsocketnotifier.h>
+#include <qdatetime.h>
+#include <qtimer.h>
+#include <qguardedptr.h>
+
+#include "ksocketaddress.h"
+#include "kresolver.h"
+#include "ksocketdevice.h"
+#include "kstreamsocket.h"
+
+using namespace KNetwork;
+
+class KNetwork::KStreamSocketPrivate
+{
+public:
+ KResolverResults::ConstIterator local, peer;
+ QTime startTime;
+ QTimer timer;
+
+ int timeout;
+
+ inline KStreamSocketPrivate()
+ : timeout(0)
+ { }
+};
+
+KStreamSocket::KStreamSocket(const QString& node, const QString& service,
+ QObject* parent, const char *name)
+ : KClientSocketBase(parent, name), d(new KStreamSocketPrivate)
+{
+ peerResolver().setNodeName(node);
+ peerResolver().setServiceName(service);
+ peerResolver().setFamily(KResolver::KnownFamily);
+ localResolver().setFamily(KResolver::KnownFamily);
+
+ setSocketOptions(socketOptions() & ~Blocking);
+
+ QObject::connect(&d->timer, SIGNAL(timeout()), this, SLOT(timeoutSlot()));
+}
+
+KStreamSocket::~KStreamSocket()
+{
+ delete d;
+ // KClientSocketBase's destructor closes the socket
+}
+
+int KStreamSocket::timeout() const
+{
+ return d->timeout;
+}
+
+int KStreamSocket::remainingTimeout() const
+{
+ if (state() != Connecting)
+ return timeout();
+ if (timeout() <= 0)
+ return 0;
+
+ return timeout() - d->startTime.elapsed();
+}
+
+void KStreamSocket::setTimeout(int msecs)
+{
+ d->timeout = msecs;
+
+ if (state() == Connecting)
+ d->timer.changeInterval(msecs);
+}
+
+bool KStreamSocket::bind(const QString& node, const QString& service)
+{
+ if (state() != Idle)
+ return false;
+
+ if (!node.isNull())
+ localResolver().setNodeName(node);
+ if (!service.isNull())
+ localResolver().setServiceName(service);
+ return true;
+}
+
+bool KStreamSocket::connect(const QString& node, const QString& service)
+{
+ if (state() == Connected)
+ return true; // already connected
+
+ if (state() > Connected)
+ return false; // can't do much here
+
+ if (!node.isNull())
+ peerResolver().setNodeName(node);
+ if (!service.isNull())
+ peerResolver().setServiceName(service);
+
+ if (state() == Connecting && !blocking())
+ {
+ setError(IO_ConnectError, InProgress);
+ emit gotError(InProgress);
+ return true; // we're already connecting
+ }
+
+ if (state() < HostFound)
+ {
+ // connection hasn't started yet
+ if (!blocking())
+ {
+ QObject::connect(this, SIGNAL(hostFound()), SLOT(hostFoundSlot()));
+ return lookup();
+ }
+
+ // blocking mode
+ if (!lookup())
+ return false; // lookup failure
+ }
+
+ /*
+ * lookup results are available here
+ */
+
+ if (timeout() > 0)
+ {
+ if (!blocking() && !d->timer.isActive())
+ d->timer.start(timeout(), true);
+ else
+ {
+ // blocking connection with timeout
+ // this must be handled as a special case because it requires a
+ // non-blocking socket
+
+ d->timer.stop(); // no need for a timer here
+
+ socketDevice()->setBlocking(false);
+ while (true)
+ {
+ connectionEvent();
+ if (state() < Connecting)
+ return false; // error connecting
+ if (state() == Connected)
+ return true; // connected!
+
+ if (remainingTimeout() <= 0)
+ {
+ // we've timed out
+ timeoutSlot();
+ return false;
+ }
+
+ if (socketDevice()->error() == InProgress)
+ {
+ bool timedout;
+ socketDevice()->poll(remainingTimeout(), &timedout);
+ if (timedout)
+ {
+ timeoutSlot();
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ connectionEvent();
+ return error() == NoError;
+}
+
+bool KStreamSocket::connect(const KResolverEntry& entry)
+{
+ return KClientSocketBase::connect(entry);
+}
+
+void KStreamSocket::hostFoundSlot()
+{
+ QObject::disconnect(this, SLOT(hostFoundSlot()));
+ if (timeout() > 0)
+ d->timer.start(timeout(), true);
+ QTimer::singleShot(0, this, SLOT(connectionEvent()));
+}
+
+void KStreamSocket::connectionEvent()
+{
+ if (state() != HostFound && state() != Connecting)
+ return; // nothing to do
+
+ const KResolverResults& peer = peerResults();
+ if (state() == HostFound)
+ {
+ d->startTime.start();
+
+ setState(Connecting);
+ emit stateChanged(Connecting);
+ d->peer = peer.begin();
+ d->local = localResults().begin(); // just to be on the safe side
+ }
+
+ while (d->peer != peer.end())
+ {
+ const KResolverEntry &r = *d->peer;
+
+ if (socketDevice()->socket() != -1)
+ {
+ // we have an existing file descriptor
+ // this means that we've got activity in it (connection result)
+ if (socketDevice()->connect(r) && socketDevice()->error() == NoError)
+ {
+ // yes, it did connect!
+ connectionSucceeded(r);
+ return;
+ }
+ else if (socketDevice()->error() == InProgress)
+ // nope, still in progress
+ return;
+
+ // no, the socket failed to connect
+ copyError();
+ socketDevice()->close();
+ ++d->peer;
+ continue;
+ }
+
+ // try to bind
+ if (!bindLocallyFor(r))
+ {
+ // could not find a matching family
+ ++d->peer;
+ continue;
+ }
+
+ {
+ bool skip = false;
+ emit aboutToConnect(r, skip);
+ if (skip)
+ {
+ ++d->peer;
+ continue;
+ }
+ }
+
+ if (socketDevice()->connect(r) || socketDevice()->error() == InProgress)
+ {
+ // socket is attempting to connect
+ if (socketDevice()->error() == InProgress)
+ {
+ QSocketNotifier *n = socketDevice()->readNotifier();
+ QObject::connect(n, SIGNAL(activated(int)),
+ this, SLOT(connectionEvent()));
+ n->setEnabled(true);
+
+ n = socketDevice()->writeNotifier();
+ QObject::connect(n, SIGNAL(activated(int)),
+ this, SLOT(connectionEvent()));
+ n->setEnabled(true);
+
+ return; // wait for activity
+ }
+
+ // socket has connected
+ connectionSucceeded(r);
+ return;
+ }
+
+ // connection failed
+ // try next
+ copyError();
+ socketDevice()->close();
+ ++d->peer;
+ }
+
+ // that was the last item
+ socketDevice()->setSocketOptions(socketOptions());
+ setState(Idle);
+ emit stateChanged(Idle);
+ emit gotError(error());
+ return;
+}
+
+void KStreamSocket::timeoutSlot()
+{
+ if (state() != Connecting)
+ return;
+
+ // halt the connections
+ socketDevice()->close(); // this also kills the notifiers
+
+ setError(IO_TimeOutError, Timeout);
+ setState(HostFound);
+ emit stateChanged(HostFound);
+
+ QGuardedPtr<KStreamSocket> that = this;
+ emit gotError(Timeout);
+ if (!that.isNull())
+ emit timedOut();
+}
+
+bool KStreamSocket::bindLocallyFor(const KResolverEntry& peer)
+{
+ const KResolverResults& local = localResults();
+
+ if (local.isEmpty())
+ // user doesn't want to bind to any specific local address
+ return true;
+
+ bool foundone = false;
+ // scan the local resolution for a matching family
+ for (d->local = local.begin(); d->local != local.end(); ++d->local)
+ if ((*d->local).family() == peer.family())
+ {
+ // found a suitable address!
+ foundone = true;
+
+ if (socketDevice()->bind(*d->local))
+ return true;
+ }
+
+ if (!foundone)
+ {
+ // found nothing
+ setError(IO_BindError, NotSupported);
+ emit gotError(NotSupported);
+ }
+ else
+ copyError();
+ return false;
+}
+
+void KStreamSocket::connectionSucceeded(const KResolverEntry& peer)
+{
+ QObject::disconnect(socketDevice()->readNotifier(), 0, this, SLOT(connectionEvent()));
+ QObject::disconnect(socketDevice()->writeNotifier(), 0, this, SLOT(connectionEvent()));
+
+ resetError();
+ setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
+ setState(Connected);
+ socketDevice()->setSocketOptions(socketOptions());
+ d->timer.stop();
+ emit stateChanged(Connected);
+
+ if (!localResults().isEmpty())
+ emit bound(*d->local);
+ emit connected(peer);
+}
+
+#include "kstreamsocket.moc"
diff --git a/kdecore/network/kstreamsocket.h b/kdecore/network/kstreamsocket.h
new file mode 100644
index 000000000..d9be79657
--- /dev/null
+++ b/kdecore/network/kstreamsocket.h
@@ -0,0 +1,249 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago@kde.org>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KSTREAMSOCKET_H
+#define KSTREAMSOCKET_H
+
+#include <qstring.h>
+
+#include "kclientsocketbase.h"
+
+/** A namespace to store all networking-related (socket) classes. */
+namespace KNetwork {
+
+class KResolverEntry;
+class KResolverResults;
+class KServerSocket;
+class KBufferedSocket;
+
+class KStreamSocketPrivate;
+/** @class KStreamSocket kstreamsocket.h kstreamsocket.h
+ * @brief Simple stream socket
+ *
+ * This class provides functionality to creating unbuffered, stream
+ * sockets. In the case of Internet (IP) sockets, this class creates and
+ * uses TCP/IP sockets.
+ *
+ * Objects of this class start, by default, on non-blocking mode. Call
+ * setBlocking if you wish to change that.
+ *
+ * KStreamSocket objects are thread-safe and can be used in auxiliary
+ * threads (i.e., not the thread in which the Qt event loop runs in).
+ * Note that KBufferedSocket cannot be used reliably in an auxiliary thread.
+ *
+ * Sample usage:
+ * \code
+ * QByteArray httpGet(const QString& hostname)
+ * {
+ * KStreamSocket socket(hostname, "http");
+ * if (!socket.connect())
+ * return QByteArray();
+ * QByteArray data = socket.readAll();
+ * return data;
+ * }
+ * \endcode
+ *
+ * Here's another sample, showing asynchronous operation:
+ * \code
+ * DataRetriever::DataRetriever(const QString& hostname, const QString& port)
+ * : socket(hostname, port)
+ * {
+ * // connect signals to our slots
+ * QObject::connect(&socket, SIGNAL(connected(const KResolverEntry&)),
+ * this, SLOT(slotSocketConnected()));
+ * QObject::connect(&socket, SIGNAL(gotError(int)),
+ * this, SLOT(slotSocketError(int)));
+ * QObject::connect(&socket, SIGNAL(readyRead()),
+ * this, SLOT(slotSocketReadyToRead()));
+ * QObject::connect(&socket, SIGNAL(readyWrite()),
+ * this, SLOT(slotSocketReadyToWrite()));
+ *
+ * // set non-blocking mode in order to work asynchronously
+ * socket.setBlocking(false);
+ *
+ * // turn on signal emission
+ * socket.enableRead(true);
+ * socket.enableWrite(true);
+ *
+ * // start connecting
+ * socket.connect();
+ * }
+ * \endcode
+ *
+ * @see KNetwork::KBufferedSocket, KNetwork::KServerSocket
+ * @author Thiago Macieira <thiago@kde.org>
+ */
+class KDECORE_EXPORT KStreamSocket: public KClientSocketBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Default constructor.
+ *
+ * @param node destination host
+ * @param service destination service to connect to
+ * @param parent the parent QObject object
+ * @param name name for this object
+ */
+ KStreamSocket(const QString& node = QString::null, const QString& service = QString::null,
+ QObject* parent = 0L, const char *name = 0L);
+
+ /**
+ * Destructor. This closes the socket.
+ */
+ virtual ~KStreamSocket();
+
+ /**
+ * Retrieves the timeout value (in milliseconds).
+ */
+ int timeout() const;
+
+ /**
+ * Retrieves the remaining timeout time (in milliseconds). This value
+ * equals @ref timeout() if there's no connection in progress.
+ */
+ int remainingTimeout() const;
+
+ /**
+ * Sets the timeout value. Setting this value while a connection attempt
+ * is in progress will reset the timer.
+ *
+ * Please note that the timeout value is valid for the connection attempt
+ * only. No other operations are timed against this value -- including the
+ * name lookup associated.
+ *
+ * @param msecs the timeout value in milliseconds
+ */
+ void setTimeout(int msecs);
+
+ /**
+ * Binds this socket to the given nodename and service,
+ * or use the default ones if none are given. In order to bind to a service
+ * and allow the operating system to choose the interface, set @p node to
+ * QString::null.
+ *
+ * Reimplemented from KClientSocketBase.
+ *
+ * Upon successful binding, the @ref bound signal will be
+ * emitted. If an error is found, the @ref gotError
+ * signal will be emitted.
+ *
+ * @note Due to the internals of the name lookup and binding
+ * mechanism, some (if not most) implementations of this function
+ * do not actually bind the socket until the connection
+ * is requested (see @ref connect). They only set the values
+ * for future reference.
+ *
+ * This function returns true on success.
+ *
+ * @param node the nodename
+ * @param service the service
+ */
+ virtual bool bind(const QString& node = QString::null,
+ const QString& service = QString::null);
+
+ /**
+ * Reimplemented from KClientSocketBase. Connect this socket to this
+ * specific address.
+ *
+ * Unlike @ref bind(const QString&, const QString&) above, this function
+ * really does bind the socket. No lookup is performed. The @ref bound
+ * signal will be emitted.
+ */
+ virtual bool bind(const KResolverEntry& entry)
+ { return KClientSocketBase::bind(entry); }
+
+ /**
+ * Reimplemented from KClientSocketBase.
+ *
+ * Attempts to connect to the these hostname and service,
+ * or use the default ones if none are given. If a connection attempt
+ * is already in progress, check on its state and set the error status
+ * (NoError, meaning the connection is completed, or InProgress).
+ *
+ * If the blocking mode for this object is on, this function will only
+ * return when all the resolved peer addresses have been tried or when
+ * a connection is established.
+ *
+ * Upon successfully connecting, the @ref connected signal
+ * will be emitted. If an error is found, the @ref gotError
+ * signal will be emitted.
+ *
+ * This function also implements timeout handling.
+ *
+ * @param node the remote node to connect to
+ * @param service the service on the remote node to connect to
+ */
+ virtual bool connect(const QString& node = QString::null,
+ const QString& service = QString::null);
+
+ /**
+ * Unshadowing from KClientSocketBase.
+ */
+ virtual bool connect(const KResolverEntry& entry);
+
+signals:
+ /**
+ * This signal is emitted when a connection timeout occurs.
+ */
+ void timedOut();
+
+private slots:
+ void hostFoundSlot();
+ void connectionEvent();
+ void timeoutSlot();
+
+private:
+ /**
+ * @internal
+ * If the user requested local bind before connection, bind the socket to one
+ * suitable address and return true. Also sets d->local to the address used.
+ *
+ * Return false in case of error.
+ */
+ bool bindLocallyFor(const KResolverEntry& peer);
+
+ /**
+ * @internal
+ * Finishes the connection process by setting internal values and
+ * emitting the proper signals.
+ *
+ * Note: assumes d->local iterator points to the address that we bound
+ * to.
+ */
+ void connectionSucceeded(const KResolverEntry& peer);
+
+ KStreamSocket(const KStreamSocket&);
+ KStreamSocket& operator=(const KStreamSocket&);
+
+ KStreamSocketPrivate *d;
+
+ friend class KServerSocket;
+ friend class KBufferedSocket;
+};
+
+} // namespace KNetwork
+
+#endif
diff --git a/kdecore/network/syssocket.h b/kdecore/network/syssocket.h
new file mode 100644
index 000000000..e34db1bd1
--- /dev/null
+++ b/kdecore/network/syssocket.h
@@ -0,0 +1,93 @@
+/* -*- C++ -*-
+ * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef KDE_SYSSOCKET_H
+#define KDE_SYSSOCKET_H
+
+#ifdef KSOCKETBASE_H
+#error syssocket.h must be included before ksocketbase.h!
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+namespace {
+
+ /*
+ * These function here are just wrappers for the real system calls.
+ *
+ * Unfortunately, a number of systems out there work by redefining
+ * symbols through the preprocessor -- symbols that we need.
+ *
+ * So we write wrappers for all the low-level system calls.
+ *
+ * Qt has a very similar implementation. I got the idea from them, but
+ * I copied no code.
+ */
+
+ // socket
+ inline int kde_socket(int af, int style, int protocol)
+ {
+ return ::socket(af, style, protocol);
+ }
+
+ // bind
+ inline int kde_bind(int fd, const struct sockaddr* sa, socklen_t len)
+ {
+ return ::bind(fd, sa, len);
+ }
+
+ // listen
+ inline int kde_listen(int fd, int backlog)
+ {
+ return ::listen(fd, backlog);
+ }
+
+ // connect
+ inline int kde_connect(int fd, const struct sockaddr* sa, socklen_t len)
+ {
+ return ::connect(fd, (struct sockaddr*)sa, len);
+ }
+
+ // accept
+ inline int kde_accept(int fd, struct sockaddr* sa, socklen_t* len)
+ {
+ return ::accept(fd, sa, len);
+ }
+
+ // getpeername
+ inline int kde_getpeername(int fd, struct sockaddr* sa, socklen_t* len)
+ {
+ return ::getpeername(fd, sa, len);
+ }
+
+ // getsockname
+ inline int kde_getsockname(int fd, struct sockaddr* sa, socklen_t* len)
+ {
+ return ::getsockname(fd, sa, len);
+ }
+
+} // anonymous namespace
+
+#endif
diff --git a/kdecore/standard_weak.nmcheck b/kdecore/standard_weak.nmcheck
new file mode 100644
index 000000000..27c3bac7e
--- /dev/null
+++ b/kdecore/standard_weak.nmcheck
@@ -0,0 +1,6 @@
+# KDE namespace check file
+
+# various symbols coming from other non-Qt/KDE libraries
+
+# libstdc++
+std::*
diff --git a/kdecore/svgicons/Makefile.am b/kdecore/svgicons/Makefile.am
new file mode 100644
index 000000000..ca398a5bd
--- /dev/null
+++ b/kdecore/svgicons/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = -I$(srcdir)/.. $(LIBART_CFLAGS) $(all_includes)
+
+noinst_LTLIBRARIES = libkdesvgicons.la
+
+include_HEADERS = ksvgiconengine.h
+libkdesvgicons_la_SOURCES = ksvgiconengine.cpp ksvgiconpainter.cpp
diff --git a/kdecore/svgicons/TODO b/kdecore/svgicons/TODO
new file mode 100644
index 000000000..6ecafb8bf
--- /dev/null
+++ b/kdecore/svgicons/TODO
@@ -0,0 +1,5 @@
+* Units.svg is wrong
+* faster implementations of parseStyle, parseTransform, if needed
+* smaller art_render_new areas, if needed
+* make gradients work for boundingbox as well
+* patterns
diff --git a/kdecore/svgicons/ksvgiconengine.cpp b/kdecore/svgicons/ksvgiconengine.cpp
new file mode 100644
index 000000000..66bf33f0b
--- /dev/null
+++ b/kdecore/svgicons/ksvgiconengine.cpp
@@ -0,0 +1,686 @@
+/*
+ Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdom.h>
+#include <qfile.h>
+#include <qcolor.h>
+#include <qimage.h>
+#include <qwmatrix.h>
+#include <qregexp.h>
+
+#include <kmdcodec.h>
+
+#include <zlib.h>
+
+#include "ksvgiconpainter.h"
+#include "ksvgiconengine.h"
+
+class KSVGIconEngineHelper
+{
+public:
+ KSVGIconEngineHelper(KSVGIconEngine *engine)
+ {
+ m_engine = engine;
+ }
+
+ ~KSVGIconEngineHelper()
+ {
+ }
+
+ double toPixel(const QString &s, bool hmode)
+ {
+ return m_engine->painter()->toPixel(s, hmode);
+ }
+
+ ArtGradientStop *parseGradientStops(QDomElement element, int &offsets)
+ {
+ if (!element.hasChildNodes())
+ return 0;
+
+ QValueList<ArtGradientStop> stopList;
+
+ float oldOffset = -1, newOffset = -1;
+ for(QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ QDomElement element = node.toElement();
+
+ oldOffset = newOffset;
+ QString temp = element.attribute("offset");
+
+ if(temp.contains("%"))
+ {
+ temp = temp.left(temp.length() - 1);
+ newOffset = temp.toFloat() / 100.0;
+ }
+ else
+ newOffset = temp.toFloat();
+
+ // Spec skip double offset specifications
+ if(oldOffset == newOffset)
+ continue;
+
+ offsets++;
+ stopList.append(ArtGradientStop());
+
+ ArtGradientStop &stop = stopList.last();
+
+ stop.offset = newOffset;
+
+ QString parseOpacity;
+ QString parseColor;
+
+ if(element.hasAttribute("stop-opacity"))
+ parseOpacity = element.attribute("stop-opacity");
+
+ if(element.hasAttribute("stop-color"))
+ parseColor = element.attribute("stop-color");
+
+ if(parseOpacity.isEmpty() || parseColor.isEmpty())
+ {
+ QString style = element.attribute("style");
+
+ QStringList substyles = QStringList::split(';', style);
+ for(QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it)
+ {
+ QStringList substyle = QStringList::split(':', (*it));
+ QString command = substyle[0];
+ QString params = substyle[1];
+ command = command.stripWhiteSpace();
+ params = params.stripWhiteSpace();
+
+ if(command == "stop-color")
+ {
+ parseColor = params;
+
+ if(!parseOpacity.isEmpty())
+ break;
+ }
+ else if(command == "stop-opacity")
+ {
+ parseOpacity = params;
+
+ if(!parseColor.isEmpty())
+ break;
+ }
+ }
+ }
+
+ // Parse color using KSVGIconPainter (which uses Qt)
+ // Supports all svg-needed color formats
+ QColor qStopColor = m_engine->painter()->parseColor(parseColor);
+
+ // Convert in a libart suitable form
+ Q_UINT32 stopColor = m_engine->painter()->toArtColor(qStopColor);
+
+ int opacity = m_engine->painter()->parseOpacity(parseOpacity);
+
+ Q_UINT32 rgba = (stopColor << 8) | opacity;
+ Q_UINT32 r, g, b, a;
+
+ // Convert from separated to premultiplied alpha
+ a = rgba & 0xff;
+ r = (rgba >> 24) * a + 0x80;
+ r = (r + (r >> 8)) >> 8;
+ g = ((rgba >> 16) & 0xff) * a + 0x80;
+ g = (g + (g >> 8)) >> 8;
+ b = ((rgba >> 8) & 0xff) * a + 0x80;
+ b = (b + (b >> 8)) >> 8;
+
+ stop.color[0] = ART_PIX_MAX_FROM_8(r);
+ stop.color[1] = ART_PIX_MAX_FROM_8(g);
+ stop.color[2] = ART_PIX_MAX_FROM_8(b);
+ stop.color[3] = ART_PIX_MAX_FROM_8(a);
+ }
+
+ if (stopList.isEmpty())
+ return 0;
+
+ ArtGradientStop *stops = new ArtGradientStop[stopList.count()];
+
+ QValueList<ArtGradientStop>::iterator it = stopList.begin();
+ QValueList<ArtGradientStop>::iterator end = stopList.end();
+
+ for (int i = 0; it != end; ++i, ++it)
+ stops[i] = *it;
+
+ return stops;
+ }
+
+ QPointArray parsePoints(QString points)
+ {
+ if(points.isEmpty())
+ return QPointArray();
+
+ points = points.simplifyWhiteSpace();
+
+ if(points.contains(",,") || points.contains(", ,"))
+ return QPointArray();
+
+ points.replace(',', ' ');
+ points.replace('\r', QString::null);
+ points.replace('\n', QString::null);
+
+ points = points.simplifyWhiteSpace();
+
+ QStringList pointList = QStringList::split(' ', points);
+
+ QPointArray array(pointList.count() / 2);
+ int i = 0;
+
+ for(QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++)
+ {
+ float x = (*(it++)).toFloat();
+ float y = (*(it)).toFloat();
+
+ array.setPoint(i, static_cast<int>(x), static_cast<int>(y));
+ i++;
+ }
+
+ return array;
+ }
+
+ void parseTransform(const QString &transform)
+ {
+ // Combine new and old matrix
+ QWMatrix matrix = m_engine->painter()->parseTransform(transform);
+
+ QWMatrix *current = m_engine->painter()->worldMatrix();
+ *current = matrix * *current;
+ }
+
+ void parseCommonAttributes(QDomNode &node)
+ {
+ // Set important default attributes
+ m_engine->painter()->setFillColor("black");
+ m_engine->painter()->setStrokeColor("none");
+ m_engine->painter()->setStrokeDashArray("");
+ m_engine->painter()->setStrokeWidth(1);
+ m_engine->painter()->setJoinStyle("");
+ m_engine->painter()->setCapStyle("");
+ // m_engine->painter()->setFillOpacity(255, true);
+ // m_engine->painter()->setStrokeOpacity(255, true);
+
+ // Collect parent node's attributes
+ QPtrList<QDomNamedNodeMap> applyList;
+ applyList.setAutoDelete(true);
+
+ QDomNode shape = node.parentNode();
+ for(; !shape.isNull() ; shape = shape.parentNode())
+ applyList.prepend(new QDomNamedNodeMap(shape.attributes()));
+
+ // Apply parent attributes
+ for(QDomNamedNodeMap *map = applyList.first(); map != 0; map = applyList.next())
+ {
+ QDomNamedNodeMap attr = *map;
+
+ for(unsigned int i = 0; i < attr.count(); i++)
+ {
+ QString name, value;
+
+ name = attr.item(i).nodeName().lower();
+ value = attr.item(i).nodeValue();
+
+ if(name == "transform")
+ parseTransform(value);
+ else if(name == "style")
+ parseStyle(value);
+ else
+ parsePA(name, value);
+ }
+ }
+
+ // Apply local attributes
+ QDomNamedNodeMap attr = node.attributes();
+
+ for(unsigned int i = 0; i < attr.count(); i++)
+ {
+ QDomNode current = attr.item(i);
+
+ if(current.nodeName().lower() == "transform")
+ parseTransform(current.nodeValue());
+ else if(current.nodeName().lower() == "style")
+ parseStyle(current.nodeValue());
+ else
+ parsePA(current.nodeName().lower(), current.nodeValue());
+ }
+ }
+
+ bool handleTags(QDomElement element, bool paint)
+ {
+ if(element.attribute("display") == "none")
+ return false;
+ if(element.tagName() == "linearGradient")
+ {
+ ArtGradientLinear *gradient = new ArtGradientLinear();
+
+ int offsets = -1;
+ gradient->stops = parseGradientStops(element, offsets);
+ gradient->n_stops = offsets + 1;
+
+ QString spread = element.attribute("spreadMethod");
+ if(spread == "repeat")
+ gradient->spread = ART_GRADIENT_REPEAT;
+ else if(spread == "reflect")
+ gradient->spread = ART_GRADIENT_REFLECT;
+ else
+ gradient->spread = ART_GRADIENT_PAD;
+
+ m_engine->painter()->addLinearGradient(element.attribute("id"), gradient);
+ m_engine->painter()->addLinearGradientElement(gradient, element);
+ return true;
+ }
+ else if(element.tagName() == "radialGradient")
+ {
+ ArtGradientRadial *gradient = new ArtGradientRadial();
+
+ int offsets = -1;
+ gradient->stops = parseGradientStops(element, offsets);
+ gradient->n_stops = offsets + 1;
+
+ m_engine->painter()->addRadialGradient(element.attribute("id"), gradient);
+ m_engine->painter()->addRadialGradientElement(gradient, element);
+ return true;
+ }
+
+ if(!paint)
+ return true;
+
+ // TODO: Default attribute values
+ if(element.tagName() == "rect")
+ {
+ double x = toPixel(element.attribute("x"), true);
+ double y = toPixel(element.attribute("y"), false);
+ double w = toPixel(element.attribute("width"), true);
+ double h = toPixel(element.attribute("height"), false);
+
+ double rx = 0.0;
+ double ry = 0.0;
+
+ if(element.hasAttribute("rx"))
+ rx = toPixel(element.attribute("rx"), true);
+
+ if(element.hasAttribute("ry"))
+ ry = toPixel(element.attribute("ry"), false);
+
+ m_engine->painter()->drawRectangle(x, y, w, h, rx, ry);
+ }
+ else if(element.tagName() == "switch")
+ {
+ QDomNode iterate = element.firstChild();
+
+ while(!iterate.isNull())
+ {
+ // Reset matrix
+ m_engine->painter()->setWorldMatrix(new QWMatrix(m_initialMatrix));
+
+ // Parse common attributes, style / transform
+ parseCommonAttributes(iterate);
+
+ if(handleTags(iterate.toElement(), true))
+ return true;
+ iterate = iterate.nextSibling();
+ }
+ return true;
+ }
+ else if(element.tagName() == "g" || element.tagName() == "defs")
+ {
+ QDomNode iterate = element.firstChild();
+
+ while(!iterate.isNull())
+ {
+ // Reset matrix
+ m_engine->painter()->setWorldMatrix(new QWMatrix(m_initialMatrix));
+
+ // Parse common attributes, style / transform
+ parseCommonAttributes(iterate);
+
+ handleTags(iterate.toElement(), (element.tagName() == "defs") ? false : true);
+ iterate = iterate.nextSibling();
+ }
+ return true;
+ }
+ else if(element.tagName() == "line")
+ {
+ double x1 = toPixel(element.attribute("x1"), true);
+ double y1 = toPixel(element.attribute("y1"), false);
+ double x2 = toPixel(element.attribute("x2"), true);
+ double y2 = toPixel(element.attribute("y2"), false);
+
+ m_engine->painter()->drawLine(x1, y1, x2, y2);
+ return true;
+ }
+ else if(element.tagName() == "circle")
+ {
+ double cx = toPixel(element.attribute("cx"), true);
+ double cy = toPixel(element.attribute("cy"), false);
+
+ double r = toPixel(element.attribute("r"), true); // TODO: horiz correct?
+
+ m_engine->painter()->drawEllipse(cx, cy, r, r);
+ return true;
+ }
+ else if(element.tagName() == "ellipse")
+ {
+ double cx = toPixel(element.attribute("cx"), true);
+ double cy = toPixel(element.attribute("cy"), false);
+
+ double rx = toPixel(element.attribute("rx"), true);
+ double ry = toPixel(element.attribute("ry"), false);
+
+ m_engine->painter()->drawEllipse(cx, cy, rx, ry);
+ return true;
+ }
+ else if(element.tagName() == "polyline")
+ {
+ QPointArray polyline = parsePoints(element.attribute("points"));
+ m_engine->painter()->drawPolyline(polyline);
+ return true;
+ }
+ else if(element.tagName() == "polygon")
+ {
+ QPointArray polygon = parsePoints(element.attribute("points"));
+ m_engine->painter()->drawPolygon(polygon);
+ return true;
+ }
+ else if(element.tagName() == "path")
+ {
+ bool filled = true;
+
+ if(element.hasAttribute("fill") && element.attribute("fill").contains("none"))
+ filled = false;
+
+ if(element.attribute("style").contains("fill") && element.attribute("style").stripWhiteSpace().contains("fill:none"))
+ filled = false;
+
+ m_engine->painter()->drawPath(element.attribute("d"), filled);
+ return true;
+ }
+ else if(element.tagName() == "image")
+ {
+ double x = toPixel(element.attribute("x"), true);
+ double y = toPixel(element.attribute("y"), false);
+ double w = toPixel(element.attribute("width"), true);
+ double h = toPixel(element.attribute("height"), false);
+
+ QString href = element.attribute("xlink:href");
+
+ QImage image;
+ if(href.startsWith("data:"))
+ {
+ // Get input
+ QCString input = href.remove(QRegExp("^data:image/.*;base64,")).utf8();
+
+ // Decode into 'output'
+ QByteArray output;
+ KCodecs::base64Decode(input, output);
+
+ // Display
+ image.loadFromData(output);
+ }
+ else
+ image.load(href);
+
+ if (!image.isNull())
+ {
+ // Scale, if needed
+ if(image.width() != (int) w || image.height() != (int) h)
+ image = image.smoothScale((int) w, (int) h, QImage::ScaleFree);
+
+ m_engine->painter()->drawImage(x, y, image);
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ void parseStyle(const QString &style)
+ {
+ QStringList substyles = QStringList::split(';', style);
+ for(QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it)
+ {
+ QStringList substyle = QStringList::split(':', (*it));
+ QString command = substyle[0];
+ QString params = substyle[1];
+ command = command.stripWhiteSpace();
+ params = params.stripWhiteSpace();
+
+ parsePA(command, params);
+ }
+ }
+
+ void parsePA(const QString &command, const QString &value)
+ {
+ if(command == "stroke-width") // TODO: horiz:false correct?
+ m_engine->painter()->setStrokeWidth(toPixel(value, false));
+ else if(command == "stroke-miterlimit")
+ m_engine->painter()->setStrokeMiterLimit(value);
+ else if(command == "stroke-linecap")
+ m_engine->painter()->setCapStyle(value);
+ else if(command == "stroke-linejoin")
+ m_engine->painter()->setJoinStyle(value);
+ else if(command == "stroke-dashoffset")
+ m_engine->painter()->setStrokeDashOffset(value);
+ else if(command == "stroke-dasharray" && value != "none")
+ m_engine->painter()->setStrokeDashArray(value);
+ else if(command == "stroke")
+ m_engine->painter()->setStrokeColor(value);
+ else if(command == "fill")
+ m_engine->painter()->setFillColor(value);
+ else if(command == "fill-rule")
+ m_engine->painter()->setFillRule(value);
+ else if(command == "fill-opacity" || command == "stroke-opacity" || command == "opacity")
+ {
+ if(command == "fill-opacity")
+ m_engine->painter()->setFillOpacity(value);
+ else if(command == "stroke-value")
+ m_engine->painter()->setStrokeOpacity(value);
+ else
+ {
+ m_engine->painter()->setOpacity(value);
+ m_engine->painter()->setFillOpacity(value);
+ m_engine->painter()->setStrokeOpacity(value);
+ }
+ }
+ }
+
+private:
+ friend class KSVGIconEngine;
+
+ KSVGIconEngine *m_engine;
+ QWMatrix m_initialMatrix;
+};
+
+struct KSVGIconEngine::Private
+{
+ KSVGIconPainter *painter;
+ KSVGIconEngineHelper *helper;
+
+ double width;
+ double height;
+};
+
+KSVGIconEngine::KSVGIconEngine() : d(new Private())
+{
+ d->painter = 0;
+ d->helper = new KSVGIconEngineHelper(this);
+
+ d->width = 0.0;
+ d->height = 0.0;
+}
+
+KSVGIconEngine::~KSVGIconEngine()
+{
+ if(d->painter)
+ delete d->painter;
+
+ delete d->helper;
+
+ delete d;
+}
+
+bool KSVGIconEngine::load(int width, int height, const QString &path)
+{
+ QDomDocument svgDocument("svg");
+ QFile file(path);
+
+ if(path.right(3).upper() == "SVG")
+ {
+ // Open SVG Icon
+ if(!file.open(IO_ReadOnly))
+ return false;
+
+ svgDocument.setContent(&file);
+ }
+ else // SVGZ
+ {
+ gzFile svgz = gzopen(path.latin1(), "ro");
+ if(!svgz)
+ return false;
+
+ QString data;
+ bool done = false;
+
+ QCString buffer(1024);
+ int length = 0;
+
+ while(!done)
+ {
+ int ret = gzread(svgz, buffer.data() + length, 1024);
+ if(ret == 0)
+ done = true;
+ else if(ret == -1)
+ return false;
+ else {
+ buffer.resize(buffer.size()+1024);
+ length += ret;
+ }
+ }
+
+ gzclose(svgz);
+
+ svgDocument.setContent(buffer);
+ }
+
+ if(svgDocument.isNull())
+ return false;
+
+ // Check for root element
+ QDomNode rootNode = svgDocument.namedItem("svg");
+ if(rootNode.isNull() || !rootNode.isElement())
+ return false;
+
+ // Detect width and height
+ QDomElement rootElement = rootNode.toElement();
+
+ // Create icon painter
+ d->painter = new KSVGIconPainter(width, height);
+
+ d->width = width; // this sets default for no width -> 100% case
+ if(rootElement.hasAttribute("width"))
+ d->width = d->helper->toPixel(rootElement.attribute("width"), true);
+
+ d->height = height; // this sets default for no height -> 100% case
+ if(rootElement.hasAttribute("height"))
+ d->height = d->helper->toPixel(rootElement.attribute("height"), false);
+
+ // Create icon painter
+ d->painter->setDrawWidth(static_cast<int>(d->width));
+ d->painter->setDrawHeight(static_cast<int>(d->height));
+
+ // Set viewport clipping rect
+ d->painter->setClippingRect(0, 0, width, height);
+
+ // Apply viewbox
+ if(rootElement.hasAttribute("viewBox"))
+ {
+ QStringList points = QStringList::split(' ', rootElement.attribute("viewBox").simplifyWhiteSpace());
+
+ float w = points[2].toFloat();
+ float h = points[3].toFloat();
+
+ double vratiow = width / w;
+ double vratioh = height / h;
+
+ d->width = w;
+ d->height = h;
+
+ d->painter->worldMatrix()->scale(vratiow, vratioh);
+ }
+ else
+ {
+ // Fit into 'width' and 'height'
+ // FIXME: Use an aspect ratio
+ double ratiow = width / d->width;
+ double ratioh = height / d->height;
+
+ d->painter->worldMatrix()->scale(ratiow, ratioh);
+ }
+
+ QWMatrix initialMatrix = *d->painter->worldMatrix();
+ d->helper->m_initialMatrix = initialMatrix;
+
+ // Apply transform
+ if(rootElement.hasAttribute("transform"))
+ d->helper->parseTransform(rootElement.attribute("transform"));
+
+ // Go through all elements
+ QDomNode svgNode = rootElement.firstChild();
+ while(!svgNode.isNull())
+ {
+ QDomElement svgChild = svgNode.toElement();
+ if(!svgChild.isNull())
+ {
+ d->helper->parseCommonAttributes(svgNode);
+ d->helper->handleTags(svgChild, true);
+ }
+
+ svgNode = svgNode.nextSibling();
+
+ // Reset matrix
+ d->painter->setWorldMatrix(new QWMatrix(initialMatrix));
+ }
+
+ d->painter->finish();
+
+ return true;
+}
+
+KSVGIconPainter *KSVGIconEngine::painter()
+{
+ return d->painter;
+}
+
+QImage *KSVGIconEngine::image()
+{
+ return d->painter->image();
+}
+
+double KSVGIconEngine::width()
+{
+ return d->width;
+}
+
+double KSVGIconEngine::height()
+{
+ return d->height;
+}
+
+// vim:ts=4:noet
diff --git a/kdecore/svgicons/ksvgiconengine.h b/kdecore/svgicons/ksvgiconengine.h
new file mode 100644
index 000000000..3d3f46ea5
--- /dev/null
+++ b/kdecore/svgicons/ksvgiconengine.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGIconEngine_H
+#define KSVGIconEngine_H
+
+#include <kdelibs_export.h>
+
+/** \internal DO NOT USE! */
+
+class KSVGIconPainter;
+
+class KDECORE_EXPORT KSVGIconEngine
+{
+public:
+ KSVGIconEngine();
+ ~KSVGIconEngine();
+
+ bool load(int width, int height, const QString &path);
+
+ KSVGIconPainter *painter();
+ QImage *image();
+
+ double width();
+ double height();
+
+private:
+ struct Private;
+ Private *d;
+};
+
+#endif
diff --git a/kdecore/svgicons/ksvgiconpainter.cpp b/kdecore/svgicons/ksvgiconpainter.cpp
new file mode 100644
index 000000000..100369570
--- /dev/null
+++ b/kdecore/svgicons/ksvgiconpainter.cpp
@@ -0,0 +1,2837 @@
+/*
+ Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qvaluevector.h>
+#include <qstringlist.h>
+#include <qwmatrix.h>
+#include <qregexp.h>
+#include <qimage.h>
+#include <qdict.h>
+#include <qmap.h>
+#include <qdom.h>
+
+#include <math.h>
+
+#include <kdebug.h>
+
+#include <libart_lgpl/art_rgba.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_vpath_dash.h>
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_render_svp.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_vpath.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_svp_vpath_stroke.h>
+
+#include "ksvgiconpainter.h"
+
+#define ART_END2 10
+
+const double deg2rad = 0.017453292519943295769; // pi/180
+
+class KSVGIconPainterHelper
+{
+public:
+ KSVGIconPainterHelper(int width, int height, KSVGIconPainter *painter)
+ {
+ m_painter = painter;
+
+ m_clipSVP = 0;
+
+ m_fillColor = Qt::black;
+
+ m_useFill = true;
+ m_useStroke = false;
+
+ m_useFillGradient = false;
+ m_useStrokeGradient = false;
+
+ m_worldMatrix = new QWMatrix();
+
+ // Create new image with alpha support
+ m_image = new QImage(width, height, 32);
+ m_image->setAlphaBuffer(true);
+
+ m_strokeWidth = 1.0;
+ m_strokeMiterLimit = 4;
+ m_dashOffset = 0;
+ m_dashes = "";
+
+ m_opacity = 0xff;
+ m_fillOpacity = 0xff;
+ m_strokeOpacity = 0xff;
+
+ m_fillRule = "nonzero";
+
+ m_width = width;
+ m_height = height;
+
+ m_rowstride = m_width * 4;
+
+ // Make internal libart rendering buffer transparent
+ m_buffer = art_new(art_u8, m_rowstride * m_height);
+ memset(m_buffer, 0, m_rowstride * m_height);
+
+ m_tempBuffer = 0;
+ }
+
+ ~KSVGIconPainterHelper()
+ {
+ if(m_clipSVP)
+ art_svp_free(m_clipSVP);
+
+ art_free(m_buffer);
+
+ delete m_image;
+ delete m_worldMatrix;
+
+ for(QMap<QString, ArtGradientLinear *>::Iterator it = m_linearGradientMap.begin(); it != m_linearGradientMap.end(); ++it)
+ {
+ if (!it.data())
+ continue;
+ delete [] it.data()->stops;
+ delete it.data();
+ }
+ for(QMap<QString, ArtGradientRadial *>::Iterator it = m_radialGradientMap.begin(); it != m_radialGradientMap.end(); ++it)
+ {
+ if (!it.data())
+ continue;
+ delete [] it.data()->stops;
+ delete it.data();
+ }
+ }
+
+ ArtVpath *allocVPath(int number)
+ {
+ return art_new(ArtVpath, number);
+ }
+
+ ArtBpath *allocBPath(int number)
+ {
+ return art_new(ArtBpath, number);
+ }
+
+ void ensureSpace(QMemArray<ArtBpath> &vec, int index)
+ {
+ if(vec.size() == (unsigned int) index)
+ vec.resize(index + 1);
+ }
+
+ void createBuffer()
+ {
+ m_tempBuffer = art_new(art_u8, m_rowstride * m_height);
+ memset(m_tempBuffer, 0, m_rowstride * m_height);
+
+ // Swap buffers, so we work with the new one internally...
+ art_u8 *temp = m_buffer;
+ m_buffer = m_tempBuffer;
+ m_tempBuffer = temp;
+ }
+
+ void mixBuffer(int opacity)
+ {
+ art_u8 *srcPixel = m_buffer;
+ art_u8 *dstPixel = m_tempBuffer;
+
+ for(int y = 0; y < m_height; y++)
+ {
+ for(int x = 0; x < m_width; x++)
+ {
+ art_u8 r, g, b, a;
+
+ a = srcPixel[4 * x + 3];
+
+ if(a)
+ {
+ r = srcPixel[4 * x];
+ g = srcPixel[4 * x + 1];
+ b = srcPixel[4 * x + 2];
+
+ int temp = a * opacity + 0x80;
+ a = (temp + (temp >> 8)) >> 8;
+ art_rgba_run_alpha(dstPixel + 4 * x, r, g, b, a, 1);
+ }
+ }
+
+ srcPixel += m_rowstride;
+ dstPixel += m_rowstride;
+ }
+
+ // Re-swap again...
+ art_u8 *temp = m_buffer;
+ m_buffer = m_tempBuffer;
+ m_tempBuffer = temp;
+
+ art_free(m_tempBuffer);
+ m_tempBuffer = 0;
+ }
+
+ Q_UINT32 toArtColor(const QColor &color)
+ {
+ // Convert in a libart suitable form
+ QString tempName = color.name();
+ const char *str = tempName.latin1();
+
+ int result = 0;
+
+ for(int i = 1; str[i]; i++)
+ {
+ int hexval;
+ if(str[i] >= '0' && str[i] <= '9')
+ hexval = str[i] - '0';
+ else if (str[i] >= 'A' && str[i] <= 'F')
+ hexval = str[i] - 'A' + 10;
+ else if (str[i] >= 'a' && str[i] <= 'f')
+ hexval = str[i] - 'a' + 10;
+ else
+ break;
+
+ result = (result << 4) + hexval;
+ }
+
+ return result;
+ }
+
+ void drawSVP(ArtSVP *svp, Q_UINT32 rgb, int opacity)
+ {
+ if(!svp)
+ return;
+
+ ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0);
+ art_render_svp(render, svp);
+
+ art_render_mask_solid(render, (opacity << 8) + opacity + (opacity >> 7));
+
+ ArtPixMaxDepth color[3];
+ color[0] = ART_PIX_MAX_FROM_8(rgb >> 16);
+ color[1] = ART_PIX_MAX_FROM_8((rgb >> 8) & 0xff);
+ color[2] = ART_PIX_MAX_FROM_8(rgb & 0xff);
+
+ art_render_image_solid(render, color);
+ art_render_invoke(render);
+ }
+
+ void drawBPath(ArtBpath *bpath)
+ {
+ double affine[6];
+ affine[0] = m_worldMatrix->m11();
+ affine[1] = m_worldMatrix->m12();
+ affine[2] = m_worldMatrix->m21();
+ affine[3] = m_worldMatrix->m22();
+ affine[4] = m_worldMatrix->dx();
+ affine[5] = m_worldMatrix->dy();
+
+ ArtBpath *temp = art_bpath_affine_transform(bpath, affine);
+ ArtVpath *vec = art_bez_path_to_vec(temp, 0.25);
+ art_free(temp);
+ drawPathInternal(vec, affine);
+ }
+
+ void drawVPath(ArtVpath *vec)
+ {
+ double affine[6];
+ affine[0] = m_worldMatrix->m11();
+ affine[1] = m_worldMatrix->m12();
+ affine[2] = m_worldMatrix->m21();
+ affine[3] = m_worldMatrix->m22();
+ affine[4] = m_worldMatrix->dx();
+ affine[5] = m_worldMatrix->dy();
+
+ ArtVpath *temp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+ vec = temp;
+ drawPathInternal(vec, affine);
+ }
+
+ void drawPathInternal(ArtVpath *vec, double *affine)
+ {
+ ArtSVP *svp;
+ ArtSVP *fillSVP = 0, *strokeSVP = 0;
+
+ Q_UINT32 fillColor = 0, strokeColor = 0;
+
+ // Filling
+ {
+ int index = -1;
+ QValueVector<int> toCorrect;
+ while(vec[++index].code != ART_END)
+ {
+ if(vec[index].code == ART_END2)
+ {
+ vec[index].code = ART_LINETO;
+ toCorrect.push_back(index);
+ }
+ }
+
+ fillColor = toArtColor(m_fillColor);
+
+ ArtSvpWriter *swr;
+ ArtSVP *temp;
+ temp = art_svp_from_vpath(vec);
+
+ if(m_fillRule == "evenodd")
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
+ else
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_NONZERO);
+
+ art_svp_intersector(temp, swr);
+ svp = art_svp_writer_rewind_reap(swr);
+
+ fillSVP = svp;
+
+ art_svp_free(temp);
+
+ QValueVector<int>::iterator it;
+ for(it = toCorrect.begin(); it != toCorrect.end(); ++it)
+ vec[(*it)].code = (ArtPathcode)ART_END2;
+ }
+
+ // There seems to be a problem when stroke width is zero, this is a quick
+ // fix (Rob).
+ if(m_strokeWidth <= 0)
+ m_useStroke = m_useStrokeGradient = false;
+
+ // Stroking
+ if(m_useStroke || m_useStrokeGradient)
+ {
+ strokeColor = toArtColor(m_strokeColor);
+
+ double ratio = art_affine_expansion(affine);
+ double strokeWidth = m_strokeWidth * ratio;
+
+ ArtPathStrokeJoinType joinStyle = ART_PATH_STROKE_JOIN_MITER;
+ ArtPathStrokeCapType capStyle = ART_PATH_STROKE_CAP_BUTT;
+
+ if(m_joinStyle == "miter")
+ joinStyle = ART_PATH_STROKE_JOIN_MITER;
+ else if(m_joinStyle == "round")
+ joinStyle = ART_PATH_STROKE_JOIN_ROUND;
+ else if(m_joinStyle == "bevel")
+ joinStyle = ART_PATH_STROKE_JOIN_BEVEL;
+
+ if(m_capStyle == "butt")
+ capStyle = ART_PATH_STROKE_CAP_BUTT;
+ else if(m_capStyle == "round")
+ capStyle = ART_PATH_STROKE_CAP_ROUND;
+ else if(m_capStyle == "square")
+ capStyle = ART_PATH_STROKE_CAP_SQUARE;
+
+ if(m_dashes.length() > 0)
+ {
+ QRegExp reg("[, ]");
+ QStringList dashList = QStringList::split(reg, m_dashes);
+
+ double *dashes = new double[dashList.count()];
+ for(unsigned int i = 0; i < dashList.count(); i++)
+ dashes[i] = m_painter->toPixel(dashList[i], true);
+
+ ArtVpathDash dash;
+ dash.offset = m_dashOffset;
+ dash.n_dash = dashList.count();
+
+ dash.dash = dashes;
+
+ ArtVpath *vec2 = art_vpath_dash(vec, &dash);
+ art_free(vec);
+
+ delete[] dashes;
+
+ vec = vec2;
+ }
+
+ svp = art_svp_vpath_stroke(vec, joinStyle, capStyle, strokeWidth, m_strokeMiterLimit, 0.25);
+
+ strokeSVP = svp;
+ }
+
+ // Apply opacity
+ int fillOpacity = static_cast<int>(m_fillOpacity);
+ int strokeOpacity = static_cast<int>(m_strokeOpacity);
+ int opacity = static_cast<int>(m_opacity);
+
+ // Needed hack, to support both transparent
+ // paths and transparent gradients
+ if(fillOpacity == strokeOpacity && fillOpacity == opacity && !m_useFillGradient && !m_useStrokeGradient)
+ opacity = 255;
+
+ if(fillOpacity != 255)
+ {
+ int temp = fillOpacity * opacity + 0x80;
+ fillOpacity = (temp + (temp >> 8)) >> 8;
+ }
+
+ if(strokeOpacity != 255)
+ {
+ int temp = strokeOpacity * opacity + 0x80;
+ strokeOpacity = (temp + (temp >> 8)) >> 8;
+ }
+
+ // Create temporary buffer if necessary
+ bool tempDone = false;
+ if(m_opacity != 0xff)
+ {
+ tempDone = true;
+ createBuffer();
+ }
+
+ // Apply Gradients on fill/stroke
+ if(m_useFillGradient)
+ applyGradient(fillSVP, true);
+ else if(m_useFill)
+ drawSVP(fillSVP, fillColor, fillOpacity);
+
+ if(m_useStrokeGradient)
+ applyGradient(strokeSVP, false);
+ else if(m_useStroke)
+ drawSVP(strokeSVP, strokeColor, strokeOpacity);
+
+ // Mix in temporary buffer, if possible
+ if(tempDone)
+ mixBuffer(opacity);
+
+ if(m_clipSVP)
+ {
+ art_svp_free(m_clipSVP);
+ m_clipSVP = 0;
+ }
+
+ if(fillSVP)
+ art_svp_free(fillSVP);
+
+ if(strokeSVP)
+ art_svp_free(strokeSVP);
+
+ // Reset opacity values
+ m_opacity = 255.0;
+ m_fillOpacity = 255.0;
+ m_strokeOpacity = 255.0;
+
+ art_free(vec);
+ }
+
+ void applyLinearGradient(ArtSVP *svp, const QString &ref)
+ {
+ ArtGradientLinear *linear = m_linearGradientMap[ref];
+ if(linear)
+ {
+ QDomElement element = m_linearGradientElementMap[linear];
+
+ double x1, y1, x2, y2;
+ if(element.hasAttribute("x1"))
+ x1 = m_painter->toPixel(element.attribute("x1"), true);
+ else
+ x1 = 0;
+
+ if(element.hasAttribute("y1"))
+ y1 = m_painter->toPixel(element.attribute("y1"), false);
+ else
+ y1 = 0;
+
+ if(element.hasAttribute("x2"))
+ x2 = m_painter->toPixel(element.attribute("x2"), true);
+ else
+ x2 = 100;
+
+ if(element.hasAttribute("y2"))
+ y2 = m_painter->toPixel(element.attribute("y2"), false);
+ else
+ y2 = 0;
+
+ // Adjust to gradientTransform
+ QWMatrix m = m_painter->parseTransform(element.attribute("gradientTransform"));
+ m.map(x1, y1, &x1, &y1);
+ m.map(x2, y2, &x2, &y2);
+
+ double x1n = x1 * m_worldMatrix->m11() + y1 * m_worldMatrix->m21() + m_worldMatrix->dx();
+ double y1n = x1 * m_worldMatrix->m12() + y1 * m_worldMatrix->m22() + m_worldMatrix->dy();
+ double x2n = x2 * m_worldMatrix->m11() + y2 * m_worldMatrix->m21() + m_worldMatrix->dx();
+ double y2n = x2 * m_worldMatrix->m12() + y2 * m_worldMatrix->m22() + m_worldMatrix->dy();
+
+ double dx = x2n - x1n;
+ double dy = y2n - y1n;
+ double scale = 1.0 / (dx * dx + dy * dy);
+
+ linear->a = dx * scale;
+ linear->b = dy * scale;
+ linear->c = -(x1n * linear->a + y1n * linear->b);
+
+ ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0);
+ art_render_svp(render, svp);
+
+ art_render_gradient_linear(render, linear, ART_FILTER_HYPER);
+ art_render_invoke(render);
+ }
+ }
+
+ void applyRadialGradient(ArtSVP *svp, const QString &ref)
+ {
+ ArtGradientRadial *radial = m_radialGradientMap[ref];
+ if(radial)
+ {
+ QDomElement element = m_radialGradientElementMap[radial];
+
+ double cx, cy, r, fx, fy;
+ if(element.hasAttribute("cx"))
+ cx = m_painter->toPixel(element.attribute("cx"), true);
+ else
+ cx = 50;
+
+ if(element.hasAttribute("cy"))
+ cy = m_painter->toPixel(element.attribute("cy"), false);
+ else
+ cy = 50;
+
+ if(element.hasAttribute("r"))
+ r = m_painter->toPixel(element.attribute("r"), true);
+ else
+ r = 50;
+
+ if(element.hasAttribute("fx"))
+ fx = m_painter->toPixel(element.attribute("fx"), false);
+ else
+ fx = cx;
+
+ if(element.hasAttribute("fy"))
+ fy = m_painter->toPixel(element.attribute("fy"), false);
+ else
+ fy = cy;
+
+ radial->affine[0] = m_worldMatrix->m11();
+ radial->affine[1] = m_worldMatrix->m12();
+ radial->affine[2] = m_worldMatrix->m21();
+ radial->affine[3] = m_worldMatrix->m22();
+ radial->affine[4] = m_worldMatrix->dx();
+ radial->affine[5] = m_worldMatrix->dy();
+
+ radial->fx = (fx - cx) / r;
+ radial->fy = (fy - cy) / r;
+
+ double aff1[6], aff2[6], gradTransform[6];
+
+ // Respect gradientTransform
+ QWMatrix m = m_painter->parseTransform(element.attribute("gradientTransform"));
+
+ gradTransform[0] = m.m11();
+ gradTransform[1] = m.m12();
+ gradTransform[2] = m.m21();
+ gradTransform[3] = m.m22();
+ gradTransform[4] = m.dx();
+ gradTransform[5] = m.dy();
+
+ art_affine_scale(aff1, r, r);
+ art_affine_translate(aff2, cx, cy);
+
+ art_affine_multiply(aff1, aff1, aff2);
+ art_affine_multiply(aff1, aff1, gradTransform);
+ art_affine_multiply(aff1, aff1, radial->affine);
+ art_affine_invert(radial->affine, aff1);
+
+ ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0);
+ art_render_svp(render, svp);
+
+ art_render_gradient_radial(render, radial, ART_FILTER_HYPER);
+ art_render_invoke(render);
+ }
+ }
+
+ void applyGradient(ArtSVP *svp, const QString &ref)
+ {
+ ArtGradientLinear *linear = m_linearGradientMap[ref];
+ if(linear)
+ {
+ QDomElement element = m_linearGradientElementMap[linear];
+
+ if(!element.hasAttribute("xlink:href"))
+ {
+ applyLinearGradient(svp, ref);
+ return;
+ }
+ else
+ {
+ ArtGradientLinear *linear = m_linearGradientMap[element.attribute("xlink:href").mid(1)];
+ QDomElement newElement = m_linearGradientElementMap[linear];
+
+ // Saved 'old' attributes
+ QDict<QString> refattrs;
+ refattrs.setAutoDelete(true);
+
+ for(unsigned int i = 0; i < newElement.attributes().length(); ++i)
+ refattrs.insert(newElement.attributes().item(i).nodeName(), new QString(newElement.attributes().item(i).nodeValue()));
+
+ // Copy attributes
+ if(!newElement.isNull())
+ {
+ QDomNamedNodeMap attr = element.attributes();
+
+ for(unsigned int i = 0; i < attr.length(); i++)
+ {
+ QString name = attr.item(i).nodeName();
+ if(name != "xlink:href" && name != "id")
+ newElement.setAttribute(name, attr.item(i).nodeValue());
+ }
+ }
+
+ applyGradient(svp, element.attribute("xlink:href").mid(1));
+
+ // Restore attributes
+ QDictIterator<QString> itr(refattrs);
+ for(; itr.current(); ++itr)
+ newElement.setAttribute(itr.currentKey(), *(itr.current()));
+
+ return;
+ }
+ }
+
+ ArtGradientRadial *radial = m_radialGradientMap[ref];
+ if(radial)
+ {
+ QDomElement element = m_radialGradientElementMap[radial];
+
+ if(!element.hasAttribute("xlink:href"))
+ {
+ applyRadialGradient(svp, ref);
+ return;
+ }
+ else
+ {
+ ArtGradientRadial *radial = m_radialGradientMap[element.attribute("xlink:href").mid(1)];
+ QDomElement newElement = m_radialGradientElementMap[radial];
+
+ // Saved 'old' attributes
+ QDict<QString> refattrs;
+ refattrs.setAutoDelete(true);
+
+ for(unsigned int i = 0; i < newElement.attributes().length(); ++i)
+ refattrs.insert(newElement.attributes().item(i).nodeName(), new QString(newElement.attributes().item(i).nodeValue()));
+
+ // Copy attributes
+ if(!newElement.isNull())
+ {
+ QDomNamedNodeMap attr = element.attributes();
+
+ for(unsigned int i = 0; i < attr.length(); i++)
+ {
+ QString name = attr.item(i).nodeName();
+ if(name != "xlink:href" && name != "id")
+ newElement.setAttribute(name, attr.item(i).nodeValue());
+ }
+ }
+
+ applyGradient(svp, element.attribute("xlink:href").mid(1));
+
+ // Restore attributes
+ QDictIterator<QString> itr(refattrs);
+ for(; itr.current(); ++itr)
+ newElement.setAttribute(itr.currentKey(), *(itr.current()));
+
+ return;
+ }
+ }
+ }
+
+ void applyGradient(ArtSVP *svp, bool fill)
+ {
+ QString ref;
+
+ if(fill)
+ {
+ m_useFillGradient = false;
+ ref = m_fillGradientReference;
+ }
+ else
+ {
+ m_useStrokeGradient = false;
+ ref = m_strokeGradientReference;
+ }
+
+ applyGradient(svp, ref);
+ }
+
+ void blit()
+ {
+ unsigned char *line = m_buffer;
+
+ for(int y = 0; y < m_height; y++)
+ {
+ QRgb *sl = reinterpret_cast<QRgb *>(m_image->scanLine(y));
+ for(int x = 0; x < m_width; x++)
+ sl[x] = qRgba(line[x * 4], line[x * 4 + 1], line[x * 4 + 2], line[x * 4 + 3]);
+
+ line += m_rowstride;
+ }
+ }
+
+ void calculateArc(bool relative, QMemArray<ArtBpath> &vec, int &index, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
+ {
+ double sin_th, cos_th;
+ double a00, a01, a10, a11;
+ double x0, y0, x1, y1, xc, yc;
+ double d, sfactor, sfactor_sq;
+ double th0, th1, th_arc;
+ int i, n_segs;
+
+ sin_th = sin(angle * (M_PI / 180.0));
+ cos_th = cos(angle * (M_PI / 180.0));
+
+ double dx;
+
+ if(!relative)
+ dx = (curx - x) / 2.0;
+ else
+ dx = -x / 2.0;
+
+ double dy;
+
+ if(!relative)
+ dy = (cury - y) / 2.0;
+ else
+ dy = -y / 2.0;
+
+ double _x1 = cos_th * dx + sin_th * dy;
+ double _y1 = -sin_th * dx + cos_th * dy;
+ double Pr1 = r1 * r1;
+ double Pr2 = r2 * r2;
+ double Px = _x1 * _x1;
+ double Py = _y1 * _y1;
+
+ // Spec : check if radii are large enough
+ double check = Px / Pr1 + Py / Pr2;
+ if(check > 1)
+ {
+ r1 = r1 * sqrt(check);
+ r2 = r2 * sqrt(check);
+ }
+
+ a00 = cos_th / r1;
+ a01 = sin_th / r1;
+ a10 = -sin_th / r2;
+ a11 = cos_th / r2;
+
+ x0 = a00 * curx + a01 * cury;
+ y0 = a10 * curx + a11 * cury;
+
+ if(!relative)
+ x1 = a00 * x + a01 * y;
+ else
+ x1 = a00 * (curx + x) + a01 * (cury + y);
+
+ if(!relative)
+ y1 = a10 * x + a11 * y;
+ else
+ y1 = a10 * (curx + x) + a11 * (cury + y);
+
+ /* (x0, y0) is current point in transformed coordinate space.
+ (x1, y1) is new point in transformed coordinate space.
+
+ The arc fits a unit-radius circle in this space.
+ */
+
+ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
+
+ sfactor_sq = 1.0 / d - 0.25;
+
+ if(sfactor_sq < 0)
+ sfactor_sq = 0;
+
+ sfactor = sqrt(sfactor_sq);
+
+ if(sweepFlag == largeArcFlag)
+ sfactor = -sfactor;
+
+ xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
+ yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
+
+ /* (xc, yc) is center of the circle. */
+ th0 = atan2(y0 - yc, x0 - xc);
+ th1 = atan2(y1 - yc, x1 - xc);
+
+ th_arc = th1 - th0;
+ if(th_arc < 0 && sweepFlag)
+ th_arc += 2 * M_PI;
+ else if(th_arc > 0 && !sweepFlag)
+ th_arc -= 2 * M_PI;
+
+ n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001)));
+
+ for(i = 0; i < n_segs; i++)
+ {
+ index++;
+
+ ensureSpace(vec, index);
+
+ {
+ double sin_th, cos_th;
+ double a00, a01, a10, a11;
+ double x1, y1, x2, y2, x3, y3;
+ double t;
+ double th_half;
+
+ double _th0 = th0 + i * th_arc / n_segs;
+ double _th1 = th0 + (i + 1) * th_arc / n_segs;
+
+ sin_th = sin(angle * (M_PI / 180.0));
+ cos_th = cos(angle * (M_PI / 180.0));
+
+ /* inverse transform compared with rsvg_path_arc */
+ a00 = cos_th * r1;
+ a01 = -sin_th * r2;
+ a10 = sin_th * r1;
+ a11 = cos_th * r2;
+
+ th_half = 0.5 * (_th1 - _th0);
+ t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
+ x1 = xc + cos(_th0) - t * sin(_th0);
+ y1 = yc + sin(_th0) + t * cos(_th0);
+ x3 = xc + cos(_th1);
+ y3 = yc + sin(_th1);
+ x2 = x3 + t * sin(_th1);
+ y2 = y3 - t * cos(_th1);
+
+ ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = a00 * x1 + a01 * y1;
+ vec[index].y1 = a10 * x1 + a11 * y1;
+ vec[index].x2 = a00 * x2 + a01 * y2;
+ vec[index].y2 = a10 * x2 + a11 * y2;
+ vec[index].x3 = a00 * x3 + a01 * y3;
+ vec[index].y3 = a10 * x3 + a11 * y3;
+ }
+ }
+
+ if(!relative)
+ curx = x;
+ else
+ curx += x;
+
+ if(!relative)
+ cury = y;
+ else
+ cury += y;
+ }
+
+ // For any docs, see the libart library
+ static void art_vpath_render_bez(ArtVpath **p_vpath, int *pn, int *pn_max,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ double flatness)
+ {
+ double x3_0, y3_0, z3_0_dot, z1_dot, z2_dot;
+ double z1_perp, z2_perp, max_perp_sq;
+
+ double x_m, y_m, xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2;
+
+ x3_0 = x3 - x0;
+ y3_0 = y3 - y0;
+
+ z3_0_dot = x3_0 * x3_0 + y3_0 * y3_0;
+
+ if (z3_0_dot < 0.001)
+ goto nosubdivide;
+
+ max_perp_sq = flatness * flatness * z3_0_dot;
+
+ z1_perp = (y1 - y0) * x3_0 - (x1 - x0) * y3_0;
+ if (z1_perp * z1_perp > max_perp_sq)
+ goto subdivide;
+
+ z2_perp = (y3 - y2) * x3_0 - (x3 - x2) * y3_0;
+ if (z2_perp * z2_perp > max_perp_sq)
+ goto subdivide;
+
+ z1_dot = (x1 - x0) * x3_0 + (y1 - y0) * y3_0;
+ if (z1_dot < 0 && z1_dot * z1_dot > max_perp_sq)
+ goto subdivide;
+
+ z2_dot = (x3 - x2) * x3_0 + (y3 - y2) * y3_0;
+ if (z2_dot < 0 && z2_dot * z2_dot > max_perp_sq)
+ goto subdivide;
+
+ if (z1_dot + z1_dot > z3_0_dot)
+ goto subdivide;
+
+ if (z2_dot + z2_dot > z3_0_dot)
+ goto subdivide;
+
+ nosubdivide:
+ art_vpath_add_point (p_vpath, pn, pn_max, ART_LINETO, x3, y3);
+ return;
+
+ subdivide:
+ xa1 = (x0 + x1) * 0.5;
+ ya1 = (y0 + y1) * 0.5;
+ xa2 = (x0 + 2 * x1 + x2) * 0.25;
+ ya2 = (y0 + 2 * y1 + y2) * 0.25;
+ xb1 = (x1 + 2 * x2 + x3) * 0.25;
+ yb1 = (y1 + 2 * y2 + y3) * 0.25;
+ xb2 = (x2 + x3) * 0.5;
+ yb2 = (y2 + y3) * 0.5;
+ x_m = (xa2 + xb1) * 0.5;
+ y_m = (ya2 + yb1) * 0.5;
+ art_vpath_render_bez (p_vpath, pn, pn_max, x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, flatness);
+ art_vpath_render_bez (p_vpath, pn, pn_max, x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, flatness);
+ }
+
+ ArtVpath *art_bez_path_to_vec(const ArtBpath *bez, double flatness)
+ {
+ ArtVpath *vec;
+ int vec_n, vec_n_max;
+ int bez_index;
+ double x, y;
+
+ vec_n = 0;
+ vec_n_max = (1 << 4);
+ vec = art_new (ArtVpath, vec_n_max);
+
+ x = 0;
+ y = 0;
+
+ bez_index = 0;
+ do
+ {
+ if(vec_n >= vec_n_max)
+ art_expand (vec, ArtVpath, vec_n_max);
+
+ switch (bez[bez_index].code)
+ {
+ case ART_MOVETO_OPEN:
+ case ART_MOVETO:
+ case ART_LINETO:
+ x = bez[bez_index].x3;
+ y = bez[bez_index].y3;
+ vec[vec_n].code = bez[bez_index].code;
+ vec[vec_n].x = x;
+ vec[vec_n].y = y;
+ vec_n++;
+ break;
+ case ART_END:
+ vec[vec_n].code = ART_END;
+ vec[vec_n].x = 0;
+ vec[vec_n].y = 0;
+ vec_n++;
+ break;
+ case ART_END2:
+ vec[vec_n].code = (ArtPathcode)ART_END2;
+ vec[vec_n].x = bez[bez_index].x3;
+ vec[vec_n].y = bez[bez_index].y3;
+ vec_n++;
+ break;
+ case ART_CURVETO:
+ art_vpath_render_bez (&vec, &vec_n, &vec_n_max,
+ x, y,
+ bez[bez_index].x1, bez[bez_index].y1,
+ bez[bez_index].x2, bez[bez_index].y2,
+ bez[bez_index].x3, bez[bez_index].y3,
+ flatness);
+ x = bez[bez_index].x3;
+ y = bez[bez_index].y3;
+ break;
+ }
+ }
+
+ while (bez[bez_index++].code != ART_END);
+ return vec;
+ }
+
+ static void art_rgb_affine_run(int *p_x0, int *p_x1, int y,
+ int src_width, int src_height,
+ const double affine[6])
+ {
+ int x0, x1;
+ double z;
+ double x_intercept;
+ int xi;
+
+ x0 = *p_x0;
+ x1 = *p_x1;
+
+ if (affine[0] > 1e-6)
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ x_intercept = -z / affine[0];
+ xi = (int) (int) ceil (x_intercept + 1e-6 - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = (-z + src_width) / affine[0];
+ xi = (int) ceil (x_intercept - 1e-6 - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else if (affine[0] < -1e-6)
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ x_intercept = (-z + src_width) / affine[0];
+ xi = (int) ceil (x_intercept + 1e-6 - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = -z / affine[0];
+ xi = (int) ceil (x_intercept - 1e-6 - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ if (z < 0 || z >= src_width)
+ {
+ *p_x1 = *p_x0;
+ return;
+ }
+ }
+ if (affine[1] > 1e-6)
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ x_intercept = -z / affine[1];
+ xi = (int) ceil (x_intercept + 1e-6 - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = (-z + src_height) / affine[1];
+ xi = (int) ceil (x_intercept - 1e-6 - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else if (affine[1] < -1e-6)
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ x_intercept = (-z + src_height) / affine[1];
+ xi = (int) ceil (x_intercept + 1e-6 - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = -z / affine[1];
+ xi = (int) ceil (x_intercept - 1e-6 - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ if (z < 0 || z >= src_height)
+ {
+ *p_x1 = *p_x0;
+ return;
+ }
+ }
+
+ *p_x0 = x0;
+ *p_x1 = x1;
+ }
+
+ // Slightly modified version to support RGBA buffers, copied from gnome-print
+ static void art_rgba_rgba_affine(art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6])
+ {
+ int x, y;
+ double inv[6];
+ art_u8 *dst_p, *dst_linestart;
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int alpha;
+ art_u8 bg_r, bg_g, bg_b, bg_a, cr, cg, cb;
+ art_u8 fg_r, fg_g, fg_b;
+ int tmp;
+ int run_x0, run_x1;
+
+ dst_linestart = dst;
+ art_affine_invert (inv, affine);
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 4;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = (int) floor (src_pt.x);
+ src_y = (int) floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+ if (src_x >= 0 && src_x < src_width &&
+ src_y >= 0 && src_y < src_height)
+ {
+
+ alpha = src_p[3];
+ if (alpha)
+ {
+ if (alpha == 255)
+ {
+ dst_p[0] = src_p[0];
+ dst_p[1] = src_p[1];
+ dst_p[2] = src_p[2];
+ dst_p[3] = 255;
+ }
+ else
+ {
+ bg_r = dst_p[0];
+ bg_g = dst_p[1];
+ bg_b = dst_p[2];
+ bg_a = dst_p[3];
+
+ cr = (bg_r * bg_a + 0x80) >> 8;
+ cg = (bg_g * bg_g + 0x80) >> 8;
+ cb = (bg_b * bg_b + 0x80) >> 8;
+
+ tmp = (src_p[0] - bg_r) * alpha;
+ fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = (src_p[1] - bg_g) * alpha;
+ fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = (src_p[2] - bg_b) * alpha;
+ fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8);
+
+ dst_p[0] = fg_r;
+ dst_p[1] = fg_g;
+ dst_p[2] = fg_b;
+ dst_p[3] = bg_a + (((255 - bg_a) * alpha + 0x80) >> 8);
+ }
+ }
+ } else { dst_p[0] = 255; dst_p[1] = 0; dst_p[2] = 0; dst_p[3] = 255;}
+ dst_p += 4;
+ }
+ dst_linestart += dst_rowstride;
+ }
+ }
+
+private:
+ friend class KSVGIconPainter;
+ ArtSVP *m_clipSVP;
+
+ QImage *m_image;
+ QWMatrix *m_worldMatrix;
+
+ QString m_fillRule;
+ QString m_joinStyle;
+ QString m_capStyle;
+
+ int m_strokeMiterLimit;
+
+ QString m_dashes;
+ unsigned short m_dashOffset;
+
+ QColor m_fillColor;
+ QColor m_strokeColor;
+
+ art_u8 *m_buffer;
+ art_u8 *m_tempBuffer;
+
+ int m_width;
+ int m_height;
+
+ int m_rowstride;
+
+ double m_opacity;
+ double m_fillOpacity;
+ double m_strokeOpacity;
+
+ bool m_useFill;
+ bool m_useStroke;
+
+ bool m_useFillGradient;
+ bool m_useStrokeGradient;
+
+ QString m_fillGradientReference;
+ QString m_strokeGradientReference;
+
+ QMap<QString, ArtGradientLinear *> m_linearGradientMap;
+ QMap<ArtGradientLinear *, QDomElement> m_linearGradientElementMap;
+
+ QMap<QString, ArtGradientRadial *> m_radialGradientMap;
+ QMap<ArtGradientRadial *, QDomElement> m_radialGradientElementMap;
+
+ KSVGIconPainter *m_painter;
+
+ double m_strokeWidth;
+};
+
+struct KSVGIconPainter::Private
+{
+ KSVGIconPainterHelper *helper;
+
+ int drawWidth;
+ int drawHeight;
+};
+
+KSVGIconPainter::KSVGIconPainter(int width, int height) : d(new Private())
+{
+ d->helper = new KSVGIconPainterHelper(width, height, this);
+
+ d->drawWidth = width;
+ d->drawHeight = height;
+}
+
+KSVGIconPainter::~KSVGIconPainter()
+{
+ delete d->helper;
+ delete d;
+}
+
+void KSVGIconPainter::setDrawWidth(int dwidth)
+{
+ d->drawWidth = dwidth;
+}
+
+void KSVGIconPainter::setDrawHeight(int dheight)
+{
+ d->drawHeight = dheight;
+}
+
+void KSVGIconPainter::finish()
+{
+ d->helper->blit();
+}
+
+QImage *KSVGIconPainter::image()
+{
+ return new QImage(*d->helper->m_image);
+}
+
+QWMatrix *KSVGIconPainter::worldMatrix()
+{
+ return d->helper->m_worldMatrix;
+}
+
+void KSVGIconPainter::setWorldMatrix(QWMatrix *matrix)
+{
+ if(d->helper->m_worldMatrix)
+ delete d->helper->m_worldMatrix;
+
+ d->helper->m_worldMatrix = matrix;
+}
+
+void KSVGIconPainter::setStrokeWidth(double width)
+{
+ d->helper->m_strokeWidth = width;
+}
+
+void KSVGIconPainter::setStrokeMiterLimit(const QString &miter)
+{
+ d->helper->m_strokeMiterLimit = miter.toInt();
+}
+
+void KSVGIconPainter::setStrokeDashOffset(const QString &dashOffset)
+{
+ d->helper->m_dashOffset = dashOffset.toUInt();
+}
+
+void KSVGIconPainter::setStrokeDashArray(const QString &dashes)
+{
+ d->helper->m_dashes = dashes;
+}
+
+void KSVGIconPainter::setCapStyle(const QString &cap)
+{
+ d->helper->m_capStyle = cap;
+}
+
+void KSVGIconPainter::setJoinStyle(const QString &join)
+{
+ d->helper->m_joinStyle = join;
+}
+
+void KSVGIconPainter::setStrokeColor(const QString &stroke)
+{
+ if(stroke.startsWith("url"))
+ {
+ d->helper->m_useStroke = false;
+ d->helper->m_useStrokeGradient = true;
+
+ QString url = stroke;
+
+ unsigned int start = url.find("#") + 1;
+ unsigned int end = url.findRev(")");
+
+ d->helper->m_strokeGradientReference = url.mid(start, end - start);
+ }
+ else
+ {
+ d->helper->m_strokeColor = parseColor(stroke);
+
+ d->helper->m_useStrokeGradient = false;
+ d->helper->m_strokeGradientReference = QString::null;
+
+ if(stroke.stripWhiteSpace().lower() != "none")
+ setUseStroke(true);
+ else
+ setUseStroke(false);
+ }
+}
+
+void KSVGIconPainter::setFillColor(const QString &fill)
+{
+ if(fill.startsWith("url"))
+ {
+ d->helper->m_useFill = false;
+ d->helper->m_useFillGradient = true;
+
+ QString url = fill;
+
+ unsigned int start = url.find("#") + 1;
+ unsigned int end = url.findRev(")");
+
+ d->helper->m_fillGradientReference = url.mid(start, end - start);
+ }
+ else
+ {
+ d->helper->m_fillColor = parseColor(fill);
+
+ d->helper->m_useFillGradient = false;
+ d->helper->m_fillGradientReference = QString::null;
+
+ if(fill.stripWhiteSpace().lower() != "none")
+ setUseFill(true);
+ else
+ setUseFill(false);
+ }
+}
+
+void KSVGIconPainter::setFillRule(const QString &fillRule)
+{
+ d->helper->m_fillRule = fillRule;
+}
+
+Q_UINT32 KSVGIconPainter::parseOpacity(const QString &data)
+{
+ int opacity = 255;
+
+ if(!data.isEmpty())
+ {
+ double temp;
+
+ if(data.contains("%"))
+ {
+ QString tempString = data.left(data.length() - 1);
+ temp = double(255 * tempString.toDouble()) / 100.0;
+ }
+ else
+ temp = data.toDouble();
+
+ opacity = (int) floor(temp * 255 + 0.5);
+ }
+
+ return opacity;
+}
+
+void KSVGIconPainter::setFillOpacity(const QString &fillOpacity)
+{
+ d->helper->m_fillOpacity = parseOpacity(fillOpacity);
+}
+
+void KSVGIconPainter::setStrokeOpacity(const QString &strokeOpacity)
+{
+ d->helper->m_strokeOpacity = parseOpacity(strokeOpacity);
+}
+
+void KSVGIconPainter::setOpacity(const QString &opacity)
+{
+ d->helper->m_opacity = parseOpacity(opacity);
+}
+
+void KSVGIconPainter::setUseFill(bool fill)
+{
+ d->helper->m_useFill = fill;
+}
+
+void KSVGIconPainter::setUseStroke(bool stroke)
+{
+ d->helper->m_useStroke = stroke;
+}
+
+void KSVGIconPainter::setClippingRect(int x, int y, int w, int h)
+{
+ ArtVpath *vec = d->helper->allocVPath(6);
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = x;
+ vec[0].y = y;
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = x;
+ vec[1].y = y + h;
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = x + w;
+ vec[2].y = y + h;
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = x + w;
+ vec[3].y = y;
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = x;
+ vec[4].y = y;
+
+ vec[5].code = ART_END;
+
+ if(d->helper->m_clipSVP)
+ art_svp_free(d->helper->m_clipSVP);
+
+ d->helper->m_clipSVP = art_svp_from_vpath(vec);
+
+ art_free(vec);
+}
+
+void KSVGIconPainter::drawRectangle(double x, double y, double w, double h, double rx, double ry)
+{
+ if((int) rx != 0 && (int) ry != 0)
+ {
+ ArtVpath *res;
+ ArtBpath *vec = d->helper->allocBPath(10);
+
+ int i = 0;
+
+ if(rx > w / 2)
+ rx = w / 2;
+
+ if(ry > h / 2)
+ ry = h / 2;
+
+ vec[i].code = ART_MOVETO_OPEN;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y;
+
+ i++;
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + rx * (1 - 0.552);
+ vec[i].y1 = y;
+ vec[i].x2 = x;
+ vec[i].y2 = y + ry * (1 - 0.552);
+ vec[i].x3 = x;
+ vec[i].y3 = y + ry;
+
+ i++;
+
+ if(ry < h / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x;
+ vec[i].y3 = y + h - ry;
+
+ i++;
+ }
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x;
+ vec[i].y1 = y + h - ry * (1 - 0.552);
+ vec[i].x2 = x + rx * (1 - 0.552);
+ vec[i].y2 = y + h;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y + h;
+
+ i++;
+
+ if(rx < w / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + w - rx;
+ vec[i].y3 = y + h;
+
+ i++;
+ }
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + w - rx * (1 - 0.552);
+ vec[i].y1 = y + h;
+ vec[i].x2 = x + w;
+ vec[i].y2 = y + h - ry * (1 - 0.552);
+ vec[i].x3 = x + w;
+
+ vec[i].y3 = y + h - ry;
+
+ i++;
+
+ if(ry < h / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + w;
+ vec[i].y3 = y + ry;
+
+ i++;
+ }
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + w;
+ vec[i].y1 = y + ry * (1 - 0.552);
+ vec[i].x2 = x + w - rx * (1 - 0.552);
+ vec[i].y2 = y;
+ vec[i].x3 = x + w - rx;
+ vec[i].y3 = y;
+
+ i++;
+
+ if(rx < w / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y;
+
+ i++;
+ }
+
+ vec[i].code = ART_END;
+
+ res = d->helper->art_bez_path_to_vec(vec, 0.25);
+ art_free(vec);
+ d->helper->drawVPath(res);
+ }
+ else
+ {
+ ArtVpath *vec = d->helper->allocVPath(6);
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = x;
+ vec[0].y = y;
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = x;
+ vec[1].y = y + h;
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = x + w;
+ vec[2].y = y + h;
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = x + w;
+ vec[3].y = y;
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = x;
+ vec[4].y = y;
+
+ vec[5].code = ART_END;
+
+ d->helper->drawVPath(vec);
+ }
+}
+
+void KSVGIconPainter::drawEllipse(double cx, double cy, double rx, double ry)
+{
+ ArtBpath *temp;
+
+ temp = d->helper->allocBPath(6);
+
+ double x1, y1, x2, y2, x3, y3;
+ double len = 0.55228474983079356;
+ double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0};
+ double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0};
+ int i = 0;
+
+ temp[i].code = ART_MOVETO;
+ temp[i].x3 = cx + rx;
+ temp[i].y3 = cy;
+
+ i++;
+
+ while(i < 5)
+ {
+ x1 = cos4[i-1] + len * cos4[i];
+ y1 = sin4[i-1] + len * sin4[i];
+ x2 = cos4[i] + len * cos4[i-1];
+ y2 = sin4[i] + len * sin4[i-1];
+ x3 = cos4[i];
+ y3 = sin4[i];
+
+ temp[i].code = ART_CURVETO;
+ temp[i].x1 = cx + x1 * rx;
+ temp[i].y1 = cy + y1 * ry;
+ temp[i].x2 = cx + x2 * rx;
+ temp[i].y2 = cy + y2 * ry;
+ temp[i].x3 = cx + x3 * rx;
+ temp[i].y3 = cy + y3 * ry;
+
+ i++;
+ }
+
+ temp[i].code = ART_END;
+
+ d->helper->drawBPath(temp);
+
+ art_free(temp);
+}
+
+void KSVGIconPainter::drawLine(double x1, double y1, double x2, double y2)
+{
+ ArtVpath *vec;
+
+ vec = d->helper->allocVPath(3);
+
+ vec[0].code = ART_MOVETO_OPEN;
+ vec[0].x = x1;
+ vec[0].y = y1;
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = x2;
+ vec[1].y = y2;
+
+ vec[2].code = ART_END;
+
+ d->helper->drawVPath(vec);
+}
+
+void KSVGIconPainter::drawPolyline(QPointArray polyArray, int points)
+{
+ if(polyArray.point(0).x() == -1 || polyArray.point(0).y() == -1)
+ return;
+
+ ArtVpath *polyline;
+
+ if(points == -1)
+ points = polyArray.count();
+
+ polyline = d->helper->allocVPath(3 + points);
+ polyline[0].code = ART_MOVETO;
+ polyline[0].x = polyArray.point(0).x();
+ polyline[0].y = polyArray.point(0).y();
+
+ int index;
+ for(index = 1; index < points; index++)
+ {
+ QPoint point = polyArray.point(index);
+ polyline[index].code = ART_LINETO;
+ polyline[index].x = point.x();
+ polyline[index].y = point.y();
+ }
+
+ if(d->helper->m_useFill) // if the polyline must be filled, inform libart that it should not be closed.
+ {
+ polyline[index].code = (ArtPathcode)ART_END2;
+ polyline[index].x = polyArray.point(0).x();
+ polyline[index++].y = polyArray.point(0).y();
+ }
+
+ polyline[index].code = ART_END;
+
+ d->helper->drawVPath(polyline);
+}
+
+void KSVGIconPainter::drawPolygon(QPointArray polyArray)
+{
+ ArtVpath *polygon;
+
+ polygon = d->helper->allocVPath(3 + polyArray.count());
+ polygon[0].code = ART_MOVETO;
+ polygon[0].x = polyArray.point(0).x();
+ polygon[0].y = polyArray.point(0).y();
+
+ unsigned int index;
+ for(index = 1; index < polyArray.count(); index++)
+ {
+ QPoint point = polyArray.point(index);
+ polygon[index].code = ART_LINETO;
+ polygon[index].x = point.x();
+ polygon[index].y = point.y();
+ }
+
+ polygon[index].code = ART_LINETO;
+ polygon[index].x = polyArray.point(0).x();
+ polygon[index].y = polyArray.point(0).y();
+
+ index++;
+ polygon[index].code = ART_END;
+
+ d->helper->drawVPath(polygon);
+}
+
+// Path parsing tool
+// parses the coord into number and forwards to the next token
+static const char *getCoord(const char *ptr, double &number)
+{
+ int integer, exponent;
+ double decimal, frac;
+ int sign, expsign;
+
+ exponent = 0;
+ integer = 0;
+ frac = 1.0;
+ decimal = 0;
+ sign = 1;
+ expsign = 1;
+
+ // read the sign
+ if(*ptr == '+')
+ ptr++;
+ else if(*ptr == '-')
+ {
+ ptr++;
+ sign = -1;
+ }
+ // read the integer part
+ while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+ integer = (integer * 10) + *(ptr++) - '0';
+
+ if(*ptr == '.') // read the decimals
+ {
+ ptr++;
+ while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+ decimal += (*(ptr++) - '0') * (frac *= 0.1);
+ }
+
+ if(*ptr == 'e' || *ptr == 'E') // read the exponent part
+ {
+ ptr++;
+
+ // read the sign of the exponent
+ if(*ptr == '+')
+ ptr++;
+ else if(*ptr == '-')
+ {
+ ptr++;
+ expsign = -1;
+ }
+
+ exponent = 0;
+ while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+ {
+ exponent *= 10;
+ exponent += *ptr - '0';
+ ptr++;
+ }
+ }
+
+ number = integer + decimal;
+ number *= sign * pow(10.0, expsign * exponent);
+
+ // skip the following space
+ if(*ptr == ' ')
+ ptr++;
+
+ return ptr;
+}
+
+void KSVGIconPainter::drawPath(const QString &data, bool filled)
+{
+ if (!data.isEmpty())
+ {
+ QString value = data;
+
+ QMemArray<ArtBpath> vec;
+ int index = -1;
+
+ double curx = 0.0, cury = 0.0, contrlx = 0.0, contrly = 0.0, xc, yc;
+ unsigned int lastCommand = 0;
+
+ QString _d = value.replace(",", " ");
+ _d = _d.simplifyWhiteSpace();
+ const char *ptr = _d.latin1();
+ const char *end = _d.latin1() + _d.length() + 1;
+
+ double tox, toy, x1, y1, x2, y2, rx, ry, angle;
+ bool largeArc, sweep;
+ char command = *(ptr++);
+
+ while(ptr < end)
+ {
+ if(*ptr == ' ')
+ ptr++;
+
+ switch(command)
+ {
+ case 'm':
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ if(index != -1 && lastCommand != 'z')
+ {
+ // Find last subpath
+ int find = -1;
+ for(int i = index; i >= 0; i--)
+ {
+ if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ index++;
+
+ if(vec.size() == (unsigned int) index)
+ vec.resize(index + 1);
+
+ vec[index].code = (ArtPathcode)ART_END2;
+ vec[index].x3 = vec[find].x3;
+ vec[index].y3 = vec[find].y3;
+ }
+
+ curx += tox;
+ cury += toy;
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
+ vec[index].x3 = curx;
+ vec[index].y3 = cury;
+
+ lastCommand = 'm';
+ break;
+ case 'M':
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+ if(index != -1 && lastCommand != 'z')
+ {
+ // Find last subpath
+ int find = -1;
+ for(int i = index; i >= 0; i--)
+ {
+ if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ index++;
+
+ if(vec.size() == (unsigned int) index)
+ vec.resize(index + 1);
+
+ vec[index].code = (ArtPathcode)ART_END2;
+ vec[index].x3 = vec[find].x3;
+ vec[index].y3 = vec[find].y3;
+ }
+
+ curx = tox;
+ cury = toy;
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
+ vec[index].x3 = curx;
+ vec[index].y3 = cury;
+
+ lastCommand = 'M';
+ break;
+ case 'l':
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = curx + tox;
+ vec[index].y3 = cury + toy;
+
+ curx += tox;
+ cury += toy;
+
+ lastCommand = 'l';
+ break;
+ case 'L':
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = tox;
+ vec[index].y3 = toy;
+
+ curx = tox;
+ cury = toy;
+
+ lastCommand = 'L';
+ break;
+ case 'h':
+ ptr = getCoord(ptr, tox);
+
+ index++;
+
+ curx += tox;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = curx;
+ vec[index].y3 = cury;
+
+ lastCommand = 'h';
+ break;
+ case 'H':
+ ptr = getCoord(ptr, tox);
+
+ index++;
+
+ curx = tox;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = curx;
+ vec[index].y3 = cury;
+
+ lastCommand = 'H';
+ break;
+ case 'v':
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ cury += toy;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = curx;
+ vec[index].y3 = cury;
+
+ lastCommand = 'v';
+ break;
+ case 'V':
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ cury = toy;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = curx;
+ vec[index].y3 = cury;
+
+ lastCommand = 'V';
+ break;
+ case 'c':
+ ptr = getCoord(ptr, x1);
+ ptr = getCoord(ptr, y1);
+ ptr = getCoord(ptr, x2);
+ ptr = getCoord(ptr, y2);
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = curx + x1;
+ vec[index].y1 = cury + y1;
+ vec[index].x2 = curx + x2;
+ vec[index].y2 = cury + y2;
+ vec[index].x3 = curx + tox;
+ vec[index].y3 = cury + toy;
+
+ curx += tox;
+ cury += toy;
+
+ contrlx = vec[index].x2;
+ contrly = vec[index].y2;
+
+ lastCommand = 'c';
+ break;
+ case 'C':
+ ptr = getCoord(ptr, x1);
+ ptr = getCoord(ptr, y1);
+ ptr = getCoord(ptr, x2);
+ ptr = getCoord(ptr, y2);
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = x1;
+ vec[index].y1 = y1;
+ vec[index].x2 = x2;
+ vec[index].y2 = y2;
+ vec[index].x3 = tox;
+ vec[index].y3 = toy;
+
+ curx = vec[index].x3;
+ cury = vec[index].y3;
+ contrlx = vec[index].x2;
+ contrly = vec[index].y2;
+
+ lastCommand = 'C';
+ break;
+ case 's':
+ ptr = getCoord(ptr, x2);
+ ptr = getCoord(ptr, y2);
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = 2 * curx - contrlx;
+ vec[index].y1 = 2 * cury - contrly;
+ vec[index].x2 = curx + x2;
+ vec[index].y2 = cury + y2;
+ vec[index].x3 = curx + tox;
+ vec[index].y3 = cury + toy;
+
+ curx += tox;
+ cury += toy;
+
+ contrlx = vec[index].x2;
+ contrly = vec[index].y2;
+
+ lastCommand = 's';
+ break;
+ case 'S':
+ ptr = getCoord(ptr, x2);
+ ptr = getCoord(ptr, y2);
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = 2 * curx - contrlx;
+ vec[index].y1 = 2 * cury - contrly;
+ vec[index].x2 = x2;
+ vec[index].y2 = y2;
+ vec[index].x3 = tox;
+ vec[index].y3 = toy;
+
+ curx = vec[index].x3;
+ cury = vec[index].y3;
+ contrlx = vec[index].x2;
+ contrly = vec[index].y2;
+
+ lastCommand = 'S';
+ break;
+ case 'q':
+ ptr = getCoord(ptr, x1);
+ ptr = getCoord(ptr, y1);
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = (curx + 2 * (x1 + curx)) * (1.0 / 3.0);
+ vec[index].y1 = (cury + 2 * (y1 + cury)) * (1.0 / 3.0);
+ vec[index].x2 = ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0);
+ vec[index].y2 = ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0);
+ vec[index].x3 = curx + tox;
+ vec[index].y3 = cury + toy;
+
+ contrlx = curx + x1;
+ contrly = cury + y1;
+ curx += tox;
+ cury += toy;
+
+ lastCommand = 'q';
+ break;
+ case 'Q':
+ ptr = getCoord(ptr, x1);
+ ptr = getCoord(ptr, y1);
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ // TODO : if this fails make it more like QuadraticRel
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = (curx + 2 * x1) * (1.0 / 3.0);
+ vec[index].y1 = (cury + 2 * y1) * (1.0 / 3.0);
+ vec[index].x2 = (tox + 2 * x1) * (1.0 / 3.0);
+ vec[index].y2 = (toy + 2 * y1) * (1.0 / 3.0);
+ vec[index].x3 = tox;
+ vec[index].y3 = toy;
+
+ curx = vec[index].x3;
+ cury = vec[index].y3;
+ contrlx = vec[index].x2;
+ contrly = vec[index].y2;
+
+ lastCommand = 'Q';
+ break;
+ case 't':
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ xc = 2 * curx - contrlx;
+ yc = 2 * cury - contrly;
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0);
+ vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0);
+ vec[index].x2 = ((curx + tox) + 2 * xc) * (1.0 / 3.0);
+ vec[index].y2 = ((cury + toy) + 2 * yc) * (1.0 / 3.0);
+
+ vec[index].x3 = curx + tox;
+ vec[index].y3 = cury + toy;
+
+ curx += tox;
+ cury += toy;
+ contrlx = xc;
+ contrly = yc;
+
+ lastCommand = 't';
+ break;
+ case 'T':
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ xc = 2 * curx - contrlx;
+ yc = 2 * cury - contrly;
+
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_CURVETO;
+ vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0);
+ vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0);
+ vec[index].x2 = (tox + 2 * xc) * (1.0 / 3.0);
+ vec[index].y2 = (toy + 2 * yc) * (1.0 / 3.0);
+ vec[index].x3 = tox;
+ vec[index].y3 = toy;
+
+ curx = tox;
+ cury = toy;
+ contrlx = xc;
+ contrly = yc;
+
+ lastCommand = 'T';
+ break;
+ case 'z':
+ case 'Z':
+ int find;
+ find = -1;
+ for(int i = index; i >= 0; i--)
+ {
+ if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ if(find != -1)
+ {
+ if(vec[find].x3 != curx || vec[find].y3 != cury)
+ {
+ index++;
+
+ d->helper->ensureSpace(vec, index);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = vec[find].x3;
+ vec[index].y3 = vec[find].y3;
+ }
+ }
+
+ // reset for next (sub)path
+ curx = vec[find].x3;
+ cury = vec[find].y3;
+
+ lastCommand = 'z';
+ break;
+ case 'a':
+ ptr = getCoord(ptr, rx);
+ ptr = getCoord(ptr, ry);
+ ptr = getCoord(ptr, angle);
+ ptr = getCoord(ptr, tox);
+ largeArc = tox == 1;
+ ptr = getCoord(ptr, tox);
+ sweep = tox == 1;
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ // Spec: radii are nonnegative numbers
+ rx = fabs(rx);
+ ry = fabs(ry);
+
+ d->helper->calculateArc(true, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
+
+ lastCommand = 'a';
+ break;
+ case 'A':
+ ptr = getCoord(ptr, rx);
+ ptr = getCoord(ptr, ry);
+ ptr = getCoord(ptr, angle);
+ ptr = getCoord(ptr, tox);
+ largeArc = tox == 1;
+ ptr = getCoord(ptr, tox);
+ sweep = tox == 1;
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ // Spec: radii are nonnegative numbers
+ rx = fabs(rx);
+ ry = fabs(ry);
+
+ d->helper->calculateArc(false, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
+
+ lastCommand = 'A';
+ break;
+ }
+
+ if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
+ {
+ // there are still coords in this command
+ if(command == 'M')
+ command = 'L';
+ else if(command == 'm')
+ command = 'l';
+ }
+ else
+ command = *(ptr++);
+
+ // Detect reflection points
+ if(lastCommand != 'C' && lastCommand != 'c' &&
+ lastCommand != 'S' && lastCommand != 's' &&
+ lastCommand != 'Q' && lastCommand != 'q' &&
+ lastCommand != 'T' && lastCommand != 't')
+ {
+ contrlx = curx;
+ contrly = cury;
+ }
+ }
+
+ // Find last subpath
+ int find = -1;
+ for(int i = index; i >= 0; i--)
+ {
+ if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ // Fix a problem where the .svg file used doubles as values... (sofico.svg)
+ if(curx != vec[find].x3 && cury != vec[find].y3)
+ {
+ if((int) curx == (int) vec[find].x3 && (int) cury == (int) vec[find].y3)
+ {
+ index++;
+
+ if(vec.size() == (unsigned int) index)
+ vec.resize(index + 1);
+
+ vec[index].code = ART_LINETO;
+ vec[index].x3 = vec[find].x3;
+ vec[index].y3 = vec[find].y3;
+
+ curx = vec[find].x3;
+ cury = vec[find].y3;
+ }
+ }
+
+ // Handle filled paths that are not closed explicitly
+ if(filled)
+ {
+ if((int) curx != (int) vec[find].x3 || (int) cury != (int) vec[find].y3)
+ {
+ index++;
+
+ if(vec.size() == (unsigned int) index)
+ vec.resize(index + 1);
+
+ vec[index].code = (ArtPathcode)ART_END2;
+ vec[index].x3 = vec[find].x3;
+ vec[index].y3 = vec[find].y3;
+
+ curx = vec[find].x3;
+ cury = vec[find].y3;
+ }
+ }
+
+ // Close
+ index++;
+
+ if(vec.size() == (unsigned int) index)
+ vec.resize(index + 1);
+
+ vec[index].code = ART_END;
+
+ // There are pure-moveto paths which reference paint servers *bah*
+ // Do NOT render them
+ bool render = false;
+ for(int i = index; i >= 0; i--)
+ {
+ if(vec[i].code != ART_MOVETO_OPEN && vec[i].code != ART_MOVETO && !(vec[i].code >= ART_END))
+ {
+ render = true;
+ break;
+ }
+ }
+
+ if(render)
+ d->helper->drawBPath(vec.data());
+ }
+}
+
+void KSVGIconPainter::drawImage(double x, double y, QImage &image)
+{
+ if(image.depth() != 32)
+ image = image.convertDepth(32);
+
+ double affine[6];
+ affine[0] = d->helper->m_worldMatrix->m11();
+ affine[1] = d->helper->m_worldMatrix->m12();
+ affine[2] = d->helper->m_worldMatrix->m21();
+ affine[3] = d->helper->m_worldMatrix->m22();
+ // use the world matrix to convert the coordinates
+ d->helper->m_worldMatrix->map(x, y, &affine[4], &affine[5]);
+
+ d->helper->art_rgba_rgba_affine(d->helper->m_buffer, 0, 0, d->helper->m_width, d->helper->m_height,
+ d->helper->m_rowstride, image.bits(), image.width(), image.height(),
+ image.width() * 4, affine);
+}
+
+QColor KSVGIconPainter::parseColor(const QString &param)
+{
+ if(param.stripWhiteSpace().startsWith("#"))
+ {
+ QColor color;
+ color.setNamedColor(param.stripWhiteSpace());
+ return color;
+ }
+ else if(param.stripWhiteSpace().startsWith("rgb("))
+ {
+ QString parse = param.stripWhiteSpace();
+ QStringList colors = QStringList::split(',', parse);
+ QString r = colors[0].right((colors[0].length() - 4));
+ QString g = colors[1];
+ QString b = colors[2].left((colors[2].length() - 1));
+
+ if(r.contains("%"))
+ {
+ r = r.left(r.length() - 1);
+ r = QString::number(int((double(255 * r.toDouble()) / 100.0)));
+ }
+
+ if(g.contains("%"))
+ {
+ g = g.left(g.length() - 1);
+ g = QString::number(int((double(255 * g.toDouble()) / 100.0)));
+ }
+
+ if(b.contains("%"))
+ {
+ b = b.left(b.length() - 1);
+ b = QString::number(int((double(255 * b.toDouble()) / 100.0)));
+ }
+
+ return QColor(r.toInt(), g.toInt(), b.toInt());
+ }
+ else
+ {
+ QString rgbColor = param.stripWhiteSpace();
+
+ if(rgbColor == "aliceblue")
+ return QColor(240, 248, 255);
+ else if(rgbColor == "antiquewhite")
+ return QColor(250, 235, 215);
+ else if(rgbColor == "aqua")
+ return QColor(0, 255, 255);
+ else if(rgbColor == "aquamarine")
+ return QColor(127, 255, 212);
+ else if(rgbColor == "azure")
+ return QColor(240, 255, 255);
+ else if(rgbColor == "beige")
+ return QColor(245, 245, 220);
+ else if(rgbColor == "bisque")
+ return QColor(255, 228, 196);
+ else if(rgbColor == "black")
+ return QColor(0, 0, 0);
+ else if(rgbColor == "blanchedalmond")
+ return QColor(255, 235, 205);
+ else if(rgbColor == "blue")
+ return QColor(0, 0, 255);
+ else if(rgbColor == "blueviolet")
+ return QColor(138, 43, 226);
+ else if(rgbColor == "brown")
+ return QColor(165, 42, 42);
+ else if(rgbColor == "burlywood")
+ return QColor(222, 184, 135);
+ else if(rgbColor == "cadetblue")
+ return QColor(95, 158, 160);
+ else if(rgbColor == "chartreuse")
+ return QColor(127, 255, 0);
+ else if(rgbColor == "chocolate")
+ return QColor(210, 105, 30);
+ else if(rgbColor == "coral")
+ return QColor(255, 127, 80);
+ else if(rgbColor == "cornflowerblue")
+ return QColor(100, 149, 237);
+ else if(rgbColor == "cornsilk")
+ return QColor(255, 248, 220);
+ else if(rgbColor == "crimson")
+ return QColor(220, 20, 60);
+ else if(rgbColor == "cyan")
+ return QColor(0, 255, 255);
+ else if(rgbColor == "darkblue")
+ return QColor(0, 0, 139);
+ else if(rgbColor == "darkcyan")
+ return QColor(0, 139, 139);
+ else if(rgbColor == "darkgoldenrod")
+ return QColor(184, 134, 11);
+ else if(rgbColor == "darkgray")
+ return QColor(169, 169, 169);
+ else if(rgbColor == "darkgrey")
+ return QColor(169, 169, 169);
+ else if(rgbColor == "darkgreen")
+ return QColor(0, 100, 0);
+ else if(rgbColor == "darkkhaki")
+ return QColor(189, 183, 107);
+ else if(rgbColor == "darkmagenta")
+ return QColor(139, 0, 139);
+ else if(rgbColor == "darkolivegreen")
+ return QColor(85, 107, 47);
+ else if(rgbColor == "darkorange")
+ return QColor(255, 140, 0);
+ else if(rgbColor == "darkorchid")
+ return QColor(153, 50, 204);
+ else if(rgbColor == "darkred")
+ return QColor(139, 0, 0);
+ else if(rgbColor == "darksalmon")
+ return QColor(233, 150, 122);
+ else if(rgbColor == "darkseagreen")
+ return QColor(143, 188, 143);
+ else if(rgbColor == "darkslateblue")
+ return QColor(72, 61, 139);
+ else if(rgbColor == "darkslategray")
+ return QColor(47, 79, 79);
+ else if(rgbColor == "darkslategrey")
+ return QColor(47, 79, 79);
+ else if(rgbColor == "darkturquoise")
+ return QColor(0, 206, 209);
+ else if(rgbColor == "darkviolet")
+ return QColor(148, 0, 211);
+ else if(rgbColor == "deeppink")
+ return QColor(255, 20, 147);
+ else if(rgbColor == "deepskyblue")
+ return QColor(0, 191, 255);
+ else if(rgbColor == "dimgray")
+ return QColor(105, 105, 105);
+ else if(rgbColor == "dimgrey")
+ return QColor(105, 105, 105);
+ else if(rgbColor == "dodgerblue")
+ return QColor(30, 144, 255);
+ else if(rgbColor == "firebrick")
+ return QColor(178, 34, 34);
+ else if(rgbColor == "floralwhite")
+ return QColor(255, 250, 240);
+ else if(rgbColor == "forestgreen")
+ return QColor(34, 139, 34);
+ else if(rgbColor == "fuchsia")
+ return QColor(255, 0, 255);
+ else if(rgbColor == "gainsboro")
+ return QColor(220, 220, 220);
+ else if(rgbColor == "ghostwhite")
+ return QColor(248, 248, 255);
+ else if(rgbColor == "gold")
+ return QColor(255, 215, 0);
+ else if(rgbColor == "goldenrod")
+ return QColor(218, 165, 32);
+ else if(rgbColor == "gray")
+ return QColor(128, 128, 128);
+ else if(rgbColor == "grey")
+ return QColor(128, 128, 128);
+ else if(rgbColor == "green")
+ return QColor(0, 128, 0);
+ else if(rgbColor == "greenyellow")
+ return QColor(173, 255, 47);
+ else if(rgbColor == "honeydew")
+ return QColor(240, 255, 240);
+ else if(rgbColor == "hotpink")
+ return QColor(255, 105, 180);
+ else if(rgbColor == "indianred")
+ return QColor(205, 92, 92);
+ else if(rgbColor == "indigo")
+ return QColor(75, 0, 130);
+ else if(rgbColor == "ivory")
+ return QColor(255, 255, 240);
+ else if(rgbColor == "khaki")
+ return QColor(240, 230, 140);
+ else if(rgbColor == "lavender")
+ return QColor(230, 230, 250);
+ else if(rgbColor == "lavenderblush")
+ return QColor(255, 240, 245);
+ else if(rgbColor == "lawngreen")
+ return QColor(124, 252, 0);
+ else if(rgbColor == "lemonchiffon")
+ return QColor(255, 250, 205);
+ else if(rgbColor == "lightblue")
+ return QColor(173, 216, 230);
+ else if(rgbColor == "lightcoral")
+ return QColor(240, 128, 128);
+ else if(rgbColor == "lightcyan")
+ return QColor(224, 255, 255);
+ else if(rgbColor == "lightgoldenrodyellow")
+ return QColor(250, 250, 210);
+ else if(rgbColor == "lightgray")
+ return QColor(211, 211, 211);
+ else if(rgbColor == "lightgrey")
+ return QColor(211, 211, 211);
+ else if(rgbColor == "lightgreen")
+ return QColor(144, 238, 144);
+ else if(rgbColor == "lightpink")
+ return QColor(255, 182, 193);
+ else if(rgbColor == "lightsalmon")
+ return QColor(255, 160, 122);
+ else if(rgbColor == "lightseagreen")
+ return QColor(32, 178, 170);
+ else if(rgbColor == "lightskyblue")
+ return QColor(135, 206, 250);
+ else if(rgbColor == "lightslategray")
+ return QColor(119, 136, 153);
+ else if(rgbColor == "lightslategrey")
+ return QColor(119, 136, 153);
+ else if(rgbColor == "lightsteelblue")
+ return QColor(176, 196, 222);
+ else if(rgbColor == "lightyellow")
+ return QColor(255, 255, 224);
+ else if(rgbColor == "lime")
+ return QColor(0, 255, 0);
+ else if(rgbColor == "limegreen")
+ return QColor(50, 205, 50);
+ else if(rgbColor == "linen")
+ return QColor(250, 240, 230);
+ else if(rgbColor == "magenta")
+ return QColor(255, 0, 255);
+ else if(rgbColor == "maroon")
+ return QColor(128, 0, 0);
+ else if(rgbColor == "mediumaquamarine")
+ return QColor(102, 205, 170);
+ else if(rgbColor == "mediumblue")
+ return QColor(0, 0, 205);
+ else if(rgbColor == "mediumorchid")
+ return QColor(186, 85, 211);
+ else if(rgbColor == "mediumpurple")
+ return QColor(147, 112, 219);
+ else if(rgbColor == "mediumseagreen")
+ return QColor(60, 179, 113);
+ else if(rgbColor == "mediumslateblue")
+ return QColor(123, 104, 238);
+ else if(rgbColor == "mediumspringgreen")
+ return QColor(0, 250, 154);
+ else if(rgbColor == "mediumturquoise")
+ return QColor(72, 209, 204);
+ else if(rgbColor == "mediumvioletred")
+ return QColor(199, 21, 133);
+ else if(rgbColor == "midnightblue")
+ return QColor(25, 25, 112);
+ else if(rgbColor == "mintcream")
+ return QColor(245, 255, 250);
+ else if(rgbColor == "mistyrose")
+ return QColor(255, 228, 225);
+ else if(rgbColor == "moccasin")
+ return QColor(255, 228, 181);
+ else if(rgbColor == "navajowhite")
+ return QColor(255, 222, 173);
+ else if(rgbColor == "navy")
+ return QColor(0, 0, 128);
+ else if(rgbColor == "oldlace")
+ return QColor(253, 245, 230);
+ else if(rgbColor == "olive")
+ return QColor(128, 128, 0);
+ else if(rgbColor == "olivedrab")
+ return QColor(107, 142, 35);
+ else if(rgbColor == "orange")
+ return QColor(255, 165, 0);
+ else if(rgbColor == "orangered")
+ return QColor(255, 69, 0);
+ else if(rgbColor == "orchid")
+ return QColor(218, 112, 214);
+ else if(rgbColor == "palegoldenrod")
+ return QColor(238, 232, 170);
+ else if(rgbColor == "palegreen")
+ return QColor(152, 251, 152);
+ else if(rgbColor == "paleturquoise")
+ return QColor(175, 238, 238);
+ else if(rgbColor == "palevioletred")
+ return QColor(219, 112, 147);
+ else if(rgbColor == "papayawhip")
+ return QColor(255, 239, 213);
+ else if(rgbColor == "peachpuff")
+ return QColor(255, 218, 185);
+ else if(rgbColor == "peru")
+ return QColor(205, 133, 63);
+ else if(rgbColor == "pink")
+ return QColor(255, 192, 203);
+ else if(rgbColor == "plum")
+ return QColor(221, 160, 221);
+ else if(rgbColor == "powderblue")
+ return QColor(176, 224, 230);
+ else if(rgbColor == "purple")
+ return QColor(128, 0, 128);
+ else if(rgbColor == "red")
+ return QColor(255, 0, 0);
+ else if(rgbColor == "rosybrown")
+ return QColor(188, 143, 143);
+ else if(rgbColor == "royalblue")
+ return QColor(65, 105, 225);
+ else if(rgbColor == "saddlebrown")
+ return QColor(139, 69, 19);
+ else if(rgbColor == "salmon")
+ return QColor(250, 128, 114);
+ else if(rgbColor == "sandybrown")
+ return QColor(244, 164, 96);
+ else if(rgbColor == "seagreen")
+ return QColor(46, 139, 87);
+ else if(rgbColor == "seashell")
+ return QColor(255, 245, 238);
+ else if(rgbColor == "sienna")
+ return QColor(160, 82, 45);
+ else if(rgbColor == "silver")
+ return QColor(192, 192, 192);
+ else if(rgbColor == "skyblue")
+ return QColor(135, 206, 235);
+ else if(rgbColor == "slateblue")
+ return QColor(106, 90, 205);
+ else if(rgbColor == "slategray")
+ return QColor(112, 128, 144);
+ else if(rgbColor == "slategrey")
+ return QColor(112, 128, 144);
+ else if(rgbColor == "snow")
+ return QColor(255, 250, 250);
+ else if(rgbColor == "springgreen")
+ return QColor(0, 255, 127);
+ else if(rgbColor == "steelblue")
+ return QColor(70, 130, 180);
+ else if(rgbColor == "tan")
+ return QColor(210, 180, 140);
+ else if(rgbColor == "teal")
+ return QColor(0, 128, 128);
+ else if(rgbColor == "thistle")
+ return QColor(216, 191, 216);
+ else if(rgbColor == "tomato")
+ return QColor(255, 99, 71);
+ else if(rgbColor == "turquoise")
+ return QColor(64, 224, 208);
+ else if(rgbColor == "violet")
+ return QColor(238, 130, 238);
+ else if(rgbColor == "wheat")
+ return QColor(245, 222, 179);
+ else if(rgbColor == "white")
+ return QColor(255, 255, 255);
+ else if(rgbColor == "whitesmoke")
+ return QColor(245, 245, 245);
+ else if(rgbColor == "yellow")
+ return QColor(255, 255, 0);
+ else if(rgbColor == "yellowgreen")
+ return QColor(154, 205, 50);
+ }
+
+ return QColor();
+}
+
+double KSVGIconPainter::dpi()
+{
+ return 90.0; // TODO: make modal?
+}
+
+double KSVGIconPainter::toPixel(const QString &s, bool hmode)
+{
+ if(s.isEmpty())
+ return 0.0;
+
+ QString check = s;
+
+ double ret = 0.0;
+
+ double value = 0;
+ const char *start = check.latin1();
+ const char *end = getCoord(start, value);
+
+ if(uint(end - start) < check.length())
+ {
+ if(check.endsWith("px"))
+ ret = value;
+ else if(check.endsWith("cm"))
+ ret = (value / 2.54) * dpi();
+ else if(check.endsWith("pc"))
+ ret = (value / 6.0) * dpi();
+ else if(check.endsWith("mm"))
+ ret = (value / 25.4) * dpi();
+ else if(check.endsWith("in"))
+ ret = value * dpi();
+ else if(check.endsWith("pt"))
+ ret = (value / 72.0) * dpi();
+ else if(check.endsWith("%"))
+ {
+ ret = value / 100.0;
+
+ if(hmode)
+ ret *= d->drawWidth;
+ else
+ ret *= d->drawHeight;
+ }
+ else if(check.endsWith("em"))
+ {
+ ret = value * 10.0; // TODO make this depend on actual font size
+ }
+ }
+ else
+ ret = value;
+
+ return ret;
+}
+
+ArtGradientLinear *KSVGIconPainter::linearGradient(const QString &id)
+{
+ return d->helper->m_linearGradientMap[id];
+}
+
+void KSVGIconPainter::addLinearGradient(const QString &id, ArtGradientLinear *gradient)
+{
+ d->helper->m_linearGradientMap.insert(id, gradient);
+}
+
+QDomElement KSVGIconPainter::linearGradientElement(ArtGradientLinear *linear)
+{
+ return d->helper->m_linearGradientElementMap[linear];
+}
+
+void KSVGIconPainter::addLinearGradientElement(ArtGradientLinear *gradient, QDomElement element)
+{
+ d->helper->m_linearGradientElementMap.insert(gradient, element);
+}
+
+ArtGradientRadial *KSVGIconPainter::radialGradient(const QString &id)
+{
+ return d->helper->m_radialGradientMap[id];
+}
+
+void KSVGIconPainter::addRadialGradient(const QString &id, ArtGradientRadial *gradient)
+{
+ d->helper->m_radialGradientMap.insert(id, gradient);
+}
+
+QDomElement KSVGIconPainter::radialGradientElement(ArtGradientRadial *radial)
+{
+ return d->helper->m_radialGradientElementMap[radial];
+}
+
+void KSVGIconPainter::addRadialGradientElement(ArtGradientRadial *gradient, QDomElement element)
+{
+ d->helper->m_radialGradientElementMap.insert(gradient, element);
+}
+
+Q_UINT32 KSVGIconPainter::toArtColor(const QColor &color)
+{
+ return d->helper->toArtColor(color);
+}
+
+QWMatrix KSVGIconPainter::parseTransform(const QString &transform)
+{
+ QWMatrix result;
+
+ // Split string for handling 1 transform statement at a time
+ QStringList subtransforms = QStringList::split(')', transform);
+ QStringList::ConstIterator it = subtransforms.begin();
+ QStringList::ConstIterator end = subtransforms.end();
+ for(; it != end; ++it)
+ {
+ QStringList subtransform = QStringList::split('(', (*it));
+
+ subtransform[0] = subtransform[0].stripWhiteSpace().lower();
+ subtransform[1] = subtransform[1].simplifyWhiteSpace();
+ QRegExp reg("([-]?\\d*\\.?\\d+(?:e[-]?\\d+)?)");
+
+ int pos = 0;
+ QStringList params;
+
+ while(pos >= 0)
+ {
+ pos = reg.search(subtransform[1], pos);
+ if(pos != -1)
+ {
+ params += reg.cap(1);
+ pos += reg.matchedLength();
+ }
+ }
+
+ if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
+ subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
+
+ if(subtransform[0] == "rotate")
+ {
+ if(params.count() == 3)
+ {
+ double x = params[1].toDouble();
+ double y = params[2].toDouble();
+
+ result.translate(x, y);
+ result.rotate(params[0].toDouble());
+ result.translate(-x, -y);
+ }
+ else
+ result.rotate(params[0].toDouble());
+ }
+ else if(subtransform[0] == "translate")
+ {
+ if(params.count() == 2)
+ result.translate(params[0].toDouble(), params[1].toDouble());
+ else // Spec : if only one param given, assume 2nd param to be 0
+ result.translate(params[0].toDouble() , 0);
+ }
+ else if(subtransform[0] == "scale")
+ {
+ if(params.count() == 2)
+ result.scale(params[0].toDouble(), params[1].toDouble());
+ else // Spec : if only one param given, assume uniform scaling
+ result.scale(params[0].toDouble(), params[0].toDouble());
+ }
+ else if(subtransform[0] == "skewx")
+ result.shear(tan(params[0].toDouble() * deg2rad), 0.0F);
+ else if(subtransform[0] == "skewy")
+ result.shear(tan(params[0].toDouble() * deg2rad), 0.0F);
+ else if(subtransform[0] == "skewy")
+ result.shear(0.0F, tan(params[0].toDouble() * deg2rad));
+ else if(subtransform[0] == "matrix")
+ {
+ if(params.count() >= 6)
+ {
+ result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), params[5].toDouble());
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/kdecore/svgicons/ksvgiconpainter.h b/kdecore/svgicons/ksvgiconpainter.h
new file mode 100644
index 000000000..6617897fc
--- /dev/null
+++ b/kdecore/svgicons/ksvgiconpainter.h
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGIconPainter_H
+#define KSVGIconPainter_H
+
+#include <libart_lgpl/art_render.h>
+#include <libart_lgpl/art_render_gradient.h>
+
+class QImage;
+class QColor;
+class QWMatrix;
+class QDomElement;
+class QPointArray;
+
+class KDECORE_EXPORT KSVGIconPainter
+{
+public:
+ KSVGIconPainter(int width, int height);
+ ~KSVGIconPainter();
+
+ void setDrawWidth(int dwidth);
+ void setDrawHeight(int dheight);
+
+ QImage *image();
+
+ QWMatrix *worldMatrix();
+
+ void finish();
+
+ void setUseFill(bool fill);
+ void setUseStroke(bool stroke);
+
+ void setStrokeWidth(double width);
+ void setStrokeMiterLimit(const QString &miter);
+ void setCapStyle(const QString &cap);
+ void setJoinStyle(const QString &join);
+ void setStrokeColor(const QString &stroke);
+ void setFillColor(const QString &fill);
+ void setFillRule(const QString &fillRule);
+ void setOpacity(const QString &opacity);
+ void setFillOpacity(const QString &fillOpacity);
+ void setStrokeOpacity(const QString &strokeOpacity);
+ void setStrokeDashOffset(const QString &dashOffset);
+ void setStrokeDashArray(const QString &dashes);
+
+ void setWorldMatrix(QWMatrix *worldMatrix);
+ void setClippingRect(int x, int y, int w, int h);
+
+ void drawRectangle(double x, double y, double w, double h, double rx, double ry);
+ void drawEllipse(double cx, double cy, double rx, double ry);
+ void drawLine(double x1, double y1, double x2, double y2);
+ void drawPolyline(QPointArray polyArray, int points = -1);
+ void drawPolygon(QPointArray polyArray);
+ void drawPath(const QString &data, bool fill);
+ void drawImage(double x, double y, QImage &image);
+
+ QColor parseColor(const QString &param);
+ Q_UINT32 toArtColor(const QColor &color);
+ Q_UINT32 parseOpacity(const QString &data);
+
+ double toPixel(const QString &s, bool hmode);
+ double dpi();
+
+ ArtGradientLinear *linearGradient(const QString &id);
+ void addLinearGradient(const QString &id, ArtGradientLinear *gradient);
+
+ QDomElement linearGradientElement(ArtGradientLinear *linear);
+ void addLinearGradientElement(ArtGradientLinear *gradient, QDomElement element);
+
+ ArtGradientRadial *radialGradient(const QString &id);
+ void addRadialGradient(const QString &id, ArtGradientRadial *gradient);
+
+ QDomElement radialGradientElement(ArtGradientRadial *radial);
+ void addRadialGradientElement(ArtGradientRadial *gradient, QDomElement element);
+
+ QWMatrix parseTransform(const QString &transform);
+
+private:
+ struct Private;
+ Private *d;
+};
+
+#endif
diff --git a/kdecore/tests/KIDLTest.cpp b/kdecore/tests/KIDLTest.cpp
new file mode 100644
index 000000000..89e2142fc
--- /dev/null
+++ b/kdecore/tests/KIDLTest.cpp
@@ -0,0 +1,33 @@
+#include "KIDLTest.h"
+
+#include <kapplication.h>
+#include <dcopclient.h>
+
+KIDLTest::KIDLTest( const QCString& id )
+ : DCOPObject( id )
+{
+}
+
+QString KIDLTest::hello( const QString& name )
+{
+ qDebug("Du heter %s", name.latin1() );
+ qDebug("Ha det %s", name.latin1() );
+
+ return QString("Jeg heter KIDLTest");
+}
+
+int main( int argc, char** argv )
+{
+ KApplication app( argc, argv, "kidlservertest", false /* No GUI */ );
+
+ app.dcopClient()->attach();
+ app.dcopClient()->registerAs( "kidlservertest" );
+
+ qDebug("Server process started...");
+
+ (void) new KIDLTest( "Hello" );
+
+ qDebug("Server listening ...");
+
+ return app.exec();
+}
diff --git a/kdecore/tests/KIDLTest.h b/kdecore/tests/KIDLTest.h
new file mode 100644
index 000000000..f0c4aaefd
--- /dev/null
+++ b/kdecore/tests/KIDLTest.h
@@ -0,0 +1,16 @@
+#ifndef KIDLTEST_H
+#define KIDLTEST_H
+
+#include <dcopobject.h>
+
+class KIDLTest : virtual public DCOPObject
+{
+ K_DCOP
+public:
+ KIDLTest( const QCString& id );
+
+k_dcop:
+ virtual QString hello( const QString& name );
+};
+
+#endif
diff --git a/kdecore/tests/KIDLTestClient.cpp b/kdecore/tests/KIDLTestClient.cpp
new file mode 100644
index 000000000..0b9e45768
--- /dev/null
+++ b/kdecore/tests/KIDLTestClient.cpp
@@ -0,0 +1,17 @@
+#include <kapplication.h>
+#include <dcopclient.h>
+
+#include "KIDLTest_stub.h"
+
+int main( int argc, char** argv )
+{
+ KApplication app( argc, argv, "KIDLTestClient", false /* No GUI */ );
+
+ kapp->dcopClient()->attach();
+ // kapp->dcopClient()->registerAs( "kidlclienttest" );
+
+ KIDLTest_stub* t = new KIDLTest_stub( "kidlservertest", "Hello" );
+
+ QString ret = t->hello("Torben");
+ qDebug("Server says: %s", ret.latin1() );
+}
diff --git a/kdecore/tests/Makefile.am b/kdecore/tests/Makefile.am
new file mode 100644
index 000000000..3d05e1ac2
--- /dev/null
+++ b/kdecore/tests/Makefile.am
@@ -0,0 +1,86 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997-1998 Stephan Kulow (coolo@kde.org)
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+
+# This library 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+INCLUDES = -I$(top_srcdir)/kdecore $(all_includes)
+
+AM_LDFLAGS = $(QT_LDFLAGS) $(X_LDFLAGS) $(KDE_RPATH)
+
+check_PROGRAMS = kconfigtestgui klocaletest kprocesstest ksimpleconfigtest \
+ kstddirstest kurltest kuniqueapptest ktempfiletest krandomsequencetest \
+ kdebugtest ksocktest kstringhandlertest kcmdlineargstest kapptest \
+ kmemtest kidlservertest kidlclienttest dcopkonqtest kipctest \
+ cplusplustest kiconloadertest kresolvertest kmdcodectest knotifytest \
+ ksortablevaluelisttest krfcdatetest testqtargs kprociotest \
+ kcharsetstest kcalendartest kmacroexpandertest kshelltest \
+ kxerrorhandlertest startserviceby kstdacceltest kglobaltest ktimezonestest
+
+TESTS = kurltest kstdacceltest
+
+noinst_HEADERS = klocaletest.h kprocesstest.h KIDLTest.h \
+ kipctest.h kprociotest.h
+
+METASOURCES = AUTO
+
+LDADD = ../libkdecore.la
+kconfigtestgui_SOURCES = kconfigtestgui.cpp
+kdebugtest_SOURCES = kdebugtest.cpp
+klocaletest_SOURCES = klocaletest.cpp
+#klocaletest2_SOURCES = klocaletest2.cpp klocale.cpp libintl.cpp kcatalogue.cpp
+#kcatalogue_SOURCES = kcatalogue.cpp libintl.cpp
+ksimpleconfigtest_SOURCES = ksimpleconfigtest.cpp
+kurltest_SOURCES = kurltest.cpp
+kstddirstest_SOURCES = kstddirstest.cpp
+kprocesstest_SOURCES = kprocesstest.cpp
+kuniqueapptest_SOURCES = kuniqueapptest.cpp
+kapptest_SOURCES = kapptest.cpp
+ksocktest_SOURCES = ksocktest.cpp
+ktempfiletest_SOURCES = ktempfiletest.cpp
+krandomsequencetest_SOURCES = krandomsequencetest.cpp
+kstringhandlertest_SOURCES = kstringhandlertest.cpp
+kcmdlineargstest_SOURCES = kcmdlineargstest.cpp
+dcopkonqtest_SOURCES = dcopkonqtest.cpp
+kmemtest_SOURCES = kmemtest.cpp
+kidlservertest_SOURCES = KIDLTest.cpp KIDLTest.skel
+kidlclienttest_SOURCES = KIDLTestClient.cpp KIDLTest.stub
+$(srcdir)/KIDLTestClient.cpp: KIDLTest_stub.h
+kipctest_SOURCES = kipctest.cpp
+cplusplustest_SOURCES = cplusplustest.cpp
+kiconloadertest_SOURCES = kiconloadertest.cpp
+kresolvertest_SOURCES = kresolvertest.cpp
+kmdcodectest_SOURCES = kmdcodectest.cpp
+knotifytest_SOURCES = knotifytest.cpp
+ksortablevaluelisttest_SOURCES = ksortablevaluelisttest.cpp
+krfcdatetest_SOURCES = krfcdatetest.cpp
+testqtargs_SOURCES = testqtargs.cpp
+kprociotest_SOURCES = kprociotest.cpp
+kcharsetstest_SOURCES = kcharsetstest.cpp
+kcalendartest_SOURCES = kcalendartest.cpp
+kmacroexpandertest_SOURCES = kmacroexpandertest.cpp
+kshelltest_SOURCES = kshelltest.cpp
+kxerrorhandlertest_SOURCES = kxerrorhandlertest.cpp
+startserviceby_SOURCES = startserviceby.cpp
+kstdacceltest_SOURCES = kstdacceltest.cpp
+kglobaltest_SOURCES = kglobaltest.cpp
+ktimezonestest_SOURCES = ktimezonestest.cpp
+
+check_LTLIBRARIES = kunittest_kconfig.la
+
+kunittest_kconfig_la_SOURCES = kconfigtest.cpp
+kunittest_kconfig_la_LIBADD = $(LIB_KUNITTEST)
+kunittest_kconfig_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN)
diff --git a/kdecore/tests/cplusplustest.cpp b/kdecore/tests/cplusplustest.cpp
new file mode 100644
index 000000000..387dac014
--- /dev/null
+++ b/kdecore/tests/cplusplustest.cpp
@@ -0,0 +1,44 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qstring.h>
+#include <qdict.h>
+
+class A { int foo; };
+class B { int bar; };
+class C : public A, public B { int foobar; };
+
+QDict<A> dictA;
+QDict<B> dictB;
+
+int main(int , char *[])
+{
+ C obj;
+ A *pA = &obj;
+ B *pB = &obj;
+ C *pC = &obj;
+qWarning("pA = %p, pB = %p, pC = %p", pA, pB, pC);
+ if (pA == pC) qWarning("pA == pC");
+ if (pB == pC) qWarning("pB == pC");
+
+ dictA.insert("hello", pC);
+ dictB.insert("hello", pC);
+
+ if (dictA["hello"] == pC) qWarning("dictA['hello'] == pC");
+ if (dictB["hello"] == pC) qWarning("dictB['hello'] == pC");
+}
diff --git a/kdecore/tests/dcopkonqtest.cpp b/kdecore/tests/dcopkonqtest.cpp
new file mode 100644
index 000000000..95dd726e3
--- /dev/null
+++ b/kdecore/tests/dcopkonqtest.cpp
@@ -0,0 +1,36 @@
+#include <kapplication.h>
+#include <kdebug.h>
+#include <dcopclient.h>
+
+int main( int argc, char** argv )
+{
+ KApplication app( argc, argv, "KIDLTestClient", false );
+
+ kapp->dcopClient()->attach();
+ // kapp->dcopClient()->registerAs( "kidlclienttest" );
+
+ QByteArray data;
+
+ kdDebug() << "sending reparseConfiguration to object KonquerorIface in konqueror" << endl;
+ QByteArray snd;
+ QByteArray rcv;
+ QCString _type_;
+ kapp->dcopClient()->call( "konqueror", "KonquerorIface", "reparseConfiguration()", snd, _type_, rcv );
+ kdDebug() << _type_ << endl;
+ if( _type_ != "void" ) kdDebug() << "void expected, " << _type_.data() << " returned" << endl;
+
+/*
+debug("sending configure to object KonquerorIface in konqueror");
+ if (kapp->dcopClient()->send( "konqueror", "KonquerorIface", "configure()", data ))
+ debug("ok");
+ else
+ debug("ko");
+
+/// BROADCAST
+debug("sending databaseChanged to object ksycoca in all apps");
+ if (kapp->dcopClient()->send( "*", "ksycoca", "databaseChanged()", data ))
+ debug("ok");
+ else
+ debug("ko");
+*/
+}
diff --git a/kdecore/tests/kapptest.cpp b/kdecore/tests/kapptest.cpp
new file mode 100644
index 000000000..4a6465099
--- /dev/null
+++ b/kdecore/tests/kapptest.cpp
@@ -0,0 +1,40 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#define private public
+#include "kapplication.h"
+#include <stdio.h>
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kglobalsettings.h>
+#include <ksycoca.h>
+
+int
+main(int argc, char *argv[])
+{
+ KAboutData about("kapptest", "kapptest", "version");
+ KCmdLineArgs::init(argc, argv, &about);
+
+ KApplication a;
+
+ KSycoca *s = KSycoca::self();
+
+ qWarning("s->language() %s", s->language().latin1());
+ qWarning("Offset of aIconName: %ld", (long) &(static_cast<KApplication *>(0)->aIconName));
+}
diff --git a/kdecore/tests/kcalendartest.cpp b/kdecore/tests/kcalendartest.cpp
new file mode 100644
index 000000000..18b4fc297
--- /dev/null
+++ b/kdecore/tests/kcalendartest.cpp
@@ -0,0 +1,152 @@
+// Simplest example using two kde calendar systems (gregorian and hijri)
+// Carlos Moro <cfmoro@correo.uniovi.es>
+// GNU-GPL v.2
+
+#include "kcalendarsystemfactory.h"
+#include "kcalendarsystem.h"
+
+#include <qstringlist.h>
+
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+class KLocale;
+
+void test(QDate & date);
+
+static const char description[] = "KCalendarTest";
+
+static KCmdLineOptions options[] =
+{
+ { "help", I18N_NOOP("Prints this help"), 0 },
+ { "type hijri|gregorian|jalali|hebrew", I18N_NOOP("Supported calendar types"), 0 },
+ { "date <date>", I18N_NOOP("Show day info"), 0 },
+};
+
+int main(int argc, char **argv) {
+
+ QDate date;
+ QString calType, option;
+
+ KAboutData aboutData( "kcalendartest", "KCalendarTest" ,
+ "0.1", description, KAboutData::License_GPL,
+ "(c) 2002, Carlos Moro", 0, 0,
+ "cfmoro@correo.uniovi.es");
+ aboutData.addAuthor("Carlos Moro",0, "cfmoro@correo.uniovi.es");
+
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ KApplication app(false, false);
+
+ QStringList lst = KCalendarSystemFactory::calendarSystems();
+ kdDebug() << "Supported calendar types: " << endl;
+ for (QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
+ kdDebug() << *it << endl;
+ kdDebug() << endl;
+
+
+ if ( args->isSet("type") )
+ calType = args->getOption("type");
+
+
+ KGlobal::locale()->setCalendar(calType);
+
+ /*
+ * If we like to see some date
+ *
+ */
+ if ( args->isSet("date") ) {
+ option = args->getOption("date");
+ date = KGlobal::locale()->readDate(option);
+ } else
+ date = QDate::currentDate();
+
+ args->clear(); // Free up some memory.
+
+ test(date);
+
+ return 0;
+
+
+
+}
+
+void test(QDate & date) {
+
+ kdDebug() << "(KLocale) readDate" << endl;
+
+ kdDebug() << "Created calendar: " << KGlobal::locale()->calendar()->calendarName() << endl;
+
+ kdDebug() << "Day name for first day of week is " << KGlobal::locale()->calendar()->weekDayName(1) << endl;
+ kdDebug() << "Short month name for second month is " << KGlobal::locale()->calendar()->weekDayName(1, true) << endl;
+
+ kdDebug() << "Month name for second month is " << KGlobal::locale()->calendar()->monthName(2, KGlobal::locale()->calendar()->year(date)) << endl;
+ kdDebug() << "Short month name for second month is " << KGlobal::locale()->calendar()->monthName(2, KGlobal::locale()->calendar()->year(date), true) << endl;
+ kdDebug() << "Month name possessive for second month is " << KGlobal::locale()->calendar()->monthNamePossessive(2, KGlobal::locale()->calendar()->year(date)) << endl;
+ kdDebug() << "Short month name possessive for second month is " << KGlobal::locale()->calendar()->monthNamePossessive(2, KGlobal::locale()->calendar()->year(date), true) << endl;
+ kdDebug() << "Month name for fifth month is " << KGlobal::locale()->calendar()->monthName(5, KGlobal::locale()->calendar()->year(date)) << endl;
+ kdDebug() << "Short month name for fifth month is " << KGlobal::locale()->calendar()->monthName(5, KGlobal::locale()->calendar()->year(date), true) << endl;
+ kdDebug() << "Month name possessive for fifth month is " << KGlobal::locale()->calendar()->monthNamePossessive(5, KGlobal::locale()->calendar()->year(date)) << endl;
+ kdDebug() << "Short month name possessive for fifth month is " << KGlobal::locale()->calendar()->monthNamePossessive(5, KGlobal::locale()->calendar()->year(date), true) << endl;
+
+ kdDebug() << "Day for date " << date.toString() << " is " << KGlobal::locale()->calendar()->day(date) << endl;
+ kdDebug() << "Month for date " << date.toString() << " is " << KGlobal::locale()->calendar()->month(date) << endl;
+ kdDebug() << "Year for date " << date.toString() << " is " << KGlobal::locale()->calendar()->year(date) << endl;
+
+ kdDebug() << "Day for date " << date.toString() << " as a string is " << KGlobal::locale()->calendar()->dayString(date, true) << endl;
+ kdDebug() << "Month for date " << date.toString() << " as a string is " << KGlobal::locale()->calendar()->monthString(date, true) << endl;
+ kdDebug() << "Year for date " << date.toString() << " as a string is " << KGlobal::locale()->calendar()->yearString(date, true) << endl;
+
+ kdDebug() << "Day of week for date " << date.toString() << " is number " << KGlobal::locale()->calendar()->dayOfWeek(date) << endl;
+ kdDebug() << "Week name for date " << date.toString() << " is " << KGlobal::locale()->calendar()->weekDayName(date) << endl;
+ kdDebug() << "Short week name for date " << date.toString() << " is " << KGlobal::locale()->calendar()->weekDayName(date, true) << endl;
+
+ kdDebug() << "Month name for date " << date.toString() << " is " << KGlobal::locale()->calendar()->monthName(date) << endl;
+ kdDebug() << "Short month name for date " << date.toString() << " is " << KGlobal::locale()->calendar()->monthName(date, true) << endl;
+ kdDebug() << "Month name possessive for date " << date.toString() << " is " << KGlobal::locale()->calendar()->monthNamePossessive(date) << endl;
+ kdDebug() << "Short month name possessive for date " << date.toString() << " is " << KGlobal::locale()->calendar()->monthNamePossessive(date, true) << endl;
+
+ kdDebug() << "It's week number " << KGlobal::locale()->calendar()->weekNumber(date) << endl;
+
+
+ kdDebug() << "(KLocale) Formatted date: " << KGlobal::locale()->formatDate(date) << endl;
+ kdDebug() << "(KLocale) Short formatted date: " << KGlobal::locale()->formatDate(date, true) << endl;
+
+ kdDebug() << "That month have : " << KGlobal::locale()->calendar()->daysInMonth(date) << " days" << endl;
+
+ kdDebug() << "That year has " << KGlobal::locale()->calendar()->monthsInYear(date) << " months" << endl;
+ kdDebug() << "There are " << KGlobal::locale()->calendar()->weeksInYear(KGlobal::locale()->calendar()->year(date)) << " weeks that year" << endl;
+ kdDebug() << "There are " << KGlobal::locale()->calendar()->daysInYear(date) << " days that year" << endl;
+
+ kdDebug() << "The day of pray is number " << KGlobal::locale()->calendar()->weekDayOfPray() << endl;
+
+ kdDebug() << "Max valid year supported is " << KGlobal::locale()->calendar()->maxValidYear() << endl;
+ kdDebug() << "Min valid year supported is " << KGlobal::locale()->calendar()->minValidYear() << endl;
+
+ kdDebug() << "It's the day number " << KGlobal::locale()->calendar()->dayOfYear(date) << " of year" << endl;
+
+ kdDebug() << "Add 3 days" << endl;
+ date = KGlobal::locale()->calendar()->addDays(date, 3);
+ kdDebug() << "It's " << KGlobal::locale()->formatDate(date) << endl;
+
+ kdDebug() << "Then add 3 months" << endl;
+ date = KGlobal::locale()->calendar()->addMonths(date, 3);
+ kdDebug() << "It's " << KGlobal::locale()->formatDate(date) << endl;
+
+ kdDebug() << "And last, add -3 years" << endl;
+ date = KGlobal::locale()->calendar()->addYears(date, -3);
+ kdDebug() << "It's " << KGlobal::locale()->formatDate(date) << endl;
+
+ kdDebug() << "Is lunar based: " << KGlobal::locale()->calendar()->isLunar() << endl;
+ kdDebug() << "Is lunisolar based: " << KGlobal::locale()->calendar()->isLunisolar() << endl;
+ kdDebug() << "Is solar based: " << KGlobal::locale()->calendar()->isSolar() << endl;
+
+}
diff --git a/kdecore/tests/kcharsetstest.cpp b/kdecore/tests/kcharsetstest.cpp
new file mode 100644
index 000000000..de281d3d9
--- /dev/null
+++ b/kdecore/tests/kcharsetstest.cpp
@@ -0,0 +1,12 @@
+
+#include <kcharsets.h>
+
+#include <assert.h>
+
+int main()
+{
+ QString input( "&lt;Hello &amp;World&gt;" );
+ QString output = KCharsets::resolveEntities( input );
+ assert( output == "<Hello &World>" );
+ return 0;
+}
diff --git a/kdecore/tests/kcmdlineargstest.cpp b/kdecore/tests/kcmdlineargstest.cpp
new file mode 100644
index 000000000..2d6c7ecd2
--- /dev/null
+++ b/kdecore/tests/kcmdlineargstest.cpp
@@ -0,0 +1,91 @@
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kapplication.h>
+
+#include <stdio.h>
+
+// we use our own macro to not bother translators
+// but still demonstrate the use. You would use I18N_NOOP
+#define I18N_NOP(x) x
+
+static const char version[] = "v0.0.2 1999 (c) Waldo Bastian";
+static const char description[] = I18N_NOP("This is a test program.");
+
+static KCmdLineOptions options[] =
+{
+ { "test", I18N_NOP("do a short test only, note that\n"
+ "this is rather long comment"), 0 },
+ { "baud <baudrate>", I18N_NOP("set baudrate"), "9600" },
+ { "+file(s)", I18N_NOP("Files to load"), 0 },
+ KCmdLineLastOption
+};
+
+#if 1
+int
+main(int argc, char *argv[])
+{
+ KLocale::setMainCatalogue("kdelibs");
+ KCmdLineArgs::init( argc, argv, "testapp", description, version);
+
+ KCmdLineArgs::addCmdLineOptions( options ); // Add my own options.
+
+ // MyWidget::addCmdLineOptions();
+
+ KApplication k( false, false /*true, true*/ );
+
+ // Get application specific arguments
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ // Check if an option is set
+ if (args->isSet("test"))
+ {
+ // Do stuff
+ printf("Option 'test' is set.\n");
+ }
+
+ if (args->isSet("baud"))
+ {
+ // Do stuff
+ printf("Option 'baud' is set.\n");
+ }
+
+ // Read the value of an option.
+ QCString baudrate = args->getOption("baud"); // 9600 is the default value.
+
+ printf("Baudrate = %s\n", baudrate.data());
+
+ printf("Full list of baudrates:\n");
+ QCStringList result = args->getOptionList("baud");
+ for(QCStringList::ConstIterator it=result.begin();
+ it != result.end();
+ ++it)
+ {
+ printf("Baudrate = %s\n", (*it).data());
+ }
+ printf("End of list\n");
+
+ for(int i = 0; i < args->count(); i++)
+ {
+ printf("%d: %s\n", i, args->arg(i));
+ printf("%d: %s\n", i, args->url(i).url().ascii());
+ }
+
+ args->clear(); // Free up memory.
+
+
+// k.exec();
+ return 0;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+ KCmdLineArgs::init( argc, argv, "testapp", description, version);
+
+ KApplication k( true, true );
+
+ k.exec();
+ return 0;
+}
+#endif
+
+
diff --git a/kdecore/tests/kconfigtest.cpp b/kdecore/tests/kconfigtest.cpp
new file mode 100644
index 000000000..5ec4c309f
--- /dev/null
+++ b/kdecore/tests/kconfigtest.cpp
@@ -0,0 +1,162 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kunittest/tester.h>
+#include <kunittest/module.h>
+
+#include <kconfig.h>
+
+class KConfigTest : public KUnitTest::Tester
+{
+public:
+ void allTests();
+private:
+ void writeConfigFile();
+ void revertEntries();
+};
+
+KUNITTEST_MODULE( kunittest_kconfig, "KConfigTest" )
+KUNITTEST_MODULE_REGISTER_TESTER( KConfigTest )
+
+// test data
+#define BOOLENTRY1 true
+#define BOOLENTRY2 false
+#define STRINGENTRY1 "hello"
+#define STRINGENTRY2 " hello"
+#define STRINGENTRY3 "hello "
+#define STRINGENTRY4 " hello "
+#define STRINGENTRY5 " "
+#define STRINGENTRY6 ""
+#define LOCAL8BITENTRY "Hello äöü"
+#define POINTENTRY QPoint( 4351, 1235 )
+#define SIZEENTRY QSize( 10, 20 )
+#define RECTENTRY QRect( 10, 23, 5321, 13 )
+#define DATETIMEENTRY QDateTime( QDate( 2002, 06, 23 ), QTime( 12, 55, 40 ) )
+#define STRINGLISTENTRY QStringList( "Hello," )
+
+void KConfigTest::writeConfigFile()
+{
+ KConfig sc( "kconfigtest" );
+
+ sc.setGroup("AAA");
+ sc.writeEntry("stringEntry1", STRINGENTRY1, true, true);
+ sc.deleteEntry("stringEntry2", false, true);
+
+ sc.setGroup("Hello");
+ sc.writeEntry( "boolEntry1", BOOLENTRY1 );
+ sc.writeEntry( "boolEntry2", BOOLENTRY2 );
+
+ sc.writeEntry( "Test", QString::fromLocal8Bit( LOCAL8BITENTRY ) );
+ sc.writeEntry( "Test2", "");
+ sc.writeEntry( "stringEntry1", STRINGENTRY1 );
+ sc.writeEntry( "stringEntry2", STRINGENTRY2 );
+ sc.writeEntry( "stringEntry3", STRINGENTRY3 );
+ sc.writeEntry( "stringEntry4", STRINGENTRY4 );
+ sc.writeEntry( "stringEntry5", STRINGENTRY5 );
+// sc.writeEntry( "stringEntry6", STRINGENTRY6 );
+ sc.writeEntry( "keywith=equalsign", STRINGENTRY1 );
+ sc.deleteEntry( "stringEntry5" );
+ sc.deleteEntry( "stringEntry6" );
+
+ sc.deleteGroup("deleteMe", true);
+
+ sc.setGroup("Bye");
+ sc.writeEntry( "rectEntry", RECTENTRY );
+ sc.writeEntry( "pointEntry", POINTENTRY );
+ sc.writeEntry( "sizeEntry", SIZEENTRY );
+ sc.writeEntry( "dateTimeEntry", DATETIMEENTRY );
+ sc.writeEntry( "stringListEntry", STRINGLISTENTRY );
+ sc.sync();
+}
+
+// ### TODO: call this, and test the state of things afterwards
+void KConfigTest::revertEntries()
+{
+ qWarning("Reverting entries");
+ KConfig sc( "kconfigtest" );
+
+ sc.setGroup("Hello");
+ sc.revertToDefault( "boolEntry1");
+ sc.revertToDefault( "boolEntry2");
+
+ sc.revertToDefault( "Test" );
+ sc.revertToDefault( "Test2" );
+ sc.revertToDefault( "stringEntry1" );
+ sc.revertToDefault( "stringEntry2" );
+ sc.revertToDefault( "stringEntry3" );
+ sc.revertToDefault( "stringEntry4" );
+ sc.revertToDefault( "stringEntry5" );
+ sc.sync();
+}
+
+void KConfigTest::allTests()
+{
+ writeConfigFile();
+
+ KConfig sc2( "kconfigtest" );
+
+ KConfigGroup sc3( &sc2, "AAA");
+ bool bImmutable = sc3.entryIsImmutable("stringEntry1");
+
+ CHECK( bImmutable, false );
+ //qWarning("sc3.entryIsImmutable() 1: %s", bImmutable ? "true" : "false");
+
+ sc2.setGroup("AAA");
+ CHECK( sc2.hasKey( "stringEntry1" ), true );
+ CHECK( sc2.readEntry( "stringEntry1" ), QString( STRINGENTRY1 ) );
+ CHECK( sc2.entryIsImmutable("stringEntry1"), bImmutable );
+ CHECK( sc2.hasKey( "stringEntry2" ), false );
+ CHECK( sc2.readEntry( "stringEntry2", "bla" ), QString( "bla" ) );
+
+ CHECK( sc2.hasDefault( "stringEntry1" ), false );
+
+ sc2.setGroup("Hello");
+ CHECK( sc2.readEntry( "Test" ), QString::fromLocal8Bit( LOCAL8BITENTRY ) );
+ CHECK( sc2.readEntry("Test2", "Fietsbel").isEmpty(), true );
+ CHECK( sc2.readEntry( "stringEntry1" ), QString( STRINGENTRY1 ) );
+ CHECK( sc2.readEntry( "stringEntry2" ), QString( STRINGENTRY2 ) );
+ CHECK( sc2.readEntry( "stringEntry3" ), QString( STRINGENTRY3 ) );
+ CHECK( sc2.readEntry( "stringEntry4" ), QString( STRINGENTRY4 ) );
+ CHECK( sc2.hasKey( "stringEntry5" ), false);
+ CHECK( sc2.readEntry( "stringEntry5", "test" ), QString( "test" ) );
+ CHECK( sc2.hasKey( "stringEntry6" ), false);
+ CHECK( sc2.readEntry( "stringEntry6", "foo" ), QString( "foo" ) );
+ CHECK( sc2.readBoolEntry( "boolEntry1" ), BOOLENTRY1 );
+ CHECK( sc2.readBoolEntry( "boolEntry2" ), BOOLENTRY2 );
+
+#if 0
+ QString s;
+ s = sc2.readEntry( "keywith=equalsign" );
+ fprintf(stderr, "comparing keywith=equalsign %s with %s -> ", STRINGENTRY1, s.latin1());
+ if (s == STRINGENTRY1)
+ fprintf(stderr, "OK\n");
+ else {
+ fprintf(stderr, "not OK\n");
+ exit(-1);
+ }
+#endif
+
+ sc2.setGroup("Bye");
+
+ CHECK( sc2.readPointEntry( "pointEntry" ), POINTENTRY );
+ CHECK( sc2.readSizeEntry( "sizeEntry" ), SIZEENTRY);
+ CHECK( sc2.readRectEntry( "rectEntry" ), RECTENTRY );
+ CHECK( sc2.readDateTimeEntry( "dateTimeEntry" ).toString(), DATETIMEENTRY.toString() );
+ CHECK( sc2.readListEntry( "stringListEntry").join( "," ), STRINGLISTENTRY.join( "," ) );
+}
diff --git a/kdecore/tests/kconfigtestgui.cpp b/kdecore/tests/kconfigtestgui.cpp
new file mode 100644
index 000000000..6dbf98e52
--- /dev/null
+++ b/kdecore/tests/kconfigtestgui.cpp
@@ -0,0 +1,200 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kconfigtestgui.h"
+#include "kconfigtestgui.moc"
+
+//
+// configtest.cpp: libKDEcore example
+//
+// demonstrates use of KConfig class
+//
+// adapted from Qt widgets demo
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <kapplication.h>
+#include <qdialog.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdatetime.h>
+#include <kdebug.h>
+#include <ksimpleconfig.h>
+#include <config.h>
+
+// Standard Qt widgets
+
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+
+// KDE includes
+#include <kconfig.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef _PATH_TMP
+#define _PATH_TMP "/tmp/"
+#endif
+
+//
+// Construct the KConfigTestView with buttons
+//
+
+KConfigTestView::KConfigTestView( QWidget *parent, const char *name )
+ : QDialog( parent, name ),
+ pConfig( 0L ),
+ pFile( 0L ),
+ pStream( 0L )
+{
+ // Set the window caption/title
+
+ setCaption( "KConfig test" );
+
+ // Label and edit for the app config file
+ pAppFileLabel = new QLabel( this, "appconfiglabel" );
+ pAppFileLabel->setText( "Application config file:" );
+ pAppFileLabel->setGeometry( 20, 20, 200, 20 );
+
+ pAppFileEdit = new QLineEdit( this, "appconfigedit" );
+ pAppFileEdit->setGeometry( 240, 20, 160, 20 );
+ connect( pAppFileEdit, SIGNAL(returnPressed()),
+ SLOT(appConfigEditReturnPressed()));
+
+ // Label and edit for the group
+ pGroupLabel = new QLabel( this, "grouplabel" );
+ pGroupLabel->setText( "Group:" );
+ pGroupLabel->setGeometry( 20, 60, 80, 20 );
+
+ pGroupEdit = new QLineEdit( this, "groupedit" );
+ pGroupEdit->setGeometry( 120, 60, 100, 20 );
+ connect( pGroupEdit, SIGNAL(returnPressed()),
+ SLOT(groupEditReturnPressed()));
+
+ // Edit and label for the key/value pair
+ pKeyEdit = new QLineEdit( this, "keyedit" );
+ pKeyEdit->setGeometry( 20, 100, 80, 20 );
+ connect( pKeyEdit, SIGNAL( returnPressed()),
+ SLOT(keyEditReturnPressed()));
+
+ pEqualsLabel = new QLabel( this, "equalslabel" );
+ pEqualsLabel->setGeometry( 105, 100, 20, 20 );
+ pEqualsLabel->setText( "=" );
+
+ pValueEdit = new QLineEdit( this, "valueedit" );
+ pValueEdit->setGeometry( 120, 100, 100, 20 );
+ pValueEdit->setText( "---" );
+
+ pWriteButton = new QPushButton( this, "writebutton" );
+ pWriteButton->setGeometry( 20,140, 80, 20 );
+ pWriteButton->setText( "Write entry" );
+ connect( pWriteButton, SIGNAL(clicked()), SLOT( writeButtonClicked() ) );
+
+ // Labels for the info line
+ pInfoLabel1 = new QLabel( this, "infolabel1" );
+ pInfoLabel1->setGeometry( 20, 200, 60, 20 );
+ pInfoLabel1->setText( "Info:" );
+
+ pInfoLabel2 = new QLabel( this, "infolabel2" );
+ pInfoLabel2->setGeometry( 100, 200, 300, 20 );
+ pInfoLabel2->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ // Quit button
+ pQuitButton = new QPushButton( this, "quitbutton" );
+ pQuitButton->setText( "Quit" );
+ pQuitButton->setGeometry( 340, 60, 60, 60 );
+ connect( pQuitButton, SIGNAL(clicked()), qApp, SLOT(quit()) );
+
+ // create a default KConfig object in order to be able to start right away
+ pConfig = new KConfig( QString::null );
+}
+
+KConfigTestView::~KConfigTestView()
+{
+ delete pConfig;
+ delete pFile;
+ delete pStream;
+}
+
+void KConfigTestView::appConfigEditReturnPressed()
+{
+ // if there already was a config object, delete it and its associated data
+ delete pConfig;
+ pConfig = 0L;
+ delete pFile;
+ pFile = 0L;
+ delete pStream;
+ pStream = 0L;
+
+ // create a new config object
+ if( !pAppFileEdit->text().isEmpty() )
+ pConfig = new KConfig( pAppFileEdit->text() );
+
+ pInfoLabel2->setText( "New config object created." );
+}
+
+void KConfigTestView::groupEditReturnPressed()
+{
+ pConfig->setGroup( pGroupEdit->text() );
+ // according to the Qt doc, this is begging for trouble, but for a
+ // test program this will do
+ QString aText;
+ aText.sprintf( "Group set to %s", QString( pConfig->group() ).isEmpty() ?
+ QString("<default>").ascii() : pConfig->group().ascii() );
+ pInfoLabel2->setText( aText );
+}
+
+void KConfigTestView::keyEditReturnPressed()
+{
+ QString aValue = pConfig->readEntry( pKeyEdit->text() );
+ // just checking aValue.isNull() would be easier here, but this is
+ // to demonstrate the HasKey()-method. Besides, it is better data
+ // encapsulation because we do not make any assumption about coding
+ // non-values here.
+ if( !pConfig->hasKey( pKeyEdit->text() ) )
+ {
+ pInfoLabel2->setText( "Key not found!" );
+ pValueEdit->setText( "---" );
+ }
+ else
+ {
+ pInfoLabel2->setText( "Key found!" );
+ pValueEdit->setText( aValue );
+ }
+}
+
+void KConfigTestView::writeButtonClicked()
+{
+ pConfig->writeEntry( pKeyEdit->text(), QString( pValueEdit->text() ) );
+ pInfoLabel2->setText( "Entry written" );
+
+ kdDebug() << "Entry written: " << 27 << endl;
+}
+
+
+int main( int argc, char **argv )
+{
+ KApplication a( argc, argv, "bla" );
+
+ KConfigTestView *w = new KConfigTestView();
+ a.setMainWidget( w );
+ return w->exec();
+}
diff --git a/kdecore/tests/kconfigtestgui.h b/kdecore/tests/kconfigtestgui.h
new file mode 100644
index 000000000..e293000f5
--- /dev/null
+++ b/kdecore/tests/kconfigtestgui.h
@@ -0,0 +1,72 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KCONFIG_TEST_H
+#define _KCONFIG_TEST_H
+
+#include <kapplication.h>
+#include <qdialog.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <kdebug.h>
+#include <ksimpleconfig.h>
+#include <qtextstream.h>
+
+// Standard Qt widgets
+
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+
+#include <kconfig.h>
+
+//
+// KConfigTestView contains lots of Qt widgets.
+//
+
+class KConfigTestView : public QDialog
+{
+ Q_OBJECT
+public:
+ KConfigTestView( QWidget *parent=0, const char *name=0 );
+ ~KConfigTestView();
+
+private slots:
+ void appConfigEditReturnPressed();
+ void groupEditReturnPressed();
+ void keyEditReturnPressed();
+ void writeButtonClicked();
+
+private:
+ QLabel* pAppFileLabel;
+ QLineEdit* pAppFileEdit;
+ QLabel* pGroupLabel;
+ QLineEdit* pGroupEdit;
+ QLineEdit* pKeyEdit;
+ QLabel* pEqualsLabel;
+ QLineEdit* pValueEdit;
+ QPushButton* pWriteButton;
+ QLabel* pInfoLabel1, *pInfoLabel2;
+ QPushButton* pQuitButton;
+
+ KConfig* pConfig;
+ QFile* pFile;
+ QTextStream* pStream;
+};
+
+#endif
diff --git a/kdecore/tests/kdebugtest.cpp b/kdecore/tests/kdebugtest.cpp
new file mode 100644
index 000000000..d97fb671b
--- /dev/null
+++ b/kdecore/tests/kdebugtest.cpp
@@ -0,0 +1,98 @@
+#include "kdebug.h"
+#include <qwidget.h>
+#include <kinstance.h>
+#include <iostream>
+#include <qapplication.h>
+#include <qpen.h>
+#include <qvariant.h>
+
+class TestWidget : public QWidget
+{
+
+public:
+ TestWidget(QWidget* parent, const char* name)
+ : QWidget(parent, name)
+ {
+ kdDebug().form("mytest %s", "hello") << endl;
+ QString test = "%20C this is a string";
+ kdDebug(150) << test << endl;
+ QCString cstr = test.latin1();
+ kdDebug(150) << test << endl;
+ QChar ch = 'a';
+ kdDebug() << "QChar a: " << ch << endl;
+ ch = '\r';
+ kdDebug() << "QChar \\r: " << ch << endl;
+ kdDebug() << k_lineinfo << "error on this line" << endl;
+ kdDebug(2 == 2) << "this is right " << perror << endl;
+ kdDebug() << "Before instance creation" << endl;
+ kdDebug(1202) << "Before instance creation" << endl;
+ KInstance i("kdebugtest");
+ kdDebug(1) << "kDebugInfo with inexisting area number" << endl;
+ kdDebug(1202) << "This number has a value of " << 5 << endl;
+ // kdDebug() << "This number should come out as appname " << 5 << " " << "test" << endl;
+ kdWarning() << "1+1 = " << 1+1+1 << endl;
+ kdError(1+1 != 2) << "there is something really odd!" << endl;
+ QString s = "mystring";
+ kdDebug() << s << endl;
+ kdError(1202) << "Error !!!" << endl;
+ kdError() << "Error with no area" << endl;
+
+ kdDebug() << "Printing a null QWidget pointer: " << (QWidget*)0 << endl;
+
+ kdDebug() << "char " << '^' << " " << char(26) << endl;
+ QPoint p(0,9);
+ kdDebug() << p << endl;
+
+ QRect r(9,12,58,234);
+ kdDebug() << r << endl;
+
+ QRegion reg(r);
+ reg += QRect(1,60,200,59);
+ kdDebug() << reg << endl;
+
+ QStringList sl;
+ sl << "hi" << "this" << "list" << "is" << "short";
+ kdDebug() << sl << endl;
+
+ QValueList<int> il;
+ kdDebug() << "Empty QValueList<int>: " << il << endl;
+ il << 1 << 2 << 3 << 4 << 5;
+ kdDebug() << "QValueList<int> filled: " << il << endl;
+
+ Q_LLONG big = 65536LL*65536*500;
+ kdDebug() << big << endl;
+
+ QVariant v( 0.12345 );
+ kdDebug() << "Variant: " << v << endl;
+ v = QPen( Qt::red );
+ kdDebug() << "Variant: " << v << endl;
+
+ QByteArray data( 6 );
+ data[0] = 42;
+ data[1] = 'H';
+ data[2] = 'e';
+ data[3] = 'l';
+ data[4] = 'l';
+ data[5] = 'o';
+ kdDebug() << data << endl;
+ data.resize( 80 );
+ data.fill( 42 );
+ kdDebug() << data << endl;
+ }
+ void resizeEvent(QResizeEvent*)
+ {
+ kdDebug() << this << endl;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ TestWidget widget(0, "NoNameWidget");
+ widget.setGeometry(45, 54, 120, 80);
+ widget.show();
+ app.setMainWidget(&widget);
+ app.exec();
+ return 0;
+}
+
diff --git a/kdecore/tests/kglobaltest.cpp b/kdecore/tests/kglobaltest.cpp
new file mode 100644
index 000000000..90332e3e6
--- /dev/null
+++ b/kdecore/tests/kglobaltest.cpp
@@ -0,0 +1,64 @@
+#include <config.h>
+
+#include <kglobal.h>
+#include <stdio.h>
+#include <kapplication.h>
+#include <stdlib.h>
+#include <kdebug.h>
+#include <assert.h>
+#include <kcmdlineargs.h>
+
+static bool check(const QString& txt, QString a, QString b)
+{
+ if (a.isEmpty())
+ a = QString::null;
+ if (b.isEmpty())
+ b = QString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+void testkasciistricmp()
+{
+ assert( kasciistricmp( "test", "test" ) == 0 );
+ assert( kasciistricmp( "test", "Test" ) == 0 );
+ assert( kasciistricmp( "TeSt", "tEst" ) == 0 );
+
+ assert( kasciistricmp( 0, 0 ) == 0 );
+ assert( kasciistricmp( "", "" ) == 0 );
+ assert( kasciistricmp( 0, "" ) < 0 );
+ assert( kasciistricmp( "", 0 ) > 0 );
+
+ assert( kasciistricmp( "", "foo" ) < 0 );
+ assert( kasciistricmp( "foo", "" ) > 0 );
+
+ assert( kasciistricmp( "test", "testtest" ) < 0 );
+ assert( kasciistricmp( "testtest", "test" ) > 0 );
+
+ assert( kasciistricmp( "a", "b" ) < 0 );
+ assert( kasciistricmp( "b", "a" ) > 0 );
+ assert( kasciistricmp( "A", "b" ) < 0 );
+ assert( kasciistricmp( "b", "A" ) > 0 );
+ assert( kasciistricmp( "a", "B" ) < 0 );
+ assert( kasciistricmp( "B", "a" ) > 0 );
+ assert( kasciistricmp( "A", "B" ) < 0 );
+ assert( kasciistricmp( "B", "A" ) > 0 );
+}
+
+int main(int argc, char *argv[])
+{
+ KApplication::disableAutoDcopRegistration();
+ KCmdLineArgs::init( argc, argv, "kglobaltest", 0, 0, 0, 0 );
+ KApplication app( false, false );
+
+ testkasciistricmp();
+
+ printf("\nTest OK !\n");
+}
+
diff --git a/kdecore/tests/kiconloadertest.cpp b/kdecore/tests/kiconloadertest.cpp
new file mode 100644
index 000000000..77930218c
--- /dev/null
+++ b/kdecore/tests/kiconloadertest.cpp
@@ -0,0 +1,34 @@
+#include <kiconloader.h>
+#include <qdatetime.h>
+#include <stdio.h>
+#include <kapplication.h>
+#include <stdlib.h>
+#include <kdebug.h>
+
+int main(int argc, char *argv[])
+{
+ KApplication app(argc,argv,"kiconloadertest"/*,false,false*/);
+
+ KIconLoader * mpLoader = KGlobal::iconLoader();
+ KIcon::Context mContext = KIcon::Application;
+ QTime dt;
+ dt.start();
+ int count = 0;
+ for ( int mGroup = 0; mGroup < KIcon::LastGroup ; ++mGroup )
+ {
+ kdDebug() << "queryIcons " << mGroup << "," << mContext << endl;
+ QStringList filelist=mpLoader->queryIcons(mGroup, mContext);
+ kdDebug() << " -> found " << filelist.count() << " icons." << endl;
+ int i=0;
+ for(QStringList::Iterator it = filelist.begin();
+ it != filelist.end() /*&& i<10*/;
+ ++it, ++i )
+ {
+ //kdDebug() << ( i==9 ? "..." : (*it) ) << endl;
+ mpLoader->loadIcon( (*it), (KIcon::Group)mGroup );
+ ++count;
+ }
+ }
+ kdDebug() << "Loading " << count << " icons took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
+}
+
diff --git a/kdecore/tests/kipctest.cpp b/kdecore/tests/kipctest.cpp
new file mode 100644
index 000000000..15daa24d9
--- /dev/null
+++ b/kdecore/tests/kipctest.cpp
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <qobject.h>
+#include <kapplication.h>
+#include <kipc.h>
+#include "kipctest.h"
+
+MyObject::MyObject()
+ : QObject(0L, "testobj")
+{
+ connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(slotPaletteChanged()));
+ connect(kapp, SIGNAL(kdisplayFontChanged()), SLOT(slotFontChanged()));
+ connect(kapp, SIGNAL(kdisplayStyleChanged()), SLOT(slotStyleChanged()));
+ connect(kapp, SIGNAL(backgroundChanged(int)), SLOT(slotBackgroundChanged(int)));
+ connect(kapp, SIGNAL(appearanceChanged()), SLOT(slotAppearanceChanged()));
+ connect(kapp, SIGNAL(kipcMessage(int,int)), SLOT(slotMessage(int,int)));
+}
+
+int main(int argc, char **argv)
+{
+ KApplication app(argc, argv, "kipc");
+
+ if (argc == 3)
+ {
+ KIPC::sendMessageAll((KIPC::Message) atoi(argv[1]), atoi(argv[2]));
+ return 0;
+ }
+
+ MyObject obj;
+ return app.exec();
+}
+
+#include "kipctest.moc"
diff --git a/kdecore/tests/kipctest.h b/kdecore/tests/kipctest.h
new file mode 100644
index 000000000..5a9a18467
--- /dev/null
+++ b/kdecore/tests/kipctest.h
@@ -0,0 +1,21 @@
+#ifndef __blah__h__
+#define __blah__h__
+
+#include <qobject.h>
+
+class MyObject: public QObject
+{
+ Q_OBJECT
+public:
+ MyObject();
+
+public slots:
+ void slotPaletteChanged() { printf("SIGNAL: Palette changed\n"); }
+ void slotStyleChanged() { printf("SIGNAL: Style changed\n"); }
+ void slotFontChanged() { printf("SIGNAL: Font changed\n"); }
+ void slotBackgroundChanged(int i) { printf("SIGNAL: Background %d changed\n", i); }
+ void slotAppearanceChanged() { printf("SIGNAL: Appearance changed\n"); }
+ void slotMessage(int id, int arg) { printf("SIGNAL: user message: %d,%d\n", id, arg); }
+};
+
+#endif
diff --git a/kdecore/tests/klocaletest.cpp b/kdecore/tests/klocaletest.cpp
new file mode 100644
index 000000000..acec373de
--- /dev/null
+++ b/kdecore/tests/klocaletest.cpp
@@ -0,0 +1,199 @@
+// klocaletest.cpp -*- C++ -*-
+//
+// $Id$
+//
+// Author: Jacek Konieczny <jajcus@zeus.polsl.gliwice.pl>
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <qdatetime.h>
+#include <qlabel.h>
+
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include "klocale.h"
+#include <kapplication.h>
+#include <kcharsets.h>
+#include <kdebug.h>
+
+#include "klocaletest.h"
+
+bool check(QString txt, QString a, QString b)
+{
+ if (a.isEmpty())
+ a = QString::null;
+ if (b.isEmpty())
+ b = QString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+bool checkDate(QString txt, QDate a, QDate b)
+{
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a.toString() << "' against expected value '" << b.toString() << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a.toString() << "' against expected value '" << b.toString() << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+Test::Test( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ setCaption("Testing KLocale");
+
+ QWidget *d = qApp->desktop();
+ setGeometry((d->width()-320)>>1, (d->height()-160)>>1, 420, 420);
+
+ createFields();
+ show();
+}
+
+Test::~Test()
+{
+ ;
+}
+
+void Test::createFields()
+{
+ QString string;
+
+ string+="Selected languages: ";
+ string+=KGlobal::locale()->languages()+"\n";
+
+ // This will show nothing, as there is no klocaletest.mo
+ // but you can copy other *.mo file
+ string+="Used language: ";
+ string+=KGlobal::locale()->language()+"\n";
+ string+="Locale encoding: ";
+ string+=QString::fromLatin1(KGlobal::locale()->encoding())+"\n";
+
+ string+="Localized date and time: ";
+ string+=KGlobal::locale()->formatDateTime(QDateTime::currentDateTime());
+ string+="\nLocalized monetary numbers: ";
+ string+=KGlobal::locale()->formatMoney(1234567.89) + " / \n" +KGlobal::locale()->formatMoney(-1234567.89);
+ // This will not work
+ // but you can copy other *.mo file
+ string+="\nSome localized strings:\n";
+ string+=QString::fromLatin1("Yes = ")+i18n("Yes")+"\n";
+ string+=QString::fromLatin1("No = ")+i18n("No")+"\n";
+ string+=QString::fromLatin1("Help = ")+i18n("Help")+"\n";
+ string+=QString::fromLatin1("Cancel = ")+i18n("Cancel")+"\n";
+
+ label=new QLabel(string,this,"Label");
+ label->setGeometry(10,10,400,400);
+ label->setFont(KGlobalSettings::generalFont());
+ label->show();
+}
+
+int main( int argc, char ** argv )
+{
+ KLocale::setMainCatalogue("kdelibs");
+ KApplication a( argc, argv, "klocaletest" );
+
+ KGlobal::locale()->setLanguage(QString::fromLatin1("en_US"));
+ KGlobal::locale()->setCountry(QString::fromLatin1("C"));
+ KGlobal::locale()->setThousandsSeparator(QString::fromLatin1(","));
+
+ QString formatted;
+ formatted = KGlobal::locale()->formatNumber( 70 ); check("formatNumber(70)",formatted,"70.00");
+ formatted = KGlobal::locale()->formatNumber( 70, 0 ); check("formatNumber(70, 0)",formatted,"70");
+ formatted = KGlobal::locale()->formatNumber( 70.2 ); check("formatNumber(70.2)",formatted,"70.20");
+ formatted = KGlobal::locale()->formatNumber( 70.24 ); check("formatNumber(70.24)",formatted,"70.24");
+ formatted = KGlobal::locale()->formatNumber( 70.245 ); check("formatNumber(70.245)",formatted,"70.25"); /*rounded*/
+ formatted = KGlobal::locale()->formatNumber(1234567.89123456789,8); check("formatNumber(1234567.89123456789,8)",formatted,"1,234,567.89123457");
+
+ formatted = KGlobal::locale()->formatNumber("70"); check("formatNumber(\"70\")",formatted,"70.00");
+ formatted = KGlobal::locale()->formatNumber("70", true, 2); check("formatNumber(\"70\", true, 2)",formatted,"70.00");
+ formatted = KGlobal::locale()->formatNumber("70", true, 0); check("formatNumber(\"70\", true, 0)",formatted,"70");
+ formatted = KGlobal::locale()->formatNumber("70.9123", true, 0); check("formatNumber(\"70.9123\", true, 0)",formatted,"71"); /* rounded */
+ formatted = KGlobal::locale()->formatNumber("-70.2", true, 2); check("formatNumber(\"-70.2\", true, 2)",formatted,"-70.20");
+ formatted = KGlobal::locale()->formatNumber("+70.24", true, 2); check("formatNumber(\"+70.24\", true, 2)",formatted,"70.24");
+ formatted = KGlobal::locale()->formatNumber("70.245", true, 2); check("formatNumber(\"70.245\", true, 2)",formatted,"70.25"); /*rounded*/
+ formatted = KGlobal::locale()->formatNumber("99.996", true, 2); check("formatNumber(\"99.996\", true, 2)",formatted,"100.00"); /*rounded*/
+ formatted = KGlobal::locale()->formatNumber("12345678901234567.89123456789", false, 0); check("formatNumber(\"12345678901234567.89123456789\", false, 0)",formatted,"12,345,678,901,234,567.89123456789");
+
+
+
+ double num;
+ bool ok;
+ num = KGlobal::locale()->readNumber( "12,1", &ok ); check("readNumber(12,1)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,100", &ok ); check("readNumber(12,100)",ok?"yes":"no","yes");
+ num = KGlobal::locale()->readNumber( "12,100000,000", &ok ); check("readNumber(12,100000,000)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,100000000", &ok ); check("readNumber(12,100000000)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,100000,000", &ok ); check("readNumber(12,100000,000)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,,100,000", &ok ); check("readNumber(12,,100,000)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,1000,000", &ok ); check("readNumber(12,1000,000)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,0000000,000", &ok ); check("readNumber(12,0000000,000)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,0000000", &ok ); check("readNumber(12,0000000)",ok?"yes":"no","no");
+ num = KGlobal::locale()->readNumber( "12,146,131.12", &ok ); check("readNumber(12,146,131.12)",ok?"yes":"no","yes");
+ num = KGlobal::locale()->readNumber( "1.12345678912", &ok );
+ qDebug( "%s", QString::number( num, 'g', 12 ).latin1() ); // warning this is the only way to see all decimals
+ check("readNumber(1.12345678912)",ok && num==1.12345678912?"yes":"no","yes");
+ // bug 95511
+ KLocale locale(*KGlobal::locale());
+ locale.setCurrencySymbol("$$");
+ num = locale.readMoney("1,234,567.89$$", &ok);
+ check("readMoney(1,234,567.89$$)",ok?"yes":"no","yes");
+ num = locale.readMoney("-1,234,567.89$$", &ok);
+ check("readMoney(-1,234,567.89$$)",ok?"yes":"no","yes");
+
+ QDate date;
+ date.setYMD( 2002, 5, 3 );
+ checkDate("readDate( 3, 5, 2002 )",date,KGlobal::locale()->readDate( KGlobal::locale()->formatDate( date ) ) );
+ date = QDate::currentDate();
+ checkDate("readDate( QDate::currentDate() )",date,KGlobal::locale()->readDate( KGlobal::locale()->formatDate( date ) ) );
+
+ QTime time;
+ time = KGlobal::locale()->readTime( "11:22:33", &ok );
+ check("readTime(\"11:22:33\")", (ok && time == QTime(11, 22, 33)) ?
+ "yes" : "no", "yes");
+ time = KGlobal::locale()->readTime( "11:22", &ok );
+ check("readTime(\"11:22\")", (ok && time == QTime(11, 22, 0)) ?
+ "yes" : "no", "yes");
+ time = KGlobal::locale()->readTime( "foo", &ok );
+ check("readTime(\"foo\")", (!ok && !time.isValid()) ?
+ "invalid" : "valid", "invalid");
+
+ time = KGlobal::locale()->readTime( "11:22:33", KLocale::WithoutSeconds, &ok );
+ check("readTime(\"11:22:33\", WithoutSeconds)", (!ok && !time.isValid()) ?
+ "invalid" : "valid", "invalid");
+ time = KGlobal::locale()->readTime( "11:22", KLocale::WithoutSeconds, &ok );
+ check("readTime(\"11:22\", WithoutSeconds)", (ok && time == QTime(11, 22, 0)) ?
+ "yes" : "no", "yes");
+
+ KGlobal::locale()->setTimeFormat( "%H:%M %p" );
+ time = QTime( 0, 22, 33 );
+ QString timeStr = KGlobal::locale()->formatTime( time, true /*seconds*/, false /*duration*/ );
+ check("formatTime(\"0:22\", as time)", timeStr, "00:22 am" );
+ timeStr = KGlobal::locale()->formatTime( time, true /*seconds*/, true /*duration*/ );
+ check("formatTime(\"0:22\", as duration)", timeStr, "00:22" );
+
+ kdDebug() << "setLanguage C\n";
+ KGlobal::locale()->setLanguage(QString::fromLatin1("C"));
+ kdDebug() << "C: " << i18n("yes") << " " << i18n("QAccel", "Space") << endl;
+
+ kdDebug() << "setLanguage de\n";
+ KGlobal::locale()->setLanguage(QString::fromLatin1("de"));
+ kdDebug() << "de: " << i18n("yes") << " " << i18n("QAccel", "Space") << endl;
+
+
+ Test m;
+ a.setMainWidget( &m );
+ m.show();
+
+ return a.exec();
+}
+
+#include "klocaletest.moc"
diff --git a/kdecore/tests/klocaletest.h b/kdecore/tests/klocaletest.h
new file mode 100644
index 000000000..7b6cb328e
--- /dev/null
+++ b/kdecore/tests/klocaletest.h
@@ -0,0 +1,32 @@
+// $Id$
+
+#ifndef KLOCALETEST_H
+#define KLOCALETEST_H
+
+#include <qwidget.h>
+
+class QLabel;
+
+/** test: a small test program for KLocale
+ */
+class Test : public QWidget
+{
+ Q_OBJECT
+
+public:
+ /**@name methods */
+ //@{
+ /** Constructor
+ */
+ Test( QWidget *parent=0, const char *name=0 );
+ /** Destructor
+ */
+ ~Test();
+
+private:
+ QString showLocale(QString cat);
+ void createFields();
+
+ QLabel *label;
+};
+#endif // TEST_H
diff --git a/kdecore/tests/kmacroexpandertest.cpp b/kdecore/tests/kmacroexpandertest.cpp
new file mode 100644
index 000000000..6c92ba935
--- /dev/null
+++ b/kdecore/tests/kmacroexpandertest.cpp
@@ -0,0 +1,137 @@
+#include <kmacroexpander.h>
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+
+#include <stdlib.h>
+
+bool check(QString txt, QString s, QString a, QString b)
+{
+ if (a.isEmpty())
+ a = QString::null;
+ if (b.isEmpty())
+ b = QString::null;
+ if (a == b)
+ kdDebug() << txt << " (" << s << ") : '" << a << "' - ok" << endl;
+ else {
+ kdDebug() << txt << " (" << s << ") : got '" << a << "' but expected '" << b << "' - KO!" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+class MyCExpander : public KCharMacroExpander {
+public:
+ MyCExpander() : KCharMacroExpander() {}
+protected:
+ bool expandMacro(QChar chr, QStringList &ret)
+ {
+ if (chr == 'm') {
+ ret = QString("expanded");
+ return true;
+ }
+ return false;
+ }
+};
+
+class MyWExpander : public KWordMacroExpander {
+public:
+ MyWExpander() : KWordMacroExpander() {}
+protected:
+ bool expandMacro(const QString &str, QStringList &ret)
+ {
+ if (str == "macro") {
+ ret = QString("expanded");
+ return true;
+ }
+ return false;
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ KCmdLineArgs::init(argc, argv, ":", "", "", "");
+ KApplication app(false,false);
+ QString s, s2;
+
+ QMap<QChar,QStringList> map1;
+ map1.insert('n', "Restaurant \"Chew It\"");
+ QStringList li;
+ li << "element1" << "'element2'";
+ map1.insert('l', li);
+
+ s = "text %l %n text";
+ check( "KMacroExpander::expandMacros", s, KMacroExpander::expandMacros(s, map1), "text element1 'element2' Restaurant \"Chew It\" text");
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map1), "text 'element1' ''\\''element2'\\''' 'Restaurant \"Chew It\"' text");
+ s = "text \"%l %n\" text";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map1), "text \"element1 'element2' Restaurant \\\"Chew It\\\"\" text");
+
+ QMap<QChar,QString> map;
+ map.insert('a', "%n");
+ map.insert('f', "filename.txt");
+ map.insert('u', "http://www.kde.org/index.html");
+ map.insert('n', "Restaurant \"Chew It\"");
+
+ s = "Title: %a - %f - %u - %n - %%";
+ check( "KMacroExpander::expandMacros", s, KMacroExpander::expandMacros(s, map), "Title: %n - filename.txt - http://www.kde.org/index.html - Restaurant \"Chew It\" - %");
+
+ s = "kedit --caption %n %f";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map), "kedit --caption 'Restaurant \"Chew It\"' 'filename.txt'");
+
+ map.replace('n', "Restaurant 'Chew It'");
+ s = "kedit --caption %n %f";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map), "kedit --caption 'Restaurant '\\''Chew It'\\''' 'filename.txt'");
+
+ s = "kedit --caption \"%n\" %f";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map), "kedit --caption \"Restaurant 'Chew It'\" 'filename.txt'");
+
+ map.replace('n', "Restaurant \"Chew It\"");
+ s = "kedit --caption \"%n\" %f";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map), "kedit --caption \"Restaurant \\\"Chew It\\\"\" 'filename.txt'");
+
+ map.replace('n', "Restaurant $HOME");
+ s = "kedit --caption \"%n\" %f";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map), "kedit --caption \"Restaurant \\$HOME\" 'filename.txt'");
+
+ map.replace('n', "Restaurant `echo hello`");
+ s = "kedit --caption \"%n\" %f";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map), "kedit --caption \"Restaurant \\`echo hello\\`\" 'filename.txt'");
+
+ map.replace('n', "Restaurant `echo hello`");
+ s = "kedit --caption \"`echo %n`\" %f";
+ check( "KMacroExpander::expandMacrosShellQuote", s, KMacroExpander::expandMacrosShellQuote(s, map), "kedit --caption \"$( echo 'Restaurant `echo hello`')\" 'filename.txt'");
+
+ QMap<QString,QString> smap;
+ smap.insert("foo", "%n");
+ smap.insert("file", "filename.txt");
+ smap.insert("url", "http://www.kde.org/index.html");
+ smap.insert("name", "Restaurant \"Chew It\"");
+
+ s = "Title: %foo - %file - %url - %name - %";
+ check( "KMacroExpander::expandMacros", s, KMacroExpander::expandMacros(s, smap), "Title: %n - filename.txt - http://www.kde.org/index.html - Restaurant \"Chew It\" - %");
+
+ s = "Title: %{foo} - %{file} - %{url} - %{name} - %";
+ check( "KMacroExpander::expandMacros", s, KMacroExpander::expandMacros(s, smap), "Title: %n - filename.txt - http://www.kde.org/index.html - Restaurant \"Chew It\" - %");
+
+ s = "Title: %foo-%file-%url-%name-%";
+ check( "KMacroExpander::expandMacros", s, KMacroExpander::expandMacros(s, smap), "Title: %n-filename.txt-http://www.kde.org/index.html-Restaurant \"Chew It\"-%");
+
+ s = "Title: %{file} %{url";
+ check( "KMacroExpander::expandMacros", s, KMacroExpander::expandMacros(s, smap), "Title: filename.txt %{url");
+
+ MyCExpander mx1;
+ s = "subst %m but not %n equ %%";
+ s2 = s;
+ mx1.expandMacros(s2);
+ check( "MyCExpander::expandMacros", s, s2, "subst expanded but not %n equ %");
+
+ MyWExpander mx2;
+ s = "subst %macro but not %not equ %%";
+ s2 = s;
+ mx2.expandMacros(s2);
+ check( "MyWExpander::expandMacros", s, s2, "subst expanded but not %not equ %");
+
+ kdDebug() << endl << "Test OK!" << endl;
+}
+
diff --git a/kdecore/tests/kmdcodectest.cpp b/kdecore/tests/kmdcodectest.cpp
new file mode 100644
index 000000000..1156f03f2
--- /dev/null
+++ b/kdecore/tests/kmdcodectest.cpp
@@ -0,0 +1,395 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <iostream>
+
+#include <qbuffer.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kapplication.h>
+
+#include <kmdcodec.h>
+
+using namespace std;
+
+#define TEST_BLOCK_LEN 1000 // Length of test blocks.
+#define TEST_BLOCK_COUNT 10000 // Number of test blocks.
+#define MAX_READ_BUF_SIZE 8192
+
+enum Codec
+{
+ Unspecified=0,
+ Base64Encode,
+ Base64Decode,
+ UUEncode,
+ UUDecode,
+ QPEncode,
+ QPDecode
+};
+
+void MD5_timeTrial ();
+void MD5_testSuite ();
+void testCodec (const char*, Codec, bool);
+void MD5_verify (const char*, const char*, bool);
+void MD5_file (const char * , bool rawOutput = false);
+void MD5_string (const char *, const char *expected = 0, bool rawOutput = false);
+
+long readContent (const QFile& f, long count, QByteArray& buf)
+{
+ long result;
+ int old_size;
+
+ old_size = buf.size();
+ buf.resize(old_size+count);
+
+ result = read (f.handle (), buf.data()+old_size, count);
+
+ if ( result > 0 && result < count )
+ {
+ buf.resize( old_size + result );
+ }
+ else if ( result == 0 )
+ {
+ buf.resize( old_size );
+ }
+ else if ( result == -1 )
+ {
+ kdError() << "Could not read the file!" << endl;
+ }
+
+ return result;
+}
+
+void testCodec (const char* msg, Codec type, bool isFile)
+{
+ QByteArray output;
+
+ if ( isFile )
+ {
+ int count;
+ QByteArray data;
+
+ QFile f (QFile::encodeName(msg));
+
+ if (!f.exists())
+ {
+ kdError() << "Could not find: " << f.name () << endl;
+ return;
+ }
+
+ if (!f.open(IO_ReadOnly))
+ {
+ f.close ();
+ kdError() << "Could not open: " << f.name() << endl;
+ return;
+ }
+
+ // Read contents of file...
+ count = 0;
+
+ while ((count= readContent(f, MAX_READ_BUF_SIZE, data)) > 0);
+
+ // Error! Exit!
+ if ( count == -1 )
+ {
+ kdError () << "Error reading from: " << f.name() << endl;
+ f.close ();
+ return;
+ }
+
+ f.close ();
+
+ // Perform the requested encoding or decoding...
+ switch (type)
+ {
+ case Base64Encode:
+ KCodecs::base64Encode(data, output, true);
+ break;
+ case Base64Decode:
+ KCodecs::base64Decode(data, output);
+ break;
+ case UUEncode:
+ KCodecs::uuencode(data, output);
+ break;
+ case UUDecode:
+ KCodecs::uudecode(data, output);
+ break;
+ case QPEncode:
+ KCodecs::quotedPrintableEncode(data, output, true);
+ break;
+ case QPDecode:
+ KCodecs::quotedPrintableDecode(data, output);
+ break;
+ default:
+ break;
+ }
+
+ QCString result (output.data(), output.size()+1);
+ cout << "Result: " << endl << result << endl;
+ }
+ else
+ {
+ QCString result;
+
+ const size_t len = strlen(msg);
+ output.resize(len);
+ memcpy (output.data(), msg, len);
+
+ switch (type)
+ {
+ case Base64Encode:
+ result = KCodecs::base64Encode(output);
+ break;
+ case Base64Decode:
+ result = KCodecs::base64Decode(output);
+ break;
+ case UUEncode:
+ result = KCodecs::uuencode(output);
+ break;
+ case UUDecode:
+ result = KCodecs::uudecode(output);
+ break;
+ case QPEncode:
+ result = KCodecs::quotedPrintableEncode(output);
+ break;
+ case QPDecode:
+ result = KCodecs::quotedPrintableDecode(output);
+ break;
+ default:
+ break;
+ }
+ cout << result << endl;
+ }
+}
+
+void MD5_timeTrial ()
+{
+ KMD5 context;
+
+ time_t endTime;
+ time_t startTime;
+
+ Q_UINT8 block[TEST_BLOCK_LEN];
+ Q_UINT32 i;
+
+ cout << "Timing test. Digesting " << TEST_BLOCK_COUNT << " blocks of "
+ << TEST_BLOCK_LEN << "-byte..." << endl;
+
+ // Initialize block
+ for (i = 0; i < TEST_BLOCK_LEN; i++)
+ block[i] = (Q_UINT8)(i & 0xff);
+
+ // Start timer
+ time (&startTime);
+
+ // Digest blocks
+ for (i = 0; i < TEST_BLOCK_COUNT; i++)
+ context.update (block, TEST_BLOCK_LEN);
+
+ // Stop timer
+ time (&endTime);
+
+ long duration = endTime - startTime;
+ long speed;
+ if (duration)
+ speed = (TEST_BLOCK_LEN * (TEST_BLOCK_COUNT/duration));
+ else
+ speed = TEST_BLOCK_COUNT;
+
+ cout << "Result: " << endl;
+ cout << " Time = " << duration << " seconds" << endl;
+ cout << " Speed = " << speed << " bytes/second" << endl;
+ cout << " Digest = " << context.hexDigest() << endl;
+}
+
+void MD5_testSuite ()
+{
+ cout << "MD5 preset test suite as defined in RFC 1321:" << endl;
+ MD5_string ( "", "d41d8cd98f00b204e9800998ecf8427e" );
+ MD5_string ( "a", "0cc175b9c0f1b6a831c399e269772661" );
+ MD5_string ( "abc", "900150983cd24fb0d6963f7d28e17f72" );
+ MD5_string ( "message digest", "f96b697d7cb7938d525a2f31aaf161d0" );
+ MD5_string ( "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b" );
+ MD5_string ( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "d174ab98d277d9f5a5611c2c9f419d9f" );
+ MD5_string ( "12345678901234567890123456789012345678901234567890123456789012"
+ "345678901234567890", "57edf4a22be3c955ac49da2e2107b67a" );
+}
+
+void MD5_verify( const char *input, const char *digest, bool isFile )
+{
+ bool result;
+ KMD5 context;
+
+ if ( !isFile )
+ {
+ context.update (QCString(input));
+ result = context.verify( digest );
+ cout << "Input string: " << input << endl;
+ }
+ else
+ {
+ QFile f (input);
+
+ if (!f.open (IO_ReadOnly))
+ {
+ f.close ();
+ kdFatal() << "Cannot open file for reading!" << endl;
+ }
+
+ result = context.verify (digest);
+ f.close ();
+
+ cout << "Input filename: " << input << endl;
+ }
+
+ cout << "Calculated Digest = " << context.hexDigest() << endl;
+ cout << "Supplied Digest = " << digest << endl;
+ cout << "Matches: " << (result ? "TRUE":"FALSE") << endl;
+}
+
+void MD5_file (const char *filename, bool rawOutput )
+{
+ QFile f (QFile::encodeName(filename));
+
+ if (!f.open(IO_ReadOnly))
+ {
+ f.close();
+ kdError() << "(" << filename << ") cannot be opened!" << endl;
+ return;
+ }
+
+ KMD5 context;
+ context.update( f );
+
+ if ( rawOutput )
+ cout << "MD5 (" << filename << ") = " << context.rawDigest() << endl;
+ else
+ cout << "MD5 (" << filename << ") = " << context.hexDigest() << endl;
+
+ f.close ();
+}
+
+void MD5_string (const char *input, const char* expected, bool rawOutput )
+{
+ KMD5 context;
+ context.update (QCString(input));
+
+ cout << "Checking MD5 for: " << input << endl;
+
+ if ( rawOutput )
+ cout << "Result: " << context.rawDigest() << endl;
+ else
+ cout << "Result: " << context.hexDigest() << endl;
+
+ if ( expected )
+ {
+ cout << "Expected: " << expected << endl;
+ cout << "Status: " << context.verify (expected) << endl;
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ const char *version = "1.0";
+ const char *description = "Unit test for md5, base64 encode/decode and uuencode/decode facilities";
+ KCmdLineOptions options[] =
+ {
+ { "c <digest>", "compare <digest> with the calculated digest for a string or file.", 0 },
+ { "d", "decode the given string or file using base64", 0 },
+ { "e", "encode the given string or file using base64", 0 },
+ { "f", "the filename to be used as input", "default" },
+ { "p", "encode the given string or file using quoted-printable", 0},
+ { "q", "decode the given string or file using quoted-printable", 0},
+ { "r", "calculate the raw md5 for the given string or file", 0 },
+ { "s", "the string to be used as input", 0 },
+ { "t", "perform a timed message-digest test", 0 },
+ { "u", "uuencode the given string or file", 0 },
+ { "x", "uudecode the given string or file", 0 },
+ { "z", "run a preset message-digest test", 0 },
+ { "+command", "[input1, input2,...]", 0 },
+ KCmdLineLastOption
+ };
+
+ KCmdLineArgs::init( argc, argv, "kmdcodectest", description, version );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ int count = args->count();
+
+ KApplication app;
+
+ if (!count)
+ {
+ if ( args->isSet("t") )
+ MD5_timeTrial ();
+ else if ( args->isSet("z") )
+ MD5_testSuite ();
+ else
+ args->usage();
+ }
+ else
+ {
+ bool isVerify = args->isSet("c");
+ bool isString = args->isSet("s");
+ bool isFile = args->isSet( "f" );
+ Codec type = Unspecified;
+ if ( args->isSet("d") )
+ type = Base64Decode;
+ else if ( args->isSet("e") )
+ type = Base64Encode;
+ else if ( args->isSet("u") )
+ type = UUEncode;
+ else if ( args->isSet("x") )
+ type = UUDecode;
+ else if ( args->isSet("p") )
+ type = QPEncode;
+ else if ( args->isSet("q") )
+ type = QPDecode;
+ if ( isVerify )
+ {
+ const char* opt = args->getOption( "c" ).data();
+ for ( int i=0 ; i < count; i++ )
+ MD5_verify ( QCString(args->arg(i)), opt, (isString || !isFile) );
+ }
+ else
+ {
+ for ( int i=0 ; i < count; i++ )
+ {
+ if ( type != Unspecified )
+ testCodec( args->arg(i), type, isFile );
+ else
+ {
+ if ( isString )
+ MD5_string( args->arg( i ), 0, args->isSet("r") );
+ else
+ MD5_file( args->arg( i ), args->isSet("r") );
+ }
+ }
+ }
+ }
+ args->clear();
+ return (0);
+}
diff --git a/kdecore/tests/kmemtest.cpp b/kdecore/tests/kmemtest.cpp
new file mode 100644
index 000000000..83c452e50
--- /dev/null
+++ b/kdecore/tests/kmemtest.cpp
@@ -0,0 +1,248 @@
+#include <stdio.h>
+#include <kapplication.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+void showMem()
+{
+ char buf[257];
+
+ printf("Reported Memory Usage Of This Process:\n");
+
+ FILE *fs = fopen("/proc/self/status", "r");
+ bool done = false;
+ while (!done)
+ {
+ fgets(buf, 256, fs);
+ buf[256] = 0;
+ if ((strncmp(buf, "VmLib", 5)==0) ||
+ (strncmp(buf, "VmData", 6)==0) ||
+ (strncmp(buf, "VmSize", 6)==0) ||
+ (strncmp(buf, "VmExe", 5)==0) ||
+ (strncmp(buf, "VmRSS", 5)==0) ||
+ (strncmp(buf, "VmLck", 5)==0))
+ printf("%s", buf);
+ done = (strncmp(buf, "VmLib", 5) == 0);
+ }
+ fclose(fs);
+}
+
+long showTotalMem()
+{
+ long realMem = 0;
+ char buf[257];
+
+ FILE *fs = fopen("/proc/meminfo", "r");
+ bool done = false;
+ while (!done)
+ {
+ fgets(buf, 256, fs);
+ buf[256] = 0;
+ if (strlen(buf)==0) done = true;
+ if (strncmp(buf, "Mem:", 4)==0)
+ {
+ long total = 0;
+ long used = 0;
+ long free = 0;
+ long shared = 0;
+ long buffers = 0;
+ long cached = 0;
+ sscanf(buf, "Mem: %ld %ld %ld %ld %ld %ld",
+ &total, &used, &free, &shared, &buffers, &cached);
+ realMem = used-buffers-cached;
+ printf("Actual Total Memory Usage: %0.1fKb\n", realMem/1024.0);
+ done = true;
+ }
+ }
+ fclose(fs);
+ return realMem;
+}
+
+long memSize()
+{
+ long realMem = 0;
+ char buf[257];
+
+ FILE *fs = fopen("/proc/meminfo", "r");
+ bool done = false;
+ while (!done)
+ {
+ fgets(buf, 256, fs);
+ buf[256] = 0;
+ if (strlen(buf)==0) done = true;
+ if (strncmp(buf, "Mem:", 4)==0)
+ {
+ long total = 0;
+ long used = 0;
+ long free = 0;
+ long shared = 0;
+ long buffers = 0;
+ long cached = 0;
+ sscanf(buf, "Mem: %ld %ld %ld %ld %ld %ld",
+ &total, &used, &free, &shared, &buffers, &cached);
+ realMem = total;
+ done = true;
+ }
+ }
+ fclose(fs);
+ return realMem;
+}
+
+void *mmapFile(const char *file)
+{
+ int fd = open(file, O_RDONLY);
+ if (fd == 0)
+ {
+ printf("open: %s\n", strerror(errno));
+ exit(-1);
+ }
+
+ struct stat stat_s;
+ int result = fstat(fd, &stat_s);
+ if (result)
+ {
+ printf("stat: %s\n", strerror(errno));
+ exit(-1);
+ }
+
+ void *ptr = mmap(0, stat_s.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (ptr == 0)
+ {
+ printf("mmap: %s\n", strerror(errno));
+ exit(-1);
+ }
+ return ptr;
+}
+
+int main(int argc, char *argv[])
+{
+ if ((argc==2) && (strcmp(argv[1], "all")==0))
+ {
+ long mem_size = memSize();
+ mem_size += mem_size / 16;
+ printf("Malloc... %0.1fMb\n", mem_size/(1024.0*1024.0));
+ char *mem = (char *) malloc(mem_size);
+ for(long i=0; i < mem_size; i+=1024)
+ {
+ mem[i] = 99;
+ }
+ printf("Done!\n");
+ exit(1);
+ }
+
+ if ((argc==3) && (strcmp(argv[1], "calc")==0))
+ {
+ char buf[257];
+ int total = 0;
+ long val;
+ while(true)
+ {
+ buf[0] = 0;
+ fgets(buf, sizeof(buf), stdin);
+ if (!strlen(buf))
+ {
+ printf("%s total = %0.1fKb (%d bytes)\n", argv[2], total/1024.0, total);
+ exit(1);
+ }
+ sscanf(buf, "%lx", &val);
+ total += val;
+// printf("Val = %ld\n", val);
+ }
+ exit(1);
+ }
+
+
+ if ((argc>=2) && (strcmp(argv[1], "launch")==0))
+ {
+ showMem();
+
+ char buf[200];
+
+ if (argc >=3)
+ snprintf(buf, 200, "%s &", argv[2]);
+ else
+ snprintf(buf, 200, "%s &", argv[0]);
+
+ printf("Waiting for memory usage to settle down....\n");
+ long prev = showTotalMem();
+ long diff = 0;
+ do {
+ sleep(15);
+ long next = showTotalMem();
+ if (next > prev)
+ diff = next - prev;
+ else
+ diff = prev-next;
+ prev = next;
+ }
+ while (diff > 2*1024);
+
+ for(int i=0; i < 5; i++)
+ {
+ printf("Launching #%d\n", i);
+ system(buf);
+ sleep(2);
+ }
+
+ sleep(10);
+ printf("Waiting for memory usage to settle down....\n");
+ prev = showTotalMem();
+ diff = 0;
+ do {
+ sleep(15);
+ long next = showTotalMem();
+ if (next > prev)
+ diff = next - prev;
+ else
+ diff = prev-next;
+ prev = next;
+ }
+ while (diff > 2*1024);
+ long fiveMem = prev;
+
+ for(int i=5; i < 15; i++)
+ {
+ printf("Launching #%d\n", i);
+ system(buf);
+ sleep(2);
+ }
+
+ sleep(10);
+ printf("Waiting for memory usage to settle down....\n");
+ prev = showTotalMem();
+ diff = 0;
+ do {
+ sleep(15);
+ long next = showTotalMem();
+ if (next > prev)
+ diff = next - prev;
+ else
+ diff = prev-next;
+ prev = next;
+ }
+ while (diff > 2*1024);
+ long fifteenMem = prev;
+ showMem();
+
+ printf("Actual memory usage of 1 instance = %0.1f Kb\n",
+ (fifteenMem - fiveMem) /10240.0);
+ }
+// showMem("second");
+
+ KApplication app(argc,argv,"kurltest");
+
+// showMem("After KApplication constructor");
+
+// malloc(10*1024);
+
+// showMem("After 10K malloc");
+
+ printf("Sleeping...\n");
+ sleep(8000);
+}
diff --git a/kdecore/tests/knotifytest.cpp b/kdecore/tests/knotifytest.cpp
new file mode 100644
index 000000000..8eb0586c0
--- /dev/null
+++ b/kdecore/tests/knotifytest.cpp
@@ -0,0 +1,10 @@
+#include <knotifyclient.h>
+#include <kapplication.h>
+
+int main( int argc, char **argv )
+{
+ KApplication app( argc, argv, "knotifytest" );
+ KNotifyClient::userEvent( "This is a notification to notify you :)",
+ KNotifyClient::Messagebox,
+ KNotifyClient::Error );
+}
diff --git a/kdecore/tests/kprocesstest.cpp b/kdecore/tests/kprocesstest.cpp
new file mode 100644
index 000000000..79769a90d
--- /dev/null
+++ b/kdecore/tests/kprocesstest.cpp
@@ -0,0 +1,116 @@
+//
+// MAIN -- a little demo of the capabilities of the "KProcess" class
+//
+// version 0.2, Aug 2nd 1997
+// $Id$
+//
+// (C) Christian Czezatke
+// e9025461@student.tuwien.ac.at
+//
+
+
+#include "kprocess.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <kapplication.h>
+
+#include <signal.h>
+
+#include "kprocesstest.h"
+
+#define PROCNO 10
+
+
+//
+// A nice input for "sort"... ;- )
+//
+static const char txt[] = "hat\nder\nalte\nhexenmeister\nsich\ndoch\neinmal\nwegbegeben\n\
+und\nnun\nsollen\nseine\ngeister\nsich\nnach\nmeinem\nwillen\nregen\nseine\nwort\nund\n\
+werke\nmerkt\nich\nund\nden\nbrauch\nund\nmit\ngeistesstaerke\ntu\nich\nwunder\nauch\n";
+
+
+int main(int argc, char *argv[])
+{
+ KProcess p1, p2, p3, p4;
+ Dummy dummy;
+ KApplication app(argc, argv, "kprocesstest");
+
+
+ printf("Welcome to the KProcess Demo Application!\n");
+
+ //
+ // The kghostview demo -- Starts a kghostview instance blocking. -- After
+ // kghostview has exited, kghostview is restarted non-blocking. When the process exits,
+ // the signal "processExited" will be emitted.
+ //
+
+ p1 << "kghostview";
+ QObject::connect(&p1, SIGNAL(processExited(KProcess *)), &dummy, SLOT(printMessage(KProcess *)));
+
+ printf("starting kghostview blocking (close to continue)\n");
+ p1.start(KProcess::Block);
+ printf("restarting kghostview non blocking\n");
+ p1.start();
+
+
+ //
+ // A konsole with tcsh to demonstrate how to pass command line options to a process
+ // with "KProcess" (is run blocking)
+ //
+
+ printf("Starting konsole with /bin/tcsh as shell (close to continue)\n");
+ p2 << "konsole" << "-e" << "/bin/tcsh";
+ p2.setWorkingDirectory("/tmp");
+ QObject::connect(&p2, SIGNAL(processExited(KProcess *)), &dummy, SLOT(printMessage(KProcess *)));
+ p2.start(KProcess::Block);
+
+ //
+ // Getting the output from a process. "ls" with parameter "-l" is called and it output is captured
+ //
+
+ p3 << "ls" << "-l";
+ QObject::connect(&p3, SIGNAL(processExited(KProcess *)),
+ &dummy, SLOT(printMessage(KProcess *)));
+
+ QObject::connect(&p3, SIGNAL(receivedStdout(KProcess *, char *, int)),
+ &dummy, SLOT(gotOutput(KProcess *, char *, int)));
+ QObject::connect(&p3, SIGNAL(receivedStderr(KProcess *, char *, int)),
+ &dummy, SLOT(gotOutput(KProcess *, char *, int)));
+
+ p3.start(KProcess::NotifyOnExit, KProcess::AllOutput);
+
+
+ //
+ // An even more advanced example of communicating with a child proces. -- A "sort" command
+ // is started. After it has been started a list of words (as stored in "txt") is written
+ // to its stdin. When the sort command has absorbed all its input it will emit the signal
+ // "inputSent". -- This signal is connected to "outputDone" in the Dummy object.
+ //
+ // "OutputDone" will do a "sendEof" to p4. -- This will cause "sort" to perform its task.
+ // The output of sort is then captured once more by connecting to the signal "outputWaiting"
+ //
+ //
+
+ p4 << "sort";
+ QObject::connect(&p4, SIGNAL(processExited(KProcess *)),
+ &dummy, SLOT(printMessage(KProcess *)));
+
+ QObject::connect(&p4, SIGNAL(receivedStdout(KProcess *, char *, int)),
+ &dummy, SLOT(gotOutput(KProcess *, char *, int)));
+ QObject::connect(&p4, SIGNAL(receivedStderr(KProcess *, char *, int)),
+ &dummy, SLOT(gotOutput(KProcess *, char *, int)));
+
+ QObject::connect(&p4, SIGNAL(wroteStdin(KProcess *)),
+ &dummy, SLOT(outputDone(KProcess *)));
+
+ p4.start(KProcess::NotifyOnExit, KProcess::All);
+ printf("after p4.start");
+ p4.writeStdin(txt, strlen(txt));
+
+ printf("Entering man Qt event loop -- press <CTRL><C> to abort\n");
+ app.exec();
+
+ return 0;
+}
+#include "kprocesstest.moc"
diff --git a/kdecore/tests/kprocesstest.h b/kdecore/tests/kprocesstest.h
new file mode 100644
index 000000000..193895510
--- /dev/null
+++ b/kdecore/tests/kprocesstest.h
@@ -0,0 +1,50 @@
+//
+// DUMMY -- A dummy class with a slot to demonstrate KProcess signals
+//
+// version 0.2, Aug 2nd 1997
+//
+// (C) Christian Czezatke
+// e9025461@student.tuwien.ac.at
+//
+
+
+#ifndef __DUMMY_H__
+#define __DUMMY_H__
+
+#include <stdio.h>
+#include <qobject.h>
+#include "kprocess.h"
+
+class Dummy : public QObject
+{
+ Q_OBJECT
+
+ public slots:
+ void printMessage(KProcess *proc)
+ {
+ printf("Process %d exited!\n", (int)proc->getPid());
+ }
+
+ void gotOutput(KProcess*, char *buffer, int len)
+ {
+ char result[1025]; // this is ugly since it relys on the internal buffer size of KProcess,
+ memcpy(result, buffer, len); // NEVER do that in your own application... ;-)
+ result[len] = '\0';
+ printf("OUTPUT>>%s", result);
+ }
+
+ void outputDone(KProcess *proc)
+ /*
+ Slot Procedure for the "sort" example. -- If it is indicated that the "sort" command has
+ absorbed all its input, we send an "EOF" to it to indicate that there is no more
+ data to be processed.
+ */
+ {
+ proc->closeStdin();
+ }
+
+};
+
+#endif
+
+
diff --git a/kdecore/tests/kprociotest.cpp b/kdecore/tests/kprociotest.cpp
new file mode 100644
index 000000000..7585b7657
--- /dev/null
+++ b/kdecore/tests/kprociotest.cpp
@@ -0,0 +1,65 @@
+//
+// MAIN -- a little demo of the capabilities of the "KProcess" class
+//
+// version 0.2, Aug 2nd 1997
+// $Id$
+//
+// (C) Christian Czezatke
+// e9025461@student.tuwien.ac.at
+//
+
+
+#include "kprocess.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <kapplication.h>
+
+#include <signal.h>
+
+#include "kprociotest.h"
+
+
+
+//
+// A nice input for "sort"... ;- )
+//
+static const char txt[] = "hat\nder\nalte\nhexenmeister\nsich\ndoch\neinmal\nwegbegeben\n\
+und\nnun\nsollen\nseine\ngeister\nsich\nnach\nmeinem\nwillen\nregen\nseine\nwort\nund\n\
+werke\nmerkt\nich\nund\nden\nbrauch\nund\nmit\ngeistesstaerke\ntu\nich\nwunder\nauch\n";
+
+
+int main(int argc, char *argv[])
+{
+ Dummy dummy;
+ KApplication app(argc, argv, "kprociotest");
+
+ printf("Welcome to the KProcIO Demo Application!\n");
+
+
+ KProcIO p;
+
+ p << "rev";
+
+ p.connect(&p, SIGNAL(processExited(KProcess*)), &dummy, SLOT(printMessage(KProcess*)));
+ p.connect(&p, SIGNAL(readReady(KProcIO*)), &dummy, SLOT(gotOutput(KProcIO*)));
+
+ bool b;
+
+ b = p.start();
+ printf("Start returns %s\n", b ? "true" : "false");
+
+ b = p.fputs("Hello World!");
+ printf("fputs returns %s\n", b ? "true" : "false");
+
+ b = p.fputs("This is a test. It should come out in reverse (esrever)");
+ printf("fputs returns %s\n", b ? "true" : "false");
+
+ p.closeWhenDone();
+
+ printf("Entering man Qt event loop -- press <CTRL><C> to abort\n");
+ app.exec();
+
+ return 0;
+}
+#include "kprociotest.moc"
diff --git a/kdecore/tests/kprociotest.h b/kdecore/tests/kprociotest.h
new file mode 100644
index 000000000..a7bb36f0f
--- /dev/null
+++ b/kdecore/tests/kprociotest.h
@@ -0,0 +1,42 @@
+//
+// DUMMY -- A dummy class with a slot to demonstrate KProcess signals
+//
+// version 0.2, Aug 2nd 1997
+//
+// (C) Christian Czezatke
+// e9025461@student.tuwien.ac.at
+//
+
+
+#ifndef __DUMMY_H__
+#define __DUMMY_H__
+
+#include <stdio.h>
+#include <qobject.h>
+#include "kprocio.h"
+
+class Dummy : public QObject
+{
+ Q_OBJECT
+
+ public slots:
+ void printMessage(KProcess *proc)
+ {
+ printf("Process %d exited!\n", (int)proc->getPid());
+ }
+
+ void gotOutput(KProcIO*proc)
+ {
+ QString line;
+ while(true) {
+ int result = proc->readln(line);
+ if (result == -1) return;
+ printf("OUTPUT>> [%d] '%s'\n", result, line.latin1());
+ }
+ }
+
+};
+
+#endif
+
+
diff --git a/kdecore/tests/krandomsequencetest.cpp b/kdecore/tests/krandomsequencetest.cpp
new file mode 100644
index 000000000..215349a05
--- /dev/null
+++ b/kdecore/tests/krandomsequencetest.cpp
@@ -0,0 +1,91 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qptrlist.h>
+
+#include "krandomsequence.h"
+#include "kapplication.h"
+
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+ KApplication a(argc, argv, "krandomsequencetest");
+
+ long seed;
+ KRandomSequence seq;
+
+ seed = 2;
+ seq.setSeed(seed);printf("Seed = %4ld :", seed);
+ for(int i = 0; i < 20; i++)
+ printf("%3ld ", seq.getLong(100));
+ printf("\n");
+
+ seed = 0;
+ seq.setSeed(seed);printf("Seed = %4ld :", seed);
+ for(int i = 0; i < 20; i++)
+ printf("%3ld ", seq.getLong(100));
+ printf("\n");
+
+ seed = 0;
+ seq.setSeed(seed);printf("Seed = %4ld :", seed);
+ for(int i = 0; i < 20; i++)
+ printf("%3ld ", seq.getLong(100));
+ printf("\n");
+
+ seed = 2;
+ seq.setSeed(seed);printf("Seed = %4ld :", seed);
+ for(int i = 0; i < 20; i++)
+ printf("%3ld ", seq.getLong(100));
+
+ seq.setSeed(kapp->random());
+
+ QPtrList<QString> list;
+ list.append(new QString("A"));
+ list.append(new QString("B"));
+ list.append(new QString("C"));
+ list.append(new QString("D"));
+ list.append(new QString("E"));
+ list.append(new QString("F"));
+ list.append(new QString("G"));
+
+ for(QString *str = list.first(); str; str = list.next())
+ printf("%s", str->latin1());
+ printf("\n\n");
+
+ seq.randomize(&list);
+
+ for(QString *str = list.first(); str; str = list.next())
+ printf("%s", str->latin1());
+ printf("\n\n");
+
+ seq.randomize(&list);
+
+ for(QString *str = list.first(); str; str = list.next())
+ printf("%s", str->latin1());
+ printf("\n\n");
+
+ seq.randomize(&list);
+
+ for(QString *str = list.first(); str; str = list.next())
+ printf("%s", str->latin1());
+ printf("\n\n");
+
+ printf("\n");
+}
diff --git a/kdecore/tests/kresolvertest.cpp b/kdecore/tests/kresolvertest.cpp
new file mode 100644
index 000000000..30003265a
--- /dev/null
+++ b/kdecore/tests/kresolvertest.cpp
@@ -0,0 +1,420 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2001 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+#include <kuniqueapplication.h>
+#include <ksocks.h>
+#include <ksockaddr.h>
+#include <kextsock.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+
+#include "netsupp.h"
+
+/*
+ * These constants tell the flags in KDE::resolverFlags
+ * This is copied from ../netsupp.cpp
+ */
+#define KRF_KNOWS_AF_INET6 0x01 /* if present, the code knows about AF_INET6 */
+#define KRF_USING_OWN_GETADDRINFO 0x02 /* if present, we are using our own getaddrinfo */
+#define KRF_USING_OWN_INET_NTOP 0x04 /* if present, we are using our own inet_ntop */
+#define KRF_USING_OWN_INET_PTON 0x08 /* if present, we are using our own inet_pton */
+#define KRF_CAN_RESOLVE_UNIX 0x100 /* if present, the resolver can resolve Unix sockets */
+#define KRF_CAN_RESOLVE_IPV4 0x200 /* if present, the resolver can resolve to IPv4 */
+#define KRF_CAN_RESOLVE_IPV6 0x400 /* if present, the resolver can resolve to IPv6 */
+
+namespace KDE
+{
+ extern const int resolverFlags;
+}
+
+class TestApp : public KUniqueApplication
+{
+public:
+ TestApp() :
+ KUniqueApplication()
+ { }
+
+ int newInstance(QValueList<QCString> params);
+};
+
+bool tryLookup(const char* node, const char *serv)
+{
+ int error;
+ QString _node = QString::fromLatin1(node);
+ QString _serv = QString::fromLatin1(serv);
+
+ printf("\tTrying to lookup %s|%s... ", node, serv);
+ QPtrList<KAddressInfo> list = KExtendedSocket::lookup(_node, _serv, 0, &error);
+ list.setAutoDelete(true);
+ if (!list.isEmpty())
+ {
+ printf("worked\n");
+ return true;
+ }
+
+ printf("failed\n\tReason was: %s\n",
+ (const char*)KExtendedSocket::strError(IO_LookupError, error).local8Bit());
+ return false;
+}
+
+#ifdef AF_INET6
+bool try_ntop()
+{
+ char buf[50]; // 46 is enough
+ kde_in6_addr in;
+
+ memset(&in, 0, sizeof(in));
+ ((unsigned char*)&in)[15] = 1; // set this to be ::1
+
+ printf("\tTrying to convert ::1 into string...");
+ if (inet_ntop(AF_INET6, &in, buf, sizeof(buf)) == NULL)
+ {
+ printf("failed\n");
+ return false;
+ }
+
+ printf("suceeded\n\treturned '%s'\n", buf);
+ return strcmp(buf, "::1") == 0;
+}
+
+bool try_pton()
+{
+ const char *buf = "::1";
+ kde_in6_addr in;
+
+ printf("\tTrying to convert '::1' into binary form...");
+ if (inet_pton(AF_INET6, buf, &in) == 0)
+ {
+ printf("failed\n");
+ return false;
+ }
+
+ if (KDE_IN6_IS_ADDR_LOOPBACK(&in))
+ {
+ printf("succeeded\n");
+ return true;
+ }
+
+ printf("claims to have suceeded, but returned invalid value\n");
+ return false;
+}
+#endif
+
+bool tryLookup6(const char *node, const char *serv)
+{
+ int error;
+ QString _node = QString::fromLatin1(node);
+ QString _serv = QString::fromLatin1(serv);
+
+ printf("\tTrying to lookup IPv6 of %s|%s... ", node, serv);
+ QPtrList<KAddressInfo> list = KExtendedSocket::lookup(_node, _serv, KExtendedSocket::ipv6Socket, &error);
+ list.setAutoDelete(true);
+ if (!list.isEmpty())
+ {
+ printf("worked\n");
+ return true;
+ }
+
+ printf("failed\n\tReason was: %s\n",
+ (const char*)KExtendedSocket::strError(IO_LookupError, error).local8Bit());
+ return false;
+}
+
+bool testKernel()
+{
+#ifndef AF_INET6
+ printf("\tAF_INET6 unknown. Can't test anything\n");
+ return false;
+
+#else
+ int sock;
+ kde_sockaddr_in6 sin6;
+ socklen_t len = sizeof(sin6);
+
+ printf("\tAF_INET6 == %d\n", AF_INET6);
+ printf("\tTrying to create an IPv6 socket...");
+ sock = socket(AF_INET6, SOCK_STREAM, 0);
+ if (sock == -1)
+ printf("failed\n\tReason was: %s", strerror(errno));
+ else
+ {
+ printf("succeeded\n");
+
+ if (getsockname(sock, (struct sockaddr*)&sin6, &len) == 0)
+ printf("\tSize of kernel's sockaddr_in6 is %d bytes\n", len);
+ else
+ printf("\tCould not get socket name\n");
+ }
+
+ printf("\tSize of KDE's internal sockaddr_in6 is %d bytes\n",
+ sizeof(kde_sockaddr_in6));
+
+# ifdef HAVE_SOCKADDR_IN6
+ printf("\tSize of system libraries' sockaddr_in6 is %d bytes\n",
+ sizeof(sockaddr_in6));
+# else
+ printf("\tSystem libraries don't define sockaddr_in6\n");
+# endif
+
+ if (sock == -1)
+ return false;
+
+ printf("\tTrying to bind the socket to an address...");
+ sin6.sin6_family = AF_INET6;
+# ifdef HAVE_SOCKADDR_SA_LEN
+ sin6.sin6_len = sizeof(sin6);
+# endif
+ sin6.sin6_flowinfo = 0;
+ sin6.sin6_scope_id = 0;
+ sin6.sin6_port = 0; // bind to any port
+ memset(&sin6.sin6_addr, 0, sizeof(sin6.sin6_addr)); // any address
+
+ if (bind(sock, (sockaddr*)&sin6, sizeof(sin6)) == -1)
+ {
+ printf("failed\n\tReason was: %s\n", strerror(errno));
+ close(sock);
+ return false;
+ }
+
+ printf("succeeded\n");
+
+ KSocketAddress *ksin = KExtendedSocket::localAddress(sock);
+ if (ksin != NULL)
+ {
+ printf("\tWe got socket %s\n", (const char*)ksin->pretty().latin1());
+ delete ksin;
+ }
+
+ close(sock);
+ return true;
+#endif // AF_INET6
+}
+
+bool tryConnectLocal()
+{
+ KExtendedSocket ks1("::", "0", KExtendedSocket::ipv6Socket | KExtendedSocket::passiveSocket),
+ ks2;
+ const KInetSocketAddress *ksin1, *ksin2;
+
+ printf("Attempting a loop-back connection\n\tTrying to listen on socket...");
+ if (ks1.listen() != 0)
+ {
+ printf("failed\n\tReason was: %s\n",
+ (const char*)KExtendedSocket::strError(ks1.status(), ks1.systemError()).local8Bit());
+ return false;
+ }
+
+ ks1.setBlockingMode(false);
+ ksin1 = (KInetSocketAddress*)ks1.localAddress();
+
+ printf("succeeded\n\tWe have socket %s listening\n",
+ (const char*)ksin1->pretty().local8Bit());
+
+ ks2.setAddress("::1", ksin1->port());
+ ks2.setSocketFlags(KExtendedSocket::ipv6Socket | KExtendedSocket::noResolve);
+
+ printf("\tTrying to connect to that socket...");
+ if (ks2.connect() != 0)
+ {
+ printf("failed\n\tReason was: %s\n",
+ (const char*)KExtendedSocket::strError(ks2.status(), ks2.systemError()).local8Bit());
+ return false;
+ }
+
+ printf("suceeded\n");
+
+ ksin2 = dynamic_cast<const KInetSocketAddress *>(ks2.localAddress());
+ printf("\tIf you may flip to another terminal/xterm and run netstat to see\n"
+ "\tthis connection. It should be a connection from %s to %s.\n"
+ "\tPress any key to continue\n",
+ (const char*)ksin2->pretty().local8Bit(), (const char*)ksin1->pretty().local8Bit());
+ getchar();
+ return true;
+}
+
+bool tryConnectRemote()
+{
+ KExtendedSocket ks("www.6bone.net", "80", KExtendedSocket::ipv6Socket);
+
+ printf("\nAttempting a remote connection to www.6bone.net|80\n");
+
+ if (ks.connect() != 0)
+ {
+ printf("\tConnection failed with error: %s\n",
+ (const char*)KExtendedSocket::strError(ks.status(), ks.systemError()).local8Bit());
+ return false;
+ }
+
+ printf("\tConnection succeeded\n");
+ return true;
+}
+
+void go()
+{
+ int rf = KDE::resolverFlags;
+ printf("The resolver claims to:\n");
+ if (rf & KRF_USING_OWN_GETADDRINFO)
+ {
+ printf(" - Be using its own version of getaddrinfo()\n");
+ if (rf & KRF_CAN_RESOLVE_UNIX)
+ printf(" - Be able to resolve Unix-domain sockets\n");
+ else
+ printf(" - Be unable to resolve Unix-domain sockets -- This shouldn't happen\n");
+ if (rf & KRF_CAN_RESOLVE_IPV4)
+ printf(" - Be able to resolve IPv4 Internet sockets\n");
+ else
+ printf(" - Be unable to resolve IPv4 Internet sockets -- This shouldn't happen\n");
+ if (rf & KRF_CAN_RESOLVE_IPV6)
+ printf(" - Be able to resolve IPv6 Internet sockets\n");
+ else
+ printf(" - Be unable to resolve IPv6 Internet sockets\n");
+ }
+ else
+ printf(" - Be using the system getaddrinfo()\n");
+
+ if (rf & KRF_USING_OWN_INET_NTOP)
+ printf(" - Be using its own inet_ntop()\n");
+ else
+ printf(" - Be using the system inet_ntop()\n");
+
+ if (rf & KRF_USING_OWN_INET_PTON)
+ printf(" - Be using its own inet_pton()\n");
+ else
+ printf(" - Be using the system inet_pton()\n");
+
+ if (rf & KRF_KNOWS_AF_INET6)
+ printf(" - To know the value of AF_INET6\n");
+ else
+ printf(" - Not to know the value of AF_INET6\n");
+
+ printf("\n\nGeneral conclusion is:\n");
+ if ((rf & KRF_USING_OWN_GETADDRINFO) == 0 &&
+ rf & KRF_KNOWS_AF_INET6)
+ printf(" Your system probably supports full IPv6 implementation.\n"
+ " This depends on whether your system's getaddrinfo() supports IPv6.\n"
+ " However, KDE Libraries were compiled to use the support whenever available.\n");
+ else if ((rf & (KRF_USING_OWN_GETADDRINFO|KRF_KNOWS_AF_INET6)) == 0)
+ printf(" Your system supports partial IPv6 implementation.\n"
+ " That is, your system has a getaddrinfo() implementation, but KDE Libraries\n"
+ " don't know how to detect an IPv6 socket. That means that only request to"
+ " any kind of socket will use IPv6, if your getaddrinfo() returns them.");
+ else if (rf & KRF_USING_OWN_GETADDRINFO)
+ {
+ if (rf & KRF_KNOWS_AF_INET6)
+ {
+ printf(" Your system supports partial IPv6 implementation.\n");
+ if (rf & KRF_CAN_RESOLVE_IPV6)
+ printf(" The KDE implementation of getaddrinfo() claims to be able to resolve\n"
+ " IPv6 lookups and the value of AF_INET6 is known.\n");
+ else
+ printf(" The KDE implementation of getaddrinfo() cannot resolve IPv6 lookups.\n"
+ " That means that IPv6 support is limited to two addresses (:: and ::1)\n");
+ }
+ else
+ printf(" Your system doesn't support IPv6\n");
+ }
+
+ /* Make sure KSocks doesn't interfere in testing */
+ KSocks::disable();
+
+ /* Begin testing */
+ printf("\nReady to start testing\nPress any key to continue...");
+ getchar();
+ printf("\n");
+
+ /* Start with simple lookups */
+ printf("Trying simple lookups\n"
+ "All of the following look ups should work\n\n");
+ tryLookup(NULL, "/tmp/something");
+ tryLookup("127.0.0.1", "80");
+ tryLookup("localhost", "http");
+
+#ifdef AF_INET6
+ printf("\nPress any key for next test");
+ getchar();
+
+ printf("\nThis test determines if the inet_ntop and inet_pton functions work\n");
+ try_ntop();
+ try_pton();
+#endif
+
+ printf("\nPress any key for next test");
+ getchar();
+
+ printf("\nThis test determines how far the IPv6 resolution can go\n");
+ if (!tryLookup6("::1", "80"))
+ printf("Your system can't resolve a numeric IPv6 address\n");
+ else if (!tryLookup6("localhost", "80"))
+ printf("Your system can resolve a numeric IPv6 address, but not localhost\n");
+ else if (!tryLookup6("www.6bone.net", "80"))
+ printf("Your system can resolve numeric IPv6 addresses and localhost, \n"
+ "but cannot resolve an external address to IPv6 (www.6bone.net)\n");
+ else
+ printf("Your system can resolve any kind of IPv6 addresses\n");
+
+ printf("\nPress any key for next test");
+ getchar();
+
+ printf("\nThis test determines how supported IPv6 is in your kernel\n");
+ testKernel();
+
+ printf("\nPress any key for next test");
+ getchar();
+
+ printf("\nThis test determines if you can connect to IPv6 addresses via TCP\n");
+ tryConnectLocal();
+ tryConnectRemote();
+
+ printf("\n\nTest finished\n");
+}
+
+int TestApp::newInstance(QValueList<QCString> /*params*/)
+{
+ go();
+}
+
+int main(int argc, char **argv)
+{
+ KAboutData about("socktest2", "SockTest", "1.0");
+ KCmdLineArgs::init(argc, argv, &about);
+ KUniqueApplication::addCmdLineOptions();
+
+ /* TestApp a;
+ a.exec();*/
+ go();
+}
diff --git a/kdecore/tests/krfcdatetest.cpp b/kdecore/tests/krfcdatetest.cpp
new file mode 100644
index 000000000..1c1957b54
--- /dev/null
+++ b/kdecore/tests/krfcdatetest.cpp
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <kapplication.h>
+#include <stdlib.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kcharsets.h>
+#include <qtextcodec.h>
+#include <krfcdate.h>
+
+bool check(QString txt, time_t a, time_t b)
+{
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ KApplication app(argc,argv,"kurltest",false,false);
+
+ time_t a;
+ time_t b;
+
+ // From http://www.w3.org/TR/NOTE-datetime
+ b = KRFCDate::parseDateISO8601("1994-11-05T13:15:30Z");
+ a = KRFCDate::parseDateISO8601("1994-11-05T08:15:30-05:00");
+ check( "1994-11-05T08:15:30-05:00", a, b);
+
+ a = KRFCDate::parseDateISO8601("1994-11-05T18:15:30+05:00");
+ check( "1994-11-05T18:15:30+05:00", a, b);
+
+ a = KRFCDate::parseDate("Thu Nov 5 1994 18:15:30 GMT+0500");
+ check( "Thu Nov 5 1994 18:15:30 GMT+0500", a, b);
+
+ a = KRFCDate::parseDate("Thu Nov 5 1994 18:15:30 GMT+05:00");
+ check( "Thu Nov 5 1994 18:15:30 GMT+05:00", a, b);
+
+ a = KRFCDate::parseDate("Wednesday, 05-Nov-94 13:15:30 GMT");
+ check( "Wednesday, 05-Nov-94 13:15:30 GMT", a, b);
+
+ a = KRFCDate::parseDate("Wed, 05-Nov-1994 13:15:30 GMT");
+ check( "Wed, 05-Nov-1994 13:15:30 GMT", a, b);
+
+ a = KRFCDate::parseDate("Wed, 05-November-1994 13:15:30 GMT");
+ check( "Wed, 05-November-1994 13:15:30 GMT", a, b);
+
+ b = KRFCDate::parseDateISO8601("1994-01-01T12:00:00");
+ a = KRFCDate::parseDateISO8601("1994");
+ check( "1994", a, b );
+
+ a = KRFCDate::parseDateISO8601("1994-01");
+ check( "1994-01", a, b );
+
+ a = KRFCDate::parseDateISO8601("1994-01-01");
+ check( "1994-01-01", a, b );
+
+ b = 0;
+
+ // pass RFC date to ISO parser
+ a = KRFCDate::parseDateISO8601("Thu, 01 Jan 2004 19:48:21 GMT");
+ check("pass RFC date \"Thu, 01 Jan 2004 19:48:21 GMT\" to parseDateISO8601", a, b);
+
+ // pass ISO date to RFC parser
+ a = KRFCDate::parseDate("1994-01-01T12:00:00");
+ check("pass ISO date \"1994-01-01T12:00:00\" to parseDate()", a, b);
+
+ // empty/null strings
+
+ check("parseDateISO8601(QString())", KRFCDate::parseDateISO8601(QString()), b);
+ check("parseDateISO8601(\"\")", KRFCDate::parseDateISO8601(""), b);
+ check("parseDate(QString())", KRFCDate::parseDate(QString()), b);
+ check("parseDate(\"\")", KRFCDate::parseDate(""), b);
+
+ printf("\nTest OK !\n");
+}
+
diff --git a/kdecore/tests/kshelltest.cpp b/kdecore/tests/kshelltest.cpp
new file mode 100644
index 000000000..eaca1fcbe
--- /dev/null
+++ b/kdecore/tests/kshelltest.cpp
@@ -0,0 +1,55 @@
+#include <kshell.h>
+
+#include <iostream>
+
+static QCString
+ps(const QString &s)
+{
+ if (s.isNull())
+ return "(null)";
+ else
+ return s.local8Bit();
+}
+
+static void
+tx(const char *t)
+{
+ std::cout << t << " -> " << ps(KShell::tildeExpand(t)) << std::endl;
+}
+
+static void
+sj(const char *t, int flg)
+{
+ int err;
+ std::cout << t << " (" << flg << ") -> " << ps(KShell::joinArgsDQ(KShell::splitArgs(t, flg, &err))) << " (" << err << ")" << std::endl;
+}
+
+int main()
+{
+#if 1
+ tx("~");
+ tx("~/sulli");
+ tx("~root");
+ tx("~root/sulli");
+ tx("~sulli");
+#endif
+#if 1
+ QStringList lst;
+ lst << "this" << "is" << "text";
+ std::cout << KShell::joinArgs(lst).latin1() << std::endl;
+#endif
+#if 1
+ sj("\"~sulli\" 'text' 'jo'\"jo\" $'crap' $'\\\\\\'\\ca\\e\\x21' ha\\ lo ", KShell::NoOptions);
+ sj("\"~sulli\" 'text'", KShell::TildeExpand);
+ sj("~\"sulli\" 'text'", KShell::TildeExpand);
+ sj("~/\"sulli\" 'text'", KShell::TildeExpand);
+ sj("~ 'text' ~", KShell::TildeExpand);
+ sj("~sulli ~root", KShell::TildeExpand);
+#endif
+ sj("say \" error", KShell::NoOptions);
+ sj("say `echo no error`", KShell::NoOptions);
+ sj("say \" still error", KShell::AbortOnMeta);
+ sj("say `echo meta error`", KShell::AbortOnMeta);
+ sj("BLA=say echo meta", KShell::AbortOnMeta);
+ sj("B\"L\"A=say FOO=bar echo meta", KShell::AbortOnMeta);
+}
diff --git a/kdecore/tests/ksimpleconfigtest.cpp b/kdecore/tests/ksimpleconfigtest.cpp
new file mode 100644
index 000000000..6aa93c06d
--- /dev/null
+++ b/kdecore/tests/ksimpleconfigtest.cpp
@@ -0,0 +1,48 @@
+// $Id$
+
+//
+// configtest.cpp: libKDEcore example
+//
+// demonstrates use of KSimpleConfig class
+
+#include <ksimpleconfig.h>
+#include <kapplication.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef _PATH_TMP
+#define _PATH_TMP "/tmp/"
+#endif
+
+int main( int argc, char **argv )
+{
+ KApplication a( argc, argv, "kconfigtest" );
+
+ KSimpleConfig aConfig( _PATH_TMP"/simpleconfig.cfg" );
+
+ aConfig.setGroup( "Test group" );
+ aConfig.writeEntry( "key1", "value1" );
+ aConfig.writeEntry( "key2", "value2" );
+
+ aConfig.setGroup( "Another Test group" );
+ aConfig.writeEntry( "akey1", "avalue1" );
+ aConfig.writeEntry( "akey2", "avalue2" );
+
+ fprintf( stderr, "entries written, sleeping for 10 seconds\n" );
+ aConfig.sync();
+ sleep( 10 );
+
+ aConfig.setGroup( "Test group" );
+ aConfig.deleteEntry( "key2", false );
+ fprintf( stderr, "Deleted on entry from Test group, sleeping\n" );
+ aConfig.sync();
+ sleep( 10 );
+
+ aConfig.deleteGroup( "Another Test group", true );
+ fprintf( stderr, "Deleted Another Test group\n" );
+}
+
diff --git a/kdecore/tests/ksocktest.cpp b/kdecore/tests/ksocktest.cpp
new file mode 100644
index 000000000..89b59c62a
--- /dev/null
+++ b/kdecore/tests/ksocktest.cpp
@@ -0,0 +1,109 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kuniqueapplication.h"
+#include "kglobal.h"
+#include "kdebug.h"
+#include "ksock.h"
+#include "ksockaddr.h"
+#include "kextsock.h"
+
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+bool check(QString txt, QString a, QString b)
+{
+ if (a.isEmpty())
+ a = QString::null;
+ if (b.isEmpty())
+ b = QString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ KAboutData about("socktest", "SockTest", "version");
+ KCmdLineArgs::init(argc, argv, &about);
+ KApplication::addCmdLineOptions();
+
+ KApplication app;
+
+ QString host, port;
+
+ KInetSocketAddress host_address("213.203.58.36", 80);
+
+ check("KInetSocketAddress(\"213.203.58.36\", 80)", host_address.pretty(), "213.203.58.36 port 80");
+
+ int result = KExtendedSocket::resolve(&host_address, host, port, NI_NAMEREQD);
+ printf( "resolve result: %d\n", result );
+ check("KExtendedSocket::resolve() host=", host, "www.kde.org");
+// check("KExtendedSocket::resolve() port=", port, "http");
+ QPtrList<KAddressInfo> list;
+ list = KExtendedSocket::lookup("www.kde.org", "http", KExtendedSocket::inetSocket);
+ for(KAddressInfo *info = list.first(); info; info = list.next())
+ {
+ qWarning("Lookup: %s %s %s", info->address()->pretty().latin1(),
+ info->address()->isEqual(KInetSocketAddress("213.203.58.36", 80)) ?
+ "is equal to" : "is NOT equal to",
+ "213.203.58.36 port 80");
+ }
+ check("KExtendedSocket::lookup()", list.first()->address()->pretty(), "213.203.58.36 port 80");
+
+
+
+ int err;
+
+ QPtrList<KAddressInfo> cns = KExtendedSocket::lookup("www.kde.org", 0, KExtendedSocket::canonName, &err);
+ for (KAddressInfo *x = cns.first(); x; x = cns.next()) {
+ const char *canon = x->canonname();
+ qWarning( "Lookup: %s", canon ? canon : "<Null>");
+ }
+ check("KExtendedSocket::lookup() canonical", cns.first()->canonname(), "www.kde.org");
+
+ KExtendedSocket * sock2 = new KExtendedSocket( "www.kde.org", 80 );
+ check( "KExtendedSocket ctor / connect", QString::number( sock2->connect() ), "0" );
+
+ printf("FD %d\n", sock2->fd());
+
+ KSocketAddress* addr = KExtendedSocket::peerAddress( sock2->fd() );
+ check( "peerAddress:", addr->nodeName().latin1(), "213.203.58.36" );
+
+ check( "isEqual:", addr->isEqual(KInetSocketAddress("213.203.58.36", 80)) ? "TRUE" : "FALSE", "TRUE");
+ check( "isEqual:", addr->isEqual(KInetSocketAddress("213.203.58.36", 8080)) ? "TRUE" : "FALSE", "FALSE");
+ check( "isEqual:", addr->isCoreEqual(KInetSocketAddress("213.203.58.36", 8080)) ? "TRUE" : "FALSE", "TRUE");
+}
diff --git a/kdecore/tests/ksortablevaluelisttest.cpp b/kdecore/tests/ksortablevaluelisttest.cpp
new file mode 100644
index 000000000..de937c797
--- /dev/null
+++ b/kdecore/tests/ksortablevaluelisttest.cpp
@@ -0,0 +1,32 @@
+#include <qstring.h>
+#include <ksortablevaluelist.h>
+
+int main( int argc, char **argv )
+{
+ KSortableValueList<QString> list;
+ list.insert( 1, "FOO (1)" );
+ list.insert( 2, "Test (2)" );
+ list.insert( 1, "Huba! (1)" );
+ list.insert( 5, "MAAOOAM! (5)" );
+ list.insert( 10, "Teeheeest (10)" );
+ list.insert( 2, "I was here :) (2)" );
+ list.insert( 4, "Yeehaa... (4)" );
+
+ QValueListIterator<KSortableItem<QString> > it = list.begin();
+
+ qDebug("Insertion order:");
+ qDebug("================");
+ for ( ; it != list.end(); ++it )
+ qDebug( "%i: %s", (*it).index(), (*it).value().latin1() );
+
+ list.sort();
+
+ qDebug("\nSorted:");
+ qDebug("=======");
+
+ it = list.begin();
+ for ( ; it != list.end(); ++it )
+ qDebug( "%i: %s", (*it).index(), (*it).value().latin1() );
+
+ return 0;
+}
diff --git a/kdecore/tests/kstdacceltest.cpp b/kdecore/tests/kstdacceltest.cpp
new file mode 100644
index 000000000..71eff30cd
--- /dev/null
+++ b/kdecore/tests/kstdacceltest.cpp
@@ -0,0 +1,39 @@
+#include <config.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kstdaccel.h>
+#include <stdlib.h> // for exit
+
+static bool check(QString txt, QString a, QString b)
+{
+ if (a.isEmpty())
+ a = QString::null;
+ if (b.isEmpty())
+ b = QString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ KApplication::disableAutoDcopRegistration();
+ KApplication app(argc,argv,"kstdacceltest",false,false);
+
+ check( "shortcutDefault FullScreen", KStdAccel::shortcutDefault( KStdAccel::FullScreen ).toString(), "Ctrl+Shift+F" );
+ check( "shortcutDefault BeginningOfLine", KStdAccel::shortcutDefault( KStdAccel::BeginningOfLine ).toString(), "Home" );
+ check( "shortcutDefault EndOfLine", KStdAccel::shortcutDefault( KStdAccel::EndOfLine ).toString(), "End" );
+
+ check( "name BeginningOfLine", KStdAccel::name( KStdAccel::BeginningOfLine ), "BeginningOfLine" );
+ check( "name EndOfLine", KStdAccel::name( KStdAccel::EndOfLine ), "EndOfLine" );
+
+ check( "shortcut method", KStdAccel::shortcut( KStdAccel::ZoomIn ).toString(), KStdAccel::zoomIn().toString() );
+
+ return 0;
+}
diff --git a/kdecore/tests/kstddirstest.cpp b/kdecore/tests/kstddirstest.cpp
new file mode 100644
index 000000000..23c0f0a1c
--- /dev/null
+++ b/kdecore/tests/kstddirstest.cpp
@@ -0,0 +1,52 @@
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kinstance.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+
+int main(int argc, char **argv)
+{
+ KApplication a(argc, argv, "whatever", false);
+ KStandardDirs t;
+ KConfig config; // to add custom entries - a bit tricky :/
+
+ QStringList list;
+ QString s;
+
+ t.saveLocation("icon");
+
+ s = t.findResource("icon", "xv.xpm");
+ if (!s.isNull()) kdDebug() << s << endl;
+
+ list = t.findAllResources("data", "kfind/toolbar", true);
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ kdDebug() << "data " << (*it).ascii() << endl;
+ }
+
+ list = t.findAllResources("config", "kcmdisplayrc");
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ kdDebug() << "config " << (*it).ascii() << endl;
+ }
+
+ list = t.findAllResources("config", "kcmdisplayrc", false, true);
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ kdDebug() << "config2 " << (*it).ascii() << endl;
+ }
+
+ list = t.findAllResources("html", "en/*/index.html", false);
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ kdDebug() << "docs " << (*it).ascii() << endl;
+ }
+
+ list = t.findAllResources("html", "*/*/*.html", false);
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ kdDebug() << "docs " << (*it).ascii() << endl;
+ }
+
+ list = t.findDirs("data", "kwin");
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ kdDebug() << "kwin dirs " << (*it).ascii() << endl;
+ }
+
+ kdDebug() << "hit " << t.findResourceDir("config", "kcmdisplayrc") << endl;
+}
diff --git a/kdecore/tests/kstringhandlertest.cpp b/kdecore/tests/kstringhandlertest.cpp
new file mode 100644
index 000000000..75695309d
--- /dev/null
+++ b/kdecore/tests/kstringhandlertest.cpp
@@ -0,0 +1,97 @@
+#include "kstringhandler.h"
+#include <iostream>
+using std::cout;
+using std::endl;
+
+bool check(const QString &txt, const QString &a, const QString &b)
+{
+ if ( a != b ) {
+ cout << "ERROR: Tested " << txt.latin1() << ", expected" << endl;
+ cout << "'" << b.latin1() << "' (" << b.length() << " chars)" << endl;
+ cout << "but got" << endl;
+ cout << "'" << a.latin1() << "' (" << a.length() << " chars)" << endl;
+ exit( 1 );
+ }
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ QString test = "The quick brown fox jumped over the lazy bridge. ";
+
+ check("word(test, 3)",
+ KStringHandler::word(test, 2),
+ "brown");
+ check("word(test, \"3:5\")",
+ KStringHandler::word(test, "2:4"),
+ "brown fox jumped");
+ check("insword(test, \"very\", 1)",
+ KStringHandler::insword(test, "very", 1),
+ "The very quick brown fox jumped over the lazy bridge. ");
+ check("setword(test, \"very\", 1)",
+ KStringHandler::setword(test, "very", 1),
+ "The very brown fox jumped over the lazy bridge. ");
+ check("remrange(test, \"4:6\")",
+ KStringHandler::remrange(test, "4:6"),
+ "The quick brown fox lazy bridge. " );
+ check("remrange(test, \"4:8\")",
+ KStringHandler::remrange(test, "4:8"),
+ "The quick brown fox ");
+ check("remword(test, 4)",
+ KStringHandler::remword(test, 4),
+ "The quick brown fox over the lazy bridge. ");
+ check("remword(test, \"lazy\")",
+ KStringHandler::remword(test, "lazy"),
+ "The quick brown fox jumped over the bridge. ");
+ check("capwords(test)",
+ KStringHandler::capwords(test),
+ "The Quick Brown Fox Jumped Over The Lazy Bridge. ");
+ check("reverse(test)",
+ KStringHandler::reverse(test),
+ " bridge. lazy the over jumped fox brown quick The");
+ QString result;
+ result = KStringHandler::ljust(test, 70);
+ if (result.length() != 70)
+ {
+ printf("Length = %d, expected 70.\n", result.length());
+ exit(1);
+ }
+ check("ljust(test, 70)",
+ result,
+ "The quick brown fox jumped over the lazy bridge. ");
+ result = KStringHandler::rjust(test, 70);
+ if (result.length() != 70)
+ {
+ printf("Length = %d, expected 70.\n", result.length());
+ exit(1);
+ }
+ check("rjust(test, 70)",
+ result,
+ " The quick brown fox jumped over the lazy bridge.");
+ result = KStringHandler::center(test, 70);
+ if (result.length() != 70)
+ {
+ printf("Length = %d, expected 70.\n", result.length());
+ exit(1);
+ }
+ check("center(test, 70)",
+ result,
+ " The quick brown fox jumped over the lazy bridge. ");
+
+ test = "Click on http://foo@bar:www.kde.org/yoyo/dyne.html#a1 for info.";
+ check( "tagURLs()", KStringHandler::tagURLs( test ),
+ "Click on <a href=\"http://foo@bar:www.kde.org/yoyo/dyne.html#a1\">http://foo@bar:www.kde.org/yoyo/dyne.html#a1</a> for info." );
+
+ test = "http://www.foo.org/story$806";
+ check( "tagURLs()", KStringHandler::tagURLs( test ),
+ "<a href=\"http://www.foo.org/story$806\">http://www.foo.org/story$806</a>" );
+
+#if 0
+ // XFAIL - i.e. this needs to be fixed, but has never been
+ test = "&lt;a href=www.foo.com&gt;";
+ check( "tagURLs()", KStringHandler::tagURLs( test ),
+ "&lt;a href=<a href=\"www.foo.com\">www.foo.com</a>&gt;" );
+#endif
+
+ cout << "All OK!" << endl;
+}
diff --git a/kdecore/tests/ktempfiletest.cpp b/kdecore/tests/ktempfiletest.cpp
new file mode 100644
index 000000000..aacf30255
--- /dev/null
+++ b/kdecore/tests/ktempfiletest.cpp
@@ -0,0 +1,48 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "ktempfile.h"
+#include "kapplication.h"
+#include "kstandarddirs.h"
+#include <qstring.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(int argc, char *argv[])
+{
+ KApplication a(argc, argv, "ktempfiletest");
+ printf("Making tempfile after KApplication constructor.\n");
+ KTempFile f4;
+ printf("Filename = %s\n", f4.name().ascii());
+
+ printf("Making tempfile with \".ps\" extension.\n");
+ KTempFile f2(QString::null, ".ps");
+ printf("Filename = %s\n", f2.name().ascii());
+
+ printf("Making tempfile in home directory.\n");
+ KTempFile f3(QString((const char *)getenv("HOME"))+"/testXXX", ".myEXT", 0666);
+ printf("Filename = %s\n", f3.name().ascii());
+
+ QString name = locateLocal("socket", "test");
+ printf("Socket Filename = %s\n", name.ascii());
+
+ printf("Done.\n");
+}
diff --git a/kdecore/tests/ktimezonestest.cpp b/kdecore/tests/ktimezonestest.cpp
new file mode 100644
index 000000000..7be8bd621
--- /dev/null
+++ b/kdecore/tests/ktimezonestest.cpp
@@ -0,0 +1,62 @@
+#include "ktimezones.h"
+#include <kapplication.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ KInstance instance("ktimezonestest");
+
+ if ((argc==2) && (strcmp(argv[1], "local")==0))
+ {
+ KTimezones timezones;
+
+ // Find the local timezone.
+ const KTimezone *timezone = timezones.local();
+ printf( "Local timezone: %s\n", timezone->name().latin1() );
+
+ // Find the current offset of the UTC timezone.
+ timezone = timezones.zone("UTC");
+ printf( "UTC timezone offset should be 0: %d\n", timezone->offset(QDateTime::currentDateTime()) );
+
+ // Find some offsets for Europe/London.
+ char *london = "Europe/London";
+ timezone = timezones.zone(london);
+ QDateTime winter(QDateTime::fromString("2005-01-01T00:00:00", Qt::ISODate));
+ QDateTime summer(QDateTime::fromString("2005-06-01T00:00:00", Qt::ISODate));
+ printf( "%s winter timezone offset should be 0: %d\n", london, timezone->offset(winter) );
+ printf( "%s summer timezone offset should be 3600: %d\n", london, timezone->offset(summer) );
+
+ // Try timezone conversions.
+ const KTimezone *losAngeles = timezones.zone("America/Los_Angeles");
+ char *bstBeforePdt = "2005-03-28T00:00:00";
+ char *bstAfterPdt = "2005-05-01T00:00:00";
+ char *gmtBeforePst = "2005-10-30T01:00:00";
+ char *gmtAfterPst = "2005-12-01T00:00:00";
+ QString result;
+ result = timezone->convert(losAngeles, QDateTime::fromString(bstBeforePdt, Qt::ISODate)).toString(Qt::ISODate);
+ printf( "BST before PDT, %s should be 2005-03-27T15:00:00: %s\n", bstBeforePdt, result.latin1() );
+ result = timezone->convert(losAngeles, QDateTime::fromString(bstAfterPdt, Qt::ISODate)).toString(Qt::ISODate);
+ printf( "BST and PDT, %s should be 2005-04-30T16:00:00: %s\n", bstAfterPdt, result.latin1() );
+ result = timezone->convert(losAngeles, QDateTime::fromString(gmtBeforePst, Qt::ISODate)).toString(Qt::ISODate);
+ printf( "GMT before PST, %s should be 2005-10-29T17:00:00: %s\n", gmtBeforePst, result.latin1() );
+ result = timezone->convert(losAngeles, QDateTime::fromString(gmtAfterPst, Qt::ISODate)).toString(Qt::ISODate);
+ printf( "GMT and PST, %s should be 2005-11-30T16:00:00: %s\n", gmtAfterPst, result.latin1() );
+ printf( "Latitude 89 should be valid: %svalid\n", KTimezone::isValidLatitude(89.0) ? "" : "in");
+ printf( "Latitude 91 should be invalid: %svalid\n", KTimezone::isValidLatitude(91.0) ? "" : "in");
+ printf( "Longitude 179 should be valid: %svalid\n", KTimezone::isValidLongitude(179.0) ? "" : "in");
+ printf( "Longitude 181 should be valid: %svalid\n", KTimezone::isValidLongitude(181.0) ? "" : "in");
+ return 0;
+ }
+
+ if ((argc==2) && (strcmp(argv[1], "all")==0))
+ {
+ KTimezones timezones;
+ KTimezones::ZoneMap allZones = timezones.allZones();
+ for ( KTimezones::ZoneMap::const_iterator it = allZones.begin(), end = allZones.end(); it != end; ++it )
+ printf( "%s\n", it.key().latin1() );
+ }
+
+ printf( "Usage: ktimezonestest [local|all]!\n" );
+ return 1;
+}
diff --git a/kdecore/tests/kuniqueapptest.cpp b/kdecore/tests/kuniqueapptest.cpp
new file mode 100644
index 000000000..699c99539
--- /dev/null
+++ b/kdecore/tests/kuniqueapptest.cpp
@@ -0,0 +1,59 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kuniqueapplication.h"
+#include "kglobalsettings.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+
+class TestApp : public KUniqueApplication
+{
+public:
+ TestApp() : KUniqueApplication("TestApp") { }
+ virtual int newInstance( );
+};
+
+
+int
+TestApp::newInstance( )
+{
+ qWarning("NewInstance");
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ KAboutData about("kuniqueapptest", "kuniqueapptest", "version");
+ KCmdLineArgs::init(argc, argv, &about);
+ KUniqueApplication::addCmdLineOptions();
+
+ if (!TestApp::start())
+ {
+ exit(0);
+ }
+ TestApp a;
+
+ printf("Running.\n");
+ kapp->exec();
+ printf("Terminating.\n");
+}
diff --git a/kdecore/tests/kurltest.cpp b/kdecore/tests/kurltest.cpp
new file mode 100644
index 000000000..60e8ace09
--- /dev/null
+++ b/kdecore/tests/kurltest.cpp
@@ -0,0 +1,1124 @@
+#include <config.h>
+
+#include <kurl.h>
+#include <stdio.h>
+#include <kapplication.h>
+#include <stdlib.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kcharsets.h>
+#include <qtextcodec.h>
+#include <qdatastream.h>
+#include <assert.h>
+#include <kcmdlineargs.h>
+
+static bool check(QString txt, QString a, QString b)
+{
+ if (a.isEmpty())
+ a = QString::null;
+ if (b.isEmpty())
+ b = QString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+void testAdjustPath()
+{
+ KURL url1("file:///home/kde/");
+ url1.adjustPath(0);
+ check( "adjustPath(0)", url1.path(), "/home/kde/" );
+ url1.adjustPath(-1);
+ check( "adjustPath(-1) removes last slash", url1.path(), "/home/kde" );
+ url1.adjustPath(-1);
+ check( "adjustPath(-1) again", url1.path(), "/home/kde" );
+ url1.adjustPath(1);
+ check( "adjustPath(1)", url1.path(), "/home/kde/" );
+
+ KURL url2("file:///home/kde//");
+ url2.adjustPath(0);
+ check( "adjustPath(0)", url2.path(), "/home/kde//" );
+ url2.adjustPath(-1);
+ check( "adjustPath(-1) removes all trailing slashes", url2.path(), "/home/kde" );
+ url2.adjustPath(1);
+ check( "adjustPath(1)", url2.path(), "/home/kde/" );
+
+ KURL ftpurl1("ftp://ftp.kde.org/");
+ ftpurl1.adjustPath(0);
+ check( "adjustPath(0)", ftpurl1.path(), "/" );
+ ftpurl1.adjustPath(-1);
+ check( "adjustPath(-1) preserves last slash", ftpurl1.path(), "/" );
+
+ KURL ftpurl2("ftp://ftp.kde.org///");
+ ftpurl2.adjustPath(0);
+ check( "adjustPath(0)", ftpurl2.path(), "///" );
+ ftpurl2.adjustPath(-1);
+ check( "adjustPath(-1) removes all but last slash", ftpurl2.path(), "/" );
+ ftpurl2.adjustPath(1);
+ check( "adjustPath(1)", ftpurl2.path(), "/" );
+
+ // Equivalent tests written by the KDirLister maintainer :)
+
+ KURL u3( QCString("ftp://brade@ftp.kde.org///") );
+ u3.adjustPath(-1);
+ check("KURL::adjustPath()", u3.url(), "ftp://brade@ftp.kde.org/");
+
+ KURL u4( QCString("ftp://brade@ftp.kde.org/kde///") );
+ u4.adjustPath(-1);
+ check("KURL::adjustPath()", u4.url(), "ftp://brade@ftp.kde.org/kde");
+
+ // applying adjustPath(-1) twice should not yield two different urls
+ // (follows from the above test)
+ KURL u5 = u4;
+ u5.adjustPath(-1);
+ check("KURL::adjustPath()", u5.url(), u4.url());
+}
+
+int main(int argc, char *argv[])
+{
+ KApplication::disableAutoDcopRegistration();
+ KCmdLineArgs::init( argc, argv, "kurltest", 0, 0, 0, 0 );
+ KApplication app( false, false );
+
+ KURL::List lst;
+
+ KURL emptyURL;
+ check( "KURL::isMalformed()", emptyURL.isMalformed() ? "TRUE":"FALSE", "TRUE");
+ check( "KURL::isValid()", emptyURL.isValid() ? "TRUE":"FALSE", "FALSE");
+ check( "KURL::isEmpty()", emptyURL.isEmpty() ? "TRUE":"FALSE", "TRUE");
+ check( "prettyURL()", emptyURL.prettyURL(), "");
+ check( "isLocalFile()", emptyURL.isLocalFile()?"TRUE":"FALSE", "FALSE" );
+
+ emptyURL = "";
+ check( "KURL::isMalformed()", emptyURL.isMalformed() ? "TRUE":"FALSE", "TRUE");
+ check( "KURL::isValid()", emptyURL.isValid() ? "TRUE":"FALSE", "FALSE");
+ check( "KURL::isEmpty()", emptyURL.isEmpty() ? "TRUE":"FALSE", "TRUE");
+
+ KURL fileURL = "file:/";
+ check( "KURL::isEmpty()", fileURL.isEmpty() ? "TRUE":"FALSE", "FALSE");
+
+ fileURL = "file:///";
+ check( "KURL::isEmpty()", fileURL.isEmpty() ? "TRUE":"FALSE", "FALSE");
+
+ KURL baseURL ("hTTp://www.foo.bar:80" );
+ check( "KURL::isValid()", baseURL.isValid() ? "TRUE":"FALSE", "TRUE");
+ check( "KURL::protocol()", baseURL.protocol(), "http"); // lowercase
+ KURL url1 ( baseURL, "//www1.foo.bar" );
+ check( "KURL::host()", url1.host(), "www1.foo.bar");
+ check( "KURL::url()", url1.url(), "http://www1.foo.bar");
+
+ baseURL = "http://www.Abc.de";
+ check( "KURL::host() is lowercase", baseURL.host(), "www.abc.de");
+ baseURL = "donkey://Abc/DE";
+ check( "KURL::host() is lowercase", baseURL.host(), "abc");
+
+ baseURL = "http://www.foo.bar";
+ KURL rel_url( baseURL, "/top//test/../test1/file.html" );
+ check( "KURL::url()", rel_url.url(), "http://www.foo.bar/top//test1/file.html" );
+
+
+ baseURL = "http://www.foo.bar/top//test2/file2.html";
+ check( "KURL::url()", baseURL.url(), "http://www.foo.bar/top//test2/file2.html" );
+
+ baseURL = "file:/usr/local/src/kde2/////kdelibs/kio";
+ check( "KURL::url()", baseURL.url(), "file:///usr/local/src/kde2/////kdelibs/kio" );
+
+ baseURL = "http://www.foo.bar";
+ KURL rel_url2( baseURL, "mailto:bastian@kde.org" );
+ check( "KURL::url()", rel_url2.url(), "mailto:bastian@kde.org" );
+
+ baseURL = "mailto:bastian@kde.org?subject=hello";
+ check( "KURL::url()", baseURL.url(), "mailto:bastian@kde.org?subject=hello" );
+
+ baseURL = "file:/usr/local/src/kde2/kdelibs/kio/";
+ KURL url2( baseURL, "../../////kdebase/konqueror" );
+ check( "KURL::url()", url2.url(), "file:///usr/local/src/kde2/////kdebase/konqueror" );
+
+ QString u1 = "file:/home/dfaure/my#myref";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my#myref");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "no");
+ check("KURL::htmlRef()", url1.htmlRef(), "myref");
+ check("KURL::upURL()", url1.upURL().url(), "file:///home/dfaure/");
+
+ u1 = "file:/home/dfaure/my#%2f";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my#%2f");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "no");
+ check("KURL::encodedHtmlRef()", url1.ref(), "%2f");
+ check("KURL::htmlRef()", url1.htmlRef(), "/");
+
+ url1 = KURL(url1, "#%6a");
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my#%6a");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "no");
+ check("KURL::encodedHtmlRef()", url1.ref(), "%6a");
+ check("KURL::htmlRef()", url1.htmlRef(), "j");
+
+ KURL dxOffEagle( KURL("http://something/other.html"), "newpage.html?[{\"foo: bar\"}]" );
+ check("isValid", dxOffEagle.isValid() ? "OK" : "KO", "OK");
+ check("url", dxOffEagle.url(), QString("http://something/newpage.html?[{\"foo:%20bar\"}]") );
+
+ KURL javascript( KURL("javascript:window.location+\"__flashplugin_unique__\"") );
+ check("isValid", javascript.isValid() ? "OK" : "KO", "OK");
+ check("url", javascript.url(), QString("javascript:window.location+\"__flashplugin_unique__\"") );
+
+
+ u1 = "file:///home/dfaure/my#myref";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my#myref");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "no");
+ check("KURL::htmlRef()", url1.htmlRef(), "myref");
+ check("KURL::upURL()", url1.upURL().url(), "file:///home/dfaure/");
+
+ url1 = "gg:www.kde.org";
+ check("KURL::isValid()", url1.isValid()?"TRUE":"FALSE", "TRUE" );
+
+ url1= "KDE";
+ check("KURL::isValid()", url1.isValid()?"TRUE":"FALSE", "FALSE" );
+
+ url1= "$HOME/.kde/share/config";
+ check("KURL::isValid()", url1.isValid()?"TRUE":"FALSE", "FALSE" );
+
+ u1 = "file:/opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject::connect";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject::connect");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::htmlRef()", url1.htmlRef(), "QObject::connect");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "no");
+ check("KURL::upURL()", url1.upURL().url(), "file:///opt/kde2/qt2/doc/html/");
+
+ url1 = KURL( QCString( "http://www.kde.org/foo.cgi?foo=bar" ) );
+ check("query", url1.query(), "?foo=bar" );
+ url1.setQuery( "toto=titi&kde=rocks" );
+ check("query", url1.query(), "?toto=titi&kde=rocks" );
+ url1.setQuery( "?kde=rocks&a=b" );
+ check("query", url1.query(), "?kde=rocks&a=b" );
+ url1.setQuery( "?" );
+ check("setQuery(\"?\") -> query", url1.query(), "?" );
+ url1.setQuery( "" );
+ check("setQuery(\"\") -> query", url1.query(), "?" );
+ url1.setQuery( QString::null );
+ check("setQuery(QString::null) -> query", url1.query(), QString::null );
+
+ u1 = "file:///opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject::connect";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject::connect");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::htmlRef()", url1.htmlRef(), "QObject::connect");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "no");
+ check("KURL::upURL()", url1.upURL().url(), "file:///opt/kde2/qt2/doc/html/");
+
+ u1 = "file:/opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject:connect";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject:connect");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::htmlRef()", url1.htmlRef(), "QObject:connect");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "no");
+ check("KURL::upURL()", url1.upURL().url(), "file:///opt/kde2/qt2/doc/html/");
+
+ u1 = "file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/#myref";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/#myref");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::isLocalFile()", url1.isLocalFile() ? "yes" : "no", "no"); // Not strictly local!
+ //check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "yes");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "yes");
+ //check("KURL::htmlRef()", url1.htmlRef(), "myref");
+ check("KURL::upURL()", url1.upURL().url(), "file:///home/dfaure/");
+
+ u1 = "error:/?error=14&errText=Unknown%20host%20asdfu.adgi.sdfgoi#http://asdfu.adgi.sdfgoi";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "error:/?error=14&errText=Unknown%20host%20asdfu.adgi.sdfgoi#http://asdfu.adgi.sdfgoi");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "yes");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::isLocalFile()", url1.isLocalFile() ? "yes" : "no", "no");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "no");
+ //check("KURL::htmlRef()", url1.htmlRef(), "myref");
+
+ u1 = "file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "no");
+ check("KURL::htmlRef()", url1.htmlRef(), "");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "yes");
+ check("KURL::upURL()", url1.upURL().url(), "file:///home/dfaure/");
+
+ u1 = "file:///home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "no");
+ check("KURL::htmlRef()", url1.htmlRef(), "");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "yes");
+ check("KURL::upURL()", url1.upURL().url(), "file:///home/dfaure/");
+
+#if 0
+// This URL is broken, '#' should be escaped.
+ u1 = "file:/home/dfaure/cdrdao-1.1.5/dao/#CdrDriver.cc#";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/cdrdao-1.1.5/dao/#CdrDriver.cc#");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "no");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "no");
+ check("KURL::htmlRef()", url1.htmlRef(), "");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "yes");
+ check("KURL::prettyURL()", url1.upURL().url(), "file:///home/dfaure/cdrdao-1.1.5/dao/#CdrDriver.cc#");
+#endif
+
+ u1 = "file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/README";
+ url1 = u1;
+ check("KURL::url()", url1.url(), "file:///home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/README");
+ check("KURL::hasRef()", url1.hasRef() ? "yes" : "no", "yes");
+ check("KURL::hasHTMLRef()", url1.hasHTMLRef() ? "yes" : "no", "no");
+ check("KURL::htmlRef()", url1.htmlRef(), "");
+ check("KURL::hasSubURL()", url1.hasSubURL() ? "yes" : "no", "yes");
+ check("KURL::upURL()", url1.upURL().url(), "file:///home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/");
+
+ KURL notPretty("http://ferret.lmh.ox.ac.uk/%7Ekdecvs/");
+ check("KURL::prettyURL()", notPretty.prettyURL(), "http://ferret.lmh.ox.ac.uk/~kdecvs/");
+ KURL notPretty2("file:/home/test/directory%20with%20spaces");
+ check("KURL::prettyURL()", notPretty2.prettyURL(), "file:///home/test/directory with spaces");
+ KURL notPretty3("fish://foo/%23README%23");
+ check("KURL::prettyURL()", notPretty3.prettyURL(), "fish://foo/%23README%23");
+ KURL url15581("http://alain.knaff.linux.lu/bug-reports/kde/spaces in url.html");
+ check("KURL::prettyURL()", url15581.prettyURL(), "http://alain.knaff.linux.lu/bug-reports/kde/spaces in url.html");
+ check("KURL::url()", url15581.url(), "http://alain.knaff.linux.lu/bug-reports/kde/spaces%20in%20url.html");
+ KURL url15582("http://alain.knaff.linux.lu/bug-reports/kde/percentage%in%url.html");
+ check("KURL::prettyURL()", url15582.prettyURL(), "http://alain.knaff.linux.lu/bug-reports/kde/percentage%in%url.html");
+ check("KURL::url()", url15582.url(), "http://alain.knaff.linux.lu/bug-reports/kde/percentage%25in%25url.html");
+
+ KURL longUserName("http://thisisaverylongusername@foobar.com/");
+ check("KURL::prettyURL()", longUserName.prettyURL(), "http://thisisaverylongusername@foobar.com/");
+ check("KURL(KURL::prettyURL())", KURL(longUserName.prettyURL()).url(), "http://thisisaverylongusername@foobar.com/");
+
+ KURL whitespaceInUser("http://google.com%20%20%20@foobar.com/");
+ check("KURL::prettyURL()", whitespaceInUser.prettyURL(), "http://google.com%20%20%20@foobar.com/");
+
+ KURL whitespaceInPath("http://www.google.com/foo%20bar/");
+ check("KURL::prettyURL()", whitespaceInPath.prettyURL(), "http://www.google.com/foo bar/");
+
+ KURL whitespaceInPath2("http://www.google.com/foo%20%20%20%20%20%20%20bar/");
+ check("KURL::prettyURL()", whitespaceInPath2.prettyURL(),
+ "http://www.google.com/foo%20%20%20%20%20%20 bar/");
+
+ KURL carsten;
+ carsten.setPath("/home/gis/src/kde/kdelibs/kfile/.#kfiledetailview.cpp.1.18");
+ check("KURL::path()", carsten.path(), "/home/gis/src/kde/kdelibs/kfile/.#kfiledetailview.cpp.1.18");
+
+ KURL charles;
+ charles.setPath( "/home/charles/foo%20moo" );
+ check("KURL::path()", charles.path(), "/home/charles/foo%20moo");
+ KURL charles2("file:/home/charles/foo%20moo");
+ check("KURL::path()", charles2.path(), "/home/charles/foo moo");
+
+ KURL udir;
+ printf("\n* Empty URL\n");
+ check("KURL::url()", udir.url(), QString::null);
+ check("KURL::isEmpty()", udir.isEmpty() ? "ok" : "ko", "ok");
+ check("KURL::isValid()", udir.isValid() ? "ok" : "ko", "ko");
+ udir = udir.upURL();
+ check("KURL::upURL()", udir.upURL().isEmpty() ? "ok" : "ko", "ok");
+
+ udir.setPath("/home/dfaure/file.txt");
+ printf("\n* URL is %s\n",udir.url().ascii());
+ check("KURL::path()", udir.path(), "/home/dfaure/file.txt");
+ check("KURL::url()", udir.url(), "file:///home/dfaure/file.txt");
+ check("KURL::directory(false,false)", udir.directory(false,false), "/home/dfaure/");
+ check("KURL::directory(true,false)", udir.directory(true,false), "/home/dfaure");
+
+ KURL u2( QCString("/home/dfaure/") );
+ printf("\n* URL is %s\n",u2.url().ascii());
+ // not ignoring trailing slash
+ check("KURL::directory(false,false)", u2.directory(false,false), "/home/dfaure/");
+ check("KURL::directory(true,false)", u2.directory(true,false), "/home/dfaure");
+ // ignoring trailing slash
+ check("KURL::directory(false,true)", u2.directory(false,true), "/home/");
+ check("KURL::directory(true,true)", u2.directory(true,true), "/home");
+
+ // cleanPath() tests (before cd() since cd uses that)
+ u2.cleanPath();
+ check("cleanPath(false)", u2.url(), "file:///home/dfaure/");
+ u2.addPath( "/..//foo" );
+ check("addPath", u2.url(), "file:///home/dfaure/..//foo");
+ u2.cleanPath(false);
+ check("cleanPath()", u2.url(), "file:///home//foo");
+ u2.cleanPath(true);
+ check("cleanPath()", u2.url(), "file:///home/foo");
+
+ u2.cd("..");
+ check("KURL::cd(\"..\")", u2.url(), "file:///home");
+ u2.cd("thomas");
+ check("KURL::cd(\"thomas\")", u2.url(), "file:///home/thomas");
+ u2.cd("../");
+ check("KURL::cd(\"../\")", u2.url(), "file:///home/");
+ u2.cd("/opt/kde/bin/");
+ check("KURL::cd(\"/opt/kde/bin/\")", u2.url(), "file:///opt/kde/bin/");
+ u2 = "ftp://ftp.kde.org/";
+ printf("\n* URL is %s\n",u2.url().ascii());
+ u2.cd("pub");
+ check("KURL::cd(\"pub\")", u2.url(), "ftp://ftp.kde.org/pub");
+ u2 = u2.upURL();
+ check("KURL::upURL()", u2.url(), "ftp://ftp.kde.org/");
+ u2 = u1;
+ printf("\n* URL is %s\n",u2.url().ascii());
+ // setFileName
+ u2.setFileName( "myfile.txt" );
+ check("KURL::setFileName()", u2.url(), "file:///home/dfaure/myfile.txt");
+ u2.setFileName( "myotherfile.txt" );
+ check("KURL::setFileName()", u2.url(), "file:///home/dfaure/myotherfile.txt");
+ // more tricky, renaming a directory (kpropsdlg.cc, line ~ 238)
+ QString tmpurl = "file:/home/dfaure/myolddir/";
+ if ( tmpurl.at(tmpurl.length() - 1) == '/')
+ // It's a directory, so strip the trailing slash first
+ tmpurl.truncate( tmpurl.length() - 1);
+ KURL newUrl = tmpurl;
+ newUrl.setFileName( "mynewdir" );
+ check("KURL::setFileName() special", newUrl.url(), "file:///home/dfaure/mynewdir");
+ // addPath tests
+ newUrl.addPath( "subdir" );
+ check("KURL::addPath(\"subdir\")", newUrl.url(), "file:///home/dfaure/mynewdir/subdir");
+ newUrl.addPath( "/foo/" );
+ check("KURL::addPath(\"/foo/\")", newUrl.url(), "file:///home/dfaure/mynewdir/subdir/foo/");
+ u2 = "http://www.kde.org"; // no path
+ u2.addPath( "subdir" );
+ check("KURL::addPath(\"subdir\")", u2.url(), "http://www.kde.org/subdir");
+ u2.addPath( "" );
+ check("KURL::addPath(\"subdir\")", u2.url(), "http://www.kde.org/subdir"); // unchanged
+
+ // even more tricky
+ u2 = "print:/specials/Print%20To%20File%20(PDF%2FAcrobat)";
+ printf("\n* URL is %s\n",u2.url().ascii());
+ check("KURL::path()", u2.path(), "/specials/Print To File (PDF/Acrobat)");
+ check("KURL::fileName()", u2.fileName(), "Print To File (PDF/Acrobat)");
+ u2.setFileName( "" );
+ check("KURL::setFileName()", u2.url(), "print:/specials/");
+
+ u2 = "file:/specials/Print";
+ printf("\n* URL is %s\n",u2.url().ascii());
+ check("KURL::path()", u2.path(), "/specials/Print");
+ check("KURL::fileName()", u2.fileName(), "Print");
+ u2.setFileName( "" );
+ check("KURL::setFileName()", u2.url(), "file:///specials/");
+
+ const char * u6 = "ftp://host/dir1/dir2/myfile.txt";
+ printf("\n* URL is %s\n",u6);
+ check("KURL::hasSubURL()", KURL(u6).hasSubURL() ? "yes" : "no", "no");
+ lst.clear();
+ lst = KURL::split( KURL(u6) );
+ check("KURL::split()", lst.count()==1 ? "1" : "error", "1");
+ check("KURL::split()", lst.first().url(), "ftp://host/dir1/dir2/myfile.txt");
+ // cdUp code
+ KURL lastUrl = lst.last();
+ QString dir = lastUrl.directory( true, true );
+ check( "KURL::directory(true,true)", dir, "/dir1/dir2");
+
+ /// Comparisons
+ QString ucmp1 = "ftp://ftp.de.kde.org/dir";
+ QString ucmp2 = "ftp://ftp.de.kde.org/dir/";
+ check("urlcmp(only slash difference)", urlcmp(ucmp1,ucmp2)?"ko":"ok","ok");
+ check("urlcmp(only slash difference, ignore_trailing)", urlcmp(ucmp1,ucmp2,true,false)?"ok":"ko","ok");
+ QString ucmp3 = "ftp://ftp.de.kde.org/dir/#";
+ check("urlcmp(only hash difference)", urlcmp(ucmp2,ucmp3)?"ko":"ok","ok");
+ check("urlcmp(only hash difference, ignore_ref)", urlcmp(ucmp2,ucmp3,false,true)?"ok":"ko","ok");
+ check("urlcmp(slash and hash difference, ignore_trailing, ignore_ref)", urlcmp(ucmp2,ucmp3,true,true)?"ok":"ko","ok");
+ check("urlcmp(empty, empty)", urlcmp("","",false,true)?"ok":"ko","ok");
+ check("urlcmp(empty, empty)", urlcmp("","")?"ok":"ko","ok");
+ check("urlcmp(empty, not empty)", urlcmp("",ucmp1)?"ok":"ko","ko");
+ check("urlcmp(empty, not empty)", urlcmp("",ucmp1,false,true)?"ok":"ko","ko");
+ check("urlcmp(malformed, not empty)", urlcmp("file",ucmp1)?"ok":"ko","ko");
+ check("urlcmp(malformed, not empty)", urlcmp("file",ucmp1,false,true)?"ok":"ko","ko");
+
+ KURL ftpUrl ( "ftp://ftp.de.kde.org" );
+ printf("\n* URL is %s\n",ftpUrl.url().latin1());
+ check("KURL::path()", ftpUrl.path(), QString::null);
+ ftpUrl = "ftp://ftp.de.kde.org/";
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp.de.kde.org/host/subdir/") ? "yes" : "no", "yes");
+ ftpUrl = "ftp://ftp/host/subdir/";
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir/") ? "yes" : "no", "yes");
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir") ? "yes" : "no", "yes");
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdi") ? "yes" : "no", "no");
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir/blah/") ? "yes" : "no", "yes");
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/blah/subdir") ? "yes" : "no", "no");
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "file:////ftp/host/subdir/") ? "yes" : "no", "no");
+ check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir/subsub") ? "yes" : "no", "yes");
+
+ // WABA: The following tests are to test the handling of relative URLs as
+ // found on web-pages.
+
+ KURL waba1( "http://www.website.com/directory/?hello#ref" );
+ {
+ KURL waba2( waba1, "relative.html");
+ check("http: Relative URL, single file", waba2.url(), "http://www.website.com/directory/relative.html");
+ }
+ {
+ KURL waba2( waba1, "../relative.html");
+ check("http: Relative URL, single file, directory up", waba2.url(), "http://www.website.com/relative.html");
+ }
+ {
+ KURL waba2( waba1, "down/relative.html");
+ check("http: Relative URL, single file, directory down", waba2.url(), "http://www.website.com/directory/down/relative.html");
+ }
+ {
+ KURL waba2( waba1, "/down/relative.html");
+ check("http: Relative URL, full path", waba2.url(), "http://www.website.com/down/relative.html");
+ }
+ {
+ KURL waba2( waba1, "//www.kde.org/relative.html");
+ check("http: Relative URL, with host", waba2.url(), "http://www.kde.org/relative.html");
+ }
+ {
+ KURL waba2( waba1, "relative.html?query=test&name=harry");
+ check("http: Relative URL, with query", waba2.url(), "http://www.website.com/directory/relative.html?query=test&name=harry");
+ waba2.removeQueryItem("query");
+ check("http: Removing query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry");
+ waba2.addQueryItem("age", "18");
+ check("http: Adding query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry&age=18");
+ waba2.addQueryItem("age", "21");
+ check("http: Adding query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry&age=18&age=21");
+ waba2.addQueryItem("fullname", "Harry Potter");
+ check("http: Adding query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry&age=18&age=21&fullname=Harry%20Potter");
+ }
+ {
+ KURL waba2( waba1, "?query=test&name=harry");
+ check("http: Relative URL, with query and no filename", waba2.url(), "http://www.website.com/directory/?query=test&name=harry");
+ }
+ {
+ KURL waba2( waba1, "relative.html#with_reference");
+ check("http: Relative URL, with reference", waba2.url(), "http://www.website.com/directory/relative.html#with_reference");
+ }
+ {
+ KURL waba2( waba1, "#");
+ check("http: Relative URL, with empty reference", waba2.url(), "http://www.website.com/directory/?hello#");
+ }
+ {
+ KURL waba2( waba1, "");
+ check("http: Empty relative URL", waba2.url(), "http://www.website.com/directory/?hello#ref");
+ }
+ {
+ KURL base( "http://faure@www.kde.org" ); // no path
+ KURL waba2( base, "filename.html");
+ check("http: Relative URL, orig URL had no path", waba2.url(), "http://faure@www.kde.org/filename.html");
+ }
+ {
+ KURL base( "http://faure:pass@www.kde.org:81?query" );
+ KURL rel1( base, "http://www.kde.org/bleh/"); // same host
+ check("http: Relative URL, orig URL had username", rel1.url(), "http://faure:pass@www.kde.org/bleh/");
+ KURL rel2( base, "http://www.yahoo.org"); // different host
+ check("http: Relative URL, orig URL had username", rel2.url(), "http://www.yahoo.org");
+ }
+
+ waba1 = "http://www.website.com/directory/filename?bla#blub";
+ {
+ KURL waba2( waba1, "relative.html");
+ check("http: Relative URL, single file", waba2.url(), "http://www.website.com/directory/relative.html");
+ }
+ {
+ KURL waba2( waba1, "../relative.html");
+ check("http: Relative URL, single file, directory up", waba2.url(), "http://www.website.com/relative.html");
+ }
+ {
+ KURL waba2( waba1, "down/relative.html");
+ check("http: Relative URL, single file, directory down", waba2.url(), "http://www.website.com/directory/down/relative.html");
+ }
+ {
+ KURL waba2( waba1, "/down/relative.html");
+ check("http: Relative URL, full path", waba2.url(), "http://www.website.com/down/relative.html");
+ }
+ {
+ KURL waba2( waba1, "relative.html?query=test&name=harry");
+ check("http: Relative URL, with query", waba2.url(), "http://www.website.com/directory/relative.html?query=test&name=harry");
+ }
+ {
+ KURL waba2( waba1, "?query=test&name=harry");
+ check("http: Relative URL, with query and no filename", waba2.url(), "http://www.website.com/directory/filename?query=test&name=harry");
+ }
+ {
+ KURL waba2( waba1, "relative.html#with_reference");
+ check("http: Relative URL, with reference", waba2.url(), "http://www.website.com/directory/relative.html#with_reference");
+ }
+ {
+ KURL waba2( waba1, "http:/relative.html"); // "rfc 1606 loophole"
+ check("http: Strange relative URL", waba2.url(), "http://www.website.com/relative.html");
+ }
+ waba1.setUser("waldo");
+ check("http: Set user", waba1.url(), "http://waldo@www.website.com/directory/filename?bla#blub");
+ waba1.setUser("waldo/bastian");
+ check("http: Set user with slash in it", waba1.url(), "http://waldo%2Fbastian@www.website.com/directory/filename?bla#blub");
+ waba1.setRef( QString::null );
+ waba1.setPass( "pass" );
+ waba1.setDirectory( "/foo" );
+ waba1.setProtocol( "https" );
+ waba1.setHost( "web.com" );
+ waba1.setPort( 881 );
+ check("http: setRef/setPass/setDirectory/setHost/setPort", waba1.url(), "https://waldo%2Fbastian:pass@web.com:881/foo/?bla");
+ waba1.setDirectory( "/foo/" );
+ check("http: setDirectory #2", waba1.url(), "https://waldo%2Fbastian:pass@web.com:881/foo/?bla");
+
+ // Empty queries should be preserved!
+ waba1 = "http://www.kde.org/cgi/test.cgi?";
+ check("http: URL with empty query string", waba1.url(),
+ "http://www.kde.org/cgi/test.cgi?");
+
+ // Empty references should be preserved
+ waba1 = "http://www.kde.org/cgi/test.cgi#";
+ check("http: URL with empty reference string", waba1.url(),
+ "http://www.kde.org/cgi/test.cgi#");
+ check("hasRef()", waba1.hasRef()?"true":"false","true");
+ check("hasHTMLRef()", waba1.hasHTMLRef()?"true":"false","true");
+ check("encodedHtmlRef()", waba1.encodedHtmlRef(),QString::null);
+
+ // URLs who forgot to encode spaces in the query.
+ waba1 = "http://www.kde.org/cgi/test.cgi?hello=My Value";
+ check("http: URL with incorrect encoded query", waba1.url(),
+ "http://www.kde.org/cgi/test.cgi?hello=My%20Value");
+
+ // URL with ':' in query (':' should NOT be encoded!)
+ waba1.setQuery("hello:My Value");
+ check("http: URL with ':' in query", waba1.url(),
+ "http://www.kde.org/cgi/test.cgi?hello:My%20Value");
+ check("upURL() removes query", waba1.upURL().url(),
+ "http://www.kde.org/cgi/test.cgi");
+
+ // URLs who forgot to encode spaces in the query.
+ waba1 = "http://www.kde.org/cgi/test.cgi?hello=My Value+20";
+ check("http: URL with incorrect encoded query", waba1.url(),
+ "http://www.kde.org/cgi/test.cgi?hello=My%20Value+20");
+
+ // Urls without path (BR21387)
+ waba1 = "http://meine.db24.de?link=home_c_login_login";
+ check("http: URL with empty path string", waba1.url(),
+ "http://meine.db24.de?link=home_c_login_login");
+ check("http: URL with empty path string path", waba1.path(),
+ "");
+ check("http: URL with empty path string query", waba1.query(),
+ "?link=home_c_login_login");
+
+ waba1 = "http://a:389?b=c";
+ check( "http: URL with port, query, and empty path; url", waba1.url(), "http://a:389?b=c" );
+ check( "http: URL with port, query, and empty path; host", waba1.host(), "a" );
+ check( "http: URL with port, query, and empty path; port", QString::number( waba1.port() ), "389" );
+ check( "http: URL with port, query, and empty path; path", waba1.path(), "" );
+ check( "http: URL with port, query, and empty path; query", waba1.query(), "?b=c" );
+
+ // Urls without path (BR21387)
+ waba1 = "http://meine.db24.de#link=home_c_login_login";
+ check("http: URL with empty path string", waba1.url(),
+ "http://meine.db24.de#link=home_c_login_login");
+ check("http: URL with empty path string path", waba1.path(),
+ "");
+
+ waba1 = "http://www.meinestadt.de&url_plain=http";
+ check("http: URL with empty path string", waba1.host(),
+ "www.meinestadt.de&url_plain=http");
+ check("http: URL with empty path string", waba1.htmlURL(),
+ "http://www.meinestadt.de&amp;url_plain=http");
+
+ check("http: URL with empty path string", waba1.path(),
+ "");
+
+ waba1 = "http://a:389#b=c";
+ check( "http: URL with port, ref, and empty path; url", waba1.url(), "http://a:389#b=c" );
+ check( "http: URL with port, ref, and empty path; host", waba1.host(), "a" );
+ check( "http: URL with port, ref, and empty path; port", QString::number( waba1.port() ), "389" );
+ check( "http: URL with port, ref, and empty path; path", waba1.path(), "" );
+ check( "http: URL with port, ref, and empty path; ref", waba1.ref(), "b=c" );
+ check( "http: URL with port, ref, and empty path; query", waba1.query(), "" );
+
+ // IPV6
+ waba1 = "http://[::FFFF:129.144.52.38]:81/index.html";
+ check("http: IPV6 host", waba1.host(),
+ "::ffff:129.144.52.38");
+ check("http: IPV6 port", QString("%1").arg(waba1.port()),
+ "81");
+
+ // IPV6
+ waba1 = "http://waba:pass@[::FFFF:129.144.52.38]:81/index.html";
+ check("http: IPV6 host", waba1.host(),
+ "::ffff:129.144.52.38");
+ check("http: IPV6 host", waba1.user(),
+ "waba");
+ check("http: IPV6 host", waba1.pass(),
+ "pass");
+ check("http: IPV6 port", QString("%1").arg(waba1.port()),
+ "81");
+
+ // IPV6
+ waba1 = "http://www.kde.org/cgi/test.cgi";
+ waba1.setHost("::ffff:129.144.52.38");
+ check("http: IPV6 host", waba1.url(),
+ "http://[::ffff:129.144.52.38]/cgi/test.cgi");
+ waba1 = "http://[::ffff:129.144.52.38]/cgi/test.cgi";
+ assert( waba1.isValid() );
+
+ // IPV6 without path
+ waba1 = "http://[::ffff:129.144.52.38]?query";
+ assert( waba1.isValid() );
+ check("http: IPV6 without path", waba1.url(),
+ "http://[::ffff:129.144.52.38]?query");
+ check("http: IPV6 without path; query", waba1.query(),
+ "?query");
+ waba1 = "http://[::ffff:129.144.52.38]#ref";
+ assert( waba1.isValid() );
+ check("http: IPV6 without path", waba1.url(),
+ "http://[::ffff:129.144.52.38]#ref");
+ check("http: IPV6 without path; ref", waba1.ref(),
+ "ref");
+ // IPV6 without path but with a port
+ waba1 = "http://[::ffff:129.144.52.38]:81?query";
+ assert( waba1.isValid() );
+ check("http: IPV6 without path", waba1.url(),
+ "http://[::ffff:129.144.52.38]:81?query");
+ check("http: IPV6 without path; port", QString::number( waba1.port() ), "81" );
+ check("http: IPV6 without path; query", waba1.query(), "?query");
+ waba1 = "http://[::ffff:129.144.52.38]:81#ref";
+ assert( waba1.isValid() );
+ check("http: IPV6 without path", waba1.url(),
+ "http://[::ffff:129.144.52.38]:81#ref");
+ check("http: IPV6 without path; port", QString::number( waba1.port() ), "81" );
+ check("http: IPV6 without path; ref", waba1.ref(), "ref");
+
+ // Streaming operators
+ KURL origURL( "http://www.website.com/directory/?#ref" );
+ waba1 = "http://[::ffff:129.144.52.38]:81?query";
+ QByteArray buffer;
+ {
+ QDataStream stream( buffer, IO_WriteOnly );
+ stream << origURL
+ << KURL( "file:" ) // an invalid one
+ << waba1; // the IPv6 one
+ }
+ {
+ QDataStream stream( buffer, IO_ReadOnly );
+ KURL restoredURL;
+ stream >> restoredURL;
+ check( "Streaming valid URL", origURL.url(), restoredURL.url() );
+ stream >> restoredURL;
+ check( "Streaming invalid URL", restoredURL.isValid()?"valid":"malformed", "malformed" );
+ check( "Streaming invalid URL", restoredURL.url(), "file:" );
+ stream >> restoredURL;
+ check( "Streaming ipv6 URL with query", restoredURL.url(), waba1.url() );
+ }
+
+ // Broken stuff
+ waba1 = "file:a";
+ check("Broken stuff #1 path", waba1.path(), "a");
+ check("Broken stuff #1 fileName(false)", waba1.fileName(false), "a");
+ check("Broken stuff #1 fileName(true)", waba1.fileName(true), "a");
+ check("Broken stuff #1 directory(false, false)", waba1.directory(false, false), "");
+ check("Broken stuff #1 directory(true, false)", waba1.directory(true, false), "");
+ check("Broken stuff #1 directory(false, true)", waba1.directory(true, true), "");
+
+ waba1 = "file:a/";
+ check("Broken stuff #2 path", waba1.path(), "a/");
+ check("Broken stuff #2 fileName(false)", waba1.fileName(false), "");
+ check("Broken stuff #2 fileName(true)", waba1.fileName(true), "a");
+ check("Broken stuff #2 directory(false, false)", waba1.directory(false, false), "a/");
+ check("Broken stuff #2 directory(true, false)", waba1.directory(true, false), "a");
+ check("Broken stuff #2 directory(false, true)", waba1.directory(true, true), "");
+
+ waba1 = "file:";
+ check("Broken stuff #3 empty", waba1.isEmpty()?"EMPTY":"NOT", "NOT");
+ check("Broken stuff #3 valid", waba1.isValid()?"VALID":"MALFORMED", "MALFORMED");
+ check("Broken stuff #3 path", waba1.path(), "");
+ check("Broken stuff #3 fileName(false)", waba1.fileName(false), "");
+ check("Broken stuff #3 fileName(true)", waba1.fileName(true), "");
+ check("Broken stuff #3 directory(false, false)", waba1.directory(false, false), "");
+ check("Broken stuff #3 directory(true, false)", waba1.directory(true, false), "");
+ check("Broken stuff #3 directory(false, true)", waba1.directory(true, true), "");
+ KURL broken;
+ broken.setPath( QString::null );
+ check("Broken stuff #4 empty", broken.isEmpty()?"EMPTY":"NOT", "NOT");
+ // It's valid: because isValid refers to parsing, not to what happens afterwards.
+ check("Broken stuff #4 valid", broken.isValid()?"VALID":"MALFORMED", "VALID");
+ check("Broken stuff #4 path", broken.path(), "");
+ broken = "file://"; // just because coolo wondered
+ check("Broken stuff #5 empty", broken.isEmpty()?"EMPTY":"NOT", "NOT");
+ check("Broken stuff #5 valid", broken.isValid()?"VALID":"MALFORMED", "MALFORMED");
+ check("Broken stuff #5 path", broken.path(), "");
+ broken = "file";
+ check("Broken stuff #6 valid", broken.isValid()?"VALID":"MALFORMED", "MALFORMED");
+ broken = "/";
+ check("Broken stuff #7 valid", broken.isValid()?"VALID":"MALFORMED", "VALID");
+ check("Broken stuff #7 path", broken.path(), "/" );
+ check("Broken stuff #7 url", broken.url(), "file:///" );
+ check("Broken stuff #7 file", broken.protocol(), "file" );
+
+ broken = "LABEL=USB_STICK"; // 71430, can we use KURL for this?
+ check("Broken stuff #6 valid", broken.isValid()?"VALID":"MALFORMED", "MALFORMED");
+ check("Broken stuff #6 empty", broken.isEmpty()?"EMPTY":"NOT", "NOT");
+ check("Broken stuff #6 path", broken.path(), "");
+
+#if 0 // BROKEN?
+ // UNC like names
+ KURL unc1("FILE://localhost/home/root");
+ check("UNC, with localhost", unc1.path(), "/home/root");
+ check("UNC, with localhost", unc1.url(), "file:///home/root");
+#endif
+ KURL unc2("file:///home/root");
+ check("UNC, with empty host", unc2.path(), "/home/root");
+ check("UNC, with empty host", unc2.url(), "file:///home/root");
+
+ {
+ KURL unc3("FILE://remotehost/home/root");
+#if 0 // BROKEN?
+ check("UNC, with remote host", unc3.path(), "//remotehost/home/root");
+#endif
+ check("UNC, with remote host", unc3.url(), "file://remotehost/home/root");
+ KURL url2("file://atlas/dfaure");
+ check("KURL::host()", url2.host(), "atlas");
+ check("KURL::path()", url2.path(), "/dfaure");
+ //check("KURL::path()", url3.path(), "//atlas/dfaure"); // says Waba
+ //KURL url3("file:////atlas/dfaure");
+ //check("KURL::path()", url3.path(), "//atlas/dfaure"); // says Waba
+
+ KURL url4(url2, "//remotehost/home/root");
+ check("KURL::host()", url4.host(), "remotehost");
+ check("KURL::path()", url4.path(), "/home/root");
+ }
+
+ KURL umail1 ( "mailto:faure@kde.org" );
+ check("mailto: URL, general form", umail1.protocol(), "mailto");
+ check("mailto: URL, general form", umail1.path(), "faure@kde.org");
+ check("mailto: URL, is relative", KURL::isRelativeURL("mailto:faure@kde.org") ? "true" : "false", "false");
+ KURL umail2 ( "mailto:Faure David <faure@kde.org>" );
+ check("mailto: URL, general form", umail2.protocol(), "mailto");
+ check("mailto: URL, general form", umail2.path(), "Faure David <faure@kde.org>");
+ check("isRelativeURL(\"mailto:faure@kde.org\")", KURL::isRelativeURL("mailto:faure@kde.org") ? "yes" : "no", "no");
+ KURL umail3 ( "mailto:" );
+ check("mailto: invalid URL", umail3.isValid()?"valid":"malformed", "malformed");
+
+ check("man: URL, is relative", KURL::isRelativeURL("man:mmap") ? "true" : "false", "false");
+ check("javascript: URL, is relative", KURL::isRelativeURL("javascript:doSomething()") ? "true" : "false", "false");
+ // more isRelative
+ check("file: URL, is relative", KURL::isRelativeURL("file:///blah") ? "true" : "false", "false");
+ check("/path, is relative", KURL::isRelativeURL("/path") ? "true" : "false", "true"); // arguable, but necessary for KURL( baseURL, "//www1.foo.bar" );
+ check("something, is relative", KURL::isRelativeURL("something") ? "true" : "false", "true");
+ KURL about("about:konqueror");
+ check("about:",about.path(),"konqueror");
+
+ KURL ulong("https://swww.gad.de:443/servlet/CookieAccepted?MAIL=s@gad.de&VER=25901");
+ check("host",ulong.host(),"swww.gad.de");
+ check("path",ulong.path(),"/servlet/CookieAccepted");
+
+#if QT_VERSION < 300
+ qt_set_locale_codec( KGlobal::charsets()->codecForName( "iso-8859-1" ) );
+#else
+ QTextCodec::setCodecForLocale( KGlobal::charsets()->codecForName( "iso-8859-1" ) );
+#endif
+ QString raw = "data:text/html,%00%2540%00";
+ check("data URL: encode-decode of %00", KURL(raw).url(), raw );
+
+ // UTF8 tests
+ KURL uloc("/home/dfaure/konqtests/Matériel");
+ check("url",uloc.url().latin1(),"file:///home/dfaure/konqtests/Mat%E9riel");
+ check("pretty",uloc.prettyURL(),"file:///home/dfaure/konqtests/Matériel"); // escaping the letter would be correct too
+ check("pretty + strip",uloc.prettyURL(0, KURL::StripFileProtocol),"/home/dfaure/konqtests/Matériel"); // escaping the letter would be correct too
+ // 106 is MIB for UTF-8
+ check("UTF8",uloc.url(0, 106),"file:///home/dfaure/konqtests/Mat%C3%A9riel");
+ uloc = KURL("file:///home/dfaure/konqtests/Mat%C3%A9riel", 106);
+ check("UTF8 path", uloc.path(), "/home/dfaure/konqtests/Matériel");
+ check("encodedPathAndQuery", uloc.encodedPathAndQuery(), "/home/dfaure/konqtests/Mat%E9riel");
+
+ // fromPathOrURL tests
+ uloc = KURL::fromPathOrURL( "/home/dfaure/konqtests/Mat%E9riel" );
+ check("fromPathOrURL path", uloc.path(), "/home/dfaure/konqtests/Mat%E9riel");
+ uloc = KURL::fromPathOrURL( "http://www.kde.org" );
+ check("pathOrURL url", uloc.pathOrURL(), uloc.url() );
+ uloc = KURL::fromPathOrURL( "www.kde.org" );
+ check("fromPathOrURL malformed", uloc.isValid()?"valid":"malformed", "malformed");
+ uloc = KURL::fromPathOrURL( "index.html" );
+ check("fromPathOrURL malformed", uloc.isValid()?"valid":"malformed", "malformed");
+ uloc = KURL::fromPathOrURL( "" );
+ check("fromPathOrURL malformed", uloc.isValid()?"valid":"malformed", "malformed");
+
+ // pathOrURL tests
+ uloc = KURL::fromPathOrURL( "/home/dfaure/konqtests/Mat%E9riel" );
+ check("pathOrURL path", uloc.pathOrURL(), uloc.path() );
+ uloc = "http://www.kde.org";
+ check("pathOrURL url", uloc.url(), "http://www.kde.org");
+ uloc = "file:///home/dfaure/konq%20tests/Mat%E9riel#ref";
+ check("pathOrURL local file with ref", uloc.pathOrURL(), "file:///home/dfaure/konq tests/Matériel#ref" );
+ uloc = "file:///home/dfaure/konq%20tests/Mat%E9riel?query";
+ check("pathOrURL local file with query", uloc.pathOrURL(), "file:///home/dfaure/konq tests/Matériel?query" );
+ uloc = KURL::fromPathOrURL( "/home/dfaure/file#with#hash" );
+ check("pathOrURL local path with #", uloc.pathOrURL(), "/home/dfaure/file#with#hash" );
+
+ testAdjustPath();
+
+#if QT_VERSION < 300
+ qt_set_locale_codec( KGlobal::charsets()->codecForName( "koi8-r" ) );
+#else
+ QTextCodec::setCodecForLocale( KGlobal::charsets()->codecForName( "koi8-r" ) );
+#endif
+ baseURL = "file:/home/coolo";
+ KURL russian = baseURL.directory(false, true) + QString::fromLocal8Bit( "ÆÇÎ7" );
+ check( "russian", russian.url(), "file:///home/%C6%C7%CE7" );
+
+ KURL tobi1("http://some.host.net/path/to/file#fragmentPrecedes?theQuery");
+ check("wrong order of query and hypertext reference #1", tobi1.ref(), "fragmentPrecedes");
+ check("wrong order of query and hypertext reference #2", tobi1.query(), "?theQuery");
+
+ tobi1 = "http://host.net/path/?#http://brokenäadsfküpoij31ü029muß2890zupycÜ*!*'O´+ß0i";
+ check("zero-length query",tobi1.query(),"?");
+
+ tobi1 = "http://host.net/path/#no-query";
+ check("no query", tobi1.query(),"");
+ check("encodedPathAndQuery", tobi1.encodedPathAndQuery(), "/path/");
+
+ tobi1 = "http://host.net/path?myfirstquery#andsomeReference";
+ tobi1.setEncodedPathAndQuery("another/path/?another&query");
+ check("setEncodedPathAndQuery test#1", tobi1.query(), "?another&query");
+ check("setEncodedPathAndQuery test#2", tobi1.path(), "another/path/"); // with trailing slash
+ check("encodedPathAndQuery", tobi1.encodedPathAndQuery(), "another/path/?another&query");
+ tobi1.setEncodedPathAndQuery("another/path?another&query");
+ check("setEncodedPathAndQuery test#1", tobi1.query(), "?another&query");
+ check("setEncodedPathAndQuery test#2", tobi1.path(), "another/path"); // without trailing slash
+ check("encodedPathAndQuery", tobi1.encodedPathAndQuery(), "another/path?another&query");
+
+ KURL theKow = "http://www.google.de/search?q=frerich&hlx=xx&hl=de&empty=&lr=lang+de&test=%2B%20%3A%25";
+ check("queryItem (first item)", theKow.queryItem("q"), "frerich");
+ check("queryItem (middle item)", theKow.queryItem("hl"), "de");
+ check("queryItem (last item)", theKow.queryItem("lr"), "lang de");
+ check("queryItem (invalid item)", theKow.queryItem("InterstellarCounselor"), QString::null);
+ check("queryItem (empty item)", theKow.queryItem("empty"), "");
+ check("queryItem (item with encoded chars)", theKow.queryItem("test"), "+ :%");
+ check("encodedPathAndQuery", theKow.encodedPathAndQuery(), "/search?q=frerich&hlx=xx&hl=de&empty=&lr=lang+de&test=%2B%20%3A%25");
+
+ // checks for queryItems(), which returns a QMap<QString,QString>:
+ KURL queryUrl( "mailto:Marc%20Mutz%20%3cmutz@kde.org%3E?"
+ "Subject=subscribe+me&"
+ "body=subscribe+mutz%40kde.org&"
+ "Cc=majordomo%40lists.kde.org" );
+ check("queryItems (c.s. keys)",
+ QStringList(queryUrl.queryItems().keys()).join(", "),
+ "Cc, Subject, body" );
+ check("queryItems (c.i.s. keys)",
+ QStringList(queryUrl.queryItems(KURL::CaseInsensitiveKeys).keys()).join(", "),
+ "body, cc, subject" );
+ check("queryItems (values; c.s. keys)",
+ QStringList(queryUrl.queryItems().values()).join(", "),
+ "majordomo@lists.kde.org, subscribe me, subscribe mutz@kde.org" );
+ check("queryItems (values; c.i.s. keys)",
+ QStringList(queryUrl.queryItems(KURL::CaseInsensitiveKeys).values()).join(", "),
+ "subscribe mutz@kde.org, majordomo@lists.kde.org, subscribe me" );
+
+ KURL umlaut1("http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel");
+ check("umlaut1.url()", umlaut1.url(), "http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel");
+
+ KURL umlaut2("http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel", 106);
+ check("umlaut2.url()", umlaut2.url(), "http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel");
+
+ // Needed for #49616
+ check( "encode_string('C++')", KURL::encode_string( "C++" ), "C%2B%2B" );
+ check( "decode_string('C%2B%2B')", KURL::decode_string( "C%2B%2B" ), "C++" );
+ check( "decode_string('C%00A')", KURL::decode_string( "C%00%A" ), "C" ); // we stop at %00
+
+ check( "encode_string('%')", KURL::encode_string( "%" ), "%25" );
+ check( "encode_string(':')", KURL::encode_string( ":" ), "%3A" );
+
+ KURL amantia( "http://%E1.foo.de" );
+ check("amantia.isValid()", amantia.isValid() ? "true" : "false", "true");
+#ifdef HAVE_IDNA_H
+ check("amantia.url()", amantia.url(), "http://xn--80a.foo.de"); // Non-ascii is allowed in IDN domain names.
+#else
+ check("amantia.url()", amantia.url(), "http://?.foo.de"); // why not
+#endif
+
+ KURL thiago( QString::fromUtf8( "http://\303\244.de" ) ); // ä in utf8
+ check("thiago.isValid()", thiago.isValid() ? "true" : "false", "true");
+#ifdef HAVE_IDNA_H
+ check("thiago.url()", thiago.url(), "http://xn--4ca.de"); // Non-ascii is allowed in IDN domain names.
+#else
+ check("thiago.url()", thiago.url(), QString::fromUtf8( "http://\303\244.de" ) );
+#endif
+
+
+ KURL smb("smb://domain;username:password@server/share");
+ check("smb.isValid()", smb.isValid() ? "true" : "false", "true");
+ check("smb.user()", smb.user(), "domain;username");
+ smb = "smb:/";
+ check("smb:/", smb.isValid()?"VALID":"MALFORMED", "VALID");
+ smb = "smb://"; // kurl.cpp rev 1.106
+ check("smb://", smb.isValid()?"VALID":"MALFORMED", "MALFORMED");
+ smb = "smb://host";
+ check("smb://host", smb.isValid()?"VALID":"MALFORMED", "VALID");
+ smb = "smb:///";
+ check("smb:///", smb.isValid()?"VALID":"MALFORMED", "VALID");
+
+ KURL weird;
+ weird = "http://strange<hostname>/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "false");
+
+ weird = "http://strange<username>@strange<hostname>/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "false");
+
+ weird = "http://strange<username>@ok_hostname/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "true");
+ check("weird.host()", weird.host(), "ok_hostname");
+
+ weird = "http://strange;hostname/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "false");
+
+ weird = "http://strange;username@strange;hostname/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "false");
+
+ weird = "http://strange;username@ok_hostname/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "true");
+ check("weird.host()", weird.host(), "ok_hostname");
+
+ weird = "http://strange;username:password@strange;hostname/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "false");
+
+ weird = "http://strange;username:password@ok_hostname/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "true");
+ check("weird.host()", weird.host(), "ok_hostname");
+
+ weird = "http://[strange;hostname]/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "false");
+
+ weird = "http://[::fff:1:23]/";
+ check("weird.isValid()", weird.isValid() ? "true" : "false", "true");
+ check("weird.host()", weird.host(), "::fff:1:23");
+
+ KURL com1("http://server.com/dir/", ".");
+ check("com1.url()", com1.url(), "http://server.com/dir/");
+
+ KURL com2("http://server.com/dir/blubb/", "blah/");
+ check("com2.url()", com2.url(), "http://server.com/dir/blubb/blah/");
+
+ KURL utf8_1("audiocd:/By%20Name/15%20Geantra%C3%AE.wav", 106);
+ check("utf8_1.fileName()", utf8_1.fileName(), QString::fromLatin1("15 Geantraî.wav"));
+
+ KURL utf8_2("audiocd:/By%20Name/15%2fGeantra%C3%AE.wav", 106);
+ check("utf8_2.fileName()", utf8_2.fileName(), QString::fromLatin1("15/Geantraî.wav"));
+
+ KURL url_newline_1("http://www.foo.bar/foo/bar\ngnork");
+ check("url_newline_1.url()", url_newline_1.url(), QString::fromLatin1("http://www.foo.bar/foo/bar%0Agnork"));
+
+ KURL url_newline_2("http://www.foo.bar/foo?bar\ngnork");
+ check("url_newline_2.url()", url_newline_2.url(), QString::fromLatin1("http://www.foo.bar/foo?bar%0Agnork"));
+
+ KURL local_file_1("file://localhost/my/file");
+ check("local_file_1.isLocalFile()", local_file_1.isLocalFile() ? "true" : "false", "true");
+
+ KURL local_file_2("file://www.kde.org/my/file");
+ check("local_file_2.isLocalFile()", local_file_2.isLocalFile() ? "true" : "false", "false");
+
+ KURL local_file_3;
+ local_file_3.setHost(getenv("HOSTNAME"));
+ local_file_3.setPath("/my/file");
+ printf("\nURL=%s\n", local_file_3.url().latin1());
+ check("local_file_3.isLocalFile()", local_file_3.isLocalFile() ? "true" : "false", "true");
+
+ KURL local_file_4("file:///my/file");
+ check("local_file_4.isLocalFile()", local_file_4.isLocalFile() ? "true" : "false", "true");
+
+ KURL local_file_5;
+ local_file_5.setPath("/foo?bar");
+ check("local_file_5.url()", local_file_5.url(), "file:///foo%3Fbar");
+
+ QString basePath = "/home/bastian";
+
+ check("relativePath(\"/home/bastian\", \"/home/bastian\")", KURL::relativePath(basePath, "/home/bastian"), "./");
+ bool b;
+ check("relativePath(\"/home/bastian\", \"/home/bastian/src/plugins\")", KURL::relativePath(basePath, "/home/bastian/src/plugins", &b), "./src/plugins");
+ check("Is a subdirectory?", b ? "true" : "false", "true");
+ check("relativePath(\"/home/bastian\", \"./src/plugins\")", KURL::relativePath(basePath, "./src/plugins"), "./src/plugins");
+ check("relativePath(\"/home/bastian\", \"/home/waba/src/plugins\")", KURL::relativePath(basePath, "/home/waba/src/plugins", &b), "../waba/src/plugins");
+ check("Is a subdirectory?", b ? "true" : "false", "false");
+ check("relativePath(\"/home/bastian\", \"/\")", KURL::relativePath(basePath, "/"), "../../");
+
+ check("relativePath(\"/\", \"/\")", KURL::relativePath("/", "/"), "./");
+ check("relativePath(\"/\", \"/home/bastian\")", KURL::relativePath("/", "/home/bastian"), "./home/bastian");
+ check("relativePath(\"\", \"/home/bastian\")", KURL::relativePath("", "/home/bastian"), "/home/bastian");
+
+ baseURL = "http://www.kde.org/index.html";
+ check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/index.html#help\")", KURL::relativeURL(baseURL, "http://www.kde.org/index.html#help"), "#help");
+ check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/index.html?help=true\")", KURL::relativeURL(baseURL, "http://www.kde.org/index.html?help=true"), "index.html?help=true");
+ check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/contact.html\")", KURL::relativeURL(baseURL, "http://www.kde.org/contact.html"), "contact.html");
+ check("relativeURL(\"http://www.kde.org/index.html\", \"ftp://ftp.kde.org/pub/kde\")", KURL::relativeURL(baseURL, "ftp://ftp.kde.org/pub/kde"), "ftp://ftp.kde.org/pub/kde");
+ check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/index.html\")", KURL::relativeURL(baseURL, "http://www.kde.org/index.html"), "./");
+
+ baseURL = "http://www.kde.org/info/index.html";
+ check("relativeURL(\"http://www.kde.org/info/index.html\", \"http://www.kde.org/bugs/contact.html\")", KURL::relativeURL(baseURL, "http://www.kde.org/bugs/contact.html"), "../bugs/contact.html");
+
+ baseURL = "ptal://mlc:usb:PC_970";
+ check("isValid()?", baseURL.isValid() ? "true" : "false", "false");
+ check("url()", baseURL.url(), "ptal://mlc:usb:PC_970");
+
+ baseURL = "http://mlc:80/";
+ check("isValid()?", baseURL.isValid() ? "true" : "false", "true");
+ check("port()?", QString::number(baseURL.port()), "80");
+ check("path()?", baseURL.path(), "/");
+
+ baseURL = "ptal://mlc:usb@PC_970"; // User=mlc, password=usb, host=PC_970
+ check("isValid()?", baseURL.isValid() ? "true" : "false", "true");
+ check("host()?", baseURL.host(), "pc_970");
+ check("user()?", baseURL.user(), "mlc");
+ check("pass()?", baseURL.pass(), "usb");
+
+ weird = "ftp://user%40host.com@ftp.host.com/var/www/";
+ check("user()?", weird.user(), "user@host.com" );
+ check("host()?", weird.host(), "ftp.host.com" );
+ KURL up = weird.upURL();
+ check("KURL::upURL()", up.url(), "ftp://user%40host.com@ftp.host.com/var/");
+ up = up.upURL();
+ check("KURL::upURL()", up.url(), "ftp://user%40host.com@ftp.host.com/");
+ up = up.upURL();
+ check("KURL::upURL()", up.url(), "ftp://user%40host.com@ftp.host.com/"); // unchanged
+
+ KURL ldap = "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)";
+ check("host()?", ldap.host(), "host.com");
+ check("port()?", QString("%1").arg(ldap.port()), "6666");
+ check("path()?", ldap.path(), "/o=University of Michigan,c=US");
+ check("query()?", ldap.query(), "??sub?(cn=Babs%20Jensen)");
+ check("url()?", ldap.url(), "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)");
+ ldap.setQuery("??sub?(cn=Karl%20Marx)");
+ check("query()?", ldap.query(), "??sub?(cn=Karl%20Marx)");
+ check("url()?", ldap.url(), "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Karl%20Marx)");
+
+ KURL leo = "data:text/html,http://www.invalid/";
+ check("data URL: isValid", leo.isValid()?"valid":"malformed", "valid" );
+ check("data URL: protocol", leo.protocol(), "data" );
+ check("data URL: url", leo.url(), "data:text/html,http://www.invalid/" );
+ check("data URL: path", leo.path(), "text/html,http://www.invalid/" );
+
+ // URI Mode tests
+ url1 = "http://www.foobar.com/";
+ check("KURL(\"http://www.foobar.com/\").uriMode()", QString::number(url1.uriMode()), QString::number(KURL::URL));
+ url1 = "mailto:user@host.com";
+ check("KURL(\"mailto:user@host.com\").uriMode()", QString::number(url1.uriMode()), QString::number(KURL::Mailto));
+ check("KURL(\"mailto:user@host.com\").url()", url1.url(), "mailto:user@host.com");
+ check("KURL(\"mailto:user@host.com\").url(0, 106)", url1.url(0, 106), "mailto:user@host.com");
+ url1 = "data:text/plain,foobar?gazonk=flarp";
+ check("KURL(\"data:text/plain,foobar?gazonk=flarp\").uriMode()", QString::number(url1.uriMode()), QString::number(KURL::RawURI));
+ check("KURL(\"data:text/plain,foobar?gazonk=flarp\").path()", url1.path(), "text/plain,foobar?gazonk=flarp");
+ url1 = "mailto:User@Host.COM?subject=Hello";
+ check("KURL(\"mailto:User@Host.COM?subject=Hello\").path()", url1.path(), "User@host.com");
+
+ KURL emptyUserTest1("http://www.foobar.com/");
+ KURL emptyUserTest2("http://www.foobar.com/");
+ emptyUserTest2.setUser("");
+ check("Empty vs. null fields: user", emptyUserTest1==emptyUserTest2?"TRUE":"FALSE","TRUE");
+ emptyUserTest2.setPass("");
+ check("Empty vs. null fields: password", emptyUserTest1==emptyUserTest2?"TRUE":"FALSE","TRUE");
+
+ printf("\nTest OK !\n");
+}
+
diff --git a/kdecore/tests/kxerrorhandlertest.cpp b/kdecore/tests/kxerrorhandlertest.cpp
new file mode 100644
index 000000000..cb97be170
--- /dev/null
+++ b/kdecore/tests/kxerrorhandlertest.cpp
@@ -0,0 +1,54 @@
+#include <qwidget.h>
+#include <X11/Xlib.h>
+#include <iostream>
+using namespace std;
+
+#include <kxerrorhandler.h>
+
+int handler1( Display*, XErrorEvent* e )
+ {
+ cout << "ERR1:" << e->resourceid << ":" << (int)e->error_code << ":" << (int)e->request_code << ":" << e->serial << endl;
+ return 1;
+ }
+
+bool handler3( int request, int error_code, unsigned long resourceid )
+ {
+ cout << "ERR3:" << resourceid << ":" << error_code << ":" << request << endl;
+ return true;
+ }
+
+int main()
+ {
+ Display* dpy = XOpenDisplay( NULL );
+ XSetWindowAttributes attrs;
+ Window w = XCreateWindow( dpy, DefaultRootWindow( dpy ), 0, 0, 100, 100, 0, CopyFromParent, CopyFromParent,
+ CopyFromParent, 0, &attrs );
+ cout << w << ":" << XNextRequest( dpy ) << endl;
+ XMapWindow( dpy, w );
+ ++w;
+// XSetInputFocus( dpy, w, RevertToParent, CurrentTime );
+ {
+ KXErrorHandler handle1( handler1, dpy );
+ cout << w << ":" << XNextRequest( dpy ) << endl;
+ XMapWindow( dpy, w );
+ XWindowAttributes attr;
+ {
+ KXErrorHandler handle2( dpy );
+ XGetWindowAttributes(dpy, w, &attr);
+ {
+ KXErrorHandler handle3( handler3, dpy );
+ XSetInputFocus( dpy, w, RevertToParent, CurrentTime );
+ cout << "WAS3:" << handle3.error( /*false*/ true ) << endl;
+ }
+ cout << "WAS2:" << handle2.error( false ) << endl;
+ }
+// XSync( dpy, False );
+ cout << "WAS1:" << handle1.error( false ) << endl;
+ }
+ for(;;)
+ {
+ XEvent ev;
+ XNextEvent( dpy, &ev );
+ }
+ XCloseDisplay( dpy );
+ }
diff --git a/kdecore/tests/startserviceby.cpp b/kdecore/tests/startserviceby.cpp
new file mode 100644
index 000000000..4411eed53
--- /dev/null
+++ b/kdecore/tests/startserviceby.cpp
@@ -0,0 +1,41 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kapplication.h"
+#include <stdio.h>
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kglobalsettings.h>
+#include <kdebug.h>
+
+int
+main(int argc, char *argv[])
+{
+ KAboutData about("kapptest", "kapptest", "version");
+ KCmdLineArgs::init(argc, argv, &about);
+
+ KApplication a;
+
+ QString error;
+ QCString dcopService;
+ int pid;
+ a.startServiceByDesktopName( "kaddressbook", QString::null, &error, &dcopService, &pid );
+ kdDebug() << "Started. error=" << error << " dcopService=" << dcopService << " pid=" << pid << endl;
+ a.exec();
+}
diff --git a/kdecore/tests/testqtargs.cpp b/kdecore/tests/testqtargs.cpp
new file mode 100644
index 000000000..918b07735
--- /dev/null
+++ b/kdecore/tests/testqtargs.cpp
@@ -0,0 +1,104 @@
+/*
+ testqtargs -- is there really a bug in KCmdLineArgs or am I on crack?
+
+ I used the following compile options:
+
+ g++ -g -Wall -o testqtargs testqtargs.cpp -I/usr/X11R6/include \
+ -I/opt/qt3/include -I/opt/kde3/include -L/usr/X11R6/lib -L/opt/qt3/lib \
+ -L/opt/kde3/lib -lqt -lkdecore
+
+ if invoked like this ./testqtargs --bg blue --caption something --hello hi
+
+ The program should list argv[] then produce output like this:
+
+ qt arg[0] = background
+ qt arg[1] = blue
+ arg bg = blue
+ arg caption = something
+ arg hello = hi
+
+ Instead for me it prints:
+
+ qt arg[0] = -background
+ qt arg[1] = blue
+ arg caption = something
+ arg hello = hi
+
+ See the extra dash in qt arg[0]? I believe that is the cause of the problem.
+ --bg is aliased to --background but If you try it with --background or
+ -background, you get the same thing.
+
+ in kdecore/kapplication.cpp, KCmdLineOption qt_options is defined and used
+ by the static method Kapplication::addCmdLineOptions to add the Qt options
+ but its' entries look like this:
+
+ { "background <color>", I18N_NOOP("sets the default background color and an\n
+application palette (light and dark shades are\ncalculated)."), 0},
+
+ it looks for "background" instead of "-background" so never find the arg.
+
+ Software: g++ 2.95, kdelibs from CVS Jan 28, Qt 3.01
+ OS: Debian GNU/Linux 3.0 (sid)
+
+
+*/
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+static const KCmdLineOptions options[] =
+{
+ { "hello ", I18N_NOOP("Says hello"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ for (int i = 0; i < argc; i++)
+ {
+ qDebug("argv[%d] = %s", i, argv[i]);
+ }
+ KAboutData aboutData( "testqtargs", I18N_NOOP("testqtargs"),
+ "1.0", I18N_NOOP("testqtargs"), KAboutData::License_GPL,
+ "", "", "", "");
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ KCmdLineArgs *qtargs = KCmdLineArgs::parsedArgs("qt");
+ for (int i = 0; i < qtargs->count(); i++)
+ {
+ qDebug("qt arg[%d] = %s", i, qtargs->arg(i));
+ }
+
+ KApplication app;
+
+ KCmdLineArgs *kdeargs = KCmdLineArgs::parsedArgs("kde");
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ // An arg set by Qt
+ if(qtargs->isSet("background"))
+ {
+ qDebug("arg bg = %s", (const char*)qtargs->getOption("background"));
+ }
+ // An arg set by KDE
+ if(kdeargs->isSet("caption"))
+ {
+ qDebug("arg caption = %s", (const char*)kdeargs->getOption("caption"));
+ }
+ // An arg set by us.
+ if(args->isSet("hello"))
+ {
+ qDebug("arg hello = %s", (const char*)args->getOption("hello"));
+ }
+ args->clear();
+
+ QWidget *w = new QWidget();
+ app.setMainWidget(w);
+ w->show();
+
+ return app.exec();
+}
+
diff --git a/kdecore/vsnprintf.c b/kdecore/vsnprintf.c
new file mode 100644
index 000000000..257392aa4
--- /dev/null
+++ b/kdecore/vsnprintf.c
@@ -0,0 +1,170 @@
+#include "config.h"
+#ifndef HAVE_VSNPRINTF
+
+/*
+ * Revision 12: http://theos.com/~deraadt/snprintf.c
+ *
+ * Copyright (c) 1997 Theo de Raadt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#if __STDC__
+#include <stdarg.h>
+#include <stdlib.h>
+#else
+#include <varargs.h>
+#endif
+#include <setjmp.h>
+
+#ifndef roundup
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+#endif
+
+static int pgsize;
+static char *curobj;
+static sigjmp_buf bail;
+
+#define EXTRABYTES 2 /* XXX: why 2? you don't want to know */
+
+static char *
+msetup(str, n)
+ char *str;
+ size_t n;
+{
+ char *e;
+
+ if (n == 0)
+ return NULL;
+ if (pgsize == 0)
+ pgsize = getpagesize();
+ curobj = (char *)malloc(n + EXTRABYTES + pgsize * 2);
+ if (curobj == NULL)
+ return NULL;
+ e = curobj + n + EXTRABYTES;
+ e = (char *)roundup((unsigned long)e, pgsize);
+ if (mprotect(e, pgsize, PROT_NONE) == -1) {
+ free(curobj);
+ curobj = NULL;
+ return NULL;
+ }
+ e = e - n - EXTRABYTES;
+ *e = '\0';
+ return (e);
+}
+
+static void
+mcatch()
+{
+ siglongjmp(bail, 1);
+}
+
+static void
+mcleanup(str, n, p)
+ char *str;
+ size_t n;
+ char *p;
+{
+ int l = strlen(p);
+
+ if (l > n - 1)
+ l = n - 1;
+ memcpy(str, p, l);
+ str[l] = '\0';
+ if (mprotect((caddr_t)(p + n + EXTRABYTES), pgsize,
+ PROT_READ|PROT_WRITE|PROT_EXEC) == -1)
+ mprotect((caddr_t)(p + n + EXTRABYTES), pgsize,
+ PROT_READ|PROT_WRITE);
+ free(curobj);
+}
+
+int
+#if __STDC__
+vsnprintf(char *str, size_t n, char const *fmt, va_list ap)
+#else
+vsnprintf(str, n, fmt, ap)
+ char *str;
+ size_t n;
+ char *fmt;
+ char *ap;
+#endif
+{
+ struct sigaction osa, nsa;
+ char *p;
+ int ret = n + 1; /* if we bail, indicated we overflowed */
+
+ memset(&nsa, 0, sizeof nsa);
+ nsa.sa_handler = mcatch;
+ sigemptyset(&nsa.sa_mask);
+
+ p = msetup(str, n);
+ if (p == NULL) {
+ *str = '\0';
+ return 0;
+ }
+ if (sigsetjmp(bail, 1) == 0) {
+ if (sigaction(SIGSEGV, &nsa, &osa) == -1) {
+ mcleanup(str, n, p);
+ return (0);
+ }
+ ret = vsprintf(p, fmt, ap);
+ }
+ mcleanup(str, n, p);
+ (void) sigaction(SIGSEGV, &osa, NULL);
+ return (ret);
+}
+
+int
+#if __STDC__
+snprintf(char *str, size_t n, char const *fmt, ...)
+#else
+snprintf(str, n, fmt, va_alist)
+ char *str;
+ size_t n;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+
+ return (vsnprintf(str, n, fmt, ap));
+ va_end(ap);
+}
+
+
+#endif
+
+/* ANSI C forbids an empty source file... */
+static void dummy_func() {
+ dummy_func();
+}