Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ee1e8f2fa | ||
|
|
690f30308f | ||
|
|
fea91746a4 | ||
|
|
9d8350dabc | ||
|
|
a6879ea2a5 | ||
|
|
d2b32d528f | ||
|
|
ad675495e6 | ||
|
|
48e7e38b11 | ||
|
|
dc191668fe | ||
|
|
955be3658b | ||
|
|
dcc163ec0b | ||
|
|
14716d41b9 | ||
|
|
9018313fb2 | ||
|
|
92b391a1b2 | ||
|
|
b023229600 | ||
|
|
82b71ec5b6 | ||
|
|
1edaf21bde | ||
|
|
76bd4baa9c |
14
ChangeLog
14
ChangeLog
@@ -1,3 +1,17 @@
|
||||
2016-05-07 0.12.10
|
||||
- Fixes:
|
||||
- Fixed crash in systray with non-Latin languagess (thanks zcodes)
|
||||
- Invalidate cached pixmaps on resize/move (issue #576)
|
||||
- Battery: do not show negative durations when the sensors return garbage
|
||||
- Proper workaround for issue #555
|
||||
|
||||
2016-04-02 0.12.9
|
||||
- Fixes:
|
||||
- Regression: Do not detect empty areas as clickable (issue #572)
|
||||
- Regression: Position and resize task icon correctly (issue #575)
|
||||
- Use imlib2 for taking screenshot; if it fails, use Xlib (issue #574)
|
||||
- Battery: lower sample frequency when there is no support for reading current/power
|
||||
|
||||
2016-03-25 0.12.8
|
||||
- Major changes (see details below):
|
||||
- Icon cache and lazy icon theme loading to improve performance in tint2 and tint2conf
|
||||
|
||||
18
README.md
18
README.md
@@ -1,26 +1,26 @@
|
||||
# New stable release: 0.12.8
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/0.12.8/ChangeLog
|
||||
# Latest stable release: 0.12.10
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/0.12.10/ChangeLog
|
||||
|
||||
Documentation: https://gitlab.com/o9000/tint2/wikis/Configure
|
||||
|
||||
Try it out with (see also [dependencies](https://gitlab.com/o9000/tint2/wikis/Install#dependencies)):
|
||||
Compile it with (see also [dependencies](https://gitlab.com/o9000/tint2/wikis/Install#dependencies)):
|
||||
```
|
||||
git clone https://gitlab.com/o9000/tint2.git
|
||||
cd tint2
|
||||
git checkout 0.12.8
|
||||
git checkout 0.12.10
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j4
|
||||
./tint2 &
|
||||
./src/tint2conf/tint2conf &
|
||||
```
|
||||
|
||||
To install from source, also run (as root):
|
||||
To install, run (as root):
|
||||
```
|
||||
make install
|
||||
```
|
||||
|
||||
And then you can run the panel `tint2` and the configuration program `tint2conf`.
|
||||
|
||||
Please report any problems to https://gitlab.com/o9000/tint2/issues. Your feedback is much appreciated.
|
||||
|
||||
P.S. GitLab is now the official location of the tint2 project, migrated from Google Code, which is shutting down. In case you are wondering why not GitHub, BitBucket etc., we chose GitLab because it is open source, it is mature and works well, looks cool and has a very nice team.
|
||||
@@ -69,10 +69,10 @@ tint2 is a simple panel/taskbar made for modern X window managers. It was specif
|
||||
|
||||
# Screenshots
|
||||
|
||||
## Default config of the latest release:
|
||||
## Default config:
|
||||
|
||||

|
||||
|
||||
## Various configurations:
|
||||
## Various configs:
|
||||
|
||||

|
||||
|
||||
@@ -150,6 +150,7 @@ void init_battery_panel(void *p)
|
||||
|
||||
battery->area.parent = p;
|
||||
battery->area.panel = p;
|
||||
snprintf(battery->area.name, sizeof(battery->area.name), "Battery");
|
||||
battery->area._draw_foreground = draw_battery;
|
||||
battery->area.size_mode = LAYOUT_FIXED;
|
||||
battery->area._resize = resize_battery;
|
||||
|
||||
@@ -306,6 +306,7 @@ static gboolean update_linux_battery(struct psy_battery *bat)
|
||||
|
||||
gint64 old_timestamp = bat->timestamp;
|
||||
int old_energy_now = bat->energy_now;
|
||||
gint old_power_now = bat->power_now;
|
||||
|
||||
/* reset values */
|
||||
bat->present = 0;
|
||||
@@ -356,6 +357,12 @@ static gboolean update_linux_battery(struct psy_battery *bat)
|
||||
/* some hardware does not support reading current power consumption */
|
||||
g_error_free(error);
|
||||
bat->power_now = estimate_power_usage(bat, old_energy_now, old_timestamp);
|
||||
if (bat->power_now == 0 && bat->status != BATTERY_FULL) {
|
||||
/* If the hardware updates the level slower than our sampling period,
|
||||
* we need to sample more rarely */
|
||||
bat->power_now = old_power_now;
|
||||
bat->timestamp = old_timestamp;
|
||||
}
|
||||
} else if (error) {
|
||||
g_error_free(error);
|
||||
return FALSE;
|
||||
@@ -430,6 +437,7 @@ int battery_os_update(BatteryState *state)
|
||||
seconds = 3600 * (total_energy_full - total_energy_now) / total_power_now;
|
||||
else if (state->state == BATTERY_DISCHARGING)
|
||||
seconds = 3600 * total_energy_now / total_power_now;
|
||||
seconds = MAX(0, seconds);
|
||||
}
|
||||
battery_state_set_time(state, seconds);
|
||||
|
||||
|
||||
@@ -180,6 +180,7 @@ void init_clock_panel(void *p)
|
||||
clock_init_fonts();
|
||||
clock->area.parent = p;
|
||||
clock->area.panel = p;
|
||||
snprintf(clock->area.name, sizeof(clock->area.name), "Clock");
|
||||
clock->area._is_under_mouse = full_width_area_is_under_mouse;
|
||||
clock->area.has_mouse_press_effect = clock->area.has_mouse_over_effect =
|
||||
panel_config.mouse_effects && (clock_lclick_command || clock_mclick_command || clock_rclick_command ||
|
||||
|
||||
@@ -155,9 +155,9 @@ void init_execp_panel(void *p)
|
||||
execp->area.paddingx = execp->backend->paddingx;
|
||||
execp->area.paddingy = execp->backend->paddingy;
|
||||
execp->area.paddingxlr = execp->backend->paddingxlr;
|
||||
|
||||
execp->area.parent = panel;
|
||||
execp->area.panel = panel;
|
||||
snprintf(execp->area.name, sizeof(execp->area.name), "Execp %s", execp->backend->command ? execp->backend->command : "null");
|
||||
execp->area._draw_foreground = draw_execp;
|
||||
execp->area.size_mode = LAYOUT_FIXED;
|
||||
execp->area._resize = resize_execp;
|
||||
|
||||
@@ -39,6 +39,7 @@ void init_freespace_panel(void *p)
|
||||
freespace->area.bg = &g_array_index(backgrounds, Background, 0);
|
||||
freespace->area.parent = p;
|
||||
freespace->area.panel = p;
|
||||
snprintf(freespace->area.name, sizeof(freespace->area.name), "Freespace");
|
||||
freespace->area.size_mode = LAYOUT_FIXED;
|
||||
freespace->area.resize_needed = 1;
|
||||
freespace->area.on_screen = TRUE;
|
||||
|
||||
@@ -83,6 +83,7 @@ void init_launcher_panel(void *p)
|
||||
|
||||
launcher->area.parent = p;
|
||||
launcher->area.panel = p;
|
||||
snprintf(launcher->area.name, sizeof(launcher->area.name), "Launcher");
|
||||
launcher->area._draw_foreground = NULL;
|
||||
launcher->area.size_mode = LAYOUT_FIXED;
|
||||
launcher->area._resize = resize_launcher;
|
||||
@@ -452,6 +453,7 @@ void launcher_load_icons(Launcher *launcher)
|
||||
if (entry.exec) {
|
||||
LauncherIcon *launcherIcon = calloc(1, sizeof(LauncherIcon));
|
||||
launcherIcon->area.panel = launcher->area.panel;
|
||||
snprintf(launcherIcon->area.name, sizeof(launcherIcon->area.name), "LauncherIcon %s", entry.name ? entry.name : "null");
|
||||
launcherIcon->area._draw_foreground = draw_launcher_icon;
|
||||
launcherIcon->area.size_mode = LAYOUT_FIXED;
|
||||
launcherIcon->area._resize = NULL;
|
||||
|
||||
17
src/panel.c
17
src/panel.c
@@ -99,6 +99,7 @@ void default_panel()
|
||||
backgrounds = g_array_new(0, 0, sizeof(Background));
|
||||
|
||||
memset(&panel_config, 0, sizeof(Panel));
|
||||
snprintf(panel_config.area.name, sizeof(panel_config.area.name), "Panel");
|
||||
panel_config.mouse_over_alpha = 100;
|
||||
panel_config.mouse_over_saturation = 0;
|
||||
panel_config.mouse_over_brightness = 10;
|
||||
@@ -196,6 +197,7 @@ void init_panel()
|
||||
p->area.bg = &g_array_index(backgrounds, Background, 0);
|
||||
p->area.parent = p;
|
||||
p->area.panel = p;
|
||||
snprintf(p->area.name, sizeof(p->area.name), "Panel %d", i);
|
||||
p->area.on_screen = TRUE;
|
||||
p->area.resize_needed = 1;
|
||||
p->area.size_mode = LAYOUT_DYNAMIC;
|
||||
@@ -601,6 +603,21 @@ void place_panel_all_desktops(Panel *p)
|
||||
num_atoms);
|
||||
}
|
||||
|
||||
void replace_panel_all_desktops(Panel *p)
|
||||
{
|
||||
XClientMessageEvent m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.type = ClientMessage;
|
||||
m.send_event = True;
|
||||
m.display = server.display;
|
||||
m.window = p->main_win;
|
||||
m.message_type = server.atom._NET_WM_DESKTOP;
|
||||
m.format = 32;
|
||||
m.data.l[0] = ALL_DESKTOPS;
|
||||
XSendEvent(server.display, server.root_win, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&m);
|
||||
XSync(server.display, False);
|
||||
}
|
||||
|
||||
void set_panel_properties(Panel *p)
|
||||
{
|
||||
XStoreName(server.display, p->main_win, panel_window_name);
|
||||
|
||||
@@ -155,6 +155,7 @@ void render_panel(Panel *panel);
|
||||
|
||||
void set_panel_items_order(Panel *p);
|
||||
void place_panel_all_desktops(Panel *p);
|
||||
void replace_panel_all_desktops(Panel *p);
|
||||
void set_panel_properties(Panel *p);
|
||||
|
||||
// draw background panel
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "systraybar.h"
|
||||
#include "server.h"
|
||||
#include "panel.h"
|
||||
#include "window.h"
|
||||
|
||||
GSList *icons;
|
||||
|
||||
@@ -113,6 +114,7 @@ void init_systray_panel(void *p)
|
||||
Panel *panel = (Panel *)p;
|
||||
systray.area.parent = panel;
|
||||
systray.area.panel = panel;
|
||||
snprintf(systray.area.name, sizeof(systray.area.name), "Systray");
|
||||
if (!systray.area.bg)
|
||||
systray.area.bg = &g_array_index(backgrounds, Background, 0);
|
||||
show(&systray.area);
|
||||
@@ -533,15 +535,7 @@ gboolean add_icon(Window win)
|
||||
|
||||
XSelectInput(server.display, win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
|
||||
|
||||
XTextProperty xname;
|
||||
char *name;
|
||||
if (XGetWMName(server.display, win, &xname)) {
|
||||
name = strdup((char *)xname.value);
|
||||
XFree(xname.value);
|
||||
} else {
|
||||
name = strdup("");
|
||||
}
|
||||
|
||||
char *name = get_window_name(win);
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d win = %lu (%s)\n", profiling_get_time(), __FUNCTION__, __LINE__, win, name);
|
||||
Panel *panel = systray.area.panel;
|
||||
@@ -1067,15 +1061,7 @@ void systray_property_notify(TrayWindow *traywin, XEvent *e)
|
||||
Atom at = e->xproperty.atom;
|
||||
if (at == server.atom.WM_NAME) {
|
||||
free(traywin->name);
|
||||
|
||||
XTextProperty xname;
|
||||
if (XGetWMName(server.display, traywin->win, &xname)) {
|
||||
traywin->name = strdup((char *)xname.value);
|
||||
XFree(xname.value);
|
||||
} else {
|
||||
traywin->name = strdup("");
|
||||
}
|
||||
|
||||
traywin->name = get_window_name(traywin->win);
|
||||
if (systray.sort == SYSTRAY_SORT_ASCENDING || systray.sort == SYSTRAY_SORT_DESCENDING) {
|
||||
systray.list_icons = g_slist_sort(systray.list_icons, compare_traywindows);
|
||||
// print_icons();
|
||||
|
||||
@@ -65,6 +65,7 @@ Task *add_task(Window win)
|
||||
|
||||
Task task_template;
|
||||
memset(&task_template, 0, sizeof(task_template));
|
||||
snprintf(task_template.area.name, sizeof(task_template.area.name), "Task %d", (int)win);
|
||||
task_template.area.has_mouse_over_effect = panel_config.mouse_effects;
|
||||
task_template.area.has_mouse_press_effect = panel_config.mouse_effects;
|
||||
task_template.area._is_under_mouse = full_width_area_is_under_mouse;
|
||||
@@ -82,6 +83,7 @@ Task *add_task(Window win)
|
||||
}
|
||||
task_update_title(&task_template);
|
||||
task_update_icon(&task_template);
|
||||
snprintf(task_template.area.name, sizeof(task_template.area.name), "Task %d %s", (int)win, task_template.title ? task_template.title : "null");
|
||||
|
||||
// fprintf(stderr, "%s %d: win = %ld, task = %s\n", __FUNCTION__, __LINE__, win, task_template.title ?
|
||||
// task_template.title : "??");
|
||||
@@ -367,7 +369,7 @@ void draw_task_icon(Task *task, int text_width)
|
||||
else
|
||||
pos_x = (task->area.width - panel->g_task.icon_size1) / 2;
|
||||
} else {
|
||||
pos_x = panel->g_task.area.paddingxlr + task->area.bg->border.width;
|
||||
pos_x = task->area.bg->border.width + task->area.paddingxlr;
|
||||
}
|
||||
|
||||
// Render
|
||||
@@ -386,12 +388,12 @@ void draw_task_icon(Task *task, int text_width)
|
||||
}
|
||||
|
||||
imlib_context_set_image(image);
|
||||
render_image(task->area.pix, pos_x, panel->g_task.icon_posy);
|
||||
render_image(task->area.pix, pos_x, (task->area.height - panel->g_task.icon_size1) / 2);
|
||||
if (0) {
|
||||
fprintf(stderr, "Task icon size: %d %d pos %d\n", imlib_image_get_width(), imlib_image_get_height(), pos_x);
|
||||
fprintf(stderr, "Task icon size: %d %d pos %d %d\n", imlib_image_get_width(), imlib_image_get_height(), pos_x, panel->g_task.icon_posy);
|
||||
fprintf(stderr, "Task max size : %d %d\n", panel->g_task.maximum_width, panel->g_task.maximum_height);
|
||||
fprintf(stderr, "Task area size: %d %d\n", task->area.width, task->area.height);
|
||||
fprintf(stderr, "Task area bord: %d\n", task->area.bg->border.width);
|
||||
fprintf(stderr, "Task border : %d\n", task->area.bg->border.width);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@ void init_taskbar_panel(void *p)
|
||||
|
||||
// taskbar name
|
||||
panel->g_taskbar.area_name.panel = panel;
|
||||
snprintf(panel->g_taskbar.area_name.name, sizeof(panel->g_taskbar.area_name.name), "Taskbarname");
|
||||
panel->g_taskbar.area_name.size_mode = LAYOUT_FIXED;
|
||||
panel->g_taskbar.area_name._resize = resize_taskbarname;
|
||||
panel->g_taskbar.area_name._is_under_mouse = full_width_area_is_under_mouse;
|
||||
@@ -158,6 +159,7 @@ void init_taskbar_panel(void *p)
|
||||
// taskbar
|
||||
panel->g_taskbar.area.parent = panel;
|
||||
panel->g_taskbar.area.panel = panel;
|
||||
snprintf(panel->g_taskbar.area.name, sizeof(panel->g_taskbar.area.name), "Taskbar");
|
||||
panel->g_taskbar.area.size_mode = LAYOUT_DYNAMIC;
|
||||
panel->g_taskbar.area.alignment = taskbar_alignment;
|
||||
panel->g_taskbar.area._resize = resize_taskbar;
|
||||
@@ -178,6 +180,7 @@ void init_taskbar_panel(void *p)
|
||||
|
||||
// task
|
||||
panel->g_task.area.panel = panel;
|
||||
snprintf(panel->g_task.area.name, sizeof(panel->g_task.area.name), "Task");
|
||||
panel->g_task.area.size_mode = LAYOUT_DYNAMIC;
|
||||
panel->g_task.area._draw_foreground = draw_task;
|
||||
panel->g_task.area._on_change_layout = on_change_task;
|
||||
@@ -220,10 +223,16 @@ void init_taskbar_panel(void *p)
|
||||
if ((panel->g_task.config_background_mask & (1 << TASK_URGENT)) == 0)
|
||||
panel->g_task.background[TASK_URGENT] = panel->g_task.background[TASK_ACTIVE];
|
||||
|
||||
if (!panel->g_task.maximum_width)
|
||||
panel->g_task.maximum_width = server.monitors[panel->monitor].width;
|
||||
if (!panel->g_task.maximum_height)
|
||||
panel->g_task.maximum_height = server.monitors[panel->monitor].height;
|
||||
|
||||
if (panel_horizontal) {
|
||||
panel->g_task.area.posy = panel->g_taskbar.area.posy +
|
||||
panel->g_taskbar.background[TASKBAR_NORMAL]->border.width +
|
||||
panel->g_taskbar.area.paddingy;
|
||||
panel->g_task.area.width = panel->g_task.maximum_width;
|
||||
panel->g_task.area.height = panel->area.height - (2 * panel->g_task.area.posy);
|
||||
} else {
|
||||
panel->g_task.area.posx = panel->g_taskbar.area.posx +
|
||||
@@ -259,19 +268,26 @@ void init_taskbar_panel(void *p)
|
||||
PANGO_ELLIPSIZE_END,
|
||||
FALSE);
|
||||
|
||||
if (!panel->g_task.maximum_width && panel_horizontal)
|
||||
panel->g_task.maximum_width = server.monitors[panel->monitor].width;
|
||||
|
||||
panel->g_task.text_posx = panel->g_task.background[0]->border.width + panel->g_task.area.paddingxlr;
|
||||
panel->g_task.text_height = panel->g_task.area.height - (2 * panel->g_task.area.paddingy);
|
||||
if (panel->g_task.has_icon) {
|
||||
panel->g_task.icon_size1 =
|
||||
MIN(panel->g_task.maximum_width, MIN(panel->g_task.maximum_height, panel->g_task.area.height)) -
|
||||
MIN(MIN(panel->g_task.maximum_width, panel->g_task.maximum_height),
|
||||
MIN(panel->g_task.area.width, panel->g_task.area.height)) -
|
||||
(2 * panel->g_task.area.paddingy) - 2 * panel->g_task.area.bg->border.width;
|
||||
panel->g_task.text_posx += panel->g_task.icon_size1 + panel->g_task.area.paddingx;
|
||||
panel->g_task.icon_posy = (panel->g_task.area.height - panel->g_task.icon_size1) / 2;
|
||||
if (0)
|
||||
printf("task: icon_size = %d, textx = %f, texth = %f, icony = %d, w = %d, h = %d, maxw = %d, maxh = %d\n",
|
||||
panel->g_task.icon_size1,
|
||||
panel->g_task.text_posx,
|
||||
panel->g_task.text_height,
|
||||
panel->g_task.icon_posy,
|
||||
panel->g_task.area.width,
|
||||
panel->g_task.area.height,
|
||||
panel->g_task.maximum_width,
|
||||
panel->g_task.maximum_height);
|
||||
}
|
||||
// printf("monitor %d, task_maximum_width %d\n", panel->monitor, panel->g_task.maximum_width);
|
||||
|
||||
Taskbar *taskbar;
|
||||
panel->num_desktops = server.num_desktops;
|
||||
|
||||
54
src/tint.c
54
src/tint.c
@@ -505,6 +505,11 @@ void init_X11_post_config()
|
||||
default_icon = imlib_load_image(path);
|
||||
g_free(path);
|
||||
}
|
||||
if (!default_icon) {
|
||||
fprintf(stderr,
|
||||
RED "Could not load default_icon.png. Please check that tint2 has been installed correctly!" RESET
|
||||
"\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
@@ -560,18 +565,45 @@ void get_snapshot(const char *path)
|
||||
XCreatePixmap(server.display, server.root_win, panel->area.width, panel->area.height, server.depth);
|
||||
render_panel(panel);
|
||||
|
||||
Imlib_Image img = NULL;
|
||||
imlib_context_set_drawable(panel->temp_pmap);
|
||||
img = imlib_create_image_from_drawable(0, 0, 0, panel->area.width, panel->area.height, 0);
|
||||
XSync(server.display, False);
|
||||
|
||||
imlib_context_set_image(img);
|
||||
if (!panel_horizontal) {
|
||||
// rotate 90° vertical panel
|
||||
imlib_image_flip_horizontal();
|
||||
imlib_image_flip_diagonal();
|
||||
imlib_context_set_drawable(panel->temp_pmap);
|
||||
Imlib_Image img = imlib_create_image_from_drawable(0, 0, 0, panel->area.width, panel->area.height, 1);
|
||||
|
||||
if (!img) {
|
||||
XImage *ximg =
|
||||
XGetImage(server.display, panel->temp_pmap, 0, 0, panel->area.width, panel->area.height, AllPlanes, ZPixmap);
|
||||
|
||||
if (ximg) {
|
||||
DATA32 *pixels = calloc(panel->area.width * panel->area.height, sizeof(DATA32));
|
||||
for (int x = 0; x < panel->area.width; x++) {
|
||||
for (int y = 0; y < panel->area.height; y++) {
|
||||
DATA32 xpixel = XGetPixel(ximg, x, y);
|
||||
|
||||
DATA32 r = (xpixel >> 16) & 0xff;
|
||||
DATA32 g = (xpixel >> 8) & 0xff;
|
||||
DATA32 b = (xpixel >> 0) & 0xff;
|
||||
DATA32 a = 0x0;
|
||||
|
||||
DATA32 argb = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
pixels[y * panel->area.width + x] = argb;
|
||||
}
|
||||
}
|
||||
XDestroyImage(ximg);
|
||||
img = imlib_create_image_using_data(panel->area.width, panel->area.height, pixels);
|
||||
}
|
||||
}
|
||||
|
||||
if (img) {
|
||||
imlib_context_set_image(img);
|
||||
if (!panel_horizontal) {
|
||||
// rotate 90° vertical panel
|
||||
imlib_image_flip_horizontal();
|
||||
imlib_image_flip_diagonal();
|
||||
}
|
||||
imlib_save_image(path);
|
||||
imlib_free_image();
|
||||
}
|
||||
imlib_save_image(path);
|
||||
imlib_free_image();
|
||||
}
|
||||
|
||||
void window_action(Task *task, MouseAction action)
|
||||
@@ -953,7 +985,7 @@ void event_property_notify(XEvent *e)
|
||||
Panel *p = &panels[i];
|
||||
if (win == p->main_win) {
|
||||
if (at == server.atom._NET_WM_DESKTOP && get_window_desktop(p->main_win) != ALL_DESKTOPS)
|
||||
place_panel_all_desktops(p);
|
||||
replace_panel_all_desktops(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,4 @@
|
||||
gboolean update_snapshot();
|
||||
void menuApply();
|
||||
void refresh_current_theme();
|
||||
extern GtkWidget *g_window;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "main.h"
|
||||
#include "properties.h"
|
||||
#include "strnatcmp.h"
|
||||
#include "theme_view.h"
|
||||
#include "common.h"
|
||||
@@ -28,17 +29,15 @@ GtkListStore *theme_list_store;
|
||||
int g_width_list, g_height_list;
|
||||
GtkCellRenderer *g_renderer;
|
||||
|
||||
gint theme_name_compare(GtkTreeModel *model,
|
||||
GtkTreeIter *a,
|
||||
GtkTreeIter *b,
|
||||
gpointer user_data);
|
||||
gint theme_name_compare(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data);
|
||||
|
||||
GtkWidget *create_view()
|
||||
{
|
||||
GtkTreeViewColumn *col;
|
||||
GtkCellRenderer *renderer;
|
||||
|
||||
theme_list_store = gtk_list_store_new(NB_COL, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF);
|
||||
theme_list_store =
|
||||
gtk_list_store_new(NB_COL, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_INT, G_TYPE_INT);
|
||||
|
||||
GtkWidget *view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(theme_list_store));
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
|
||||
@@ -51,25 +50,23 @@ GtkWidget *create_view()
|
||||
gtk_tree_view_column_pack_start(col, renderer, TRUE);
|
||||
gtk_tree_view_column_add_attribute(col, renderer, "text", COL_THEME_FILE);
|
||||
gtk_tree_view_column_set_visible(col, FALSE);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view),col);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
col = gtk_tree_view_column_new();
|
||||
gtk_tree_view_column_pack_start(col, renderer, TRUE);
|
||||
gtk_tree_view_column_add_attribute(col, renderer, "text", COL_THEME_NAME);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view),col);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
||||
|
||||
g_width_list = 200;
|
||||
g_height_list = 30;
|
||||
g_renderer = gtk_cell_renderer_pixbuf_new();
|
||||
g_object_set(g_renderer, "xalign", 0.0, NULL);
|
||||
gtk_cell_renderer_set_fixed_size(g_renderer, g_width_list, g_height_list);
|
||||
// specific to gtk-2.18 or higher
|
||||
// gtk_cell_renderer_set_padding(g_renderer, 5, 5);
|
||||
gtk_cell_renderer_set_fixed_size(g_renderer, 200, 30);
|
||||
col = gtk_tree_view_column_new();
|
||||
gtk_tree_view_column_pack_start(col, g_renderer, TRUE);
|
||||
gtk_tree_view_column_add_attribute(col, g_renderer, "pixbuf", COL_SNAPSHOT);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view),col);
|
||||
gtk_tree_view_column_add_attribute(col, g_renderer, "width", COL_WIDTH);
|
||||
gtk_tree_view_column_add_attribute(col, g_renderer, "height", COL_HEIGHT);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
||||
|
||||
GtkTreeSortable *sortable = GTK_TREE_SORTABLE(theme_list_store);
|
||||
gtk_tree_sortable_set_sort_column_id(sortable, COL_THEME_FILE, GTK_SORT_ASCENDING);
|
||||
@@ -77,10 +74,7 @@ GtkWidget *create_view()
|
||||
return view;
|
||||
}
|
||||
|
||||
gint theme_name_compare(GtkTreeModel *model,
|
||||
GtkTreeIter *a,
|
||||
GtkTreeIter *b,
|
||||
gpointer user_data)
|
||||
gint theme_name_compare(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
|
||||
{
|
||||
gchar *path_a, *path_b;
|
||||
gtk_tree_model_get(model, a, COL_THEME_FILE, &path_a, -1);
|
||||
@@ -158,23 +152,35 @@ void theme_list_append(const gchar *path)
|
||||
g_free(suffix);
|
||||
}
|
||||
|
||||
|
||||
gboolean update_snapshot()
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
const gint PADDING = 20;
|
||||
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_theme_view));
|
||||
|
||||
GtkTreeIter iter;
|
||||
gboolean have_iter;
|
||||
|
||||
gint pixWidth = 200, pixHeight = 30;
|
||||
int num_updates = 0;
|
||||
have_iter = gtk_tree_model_get_iter_first(model, &iter);
|
||||
while (have_iter) {
|
||||
GdkPixbuf *pixbuf;
|
||||
gtk_tree_model_get(model, &iter, COL_SNAPSHOT, &pixbuf, -1);
|
||||
if (pixbuf)
|
||||
g_object_unref(pixbuf);
|
||||
else
|
||||
num_updates++;
|
||||
have_iter = gtk_tree_model_iter_next(model, &iter);
|
||||
}
|
||||
gboolean need_pls_wait = num_updates > 3;
|
||||
if (need_pls_wait)
|
||||
create_please_wait(GTK_WINDOW(g_window));
|
||||
|
||||
model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_theme_view));
|
||||
have_iter = gtk_tree_model_get_iter_first(model, &iter);
|
||||
while (have_iter) {
|
||||
GdkPixbuf *pixbuf;
|
||||
gtk_tree_model_get(model, &iter, COL_SNAPSHOT, &pixbuf, -1);
|
||||
if (pixbuf) {
|
||||
pixWidth = MAX(pixWidth, gdk_pixbuf_get_width(pixbuf));
|
||||
pixHeight = MAX(pixHeight, gdk_pixbuf_get_height(pixbuf));
|
||||
g_object_unref(pixbuf);
|
||||
have_iter = gtk_tree_model_iter_next(model, &iter);
|
||||
continue;
|
||||
@@ -182,9 +188,7 @@ gboolean update_snapshot()
|
||||
|
||||
// build panel's snapshot
|
||||
gchar *path;
|
||||
gtk_tree_model_get(model, &iter,
|
||||
COL_THEME_FILE, &path,
|
||||
-1);
|
||||
gtk_tree_model_get(model, &iter, COL_THEME_FILE, &path, -1);
|
||||
|
||||
char fname[128];
|
||||
sprintf(fname, "tint2-%d.jpg", (int)getpid());
|
||||
@@ -206,16 +210,26 @@ gboolean update_snapshot()
|
||||
g_free(snap);
|
||||
g_free(path);
|
||||
|
||||
pixWidth = MAX(pixWidth, gdk_pixbuf_get_width(pixbuf));
|
||||
pixHeight = MAX(pixHeight, gdk_pixbuf_get_height(pixbuf));
|
||||
|
||||
gtk_list_store_set(theme_list_store, &iter, COL_SNAPSHOT, pixbuf, -1);
|
||||
gtk_list_store_set(theme_list_store,
|
||||
&iter,
|
||||
COL_SNAPSHOT,
|
||||
pixbuf,
|
||||
COL_WIDTH,
|
||||
gdk_pixbuf_get_width(pixbuf) + PADDING,
|
||||
COL_HEIGHT,
|
||||
gdk_pixbuf_get_height(pixbuf) + PADDING,
|
||||
-1);
|
||||
if (pixbuf)
|
||||
g_object_unref(pixbuf);
|
||||
|
||||
if (need_pls_wait)
|
||||
process_events();
|
||||
|
||||
have_iter = gtk_tree_model_iter_next(model, &iter);
|
||||
}
|
||||
|
||||
gtk_cell_renderer_set_fixed_size(g_renderer, pixWidth + 30, pixHeight + 30);
|
||||
if (need_pls_wait)
|
||||
destroy_please_wait();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
|
||||
extern GtkWidget *g_theme_view;
|
||||
extern GtkListStore *theme_list_store;
|
||||
enum { COL_THEME_FILE = 0, COL_THEME_NAME, COL_SNAPSHOT, NB_COL, };
|
||||
enum { COL_THEME_FILE = 0,
|
||||
COL_THEME_NAME,
|
||||
COL_SNAPSHOT,
|
||||
COL_WIDTH,
|
||||
COL_HEIGHT,
|
||||
NB_COL, };
|
||||
|
||||
GtkWidget *create_view();
|
||||
|
||||
|
||||
@@ -70,17 +70,15 @@ void relayout_fixed(Area *a)
|
||||
relayout_fixed(l->data);
|
||||
|
||||
// Recalculate size
|
||||
a->_changed = 0;
|
||||
a->_changed = FALSE;
|
||||
if (a->resize_needed && a->size_mode == LAYOUT_FIXED) {
|
||||
a->resize_needed = 0;
|
||||
a->resize_needed = FALSE;
|
||||
|
||||
if (a->_resize) {
|
||||
if (a->_resize(a)) {
|
||||
// The size hash changed => resize needed for the parent
|
||||
if (a->parent)
|
||||
((Area *)a->parent)->resize_needed = 1;
|
||||
a->_changed = 1;
|
||||
}
|
||||
if (a->_resize && a->_resize(a)) {
|
||||
// The size has changed => resize needed for the parent
|
||||
if (a->parent)
|
||||
((Area *)a->parent)->resize_needed = TRUE;
|
||||
a->_changed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,10 +90,11 @@ void relayout_dynamic(Area *a, int level)
|
||||
|
||||
// Area is resized before its children
|
||||
if (a->resize_needed && a->size_mode == LAYOUT_DYNAMIC) {
|
||||
a->resize_needed = 0;
|
||||
a->resize_needed = FALSE;
|
||||
|
||||
if (a->_resize) {
|
||||
a->_resize(a);
|
||||
if (a->_resize(a))
|
||||
a->_changed = TRUE;
|
||||
// resize children with LAYOUT_DYNAMIC
|
||||
for (GList *l = a->children; l; l = l->next) {
|
||||
Area *child = ((Area *)l->data);
|
||||
@@ -119,13 +118,13 @@ void relayout_dynamic(Area *a, int level)
|
||||
if (pos != child->posx) {
|
||||
// pos changed => redraw
|
||||
child->posx = pos;
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (pos != child->posy) {
|
||||
// pos changed => redraw
|
||||
child->posy = pos;
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,13 +147,13 @@ void relayout_dynamic(Area *a, int level)
|
||||
if (pos != child->posx) {
|
||||
// pos changed => redraw
|
||||
child->posx = pos;
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (pos != child->posy) {
|
||||
// pos changed => redraw
|
||||
child->posy = pos;
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,13 +186,13 @@ void relayout_dynamic(Area *a, int level)
|
||||
if (pos != child->posx) {
|
||||
// pos changed => redraw
|
||||
child->posx = pos;
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (pos != child->posy) {
|
||||
// pos changed => redraw
|
||||
child->posy = pos;
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +223,7 @@ void draw_tree(Area *a)
|
||||
return;
|
||||
|
||||
if (a->_redraw_needed) {
|
||||
a->_redraw_needed = 0;
|
||||
a->_redraw_needed = FALSE;
|
||||
draw(a);
|
||||
}
|
||||
|
||||
@@ -286,7 +285,7 @@ int relayout_with_constraint(Area *a, int maximum_size)
|
||||
modulo--;
|
||||
}
|
||||
if (child->width != old_width)
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -326,7 +325,7 @@ int relayout_with_constraint(Area *a, int maximum_size)
|
||||
modulo--;
|
||||
}
|
||||
if (child->height != old_height)
|
||||
child->_changed = 1;
|
||||
child->_changed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,7 +360,7 @@ void hide(Area *a)
|
||||
|
||||
a->on_screen = FALSE;
|
||||
if (parent)
|
||||
parent->resize_needed = 1;
|
||||
parent->resize_needed = TRUE;
|
||||
if (panel_horizontal)
|
||||
a->width = 0;
|
||||
else
|
||||
@@ -374,12 +373,27 @@ void show(Area *a)
|
||||
|
||||
a->on_screen = TRUE;
|
||||
if (parent)
|
||||
parent->resize_needed = 1;
|
||||
a->resize_needed = 1;
|
||||
parent->resize_needed = TRUE;
|
||||
a->resize_needed = TRUE;
|
||||
}
|
||||
|
||||
void draw(Area *a)
|
||||
{
|
||||
if (a->_changed) {
|
||||
// On resize/move, invalidate cached pixmaps
|
||||
for (int i = 0; i < MOUSE_STATE_COUNT; i++) {
|
||||
XFreePixmap(server.display, a->pix_by_state[i]);
|
||||
if (a->pix == a->pix_by_state[i]) {
|
||||
a->pix = None;
|
||||
}
|
||||
a->pix_by_state[i] = None;
|
||||
}
|
||||
if (a->pix) {
|
||||
XFreePixmap(server.display, a->pix);
|
||||
a->pix = None;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->pix) {
|
||||
XFreePixmap(server.display, a->pix);
|
||||
if (a->pix_by_state[a->has_mouse_over_effect ? a->mouse_state : 0] != a->pix)
|
||||
@@ -594,7 +608,7 @@ gboolean area_is_first(void *obj)
|
||||
Area *node = &panel->area;
|
||||
|
||||
while (node) {
|
||||
if (!node->on_screen)
|
||||
if (!node->on_screen || node->width == 0 || node->height == 0)
|
||||
return FALSE;
|
||||
if (node == a)
|
||||
return TRUE;
|
||||
@@ -603,7 +617,7 @@ gboolean area_is_first(void *obj)
|
||||
node = NULL;
|
||||
for (; l; l = l->next) {
|
||||
Area *child = l->data;
|
||||
if (!child->on_screen)
|
||||
if (!child->on_screen || child->width == 0 || child->height == 0)
|
||||
continue;
|
||||
node = child;
|
||||
break;
|
||||
@@ -624,7 +638,7 @@ gboolean area_is_last(void *obj)
|
||||
Area *node = &panel->area;
|
||||
|
||||
while (node) {
|
||||
if (!node->on_screen)
|
||||
if (!node->on_screen || node->width == 0 || node->height == 0)
|
||||
return FALSE;
|
||||
if (node == a)
|
||||
return TRUE;
|
||||
@@ -633,7 +647,7 @@ gboolean area_is_last(void *obj)
|
||||
node = NULL;
|
||||
for (; l; l = l->next) {
|
||||
Area *child = l->data;
|
||||
if (!child->on_screen)
|
||||
if (!child->on_screen || child->width == 0 || child->height == 0)
|
||||
continue;
|
||||
node = child;
|
||||
}
|
||||
@@ -645,7 +659,7 @@ gboolean area_is_last(void *obj)
|
||||
gboolean area_is_under_mouse(void *obj, int x, int y)
|
||||
{
|
||||
Area *a = obj;
|
||||
if (!a->on_screen)
|
||||
if (!a->on_screen || a->width == 0 || a->height == 0)
|
||||
return FALSE;
|
||||
|
||||
if (a->_is_under_mouse)
|
||||
@@ -664,9 +678,9 @@ gboolean full_width_area_is_under_mouse(void *obj, int x, int y)
|
||||
return a->_is_under_mouse(a, x, y);
|
||||
|
||||
if (panel_horizontal)
|
||||
return (x >= a->posx || area_is_first(a)) && (x <= a->posx + a->width || area_is_last(a));
|
||||
return (x >= a->posx) && (x <= a->posx + a->width);
|
||||
else
|
||||
return (y >= a->posy || area_is_first(a)) && (y <= a->posy + a->height || area_is_last(a));
|
||||
return (y >= a->posy) && (y <= a->posy + a->height);
|
||||
}
|
||||
|
||||
Area *find_area_under_mouse(void *root, int x, int y)
|
||||
|
||||
@@ -194,6 +194,7 @@ typedef struct Area {
|
||||
// This is the pixmap on which the Area is rendered. Render to it directly if needed.
|
||||
Pixmap pix;
|
||||
Pixmap pix_by_state[MOUSE_STATE_COUNT];
|
||||
char name[32];
|
||||
|
||||
// Callbacks
|
||||
|
||||
|
||||
@@ -320,3 +320,32 @@ gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, i
|
||||
*ih = height[icon_num];
|
||||
return icon_data[icon_num];
|
||||
}
|
||||
|
||||
// Thanks zcodes!
|
||||
char *get_window_name(Window win)
|
||||
{
|
||||
XTextProperty text_property;
|
||||
Status status = XGetWMName(server.display, win, &text_property);
|
||||
if (!status || !text_property.value || !text_property.nitems) {
|
||||
return strdup("");
|
||||
}
|
||||
|
||||
char **name_list;
|
||||
int count;
|
||||
status = Xutf8TextPropertyToTextList(server.display, &text_property, &name_list, &count);
|
||||
if (status < Success || !count) {
|
||||
XFree(text_property.value);
|
||||
return strdup("");
|
||||
}
|
||||
|
||||
if (!name_list[0]) {
|
||||
XFreeStringList(name_list);
|
||||
XFree(text_property.value);
|
||||
return strdup("");
|
||||
}
|
||||
|
||||
char *result = strdup(name_list[0]);
|
||||
XFreeStringList(name_list);
|
||||
XFree(text_property.value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -33,4 +33,6 @@ void change_window_desktop(Window win, int desktop);
|
||||
int get_icon_count(gulong *data, int num);
|
||||
gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size);
|
||||
|
||||
char *get_window_name(Window win);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user