--- /dev/null
+Developed by:
+ Thierry Lorthiois <lorthiois@bbsoft.fr>, project maintainer
+ Pål Staurland <staura@gmail.com>, tint2 is based on ttm originally written by Pål Staurland
+
+
+Contributors:
+ Daniel Moerner <dmoerner@gmail.com>, man page
+
+
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+
+
+2008-09-30
+- change tintrc format
+ background and border can use linear gradiant
+- update documentation
+
+2008-09-24
+- change tintrc format
+ user can define a list of background and border at the beginning of tintrc
+ and each object (panel, taskbar, task, clock, systray) get a background number.
+ the background number 0 is reserved by tint2 for full transparency.
+ user's background start with number 1, 2, ...
+
+2008-09-22
+- better control on icon opacity
+ icon opacity use the same value as text opacity
+
+2008-09-21
+- new parameter task_text = 0 or 1
+ so you can show task's icon without text
+- remove task_icon_size parameter because icon_size is calculate with task->padding_y
+
+2008-09-19
+- improve clock drawing on 2 lines
+- new design : object oriented
+ clock inherit Area (with draw_background)
+- rename parameter 'panel_mode' in 'taskbar_mode'
+
+2008-09-17
+- change name from tint to tint2 because debian has already a package named tint
+- new design : object oriented
+ tasks inherit Area
+ taskbars inherit Area
+
+2008-09-16
+- new design : object oriented
+ remove task_margin parameter, replaced by taskbar_padding
+ fixed segfault with new layout
+
+2008-09-04
+- new design : object oriented
+ all objects inherit from Area : panel, taskbar, task, clock
+
+2008-09-02 licence changed to GPL V2
+> Hi Pål,
+> Since latest release (tint-0.6), I try to merge a systray in tint.
+> The code I would like to merge is under GPL V2 licence.
+> So are you agree to change the licence of tint to GPL V2 ?
+Pål Staurland answer :
+ Yeah no problem::)
+
+2008-08-17 patch from i...@noctus.net
+- fixed bug : "Task button titles do not update"
+
+2008-08-12
+- code cleanup : Taskbar use GSLIST from glib
+
+2008-08-07
+- add 1 space between task title and icon
+
+2008-07-25
+- fixed bug when (task_rounded > panel_height/2)
+
+
+----------------------------------------------------------------
+2008-07-20 thil7 <lorthiois@bbsoft.fr>
+released tint-0.6
+
+2008-07-19
+- backward compatibility : save new config file
+
+2008-07-18
+- bug fixed with multi-monitor : memory leak, move task on the same monitor
+
+2008-07-12
+- multi_monitor : added window_get_monitor(win)
+
+2008-07-05
+- multi_monitor : changed taskbar allocation when add/remove a monitor
+- update documentation
+
+2008-07-04
+- changed in config file, panel_show_all_desktop
+ replaced by panel_mode = single_desktop / multi_desktop / multi_monitor
+- with panel_mode = multi_monitor, tint show one taskbar by monitor
+
+2008-07-02
+- add xinerama dependency
+- read monitors configuration
+- tint will run in 'sleep_mode'
+ if you specify 'panel_monitor' on an unplug monitor
+- tint 'wake up' when the monitor is detected or resolution changed
+
+2008-06-30 patch from goo...@dougbarton.us
+- tint wait for window manager on startup
+
+2008-06-29
+- specify monitor with parameter 'panel_monitor'
+- panel_position is relative to your monitor
+ panel_monitor = 1
+ panel_position = bottom center
+
+2008-06-24
+- fixed bug : show tint on all desktop with fluxbox
+
+2008-06-23
+- task_width = 0 to get full taskbar width
+- added documentation in /doc
+
+2008-06-16
+- renamed parameter panel_margin to panel_padding
+- added parameter panel_margin = vertical_margin horizontal_margin
+
+2008-06-15
+- fixed bug : icon position changed when clock adjust width
+- removed boolean parameter panel_background and task_background
+ replaced with opacity (alpha) = 0
+- removed task_active_border_width parameter
+ identical to task_border_width
+- fixed bug : draw task below panel border
+
+2008-06-11
+- removed the need of desktop margin.
+ tint specify margin to window magager (_NET_WM_STRUT)
+
+2008-06-10
+- fixed bug : time/date vertical and horizontal center
+
+2008-06-10 patch from benjaminfranzke
+- fixed bug : draw icon on 64bit system.
+
+2008-06-08
+- fixed bug : in draw border and fill background
+
+2008-06-04
+- allow config file on the command line : tint -c ./tintrc2
+- allow 2 value in config file : key = value1 value2
+- panel_margin can get 2 values : vertical_margin horizontal_margin
+ panel_margin = 8 4
+
+2008-05-30
+- put panel below other window
+- set locale LANG
+
+2008-05-28
+- clock_width adjust automatically
+- configure : time2_format see 'man strftime'
+
+2008-05-27
+- configure : time1_format see 'man strftime'
+- cleanup code : refresh_pos()
+
+2008-05-26
+- catch time event in main loop
+- draw clock fixed format %H:%M
+
+2008-05-24
+- removed boolean parameter task_icon
+ task_icon_size = 0 replace task_icon = 0
+- all colors parameters can get 2 values : color and opacity (alpha)
+ font_color = #ffffff 70
+
+2008-05-23
+- cpu optimisation : limit call to visual_refresh()
+
+2008-05-22
+- configure clock : clock_font, clock_font_color
+
+
+----------------------------------------------------------------
+2008-05-20 thil7 <lorthiois@bbsoft.fr>
+released tint-0.5
+
+2008-05-19
+- improve usability in mode 'show_all_desktop'
+ -> don't switch desktop when close a task of another desktop
+ -> allow to drag and drop task between desktop
+- change panel_position : you can now specify top or bottom.
+ values : bottom left, bottom right, bottom center, top left, top right, top center
+ keep compatibility with old tintrc files
+- change Makefile :
+ add $PREFIX and $DESTDIR
+ install default config file in /etc/xdg/tint/tintrc
+- on startup, tint copy $XDG_CONFIG_DIR/tint/tintrc in ~/.config/tint/tintrc
+ so each user can customize tintrc
+- fixed : name of task in fluxbox
+- improve focus detection (TransientForHint)
+- cleanup code : send_event
+
+
+----------------------------------------------------------------
+2008-05-14 thil7 <lorthiois@bbsoft.fr>
+released tint-0.4
+
+2008-05-12
+- boolean option 'show_all_desktop'
+ 0 : tint panel show one taskbar (from current desktop)
+ 1 : tint panel show all taskbars (from all desktops)
+ - clic on a task switch to the desktop
+ - clic on a taskbar (if empty) switch to the desktop
+- add layout for taskbar : panel -> taskbar -> task
+- cleanup code : state 'active' in Task replaced by task_active in Panel
+- hide some window : _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_STATE_MODAL
+- change project to 'MIT licence'
+ because Pål Staurland put 'MIT licence' in all file source
+
+
+----------------------------------------------------------------
+2008-05-10 thil7 <lorthiois@bbsoft.fr>
+released tint-0.3
+
+2008-05-10
+- manage events : 'send to desktop' and 'send to all desktop'
+- bug solved : 'close' action now send _NET_CLOSE_WINDOW
+ so openoffice ask 'save document...' if needed
+- cpu optimisation :
+ -> don't redraw panel background on all events. just when desktop change.
+ -> don't remove/add all tasks when switch between desktop. remove 'task_new_desktop()'.
+- small bug on _NET_WM_STATE_SKIP_TASKBAR corrected
+- memory leak on g_build_filename
+
+
+----------------------------------------------------------------
+2008-05-09 thil7 <lorthiois@bbsoft.fr>
+released tint-0.2
+
+2008-05-08
+- panel : add rounded and border (color and alpha)
+- remove option 'panel_tasks_centered'
+- user can configure mouse event on task
+ (none, toggle, iconify, shade, close, toggle_iconify)
+
+2008-05-07
+- cpu optimisation : resize_tasks only when add/remove task,
+ compute pos_y at startup
+
+2008-05-04
+- task width adjust when too many task
+
+2008-05-01
+- task : add rounded and border (color and alpha)
+- panel position (left, right, center) thank to ak47izatool
+- cleanup code : vertical position (icon and text),
+ better refresh after delete task, memory leak *font
+- panel : changed panel_margin and task_margin
+
+2008-04-22
+- fork ttm projet from p://code.google.com/p/ttm/ (by Pål Staurland staura@gmail.com)
+ while the projet is no longer in developpement, have not changed the name of 'tint'.
+
+
--- /dev/null
+DEPENDENCIES:
+cairo, pango, glib, imlib2
+
+---------------------------------------------------------
+INSTALL:
+
+cd to "src" and type "make"
+as root type "make install"
+
+execute "tint2"
+or "tint2 -c path_to_config_file"
+
+documentation is in /doc
+
+check http://code.google.com/p/tint2/
+for latest release, documentation and sample config file.
+
+
--- /dev/null
+.\" Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH TINT 1 "2008-09-05"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp <n> insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+tint \- lightweight taskbar
+.SH SYNOPSIS
+.B tint
+.br
+.B tint
+.RI -c
+.IR /path/to/config/file
+.SH DESCRIPTION
+This manual page documents briefly the
+.B tint
+command.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+\fBtint\fP is a simple panel/taskbar intentionally made for openbox3, but
+should also work with other window managers. It's based on ttm code. The goal is to keep a clean and unintrusive look with code lightweight and
+compliance with freedesktop specifications.
+.PP
+On the first startup tint creates a config file in $HOME/.config/tint/tintrc.
+See the /usr/share/tint2/doc directory for more information.
+.SH OPTIONS
+.TP
+.B \-c config-file
+Specify which configuration file to use instead of the default.
+.SH AUTHOR
+tint was written by Thierry Lorthiois <lorthiois@bbsoft.fr>. It is based on
+ttm, originally written by Pål Staurland <staura@gmail.com>
+.PP
+This manual page was written by Daniel Moerner <dmoerner@gmail.com>,
+for the Debian project (but may be used by others). It was adopted from the
+tint docs.
--- /dev/null
+#CFLAGS="-O2"
+FLAGS=-Wall -g `pkg-config --cflags --libs cairo pangocairo x11 xinerama imlib2 glib-2.0`
+PROGNAME=tint2
+FILES=tint.c server.c panel.c config.c taskbar/task.c taskbar/taskbar.c clock/clock.c systray/docker.c systray/icons.c systray/kde.c systray/net.c systray/xproperty.c util/window.c util/area.c
+
+ifndef DESTDIR
+ ifndef PREFIX
+ BINDIR=/usr/bin
+ XDG_CONFIG_DIR=/etc/xdg
+ else
+ BINDIR=$(PREFIX)/bin
+ XDG_CONFIG_DIR=/etc/xdg
+ endif
+else
+ BINDIR=$(DESTDIR)/usr/bin
+ XDG_CONFIG_DIR=$(DESTDIR)/etc/xdg
+endif
+
+
+$(PROGNAME): $(FILES) $(SYSTRAYOBJ)
+ $(CC) $(CFLAGS) $(FLAGS) -I. -Iutil -Iclock -Itaskbar -Isystray -o $(PROGNAME) $(FILES)
+ strip $(PROGNAME)
+
+install:
+ mkdir -p $(BINDIR)
+ mkdir -p $(XDG_CONFIG_DIR)/tint2
+ install $(PROGNAME) $(BINDIR)
+ cp -f ../tintrc06 $(XDG_CONFIG_DIR)/tint2/tint2rc
+ cp -f ../doc/man/tint2.1 /usr/man/man1
+
+uninstall:
+ rm -f $(BINDIR)/$(PROGNAME)
+
+clean:
+ rm -f $(PROGNAME)
+
--- /dev/null
+/**************************************************************************
+*
+* Tint2 : clock
+*
+* Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <cairo.h>
+#include <cairo-xlib.h>
+#include <pango/pangocairo.h>
+
+#include "window.h"
+#include "server.h"
+#include "area.h"
+#include "clock.h"
+
+
+void init_clock(Clock *clock, int panel_height)
+{
+ char buf_time[40];
+ char buf_date[40];
+ int time_height, time_height_ink, date_height, date_height_ink;
+
+ if (!clock->time1_format) return;
+
+ if (strchr(clock->time1_format, 'S') == NULL) clock->time_precision = 60;
+ else clock->time_precision = 1;
+
+ gettimeofday(&clock->clock, 0);
+ clock->clock.tv_sec -= clock->clock.tv_sec % clock->time_precision;
+
+ strftime(buf_time, sizeof(buf_time), clock->time1_format, localtime(&clock->clock.tv_sec));
+ if (clock->time2_format)
+ strftime(buf_date, sizeof(buf_date), clock->time2_format, localtime(&clock->clock.tv_sec));
+
+ get_text_size(clock->time1_font_desc, &time_height_ink, &time_height, panel_height, buf_time, strlen(buf_time));
+ clock->time1_posy = (clock->area.height - time_height) / 2;
+
+ if (clock->time2_format) {
+ get_text_size(clock->time2_font_desc, &date_height_ink, &date_height, panel_height, buf_date, strlen(buf_date));
+
+ clock->time1_posy -= ((date_height_ink + 2) / 2);
+ clock->time2_posy = clock->time1_posy + time_height + 2 - (time_height - time_height_ink)/2 - (date_height - date_height_ink)/2;
+ }
+}
+
+
+int draw_foreground_clock (void *obj, cairo_t *c)
+{
+ Clock *clock = obj;
+ PangoLayout *layout;
+ char buf_time[40];
+ char buf_date[40];
+ int time_width, date_width, new_width;
+
+ time_width = date_width = 0;
+ strftime(buf_time, sizeof(buf_time), clock->time1_format, localtime(&clock->clock.tv_sec));
+ if (clock->time2_format)
+ strftime(buf_date, sizeof(buf_date), clock->time2_format, localtime(&clock->clock.tv_sec));
+
+ layout = pango_cairo_create_layout (c);
+
+ // check width
+ pango_layout_set_font_description (layout, clock->time1_font_desc);
+ pango_layout_set_indent(layout, 0);
+ pango_layout_set_text (layout, buf_time, strlen(buf_time));
+ pango_layout_get_pixel_size (layout, &time_width, NULL);
+ if (clock->time2_format) {
+ pango_layout_set_font_description (layout, clock->time2_font_desc);
+ pango_layout_set_indent(layout, 0);
+ pango_layout_set_text (layout, buf_date, strlen(buf_date));
+ pango_layout_get_pixel_size (layout, &date_width, NULL);
+ }
+ if (time_width > date_width) new_width = time_width;
+ else new_width = date_width;
+ new_width += (2*clock->area.paddingx) + (2*clock->area.border.width);
+
+ if (new_width > clock->area.width || (new_width != clock->area.width && date_width > time_width)) {
+ printf("clock_width %d, new_width %d\n", clock->area.width, new_width);
+ clock->area.width = new_width;
+
+ g_object_unref (layout);
+ return 1;
+ }
+
+ // draw layout
+ pango_layout_set_font_description (layout, clock->time1_font_desc);
+ pango_layout_set_width (layout, clock->area.width * PANGO_SCALE);
+ pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
+ pango_layout_set_text (layout, buf_time, strlen(buf_time));
+
+ cairo_set_source_rgba (c, clock->font.color[0], clock->font.color[1], clock->font.color[2], clock->font.alpha);
+
+ pango_cairo_update_layout (c, layout);
+ cairo_move_to (c, 0, clock->time1_posy);
+ pango_cairo_show_layout (c, layout);
+
+ if (clock->time2_format) {
+ pango_layout_set_font_description (layout, clock->time2_font_desc);
+ pango_layout_set_indent(layout, 0);
+ pango_layout_set_text (layout, buf_date, strlen(buf_date));
+ pango_layout_set_width (layout, clock->area.width * PANGO_SCALE);
+
+ pango_cairo_update_layout (c, layout);
+ cairo_move_to (c, 0, clock->time2_posy);
+ pango_cairo_show_layout (c, layout);
+ }
+
+ g_object_unref (layout);
+ return 0;
+}
+
--- /dev/null
+/**************************************************************************
+* clock :
+* - draw clock, adjust width
+*
+**************************************************************************/
+
+#ifndef CLOCK_H
+#define CLOCK_H
+
+#include <sys/time.h>
+#include "common.h"
+#include "area.h"
+
+
+typedef struct Clock {
+ // --------------------------------------------------
+ // always start with area
+ Area area;
+
+ config_color font;
+ PangoFontDescription *time1_font_desc;
+ PangoFontDescription *time2_font_desc;
+ int time1_posy;
+ int time2_posy;
+ char *time1_format;
+ char *time2_format;
+
+ struct timeval clock;
+ int time_precision;
+} Clock;
+
+
+// initialize clock : y position, precision, ...
+void init_clock(Clock *clock, int panel_height);
+
+int draw_foreground_clock (void *obj, cairo_t *c);
+
+
+#endif
--- /dev/null
+/**************************************************************************
+*
+* Tint2 : read/write config file
+*
+* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
+* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <cairo.h>
+#include <cairo-xlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib/gstdio.h>
+#include <pango/pangocairo.h>
+#include <Imlib2.h>
+
+#include "common.h"
+#include "server.h"
+#include "task.h"
+#include "taskbar.h"
+#include "clock.h"
+#include "panel.h"
+#include "config.h"
+#include "window.h"
+
+
+void cleanup_taskbar()
+{
+ Task *tsk;
+ Taskbar *tskbar;
+ GSList *l0;
+ for (l0 = panel.area.list; l0 ; l0 = l0->next) {
+ tskbar = l0->data;
+ GSList *l1;
+ for (l1 = tskbar->area.list; l1 ; l1 = l1->next) {
+ tsk = l1->data;
+ remove_task (tsk);
+ }
+ g_slist_free(tskbar->area.list);
+ }
+ g_slist_free(panel.area.list);
+ panel.area.list = 0;
+}
+
+
+void cleanup ()
+{
+ if (panel.old_task_font) free(panel.old_task_font);
+ if (g_task.font_desc) pango_font_description_free(g_task.font_desc);
+ if (panel.clock.time1_font_desc) pango_font_description_free(panel.clock.time1_font_desc);
+ if (panel.clock.time2_font_desc) pango_font_description_free(panel.clock.time2_font_desc);
+ cleanup_taskbar();
+ if (panel.clock.time1_format) g_free(panel.clock.time1_format);
+ if (panel.clock.time2_format) g_free(panel.clock.time2_format);
+ if (server.monitor) free(server.monitor);
+ XCloseDisplay(server.dsp);
+}
+
+
+void copy_file(const char *pathSrc, const char *pathDest)
+{
+ FILE *fileSrc, *fileDest;
+ char line[100];
+ int nb;
+
+ fileSrc = fopen(pathSrc, "rb");
+ if (fileSrc == NULL) return;
+
+ fileDest = fopen(pathDest, "wb");
+ if (fileDest == NULL) return;
+
+ while ((nb = fread(line, 1, 100, fileSrc)) > 0) fwrite(line, 1, nb, fileDest);
+
+ fclose (fileDest);
+ fclose (fileSrc);
+}
+
+
+void extract_values (const char *value, char **value1, char **value2)
+{
+ char *b;
+
+ if (*value1) free (*value1);
+ if (*value2) free (*value2);
+
+ if ((b = strchr (value, ' '))) {
+ b[0] = '\0';
+ b++;
+ *value2 = strdup (b);
+ g_strstrip(*value2);
+ }
+ else *value2 = 0;
+
+ *value1 = strdup (value);
+ g_strstrip(*value1);
+}
+
+
+int hex_char_to_int (char c)
+{
+ int r;
+
+ if (c >= '0' && c <= '9') r = c - '0';
+ else if (c >= 'a' && c <= 'f') r = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F') r = c - 'A' + 10;
+ else r = 0;
+
+ return r;
+}
+
+
+int hex_to_rgb (char *hex, int *r, int *g, int *b)
+{
+ int len;
+
+ if (hex == NULL || hex[0] != '#') return (0);
+
+ len = strlen (hex);
+ if (len == 3 + 1) {
+ *r = hex_char_to_int (hex[1]);
+ *g = hex_char_to_int (hex[2]);
+ *b = hex_char_to_int (hex[3]);
+ }
+ else if (len == 6 + 1) {
+ *r = hex_char_to_int (hex[1]) * 16 + hex_char_to_int (hex[2]);
+ *g = hex_char_to_int (hex[3]) * 16 + hex_char_to_int (hex[4]);
+ *b = hex_char_to_int (hex[5]) * 16 + hex_char_to_int (hex[6]);
+ }
+ else if (len == 12 + 1) {
+ *r = hex_char_to_int (hex[1]) * 16 + hex_char_to_int (hex[2]);
+ *g = hex_char_to_int (hex[5]) * 16 + hex_char_to_int (hex[6]);
+ *b = hex_char_to_int (hex[9]) * 16 + hex_char_to_int (hex[10]);
+ }
+ else return 0;
+
+ return 1;
+}
+
+
+void get_color (char *hex, double *rgb)
+{
+ int r, g, b;
+ hex_to_rgb (hex, &r, &g, &b);
+
+ rgb[0] = (r / 255.0);
+ rgb[1] = (g / 255.0);
+ rgb[2] = (b / 255.0);
+}
+
+
+void get_action (char *event, int *action)
+{
+ if (strcmp (event, "none") == 0)
+ *action = NONE;
+ else if (strcmp (event, "close") == 0)
+ *action = CLOSE;
+ else if (strcmp (event, "toggle") == 0)
+ *action = TOGGLE;
+ else if (strcmp (event, "iconify") == 0)
+ *action = ICONIFY;
+ else if (strcmp (event, "shade") == 0)
+ *action = SHADE;
+ else if (strcmp (event, "toggle_iconify") == 0)
+ *action = TOGGLE_ICONIFY;
+}
+
+
+void add_entry (char *key, char *value)
+{
+ char *value1=0, *value2=0;
+
+ /* Background and border */
+ if (strcmp (key, "rounded") == 0) {
+ // 'rounded' is the first parameter => alloc a new background
+ Area *back = calloc(1, sizeof(Area));
+ back->border.rounded = atoi (value);
+ list_back = g_slist_append(list_back, back);
+ }
+ else if (strcmp (key, "border_width") == 0) {
+ Area *back = g_slist_last(list_back)->data;
+ back->border.width = atoi (value);
+ }
+ else if (strcmp (key, "background_color") == 0) {
+ Area *back = g_slist_last(list_back)->data;
+ extract_values(value, &value1, &value2);
+ get_color (value1, back->back.color);
+ if (value2) back->back.alpha = (atoi (value2) / 100.0);
+ else back->back.alpha = 0.5;
+ }
+ else if (strcmp (key, "border_color") == 0) {
+ Area *back = g_slist_last(list_back)->data;
+ extract_values(value, &value1, &value2);
+ get_color (value1, back->border.color);
+ if (value2) back->border.alpha = (atoi (value2) / 100.0);
+ else back->border.alpha = 0.5;
+ }
+
+ /* Panel */
+ else if (strcmp (key, "panel_monitor") == 0) {
+ panel.monitor = atoi (value);
+ if (panel.monitor > 0) panel.monitor -= 1;
+ }
+ else if (strcmp (key, "panel_size") == 0) {
+ extract_values(value, &value1, &value2);
+ panel.area.width = atoi (value1);
+ if (value2) panel.area.height = atoi (value2);
+ }
+ else if (strcmp (key, "panel_margin") == 0) {
+ extract_values(value, &value1, &value2);
+ panel.marginx = atoi (value1);
+ if (value2) panel.marginy = atoi (value2);
+ }
+ else if (strcmp (key, "panel_padding") == 0) {
+ extract_values(value, &value1, &value2);
+ panel.area.paddingx = atoi (value1);
+ if (value2) panel.area.paddingy = atoi (value2);
+ }
+ else if (strcmp (key, "panel_position") == 0) {
+ extract_values(value, &value1, &value2);
+ if (strcmp (value1, "top") == 0) panel.position = TOP;
+ else panel.position = BOTTOM;
+
+ if (!value2) panel.position = CENTER;
+ else {
+ if (strcmp (value2, "left") == 0) panel.position |= LEFT;
+ else {
+ if (strcmp (value2, "right") == 0) panel.position |= RIGHT;
+ else panel.position |= CENTER;
+ }
+ }
+ }
+ else if (strcmp (key, "font_shadow") == 0)
+ g_task.font_shadow = atoi (value);
+ else if (strcmp (key, "panel_background_id") == 0) {
+ int id = atoi (value);
+ Area *back = g_slist_nth_data(list_back, id);
+ memcpy(&panel.area.back, &back->back, sizeof(Color));
+ memcpy(&panel.area.border, &back->border, sizeof(Border));
+ }
+
+ /* Clock */
+ else if (strcmp (key, "time1_format") == 0) {
+ if (panel.clock.time1_format) g_free(panel.clock.time1_format);
+ if (strlen(value) > 0) panel.clock.time1_format = strdup (value);
+ else panel.clock.time1_format = 0;
+ }
+ else if (strcmp (key, "time2_format") == 0) {
+ if (panel.clock.time2_format) g_free(panel.clock.time2_format);
+ if (strlen(value) > 0) panel.clock.time2_format = strdup (value);
+ else panel.clock.time2_format = 0;
+ }
+ else if (strcmp (key, "time1_font") == 0) {
+ if (panel.clock.time1_font_desc) pango_font_description_free(panel.clock.time1_font_desc);
+ panel.clock.time1_font_desc = pango_font_description_from_string (value);
+ }
+ else if (strcmp (key, "time2_font") == 0) {
+ if (panel.clock.time2_font_desc) pango_font_description_free(panel.clock.time2_font_desc);
+ panel.clock.time2_font_desc = pango_font_description_from_string (value);
+ }
+ else if (strcmp (key, "clock_font_color") == 0) {
+ extract_values(value, &value1, &value2);
+ get_color (value1, panel.clock.font.color);
+ if (value2) panel.clock.font.alpha = (atoi (value2) / 100.0);
+ else panel.clock.font.alpha = 0.1;
+ }
+ else if (strcmp (key, "clock_padding") == 0) {
+ extract_values(value, &value1, &value2);
+ panel.clock.area.paddingx = atoi (value1);
+ if (value2) panel.clock.area.paddingy = atoi (value2);
+ }
+ else if (strcmp (key, "clock_background_id") == 0) {
+ int id = atoi (value);
+ Area *back = g_slist_nth_data(list_back, id);
+ memcpy(&panel.clock.area.back, &back->back, sizeof(Color));
+ memcpy(&panel.clock.area.border, &back->border, sizeof(Border));
+ }
+
+ /* Taskbar */
+ else if (strcmp (key, "taskbar_mode") == 0) {
+ if (strcmp (value, "multi_desktop") == 0) panel.mode = MULTI_DESKTOP;
+ else if (strcmp (value, "multi_monitor") == 0) panel.mode = MULTI_MONITOR;
+ else panel.mode = SINGLE_DESKTOP;
+ }
+ else if (strcmp (key, "taskbar_padding") == 0) {
+ extract_values(value, &value1, &value2);
+ g_taskbar.paddingx = atoi (value1);
+ if (value2) g_taskbar.paddingy = atoi (value2);
+ }
+ else if (strcmp (key, "taskbar_background_id") == 0) {
+ int id = atoi (value);
+ Area *back = g_slist_nth_data(list_back, id);
+ memcpy(&g_taskbar.back, &back->back, sizeof(Color));
+ memcpy(&g_taskbar.border, &back->border, sizeof(Border));
+ }
+
+ /* Task */
+ else if (strcmp (key, "task_text") == 0)
+ g_task.text = atoi (value);
+ else if (strcmp (key, "task_icon") == 0)
+ g_task.icon = atoi (value);
+ else if (strcmp (key, "task_centered") == 0)
+ g_task.centered = atoi (value);
+ else if (strcmp (key, "task_width") == 0)
+ g_task.maximum_width = atoi (value);
+ else if (strcmp (key, "task_padding") == 0) {
+ extract_values(value, &value1, &value2);
+ g_task.area.paddingx = atoi (value1);
+ g_task.area_active.paddingx = atoi (value1);
+ if (value2) {
+ g_task.area.paddingy = atoi (value2);
+ g_task.area_active.paddingy = atoi (value2);
+ }
+ }
+ else if (strcmp (key, "task_font") == 0) {
+ if (g_task.font_desc) pango_font_description_free(g_task.font_desc);
+ g_task.font_desc = pango_font_description_from_string (value);
+ }
+ else if (strcmp (key, "task_font_color") == 0) {
+ extract_values(value, &value1, &value2);
+ get_color (value1, g_task.font.color);
+ if (value2) g_task.font.alpha = (atoi (value2) / 100.0);
+ else g_task.font.alpha = 0.1;
+ }
+ else if (strcmp (key, "task_active_font_color") == 0) {
+ extract_values(value, &value1, &value2);
+ get_color (value1, g_task.font_active.color);
+ if (value2) g_task.font_active.alpha = (atoi (value2) / 100.0);
+ else g_task.font_active.alpha = 0.1;
+ }
+ else if (strcmp (key, "task_background_id") == 0) {
+ int id = atoi (value);
+ Area *back = g_slist_nth_data(list_back, id);
+ memcpy(&g_task.area.back, &back->back, sizeof(Color));
+ memcpy(&g_task.area.border, &back->border, sizeof(Border));
+ }
+ else if (strcmp (key, "task_active_background_id") == 0) {
+ int id = atoi (value);
+ Area *back = g_slist_nth_data(list_back, id);
+ memcpy(&g_task.area_active.back, &back->back, sizeof(Color));
+ memcpy(&g_task.area_active.border, &back->border, sizeof(Border));
+ }
+
+ /* Mouse actions */
+ else if (strcmp (key, "mouse_middle") == 0)
+ get_action (value, &panel.mouse_middle);
+ else if (strcmp (key, "mouse_right") == 0)
+ get_action (value, &panel.mouse_right);
+ else if (strcmp (key, "mouse_scroll_up") == 0)
+ get_action (value, &panel.mouse_scroll_up);
+ else if (strcmp (key, "mouse_scroll_down") == 0)
+ get_action (value, &panel.mouse_scroll_down);
+
+
+ /* Read old config for backward compatibility */
+ else if (strcmp (key, "font") == 0) {
+ panel.old_config_file = 1;
+ if (g_task.font_desc) pango_font_description_free(g_task.font_desc);
+ g_task.font_desc = pango_font_description_from_string (value);
+ if (panel.old_task_font) free(panel.old_task_font);
+ panel.old_task_font = strdup (value);
+ }
+ else if (strcmp (key, "font_color") == 0)
+ get_color (value, g_task.font.color);
+ else if (strcmp (key, "font_alpha") == 0)
+ g_task.font.alpha = (atoi (value) / 100.0);
+ else if (strcmp (key, "font_active_color") == 0)
+ get_color (value, g_task.font_active.color);
+ else if (strcmp (key, "font_active_alpha") == 0)
+ g_task.font_active.alpha = (atoi (value) / 100.0);
+ else if (strcmp (key, "panel_show_all_desktop") == 0) {
+ if (atoi (value) == 0) panel.mode = SINGLE_DESKTOP;
+ else panel.mode = MULTI_DESKTOP;
+ }
+ else if (strcmp (key, "panel_width") == 0)
+ panel.area.width = atoi (value);
+ else if (strcmp (key, "panel_height") == 0)
+ panel.area.height = atoi (value);
+ else if (strcmp (key, "panel_background") == 0)
+ panel.old_panel_background = atoi (value);
+ else if (strcmp (key, "panel_background_alpha") == 0)
+ panel.area.back.alpha = (atoi (value) / 100.0);
+ else if (strcmp (key, "panel_border_alpha") == 0)
+ panel.area.border.alpha = (atoi (value) / 100.0);
+ else if (strcmp (key, "task_icon") == 0)
+ panel.old_task_icon = atoi (value);
+ else if (strcmp (key, "task_background") == 0)
+ panel.old_task_background = atoi (value);
+ else if (strcmp (key, "task_background_alpha") == 0)
+ g_task.area.back.alpha = (atoi (value) / 100.0);
+ else if (strcmp (key, "task_active_background_alpha") == 0)
+ g_task.area_active.back.alpha = (atoi (value) / 100.0);
+ else if (strcmp (key, "task_border_alpha") == 0)
+ g_task.area.border.alpha = (atoi (value) / 100.0);
+ else if (strcmp (key, "task_active_border_alpha") == 0)
+ g_task.area_active.border.alpha = (atoi (value) / 100.0);
+ // disabled parameters
+ else if (strcmp (key, "task_active_border_width") == 0) ;
+ else if (strcmp (key, "task_active_rounded") == 0) ;
+
+ else
+ fprintf(stderr, "Invalid option: \"%s\", correct your config file\n", key);
+
+ if (value1) free (value1);
+ if (value2) free (value2);
+}
+
+
+int parse_line (const char *line)
+{
+ char *a, *b, *key, *value;
+
+ /* Skip useless lines */
+ if ((line[0] == '#') || (line[0] == '\n')) return 0;
+ if (!(a = strchr (line, '='))) return 0;
+
+ /* overwrite '=' with '\0' */
+ a[0] = '\0';
+ key = strdup (line);
+ a++;
+
+ /* overwrite '\n' with '\0' if '\n' present */
+ if ((b = strchr (a, '\n'))) b[0] = '\0';
+
+ value = strdup (a);
+
+ g_strstrip(key);
+ g_strstrip(value);
+
+ add_entry (key, value);
+
+ free (key);
+ free (value);
+ return 1;
+}
+
+
+void config_taskbar()
+{
+ int i, j;
+
+ if (g_task.area.border.rounded > g_task.area.height/2) {
+ g_task.area.border.rounded = g_task.area.height/2;
+ g_task.area_active.border.rounded = g_task.area.border.rounded;
+ }
+
+ for (i=0 ; i < 15 ; i++) {
+ server.nb_desktop = server_get_number_of_desktop ();
+ if (server.nb_desktop > 0) break;
+ sleep(1);
+ }
+ if (server.nb_desktop == 0) {
+ server.nb_desktop = 1;
+ fprintf(stderr, "tint2 warning : cannot found number of desktop.\n");
+ }
+
+ cleanup_taskbar();
+
+ panel.nb_desktop = server.nb_desktop;
+ if (panel.mode == MULTI_MONITOR) panel.nb_monitor = server.nb_monitor;
+ else panel.nb_monitor = 1;
+
+ // TODO: mémoriser le pointeur sur la première
+ // malgré l'apparant désordre, les taskbars sont ordonnées
+ Taskbar *new_tskbar;
+ for (i=0 ; i < panel.nb_desktop ; i++) {
+ for (j=0 ; j < panel.nb_monitor ; j++) {
+ new_tskbar = calloc(1, sizeof(Taskbar));
+ memcpy(&new_tskbar->area, &g_taskbar, sizeof(Area));
+ new_tskbar->desktop = i;
+ new_tskbar->monitor = j;
+
+ panel.area.list = g_slist_append(panel.area.list, new_tskbar);
+ }
+ }
+ /*
+ comment faire pour parcourir les barres de taches ? on ne peut pas se baser sur l'ordre des éléments !!
+ a t'on besoin de parcourir les barres de taches ?? OUI !! bof ??
+ => resize_taskbar() dans panel.c =>
+ => task_refresh_tasklist () dans taskbar.c
+ => Task *task_get_task (Window win) dans taskbar.c
+ => event_button_press (int x, int y) dans tint.c => area->event_button_press() est conseillé !!
+ cela enlève aussi l'organisation des barres de taches en tableau à 2 dimensions
+ il est possible de mémoriser un pointeur sur la première barre de taches
+*/
+
+ //printf("tasbar (desktop x monitor) : (%d x %d)\n", panel.nb_desktop, panel.nb_monitor);
+ resize_taskbar();
+ task_refresh_tasklist ();
+ panel.refresh = 1;
+}
+
+
+void config_finish ()
+{
+ int height_ink, height;
+
+ if (panel.old_config_file) save_config();
+
+ // get monitor's configuration
+ get_monitors();
+
+ if (panel.monitor > (server.nb_monitor-1)) {
+ panel.sleep_mode = 1;
+ printf("tint2 sleep and wait monitor %d.\n", panel.monitor+1);
+ }
+ else {
+ panel.sleep_mode = 0;
+ //printf("tint2 wake up on monitor %d\n", panel.monitor+1);
+ if (!server.monitor[panel.monitor].width || !server.monitor[panel.monitor].height)
+ fprintf(stderr, "tint2 error : invalid monitor size.\n");
+ }
+
+ if (!panel.area.width) panel.area.width = server.monitor[panel.monitor].width;
+
+ // taskbar
+ g_taskbar.posy = panel.area.border.width + panel.area.paddingy;
+ g_taskbar.height = panel.area.height - (2 * g_taskbar.posy);
+ g_taskbar.redraw = 1;
+
+ // task
+ g_task.area.posy = g_taskbar.posy + g_taskbar.border.width + g_taskbar.paddingy;
+ g_task.area_active.posy = g_task.area.posy;
+ g_task.area.height = panel.area.height - (2 * g_task.area.posy);
+ g_task.area_active.height = g_task.area.height;
+ g_task.area.redraw = 1;
+
+ if (!g_task.maximum_width)
+ g_task.maximum_width = server.monitor[panel.monitor].width;
+
+ if (panel.area.border.rounded > panel.area.height/2)
+ panel.area.border.rounded = panel.area.height/2;
+
+ // clock
+ panel.clock.area.posy = panel.area.border.width + panel.area.paddingy;
+ panel.clock.area.height = panel.area.height - (2 * panel.clock.area.posy);
+ panel.clock.area.redraw = 1;
+ init_clock(&panel.clock, panel.area.height);
+
+ // compute vertical position : text and icon
+ get_text_size(g_task.font_desc, &height_ink, &height, panel.area.height, "TAjpg", 5);
+ g_task.text_posy = (g_task.area.height - height) / 2.0;
+
+ // add task_icon_size
+ g_task.text_posx = g_task.area.paddingx + g_task.area.border.width;
+ if (g_task.icon) {
+ g_task.icon_size1 = g_task.area.height - (2 * g_task.area.paddingy);
+ g_task.text_posx += g_task.icon_size1;
+ g_task.icon_posy = (g_task.area.height - g_task.icon_size1) / 2;
+ }
+
+ config_taskbar();
+
+ // cleanup background list
+ GSList *l0;
+ for (l0 = list_back; l0 ; l0 = l0->next) {
+ free(l0->data);
+ }
+ g_slist_free(list_back);
+}
+
+
+int config_read ()
+{
+ const gchar * const * system_dirs;
+ char *path1, *path2, *dir;
+ gint i;
+
+ // check tint2rc file according to XDG specification
+ path1 = g_build_filename (g_get_user_config_dir(), "tint2", "tint2rc", NULL);
+ if (!g_file_test (path1, G_FILE_TEST_EXISTS)) {
+
+ path2 = 0;
+ system_dirs = g_get_system_config_dirs();
+ for (i = 0; system_dirs[i]; i++) {
+ path2 = g_build_filename(system_dirs[i], "tint2", "tint2rc", NULL);
+
+ if (g_file_test(path2, G_FILE_TEST_EXISTS)) break;
+ g_free (path2);
+ path2 = 0;
+ }
+
+ if (path2) {
+ // copy file in user directory (path1)
+ dir = g_build_filename (g_get_user_config_dir(), "tint2", NULL);
+ if (!g_file_test (dir, G_FILE_TEST_IS_DIR)) g_mkdir(dir, 0777);
+ g_free(dir);
+
+ copy_file(path2, path1);
+ g_free(path2);
+ }
+ }
+
+ i = config_read_file (path1);
+ g_free(path1);
+ return i;
+}
+
+
+int config_read_file (const char *path)
+{
+ FILE *fp;
+ char line[80];
+
+ if ((fp = fopen(path, "r")) == NULL) return 0;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ parse_line (line);
+
+ fclose (fp);
+ return 1;
+}
+
+
+void save_config ()
+{
+ fprintf(stderr, "tint2 warning : convert user's config file\n");
+ panel.area.paddingx = panel.area.paddingy = panel.marginx;
+ panel.marginx = panel.marginy = 0;
+
+ if (panel.old_task_icon == 0) g_task.icon_size1 = 0;
+ if (panel.old_panel_background == 0) panel.area.back.alpha = 0;
+ if (panel.old_task_background == 0) {
+ g_task.area.back.alpha = 0;
+ g_task.area_active.back.alpha = 0;
+ }
+ g_task.area.border.rounded = g_task.area.border.rounded / 2;
+ g_task.area_active.border.rounded = g_task.area.border.rounded;
+ panel.area.border.rounded = panel.area.border.rounded / 2;
+
+ char *path;
+ FILE *fp;
+
+ path = g_build_filename (g_get_user_config_dir(), "tint2", "tint2rc", NULL);
+ fp = fopen(path, "w");
+ g_free(path);
+ if (fp == NULL) return;
+
+ fputs("#---------------------------------------------\n", fp);
+ fputs("# TINT CONFIG FILE\n", fp);
+ fputs("#---------------------------------------------\n\n", fp);
+ fputs("#---------------------------------------------\n", fp);
+ fputs("# PANEL\n", fp);
+ fputs("#---------------------------------------------\n", fp);
+ if (panel.mode == SINGLE_DESKTOP) fputs("panel_mode = single_desktop\n", fp);
+ else fputs("panel_mode = multi_desktop\n", fp);
+ fputs("panel_monitor = 1\n", fp);
+ if (panel.position & BOTTOM) fputs("panel_position = bottom", fp);
+ else fputs("panel_position = top", fp);
+ if (panel.position & LEFT) fputs(" left\n", fp);
+ else if (panel.position & RIGHT) fputs(" right\n", fp);
+ else fputs(" center\n", fp);
+ fprintf(fp, "panel_size = %d %d\n", panel.area.width, panel.area.height);
+ fprintf(fp, "panel_margin = %d %d\n", panel.marginx, panel.marginy);
+ fprintf(fp, "panel_padding = %d %d\n", panel.area.paddingx, panel.area.paddingy);
+ fprintf(fp, "font_shadow = %d\n", g_task.font_shadow);
+
+ fputs("\n#---------------------------------------------\n", fp);
+ fputs("# PANEL BACKGROUND AND BORDER\n", fp);
+ fputs("#---------------------------------------------\n", fp);
+ fprintf(fp, "panel_rounded = %d\n", panel.area.border.rounded);
+ fprintf(fp, "panel_border_width = %d\n", panel.area.border.width);
+ fprintf(fp, "panel_background_color = #%02x%02x%02x %d\n", (int)(panel.area.back.color[0]*255), (int)(panel.area.back.color[1]*255), (int)(panel.area.back.color[2]*255), (int)(panel.area.back.alpha*100));
+ fprintf(fp, "panel_border_color = #%02x%02x%02x %d\n", (int)(panel.area.border.color[0]*255), (int)(panel.area.border.color[1]*255), (int)(panel.area.border.color[2]*255), (int)(panel.area.border.alpha*100));
+
+ fputs("\n#---------------------------------------------\n", fp);
+ fputs("# TASKS\n", fp);
+ fputs("#---------------------------------------------\n", fp);
+ fprintf(fp, "task_centered = %d\n", g_task.centered);
+ fprintf(fp, "task_width = %d\n", g_task.maximum_width);
+ fprintf(fp, "task_padding = %d\n", g_task.area.paddingx);
+ fprintf(fp, "task_icon = %d\n", g_task.icon);
+ fprintf(fp, "task_font = %s\n", panel.old_task_font);
+ fprintf(fp, "task_font_color = #%02x%02x%02x %d\n", (int)(g_task.font.color[0]*255), (int)(g_task.font.color[1]*255), (int)(g_task.font.color[2]*255), (int)(g_task.font.alpha*100));
+ fprintf(fp, "task_active_font_color = #%02x%02x%02x %d\n", (int)(g_task.font_active.color[0]*255), (int)(g_task.font_active.color[1]*255), (int)(g_task.font_active.color[2]*255), (int)(g_task.font_active.alpha*100));
+
+ fputs("\n#---------------------------------------------\n", fp);
+ fputs("# TASK BACKGROUND AND BORDER\n", fp);
+ fputs("#---------------------------------------------\n", fp);
+ fprintf(fp, "task_rounded = %d\n", g_task.area.border.rounded);
+ fprintf(fp, "task_background_color = #%02x%02x%02x %d\n", (int)(g_task.area.back.color[0]*255), (int)(g_task.area.back.color[1]*255), (int)(g_task.area.back.color[2]*255), (int)(g_task.area.back.alpha*100));
+ fprintf(fp, "task_active_background_color = #%02x%02x%02x %d\n", (int)(g_task.area_active.back.color[0]*255), (int)(g_task.area_active.back.color[1]*255), (int)(g_task.area_active.back.color[2]*255), (int)(g_task.area_active.back.alpha*100));
+ fprintf(fp, "task_border_width = %d\n", g_task.area.border.width);
+ fprintf(fp, "task_border_color = #%02x%02x%02x %d\n", (int)(g_task.area.border.color[0]*255), (int)(g_task.area.border.color[1]*255), (int)(g_task.area.border.color[2]*255), (int)(g_task.area.border.alpha*100));
+ fprintf(fp, "task_active_border_color = #%02x%02x%02x %d\n", (int)(g_task.area_active.border.color[0]*255), (int)(g_task.area_active.border.color[1]*255), (int)(g_task.area_active.border.color[2]*255), (int)(g_task.area_active.border.alpha*100));
+
+ fputs("\n#---------------------------------------------\n", fp);
+ fputs("# CLOCK\n", fp);
+ fputs("#---------------------------------------------\n", fp);
+ fputs("#time1_format = %H:%M\n", fp);
+ fputs("time1_font = sans bold 8\n", fp);
+ fputs("#time2_format = %A %d %B\n", fp);
+ fputs("time2_font = sans 6\n", fp);
+ fputs("clock_font_color = #ffffff 75\n", fp);
+
+ fputs("\n#---------------------------------------------\n", fp);
+ fputs("# MOUSE ACTION ON TASK\n", fp);
+ fputs("#---------------------------------------------\n", fp);
+ if (panel.mouse_middle == NONE) fputs("mouse_middle = none\n", fp);
+ else if (panel.mouse_middle == CLOSE) fputs("mouse_middle = close\n", fp);
+ else if (panel.mouse_middle == TOGGLE) fputs("mouse_middle = toggle\n", fp);
+ else if (panel.mouse_middle == ICONIFY) fputs("mouse_middle = iconify\n", fp);
+ else if (panel.mouse_middle == SHADE) fputs("mouse_middle = shade\n", fp);
+ else fputs("mouse_middle = toggle_iconify\n", fp);
+
+ if (panel.mouse_right == NONE) fputs("mouse_right = none\n", fp);
+ else if (panel.mouse_right == CLOSE) fputs("mouse_right = close\n", fp);
+ else if (panel.mouse_right == TOGGLE) fputs("mouse_right = toggle\n", fp);
+ else if (panel.mouse_right == ICONIFY) fputs("mouse_right = iconify\n", fp);
+ else if (panel.mouse_right == SHADE) fputs("mouse_right = shade\n", fp);
+ else fputs("mouse_right = toggle_iconify\n", fp);
+
+ if (panel.mouse_scroll_up == NONE) fputs("mouse_scroll_up = none\n", fp);
+ else if (panel.mouse_scroll_up == CLOSE) fputs("mouse_scroll_up = close\n", fp);
+ else if (panel.mouse_scroll_up == TOGGLE) fputs("mouse_scroll_up = toggle\n", fp);
+ else if (panel.mouse_scroll_up == ICONIFY) fputs("mouse_scroll_up = iconify\n", fp);
+ else if (panel.mouse_scroll_up == SHADE) fputs("mouse_scroll_up = shade\n", fp);
+ else fputs("mouse_scroll_up = toggle_iconify\n", fp);
+
+ if (panel.mouse_scroll_down == NONE) fputs("mouse_scroll_down = none\n", fp);
+ else if (panel.mouse_scroll_down == CLOSE) fputs("mouse_scroll_down = close\n", fp);
+ else if (panel.mouse_scroll_down == TOGGLE) fputs("mouse_scroll_down = toggle\n", fp);
+ else if (panel.mouse_scroll_down == ICONIFY) fputs("mouse_scroll_down = iconify\n", fp);
+ else if (panel.mouse_scroll_down == SHADE) fputs("mouse_scroll_down = shade\n", fp);
+ else fputs("mouse_scroll_down = toggle_iconify\n", fp);
+
+ fputs("\n\n", fp);
+ fclose (fp);
+
+ panel.old_config_file = 0;
+}
+
--- /dev/null
+/**************************************************************************
+* config :
+* - parse config file in Panel struct.
+*
+* Check COPYING file for Copyright
+*
+**************************************************************************/
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+GSList *list_back;
+
+
+int config_read_file (const char *path);
+int config_read ();
+void config_taskbar();
+void config_finish ();
+void cleanup_taskbar();
+void cleanup ();
+void save_config ();
+
+#endif
--- /dev/null
+/**************************************************************************
+*
+* Copyright (C) 2008 Pål Staurland (staura@gmail.com)
+* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <cairo.h>
+#include <cairo-xlib.h>
+#include <pango/pangocairo.h>
+
+#include "server.h"
+#include "window.h"
+#include "task.h"
+#include "panel.h"
+
+
+void visual_refresh ()
+{
+ server_refresh_root_pixmap ();
+
+ draw (&panel.area);
+ refresh (&panel.area);
+
+/*
+pour version 0.7
+gestion du systray
+ positionnement et taille fixe du systray (objet systray)
+ détection des notifications (détection des icones, ajout a la liste)
+ ajouter la transparence des icones
+ gérer le redimentionnement des éléments
+ => voir si lon peut faire abstraction sur le positionnement des objets ?
+ sachant que certains objets (task, taskbar) on une taille définit par l'extérieur
+ et d'autres objets (clock, systray) on une taille définit par l'intérieur
+
+gestion du layout
+ voir le positionnement des taskbar, task et systray
+ définir panel_layout dans la configuration
+ comment gérer le multi panel avec des layouts différents
+
+vérifier le niveau d'abstraction du code
+ utiliser la fonction draw(obj) récurrente sur Taskbar, Task, Systray, Clock
+ est ce compatible avec l'affichage de la tache active et les changement de taille -> redessine le panel
+
+correction de bugs :
+ memory, segfault
+ background
+ remettre en place single_desktop avec nouveau layout
+ remettre en place multi_monitor avec nouveau layout
+ vérifier le changement de configuration
+
+pour version 0.8
+gestion du thème
+ voir la gestion du dégradé sur le bord et le fond (inkscape)
+ faut-il trois coordonnées de padding x, y, x inter-objects
+
+gestion du zoom
+ définir le zoom du panel
+
+*/
+
+ if (panel.clock.time1_format) {
+ if (panel.clock.area.redraw)
+ panel.refresh = 1;
+ if (draw (&panel.clock.area)) {
+ panel.clock.area.redraw = 1;
+ draw (&panel.clock.area);
+ resize_clock();
+ resize_taskbar();
+ redraw(&panel.area);
+ }
+ refresh (&panel.clock.area);
+ }
+
+ // TODO: ne pas afficher les taskbar invisibles
+ //if (panel.mode != MULTI_DESKTOP && desktop != server.desktop) continue;
+ Task *tsk;
+ Taskbar *tskbar;
+ GSList *l0;
+ for (l0 = panel.area.list; l0 ; l0 = l0->next) {
+ tskbar = l0->data;
+ draw (&tskbar->area);
+ refresh (&tskbar->area);
+
+ GSList *l1;
+ for (l1 = tskbar->area.list; l1 ; l1 = l1->next) {
+ tsk = l1->data;
+ draw(&tsk->area);
+
+ if (tsk == panel.task_active) refresh (&tsk->area_active);
+ else refresh (&tsk->area);
+ }
+ }
+
+ XCopyArea (server.dsp, server.pmap, window.main_win, server.gc, 0, 0, panel.area.width, panel.area.height, 0, 0);
+ XFlush(server.dsp);
+ panel.refresh = 0;
+}
+
+
+void set_panel_properties (Window win)
+{
+ XStoreName (server.dsp, win, "tint2");
+
+ // TODO: check if the name is really needed for a panel/taskbar ?
+ gsize len;
+ gchar *name = g_locale_to_utf8("tint2", -1, NULL, &len, NULL);
+ if (name != NULL) {
+ XChangeProperty(server.dsp, win, server.atom._NET_WM_NAME, server.atom.UTF8_STRING, 8, PropModeReplace, (unsigned char *) name, (int) len);
+ g_free(name);
+ }
+
+ // Dock
+ long val = server.atom._NET_WM_WINDOW_TYPE_DOCK;
+ XChangeProperty (server.dsp, win, server.atom._NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &val, 1);
+
+ // Reserved space
+ long struts [12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ if (panel.position & TOP) {
+ struts[2] = panel.area.height + panel.marginy;
+ struts[8] = server.posx;
+ struts[9] = server.posx + panel.area.width;
+ }
+ else {
+ struts[3] = panel.area.height + panel.marginy;
+ struts[10] = server.posx;
+ struts[11] = server.posx + panel.area.width;
+ }
+ XChangeProperty (server.dsp, win, server.atom._NET_WM_STRUT_PARTIAL, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &struts, 12);
+ // Old specification
+ XChangeProperty (server.dsp, win, server.atom._NET_WM_STRUT, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &struts, 4);
+
+ // Sticky and below other window
+ val = 0xFFFFFFFF;
+ XChangeProperty (server.dsp, win, server.atom._NET_WM_DESKTOP, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &val, 1);
+ Atom state[4];
+ state[0] = server.atom._NET_WM_STATE_SKIP_PAGER;
+ state[1] = server.atom._NET_WM_STATE_SKIP_TASKBAR;
+ state[2] = server.atom._NET_WM_STATE_STICKY;
+ state[3] = server.atom._NET_WM_STATE_BELOW;
+ XChangeProperty (server.dsp, win, server.atom._NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) state, 4);
+
+ // Fixed position
+ XSizeHints size_hints;
+ size_hints.flags = PPosition;
+ XChangeProperty (server.dsp, win, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, 32, PropModeReplace, (unsigned char *) &size_hints, sizeof (XSizeHints) / 4);
+
+ // Unfocusable
+ XWMHints wmhints;
+ wmhints.flags = InputHint;
+ wmhints.input = False;
+ XChangeProperty (server.dsp, win, XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace, (unsigned char *) &wmhints, sizeof (XWMHints) / 4);
+}
+
+
+void window_draw_panel ()
+{
+ Window win;
+
+ /* panel position determined here */
+ if (panel.position & LEFT) server.posx = server.monitor[panel.monitor].x + panel.marginx;
+ else {
+ if (panel.position & RIGHT) server.posx = server.monitor[panel.monitor].x + server.monitor[panel.monitor].width - panel.area.width - panel.marginx;
+ else server.posx = server.monitor[panel.monitor].x + ((server.monitor[panel.monitor].width - panel.area.width) / 2);
+ }
+ if (panel.position & TOP) server.posy = server.monitor[panel.monitor].y + panel.marginy;
+ else server.posy = server.monitor[panel.monitor].y + server.monitor[panel.monitor].height - panel.area.height - panel.marginy;
+
+ /* Catch some events */
+ XSetWindowAttributes att = { ParentRelative, 0L, 0, 0L, 0, 0, Always, 0L, 0L, False, ExposureMask|ButtonPressMask|ButtonReleaseMask, NoEventMask, False, 0, 0 };
+
+ /* XCreateWindow(display, parent, x, y, w, h, border, depth, class, visual, mask, attrib) */
+ if (window.main_win) XDestroyWindow(server.dsp, window.main_win);
+ win = XCreateWindow (server.dsp, server.root_win, server.posx, server.posy, panel.area.width, panel.area.height, 0, server.depth, InputOutput, CopyFromParent, CWEventMask, &att);
+
+ set_panel_properties (win);
+ window.main_win = win;
+
+ // replaced : server.gc = DefaultGC (server.dsp, 0);
+ if (server.gc) XFree(server.gc);
+ XGCValues gcValues;
+ server.gc = XCreateGC(server.dsp, win, (unsigned long) 0, &gcValues);
+
+ XMapWindow (server.dsp, win);
+ XFlush (server.dsp);
+}
+
+
+void resize_clock()
+{
+ panel.clock.area.posx = panel.area.width - panel.clock.area.width - panel.area.paddingx - panel.area.border.width;
+}
+
+
+// initialise taskbar posx and width
+void resize_taskbar()
+{
+ int taskbar_width, modulo_width, taskbar_on_screen;
+
+ if (panel.mode == MULTI_DESKTOP) taskbar_on_screen = panel.nb_desktop;
+ else taskbar_on_screen = panel.nb_monitor;
+
+ taskbar_width = panel.area.width - (2 * panel.area.paddingx) - (2 * panel.area.border.width);
+ if (panel.clock.time1_format)
+ taskbar_width -= (panel.clock.area.width + panel.area.paddingx);
+ taskbar_width = (taskbar_width - ((taskbar_on_screen-1) * panel.area.paddingx)) / taskbar_on_screen;
+
+ if (taskbar_on_screen > 1)
+ modulo_width = (taskbar_width - ((taskbar_on_screen-1) * panel.area.paddingx)) % taskbar_on_screen;
+ else
+ modulo_width = 0;
+
+ int posx, modulo, i;
+ Taskbar *tskbar;
+ GSList *l0;
+ for (i = 0, l0 = panel.area.list; l0 ; i++, l0 = l0->next) {
+ if ((i % taskbar_on_screen) == 0) {
+ posx = panel.area.border.width + panel.area.paddingx;
+ modulo = modulo_width;
+ }
+ else posx += taskbar_width + panel.area.paddingx;
+
+ tskbar = l0->data;
+ tskbar->area.posx = posx;
+ tskbar->area.width = taskbar_width;
+ if (modulo) {
+ tskbar->area.width++;
+ modulo--;
+ }
+
+ resize_tasks(tskbar);
+ }
+}
+
+
--- /dev/null
+/**************************************************************************
+* panel :
+* - draw panel and all objects according to panel_layout
+*
+* Check COPYING file for Copyright
+*
+**************************************************************************/
+
+#ifndef PANEL_H
+#define PANEL_H
+
+#include <pango/pangocairo.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "clock.h"
+#include "task.h"
+#include "taskbar.h"
+
+
+//panel mode
+enum { SINGLE_DESKTOP=0, MULTI_DESKTOP, MULTI_MONITOR };
+
+//panel alignment
+enum { LEFT=0x01, RIGHT=0x02, CENTER=0X04, TOP=0X08, BOTTOM=0x10 };
+
+
+typedef struct {
+ // --------------------------------------------------
+ // always start with area
+ Area area;
+
+ // --------------------------------------------------
+ // backward compatibility
+ int old_config_file;
+ int old_task_icon;
+ int old_panel_background;
+ int old_task_background;
+ char *old_task_font;
+
+ // --------------------------------------------------
+ // panel
+ int signal_pending;
+ int sleep_mode;
+ int refresh;
+ int monitor;
+ int position;
+ int marginx, marginy;
+
+ // --------------------------------------------------
+ // taskbar point to the first taskbar in panel.area.list. number of tasbar == nb_desktop x nb_monitor.
+ //Taskbar *taskbar;
+ int mode;
+ int nb_desktop;
+ int nb_monitor;
+ Task *task_active;
+ Task *task_drag;
+
+ // --------------------------------------------------
+ // clock
+ Clock clock;
+
+ // --------------------------------------------------
+ // systray
+
+ // --------------------------------------------------
+ // mouse events
+ int mouse_middle;
+ int mouse_right;
+ int mouse_scroll_up;
+ int mouse_scroll_down;
+} Panel;
+
+
+Panel panel;
+
+
+void visual_refresh ();
+void set_panel_properties (Window win);
+void window_draw_panel ();
+void resize_clock();
+void resize_taskbar();
+
+
+#endif
--- /dev/null
+/**************************************************************************
+*
+* Tint2 panel
+*
+* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
+* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "server.h"
+#include "panel.h"
+#include "task.h"
+#include "window.h"
+
+void server_catch_error (Display *d, XErrorEvent *ev){}
+
+
+void server_init_atoms ()
+{
+ server.atom._XROOTPMAP_ID = XInternAtom (server.dsp, "_XROOTPMAP_ID", False);
+ server.atom._NET_CURRENT_DESKTOP = XInternAtom (server.dsp, "_NET_CURRENT_DESKTOP", False);
+ server.atom._NET_NUMBER_OF_DESKTOPS = XInternAtom (server.dsp, "_NET_NUMBER_OF_DESKTOPS", False);
+ server.atom._NET_DESKTOP_GEOMETRY = XInternAtom (server.dsp, "_NET_DESKTOP_GEOMETRY", False);
+ server.atom._NET_DESKTOP_VIEWPORT = XInternAtom (server.dsp, "_NET_DESKTOP_VIEWPORT", False);
+ server.atom._NET_ACTIVE_WINDOW = XInternAtom (server.dsp, "_NET_ACTIVE_WINDOW", False);
+ server.atom._NET_WM_WINDOW_TYPE = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE", False);
+ server.atom._NET_WM_STATE_SKIP_PAGER = XInternAtom (server.dsp, "_NET_WM_STATE_SKIP_PAGER", False);
+ server.atom._NET_WM_STATE_SKIP_TASKBAR = XInternAtom (server.dsp, "_NET_WM_STATE_SKIP_TASKBAR", False);
+ server.atom._NET_WM_STATE_STICKY = XInternAtom (server.dsp, "_NET_WM_STATE_STICKY", False);
+ server.atom._NET_WM_WINDOW_TYPE_DOCK = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE_DOCK", False);
+ server.atom._NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
+ server.atom._NET_WM_WINDOW_TYPE_TOOLBAR = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
+ server.atom._NET_WM_WINDOW_TYPE_MENU = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE_MENU", False);
+ server.atom._NET_WM_WINDOW_TYPE_SPLASH = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE_SPLASH", False);
+ server.atom._NET_WM_WINDOW_TYPE_DIALOG = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ server.atom._NET_WM_WINDOW_TYPE_NORMAL = XInternAtom (server.dsp, "_NET_WM_WINDOW_TYPE_NORMAL", False);
+ server.atom._NET_WM_DESKTOP = XInternAtom (server.dsp, "_NET_WM_DESKTOP", False);
+ server.atom.WM_STATE = XInternAtom (server.dsp, "WM_STATE", False);
+ server.atom._NET_WM_STATE = XInternAtom (server.dsp, "_NET_WM_STATE", False);
+ server.atom._NET_WM_STATE_SHADED = XInternAtom (server.dsp, "_NET_WM_STATE_SHADED", False);
+ server.atom._NET_WM_STATE_BELOW = XInternAtom (server.dsp, "_NET_WM_STATE_BELOW", False);
+ server.atom._NET_WM_STATE_MODAL = XInternAtom (server.dsp, "_NET_WM_STATE_MODAL", False);
+ server.atom._NET_CLIENT_LIST = XInternAtom (server.dsp, "_NET_CLIENT_LIST", False);
+ server.atom._NET_WM_VISIBLE_NAME = XInternAtom (server.dsp, "_NET_WM_VISIBLE_NAME", False);
+ server.atom._NET_WM_NAME = XInternAtom (server.dsp, "_NET_WM_NAME", False);
+ server.atom._NET_WM_STRUT = XInternAtom (server.dsp, "_NET_WM_STRUT", False);
+ server.atom._NET_WM_ICON = XInternAtom (server.dsp, "_NET_WM_ICON", False);
+ server.atom._NET_CLOSE_WINDOW = XInternAtom (server.dsp, "_NET_CLOSE_WINDOW", False);
+ server.atom.UTF8_STRING = XInternAtom (server.dsp, "UTF8_STRING", False);
+ server.atom._NET_SUPPORTING_WM_CHECK = XInternAtom (server.dsp, "_NET_SUPPORTING_WM_CHECK", False);
+ server.atom._NET_SUPPORTING_WM_CHECK = XInternAtom (server.dsp, "_NET_WM_NAME", False);
+ server.atom._WIN_LAYER = XInternAtom (server.dsp, "_WIN_LAYER", False);
+ server.atom._NET_WM_STRUT_PARTIAL = XInternAtom (server.dsp, "_NET_WM_STRUT_PARTIAL", False);
+ server.atom.WM_NAME = XInternAtom(server.dsp, "WM_NAME", False);
+}
+
+
+void send_event32 (Window win, Atom at, long data1, long data2)
+{
+ XEvent event;
+
+ event.xclient.type = ClientMessage;
+ event.xclient.serial = 0;
+ event.xclient.send_event = True;
+ event.xclient.display = server.dsp;
+ event.xclient.window = win;
+ event.xclient.message_type = at;
+
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = data1;
+ event.xclient.data.l[1] = data2;
+ event.xclient.data.l[2] = 0;
+ event.xclient.data.l[3] = 0;
+ event.xclient.data.l[4] = 0;
+
+ XSendEvent(server.dsp, server.root_win, False, SubstructureRedirectMask|SubstructureNotifyMask, &event);
+}
+
+
+int get_property32 (Window win, Atom at, Atom type)
+{
+ Atom type_ret;
+ int format_ret = 0, data = 0;
+ unsigned long nitems_ret = 0;
+ unsigned long bafter_ret = 0;
+ unsigned char *prop_value = 0;
+ int result;
+
+ if (!win) return 0;
+
+ result = XGetWindowProperty(server.dsp, win, at, 0, 0x7fffffff, False, type, &type_ret, &format_ret, &nitems_ret, &bafter_ret, &prop_value);
+
+ if (result == Success && prop_value) {
+ data = ((gulong*)prop_value)[0];
+ XFree (prop_value);
+ }
+ return data;
+}
+
+
+void *server_get_property (Window win, Atom at, Atom type, int *num_results)
+{
+ Atom type_ret;
+ int format_ret = 0;
+ unsigned long nitems_ret = 0;
+ unsigned long bafter_ret = 0;
+ unsigned char *prop_value;
+ int result;
+
+ if (!win) return 0;
+
+ result = XGetWindowProperty(server.dsp, win, at, 0, 0x7fffffff, False, type, &type_ret, &format_ret, &nitems_ret, &bafter_ret, &prop_value);
+
+ /* Send back resultcount */
+ if (num_results) *num_results = nitems_ret;
+
+ if (result == Success && prop_value) return prop_value;
+ else return 0;
+}
+
+
+Pixmap get_root_pixmap ()
+{
+ // conky capture correctement le fond d'écran en xlib !!
+ Pixmap root_pixmap;
+ unsigned long *res;
+
+ res = server_get_property (server.root_win, server.atom._XROOTPMAP_ID, XA_PIXMAP, 0);
+ if (res) {
+ root_pixmap = *((Drawable*) res);
+ XFree(res);
+ return root_pixmap;
+ }
+ else {
+ printf("get_root_pixmap incorrect\n");
+ // try _XSETROOT_ID
+ }
+
+ return 0;
+}
+
+
+
+
+Pixmap server_create_pixmap (int width, int height)
+{
+ return XCreatePixmap (server.dsp, server.root_win, width, height, server.depth);
+}
+
+
+void server_refresh_root_pixmap ()
+{
+ if (!server.root_pmap) {
+ Pixmap wall = get_root_pixmap();
+
+ server.root_pmap = server_create_pixmap (panel.area.width, panel.area.height);
+
+ XCopyArea (server.dsp, wall, server.root_pmap, server.gc, server.posx, server.posy, panel.area.width, panel.area.height, 0, 0);
+
+ panel.area.redraw = 1;
+ }
+
+ if (server.pmap) XFreePixmap (server.dsp, server.pmap);
+ server.pmap = server_create_pixmap (panel.area.width, panel.area.height);
+
+ XCopyArea (server.dsp, server.root_pmap, server.pmap, server.gc, 0, 0, panel.area.width, panel.area.height, 0, 0);
+}
+
+
+void get_monitors()
+{
+ if (server.monitor) free(server.monitor);
+ server.nb_monitor = 0;
+ server.monitor = 0;
+
+ if (XineramaIsActive(server.dsp)) {
+ XineramaScreenInfo *info = XineramaQueryScreens(server.dsp, &server.nb_monitor);
+
+ if (info) {
+ int i;
+
+ server.monitor = calloc(server.nb_monitor, sizeof(Monitor));
+ for (i = 0; i < server.nb_monitor; i++) {
+ server.monitor[i].x = info[i].x_org;
+ server.monitor[i].y = info[i].y_org;
+ server.monitor[i].width = info[i].width;
+ server.monitor[i].height = info[i].height;
+ }
+ XFree(info);
+ }
+ }
+
+ if (!server.nb_monitor) {
+ server.nb_monitor = 1;
+ server.monitor = calloc(server.nb_monitor, sizeof(Monitor));
+ server.monitor[0].x = server.monitor[0].y = 0;
+ server.monitor[0].width = DisplayWidth (server.dsp, server.screen);
+ server.monitor[0].height = DisplayHeight (server.dsp, server.screen);
+ }
+}
+
+
--- /dev/null
+/**************************************************************************
+* server :
+* -
+*
+* Check COPYING file for Copyright
+*
+**************************************************************************/
+
+#ifndef SERVER_H
+#define SERVER_H
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/Xinerama.h>
+
+
+typedef struct Global_atom
+{
+ Atom _XROOTPMAP_ID;
+ Atom _NET_CURRENT_DESKTOP;
+ Atom _NET_NUMBER_OF_DESKTOPS;
+ Atom _NET_DESKTOP_GEOMETRY;
+ Atom _NET_DESKTOP_VIEWPORT;
+ Atom _NET_ACTIVE_WINDOW;
+ Atom _NET_WM_WINDOW_TYPE;
+ Atom _NET_WM_STATE_SKIP_PAGER;
+ Atom _NET_WM_STATE_SKIP_TASKBAR;
+ Atom _NET_WM_STATE_STICKY;
+ Atom _NET_WM_WINDOW_TYPE_DOCK;
+ Atom _NET_WM_WINDOW_TYPE_DESKTOP;
+ Atom _NET_WM_WINDOW_TYPE_TOOLBAR;
+ Atom _NET_WM_WINDOW_TYPE_MENU;
+ Atom _NET_WM_WINDOW_TYPE_SPLASH;
+ Atom _NET_WM_WINDOW_TYPE_DIALOG;
+ Atom _NET_WM_WINDOW_TYPE_NORMAL;
+ Atom _NET_WM_DESKTOP;
+ Atom WM_STATE;
+ Atom _NET_WM_STATE;
+ Atom _NET_WM_STATE_SHADED;
+ Atom _NET_WM_STATE_BELOW;
+ Atom _NET_WM_STATE_MODAL;
+ Atom _NET_CLIENT_LIST;
+ Atom _NET_WM_NAME;
+ Atom _NET_WM_VISIBLE_NAME;
+ Atom _NET_WM_STRUT;
+ Atom _NET_WM_ICON;
+ Atom _NET_CLOSE_WINDOW;
+ Atom UTF8_STRING;
+ Atom _NET_SUPPORTING_WM_CHECK;
+ Atom _WIN_LAYER;
+ Atom _NET_WM_STRUT_PARTIAL;
+ Atom WM_NAME;
+} Global_atom;
+
+
+
+typedef struct Monitor
+{
+ int x;
+ int y;
+ int width;
+ int height;
+} Monitor;
+
+
+typedef struct
+{
+ Display *dsp;
+ Window root_win;
+ int desktop;
+ int screen;
+ int depth;
+ int nb_desktop;
+ Monitor *monitor;
+ int nb_monitor;
+ int got_root_win;
+ Visual *visual;
+ int posx, posy;
+ Pixmap pmap;
+ Pixmap root_pmap;
+ GC gc;
+ Global_atom atom;
+} Server_global;
+
+
+Server_global server;
+
+
+void send_event32 (Window win, Atom at, long data1, long data2);
+int get_property32 (Window win, Atom at, Atom type);
+void *server_get_property (Window win, Atom at, Atom type, int *num_results);
+Atom server_get_atom (char *atom_name);
+void server_refresh_root_pixmap ();
+void server_refresh_main_pixmap ();
+void server_catch_error (Display *d, XErrorEvent *ev);
+void server_init_atoms ();
+Pixmap server_create_pixmap (int width, int height);
+void get_monitors();
+
+
+#endif
--- /dev/null
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# #
+# Change these values to customize your installation and build process #
+# #
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+
+# Change this PREFIX to where you want docker to be installed
+PREFIX=/usr/local
+# Change this XLIBPATH to point to your X11 development package's installation
+XLIBPATH=/usr/X11R6/lib
+
+# Sets some flags for stricter compiling
+CFLAGS=-pedantic -Wall -W -O
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# #
+# Leave the rest of the Makefile alone if you want it to build! #
+# #
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+
+PACKAGE=docker
+VERSION=1.5
+
+target=docker
+sources=docker.c kde.c icons.c xproperty.c net.c
+headers=docker.h kde.h icons.h xproperty.h net.h version.h
+extra=README COPYING version.h.in
+
+all: $(target) $(sources) $(headers)
+ @echo Build Successful
+
+$(target): $(sources:.c=.o)
+ $(CC) $(CFLAGS) -L$(XLIBPATH) -lX11 \
+ `pkg-config --libs glib-2.0` $^ -o $@
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` $<
+
+version.h: version.h.in Makefile
+ sed -e "s/@VERSION@/$(VERSION)/" version.h.in > $@
+
+install: all
+ install $(target) $(PREFIX)/bin/$(target)
+
+uninstall:
+ rm -f $(PREFIX)/$(target)
+
+clean:
+ rm -rf .dist
+ rm -f core *.o .\#* *\~ $(target)
+
+distclean: clean
+ rm -f version.h
+ rm -f $(PACKAGE)-*.tar.gz
+
+dist: Makefile $(sources) $(headers) $(extra)
+ mkdir -p .dist/$(PACKAGE)-$(VERSION) && \
+ cp $^ .dist/$(PACKAGE)-$(VERSION) && \
+ tar -c -z -C .dist -f \
+ $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION) && \
+ rm -rf .dist
+
+love: $(sources)
+ touch $^
+
+# local dependancies
+docker.o: docker.c version.h kde.h icons.h docker.h net.h
+icons.o: icons.c icons.h docker.h
+kde.o: kde.c kde.h docker.h xproperty.h
+net.o: net.c net.h docker.h icons.h
+xproperty.o: xproperty.c xproperty.h docker.h
--- /dev/null
+Docker - Docking System Tray
+
+Copyright (C) 2003 Ben Jansens
+
+
+What is Docker?
+
+Docker is a docking application (WindowMaker dock app) which acts as a system
+tray for KDE3 and GNOME2. It can be used to replace the panel in either
+environment, allowing you to have a system tray without running the KDE/GNOME
+panel.
+
+
+What window managers can I use Docker with?
+
+I wrote and designed Docker to work with Openbox 2, but it should work fine in
+any window manager that supports WindowMaker dock apps.
+
+
+Why don't my KDE3 system tray icons show up?
+
+Docker requires a KDE3 compliant window manager to handle KDE3 system tray
+icons, and since it is a docking application, the window manager needs to also
+support WindowMaker Dock Apps. The only window manager that meets these
+requirements to my knowledge is:
+ - Openbox 2 (http://icculus.org/openbox)
+If you know of any other window managers that support the KDE3 hints for the
+system tray and docking apps (i.e. that docker works in), please let me know so
+I can add them to this list, and test docker out in them!
+
+
+Why don't my GNOME2 system tray icons show up?
+
+I don't know! Email me and let me know what application isn't working. (Don't
+you dare email me about a GNOME1 application! :)
+
+
+Who wrote Docker?
+
+Me, of course. That is, Ben Jansens. I can be reached at <ben@orodu.net>. I am
+the founder and currently the project head of sorts for the Openbox project.
+
+
+===============================
+|| INSTALLATION INSTRUCTIONS ||
+===============================
+
+To install this application, simply do the following:
+
+% make
+(as root)
+# make install
+
+You can change a couple of things in the Makefile if you want to:
+PREFIX defines where the program will be installed to.
+XLIBPATH defines where your libX11.so is located. If it is not on the standard
+ /usr/X11R6/lib path, then you will have to change this.
+
+==================
+|| LICENSE INFO ||
+==================
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--- /dev/null
+#include "version.h"
+#include "kde.h"
+#include "icons.h"
+#include "docker.h"
+#include "net.h"
+
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <X11/Xutil.h>
+
+int argc;
+char **argv;
+
+Window win = None, hint_win = None, root = None;
+gboolean wmaker = FALSE; /* WindowMakerMode!!! wheeee */
+Display *display = NULL;
+GSList *icons = NULL;
+int width = 0, height = 0;
+int border = 1; /* blank area around icons. must be > 0 */
+gboolean horizontal = TRUE; /* layout direction */
+int icon_size = 24; /* width and height of systray icons */
+
+//static char *display_string = NULL;
+/* excluding the border. sum of all child apps */
+static gboolean exit_app = FALSE;
+
+/*
+void parse_cmd_line()
+{
+ int i;
+ gboolean help = FALSE;
+
+ for (i = 1; i < argc; i++) {
+ if (0 == strcasecmp(argv[i], "-display")) {
+ ++i;
+ if (i < argc) {
+ display_string = argv[i];
+ } else {
+ g_printerr("-display requires a parameter\n");
+ help = TRUE;
+ }
+ } else if (0 == strcasecmp(argv[i], "-wmaker")) {
+ wmaker = TRUE;
+ } else if (0 == strcasecmp(argv[i], "-vertical")) {
+ horizontal = FALSE;
+ } else if (0 == strcasecmp(argv[i], "-border")) {
+ ++i;
+
+ if (i < argc) {
+ int b = atoi(argv[i]);
+ if (b > 0) {
+ border = b;
+ } else {
+ g_printerr("-border must be a value greater than 0\n");
+ help = TRUE;
+ }
+ } else {
+ g_printerr("-border requires a parameter\n");
+ help = TRUE;
+ }
+ } else if (0 == strcasecmp(argv[i], "-iconsize")) {
+ ++i;
+ if (i < argc) {
+ int s = atoi(argv[i]);
+ if (s > 0) {
+ icon_size = s;
+ } else {
+ g_printerr("-iconsize must be a value greater than 0\n");
+ help = TRUE;
+ }
+ } else {
+ g_printerr("-iconsize requires a parameter\n");
+ help = TRUE;
+ }
+ } else {
+ if (argv[i][0] == '-')
+ help = TRUE;
+ }
+
+
+ if (help) {
+
+ g_print("%s - version %s\n", argv[0], VERSION);
+ g_print("Copyright 2003, Ben Jansens <ben@orodu.net>\n\n");
+ g_print("Usage: %s [OPTIONS]\n\n", argv[0]);
+ g_print("Options:\n");
+ g_print(" -help Show this help.\n");
+ g_print(" -display DISLPAY The X display to connect to.\n");
+ g_print(" -border The width of the border to put around the\n"
+ " system tray icons. Defaults to 1.\n");
+ g_print(" -vertical Line up the icons vertically. Defaults to\n"
+ " horizontally.\n");
+ g_print(" -wmaker WindowMaker mode. This makes docker a\n"
+ " fixed size (64x64) to appear nicely in\n"
+ " in WindowMaker.\n"
+ " Note: In this mode, you have a fixed\n"
+ " number of icons that docker can hold.\n");
+ g_print(" -iconsize SIZE The size (width and height) to display\n"
+ " icons as in the system tray. Defaults to\n"
+ " 24.\n");
+ exit(1);
+ }
+ }
+}
+*/
+
+void create_hint_win()
+{
+ XWMHints hints;
+ XClassHint classhints;
+
+ hint_win = XCreateSimpleWindow(display, root, 0, 0, 1, 1, 0, 0, 0);
+ assert(hint_win);
+
+ hints.flags = StateHint | WindowGroupHint | IconWindowHint;
+ hints.initial_state = WithdrawnState;
+ hints.window_group = hint_win;
+ hints.icon_window = win;
+
+ classhints.res_name = "docker";
+ classhints.res_class = "Docker";
+
+ XSetWMProperties(display, hint_win, NULL, NULL, argv, argc,
+ NULL, &hints, &classhints);
+
+ XMapWindow(display, hint_win);
+}
+
+
+void create_main_window()
+{
+ XWMHints hints;
+ XTextProperty text;
+ char *name = "Docker";
+
+ /* the border must be > 0 if not in wmaker mode */
+ assert(wmaker || border > 0);
+
+ if (!wmaker)
+ win = XCreateSimpleWindow(display, root, 0, 0,
+ border * 2, border * 2, 0, 0, 0);
+ else
+ win = XCreateSimpleWindow(display, root, 0, 0,
+ 64, 64, 0, 0, 0);
+
+ assert(win);
+
+ XStringListToTextProperty(&name, 1, &text);
+ XSetWMName(display, win, &text);
+
+ hints.flags = StateHint;
+ hints.initial_state = WithdrawnState;
+ XSetWMHints(display, win, &hints);
+
+ create_hint_win();
+
+ XSync(display, False);
+ XSetWindowBackgroundPixmap(display, win, ParentRelative);
+ XClearWindow(display, win);
+}
+
+
+void reposition_icons()
+{
+ int x = border + ((width % icon_size) / 2),
+ y = border + ((height % icon_size) / 2);
+ GSList *it;
+
+ for (it = icons; it != NULL; it = g_slist_next(it)) {
+ TrayWindow *traywin = it->data;
+ traywin->x = x;
+ traywin->y = y;
+ XMoveWindow(display, traywin->id, x, y);
+ XSync(display, False);
+ if (wmaker) {
+ x += icon_size;
+ if (x + icon_size > width) {
+ x = border;
+ y += icon_size;
+ }
+ } else if (horizontal)
+ x += icon_size;
+ else
+ y += icon_size;
+ }
+}
+
+
+void fix_geometry()
+{
+ GSList *it;
+
+ /* in wmaker mode we're a fixed size */
+ if (wmaker) return;
+
+ /* find the proper width and height */
+ width = horizontal ? 0 : icon_size;
+ height = horizontal ? icon_size : 0;
+ for (it = icons; it != NULL; it = g_slist_next(it)) {
+ if (horizontal)
+ width += icon_size;
+ else
+ height += icon_size;
+ }
+
+ XResizeWindow(display, win, width + border * 2, height + border * 2);
+}
+
+
+void event_loop()
+{
+ XEvent e;
+ Window cover;
+ GSList *it;
+
+ while (!exit_app) {
+ while (XPending(display)) {
+ XNextEvent(display, &e);
+
+ switch (e.type)
+ {
+ case PropertyNotify:
+ /* systray window list has changed? */
+ if (e.xproperty.atom == kde_systray_prop) {
+ XSelectInput(display, win, NoEventMask);
+ kde_update_icons();
+ XSelectInput(display, win, StructureNotifyMask);
+
+ while (XCheckTypedEvent(display, PropertyNotify, &e));
+ }
+
+ break;
+
+ case ConfigureNotify:
+ if (e.xany.window != win) {
+ /* find the icon it pertains to and beat it into submission */
+ GSList *it;
+
+ for (it = icons; it != NULL; it = g_slist_next(it)) {
+ TrayWindow *traywin = it->data;
+ if (traywin->id == e.xany.window) {
+ XMoveResizeWindow(display, traywin->id, traywin->x, traywin->y,
+ icon_size, icon_size);
+ break;
+ }
+ }
+ break;
+ }
+
+ /* briefly cover the entire containing window, which causes it and
+ all of the icons to refresh their windows. finally, they update
+ themselves when the background of the main window's parent changes.
+ */
+ cover = XCreateSimpleWindow(display, win, 0, 0,
+ border * 2 + width, border * 2 + height,
+ 0, 0, 0);
+ XMapWindow(display, cover);
+ XDestroyWindow(display, cover);
+
+ break;
+
+ case ReparentNotify:
+ if (e.xany.window == win) /* reparented to us */
+ break;
+ case UnmapNotify:
+ case DestroyNotify:
+ for (it = icons; it; it = g_slist_next(it)) {
+ if (((TrayWindow*)it->data)->id == e.xany.window) {
+ icon_remove(it);
+ break;
+ }
+ }
+ break;
+
+ case ClientMessage:
+ if (e.xclient.message_type == net_opcode_atom &&
+ e.xclient.format == 32 &&
+ e.xclient.window == net_sel_win)
+ net_message(&e.xclient);
+
+ default:
+ break;
+ }
+ }
+ usleep(500000);
+ }
+
+ /* remove/unparent all the icons */
+ while (icons) {
+ /* do the remove here explicitly, cuz the event handler isn't going to
+ happen anymore. */
+ icon_remove(icons);
+ }
+}
+
+/*
+int main(int c, char **v)
+{
+ struct sigaction act;
+
+ argc = c; argv = v;
+
+ act.sa_handler = signal_handler;
+ act.sa_flags = 0;
+ sigaction(SIGSEGV, &act, NULL);
+ sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGFPE, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGHUP, &act, NULL);
+
+ parse_cmd_line(argc, argv);
+
+ display = XOpenDisplay(display_string);
+ if (!display) {
+ g_printerr("Unable to open Display %s. Exiting.\n",
+ DisplayString(display_string));
+ }
+
+ root = RootWindow(display, DefaultScreen(display));
+ assert(root);
+
+ if (wmaker)
+ width = height = 64 - border * 2;
+
+ create_main_window();
+
+ // set up to find KDE systray icons, and get any that already exist
+ kde_init();
+
+ net_init();
+
+ // we want to get ConfigureNotify events, and assume our parent's background
+ // has changed when we do, so we need to refresh ourself to match
+ XSelectInput(display, win, StructureNotifyMask);
+
+ event_loop();
+
+ XCloseDisplay(display);
+
+ return 0;
+}
+*/
--- /dev/null
+#ifndef __docker_h
+#define __docker_h
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+extern Display *display;
+extern Window root, win;
+extern GSList *icons;
+extern int width, height;
+extern int border;
+extern gboolean horizontal;
+extern int icon_size;
+extern gboolean wmaker;
+
+typedef enum {
+ KDE = 1, /* kde specific */
+ NET /* follows the standard (freedesktop.org) */
+} TrayWindowType;
+
+typedef struct
+{
+ TrayWindowType type;
+ Window id;
+ int x, y;
+} TrayWindow;
+
+void reposition_icons();
+void fix_geometry();
+
+#endif /* __docker_h */
--- /dev/null
+#include "icons.h"
+#include "net.h"
+#include <assert.h>
+#include <stdlib.h>
+
+gboolean error;
+int window_error_handler(Display *d, XErrorEvent *e)
+{
+ d=d;e=e;
+ if (e->error_code == BadWindow) {
+ error = TRUE;
+ } else {
+ g_printerr("X ERROR NOT BAD WINDOW!\n");
+ abort();
+ }
+ return 0;
+}
+
+
+gboolean icon_swallow(TrayWindow *traywin)
+{
+ XErrorHandler old;
+
+ error = FALSE;
+ old = XSetErrorHandler(window_error_handler);
+ XReparentWindow(display, traywin->id, win, 0, 0);
+ XSync(display, False);
+ XSetErrorHandler(old);
+
+ return !error;
+}
+
+
+/*
+ The traywin must have its id and type set.
+*/
+gboolean icon_add(Window id, TrayWindowType type)
+{
+ TrayWindow *traywin;
+
+ assert(id);
+ assert(type);
+
+ if (wmaker) {
+ /* do we have room in our window for another icon? */
+ unsigned int max = (width / icon_size) * (height / icon_size);
+ if (g_slist_length(icons) >= max)
+ return FALSE; /* no room, sorry! REJECTED! */
+ }
+
+ traywin = g_new0(TrayWindow, 1);
+ traywin->type = type;
+ traywin->id = id;
+
+ if (!icon_swallow(traywin)) {
+ g_free(traywin);
+ return FALSE;
+ }
+
+ /* find the positon for the systray app window */
+ if (!wmaker) {
+ traywin->x = border + (horizontal ? width : 0);
+ traywin->y = border + (horizontal ? 0 : height);
+ } else {
+ int count = g_slist_length(icons);
+ traywin->x = border + ((width % icon_size) / 2) +
+ (count % (width / icon_size)) * icon_size;
+ traywin->y = border + ((height % icon_size) / 2) +
+ (count / (height / icon_size)) * icon_size;
+ }
+
+ /* add the new icon to the list */
+ icons = g_slist_append(icons, traywin);
+
+ /* watch for the icon trying to resize itself! BAD ICON! BAD! */
+ XSelectInput(display, traywin->id, StructureNotifyMask);
+
+ /* position and size the icon window */
+ XMoveResizeWindow(display, traywin->id,
+ traywin->x, traywin->y, icon_size, icon_size);
+
+ /* resize our window so that the new window can fit in it */
+ fix_geometry();
+
+ /* flush before clearing, otherwise the clear isn't effective. */
+ XFlush(display);
+ /* make sure the new child will get the right stuff in its background
+ for ParentRelative. */
+ XClearWindow(display, win);
+
+ /* show the window */
+ XMapRaised(display, traywin->id);
+
+ return TRUE;
+}
+
+
+void icon_remove(GSList *node)
+{
+ XErrorHandler old;
+ TrayWindow *traywin = node->data;
+ Window traywin_id = traywin->id;
+
+ if (traywin->type == NET)
+ net_icon_remove(traywin);
+
+ XSelectInput(display, traywin->id, NoEventMask);
+
+ /* remove it from our list */
+ g_free(node->data);
+ icons = g_slist_remove_link(icons, node);
+
+ /* reparent it to root */
+ error = FALSE;
+ old = XSetErrorHandler(window_error_handler);
+ XReparentWindow(display, traywin_id, root, 0, 0);
+ XSync(display, False);
+ XSetErrorHandler(old);
+
+ reposition_icons();
+ fix_geometry();
+}
--- /dev/null
+#ifndef __icons_h
+#define __icons_h
+
+#include <glib.h>
+#include <X11/Xlib.h>
+#include "docker.h"
+
+extern gboolean error;
+
+gboolean icon_add(Window id, TrayWindowType type);
+void icon_remove(GSList *node);
+
+#endif /* __icons_h */
--- /dev/null
+#include "kde.h"
+#include "icons.h"
+#include "docker.h"
+#include "xproperty.h"
+#include <assert.h>
+#include <X11/Xatom.h>
+
+Atom kde_systray_prop = None;
+
+void kde_init()
+{
+ kde_systray_prop = XInternAtom(display,
+ "_KDE_NET_SYSTEM_TRAY_WINDOWS", False);
+ assert(kde_systray_prop);
+
+ XSelectInput(display, root, PropertyChangeMask);
+ kde_update_icons();
+}
+
+void kde_update_icons()
+{
+ gulong count = (unsigned) -1; /* grab as many as possible */
+ Window *ids;
+ unsigned int i;
+ GSList *it, *next;
+ gboolean removed = FALSE; /* were any removed? */
+
+ if (! xprop_get32(root, kde_systray_prop, XA_WINDOW, sizeof(Window)*8,
+ &count, &ids))
+ return;
+
+ /* add new windows to our list */
+ for (i = 0; i < count; ++i) {
+ for (it = icons; it != NULL; it = g_slist_next(it)) {
+ TrayWindow *traywin = it->data;
+ if (traywin->id == ids[i])
+ break;
+ }
+ if (!it)
+ icon_add(ids[i], KDE);
+ }
+
+ /* remove windows from our list that no longer exist in the property */
+ for (it = icons; it != NULL;) {
+ TrayWindow *traywin = it->data;
+ gboolean exists;
+
+ if (traywin->type != KDE) {
+ /* don't go removing non-kde windows */
+ exists = TRUE;
+ } else {
+ exists = FALSE;
+ for (i = 0; i < count; ++i) {
+ if (traywin->id == ids[i]) {
+ exists = TRUE;
+ break;
+ }
+ }
+ }
+
+ next = g_slist_next(it);
+ if (!exists) {
+ icon_remove(it);
+ removed =TRUE;
+ }
+ it = next;
+ }
+
+ if (removed) {
+ /* at least one tray app was removed, so reorganize 'em all and resize*/
+ reposition_icons();
+ fix_geometry();
+ }
+
+ XFree(ids);
+}
--- /dev/null
+#ifndef __kde_h
+#define __kde_h
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+extern Atom kde_systray_prop;
+
+void kde_update_icons();
+void kde_init();
+
+#endif /* __kde_h */
--- /dev/null
+#include "net.h"
+#include "docker.h"
+#include "icons.h"
+#include <assert.h>
+
+Atom net_opcode_atom;
+Window net_sel_win;
+
+static Atom net_sel_atom;
+static Atom net_manager_atom;
+static Atom net_message_data_atom;
+
+/* defined in the systray spec */
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+#define SYSTEM_TRAY_BEGIN_MESSAGE 1
+#define SYSTEM_TRAY_CANCEL_MESSAGE 2
+
+static void net_create_selection_window()
+{
+ net_sel_win = XCreateSimpleWindow(display, root, -1, -1, 1, 1, 0, 0, 0);
+ assert(net_sel_win);
+}
+
+
+static void net_destroy_selection_window()
+{
+ XDestroyWindow(display, net_sel_win);
+ net_sel_win = None;
+}
+
+
+void net_init()
+{
+ char *name;
+ XEvent m;
+
+ name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", DefaultScreen(display));
+ net_sel_atom = XInternAtom(display, name, False);
+ assert(net_sel_atom);
+ net_opcode_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False);
+ assert(net_opcode_atom);
+ net_manager_atom = XInternAtom(display, "MANAGER", False);
+ assert(net_manager_atom);
+ net_message_data_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_MESSAGE_DATA",
+ False);
+ assert(net_message_data_atom);
+
+ net_create_selection_window();
+
+ XSetSelectionOwner(display, net_sel_atom, net_sel_win, CurrentTime);
+ if (XGetSelectionOwner(display, net_sel_atom) != net_sel_win)
+ return; /* we don't get the selection */
+
+ m.type = ClientMessage;
+ m.xclient.message_type = net_manager_atom;
+ m.xclient.format = 32;
+ m.xclient.data.l[0] = CurrentTime;
+ m.xclient.data.l[1] = net_sel_atom;
+ m.xclient.data.l[2] = net_sel_win;
+ m.xclient.data.l[3] = 0;
+ m.xclient.data.l[4] = 0;
+ XSendEvent(display, root, False, StructureNotifyMask, &m);
+}
+
+
+void net_destroy()
+{
+ net_destroy_selection_window();
+}
+
+
+void net_message(XClientMessageEvent *e)
+{
+ unsigned long opcode;
+ Window id;
+
+ assert(e);
+
+ opcode = e->data.l[1];
+
+ switch (opcode)
+ {
+ case SYSTEM_TRAY_REQUEST_DOCK: /* dock a new icon */
+ id = e->data.l[2];
+ if (id && icon_add(id, NET))
+ XSelectInput(display, id, StructureNotifyMask);
+ break;
+
+ case SYSTEM_TRAY_BEGIN_MESSAGE:
+ g_printerr("Message From Dockapp\n");
+ id = e->window;
+ break;
+
+ case SYSTEM_TRAY_CANCEL_MESSAGE:
+ g_printerr("Message Cancelled\n");
+ id = e->window;
+ break;
+
+ default:
+ if (opcode == net_message_data_atom) {
+ g_printerr("Text For Message From Dockapp:\n%s\n", e->data.b);
+ id = e->window;
+ break;
+ }
+
+ /* unknown message type. not in the spec. */
+ g_printerr("Warning: Received unknown client message to System Tray "
+ "selection window.\n");
+ break;
+ }
+}
+
+
+void net_icon_remove(TrayWindow *traywin)
+{
+ assert(traywin);
+
+ XSelectInput(display, traywin->id, NoEventMask);
+}
--- /dev/null
+#ifndef __net_h
+#define __net_h
+
+#include <glib.h>
+#include <X11/Xlib.h>
+#include "docker.h"
+
+extern Window net_sel_win;
+extern Atom net_opcode_atom;
+
+void net_init();
+void net_message(XClientMessageEvent *e);
+void net_icon_remove(TrayWindow *traywin);
+
+#endif /* __net_h */
--- /dev/null
+/**************************************************************************
+* Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* Merge 'docker' with 'tint2'.
+* The goal is to keep unchanged docker code, but without data duplication.
+*
+**************************************************************************/
+
+#ifndef TINT_MERGE_H
+#define TINT_MERGE_H
+
+#define display server.dsp
+#define root server.root_win
+
+/* delete main(), parse_cmd_line() and display_string from docker.c
+ * include "tint_merge.h" in docker.h
+ */
+
+
+#endif
+
--- /dev/null
+#define VERSION "1.5"
--- /dev/null
+#define VERSION "@VERSION@"
--- /dev/null
+#include "xproperty.h"
+#include "docker.h"
+
+gboolean xprop_get8(Window window, Atom atom, Atom type, int size,
+ gulong *count, guchar **value)
+{
+ Atom ret_type;
+ int ret_size;
+ unsigned long ret_bytes;
+ int result;
+ unsigned long nelements = *count;
+ unsigned long maxread = nelements;
+
+ *value = NULL;
+
+ /* try get the first element */
+ result = XGetWindowProperty(display, window, atom, 0l, 1l, False,
+ AnyPropertyType, &ret_type, &ret_size,
+ &nelements, &ret_bytes, value);
+ if (! (result == Success && ret_type == type &&
+ ret_size == size && nelements > 0)) {
+ if (*value) XFree(*value);
+ *value = NULL;
+ nelements = 0;
+ } else {
+ /* we didn't the whole property's value, more to get */
+ if (! (ret_bytes == 0 || maxread <= nelements)) {
+ int remain;
+
+ /* get the entire property since it is larger than one element long */
+ XFree(*value);
+ /*
+ the number of longs that need to be retreived to get the property's
+ entire value. The last + 1 is the first long that we retrieved above.
+ */
+ remain = (ret_bytes - 1)/sizeof(long) + 1 + 1;
+ /* dont get more than the max */
+ if (remain > size/8 * (signed)maxread)
+ remain = size/8 * (signed)maxread;
+ result = XGetWindowProperty(display, window, atom, 0l, remain,
+ False, type, &ret_type, &ret_size,
+ &nelements, &ret_bytes, value);
+ /*
+ If the property has changed type/size, or has grown since our first
+ read of it, then stop here and try again. If it shrank, then this will
+ still work.
+ */
+ if (!(result == Success && ret_type == type &&
+ ret_size == size && ret_bytes == 0)) {
+ if (*value) XFree(*value);
+ xprop_get8(window, atom, type, size, count, value);
+ }
+ }
+ }
+
+ *count = nelements;
+ return *value != NULL;
+}
+
+gboolean xprop_get32(Window window, Atom atom, Atom type, int size,
+ gulong *count, gulong **value)
+{
+ return xprop_get8(window, atom, type, size, count, (guchar**)value);
+}
--- /dev/null
+#ifndef __xproperty_h
+#define __xproperty_h
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+/* if the func returns TRUE, the returned value must be XFree()'d */
+gboolean xprop_get8(Window window, Atom atom, Atom type, int size,
+ gulong *count, guchar **value);
+gboolean xprop_get32(Window window, Atom atom, Atom type, int size,
+ gulong *count, gulong **value);
+
+#endif /* __xproperty_h */
--- /dev/null
+/**************************************************************************
+*
+* Tint2 : task
+*
+* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
+* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <Imlib2.h>
+
+#include "window.h"
+#include "task.h"
+#include "server.h"
+#include "panel.h"
+
+
+
+void add_task (Window win)
+{
+ Task *new_tsk;
+ int desktop, monitor;
+
+ if (!win || window_is_hidden (win) || win == window.main_win) return;
+
+ new_tsk = malloc(sizeof(Task));
+ new_tsk->win = win;
+ new_tsk->title = 0;
+ new_tsk->icon_data = 0;
+
+ get_icon(new_tsk);
+ get_title(new_tsk);
+ memcpy(&new_tsk->area, &g_task.area, sizeof(Area));
+ memcpy(&new_tsk->area_active, &g_task.area_active, sizeof(Area));
+ desktop = window_get_desktop (new_tsk->win);
+ monitor = window_get_monitor (new_tsk->win);
+
+ //if (panel.mode == MULTI_MONITOR) monitor = window_get_monitor (new_tsk->win);
+ //else monitor = 0;
+ //printf("task %s : desktop %d, monitor %d\n", new_tsk->title, desktop, monitor);
+
+ XSelectInput (server.dsp, new_tsk->win, PropertyChangeMask|StructureNotifyMask);
+
+ if (desktop == 0xFFFFFFFF) {
+ if (new_tsk->title) XFree (new_tsk->title);
+ if (new_tsk->icon_data) XFree (new_tsk->icon_data);
+ free(new_tsk);
+ fprintf(stderr, "task on all desktop : ignored\n");
+ return;
+ }
+
+ Taskbar *tskbar;
+ tskbar = g_slist_nth_data(panel.area.list, index(desktop, monitor));
+ new_tsk->area.parent = tskbar;
+ tskbar->area.list = g_slist_append(tskbar->area.list, new_tsk);
+
+ if (resize_tasks (tskbar))
+ redraw (&tskbar->area);
+}
+
+
+void remove_task (Task *tsk)
+{
+ if (!tsk) return;
+
+ Taskbar *tskbar;
+ tskbar = (Taskbar*)tsk->area.parent;
+ tskbar->area.list = g_slist_remove(tskbar->area.list, tsk);
+ resize_tasks (tskbar);
+ redraw (&tskbar->area);
+
+ if (tsk->title) XFree (tsk->title);
+ if (tsk->icon_data) XFree (tsk->icon_data);
+ XFreePixmap (server.dsp, tsk->area.pmap);
+ XFreePixmap (server.dsp, tsk->area_active.pmap);
+ free(tsk);
+}
+
+
+void get_title(Task *tsk)
+{
+ if (!g_task.text) return;
+
+ char *title, *name;
+
+ if (tsk->title) free(tsk->title);
+
+ name = server_get_property (tsk->win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0);
+ if (!name || !strlen(name)) {
+ name = server_get_property (tsk->win, server.atom._NET_WM_NAME, server.atom.UTF8_STRING, 0);
+ if (!name || !strlen(name)) {
+ name = server_get_property (tsk->win, server.atom.WM_NAME, XA_STRING, 0);
+ if (!name || !strlen(name)) {
+ name = malloc(10);
+ strcpy(name, "Untitled");
+ }
+ }
+ }
+
+ // add space before title
+ title = malloc(strlen(name)+1);
+ if (g_task.icon) strcpy(title, " ");
+ else title[0] = 0;
+ strcat(title, name);
+
+ if (name) XFree (name);
+ tsk->title = title;
+}
+
+
+void get_icon (Task *tsk)
+{
+ if (!g_task.icon) return;
+
+ long *data;
+ int num;
+
+ data = server_get_property (tsk->win, server.atom._NET_WM_ICON, XA_CARDINAL, &num);
+ if (!data) return;
+
+ int w, h;
+ long *tmp_data;
+ tmp_data = get_best_icon (data, get_icon_count (data, num), num, &w, &h, g_task.icon_size1);
+
+ tsk->icon_width = w;
+ tsk->icon_height = h;
+ tsk->icon_data = malloc (w * h * sizeof (long));
+ memcpy (tsk->icon_data, tmp_data, w * h * sizeof (long));
+
+ XFree (data);
+}
+
+
+void draw_task_icon (Task *tsk, int text_width, int active)
+{
+ if (tsk->icon_data == 0) get_icon (tsk);
+ if (tsk->icon_data == 0) return;
+
+ Pixmap *pmap;
+
+ if (active) pmap = &tsk->area_active.pmap;
+ else pmap = &tsk->area.pmap;
+
+ /* Find pos */
+ int pos_x;
+ if (g_task.centered) {
+ if (g_task.text)
+ pos_x = (tsk->area.width - text_width - g_task.icon_size1) / 2;
+ else
+ pos_x = (tsk->area.width - g_task.icon_size1) / 2;
+ }
+ else pos_x = g_task.area.paddingx + g_task.area.border.width;
+
+ /* Render */
+ Imlib_Image icon;
+ Imlib_Color_Modifier cmod;
+ DATA8 red[256], green[256], blue[256], alpha[256];
+
+ // TODO: cpu improvement : compute only when icon changed
+ DATA32 *data;
+ /* do we have 64bit? => long = 8bit */
+ if (sizeof(long) != 4) {
+ int length = tsk->icon_width * tsk->icon_height;
+ data = malloc(sizeof(DATA32) * length);
+ int i;
+ for (i = 0; i < length; ++i)
+ data[i] = tsk->icon_data[i];
+ }
+ else data = (DATA32 *) tsk->icon_data;
+
+ icon = imlib_create_image_using_data (tsk->icon_width, tsk->icon_height, data);
+ imlib_context_set_image (icon);
+ imlib_context_set_drawable (*pmap);
+
+ cmod = imlib_create_color_modifier ();
+ imlib_context_set_color_modifier (cmod);
+ imlib_image_set_has_alpha (1);
+ imlib_get_color_modifier_tables (red, green, blue, alpha);
+
+ int i, opacity;
+ if (active) opacity = 255*g_task.font_active.alpha;
+ else opacity = 255*g_task.font.alpha;
+ for(i = 127; i < 256; i++) alpha[i] = opacity;
+
+ imlib_set_color_modifier_tables (red, green, blue, alpha);
+
+ //imlib_render_image_on_drawable (pos_x, pos_y);
+ imlib_render_image_on_drawable_at_size (pos_x, g_task.icon_posy, g_task.icon_size1, g_task.icon_size1);
+
+ imlib_free_color_modifier ();
+ imlib_free_image ();
+ if (sizeof(long) != 4) free(data);
+}
+
+
+void draw_task_title (cairo_t *c, Task *tsk, int active)
+{
+ PangoLayout *layout;
+ config_color *config_text;
+ int width, height;
+
+ if (g_task.text) {
+ /* Layout */
+ layout = pango_cairo_create_layout (c);
+ pango_layout_set_font_description (layout, g_task.font_desc);
+ pango_layout_set_text (layout, tsk->title, -1);
+
+ /* Drawing width and Cut text */
+ pango_layout_set_width (layout, ((Taskbar*)tsk->area.parent)->text_width * PANGO_SCALE);
+ pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
+
+ /* Center text */
+ if (g_task.centered) pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
+ else pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
+
+ pango_layout_get_pixel_size (layout, &width, &height);
+
+ if (active) config_text = &g_task.font_active;
+ else config_text = &g_task.font;
+
+ cairo_set_source_rgba (c, config_text->color[0], config_text->color[1], config_text->color[2], config_text->alpha);
+
+ pango_cairo_update_layout (c, layout);
+ cairo_move_to (c, g_task.text_posx, g_task.text_posy);
+ pango_cairo_show_layout (c, layout);
+
+ if (g_task.font_shadow) {
+ cairo_set_source_rgba (c, 0.0, 0.0, 0.0, 0.5);
+ pango_cairo_update_layout (c, layout);
+ cairo_move_to (c, g_task.text_posx + 1, g_task.text_posy + 1);
+ pango_cairo_show_layout (c, layout);
+ }
+ g_object_unref (layout);
+ }
+
+ if (g_task.icon) {
+ // icon use same opacity as text
+ draw_task_icon (tsk, width, active);
+ }
+}
+
+
+int draw_foreground_task (void *obj, cairo_t *c)
+{
+ Task *tsk = obj;
+ cairo_surface_t *cs;
+ cairo_t *ca;
+
+ draw_task_title (c, tsk, 0);
+
+ // draw active pmap
+ if (tsk->area_active.pmap) XFreePixmap (server.dsp, tsk->area_active.pmap);
+ tsk->area_active.pmap = server_create_pixmap (tsk->area.width, tsk->area.height);
+
+ // add layer of root pixmap
+ XCopyArea (server.dsp, server.pmap, tsk->area_active.pmap, server.gc, tsk->area.posx, tsk->area.posy, tsk->area.width, tsk->area.height, 0, 0);
+
+ cs = cairo_xlib_surface_create (server.dsp, tsk->area_active.pmap, server.visual, tsk->area.width, tsk->area.height);
+ ca = cairo_create (cs);
+
+ // redraw task
+ draw_background (&tsk->area_active, ca);
+ draw_task_title (ca, tsk, 1);
+
+ cairo_destroy (ca);
+ cairo_surface_destroy (cs);
+ return 0;
+}
+
--- /dev/null
+/**************************************************************************
+* task :
+* -
+*
+**************************************************************************/
+
+#ifndef TASK_H
+#define TASK_H
+
+#include <X11/Xlib.h>
+#include <pango/pangocairo.h>
+#include "common.h"
+
+
+// --------------------------------------------------
+// global task parameter
+typedef struct {
+ Area area;
+ Area area_active;
+
+ int text;
+ int icon;
+ int icon_size1;
+ int centered;
+ int maximum_width;
+ int font_shadow;
+ // icon position
+ int icon_posy;
+ // starting position for text ~ task_padding + task_border + icon_size
+ double text_posx, text_posy;
+ PangoFontDescription *font_desc;
+ config_color font;
+ config_color font_active;
+} Global_task;
+
+
+
+// --------------------------------------------------
+// task parameter
+typedef struct {
+ // --------------------------------------------------
+ // always start with area
+ Area area;
+ Area area_active;
+
+ // TODO: group task with list of windows here
+ Window win;
+ long *icon_data;
+ int icon_width;
+ int icon_height;
+ char *title;
+} Task;
+
+
+Global_task g_task;
+
+
+void add_task (Window win);
+void remove_task (Task *tsk);
+
+int draw_foreground_task (void *obj, cairo_t *c);
+
+void get_icon (Task *tsk);
+void get_title(Task *tsk);
+
+#endif
+
--- /dev/null
+/**************************************************************************
+*
+* Tint2 : taskbar
+*
+* Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <Imlib2.h>
+
+#include "taskbar.h"
+#include "server.h"
+#include "window.h"
+#include "panel.h"
+
+
+
+Task *task_get_task (Window win)
+{
+ Taskbar *tskbar;
+ Task *tsk;
+ GSList *l0;
+
+ for (l0 = panel.area.list; l0 ; l0 = l0->next) {
+ tskbar = l0->data;
+ GSList *l1;
+ for (l1 = tskbar->area.list; l1 ; l1 = l1->next) {
+ tsk = l1->data;
+ if (win == tsk->win) return tsk;
+ }
+ }
+
+ // nb = panel.nb_desktop * panel.nb_monitor;
+ //printf("task_get_task return 0\n");
+ return 0;
+}
+
+
+void task_refresh_tasklist ()
+{
+ Window *win, active_win;
+ int num_results, i, j;
+
+ win = server_get_property (server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
+
+ if (!win) return;
+
+ /* Remove any old and set active win */
+ active_win = window_get_active ();
+
+ Task *tsk;
+ Taskbar *tskbar;
+ GSList *l0;
+ for (l0 = panel.area.list; l0 ; l0 = l0->next) {
+ tskbar = l0->data;
+ GSList *l1;
+ for (l1 = tskbar->area.list; l1 ; l1 = l1->next) {
+ tsk = l1->data;
+
+ if (tsk->win == active_win) panel.task_active = tsk;
+
+ for (j = 0; j < num_results; j++) {
+ if (tsk->win == win[j]) break;
+ }
+ if (tsk->win != win[j]) remove_task (tsk);
+ }
+ }
+
+ /* Add any new */
+ for (i = 0; i < num_results; i++) {
+ if (!task_get_task (win[i])) add_task (win[i]);
+ }
+
+ XFree (win);
+}
+
+
+int resize_tasks (Taskbar *taskbar)
+{
+ int ret, task_count, pixel_width, modulo_width=0;
+ int x, taskbar_width;
+ Task *tsk;
+ GSList *l;
+
+ // new task width for 'desktop'
+ task_count = g_slist_length(taskbar->area.list);
+ if (!task_count) pixel_width = g_task.maximum_width;
+ else {
+ taskbar_width = taskbar->area.width - (2 * g_taskbar.border.width) - ((task_count+1) * g_taskbar.paddingx);
+
+ pixel_width = taskbar_width / task_count;
+ if (pixel_width > g_task.maximum_width) pixel_width = g_task.maximum_width;
+ else modulo_width = taskbar_width % task_count;
+ }
+
+ if ((taskbar->task_width == pixel_width) && (taskbar->task_modulo == modulo_width)) {
+ ret = 0;
+ }
+ else {
+ ret = 1;
+ taskbar->task_width = pixel_width;
+ taskbar->task_modulo = modulo_width;
+ taskbar->text_width = pixel_width - g_task.text_posx - g_task.area.border.width - g_task.area.paddingx;
+ }
+
+ // change pos_x and width for all tasks
+ x = taskbar->area.posx + taskbar->area.border.width + taskbar->area.paddingx;
+ for (l = taskbar->area.list; l ; l = l->next) {
+ tsk = l->data;
+ tsk->area.posx = x;
+ tsk->area_active.posx = x;
+ tsk->area.width = pixel_width;
+ tsk->area_active.width = pixel_width;
+ if (modulo_width) {
+ tsk->area.width++;
+ tsk->area_active.width++;
+ modulo_width--;
+ }
+
+ x += tsk->area.width + g_taskbar.paddingx;
+ }
+ return ret;
+}
+
+
--- /dev/null
+
+#ifndef TASKBAR_H
+#define TASKBAR_H
+
+#include "task.h"
+
+
+// --------------------------------------------------
+// taskbar parameter
+typedef struct {
+ // --------------------------------------------------
+ // always start with area
+ Area area;
+
+ int desktop;
+ int monitor;
+
+ // task parameters
+ int task_width;
+ int task_modulo;
+ int text_width;
+} Taskbar;
+
+
+// --------------------------------------------------
+// global taskbar parameter
+Area g_taskbar;
+
+
+Task *task_get_task (Window win);
+void task_refresh_tasklist ();
+
+// return 1 if task_width changed
+int resize_tasks (Taskbar *tskbar);
+
+//void add_taskbar(Area *a);
+
+#endif
+
--- /dev/null
+/**************************************************************************
+*
+* Tint2 panel
+*
+* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
+* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/Xlocale.h>
+#include <Imlib2.h>
+#include <signal.h>
+
+#include "server.h"
+#include "window.h"
+#include "config.h"
+#include "task.h"
+#include "taskbar.h"
+#include "panel.h"
+#include "docker.h"
+#include "net.h"
+#include "kde.h"
+
+
+void signal_handler(int sig)
+{
+ // signal handler is light as it should be
+ panel.signal_pending = sig;
+}
+
+
+void init ()
+{
+ // Set signal handler
+ signal(SIGUSR1, signal_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
+
+ // set global data
+ memset(&panel, 0, sizeof(Panel));
+ memset(&server, 0, sizeof(Server_global));
+ memset(&g_task, 0, sizeof(Global_task));
+ memset(&g_taskbar, 0, sizeof(Area));
+ panel.clock.area.draw_foreground = draw_foreground_clock;
+ g_task.area.draw_foreground = draw_foreground_task;
+ window.main_win = 0;
+
+ // append full transparency background
+ //Area *back = calloc(1, sizeof(Area));
+ list_back = g_slist_append(0, calloc(1, sizeof(Area)));
+
+ server.dsp = XOpenDisplay (NULL);
+ if (!server.dsp) {
+ fprintf(stderr, "Could not open display.\n");
+ exit(0);
+ }
+ server_init_atoms ();
+ server.screen = DefaultScreen (server.dsp);
+ server.root_win = RootWindow (server.dsp, server.screen);
+ server.depth = DefaultDepth (server.dsp, server.screen);
+ server.visual = DefaultVisual (server.dsp, server.screen);
+ server.desktop = server_get_current_desktop ();
+
+ XSetErrorHandler ((XErrorHandler) server_catch_error);
+
+ // init systray
+ display = server.dsp;
+ root = RootWindow(display, DefaultScreen(display));
+ //create_main_window();
+ //kde_init();
+ //net_init();
+ //printf("ici 4\n");
+
+ imlib_context_set_display (server.dsp);
+ imlib_context_set_visual (server.visual);
+ imlib_context_set_colormap (DefaultColormap (server.dsp, server.screen));
+
+ /* Catch events */
+ XSelectInput (server.dsp, server.root_win, PropertyChangeMask|StructureNotifyMask);
+
+ setlocale(LC_ALL, "");
+}
+
+
+void window_action (Task *tsk, int action)
+{
+ switch (action) {
+ case CLOSE:
+ set_close (tsk->win);
+ break;
+ case TOGGLE:
+ set_active(tsk->win);
+ break;
+ case ICONIFY:
+ XIconifyWindow (server.dsp, tsk->win, server.screen);
+ break;
+ case TOGGLE_ICONIFY:
+ if (tsk == panel.task_active) XIconifyWindow (server.dsp, tsk->win, server.screen);
+ else set_active (tsk->win);
+ break;
+ case SHADE:
+ window_toggle_shade (tsk->win);
+ break;
+ }
+}
+
+
+void event_button_press (int x, int y)
+{
+ if (panel.mode == SINGLE_DESKTOP) {
+ // drag and drop disabled
+ XLowerWindow (server.dsp, window.main_win);
+ return;
+ }
+
+ Taskbar *tskbar;
+ GSList *l0;
+ for (l0 = panel.area.list; l0 ; l0 = l0->next) {
+ tskbar = l0->data;
+ if (x >= tskbar->area.posx && x <= (tskbar->area.posx + tskbar->area.width))
+ break;
+ }
+
+ if (l0) {
+ Task *tsk;
+ for (l0 = tskbar->area.list; l0 ; l0 = l0->next) {
+ tsk = l0->data;
+ if (x >= tsk->area.posx && x <= (tsk->area.posx + tsk->area.width)) {
+ panel.task_drag = tsk;
+ break;
+ }
+ }
+ }
+
+ XLowerWindow (server.dsp, window.main_win);
+}
+
+
+void event_button_release (int button, int x, int y)
+{
+ int action = TOGGLE_ICONIFY;
+
+ switch (button) {
+ case 2:
+ action = panel.mouse_middle;
+ break;
+ case 3:
+ action = panel.mouse_right;
+ break;
+ case 4:
+ action = panel.mouse_scroll_up;
+ break;
+ case 5:
+ action = panel.mouse_scroll_down;
+ break;
+ }
+
+ // TODO: ne pas afficher les taskbar invisibles
+ //if (panel.mode != MULTI_DESKTOP && desktop != server.desktop) continue;
+
+ // search taskbar
+ Taskbar *tskbar;
+ GSList *l0;
+ for (l0 = panel.area.list; l0 ; l0 = l0->next) {
+ tskbar = l0->data;
+ if (x >= tskbar->area.posx && x <= (tskbar->area.posx + tskbar->area.width))
+ goto suite;
+ }
+
+ // TODO: check better solution to keep window below
+ XLowerWindow (server.dsp, window.main_win);
+ panel.task_drag = 0;
+ return;
+
+suite:
+ // drag and drop task
+ if (panel.task_drag) {
+ if (tskbar != panel.task_drag->area.parent && action == TOGGLE_ICONIFY) {
+ windows_set_desktop(panel.task_drag->win, tskbar->desktop);
+ if (tskbar->desktop == server.desktop)
+ set_active(panel.task_drag->win);
+ panel.task_drag = 0;
+ return;
+ }
+ else panel.task_drag = 0;
+ }
+
+ // switch desktop
+ if (panel.mode == MULTI_DESKTOP)
+ if (tskbar->desktop != server.desktop && action != CLOSE)
+ set_desktop (tskbar->desktop);
+
+ // action on task
+ Task *tsk;
+ GSList *l;
+ for (l = tskbar->area.list ; l ; l = l->next) {
+ tsk = l->data;
+ if (x >= tsk->area.posx && x <= (tsk->area.posx + tsk->area.width)) {
+ window_action (tsk, action);
+ break;
+ }
+ }
+
+ // to keep window below
+ XLowerWindow (server.dsp, window.main_win);
+}
+
+
+void event_property_notify (Window win, Atom at)
+{
+
+ if (win == server.root_win) {
+ if (!server.got_root_win) {
+ XSelectInput (server.dsp, server.root_win, PropertyChangeMask|StructureNotifyMask);
+ server.got_root_win = 1;
+ }
+
+ /* Change number of desktops */
+ else if (at == server.atom._NET_NUMBER_OF_DESKTOPS) {
+ config_taskbar();
+ redraw(&panel.area);
+ panel.refresh = 1;
+ }
+ /* Change desktop */
+ else if (at == server.atom._NET_CURRENT_DESKTOP) {
+ server.desktop = server_get_current_desktop ();
+ if (panel.mode != MULTI_DESKTOP) panel.refresh = 1;
+ }
+ /* Window list */
+ else if (at == server.atom._NET_CLIENT_LIST) {
+ task_refresh_tasklist ();
+ panel.refresh = 1;
+ }
+ /* Active */
+ else if (at == server.atom._NET_ACTIVE_WINDOW) {
+ Window w1 = window_get_active ();
+ Task *t = task_get_task(w1);
+ if (t) panel.task_active = t;
+ else {
+ Window w2;
+ if (XGetTransientForHint(server.dsp, w1, &w2) != 0)
+ if (w2) panel.task_active = task_get_task(w2);
+ }
+ panel.refresh = 1;
+ }
+ /* Wallpaper changed */
+ else if (at == server.atom._XROOTPMAP_ID) {
+ XFreePixmap (server.dsp, server.root_pmap);
+ server.root_pmap = 0;
+ redraw(&panel.area);
+ panel.clock.area.redraw = 1;
+ panel.refresh = 1;
+ }
+ }
+ else {
+ Task *tsk;
+ tsk = task_get_task (win);
+ if (!tsk) return;
+ //printf("atom root_win = %s, %s\n", XGetAtomName(server.dsp, at), tsk->title);
+
+ /* Window title changed */
+ if (at == server.atom._NET_WM_VISIBLE_NAME || at == server.atom._NET_WM_NAME || at == server.atom.WM_NAME) {
+ get_title(tsk);
+ tsk->area.redraw = 1;
+ panel.refresh = 1;
+ }
+ /* Iconic state */
+ else if (at == server.atom.WM_STATE) {
+ if (window_is_iconified (win))
+ if (panel.task_active == tsk) panel.task_active = 0;
+ }
+ /* Window icon changed */
+ else if (at == server.atom._NET_WM_ICON) {
+ if (tsk->icon_data != 0) XFree (tsk->icon_data);
+ tsk->area.redraw = 1;
+ tsk->icon_data = 0;
+ panel.refresh = 1;
+ }
+ /* Window desktop changed */
+ else if (at == server.atom._NET_WM_DESKTOP) {
+ add_task (tsk->win);
+ remove_task (tsk);
+ panel.refresh = 1;
+ }
+
+ if (!server.got_root_win) server.root_win = RootWindow (server.dsp, server.screen);
+ }
+}
+
+
+void event_configure_notify (Window win)
+{
+ Task *tsk;
+
+ tsk = task_get_task (win);
+ if (!tsk) return;
+
+/* TODO ??? voir ancien code !!
+ Taskbar *tskbar;
+ tskbar = tsk->area.parent;
+ int new_monitor = window_get_monitor (win);
+ int desktop = tskbar->desktop;
+
+ // task on the same monitor
+ if (tsk->id_taskbar == index(desktop, new_monitor)) return;
+
+ add_task (tsk->win);
+ remove_task (tsk);
+ panel.refresh = 1;
+ */
+}
+
+
+void event_timer()
+{
+ struct timeval stv;
+
+ if (!panel.clock.time1_format) return;
+
+ if (gettimeofday(&stv, 0)) return;
+
+ if (abs(stv.tv_sec - panel.clock.clock.tv_sec) < panel.clock.time_precision) return;
+
+ // update clock
+ panel.clock.clock.tv_sec = stv.tv_sec;
+ panel.clock.clock.tv_sec -= panel.clock.clock.tv_sec % panel.clock.time_precision;
+ panel.clock.area.redraw = 1;
+ panel.refresh = 1;
+}
+
+
+int main (int argc, char *argv[])
+{
+ XEvent e;
+ fd_set fd;
+ int x11_fd, i, c;
+ struct timeval tv;
+
+ c = getopt (argc, argv, "c:");
+ init ();
+
+load_config:
+ if (server.root_pmap) XFreePixmap (server.dsp, server.root_pmap);
+ server.root_pmap = 0;
+ // read tint2rc config
+ i = 0;
+ if (c != -1)
+ i = config_read_file (optarg);
+ if (!i)
+ i = config_read ();
+ if (!i) {
+ fprintf(stderr, "usage: tint2 [-c] <config_file>\n");
+ cleanup();
+ exit(1);
+ }
+ config_finish ();
+
+ window_draw_panel ();
+
+ x11_fd = ConnectionNumber (server.dsp);
+ XSync (server.dsp, False);
+
+ while (1) {
+ // thanks to AngryLlama for the timer
+ // Create a File Description Set containing x11_fd
+ FD_ZERO (&fd);
+ FD_SET (x11_fd, &fd);
+
+ tv.tv_usec = 500000;
+ tv.tv_sec = 0;
+
+ // Wait for X Event or a Timer
+ if (select(x11_fd+1, &fd, 0, 0, &tv)) {
+ while (XPending (server.dsp)) {
+ XNextEvent(server.dsp, &e);
+
+ switch (e.type) {
+ case ButtonPress:
+ if (e.xbutton.button == 1) event_button_press (e.xbutton.x, e.xbutton.y);
+ break;
+
+ case ButtonRelease:
+ event_button_release (e.xbutton.button, e.xbutton.x, e.xbutton.y);
+ break;
+
+ case Expose:
+ XCopyArea (server.dsp, server.pmap, window.main_win, server.gc, 0, 0, panel.area.width, panel.area.height, 0, 0);
+ break;
+
+ case PropertyNotify:
+ event_property_notify (e.xproperty.window, e.xproperty.atom);
+ break;
+
+ case ConfigureNotify:
+ if (e.xconfigure.window == server.root_win)
+ goto load_config;
+ else
+ if (panel.mode == MULTI_MONITOR)
+ event_configure_notify (e.xconfigure.window);
+ break;
+ }
+ }
+ }
+ else event_timer();
+
+ switch (panel.signal_pending) {
+ case SIGUSR1:
+ goto load_config;
+ case SIGINT:
+ case SIGTERM:
+ cleanup ();
+ return 0;
+ }
+
+ if (panel.refresh && !panel.sleep_mode) {
+ visual_refresh ();
+ //printf(" *** visual_refresh\n");
+ }
+ }
+}
+
+
--- /dev/null
+/**************************************************************************
+*
+* Tint2 : area
+*
+* Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "window.h"
+#include "server.h"
+#include "area.h"
+
+
+
+void redraw (Area *a)
+{
+ a->redraw = 1;
+
+ GSList *l;
+ for (l = a->list ; l ; l = l->next)
+ redraw(l->data);
+}
+
+
+int draw (Area *a)
+{
+ if (!a->redraw) return 0;
+
+ cairo_surface_t *cs;
+ cairo_t *c;
+ int ret = 0;
+
+ if (a->pmap) XFreePixmap (server.dsp, a->pmap);
+ a->pmap = server_create_pixmap (a->width, a->height);
+
+ // add layer of root pixmap
+ XCopyArea (server.dsp, server.pmap, a->pmap, server.gc, a->posx, a->posy, a->width, a->height, 0, 0);
+
+ cs = cairo_xlib_surface_create (server.dsp, a->pmap, server.visual, a->width, a->height);
+ c = cairo_create (cs);
+
+ draw_background (a, c);
+
+ if (a->draw_foreground) {
+ ret = a->draw_foreground(a, c);
+ }
+ else {
+ // parcours de la liste des sous objets
+ }
+
+ cairo_destroy (c);
+ cairo_surface_destroy (cs);
+ a->redraw = 0;
+
+ return ret;
+}
+
+
+void draw_background (Area *a, cairo_t *c)
+{
+ if (a->back.alpha > 0.0) {
+ //printf(" draw_background %d %d\n", a->width, a->height);
+ draw_rect(c, a->border.width, a->border.width, a->width-(2.0 * a->border.width), a->height-(2.0*a->border.width), a->border.rounded - a->border.width/1.571);
+ /*
+ double x0, y0, x1, y1;
+ x0 = 0;
+ y0 = 100;
+ x1 = 100;
+ y1 = 0;
+
+ cairo_pattern_t *linpat;
+ cairo_matrix_t matrix;
+ linpat = cairo_pattern_create_linear (x0, y0, x1, y1);
+
+ cairo_pattern_add_color_stop_rgba (linpat, 0, a->back.color[0], a->back.color[1], a->back.color[2], a->back.alpha);
+ cairo_pattern_add_color_stop_rgba (linpat, 1, a->back.color[0], a->back.color[1], a->back.color[2], 0);
+ //cairo_matrix_init_scale (&matrix, a->height, a->width);
+ //cairo_pattern_set_matrix (linpat, &matrix);
+ cairo_set_source (c, linpat);
+ */
+ cairo_set_source_rgba(c, a->back.color[0], a->back.color[1], a->back.color[2], a->back.alpha);
+
+ cairo_fill(c);
+ //cairo_pattern_destroy (linpat);
+ }
+
+ if (a->border.width > 0 && a->border.alpha > 0.0) {
+ cairo_set_line_width (c, a->border.width);
+
+ // draw border inside (x, y, width, height)
+ draw_rect(c, a->border.width/2.0, a->border.width/2.0, a->width - a->border.width, a->height - a->border.width, a->border.rounded);
+ /*
+ // convert : radian = degre * M_PI/180
+ // définir le dégradé dans un carré de (0,0) (100,100)
+ // ensuite ce dégradé est extrapolé selon le ratio width/height
+ // dans repère (0, 0) (100, 100)
+ double X0, Y0, X1, Y1, degre;
+ // x = X * (a->width / 100), y = Y * (a->height / 100)
+ double x0, y0, x1, y1;
+ X0 = 0;
+ Y0 = 100;
+ X1 = 100;
+ Y1 = 0;
+ degre = 45;
+ // et ensuite faire la changement d'unité du repère
+ // car ce qui doit resté inchangée est les traits et pas la direction
+
+ // il faut d'abord appliquer une rotation de 90° (et -180° si l'angle est supérieur à 180°)
+ // ceci peut être appliqué une fois pour toute au départ
+ // ensuite calculer l'angle dans le nouveau repère
+ // puis faire une rotation de 90°
+ x0 = X0 * ((double)a->width / 100);
+ x1 = X1 * ((double)a->width / 100);
+ y0 = Y0 * ((double)a->height / 100);
+ y1 = Y1 * ((double)a->height / 100);
+
+ x0 = X0 * ((double)a->height / 100);
+ x1 = X1 * ((double)a->height / 100);
+ y0 = Y0 * ((double)a->width / 100);
+ y1 = Y1 * ((double)a->width / 100);
+ printf("repère (%d, %d) points (%lf, %lf) (%lf, %lf)\n", a->width, a->height, x0, y0, x1, y1);
+
+ cairo_pattern_t *linpat;
+ linpat = cairo_pattern_create_linear (x0, y0, x1, y1);
+ cairo_pattern_add_color_stop_rgba (linpat, 0, a->border.color[0], a->border.color[1], a->border.color[2], a->border.alpha);
+ cairo_pattern_add_color_stop_rgba (linpat, 1, a->border.color[0], a->border.color[1], a->border.color[2], 0);
+ cairo_set_source (c, linpat);
+ */
+ cairo_set_source_rgba (c, a->border.color[0], a->border.color[1], a->border.color[2], a->border.alpha);
+
+ cairo_stroke (c);
+ //cairo_pattern_destroy (linpat);
+ }
+}
+
+
+void refresh (Area *a)
+{
+ XCopyArea (server.dsp, a->pmap, server.pmap, server.gc, 0, 0, a->width, a->height, a->posx, a->posy);
+}
+
+
+void remove_area (Area *a)
+{
+ Area *parent;
+
+ parent = (Area*)a->parent;
+ parent->list = g_slist_remove(parent->list, a);
+ redraw (parent);
+
+}
+
+
+void add_area (Area *a)
+{
+ Area *parent;
+
+ parent = (Area*)a->parent;
+ parent->list = g_slist_remove(parent->list, a);
+ redraw (parent);
+
+}
+
--- /dev/null
+/**************************************************************************
+* base class for all objects (panel, taskbar, task, systray, clock, ...).
+* each object 'inherit' Area and implement draw_foreground if needed.
+*
+* Area is at the begining of each object so &object == &area.
+*
+* une zone comprend :
+* - fond : couleur / opacité
+* - contenu
+* - largeur / hauteur
+* - paddingx / paddingy
+* - pixmap mémorisant l'affichage (évite de redessiner l'objet à chaque rafraichissement)
+* - une liste de sous objets
+*
+* un objet comprend les actions:
+* 1) redraw(obj)
+* force l'indicateur 'redraw' sur l'objet
+* parcoure la liste des sous objets => redraw(obj)
+* 2) draw(obj)
+* dessine le background, dessine le contenu dans pmap
+* parcoure la liste des sous objets => draw(obj)
+* le pmap de l'objet se base sur le pmap de l'objet parent (cumul des couches)
+* 3) draw_background(obj)
+* dessine le fond dans pmap
+* 4) draw_foreground(obj) = 0 : fonction virtuelle à redéfinir
+* dessine le contenu dans pmap
+* si l'objet n'a pas de contenu, la fonction est nulle
+* 5) resize_width(obj, width) = 0 : fonction virtuelle à redéfinir
+* recalcule la largeur de l'objet (car la hauteur est fixe)
+* - taille systray calculée à partir de la liste des icones
+* - taille clock calculée à partir de l'heure
+* - taille d'une tache calculée à partir de la taskbar (ajout, suppression, taille)
+* - taille d'une taskbar calculée à partir de la taille du panel et des autres objets
+* 6) voir refresh(obj)
+*
+* Implémentation :
+* - tous les éléments du panel possèdent 1 objet en début de structure
+* panel, taskbar, systray, task, ...
+* - l'objet est en fait une zone (area).
+* l'imbrication des sous objet doit permettre de gérer le layout.
+* - on a une relation 1<->1 entre un objet et une zone graphique
+* les taskbar affichent toutes les taches.
+* donc on utilise la liste des objets pour gérer la liste des taches.
+* - les taches ont 2 objets : l'un pour la tache inactive et l'autre pour la tache active
+* draw(obj) est appellé sur le premier objet automatiquement
+* et draw_foreground(obj) lance l'affichage du 2 ieme objet
+* ainsi la taskbar gère bien une liste d'objets mais draw(obj) dessine les 2 objets
+* - les fonctions de refresh et de draw sont totalement dissociées
+*
+* ----------------------------------------------------
+* A évaluer :
+* 1. voir comment définir et gérer le panel_layout avec les objets
+* => peut on s'affranchir des données spécifiques à chaque objet ?
+* => comment gérer l'affichage du layout ?
+* => comment configurer le layout ?
+* => voir le cumul des couches et l'imbrication entre objet et parent ?
+* 2. voir la fonction de refresh des objets ??
+* surtout le refresh des taches qui est différent pour la tache active
+*
+* 3. tester l'implémentation et évaluer les autres abstractions possibles ?
+*
+* 4. comment gérer le groupage des taches
+* 5. la clock est le contenu du panel. mais elle ne tiens pas compte du padding vertical ?
+* c'est ok pour la clock. voir l'impact sur paddingx ?
+*
+* voir resize_taskbar(), resize_clock() et resize_tasks()
+* voir les taches actives et inactives ?? une seule tache est active !
+* variable widthChanged ou bien emission d'un signal ???
+*
+* 6) config(obj) configure un objet (définie les positions verticales)
+*
+**************************************************************************/
+
+#ifndef AREA_H
+#define AREA_H
+
+#include <X11/Xlib.h>
+#include <pango/pangocairo.h>
+
+#include "common.h"
+
+
+
+typedef struct
+{
+ double color[3];
+ double alpha;
+ int width;
+ int rounded;
+} Border;
+
+
+typedef struct
+{
+ double color[3];
+ double alpha;
+} Color;
+
+
+typedef struct {
+ // need redraw Pixmap
+ int redraw;
+
+ int paddingx, paddingy;
+ int width, height;
+ Pixmap pmap;
+
+ Color back;
+ Border border;
+
+ // absolute coordinate in panel
+ int posx, posy;
+ // parent Area
+ void *parent;
+
+ // pointer to function
+ // draw_foreground : return 1 if width changed, return O otherwise
+ int (*draw_foreground)(void *obj, cairo_t *c);
+ void (*add_child)(void *obj);
+ int (*remove_child)(void *obj);
+
+ // list of child
+ GSList *list;
+} Area;
+
+
+// redraw an area and childs
+void redraw (Area *a);
+
+// draw background and foreground
+// return 1 if width changed, return O otherwise
+int draw (Area *a);
+void draw_background (Area *a, cairo_t *c);
+
+void refresh (Area *a);
+void remove_area (Area *a);
+void add_area (Area *a);
+
+#endif
+
--- /dev/null
+/**************************************************************************
+* Common declarations
+*
+**************************************************************************/
+
+#ifndef COMMON_H
+#define COMMON_H
+
+
+#define WM_CLASS_TINT "panel"
+
+#include "area.h"
+
+// taskbar table : convert 2 dimension in 1 dimension
+#define index(i, j) ((i * panel.nb_monitor) + j)
+
+// mouse actions
+enum { NONE=0, CLOSE, TOGGLE, ICONIFY, SHADE, TOGGLE_ICONIFY };
+
+
+
+typedef struct config_border
+{
+ double color[3];
+ double alpha;
+ int width;
+ int rounded;
+} config_border;
+
+
+typedef struct config_color
+{
+ double color[3];
+ double alpha;
+} config_color;
+
+
+
+
+#endif
+
--- /dev/null
+/**************************************************************************
+*
+* Tint2 : common windows function
+*
+* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
+* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License 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 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.
+**************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <Imlib2.h>
+
+#include "common.h"
+#include "window.h"
+#include "server.h"
+
+
+
+void set_active (Window win)
+{
+ send_event32 (win, server.atom._NET_ACTIVE_WINDOW, 2, 0);
+}
+
+
+void set_desktop (int desktop)
+{
+ send_event32 (server.root_win, server.atom._NET_CURRENT_DESKTOP, desktop, 0);
+}
+
+
+void windows_set_desktop (Window win, int desktop)
+{
+ send_event32 (win, server.atom._NET_WM_DESKTOP, desktop, 2);
+}
+
+
+void set_close (Window win)
+{
+ send_event32 (win, server.atom._NET_CLOSE_WINDOW, 0, 2);
+}
+
+
+void window_toggle_shade (Window win)
+{
+ send_event32 (win, server.atom._NET_WM_STATE, 2, 0);
+}
+
+
+int window_is_hidden (Window win)
+{
+ Window window;
+ Atom *at;
+ int count, i;
+
+ if (XGetTransientForHint(server.dsp, win, &window) != 0) {
+ if (window) {
+ return 1;
+ }
+ }
+
+ at = server_get_property (win, server.atom._NET_WM_STATE, XA_ATOM, &count);
+ for (i = 0; i < count; i++) {
+ if (at[i] == server.atom._NET_WM_STATE_SKIP_PAGER || at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) {
+ XFree(at);
+ return 1;
+ }
+ }
+ XFree(at);
+
+ at = server_get_property (win, server.atom._NET_WM_WINDOW_TYPE, XA_ATOM, &count);
+ for (i = 0; i < count; i++) {
+ if (at[i] == server.atom._NET_WM_WINDOW_TYPE_DOCK || at[i] == server.atom._NET_WM_WINDOW_TYPE_DESKTOP || at[i] == server.atom._NET_WM_WINDOW_TYPE_TOOLBAR || at[i] == server.atom._NET_WM_WINDOW_TYPE_MENU || at[i] == server.atom._NET_WM_WINDOW_TYPE_SPLASH) {
+ XFree(at);
+ return 1;
+ }
+ }
+
+ // specification
+ // Windows with neither _NET_WM_WINDOW_TYPE nor WM_TRANSIENT_FOR set
+ // MUST be taken as top-level window.
+ XFree(at);
+ return 0;
+}
+
+
+int window_get_desktop (Window win)
+{
+ return get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL);
+}
+
+
+int window_get_monitor (Window win)
+{
+ int i, x, y;
+ Window src;
+
+ XTranslateCoordinates(server.dsp, win, server.root_win, 0, 0, &x, &y, &src);
+ for (i = 0; i < server.nb_monitor; i++) {
+ if (x >= server.monitor[i].x && x <= (server.monitor[i].x + server.monitor[i].width))
+ if (y >= server.monitor[i].y && y <= (server.monitor[i].y + server.monitor[i].height))
+ break;
+ }
+
+ //printf("window %lx : ecran %d, (%d, %d)\n", win, i, x, y);
+ if (i == server.nb_monitor) return 0;
+ else return i;
+}
+
+
+int window_is_iconified (Window win)
+{
+ return (IconicState == get_property32(win, server.atom.WM_STATE, server.atom.WM_STATE));
+}
+
+
+int server_get_number_of_desktop ()
+{
+ return get_property32(server.root_win, server.atom._NET_NUMBER_OF_DESKTOPS, XA_CARDINAL);
+}
+
+
+int server_get_current_desktop ()
+{
+ return get_property32(server.root_win, server.atom._NET_CURRENT_DESKTOP, XA_CARDINAL);
+}
+
+
+Window window_get_active ()
+{
+ return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW);
+}
+
+
+int window_is_active (Window win)
+{
+ return (win == get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW));
+}
+
+
+int get_icon_count (long *data, int num)
+{
+ int count, pos, w, h;
+
+ count = 0;
+ pos = 0;
+ while (pos < num) {
+ w = data[pos++];
+ h = data[pos++];
+ pos += w * h;
+ if (pos > num || w * h == 0) break;
+ count++;
+ }
+
+ return count;
+}
+
+
+long *get_best_icon (long *data, int icon_count, int num, int *iw, int *ih, int best_icon_size)
+{
+ int width[icon_count], height[icon_count], pos, i, w, h;
+ long *icon_data[icon_count];
+
+ /* List up icons */
+ pos = 0;
+ i = icon_count;
+ while (i--) {
+ w = data[pos++];
+ h = data[pos++];
+ if (pos + w * h > num) break;
+
+ width[i] = w;
+ height[i] = h;
+ icon_data[i] = &data[pos];
+
+ pos += w * h;
+ }
+
+ /* Try to find exact size */
+ int icon_num = -1;
+ for (i = 0; i < icon_count; i++) {
+ if (width[i] == best_icon_size) {
+ icon_num = i;
+ break;
+ }
+ }
+
+ /* Take the biggest or whatever */
+ if (icon_num < 0) {
+ int highest = 0;
+ for (i = 0; i < icon_count; i++) {
+ if (width[i] > highest) {
+ icon_num = i;
+ highest = width[i];
+ }
+ }
+ }
+
+ *iw = width[icon_num];
+ *ih = height[icon_num];
+ return icon_data[icon_num];
+}
+
+
+void draw_rect(cairo_t *c, double x, double y, double w, double h, double r)
+{
+ if (r > 0.0) {
+ double c1 = 0.55228475 * r;
+
+ cairo_move_to(c, x+r, y);
+ cairo_rel_line_to(c, w-2*r, 0);
+ cairo_rel_curve_to(c, c1, 0.0, r, c1, r, r);
+ cairo_rel_line_to(c, 0, h-2*r);
+ cairo_rel_curve_to(c, 0.0, c1, c1-r, r, -r, r);
+ cairo_rel_line_to (c, -w +2*r, 0);
+ cairo_rel_curve_to (c, -c1, 0, -r, -c1, -r, -r);
+ cairo_rel_line_to (c, 0, -h + 2 * r);
+ cairo_rel_curve_to (c, 0, -c1, r - c1, -r, r, -r);
+ }
+ else
+ cairo_rectangle(c, x, y, w, h);
+}
+
+
+void get_text_size(PangoFontDescription *font, int *height_ink, int *height, int panel_height, char *text, int len)
+{
+ PangoRectangle rect_ink, rect;
+
+ Pixmap pmap = server_create_pixmap (panel_height, panel_height);
+ cairo_surface_t *cs = cairo_xlib_surface_create (server.dsp, pmap, server.visual, panel_height, panel_height);
+ cairo_t *c = cairo_create (cs);
+
+ PangoLayout *layout = pango_cairo_create_layout (c);
+ pango_layout_set_font_description (layout, font);
+ pango_layout_set_text (layout, text, len);
+
+ pango_layout_get_pixel_extents(layout, &rect_ink, &rect);
+ *height_ink = rect_ink.height;
+ *height = rect.height;
+ //printf("dimension : %d - %d\n", rect_ink.height, rect.height);
+
+ g_object_unref (layout);
+ cairo_destroy (c);
+ cairo_surface_destroy (cs);
+ XFreePixmap (server.dsp, pmap);
+}
+
+
+
--- /dev/null
+/**************************************************************************
+* window :
+* -
+*
+* Check COPYING file for Copyright
+*
+**************************************************************************/
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <cairo.h>
+#include <cairo-xlib.h>
+#include <pango/pangocairo.h>
+
+
+typedef struct window_global
+{
+ Window main_win;
+} window_global;
+
+window_global window;
+
+void set_active (Window win);
+void set_desktop (int desktop);
+void set_close (Window win);
+int server_get_current_desktop ();
+int server_get_number_of_desktop ();
+int window_is_iconified (Window win);
+int window_is_hidden (Window win);
+int window_is_active (Window win);
+int get_icon_count (long *data, int num);
+long *get_best_icon (long *data, int icon_count, int num, int *iw, int *ih, int best_icon_size);
+void window_toggle_shade (Window win);
+int window_get_desktop (Window win);
+void windows_set_desktop (Window win, int desktop);
+int window_get_monitor (Window win);
+Window window_get_active ();
+
+// draw rounded rectangle
+void draw_rect(cairo_t *c, double x, double y, double w, double h, double r);
+
+void get_text_size(PangoFontDescription *font, int *height_ink, int *height, int panel_height, char *text, int len);
+
+
+#endif
--- /dev/null
+#---------------------------------------------
+# TINT CONFIG FILE
+#---------------------------------------------
+
+#---------------------------------------------
+# BACKGROUND AND BORDER
+#---------------------------------------------
+rounded = 1
+border_width = 1
+background_color = #282828 100
+border_color = #000000 100
+
+rounded = 1
+border_width = 1
+background_color = #282828 100
+#background_color = #3b3b3b 100
+border_color = #cccccc 100
+
+#---------------------------------------------
+# PANEL
+#---------------------------------------------
+panel_monitor = 1
+panel_position = bottom right
+panel_size = 0 27
+panel_margin = 0 0
+panel_padding = 3 2
+font_shadow = 0
+panel_background_id = 1
+
+#---------------------------------------------
+# TASKBAR
+#---------------------------------------------
+taskbar_mode = multi_desktop
+taskbar_padding = 4 0
+taskbar_background_id = 0
+
+#---------------------------------------------
+# TASKS
+#---------------------------------------------
+task_icon = 1
+task_text = 1
+task_width = 200
+task_centered = 1
+task_padding = 1 3
+task_font = sans 8
+task_font_color = #ffffff 40
+task_active_font_color = #ffffff 100
+task_background_id = 0
+task_active_background_id = 2
+
+#---------------------------------------------
+# SYSTRAY
+#---------------------------------------------
+#systray_padding = 9 3
+#systray_background_id = 0
+
+#---------------------------------------------
+# CLOCK
+#---------------------------------------------
+time1_format = %H:%M:%S
+time1_font = sans 7
+time2_format = %A %d %B
+time2_font = sans 7
+clock_font_color = #ffffff 100
+clock_padding = 0 0
+clock_background_id = 0
+
+#---------------------------------------------
+# MOUSE ACTION ON TASK
+#---------------------------------------------
+mouse_middle = none
+mouse_right = close
+mouse_scroll_up = toggle
+mouse_scroll_down = iconify
+
--- /dev/null
+#---------------------------------------------
+# TINT CONFIG FILE
+#---------------------------------------------
+
+#---------------------------------------------
+# BACKGROUND AND BORDER
+#---------------------------------------------
+rounded = 5
+border_width = 1
+background_color = #ffffff 40
+border_color = #ffffff 70
+
+rounded = 4
+border_width = 0
+background_color = #ffffff 0
+border_color = #d1d1d1 0
+
+rounded = 4
+border_width = 0
+background_color = #ffffff 30
+border_color = #d1d1d1 14
+
+#---------------------------------------------
+# PANEL
+#---------------------------------------------
+panel_monitor = 1
+panel_position = bottom center
+panel_size = 1000 25
+panel_margin = 0 0
+panel_padding = 6 0
+font_shadow = 0
+panel_background_id = 1
+
+#---------------------------------------------
+# TASKBAR
+#---------------------------------------------
+taskbar_mode = multi_desktop
+taskbar_padding = 2 3
+taskbar_background_id = 0
+
+#---------------------------------------------
+# TASKS
+#---------------------------------------------
+task_icon = 1
+task_text = 1
+task_width = 150
+task_centered = 1
+task_padding = 3 2
+task_font = myriad pro 8
+task_font_color = #000000 70
+task_active_font_color = #000000 100
+task_background_id = 2
+task_active_background_id = 3
+
+#---------------------------------------------
+# SYSTRAY
+#---------------------------------------------
+#systray_padding = 9 3
+#systray_background_id = 0
+
+#---------------------------------------------
+# CLOCK
+#---------------------------------------------
+time1_format = %H:%M
+time1_font = sans bold 12
+#time2_format = %A %d %B
+#time2_font = sans bold 10
+clock_font_color = #000000 70
+clock_padding = 6 0
+clock_background_id = 0
+
+#---------------------------------------------
+# MOUSE ACTION ON TASK
+#---------------------------------------------
+mouse_middle = none
+mouse_right = close
+mouse_scroll_up = toggle
+mouse_scroll_down = iconify
+
--- /dev/null
+#---------------------------------------------
+# TINT CONFIG FILE
+#---------------------------------------------
+
+#---------------------------------------------
+# BACKGROUND AND BORDER
+#---------------------------------------------
+rounded = 3
+border_width = 1
+background_color = #3c3020 90
+border_color = #3c3020 90
+
+rounded = 3
+border_width = 1
+background_color = #3c3020 90
+border_color = #ffffff 30
+
+#---------------------------------------------
+# PANEL
+#---------------------------------------------
+panel_monitor = 1
+panel_position = bottom center
+panel_size = 900 30
+panel_margin = 0 0
+panel_padding = 10 2
+font_shadow = 0
+panel_background_id = 0
+
+#---------------------------------------------
+# TASKBAR
+#---------------------------------------------
+taskbar_mode = single_desktop
+taskbar_padding = 9 0
+taskbar_background_id = 0
+
+#---------------------------------------------
+# TASKS
+#---------------------------------------------
+task_icon = 0
+task_text = 1
+task_width = 190
+task_centered = 1
+task_padding = 2 0
+task_font = sans 8.4
+task_font_color = #ececec 50
+task_active_font_color = #ffffff 90
+task_background_id = 1
+task_active_background_id = 2
+
+#---------------------------------------------
+# SYSTRAY
+#---------------------------------------------
+#systray_padding = 9 3
+#systray_background_id = 0
+
+#---------------------------------------------
+# CLOCK
+#---------------------------------------------
+time1_format = %H:%M
+time1_font = sans bold 8
+time2_format = %A %d %B
+time2_font = sans 7
+clock_font_color = #ececec 50
+clock_padding = 4 0
+clock_background_id = 1
+
+#---------------------------------------------
+# MOUSE ACTION ON TASK
+#---------------------------------------------
+mouse_middle = none
+mouse_right = close
+mouse_scroll_up = toggle
+mouse_scroll_down = iconify
+
--- /dev/null
+#---------------------------------------------
+# TINT CONFIG FILE
+#---------------------------------------------
+
+#---------------------------------------------
+# BACKGROUND AND BORDER
+#---------------------------------------------
+rounded = 10
+border_width = 1
+background_color = #000000 45
+border_color = #ffffff 0
+
+rounded = 7
+border_width = 1
+background_color = #ffffff 0
+border_color = #ffffff 70
+
+
+#---------------------------------------------
+# PANEL
+#---------------------------------------------
+panel_monitor = 1
+panel_position = bottom left
+panel_size = 1010 30
+panel_margin = 0 0
+panel_padding = 11 2
+font_shadow = 0
+panel_background_id = 0
+
+#---------------------------------------------
+# TASKBAR
+#---------------------------------------------
+taskbar_mode = multi_desktop
+taskbar_padding = 3 3
+taskbar_background_id = 1
+
+#---------------------------------------------
+# TASKS
+#---------------------------------------------
+task_icon = 0
+task_text = 1
+task_width = 160
+task_centered = 1
+task_padding = 2 2
+task_font = sans bold 8
+task_font_color = #ffffff 60
+task_active_font_color = #ffffff 95
+task_background_id = 0
+task_active_background_id = 2
+
+#---------------------------------------------
+# SYSTRAY
+#---------------------------------------------
+#systray_padding = 9 3
+#systray_icon_opacity = 50
+#systray_background_id = 1
+
+#---------------------------------------------
+# CLOCK
+#---------------------------------------------
+time1_format = %A %d %H:%M
+time1_font = sans bold 8
+#time2_format = %A %d %B
+time2_font = sans 7
+clock_font_color = #ffffff 59
+clock_padding = 6 0
+clock_background_id = 1
+
+#---------------------------------------------
+# MOUSE ACTION ON TASK
+#---------------------------------------------
+mouse_middle = none
+mouse_right = close
+mouse_scroll_up = toggle
+mouse_scroll_down = iconify
+