New import
git-svn-id: http://tint2.googlecode.com/svn/trunk@13 121b4492-b84c-0410-8b4c-0d4edfb3f3cc
This commit is contained in:
parent
a5f3607239
commit
420dd5d1e2
46 changed files with 5231 additions and 0 deletions
9
AUTHORS
Normal file
9
AUTHORS
Normal file
|
@ -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
|
||||||
|
|
||||||
|
|
340
COPYING
Normal file
340
COPYING
Normal file
|
@ -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.
|
||||||
|
|
||||||
|
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.)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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.
|
252
ChangeLog
Normal file
252
ChangeLog
Normal file
|
@ -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'.
|
||||||
|
|
||||||
|
|
18
README
Normal file
18
README
Normal file
|
@ -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.
|
||||||
|
|
||||||
|
|
50
doc/man/tint2.1
Normal file
50
doc/man/tint2.1
Normal file
|
@ -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.
|
BIN
doc/tint2-0.7.odt
Normal file
BIN
doc/tint2-0.7.odt
Normal file
Binary file not shown.
BIN
doc/tint2-0.7.pdf
Normal file
BIN
doc/tint2-0.7.pdf
Normal file
Binary file not shown.
36
src/Makefile
Normal file
36
src/Makefile
Normal file
|
@ -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)
|
||||||
|
|
126
src/clock/clock.c
Normal file
126
src/clock/clock.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
39
src/clock/clock.h
Normal file
39
src/clock/clock.h
Normal file
|
@ -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
|
751
src/config.c
Normal file
751
src/config.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
24
src/config.h
Normal file
24
src/config.h
Normal file
|
@ -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
|
249
src/panel.c
Normal file
249
src/panel.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
85
src/panel.h
Normal file
85
src/panel.h
Normal file
|
@ -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
|
216
src/server.c
Normal file
216
src/server.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
102
src/server.h
Normal file
102
src/server.h
Normal file
|
@ -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
|
71
src/systray/Makefile
Normal file
71
src/systray/Makefile
Normal file
|
@ -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
|
75
src/systray/README
Normal file
75
src/systray/README
Normal file
|
@ -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
|
346
src/systray/docker.c
Normal file
346
src/systray/docker.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
*/
|
31
src/systray/docker.h
Normal file
31
src/systray/docker.h
Normal file
|
@ -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 */
|
122
src/systray/icons.c
Normal file
122
src/systray/icons.c
Normal file
|
@ -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();
|
||||||
|
}
|
13
src/systray/icons.h
Normal file
13
src/systray/icons.h
Normal file
|
@ -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 */
|
76
src/systray/kde.c
Normal file
76
src/systray/kde.c
Normal file
|
@ -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);
|
||||||
|
}
|
12
src/systray/kde.h
Normal file
12
src/systray/kde.h
Normal file
|
@ -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 */
|
119
src/systray/net.c
Normal file
119
src/systray/net.c
Normal file
|
@ -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);
|
||||||
|
}
|
15
src/systray/net.h
Normal file
15
src/systray/net.h
Normal file
|
@ -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 */
|
21
src/systray/tint_merge.h
Normal file
21
src/systray/tint_merge.h
Normal file
|
@ -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
|
||||||
|
|
1
src/systray/version.h
Normal file
1
src/systray/version.h
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#define VERSION "1.5"
|
1
src/systray/version.h.in
Normal file
1
src/systray/version.h.in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#define VERSION "@VERSION@"
|
64
src/systray/xproperty.c
Normal file
64
src/systray/xproperty.c
Normal file
|
@ -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);
|
||||||
|
}
|
13
src/systray/xproperty.h
Normal file
13
src/systray/xproperty.h
Normal file
|
@ -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 */
|
287
src/taskbar/task.c
Normal file
287
src/taskbar/task.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
67
src/taskbar/task.h
Normal file
67
src/taskbar/task.h
Normal file
|
@ -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
|
||||||
|
|
143
src/taskbar/taskbar.c
Normal file
143
src/taskbar/taskbar.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
39
src/taskbar/taskbar.h
Normal file
39
src/taskbar/taskbar.h
Normal file
|
@ -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
|
||||||
|
|
441
src/tint.c
Normal file
441
src/tint.c
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
BIN
src/tint2
Executable file
BIN
src/tint2
Executable file
Binary file not shown.
182
src/util/area.c
Normal file
182
src/util/area.c
Normal file
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
140
src/util/area.h
Normal file
140
src/util/area.h
Normal file
|
@ -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
|
||||||
|
|
41
src/util/common.h
Normal file
41
src/util/common.h
Normal file
|
@ -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
|
||||||
|
|
264
src/util/window.c
Normal file
264
src/util/window.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
46
src/util/window.h
Normal file
46
src/util/window.h
Normal file
|
@ -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
|
75
tintrc03
Normal file
75
tintrc03
Normal file
|
@ -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
|
||||||
|
|
79
tintrc04
Normal file
79
tintrc04
Normal file
|
@ -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
|
||||||
|
|
74
tintrc05
Normal file
74
tintrc05
Normal file
|
@ -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
|
||||||
|
|
76
tintrc06
Normal file
76
tintrc06
Normal file
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue