1. configure/build changes to allow cross-compiling painlessly
2. pager module namespace changes - this was still dirty afdter the namespace
cleanup, so clean it up
3. add a powersave subsystem - doesnt have an "automatic" way to turn on and
off right now, this i think is best provided by modules (that do things like
monitor acpi status's (eg close lid of laptop), AC power status etc. etc.
this allows e to nicely defer "power" expensive actions to avoid disk
spinups etc.
4. move to use the new ecore poller system  - discussed long ago as part of
power management/saving issues. now it exists
5. add a canvas idle flush call that helsp cope with the new shm greedy
software x11 engine stuff
6. use the new powersave subsystem where appropriate
7. fix non-zeroed/initted memory access in e_fm_main
8. fix mem leak for e menus
9. remove ipc handlers for changed/removed config values
10. use animaotr not timer for menu scrolls - then menu scrolls obey the fps
config
11. fix up timer/poll happienss of cursor idle stuff
12. remove avoid damage from popups for now - causing problems
13. change battery and temp readouts to b e shorter so they fit
14. pager can emit signals on focus change for mini-windows now
15. temperature module now uses a slave process and uses stdin/out to talk to
it and get output - this makes e smoother as in my expereicne i found getting
the temp on my laptop actually took like 200ms so e "hang" for 200ms while
reading the acpi files - so now the subprocess does it and just writesa back
to e when it gets it.

ecore:
1. add ecore_pollers. see the documentation on them in doxygen comments :)
2. fix timers to only go off when they have to - bug there that made e's
select time out a LOT more than it needed to. defensive coding hid the
problem. now fixed. e should be much more power friendly now.
3. formatting/niceness in ecore_exe stuff
4. some comments on comments with SIGIO ideas vs. select
5. add call to be able to add an idle enterer at the start of the list of
them, not just the end (as has been the default)
6. fix ecore_evas to support auto evas idler calls after 0.5 secs of idle in
all canvases - and to do it right
7. if argb destination - set the shape EVENT shape (to mask out events in
transparent regions much like shape does withotu translucency)
8. in ecore_x add support for the event shape

evas:
1. fix cache to work properly and not just always fill up (as it seemed to
like to think cahce useage dropped below 0 when it didnt and thus just
over-fill)
2. software x11 engine now ONLY uses shm segments - no ximages over the
socket. this ximage hack was there to avoid the 2 round trips involved in
setting up an shm image - now i mitigated that wih an shm image cache pool.
it keeps shm images around and repurposes them for new update regions if
appropriate. this means many fewer shm creates (about 1/100th the number) and
since we recycle the memory less 0 memory page filling by the kernel - in the
end, i recorded about a 10-20% speedup over the old software x11 engine.
simple tests i have seen up to 120% speedups. idle flush now does something -
it frees all the cached shm segments. it has a hard-coded limit of 4mb worth
of shm segments (or 32 segments - whichever comes first) to keep around. once
can never complain much about speedups methinks :). also evas will defer sync
until the NEXT frame is written - this means evas can calculate the next
frame of data while x dma's/copies the images to the screen at the same time
(if you hve a dual core or multi-cpu machnike or your xserver is able to use
DMA to copy image data to the screen/video ram then this should see a decent
speedup).


SVN revision: 33448
This commit is contained in:
Carsten Haitzler 2008-01-11 07:33:57 +00:00
parent 2909ac19e4
commit c1441e1c3a
22 changed files with 919 additions and 133 deletions

View File

