Sort tasks on taskbar: config + sort by title or center (disabled, work in progress) - issue 478
git-svn-id: http://tint2.googlecode.com/svn/trunk@743 121b4492-b84c-0410-8b4c-0d4edfb3f3cc
This commit is contained in:
parent
67d5bfcfce
commit
e539c6536f
8 changed files with 293 additions and 38 deletions
|
@ -68,6 +68,7 @@ set( SOURCES src/config.c
|
||||||
src/tooltip/tooltip.c
|
src/tooltip/tooltip.c
|
||||||
src/util/area.c
|
src/util/area.c
|
||||||
src/util/common.c
|
src/util/common.c
|
||||||
|
src/util/strnatcmp.c
|
||||||
src/util/timer.c
|
src/util/timer.c
|
||||||
src/util/window.c )
|
src/util/window.c )
|
||||||
|
|
||||||
|
|
|
@ -503,6 +503,15 @@ void add_entry (char *key, char *value)
|
||||||
else if (strcmp (key, "taskbar_hide_different_monitor") == 0) {
|
else if (strcmp (key, "taskbar_hide_different_monitor") == 0) {
|
||||||
hide_task_diff_monitor = atoi (value);
|
hide_task_diff_monitor = atoi (value);
|
||||||
}
|
}
|
||||||
|
else if (strcmp (key, "taskbar_sort_order") == 0) {
|
||||||
|
if (strcmp(value, "center") == 0) {
|
||||||
|
taskbar_sort_method = TASKBAR_SORT_CENTER;
|
||||||
|
} else if (strcmp(value, "title") == 0) {
|
||||||
|
taskbar_sort_method = TASKBAR_SORT_TITLE;
|
||||||
|
} else {
|
||||||
|
taskbar_sort_method = TASKBAR_NOSORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Task */
|
/* Task */
|
||||||
else if (strcmp (key, "task_text") == 0)
|
else if (strcmp (key, "task_text") == 0)
|
||||||
|
|
|
@ -184,7 +184,10 @@ int get_title(Task *tsk)
|
||||||
Panel *panel = tsk->area.panel;
|
Panel *panel = tsk->area.panel;
|
||||||
char *title, *name;
|
char *title, *name;
|
||||||
|
|
||||||
if (!panel->g_task.text && !panel->g_task.tooltip_enabled) return 0;
|
if (!panel->g_task.text &&
|
||||||
|
!panel->g_task.tooltip_enabled &&
|
||||||
|
taskbar_sort_method != TASKBAR_SORT_TITLE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
name = server_get_property (tsk->win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0);
|
name = server_get_property (tsk->win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0);
|
||||||
if (!name || !strlen(name)) {
|
if (!name || !strlen(name)) {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "panel.h"
|
#include "panel.h"
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
|
|
||||||
/* win_to_task_table holds for every Window an array of tasks. Usually the array contains only one
|
/* win_to_task_table holds for every Window an array of tasks. Usually the array contains only one
|
||||||
|
@ -45,7 +46,7 @@ int taskbar_enabled;
|
||||||
int taskbar_distribute_size;
|
int taskbar_distribute_size;
|
||||||
int hide_inactive_tasks;
|
int hide_inactive_tasks;
|
||||||
int hide_task_diff_monitor;
|
int hide_task_diff_monitor;
|
||||||
int sort_tasks_method;
|
int taskbar_sort_method;
|
||||||
|
|
||||||
guint win_hash(gconstpointer key) { return (guint)*((Window*)key); }
|
guint win_hash(gconstpointer key) { return (guint)*((Window*)key); }
|
||||||
gboolean win_compare(gconstpointer a, gconstpointer b) { return (*((Window*)a) == *((Window*)b)); }
|
gboolean win_compare(gconstpointer a, gconstpointer b) { return (*((Window*)a) == *((Window*)b)); }
|
||||||
|
@ -61,7 +62,7 @@ void default_taskbar()
|
||||||
taskbar_distribute_size = 0;
|
taskbar_distribute_size = 0;
|
||||||
hide_inactive_tasks = 0;
|
hide_inactive_tasks = 0;
|
||||||
hide_task_diff_monitor = 0;
|
hide_task_diff_monitor = 0;
|
||||||
sort_tasks_method = TASKBAR_NOSORT;
|
taskbar_sort_method = TASKBAR_NOSORT;
|
||||||
default_taskbarname();
|
default_taskbarname();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,10 +411,9 @@ void visible_taskbar(void *p)
|
||||||
panel_refresh = 1;
|
panel_refresh = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
#define NONTRIVIAL 2
|
||||||
|
gint compare_tasks_trivial(Task *a, Task *b, Taskbar *taskbar)
|
||||||
{
|
{
|
||||||
int a_horiz_c, a_vert_c, b_horiz_c, b_vert_c;
|
|
||||||
|
|
||||||
if (a == b)
|
if (a == b)
|
||||||
return 0;
|
return 0;
|
||||||
if (taskbarname_enabled) {
|
if (taskbarname_enabled) {
|
||||||
|
@ -422,6 +422,15 @@ gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
||||||
if (b == taskbar->area.list->data)
|
if (b == taskbar->area.list->data)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return NONTRIVIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint compare_task_centers(Task *a, Task *b, Taskbar *taskbar)
|
||||||
|
{
|
||||||
|
int trivial = compare_tasks_trivial(a, b, taskbar);
|
||||||
|
if (trivial != NONTRIVIAL)
|
||||||
|
return trivial;
|
||||||
|
int a_horiz_c, a_vert_c, b_horiz_c, b_vert_c;
|
||||||
a_horiz_c = a->win_x + a->win_w / 2;
|
a_horiz_c = a->win_x + a->win_w / 2;
|
||||||
b_horiz_c = b->win_x + b->win_w / 2;
|
b_horiz_c = b->win_x + b->win_w / 2;
|
||||||
a_vert_c = a->win_y + a->win_h / 2;
|
a_vert_c = a->win_y + a->win_h / 2;
|
||||||
|
@ -439,17 +448,38 @@ gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gint compare_task_titles(Task *a, Task *b, Taskbar *taskbar)
|
||||||
|
{
|
||||||
|
int trivial = compare_tasks_trivial(a, b, taskbar);
|
||||||
|
if (trivial != NONTRIVIAL)
|
||||||
|
return trivial;
|
||||||
|
return strnatcasecmp(a->title ? a->title : "", b->title ? b->title : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
||||||
|
{
|
||||||
|
int trivial = compare_tasks_trivial(a, b, taskbar);
|
||||||
|
if (trivial != NONTRIVIAL)
|
||||||
|
return trivial;
|
||||||
|
if (taskbar_sort_method == TASKBAR_NOSORT) {
|
||||||
|
return 0;
|
||||||
|
} else if (taskbar_sort_method == TASKBAR_SORT_CENTER) {
|
||||||
|
return compare_task_centers(a, b, taskbar);
|
||||||
|
} else if (taskbar_sort_method == TASKBAR_SORT_TITLE) {
|
||||||
|
return compare_task_titles(a, b, taskbar);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int taskbar_needs_sort(Taskbar *taskbar)
|
int taskbar_needs_sort(Taskbar *taskbar)
|
||||||
{
|
{
|
||||||
if (sort_tasks_method == TASKBAR_NOSORT)
|
if (taskbar_sort_method == TASKBAR_NOSORT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (sort_tasks_method == TASKBAR_SORT_POSITION) {
|
GSList *i, *j;
|
||||||
GSList *i, *j;
|
for (i = taskbar->area.list, j = i ? i->next : NULL; i && j; i = i->next, j = j->next) {
|
||||||
for (i = taskbar->area.list, j = i ? i->next : NULL; i && j; i = i->next, j = j->next) {
|
if (compare_tasks(i->data, j->data, taskbar) > 0) {
|
||||||
if (compare_tasks(i->data, j->data, taskbar) > 0) {
|
return 1;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,34 +490,35 @@ void sort_tasks(Taskbar *taskbar)
|
||||||
{
|
{
|
||||||
if (!taskbar)
|
if (!taskbar)
|
||||||
return;
|
return;
|
||||||
if (!taskbar_needs_sort(taskbar))
|
if (!taskbar_needs_sort(taskbar)) {
|
||||||
return;
|
return;
|
||||||
if (sort_tasks_method == TASKBAR_SORT_POSITION) {
|
|
||||||
taskbar->area.list = g_slist_sort_with_data(taskbar->area.list, (GCompareDataFunc)compare_tasks, taskbar);
|
|
||||||
taskbar->area.resize = 1;
|
|
||||||
panel_refresh = 1;
|
|
||||||
}
|
}
|
||||||
|
taskbar->area.list = g_slist_sort_with_data(taskbar->area.list, (GCompareDataFunc)compare_tasks, taskbar);
|
||||||
|
taskbar->area.resize = 1;
|
||||||
|
panel_refresh = 1;
|
||||||
|
((Panel*)taskbar->area.panel)->area.resize = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sort_taskbar_for_win(Window win)
|
void sort_taskbar_for_win(Window win)
|
||||||
{
|
{
|
||||||
if (sort_tasks_method == TASKBAR_SORT_POSITION) {
|
if (taskbar_sort_method == TASKBAR_NOSORT)
|
||||||
GPtrArray* task_group = task_get_tasks(win);
|
return;
|
||||||
if (task_group) {
|
|
||||||
int i;
|
GPtrArray* task_group = task_get_tasks(win);
|
||||||
Task* tsk0 = g_ptr_array_index(task_group, 0);
|
if (task_group) {
|
||||||
if (tsk0) {
|
int i;
|
||||||
window_get_coordinates(win, &tsk0->win_x, &tsk0->win_y, &tsk0->win_w, &tsk0->win_h);
|
Task* tsk0 = g_ptr_array_index(task_group, 0);
|
||||||
}
|
if (tsk0) {
|
||||||
for (i = 0; i < task_group->len; ++i) {
|
window_get_coordinates(win, &tsk0->win_x, &tsk0->win_y, &tsk0->win_w, &tsk0->win_h);
|
||||||
Task* tsk = g_ptr_array_index(task_group, i);
|
}
|
||||||
tsk->win_x = tsk0->win_x;
|
for (i = 0; i < task_group->len; ++i) {
|
||||||
tsk->win_y = tsk0->win_y;
|
Task* tsk = g_ptr_array_index(task_group, i);
|
||||||
tsk->win_w = tsk0->win_w;
|
tsk->win_x = tsk0->win_x;
|
||||||
tsk->win_h = tsk0->win_h;
|
tsk->win_y = tsk0->win_y;
|
||||||
sort_tasks(tsk->area.parent);
|
tsk->win_w = tsk0->win_w;
|
||||||
}
|
tsk->win_h = tsk0->win_h;
|
||||||
|
sort_tasks(tsk->area.parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@ extern int taskbar_enabled;
|
||||||
extern int taskbar_distribute_size;
|
extern int taskbar_distribute_size;
|
||||||
extern int hide_inactive_tasks;
|
extern int hide_inactive_tasks;
|
||||||
extern int hide_task_diff_monitor;
|
extern int hide_task_diff_monitor;
|
||||||
enum { TASKBAR_NOSORT, TASKBAR_SORT_POSITION };
|
enum { TASKBAR_NOSORT, TASKBAR_SORT_CENTER, TASKBAR_SORT_TITLE };
|
||||||
extern int sort_tasks_method;
|
extern int taskbar_sort_method;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// always start with area
|
// always start with area
|
||||||
|
|
|
@ -462,7 +462,7 @@ void event_button_motion_notify (XEvent *e)
|
||||||
|
|
||||||
// If the event takes place on the same taskbar as the task being dragged
|
// If the event takes place on the same taskbar as the task being dragged
|
||||||
if(event_taskbar == task_drag->area.parent) {
|
if(event_taskbar == task_drag->area.parent) {
|
||||||
if (sort_tasks_method == TASKBAR_SORT_POSITION) {
|
if (taskbar_sort_method != TASKBAR_NOSORT) {
|
||||||
sort_tasks(event_taskbar);
|
sort_tasks(event_taskbar);
|
||||||
} else {
|
} else {
|
||||||
// Swap the task_drag with the task on the event's location (if they differ)
|
// Swap the task_drag with the task on the event's location (if they differ)
|
||||||
|
@ -500,7 +500,7 @@ void event_button_motion_notify (XEvent *e)
|
||||||
|
|
||||||
windows_set_desktop(task_drag->win, event_taskbar->desktop);
|
windows_set_desktop(task_drag->win, event_taskbar->desktop);
|
||||||
|
|
||||||
if (sort_tasks_method == TASKBAR_SORT_POSITION) {
|
if (taskbar_sort_method != TASKBAR_NOSORT) {
|
||||||
sort_tasks(event_taskbar);
|
sort_tasks(event_taskbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,6 +751,8 @@ void event_property_notify (XEvent *e)
|
||||||
tooltip_copy_text((Area*)tsk);
|
tooltip_copy_text((Area*)tsk);
|
||||||
tooltip_update();
|
tooltip_update();
|
||||||
}
|
}
|
||||||
|
if (taskbar_sort_method == TASKBAR_SORT_TITLE)
|
||||||
|
sort_taskbar_for_win(win);
|
||||||
panel_refresh = 1;
|
panel_refresh = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
178
src/util/strnatcmp.c
Normal file
178
src/util/strnatcmp.c
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* partial change history:
|
||||||
|
*
|
||||||
|
* 2004-10-10 mbp: Lift out character type dependencies into macros.
|
||||||
|
*
|
||||||
|
* Eric Sosman pointed out that ctype functions take a parameter whose
|
||||||
|
* value must be that of an unsigned int, even on platforms that have
|
||||||
|
* negative chars in their default char type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* These are defined as macros to make it easier to adapt this code to
|
||||||
|
* different characters types or comparison functions. */
|
||||||
|
static inline int
|
||||||
|
nat_isdigit(nat_char a)
|
||||||
|
{
|
||||||
|
return isdigit((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
nat_isspace(nat_char a)
|
||||||
|
{
|
||||||
|
return isspace((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline nat_char
|
||||||
|
nat_toupper(nat_char a)
|
||||||
|
{
|
||||||
|
return toupper((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_right(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
int bias = 0;
|
||||||
|
|
||||||
|
/* The longest run of digits wins. That aside, the greatest
|
||||||
|
value wins, but we can't know that it will until we've scanned
|
||||||
|
both numbers to know that they have the same magnitude, so we
|
||||||
|
remember it in BIAS. */
|
||||||
|
for (;; a++, b++) {
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return bias;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = -1;
|
||||||
|
} else if (*a > *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = +1;
|
||||||
|
} else if (!*a && !*b)
|
||||||
|
return bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_left(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
/* Compare two left-aligned numbers: the first to have a
|
||||||
|
different value wins. */
|
||||||
|
for (;; a++, b++) {
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return 0;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b)
|
||||||
|
return -1;
|
||||||
|
else if (*a > *b)
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int strnatcmp0(nat_char const *a, nat_char const *b, int fold_case)
|
||||||
|
{
|
||||||
|
int ai, bi;
|
||||||
|
nat_char ca, cb;
|
||||||
|
int fractional, result;
|
||||||
|
|
||||||
|
assert(a && b);
|
||||||
|
ai = bi = 0;
|
||||||
|
while (1) {
|
||||||
|
ca = a[ai]; cb = b[bi];
|
||||||
|
|
||||||
|
/* skip over leading spaces or zeros */
|
||||||
|
while (nat_isspace(ca))
|
||||||
|
ca = a[++ai];
|
||||||
|
|
||||||
|
while (nat_isspace(cb))
|
||||||
|
cb = b[++bi];
|
||||||
|
|
||||||
|
/* process run of digits */
|
||||||
|
if (nat_isdigit(ca) && nat_isdigit(cb)) {
|
||||||
|
fractional = (ca == '0' || cb == '0');
|
||||||
|
|
||||||
|
if (fractional) {
|
||||||
|
if ((result = compare_left(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
if ((result = compare_right(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ca && !cb) {
|
||||||
|
/* The strings compare the same. Perhaps the caller
|
||||||
|
will want to call strcmp to break the tie. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fold_case) {
|
||||||
|
ca = nat_toupper(ca);
|
||||||
|
cb = nat_toupper(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ca < cb)
|
||||||
|
return -1;
|
||||||
|
else if (ca > cb)
|
||||||
|
return +1;
|
||||||
|
|
||||||
|
++ai; ++bi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int strnatcmp(nat_char const *a, nat_char const *b) {
|
||||||
|
return strnatcmp0(a, b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compare, recognizing numeric string and ignoring case. */
|
||||||
|
int strnatcasecmp(nat_char const *a, nat_char const *b) {
|
||||||
|
return strnatcmp0(a, b, 1);
|
||||||
|
}
|
31
src/util/strnatcmp.h
Normal file
31
src/util/strnatcmp.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* CUSTOMIZATION SECTION
|
||||||
|
*
|
||||||
|
* You can change this typedef, but must then also change the inline
|
||||||
|
* functions in strnatcmp.c */
|
||||||
|
typedef char nat_char;
|
||||||
|
|
||||||
|
int strnatcmp(nat_char const *a, nat_char const *b);
|
||||||
|
int strnatcasecmp(nat_char const *a, nat_char const *b);
|
Loading…
Reference in a new issue