]> Dogcows Code - chaz/tint2/commitdiff
New import
authorThierry Lorthiois <lorthiois@bbsoft.fr>
Thu, 2 Oct 2008 18:47:02 +0000 (18:47 +0000)
committerThierry Lorthiois <lorthiois@bbsoft.fr>
Thu, 2 Oct 2008 18:47:02 +0000 (18:47 +0000)
46 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
README [new file with mode: 0644]
doc/man/tint2.1 [new file with mode: 0644]
doc/tint2-0.7.odt [new file with mode: 0644]
doc/tint2-0.7.pdf [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/clock/clock.c [new file with mode: 0644]
src/clock/clock.h [new file with mode: 0644]
src/config.c [new file with mode: 0644]
src/config.h [new file with mode: 0644]
src/panel.c [new file with mode: 0644]
src/panel.h [new file with mode: 0644]
src/server.c [new file with mode: 0644]
src/server.h [new file with mode: 0644]
src/systray/Makefile [new file with mode: 0644]
src/systray/README [new file with mode: 0644]
src/systray/docker.c [new file with mode: 0644]
src/systray/docker.h [new file with mode: 0644]
src/systray/icons.c [new file with mode: 0644]
src/systray/icons.h [new file with mode: 0644]
src/systray/kde.c [new file with mode: 0644]
src/systray/kde.h [new file with mode: 0644]
src/systray/net.c [new file with mode: 0644]
src/systray/net.h [new file with mode: 0644]
src/systray/tint_merge.h [new file with mode: 0644]
src/systray/version.h [new file with mode: 0644]
src/systray/version.h.in [new file with mode: 0644]
src/systray/xproperty.c [new file with mode: 0644]
src/systray/xproperty.h [new file with mode: 0644]
src/taskbar/task.c [new file with mode: 0644]
src/taskbar/task.h [new file with mode: 0644]
src/taskbar/taskbar.c [new file with mode: 0644]
src/taskbar/taskbar.h [new file with mode: 0644]
src/tint.c [new file with mode: 0644]
src/tint2 [new file with mode: 0755]
src/util/area.c [new file with mode: 0644]
src/util/area.h [new file with mode: 0644]
src/util/common.h [new file with mode: 0644]
src/util/window.c [new file with mode: 0644]
src/util/window.h [new file with mode: 0644]
tintrc03 [new file with mode: 0644]
tintrc04 [new file with mode: 0644]
tintrc05 [new file with mode: 0644]
tintrc06 [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..2a12de2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,9 @@
+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
+
+
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   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.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..ffde567
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,252 @@
+
+
+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'.
+
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..a250d34
--- /dev/null
+++ b/README
@@ -0,0 +1,18 @@
+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.
+
+
diff --git a/doc/man/tint2.1 b/doc/man/tint2.1
new file mode 100644 (file)
index 0000000..ce4646b
--- /dev/null
@@ -0,0 +1,50 @@
+.\"                                      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.
diff --git a/doc/tint2-0.7.odt b/doc/tint2-0.7.odt
new file mode 100644 (file)
index 0000000..6a99fbb
Binary files /dev/null and b/doc/tint2-0.7.odt differ
diff --git a/doc/tint2-0.7.pdf b/doc/tint2-0.7.pdf
new file mode 100644 (file)
index 0000000..873effd
Binary files /dev/null and b/doc/tint2-0.7.pdf differ
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..3eecbbb
--- /dev/null
@@ -0,0 +1,36 @@
+#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)
+
diff --git a/src/clock/clock.c b/src/clock/clock.c
new file mode 100644 (file)
index 0000000..f91e969
--- /dev/null
@@ -0,0 +1,126 @@
+/**************************************************************************
+*
+* 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;
+}
+
diff --git a/src/clock/clock.h b/src/clock/clock.h
new file mode 100644 (file)
index 0000000..0d3e9e1
--- /dev/null
@@ -0,0 +1,39 @@
+/**************************************************************************
+* 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
diff --git a/src/config.c b/src/config.c
new file mode 100644 (file)
index 0000000..c38cfec
--- /dev/null
@@ -0,0 +1,751 @@
+/**************************************************************************
+*
+* 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;
+}
+
diff --git a/src/config.h b/src/config.h
new file mode 100644 (file)
index 0000000..1fcd1ed
--- /dev/null
@@ -0,0 +1,24 @@
+/**************************************************************************
+* 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
diff --git a/src/panel.c b/src/panel.c
new file mode 100644 (file)
index 0000000..2e1c228
--- /dev/null
@@ -0,0 +1,249 @@
+/**************************************************************************
+*
+* 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);
+   }
+}
+
+
diff --git a/src/panel.h b/src/panel.h
new file mode 100644 (file)
index 0000000..1acd611
--- /dev/null
@@ -0,0 +1,85 @@
+/**************************************************************************
+* 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
diff --git a/src/server.c b/src/server.c
new file mode 100644 (file)
index 0000000..cdfa969
--- /dev/null
@@ -0,0 +1,216 @@
+/**************************************************************************
+*
+* 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);
+   }
+}
+
+
diff --git a/src/server.h b/src/server.h
new file mode 100644 (file)
index 0000000..6bb4060
--- /dev/null
@@ -0,0 +1,102 @@
+/**************************************************************************
+* 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
diff --git a/src/systray/Makefile b/src/systray/Makefile
new file mode 100644 (file)
index 0000000..03a2270
--- /dev/null
@@ -0,0 +1,71 @@
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                       #
+# 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
diff --git a/src/systray/README b/src/systray/README
new file mode 100644 (file)
index 0000000..c851765
--- /dev/null
@@ -0,0 +1,75 @@
+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
diff --git a/src/systray/docker.c b/src/systray/docker.c
new file mode 100644 (file)
index 0000000..091c62e
--- /dev/null
@@ -0,0 +1,346 @@
+#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;
+}
+*/
diff --git a/src/systray/docker.h b/src/systray/docker.h
new file mode 100644 (file)
index 0000000..f60376e
--- /dev/null
@@ -0,0 +1,31 @@
+#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 */
diff --git a/src/systray/icons.c b/src/systray/icons.c
new file mode 100644 (file)
index 0000000..5c5b240
--- /dev/null
@@ -0,0 +1,122 @@
+#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();
+}
diff --git a/src/systray/icons.h b/src/systray/icons.h
new file mode 100644 (file)
index 0000000..1d2a09c
--- /dev/null
@@ -0,0 +1,13 @@
+#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 */
diff --git a/src/systray/kde.c b/src/systray/kde.c
new file mode 100644 (file)
index 0000000..32e1848
--- /dev/null
@@ -0,0 +1,76 @@
+#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);
+}
diff --git a/src/systray/kde.h b/src/systray/kde.h
new file mode 100644 (file)
index 0000000..cb85d3d
--- /dev/null
@@ -0,0 +1,12 @@
+#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 */
diff --git a/src/systray/net.c b/src/systray/net.c
new file mode 100644 (file)
index 0000000..9f0c94a
--- /dev/null
@@ -0,0 +1,119 @@
+#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);
+}
diff --git a/src/systray/net.h b/src/systray/net.h
new file mode 100644 (file)
index 0000000..9d350ea
--- /dev/null
@@ -0,0 +1,15 @@
+#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 */
diff --git a/src/systray/tint_merge.h b/src/systray/tint_merge.h
new file mode 100644 (file)
index 0000000..475ebac
--- /dev/null
@@ -0,0 +1,21 @@
+/**************************************************************************
+* 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
+
diff --git a/src/systray/version.h b/src/systray/version.h
new file mode 100644 (file)
index 0000000..0b62be9
--- /dev/null
@@ -0,0 +1 @@
+#define VERSION "1.5"
diff --git a/src/systray/version.h.in b/src/systray/version.h.in
new file mode 100644 (file)
index 0000000..a44b122
--- /dev/null
@@ -0,0 +1 @@
+#define VERSION "@VERSION@"
diff --git a/src/systray/xproperty.c b/src/systray/xproperty.c
new file mode 100644 (file)
index 0000000..855379c
--- /dev/null
@@ -0,0 +1,64 @@
+#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);
+}
diff --git a/src/systray/xproperty.h b/src/systray/xproperty.h
new file mode 100644 (file)
index 0000000..81bc69a
--- /dev/null
@@ -0,0 +1,13 @@
+#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 */
diff --git a/src/taskbar/task.c b/src/taskbar/task.c
new file mode 100644 (file)
index 0000000..f0b9924
--- /dev/null
@@ -0,0 +1,287 @@
+/**************************************************************************
+*
+* 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;
+}
+
diff --git a/src/taskbar/task.h b/src/taskbar/task.h
new file mode 100644 (file)
index 0000000..bab6c74
--- /dev/null
@@ -0,0 +1,67 @@
+/**************************************************************************
+* 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
+
diff --git a/src/taskbar/taskbar.c b/src/taskbar/taskbar.c
new file mode 100644 (file)
index 0000000..05ba366
--- /dev/null
@@ -0,0 +1,143 @@
+/**************************************************************************
+*
+* 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;
+}
+
+
diff --git a/src/taskbar/taskbar.h b/src/taskbar/taskbar.h
new file mode 100644 (file)
index 0000000..3b3560d
--- /dev/null
@@ -0,0 +1,39 @@
+
+#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
+
diff --git a/src/tint.c b/src/tint.c
new file mode 100644 (file)
index 0000000..42581ff
--- /dev/null
@@ -0,0 +1,441 @@
+/**************************************************************************
+*
+* 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");
+      }      
+   }
+}
+
+
diff --git a/src/tint2 b/src/tint2
new file mode 100755 (executable)
index 0000000..08a6116
Binary files /dev/null and b/src/tint2 differ
diff --git a/src/util/area.c b/src/util/area.c
new file mode 100644 (file)
index 0000000..2f44cf5
--- /dev/null
@@ -0,0 +1,182 @@
+/**************************************************************************
+*
+* 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);
+
+}
+
diff --git a/src/util/area.h b/src/util/area.h
new file mode 100644 (file)
index 0000000..2ad26aa
--- /dev/null
@@ -0,0 +1,140 @@
+/**************************************************************************
+* 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
+
diff --git a/src/util/common.h b/src/util/common.h
new file mode 100644 (file)
index 0000000..313a3b7
--- /dev/null
@@ -0,0 +1,41 @@
+/**************************************************************************
+* 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
+
diff --git a/src/util/window.c b/src/util/window.c
new file mode 100644 (file)
index 0000000..ebbdce0
--- /dev/null
@@ -0,0 +1,264 @@
+/**************************************************************************
+*
+* 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);
+}
+
+
+
diff --git a/src/util/window.h b/src/util/window.h
new file mode 100644 (file)
index 0000000..fd596c0
--- /dev/null
@@ -0,0 +1,46 @@
+/**************************************************************************
+* 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
diff --git a/tintrc03 b/tintrc03
new file mode 100644 (file)
index 0000000..914dfd1
--- /dev/null
+++ b/tintrc03
@@ -0,0 +1,75 @@
+#---------------------------------------------
+# 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
+
diff --git a/tintrc04 b/tintrc04
new file mode 100644 (file)
index 0000000..fd930d4
--- /dev/null
+++ b/tintrc04
@@ -0,0 +1,79 @@
+#---------------------------------------------
+# 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
+
diff --git a/tintrc05 b/tintrc05
new file mode 100644 (file)
index 0000000..5c7378b
--- /dev/null
+++ b/tintrc05
@@ -0,0 +1,74 @@
+#---------------------------------------------
+# 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
+
diff --git a/tintrc06 b/tintrc06
new file mode 100644 (file)
index 0000000..741bb8b
--- /dev/null
+++ b/tintrc06
@@ -0,0 +1,76 @@
+#---------------------------------------------
+# 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
+
This page took 0.133901 seconds and 4 git commands to generate.