@ -85,18 +85,23 @@ extern "C" {
enum _Ecore_Exe_Flags /* flags for executing a child with its stdin and/or stdout piped back */
{
ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */
ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */
ECORE_EXE_PIPE_ERROR = 4, /**< Exe Pipe error mask */
ECORE_EXE_PIPE_READ_LINE_BUFFERED = 8, /**< Reads are buffered until a newline and delivered 1 event per line */
ECORE_EXE_PIPE_ERROR_LINE_BUFFERED = 16, /**< Errors are buffered until a newline and delivered 1 event per line */
ECORE_EXE_PIPE_AUTO = 32, /**< stdout and stderr are buffered automatically */
ECORE_EXE_RESPAWN = 64, /**< FIXME: Exe is restarted if it dies */
ECORE_EXE_USE_SH = 128 /**< Use /bin/sh to run the command. */
ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */
ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */
ECORE_EXE_PIPE_ERROR = 4, /**< Exe Pipe error mask */
ECORE_EXE_PIPE_READ_LINE_BUFFERED = 8, /**< Reads are buffered until a newline and delivered 1 event per line */
ECORE_EXE_PIPE_ERROR_LINE_BUFFERED = 16, /**< Errors are buffered until a newline and delivered 1 event per line */
ECORE_EXE_PIPE_AUTO = 32, /**< stdout and stderr are buffered automatically */
ECORE_EXE_RESPAWN = 64, /**< FIXME: Exe is restarted if it dies */
ECORE_EXE_USE_SH = 128 /**< Use /bin/sh to run the command. */
};
typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags;
enum _Ecore_Poller_Type /* Poller types */
{
ECORE_POLLER_CORE = 0 /**< The core poller interval */
};
typedef enum _Ecore_Poller_Type Ecore_Poller_Type;
#ifndef _WIN32
typedef void Ecore_Exe; /**< A handle for spawned processes */
#endif
@ -109,6 +114,7 @@ extern "C" {
typedef void Ecore_Event_Filter; /**< A handle for an event filter */
typedef void Ecore_Event; /**< A handle for an event */
typedef void Ecore_Animator; /**< A handle for animators */
typedef void Ecore_Poller; /**< A handle for pollers */
#endif
typedef struct _Ecore_Event_Signal_User Ecore_Event_Signal_User; /**< User signal event */
typedef struct _Ecore_Event_Signal_Hup Ecore_Event_Signal_Hup; /**< Hup signal event */
@ -250,6 +256,7 @@ extern "C" {
EAPI void *ecore_idler_del(Ecore_Idler *idler);
EAPI Ecore_Idle_Enterer *ecore_idle_enterer_add(int (*func) (void *data), const void *data);
EAPI Ecore_Idle_Enterer *ecore_idle_enterer_before_add(int (*func) (void *data), const void *data);
EAPI void *ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer);
EAPI Ecore_Idle_Exiter *ecore_idle_exiter_add(int (*func) (void *data), const void *data);
@ -276,6 +283,12 @@ extern "C" {
EAPI void ecore_animator_frametime_set(double frametime);
EAPI double ecore_animator_frametime_get(void);
EAPI void ecore_poller_poll_interval_set(Ecore_Poller_Type type, double poll_time);
EAPI double ecore_poller_poll_interval_get(Ecore_Poller_Type type);
EAPI Ecore_Poller *ecore_poller_add(Ecore_Poller_Type type, int interval, int (*func) (void *data), const void *data);
EAPI void *ecore_poller_del(Ecore_Poller *poller);
#ifdef __cplusplus
}
#endif

View File

@ -31,6 +31,7 @@ ecore_time.c \
ecore_timer.c \
ecore_tree.c \
ecore_value.c \
ecore_poll.c \
ecore_private.h
libecore_la_LIBADD = @dlopen_libs@ @winsock_libs@ -lm

View File

@ -84,6 +84,7 @@ ecore_shutdown(void)
return _ecore_init_count;
if (_ecore_fps_debug) _ecore_fps_debug_shutdown();
_ecore_poller_shutdown();
_ecore_animator_shutdown();
#ifndef _WIN32
_ecore_exe_shutdown();

View File

@ -260,7 +260,7 @@ ecore_exe_run(const char *exe_cmd, const void *data)
* terminated event have been called, the handle will be freed by Ecore.
*
* This function does the same thing as ecore_exe_run(), but also makes the
* standard in and/or out as wel las stderr from the child process available
* standard in and/or out as well as stderr from the child process available
* for reading or writing. To write use ecore_exe_send(). To read listen to
* ECORE_EXE_EVENT_DATA or ECORE_EXE_EVENT_ERROR events (set up handlers).
* Ecore may buffer read and error data until a newline character if asked
@ -288,16 +288,14 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
int ok = 1;
int result;
if (!exe_cmd)
return NULL;
if (!exe_cmd) return NULL;
exe = calloc(1, sizeof(Ecore_Exe));
if (exe == NULL)
return NULL;
if (exe == NULL) return NULL;
if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR))
&& (!(flags & ECORE_EXE_PIPE_READ)))
flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR; /* We need something to auto pipe. */
/* We need something to auto pipe. */
flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR;
exe->child_fd_error = -1;
exe->child_fd_read = -1;
@ -308,37 +306,44 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
/* Create some pipes. */
if (ok)
E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), ok)
{
E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), ok)
{
}
}
if (ok && (flags & ECORE_EXE_PIPE_ERROR))
E_IF_NO_ERRNO_NOLOOP(result, pipe(errorPipe), ok)
{
exe->child_fd_error = errorPipe[0];
exe->child_fd_error_x = errorPipe[1];
E_IF_NO_ERRNO_NOLOOP(result, pipe(errorPipe), ok)
{
exe->child_fd_error = errorPipe[0];
exe->child_fd_error_x = errorPipe[1];
}
}
if (ok && (flags & ECORE_EXE_PIPE_READ))
E_IF_NO_ERRNO_NOLOOP(result, pipe(readPipe), ok)
{
exe->child_fd_read = readPipe[0];
exe->child_fd_read_x = readPipe[1];
E_IF_NO_ERRNO_NOLOOP(result, pipe(readPipe), ok)
{
exe->child_fd_read = readPipe[0];
exe->child_fd_read_x = readPipe[1];
}
}
if (ok && (flags & ECORE_EXE_PIPE_WRITE))
E_IF_NO_ERRNO_NOLOOP(result, pipe(writePipe), ok)
{
exe->child_fd_write = writePipe[1];
exe->child_fd_write_x = writePipe[0];
E_IF_NO_ERRNO_NOLOOP(result, pipe(writePipe), ok)
{
exe->child_fd_write = writePipe[1];
exe->child_fd_write_x = writePipe[0];
}
}
if (ok)
{
pid_t pid = 0;
volatile int vfork_exec_errno = 0;
/* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */
/* signal(SIGPIPE, SIG_IGN); We only want EPIPE on errors */
pid = fork();
if (pid == -1)
{
fprintf(stderr, "Failed to fork process\n");
@ -346,8 +351,9 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
}
else if (pid == 0) /* child */
{
/* dup2 STDERR, STDIN, and STDOUT. dup2() allegedly closes the second pipe if it's open. */
/* On the other hand, there was the Great FD Leak Scare of '06, so let's be paranoid. */
/* dup2 STDERR, STDIN, and STDOUT. dup2() allegedly closes the
* second pipe if it's open. On the other hand, there was the
* Great FD Leak Scare of '06, so let's be paranoid. */
if (ok && (flags & ECORE_EXE_PIPE_ERROR))
{
E_NO_ERRNO(result, close(STDERR_FILENO), ok);
@ -369,10 +375,10 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
/* Setup the status pipe. */
E_NO_ERRNO(result, close(statusPipe[0]), ok);
E_IF_NO_ERRNO(result, fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC), ok) /* close on exec shows sucess */
{
/* Run the actual command. */
_ecore_exe_exec_it(exe_cmd, flags); /* Should not return from this. */
}
{
/* Run the actual command. */
_ecore_exe_exec_it(exe_cmd, flags); /* no return */
}
}
/* Something went 'orribly wrong. */
@ -380,13 +386,13 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
/* Close the pipes. */
if (flags & ECORE_EXE_PIPE_ERROR)
E_NO_ERRNO(result, close(errorPipe[1]), ok);
E_NO_ERRNO(result, close(errorPipe[1]), ok);
if (flags & ECORE_EXE_PIPE_READ)
E_NO_ERRNO(result, close(readPipe[1]), ok);
E_NO_ERRNO(result, close(readPipe[1]), ok);
if (flags & ECORE_EXE_PIPE_WRITE)
E_NO_ERRNO(result, close(writePipe[0]), ok);
E_NO_ERRNO(result, close(writePipe[0]), ok);
E_NO_ERRNO(result, close(statusPipe[1]), ok);
_exit(-1);
}
else /* parent */
@ -394,13 +400,28 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
/* Close the unused pipes. */
E_NO_ERRNO(result, close(statusPipe[1]), ok);
/* FIXME: after having a good look at the current e fd handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */
/* FIXME: after having a good look at the current e fd
* handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */
/* FIXME: above F_SETSIG etc. - this is async SIGIO based IO
* which is also linux specific so we probably don't want to
* do this as long as select() is working fine. the only time
* we really want to think of SIGIO async IO is when it all
* actually works basically everywhere and we can turn all
* IO into DMA async activities (i.e. you do a read() then
* the read is complete not on return but when you get a
* SIGIO - the read() just starts the transfer and it is
* completed in the background by DMA (or whatever mechanism
* the kernel choses)) */
/* Wait for it to start executing. */
while (1)
/* FIXME: this doesn't seem very nice - we sit and block
* waiting on a child process... even though it's just
* the segment between the fork() and the exec) it just feels
* wrong */
for (;;)
{
char buf;
E_NO_ERRNO(result, read(statusPipe[0], &buf, 1), ok);
if (result == 0)
{
@ -433,7 +454,7 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
if ((exe->cmd = strdup(exe_cmd)))
{
if (flags & ECORE_EXE_PIPE_ERROR)
{ /* Setup the error stuff. */
{ /* Setup the error stuff. */
E_IF_NO_ERRNO(result,
fcntl(exe->child_fd_error, F_SETFL,
O_NONBLOCK), ok) {}
@ -454,7 +475,7 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
}
}
if (ok && (flags & ECORE_EXE_PIPE_READ))
{ /* Setup the read stuff. */
{ /* Setup the read stuff. */
E_IF_NO_ERRNO(result,
fcntl(exe->child_fd_read, F_SETFL,
O_NONBLOCK), ok) {}
@ -497,35 +518,34 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
ok = 0;
}
}
exes = _ecore_list2_append(exes, exe);
n = 0;
}
else
ok = 0;
ok = 0;
}
else
ok = 0;
ok = 0;
}
if (!ok)
{ /* Something went wrong, so pull down everything. */
if (exe->pid)
ecore_exe_terminate(exe);
{ /* Something went wrong, so pull down everything. */
if (exe->pid) ecore_exe_terminate(exe);
IF_FN_DEL(ecore_exe_free, exe);
}
else
{
Ecore_Exe_Event_Add *e;
e = _ecore_exe_event_add_new();
e->exe = exe;
if (e) /* Send the event. */
ecore_event_add(ECORE_EXE_EVENT_ADD, e,
_ecore_exe_event_add_free, NULL);
if (e) /* Send the event. */
ecore_event_add(ECORE_EXE_EVENT_ADD, e,
_ecore_exe_event_add_free, NULL);
/* printf("Running as %d for %s.\n", exe->pid, exe->cmd); */
}
errno = n;
return exe;
}
@ -549,8 +569,7 @@ ecore_exe_send(Ecore_Exe * exe, void *data, int size)
void *buf;
buf = realloc(exe->write_data_buf, exe->write_data_size + size);
if (buf == NULL)
return 0;
if (buf == NULL) return 0;
exe->write_data_buf = buf;
memcpy((char *)exe->write_data_buf + exe->write_data_size, data, size);
@ -1365,7 +1384,10 @@ _ecore_exe_data_generic_handler(void *data, Ecore_Fd_Handler * fd_handler,
lost_exe = 0;
errno = 0;
if ((num = read(child_fd, buf, READBUFSIZ)) < 1) /* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE (currently 64k) to inbuf, use that instead of buf, and save ourselves a memcpy(). */
if ((num = read(child_fd, buf, READBUFSIZ)) < 1)
/* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE
* (currently 64k) to inbuf, use that instead of buf, and
* save ourselves a memcpy(). */
{
lost_exe = ((errno == EIO) ||
(errno == EBADF) ||

View File

@ -27,6 +27,29 @@ ecore_idle_enterer_add(int (*func) (void *data), const void *data)
return ie;
}
/**
* Add an idle enterer handler at the start of the list so it gets called earlier than others.
* @param func The function to call when entering an idle state.
* @param data The data to be passed to the @p func call
* @return A handle to the idle enterer callback if successful. Otherwise,
* NULL is returned.
* @ingroup Idle_Group
*/
EAPI Ecore_Idle_Enterer *
ecore_idle_enterer_before_add(int (*func) (void *data), const void *data)
{
Ecore_Idle_Enterer *ie;
if (!func) return NULL;
ie = calloc(1, sizeof(Ecore_Idle_Enterer));
if (!ie) return NULL;
ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
ie->func = func;
ie->data = (void *)data;
idle_enterers = _ecore_list2_prepend(idle_enterers, ie);
return ie;
}
/**
* Delete an idle enterer callback.
* @param idle_enterer The idle enterer to delete

View File

@ -0,0 +1,352 @@
#include "ecore_private.h"
#include "Ecore.h"
static Ecore_Timer *timer = NULL;
static int min_interval = -1;
static int interval_incr = 0;
static int at_tick = 0;
static int just_added_poller = 0;
static int poller_delete_count = 0;
static int poller_walking = 0;
static double poll_interval = 0.125;
static double poll_cur_interval = 0.0;
static double last_tick = 0.0;
static Ecore_Poller *pollers[16] =
{
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
};
static unsigned short poller_counters[16] =
{
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
static void _ecore_poller_next_tick_eval(void);
static int _ecore_poller_cb_timer(void *data);
static void
_ecore_poller_next_tick_eval(void)
{
int i;
double interval;
min_interval = -1;
for (i = 0; i < 15; i++)
{
if (pollers[i])
{
min_interval = i;
break;
}
}
if (min_interval < 0)
{
/* no pollers */
if (timer)
{
ecore_timer_del(timer);
timer = NULL;
}
return;
}
interval_incr = (1 << min_interval);
interval = interval_incr * poll_interval;
/* we are at the tick callback - so no need to do inter-tick adjustments
* so we can fasttrack this as t -= last_tick in theory is 0.0 (though
* in practice it will be a very very very small value. also the tick
* callback will adjust the timer interval at the end anyway */
if (at_tick)
{
if (!timer)
timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
}
else
{
double t;
if (!timer)
timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
else
{
t = ecore_time_get();
if (interval != poll_cur_interval)
{
t -= last_tick; /* time since we last ticked */
/* delete the timer and reset it to tick off in the new
* time interval. at the tick this will be adjusted */
ecore_timer_del(timer);
timer = ecore_timer_add(interval - t,
_ecore_poller_cb_timer, NULL);
}
}
}
poll_cur_interval = interval;
}
static int
_ecore_poller_cb_timer(void *data)
{
int i;
Ecore_List2 *l;
Ecore_Poller *poller;
int changes = 0;
at_tick++;
last_tick = ecore_time_get();
/* we have 16 counters - each incriments every time the poller counter
* "ticks". it incriments by the minimum interval (which can be 1, 2, 4,
* 7, 16 etc. up to 32768) */
for (i = 0; i < 15; i++)
{
poller_counters[i] += interval_incr;
/* wrap back to 0 if we exceed out loop count for the counter */
if (poller_counters[i] >= (1 << i)) poller_counters[i] = 0;
}
just_added_poller = 0;
/* walk the pollers now */
poller_walking++;
for (i = 0; i < 15; i++)
{
/* if the counter is @ 0 - this means that counter "went off" this
* tick interval, so run all pollers hooked to that counter */
if (poller_counters[i] == 0)
{
for (l = (Ecore_List2 *)pollers[i]; l; l = l->next)
{
poller = (Ecore_Poller *)l;
if (!poller->delete_me)
{
if (!poller->func(poller->data))
{
if (!poller->delete_me)
{
poller->delete_me = 1;
poller_delete_count++;
}
}
}
}
}
}
poller_walking--;
/* handle deletes afterwards */
if (poller_delete_count > 0)
{
/* FIXME: walk all pollers and remove deleted ones */
for (i = 0; i < 15; i++)
{
for (l = (Ecore_List2 *)pollers[i]; l;)
{
poller = (Ecore_Poller *)l;
l = l->next;
if (poller->delete_me)
{
pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller);
free(poller);
poller_delete_count--;
changes++;
if (poller_delete_count <= 0) break;
}
}
if (poller_delete_count <= 0) break;
}
}
/* if we deleted or added any pollers, then we need to re-evaluate our
* minimum poll interval */
if ((changes > 0) || (just_added_poller > 0))
_ecore_poller_next_tick_eval();
just_added_poller = 0;
poller_delete_count = 0;
at_tick--;
/* if the timer was deleted then there is no point returning 1 - ambiguous
* if we do as it im plies "keep running me" but we have been deleted
* anyway */
if (!timer) return 0;
/* adjust interval */
ecore_timer_interval_set(timer, poll_cur_interval);
return 1;
}
/**
* @defgroup Ecore_Poll_Group Ecore Poll Functions
*
* These functions are for the need to poll information, but provide a shared
* abstracted API to pool such polling to minimise wakeup and ensure all the
* polling happens in as few spots as possible areound a core poll interval.
* For now only 1 core poller type is supprted: ECORE_POLLER_CORE
*/
/**
* Sets the time between ticks (in seconds) for the given ticker clock.
* @param type The ticker type to adjust
* @param poll_time The time (in seconds) between ticks of the clock
* @ingroup Ecore_Poller_Group
*
* This will adjust the time between ticks of the given ticker type defined
* by @p type to the time period defined by @p poll_time.
*/
EAPI void
ecore_poller_poll_interval_set(Ecore_Poller_Type type, double poll_time)
{
poll_interval = poll_time;
_ecore_poller_next_tick_eval();
}
/**
* Gets the time between ticks (in seconds) for the fiven ticker clock.
* @param type The ticker type to query
* @return The time in seconds between ticks of the ticker clock
* @ingroup Ecore_Poller_Group
*
* This will get the time between ticks of the specifider ticker clock.
*/
EAPI double
ecore_poller_poll_interval_get(Ecore_Poller_Type type)
{
return poll_interval;
}
/**
* Creates a poller to call the given function at a particular tick interval.
* @param type The ticker type to attach the poller to
* @param interval The poll interval
* @param func The given function. If @p func returns 1, the poller is
* rescheduled for the next tick interval.
* @param data Data to pass to @p func when it is called.
* @return A poller object on success. @c NULL on failure.
* @ingroup Ecore_Poller_Group
*
* This function adds a poller callback that is to be called regularly
* along with all other poller callbacks so the pollers are synchronized with
* all other pollers running off the same poller type and at the same tick
* interval. This should be used for polling things when polling is desired
* or required, and you do not have specific requirements on the exact times
* to poll and want to avoid extra process wakeups for polling. This will
* save power as the CPU has more of a chance to go into a low power state
* the longer it is asleep for, so this should be used if you are at all
* power conscious.
*
* The @p type parameter defines the poller tick type (there is a virtual
* clock ticking all the time - though ecore avoids making it tick when
* there will not be any work to do at that tick point). There is only one
* ticker at the moment - that is ECORE_POLLER_CORE. This is here for future
* expansion if multiple clocks with different frequencies are really required.
* The default time between ticks for the ECORE_POLLER_CORE ticker is 0.125
* seconds.
*
* The @p interval is the number of ticker ticks that will pass by in between
* invocations of the @p func callback. This must be between 1 and 32768
* inclusive, and must be a power of 2 (i.e. 1, 2, 4, 8, 16, ... 16384, 32768).
* If it is 1, then the function will be called every tick. if it is 2, then it
* will be called every 2nd tick, if it is 8, then every 8th tick etc. Exactly
* which tick is undefined, as only the interval between calls can be defined.
* Ecore will endeavour to keep pollers synchronised and to call as many in
* 1 wakeup event as possible.
*
* This function adds a poller and returns its handle on success and NULL on
* failure. The function @p func will be called at tick intervals described
* above. The function will be passed the @p data pointer as its parameter.
*
* When the poller @p func is called, it must return a value of either 1 or 0.
* If it returns 1, it will be called again at the next tick, or if it returns
* 0 it will be deleted automatically making any references/handles for it
* invalid.
*/
EAPI Ecore_Poller *
ecore_poller_add(Ecore_Poller_Type type, int interval, int (*func) (void *data), const void *data)
{
Ecore_Poller *poller;
int ibit;
if (!func) return NULL;
if (interval < 1) interval = 1;
poller = calloc(1, sizeof(Ecore_Poller));
if (!poller) return NULL;
ECORE_MAGIC_SET(poller, ECORE_MAGIC_POLLER);
/* interval MUST be a power of 2, so enforce it */
if (interval < 1) interval = 1;
ibit = -1;
while (interval != 0)
{
ibit++;
interval >>= 1;
}
/* only allow up to 32768 - i.e. ibit == 15, so limit it */
if (ibit > 15) ibit = 15;
poller->ibit = ibit;
poller->func = func;
poller->data = (void *)data;
pollers[poller->ibit] = _ecore_list2_prepend(pollers[poller->ibit], poller);
if (poller_walking)
just_added_poller++;
else
_ecore_poller_next_tick_eval();
return poller;
}
/**
* Delete the specified poller from the timer list.
* @param poller The poller to delete.
* @return The data pointer set for the timer when @ref ecore_poller_add was
* called. @c NULL is returned if the function is unsuccessful.
* @ingroup Ecore_Poller_Group
*
* Note: @p poller must be a valid handle. If the poller function has already
* returned 0, the handle is no longer valid (and does not need to be delete).
*/
EAPI void *
ecore_poller_del(Ecore_Poller *poller)
{
void *data;
if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
{
ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
"ecore_poller_del");
return NULL;
}
/* we are walking the poller list - a bad idea to remove from it while
* walking it, so just flag it as delete_me and come back to it after
* the loop has finished */
if (poller_walking > 0)
{
poller_delete_count++;
poller->delete_me = 1;
return poller->data;
}
/* not in loop so safe - delete immediately */
data = poller->data;
pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller);
free(poller);
_ecore_poller_next_tick_eval();
return data;
}
void
_ecore_poller_shutdown(void)
{
int i;
Ecore_List2 *l;
Ecore_Poller *poller;
for (i = 0; i < 15; i++)
{
for (l = (Ecore_List2 *)pollers[i]; l;)
{
poller = (Ecore_Poller *)l;
l = l->next;
pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller);
free(poller);
}
}
}

View File

@ -88,6 +88,7 @@
#define ECORE_MAGIC_EVENT_FILTER 0xf78218ff
#define ECORE_MAGIC_EVENT 0xf77119fe
#define ECORE_MAGIC_ANIMATOR 0xf7643ea5
#define ECORE_MAGIC_POLLER 0xf7568127
#define ECORE_MAGIC Ecore_Magic __magic
@ -221,6 +222,11 @@ enum _Ecore_Exe_Flags
*/
};
typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags;
enum _Ecore_Poller_Type
{
ECORE_POLLER_CORE = 0
};
typedef enum _Ecore_Poller_Type Ecore_Poller_Type;
#ifndef _WIN32
typedef struct _Ecore_Exe Ecore_Exe;
@ -234,6 +240,7 @@ typedef struct _Ecore_Event_Handler Ecore_Event_Handler;
typedef struct _Ecore_Event_Filter Ecore_Event_Filter;
typedef struct _Ecore_Event Ecore_Event;
typedef struct _Ecore_Animator Ecore_Animator;
typedef struct _Ecore_Poller Ecore_Poller;
#ifndef _WIN32
struct _Ecore_Exe
@ -371,6 +378,16 @@ struct _Ecore_Animator
void *data;
};
struct _Ecore_Poller
{
Ecore_List2 __list_data;
ECORE_MAGIC;
int ibit;
signed char delete_me : 1;
int (*func) (void *data);
void *data;
};
#endif
EAPI void _ecore_magic_fail(void *d, Ecore_Magic m, Ecore_Magic req_m, const char *fname);
@ -422,7 +439,8 @@ void _ecore_exe_event_del_free(void *data, void *ev);
void _ecore_animator_shutdown(void);
void _ecore_poller_shutdown(void);
EAPI void *_ecore_list2_append (void *in_list, void *in_item);
EAPI void *_ecore_list2_prepend (void *in_list, void *in_item);
EAPI void *_ecore_list2_append_relative (void *in_list, void *in_item, void *in_relative);

View File

@ -153,10 +153,15 @@ _ecore_timer_next_get(void)
{
double now;
double in;
Ecore_Timer *timer;
if (!timers) return -1;
now = ecore_time_get();
in = timers->at - now;
timer = (Ecore_Timer *)timers;
while ((timer) && ((timer->delete_me) || (timer->just_added)))
timer = (Ecore_Timer *)((Ecore_List2 *)timer)->next;
if (!timer) return -1;
in = timer->at - now;
if (in < 0) in = 0;
return in;
}
@ -166,7 +171,7 @@ _ecore_timer_call(double when)
{
Ecore_List2 *l;
Ecore_Timer *timer;
if (!timers) return 0;
if (last_check > when)
{
@ -189,13 +194,18 @@ _ecore_timer_call(double when)
_ecore_timer_call(when);
if ((!timer->delete_me) && (timer->func(timer->data)))
{
/* if the timer would have gone off more than 30 seconds ago,
/* if the timer would have gone off more than 15 seconds ago,
* assume that the system hung and set the timer to go off
* timer->in from now.
* timer->in from now. this handles system hangs, suspends
* and more, so ecore will only "replay" the timers while
* the system is suspended if it is suspended for less than
* 15 seconds (basically). this also handles if the process
* is stopped in a debugger or IO and other handling gets
* really slow within the main loop.
*/
if (!timer->delete_me)
{
if ((timer->at + timer->in) < (when - 30.0))
if ((timer->at + timer->in) < (when - 15.0))
_ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
else
_ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);

View File

@ -26,8 +26,8 @@
*
* * Need more buffer overflow checks.
*/
#include "Ecore.h"
#include "ecore_private.h"
#include "Ecore.h"
#include "ecore_con_private.h"
#include <ctype.h>

View File

@ -120,7 +120,6 @@ _ecore_evas_buffer_render(Ecore_Evas *ee)
if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
_ecore_evas_buffer_render(ee2);
if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
_ecore_evas_idle_timeout_update(ee2);
}
if (ee->engine.buffer.image)
{
@ -143,7 +142,11 @@ _ecore_evas_buffer_render(Ecore_Evas *ee)
r->x, r->y, r->w, r->h);
}
}
if (updates) evas_render_updates_free(updates);
if (updates)
{
evas_render_updates_free(updates);
_ecore_evas_idle_timeout_update(ee);
}
}
static void

View File

@ -32,7 +32,6 @@ _ecore_evas_directfb_render(Ecore_Evas *ee)
if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
_ecore_evas_buffer_render(ee2);
if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
_ecore_evas_idle_timeout_update(ee2);
}
#endif
if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
@ -56,9 +55,9 @@ _ecore_evas_directfb_render(Ecore_Evas *ee)
surface->Flip(surface, &region,DSFLIP_BLIT);
}
evas_render_updates_free(updates);
_ecore_evas_idle_timeout_update(ee);
}
if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
_ecore_evas_idle_timeout_update(ee);
}
static int

View File

@ -211,6 +211,8 @@ _ecore_evas_idle_enter(void *data __UNUSED__)
ee = (Ecore_Evas *)l;
if (ee->visible)
{
Evas_List *updates;
#ifdef BUILD_ECORE_EVAS_BUFFER
Evas_List *ll;
#endif
@ -227,12 +229,16 @@ _ecore_evas_idle_enter(void *data __UNUSED__)
if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
}
#endif
evas_render(ee->evas);
updates = evas_render_updates(ee->evas);
if (updates)
{
evas_render_updates_free(updates);
_ecore_evas_idle_timeout_update(ee);
}
if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
}
else
evas_norender(ee->evas);
_ecore_evas_idle_timeout_update(ee);
}
if (_ecore_evas_fps_debug)
{

View File

@ -231,10 +231,16 @@ _ecore_evas_idle_enter(void *data __UNUSED__)
ee = (Ecore_Evas *)l;
if (ee->visible)
{
Evas_List *updates;
if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
evas_render(ee->evas);
updates = evas_render_updates(ee->evas);
if (updates)
{
evas_render_updates_free(updates);
_ecore_evas_idle_timeout_update(ee);
}
if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
}
else

View File

@ -149,7 +149,6 @@ _ecore_evas_x_render(Ecore_Evas *ee)
if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
_ecore_evas_buffer_render(ee2);
if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
_ecore_evas_idle_timeout_update(ee2);
}
#endif
if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
@ -184,8 +183,14 @@ _ecore_evas_x_render(Ecore_Evas *ee)
}
if ((ee->shaped) && (updates))
ecore_x_window_shape_mask_set(ee->engine.x.win, ee->engine.x.mask);
if ((ee->alpha) && (updates))
ecore_x_window_shape_input_mask_set(ee->engine.x.win, ee->engine.x.mask);
}
if (updates)
{
evas_render_updates_free(updates);
_ecore_evas_idle_timeout_update(ee);
}
if (updates) evas_render_updates_free(updates);
}
else
{
@ -291,7 +296,11 @@ _ecore_evas_x_render(Ecore_Evas *ee)
ee->engine.x.damages = 0;
}
#endif /* HAVE_ECORE_X_XCB */
if (updates) evas_render_updates_free(updates);
if (updates)
{
evas_render_updates_free(updates);
_ecore_evas_idle_timeout_update(ee);
}
}
}
else if (((ee->visible) && (ee->draw_ok)) ||
@ -307,6 +316,7 @@ _ecore_evas_x_render(Ecore_Evas *ee)
{
ecore_x_window_shape_mask_set(ee->engine.x.win, ee->engine.x.mask);
evas_render_updates_free(updates);
_ecore_evas_idle_timeout_update(ee);
}
}
else
@ -334,13 +344,15 @@ _ecore_evas_x_render(Ecore_Evas *ee)
}
#endif
evas_render_updates_free(updates);
if (ee->alpha)
ecore_x_window_shape_input_mask_set(ee->engine.x.win, ee->engine.x.mask);
_ecore_evas_idle_timeout_update(ee);
}
}
}
else
evas_norender(ee->evas);
if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
_ecore_evas_idle_timeout_update(ee);
}
static void
@ -459,7 +471,6 @@ _ecore_evas_x_resize_shape(Ecore_Evas *ee)
einfo->info.mask = ee->engine.x.mask;
evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
}
#endif /* BUILD_ECORE_EVAS_X11 */
}
@ -1060,7 +1071,7 @@ _ecore_evas_x_event_window_configure(void *data __UNUSED__, int type __UNUSED__,
ecore_evas_avoid_damage_set(ee, 0);
ecore_evas_avoid_damage_set(ee, pdam);
}
if (ee->shaped)
if ((ee->shaped) || (ee->alpha))
_ecore_evas_x_resize_shape(ee);
if ((ee->expecting_resize.w > 0) &&
(ee->expecting_resize.h > 0))
@ -1475,10 +1486,8 @@ _ecore_evas_x_resize(Ecore_Evas *ee, int w, int h)
ecore_evas_avoid_damage_set(ee, 0);
ecore_evas_avoid_damage_set(ee, pdam);
}
if (ee->shaped)
{
_ecore_evas_x_resize_shape(ee);
}
if ((ee->shaped) || (ee->alpha))
_ecore_evas_x_resize_shape(ee);
if (ee->func.fn_resize) ee->func.fn_resize(ee);
}
}
@ -1526,10 +1535,8 @@ _ecore_evas_x_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
ecore_evas_avoid_damage_set(ee, 0);
ecore_evas_avoid_damage_set(ee, pdam);
}
if (ee->shaped)
{
_ecore_evas_x_resize_shape(ee);
}
if ((ee->shaped) || (ee->alpha))
_ecore_evas_x_resize_shape(ee);
if (change_pos)
{
if (ee->func.fn_move) ee->func.fn_move(ee);
@ -1685,7 +1692,8 @@ _ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
XGCValues gcv;
#endif /* HAVE_ECORE_X_XCB */
ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1);
if (!ee->engine.x.mask)
ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1);
# ifdef HAVE_ECORE_X_XCB
gc = xcb_generate_id(ecore_x_connection_get());
value_list = 0;
@ -1713,6 +1721,7 @@ _ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
einfo->info.mask = ee->engine.x.mask;
evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0);
}
else
{
@ -1721,6 +1730,7 @@ _ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
einfo->info.mask = 0;
evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
ecore_x_window_shape_mask_set(ee->engine.x.win, 0);
ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0);
}
}
#endif /* BUILD_ECORE_EVAS_X11 */
@ -1753,7 +1763,8 @@ _ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
XGCValues gcv;
# endif /* HAVE_ECORE_X_XCB */
ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1);
if (!ee->engine.x.mask)
ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1);
# ifdef HAVE_ECORE_X_XCB
gc = xcb_generate_id(ecore_x_connection_get());
value_list = 0;
@ -1781,6 +1792,7 @@ _ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
einfo->info.mask = ee->engine.x.mask;
evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0);
}
else
{
@ -1789,6 +1801,7 @@ _ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
einfo->info.mask = 0;
evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
ecore_x_window_shape_mask_set(ee->engine.x.win, 0);
ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0);
}
}
#endif
@ -1844,7 +1857,7 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
if (((ee->alpha) && (alpha)) || ((!ee->alpha) && (!alpha)))
return;
if (!strcmp(ee->driver, "software_x11") || !strcmp(ee->driver, "software_xcb"))
if (!strcmp(ee->driver, "software_x11"))
{
#ifdef BUILD_ECORE_EVAS_X11
# ifdef HAVE_ECORE_X_XCB
@ -1871,6 +1884,8 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
ee->engine.x.win = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
else
ee->engine.x.win = ecore_x_window_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
if (!ee->engine.x.mask)
ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1);
}
else
{
@ -1878,6 +1893,9 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
ee->engine.x.win = ecore_x_window_override_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
else
ee->engine.x.win = ecore_x_window_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
ee->engine.x.mask = 0;
ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0);
}
einfo->info.destination_alpha = alpha;
@ -1900,9 +1918,9 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
einfo->info.depth = att.depth;
# endif /* HAVE_ECORE_X_XCB */
if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
ee->engine.x.mask = 0;
einfo->info.mask = 0;
// if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
// ee->engine.x.mask = 0;
einfo->info.mask = ee->engine.x.mask;
einfo->info.drawable = ee->engine.x.win;
evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
@ -1914,7 +1932,7 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
if (ee->prop.focused) ecore_x_window_focus(ee->engine.x.win);
#endif /* BUILD_ECORE_EVAS_X11 */
}
else if (!strcmp(ee->driver, "xrender_x11") || !strcmp(ee->driver, "xrender_xcb"))
else if (!strcmp(ee->driver, "xrender_x11"))
{
#ifdef BUILD_ECORE_EVAS_XRENDER
# ifdef HAVE_ECORE_X_XCB
@ -1940,6 +1958,8 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
ee->engine.x.win = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
else
ee->engine.x.win = ecore_x_window_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
if (!ee->engine.x.mask)
ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1);
}
else
{
@ -1947,6 +1967,9 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
ee->engine.x.win = ecore_x_window_override_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
else
ee->engine.x.win = ecore_x_window_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
ee->engine.x.mask = 0;
ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0);
}
einfo->info.destination_alpha = alpha;
@ -1962,9 +1985,9 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
einfo->info.visual = att.visual;
# endif /* HAVE_ECORE_X_XCB */
if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
ee->engine.x.mask = 0;
einfo->info.mask = 0;
// if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
// ee->engine.x.mask = 0;
einfo->info.mask = ee->engine.x.mask;
einfo->info.drawable = ee->engine.x.win;
evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
@ -1994,6 +2017,8 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
ee->engine.x.win = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
else
ee->engine.x.win = ecore_x_window_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
if (!ee->engine.x.mask)
ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1);
}
else
{
@ -2001,6 +2026,9 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
ee->engine.x.win = ecore_x_window_override_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
else
ee->engine.x.win = ecore_x_window_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h);
if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
ee->engine.x.mask = 0;
ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0);
}
#if 0 /* XXX no alpha window support for software_16_x11 */
@ -2008,9 +2036,9 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
#endif /* XXX no alpha window support for software_16_x11 */
#if 0 /* XXX no shaped window support for software_16_x11 */
if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
ee->engine.x.mask = 0;
einfo->info.mask = 0;
// if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask);
// ee->engine.x.mask = 0;
einfo->info.mask = ee->engine.x.mask;
#endif /* XXX no shaped window support for software_16_x11 */
einfo->info.drawable = ee->engine.x.win;

View File

@ -1216,6 +1216,7 @@ EAPI void ecore_x_window_shape_rectangles_get_prefetch(Ecore_X_Win
EAPI void ecore_x_window_shape_rectangles_get_fetch(void);
EAPI Ecore_X_Rectangle *ecore_x_window_shape_rectangles_get(Ecore_X_Window win, int *num_ret);
EAPI void ecore_x_window_shape_events_select(Ecore_X_Window win, int on);
EAPI void ecore_x_window_shape_input_mask_set(Ecore_X_Window win, Ecore_X_Pixmap mask);
EAPI Ecore_X_Pixmap ecore_x_pixmap_new(Ecore_X_Window win, int w, int h, int dep);
EAPI void ecore_x_pixmap_del(Ecore_X_Pixmap pmap);

View File

@ -169,3 +169,21 @@ ecore_x_window_shape_events_select(Ecore_X_Window win, int on)
else
XShapeSelectInput(_ecore_x_disp, win, 0);
}
/**
* Sets the input shape of the given window to that given by the pixmap @p mask.
* @param win The given window.
* @param mask A 2-bit depth pixmap that provides the new input shape of the
* window.
* @ingroup Ecore_X_Window_Shape
*/
EAPI void
ecore_x_window_shape_input_mask_set(Ecore_X_Window win, Ecore_X_Pixmap mask)
{
#ifdef ShapeInput
XShapeCombineMask(_ecore_x_disp, win, ShapeInput, 0, 0, mask, ShapeSet);
#else
XShapeCombineMask(_ecore_x_disp, win, ShapeBounding, 0, 0, mask, ShapeSet);
#endif
}

View File

@ -1313,7 +1313,6 @@ efreet_desktop_command_build(Efreet_Desktop_Command *command)
Ecore_List *execs;
char *exec;
printf("efreet_desktop_command_build()\n");
execs = ecore_list_new();
ecore_list_first_goto(command->files);

View File

@ -165,6 +165,9 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *
{
cache->lru = evas_object_list_remove(cache->lru, im);
cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im);
// printf("IMG %p %ix%i %s SUB %i\n",
// im, im->image->w, im->image->h, im->cache_key,
// cache->func.mem_size_get(im));
cache->usage -= cache->func.mem_size_get(im);
if (im->cache_key)
{
@ -192,6 +195,9 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *
cache->lru = evas_object_list_remove(cache->lru, im);
cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im);
cache->activ = evas_hash_direct_add(cache->activ, im->cache_key, im);
// printf("IMG %p %ix%i %s SUB %i\n",
// im, im->image->w, im->image->h, im->cache_key,
// cache->func.mem_size_get(im));
cache->usage -= cache->func.mem_size_get(im);
goto on_ok;
}
@ -199,6 +205,9 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *
{
cache->lru = evas_object_list_remove(cache->lru, im);
cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im);
// printf("IMG %p %ix%i %s SUB %i\n",
// im, im->image->w, im->image->h, im->cache_key,
// cache->func.mem_size_get(im));
cache->usage -= cache->func.mem_size_get(im);
if (im->cache_key)
{
@ -261,7 +270,11 @@ evas_cache_image_drop(RGBA_Image *im)
// if (im->cache_key) printf("DROP %s -> ref = %i\n", im->cache_key, im->references);
if ((im->flags & RGBA_IMAGE_IS_DIRTY) == RGBA_IMAGE_IS_DIRTY)
{
cache->usage -= cache->func.mem_size_get(im);
// printf("IMG %p %ix%i %s SUB %i\n",
// im, im->image->w, im->image->h, im->cache_key,
// cache->func.mem_size_get(im));
//// don't decrement cache usage - unless we remove from the lru
// cache->usage -= cache->func.mem_size_get(im);
// if (im->cache_key) printf("IM-- %s, cache = %i\n", im->cache_key, cache->usage);
cache->dirty = evas_object_list_remove(cache->dirty, im);
if (cache->func.debug)
@ -279,6 +292,9 @@ evas_cache_image_drop(RGBA_Image *im)
cache->inactiv = evas_hash_direct_add(cache->inactiv, im->cache_key, im);
cache->lru = evas_object_list_prepend(cache->lru, im);
// printf("IMG %p %ix%i %s ADD %i\n",
// im, im->image->w, im->image->h, im->cache_key,
// cache->func.mem_size_get(im));
cache->usage += cache->func.mem_size_get(im);
// printf("FLUSH!\n");
evas_cache_image_flush(cache);
@ -562,6 +578,7 @@ evas_cache_image_flush(Evas_Cache_Image *cache)
{
assert(cache);
// printf("cache->limit = %i (used = %i)\n", cache->limit, cache->usage);
if (cache->limit == -1)
return -1;
@ -572,6 +589,9 @@ evas_cache_image_flush(Evas_Cache_Image *cache)
im = (RGBA_Image *) cache->lru->last;
cache->lru = evas_object_list_remove(cache->lru, im);
cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im);
// printf("IMG %p %ix%i %s SUB %i\n",
// im, im->image->w, im->image->h, im->cache_key,
// cache->func.mem_size_get(im));
cache->usage -= cache->func.mem_size_get(im);
if (im->cache_key)
@ -579,6 +599,7 @@ evas_cache_image_flush(Evas_Cache_Image *cache)
evas_stringshare_del(im->cache_key);
im->cache_key = NULL;
}
// printf("DEL IMG FROM CACHE\n");
cache->func.destructor(im);
evas_common_image_delete(im);
}

View File

@ -216,6 +216,7 @@ evas_debug_magic_string_get(DATA32 magic)
//#define NOPOOL
typedef struct _Pool Pool;
@ -228,6 +229,12 @@ struct _Pool
Pool *
_evas_mp_pool_new(Evas_Mempool *pool)
#ifdef NOPOOL
{
static Pool thepool;
return &thepool;
}
#else
{
Pool *p;
void **ptr;
@ -246,14 +253,19 @@ _evas_mp_pool_new(Evas_Mempool *pool)
*ptr = NULL;
return p;
}
#endif
void
_evas_mp_pool_free(Pool *p)
#ifdef NOPOOL
{
}
#else
{
free(p);
}
#endif
//#define NOPOOL
void *
evas_mempool_malloc(Evas_Mempool *pool, int size)
#ifdef NOPOOL
@ -364,6 +376,11 @@ evas_mempool_free(Evas_Mempool *pool, void *ptr)
void *
evas_mempool_calloc(Evas_Mempool *pool, int size)
#ifdef NOPOOL
{
return calloc(1, size);
}
#else
{
void *mem;
@ -371,3 +388,4 @@ evas_mempool_calloc(Evas_Mempool *pool, int size)
memset(mem, 0, size);
return mem;
}
#endif

View File

@ -58,6 +58,8 @@ struct _Outbuf
/* a list of pending regions to write to the target */
Evas_List *pending_writes;
/* a list of previous frame pending regions to write to the target */
Evas_List *prev_pending_writes;
unsigned char mask_dither : 1;
unsigned char destination_alpha : 1;
@ -77,7 +79,10 @@ struct _X_Output_Buffer
Display *display;
XImage *xim;
XShmSegmentInfo *shm_info;
Visual *visual;
void *data;
int w, h, bpl;
int psize;
};
/****/

View File

@ -4,6 +4,110 @@
#include <sys/time.h>
#include <sys/utsname.h>
static Evas_List *shmpool = NULL;
static int shmsize = 0;
static X_Output_Buffer *
_find_xob(Display *d, Visual *v, int depth, int w, int h, int shm, void *data)
{
Evas_List *l, *xl;
X_Output_Buffer *xob = NULL;
int fitness = 0x7fffffff;
int sz, lbytes, bpp;
// return evas_software_x11_x_output_buffer_new(d, v, depth, w, h, shm, data);
if (!shm)
return evas_software_x11_x_output_buffer_new(d, v, depth, w, h, shm, data);
if (depth > 1)
{
bpp = depth / 8;
if (bpp == 3) bpp = 4;
lbytes = (((w * bpp) + 3) / 4) * 4;
}
else
lbytes = ((w + 31) / 32) * 4;
sz = lbytes * h;
for (l = shmpool; l; l = l->next)
{
X_Output_Buffer *xob2;
int szdif;
xob2 = l->data;
if ((xob2->xim->depth != depth) || (xob2->visual != v) ||
(xob2->display != d))
continue;
szdif = xob2->psize - sz;
if (szdif < 0) continue;
if (szdif == 0)
{
xob = xob2;
xl = l;
goto have_xob;
}
if (szdif < fitness)
{
fitness = szdif;
xob = xob2;
xl = l;
}
}
if ((fitness > (100 * 100)) || (!xob))
return evas_software_x11_x_output_buffer_new(d, v, depth, w, h, shm, data);
have_xob:
shmpool = evas_list_remove_list(shmpool, xl);
xob->w = w;
xob->h = h;
xob->bpl = lbytes;
xob->xim->width = xob->w;
xob->xim->height = xob->h;
xob->xim->bytes_per_line = xob->bpl;
shmsize -= xob->psize * (xob->xim->depth / 8);
return xob;
}
static void
_unfind_xob(X_Output_Buffer *xob, int sync)
{
// evas_software_x11_x_output_buffer_free(xob, sync); return;
if (xob->shm_info)
{
shmpool = evas_list_prepend(shmpool, xob);
shmsize += xob->psize * xob->xim->depth / 8;
while ((shmsize > (1024 * 4096)) ||
(evas_list_count(shmpool) > 32))
{
Evas_List *xl;
xl = evas_list_last(shmpool);
if (!xl)
{
shmsize = 0;
break;
}
xob = xl->data;
shmpool = evas_list_remove_list(shmpool, xl);
evas_software_x11_x_output_buffer_free(xob, sync);
}
}
else
evas_software_x11_x_output_buffer_free(xob, sync);
}
static void
_clear_xob(int sync)
{
while (shmpool)
{
X_Output_Buffer *xob;
xob = shmpool->data;
shmpool = evas_list_remove_list(shmpool, shmpool);
evas_software_x11_x_output_buffer_free(xob, sync);
}
shmsize = 0;
}
void
evas_software_x11_outbuf_init(void)
{
@ -12,6 +116,19 @@ evas_software_x11_outbuf_init(void)
void
evas_software_x11_outbuf_free(Outbuf *buf)
{
while (buf->priv.pending_writes)
{
RGBA_Image *im;
Outbuf_Region *obr;
im = buf->priv.pending_writes->data;
buf->priv.pending_writes = evas_list_remove_list(buf->priv.pending_writes, buf->priv.pending_writes);
obr = im->extended_info;
evas_cache_image_drop(im);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
free(obr);
}
evas_software_x11_outbuf_idle_flush(buf);
evas_software_x11_outbuf_flush(buf);
if (buf->priv.x.gc)
@ -22,6 +139,7 @@ evas_software_x11_outbuf_free(Outbuf *buf)
evas_software_x11_x_color_deallocate(buf->priv.x.disp, buf->priv.x.cmap,
buf->priv.x.vis, buf->priv.pal);
free(buf);
_clear_xob(0);
}
void
@ -190,7 +308,7 @@ evas_software_x11_outbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth,
" At depth %i:\n"
" RGB format mask: %08x, %08x, %08x\n"
" Palette mode: %i\n"
" Not supported by and compiled in converters!\n"
" Not supported by compiled in converters!\n"
" }\n",
buf->priv.x.depth,
buf->priv.mask.r,
@ -342,7 +460,8 @@ evas_software_x11_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w,
/* FIXME: magic - i found if shm regions are smaller than 200x200 its
* faster to use ximages over unix sockets - trial and error
*/
if ((w * h) < (200 * 200)) use_shm = 0;
// use_shm = 0; /* 630 -> 1006 fps */
// if ((w * h) < (200 * 200)) use_shm = 0; /* 630 -> 962 fps */
if ((buf->rot == 0) &&
(buf->priv.mask.r == 0xff0000) &&
@ -355,19 +474,34 @@ evas_software_x11_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w,
im->image->data = NULL;
im->image->no_free = 1;
im->extended_info = obr;
obr->xob = _find_xob(buf->priv.x.disp,
buf->priv.x.vis,
buf->priv.x.depth,
w, h,
use_shm,
NULL);
/*
obr->xob = evas_software_x11_x_output_buffer_new(buf->priv.x.disp,
buf->priv.x.vis,
buf->priv.x.depth,
w, h,
use_shm,
NULL);
*/
im->image->data = (DATA32 *) evas_software_x11_x_output_buffer_data(obr->xob, &bpl);
if (buf->priv.x.mask)
obr->mxob = _find_xob(buf->priv.x.disp,
buf->priv.x.vis,
1, w, h,
use_shm,
NULL);
/*
obr->mxob = evas_software_x11_x_output_buffer_new(buf->priv.x.disp,
buf->priv.x.vis,
1, w, h,
use_shm,
NULL);
*/
}
else
{
@ -377,25 +511,48 @@ evas_software_x11_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w,
evas_common_image_surface_alloc(im->image);
im->extended_info = obr;
if ((buf->rot == 0) || (buf->rot == 180))
obr->xob = _find_xob(buf->priv.x.disp,
buf->priv.x.vis,
buf->priv.x.depth,
w, h,
use_shm,
NULL);
/*
obr->xob = evas_software_x11_x_output_buffer_new(buf->priv.x.disp,
buf->priv.x.vis,
buf->priv.x.depth,
w, h,
use_shm,
NULL);
*/
else if ((buf->rot == 90) || (buf->rot == 270))
obr->xob = _find_xob(buf->priv.x.disp,
buf->priv.x.vis,
buf->priv.x.depth,
h, w,
use_shm,
NULL);
/*
obr->xob = evas_software_x11_x_output_buffer_new(buf->priv.x.disp,
buf->priv.x.vis,
buf->priv.x.depth,
h, w,
use_shm,
NULL);
*/
if (buf->priv.x.mask)
obr->mxob = _find_xob(buf->priv.x.disp,
buf->priv.x.vis,
1, w, h,
use_shm,
NULL);
/*
obr->mxob = evas_software_x11_x_output_buffer_new(buf->priv.x.disp,
buf->priv.x.vis,
1, w, h,
use_shm,
NULL);
*/
}
if ((buf->priv.x.mask) || (buf->priv.destination_alpha))
{
@ -461,6 +618,8 @@ evas_software_x11_outbuf_flush(Outbuf *buf)
}
else
{
#if 1
XSync(buf->priv.x.disp, False);
for (l = buf->priv.pending_writes; l; l = l->next)
{
RGBA_Image *im;
@ -468,7 +627,6 @@ evas_software_x11_outbuf_flush(Outbuf *buf)
im = l->data;
obr = im->extended_info;
/* paste now */
if (buf->priv.debug)
evas_software_x11_outbuf_debug_show(buf, buf->priv.x.win,
obr->x, obr->y, obr->w, obr->h);
@ -481,7 +639,53 @@ evas_software_x11_outbuf_flush(Outbuf *buf)
buf->priv.x.gcm,
obr->x, obr->y, 0);
}
while (buf->priv.prev_pending_writes)
{
RGBA_Image *im;
Outbuf_Region *obr;
im = buf->priv.prev_pending_writes->data;
buf->priv.prev_pending_writes =
evas_list_remove_list(buf->priv.prev_pending_writes,
buf->priv.prev_pending_writes);
obr = im->extended_info;
evas_cache_image_drop(im);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
/*
if (obr->xob) evas_software_x11_x_output_buffer_free(obr->xob, 0);
if (obr->mxob) evas_software_x11_x_output_buffer_free(obr->mxob, 0);
*/
free(obr);
}
buf->priv.prev_pending_writes = buf->priv.pending_writes;
buf->priv.pending_writes = NULL;
XFlush(buf->priv.x.disp);
#else
/* XX async push - disable */
/*
for (l = buf->priv.pending_writes; l; l = l->next)
{
RGBA_Image *im;
Outbuf_Region *obr;
im = l->data;
obr = im->extended_info;
if (buf->priv.debug)
evas_software_x11_outbuf_debug_show(buf, buf->priv.x.win,
obr->x, obr->y, obr->w, obr->h);
evas_software_x11_x_output_buffer_paste(obr->xob, buf->priv.x.win,
buf->priv.x.gc,
obr->x, obr->y, 0);
if (obr->mxob)
evas_software_x11_x_output_buffer_paste(obr->mxob,
buf->priv.x.mask,
buf->priv.x.gcm,
obr->x, obr->y, 0);
}
*/
XSync(buf->priv.x.disp, False);
while (buf->priv.pending_writes)
{
RGBA_Image *im;
@ -491,10 +695,15 @@ evas_software_x11_outbuf_flush(Outbuf *buf)
buf->priv.pending_writes = evas_list_remove_list(buf->priv.pending_writes, buf->priv.pending_writes);
obr = im->extended_info;
evas_cache_image_drop(im);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
/*
if (obr->xob) evas_software_x11_x_output_buffer_free(obr->xob, 0);
if (obr->mxob) evas_software_x11_x_output_buffer_free(obr->mxob, 0);
*/
free(obr);
}
#endif
}
evas_common_cpu_end_opt();
}
@ -515,6 +724,26 @@ evas_software_x11_outbuf_idle_flush(Outbuf *buf)
if (obr->mxob) evas_software_x11_x_output_buffer_free(obr->mxob, 0);
free(obr);
}
else
{
if (buf->priv.prev_pending_writes) XSync(buf->priv.x.disp, False);
while (buf->priv.prev_pending_writes)
{
RGBA_Image *im;
Outbuf_Region *obr;
im = buf->priv.prev_pending_writes->data;
buf->priv.prev_pending_writes =
evas_list_remove_list(buf->priv.prev_pending_writes,
buf->priv.prev_pending_writes);
obr = im->extended_info;
evas_cache_image_drop(im);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
free(obr);
}
_clear_xob(0);
}
}
void
@ -609,38 +838,40 @@ evas_software_x11_outbuf_push_updated_region(Outbuf *buf, RGBA_Image *update, in
bpl /
((evas_software_x11_x_output_buffer_depth(obr->xob) /
8)) - obr->w, obr->w, obr->h, x, y, NULL);
#if 0
/* FIXME: this is evil - but it makes ARGB targets look correct */
if ((buf->priv.destination_alpha) && (!obr->mxob) &&
(evas_software_x11_x_output_buffer_depth(obr->xob) == 32))
{
int i;
DATA32 a;
DATA32 *s, *e;
for (i = 0; i < obr->h; i++)
{
s = ((DATA32 *)data) + ((bpl * i) / sizeof(DATA32));
e = s + obr->w;
while (s < e)
{
a = A_VAL(s) + 1;
R_VAL(s) = (R_VAL(s) * a) >> 8;
G_VAL(s) = (G_VAL(s) * a) >> 8;
B_VAL(s) = (B_VAL(s) * a) >> 8;
s++;
}
}
}
#endif
}
#if 1
#else
/* XX async push */
if (!((buf->priv.onebuf) && (buf->priv.onebuf_regions)))
{
if (buf->priv.debug)
evas_software_x11_outbuf_debug_show(buf, buf->priv.x.win,
obr->x, obr->y, obr->w, obr->h);
evas_software_x11_x_output_buffer_paste(obr->xob, buf->priv.x.win,
buf->priv.x.gc,
obr->x, obr->y, 0);
}
#endif
if (obr->mxob)
{
for (yy = 0; yy < obr->h; yy++)
evas_software_x11_x_write_mask_line(buf, obr->mxob,
src_data +
(yy * obr->w), obr->w, yy);
#if 1
#else
/* XX async push */
if (!((buf->priv.onebuf) && (buf->priv.onebuf_regions)))
evas_software_x11_x_output_buffer_paste(obr->mxob,
buf->priv.x.mask,
buf->priv.x.gcm,
obr->x, obr->y, 0);
#endif
}
#if 1
#else
XFlush(buf->priv.x.disp);
#endif
}
void

View File

@ -103,8 +103,11 @@ evas_software_x11_x_output_buffer_new(Display *d, Visual *v, int depth, int w, i
if (!xob) return NULL;
xob->display = d;
xob->visual = v;
xob->xim = NULL;
xob->shm_info = NULL;
xob->w = w;
xob->h = h;
if (try_shm > 0)
{
@ -142,6 +145,8 @@ evas_software_x11_x_output_buffer_new(Display *d, Visual *v, int depth, int w, i
// xob->xim->bytes_per_line * xob->xim->height,
// creates);
// creates++;
xob->bpl = xob->xim->bytes_per_line;
xob->psize = xob->bpl * xob->h;
return xob;
}
}
@ -177,6 +182,8 @@ evas_software_x11_x_output_buffer_new(Display *d, Visual *v, int depth, int w, i
return NULL;
}
}
xob->bpl = xob->xim->bytes_per_line;
xob->psize = xob->bpl * xob->h;
return xob;
}
@ -209,13 +216,17 @@ evas_software_x11_x_output_buffer_paste(X_Output_Buffer *xob, Drawable d, GC gc,
{
if (xob->shm_info)
{
// printf("shm\n");
XShmPutImage(xob->display, d, gc, xob->xim, 0, 0, x, y,
xob->xim->width, xob->xim->height, False);
xob->w, xob->h, False);
if (sync) XSync(xob->display, False);
}
else
XPutImage(xob->display, d, gc, xob->xim, 0, 0, x, y,
xob->xim->width, xob->xim->height);
{
// printf("NO! shm\n");
XPutImage(xob->display, d, gc, xob->xim, 0, 0, x, y,
xob->w, xob->h);
}
}
DATA8 *