...
This commit is contained in:
parent
c82a582a94
commit
11fde3a11a
20 changed files with 878 additions and 434 deletions
6
po/.cvsignore
Normal file
6
po/.cvsignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
Makefile.in.in
|
||||
POTFILES
|
||||
Makefile.in
|
||||
Makefile
|
||||
stamp-cat-id
|
||||
cat-id-tbl.c
|
7
src/.cvsignore
Normal file
7
src/.cvsignore
Normal file
|
@ -0,0 +1,7 @@
|
|||
.libs
|
||||
Makefile.in
|
||||
Makefile
|
||||
.deps
|
||||
metacity
|
||||
messagequeue.h
|
||||
messagequeue.c
|
|
@ -18,7 +18,22 @@ BUILT_SOURCES=$(copied_sources)
|
|||
$(copied_sources): $(copied_sources_deps)
|
||||
for I in $(copied_sources); do \
|
||||
rm -f $$I ; \
|
||||
cp $(srcdir)/uislave/$$I . ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" > $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
echo "/* DO NOT EDIT THIS FILE */" >> $$I ; \
|
||||
cat $(srcdir)/uislave/$$I >> $$I ; \
|
||||
done
|
||||
|
||||
metacity_SOURCES= \
|
||||
|
|
|
@ -356,7 +356,7 @@ event_queue_callback (MetaEventQueue *queue,
|
|||
case ReparentNotify:
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
if (event->xconfigure.override_redirect)
|
||||
if (window && event->xconfigure.override_redirect)
|
||||
{
|
||||
/* Unmanage it, override_redirect was toggled on?
|
||||
* Can this happen?
|
||||
|
|
78
src/fixedtip.c
Normal file
78
src/fixedtip.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* Metacity fixed tooltip routine */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "fixedtip.h"
|
||||
|
||||
static GtkWidget *tip = NULL;
|
||||
static GtkWidget *label = NULL;
|
||||
|
||||
static gint
|
||||
expose_handler (GtkTooltips *tooltips)
|
||||
{
|
||||
gtk_paint_flat_box (tip->style, tip->window,
|
||||
GTK_STATE_NORMAL, GTK_SHADOW_OUT,
|
||||
NULL, tip, "tooltip",
|
||||
0, 0, -1, -1);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_fixed_tip_show (int root_x, int root_y,
|
||||
const char *markup_text)
|
||||
{
|
||||
if (tip == NULL)
|
||||
{
|
||||
tip = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
gtk_widget_set_app_paintable (tip, TRUE);
|
||||
gtk_window_set_policy (GTK_WINDOW (tip), FALSE, FALSE, TRUE);
|
||||
gtk_widget_set_name (tip, "gtk-tooltips");
|
||||
gtk_container_set_border_width (GTK_CONTAINER (tip), 4);
|
||||
|
||||
gtk_signal_connect_object (GTK_OBJECT (tip),
|
||||
"expose_event",
|
||||
GTK_SIGNAL_FUNC (expose_handler),
|
||||
NULL);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
|
||||
gtk_widget_show (label);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (tip), label);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (tip),
|
||||
"destroy",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
||||
&tip);
|
||||
}
|
||||
|
||||
gtk_widget_set_uposition (tip, root_x, root_y);
|
||||
gtk_label_set_markup (GTK_LABEL (label), markup_text);
|
||||
|
||||
gtk_widget_show (tip);
|
||||
}
|
||||
|
||||
void
|
||||
meta_fixed_tip_hide (void)
|
||||
{
|
||||
gtk_widget_destroy (tip);
|
||||
}
|
32
src/fixedtip.h
Normal file
32
src/fixedtip.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* Metacity fixed tooltip routine */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_FIXED_TIP_H
|
||||
#define META_FIXED_TIP_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
void meta_fixed_tip_show (int root_x, int root_y,
|
||||
const char *markup_text);
|
||||
void meta_fixed_tip_hide (void);
|
||||
|
||||
|
||||
#endif
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "frame.h"
|
||||
#include "errors.h"
|
||||
#include "uislave.h"
|
||||
|
||||
static void
|
||||
meta_frame_init_info (MetaFrame *frame,
|
||||
|
@ -517,7 +518,13 @@ meta_frame_event (MetaFrame *frame,
|
|||
case META_FRAME_ACTION_RESIZING_SE:
|
||||
update_resize_se (frame);
|
||||
break;
|
||||
|
||||
|
||||
case META_FRAME_ACTION_NONE:
|
||||
meta_ui_slave_show_tip (frame->window->screen->uislave,
|
||||
frame->rect.x,
|
||||
frame->rect.y,
|
||||
"Hi this is a tooltip");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -32,8 +32,10 @@ static GMainLoop *meta_main_loop = NULL;
|
|||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
g_set_prgname (PACKAGE);
|
||||
|
||||
meta_main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
|
||||
meta_set_verbose (TRUE);
|
||||
meta_set_debugging (TRUE);
|
||||
meta_set_syncing (g_getenv ("METACITY_SYNC") != NULL);
|
||||
|
|
|
@ -34,6 +34,8 @@ struct _MetaScreen
|
|||
Window xroot;
|
||||
|
||||
MetaThemeEngine *engine;
|
||||
|
||||
MetaUISlave *uislave;
|
||||
|
||||
/*< private >*/
|
||||
|
||||
|
@ -41,8 +43,6 @@ struct _MetaScreen
|
|||
* root window)
|
||||
*/
|
||||
PangoContext *pango_context;
|
||||
|
||||
MetaUISlave *uislave;
|
||||
};
|
||||
|
||||
MetaScreen* meta_screen_new (MetaDisplay *display,
|
||||
|
|
477
src/uislave.c
477
src/uislave.c
|
@ -27,37 +27,16 @@
|
|||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
READ_FAILED = 0, /* FALSE */
|
||||
READ_OK,
|
||||
READ_EOF
|
||||
} ReadResult;
|
||||
|
||||
static void respawn_child (MetaUISlave *uislave);
|
||||
static gboolean error_callback (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data);
|
||||
static void kill_child (MetaUISlave *uislave);
|
||||
static void reset_vals (MetaUISlave *uislave);
|
||||
static ReadResult read_data (GString *str,
|
||||
gint fd);
|
||||
static void message_queue_func (MetaMessageQueue *mq,
|
||||
MetaMessage* message,
|
||||
gpointer data);
|
||||
|
||||
/* Message queue main loop source */
|
||||
static gboolean mq_prepare (GSource *source,
|
||||
gint *timeout);
|
||||
static gboolean mq_check (GSource *source);
|
||||
static gboolean mq_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data);
|
||||
static void mq_destroy (GSource *source);
|
||||
|
||||
static GSourceFuncs mq_funcs = {
|
||||
mq_prepare,
|
||||
mq_check,
|
||||
mq_dispatch,
|
||||
mq_destroy
|
||||
};
|
||||
|
||||
MetaUISlave*
|
||||
meta_ui_slave_new (const char *display_name,
|
||||
|
@ -65,16 +44,13 @@ meta_ui_slave_new (const char *display_name,
|
|||
gpointer data)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
GSource *source;
|
||||
|
||||
source = g_source_new (&mq_funcs, sizeof (MetaUISlave));
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
uislave = g_new (MetaUISlave, 1);
|
||||
|
||||
uislave->display_name = g_strdup (display_name);
|
||||
uislave->queue = g_queue_new ();
|
||||
uislave->buf = g_string_new ("");
|
||||
uislave->current_message = g_string_new ("");
|
||||
uislave->func = func;
|
||||
uislave->data = data;
|
||||
uislave->no_respawn = FALSE;
|
||||
|
||||
reset_vals (uislave);
|
||||
|
||||
|
@ -82,14 +58,7 @@ meta_ui_slave_new (const char *display_name,
|
|||
* if uislave->child_pids == 0, and metacity just runs
|
||||
* with no UI features other than window borders.
|
||||
*/
|
||||
respawn_child (uislave);
|
||||
|
||||
g_source_set_priority (source, G_PRIORITY_DEFAULT);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
|
||||
g_source_set_callback (source, (GSourceFunc) func, data, NULL);
|
||||
|
||||
g_source_attach (source, NULL);
|
||||
respawn_child (uislave);
|
||||
|
||||
return uislave;
|
||||
}
|
||||
|
@ -97,11 +66,15 @@ meta_ui_slave_new (const char *display_name,
|
|||
void
|
||||
meta_ui_slave_free (MetaUISlave *uislave)
|
||||
{
|
||||
GSource *source;
|
||||
|
||||
source = (GSource*) uislave;
|
||||
meta_verbose ("Deleting UI slave for display '%s'\n",
|
||||
uislave->display_name);
|
||||
|
||||
g_source_destroy (source);
|
||||
kill_child (uislave);
|
||||
|
||||
g_free (uislave->display_name);
|
||||
|
||||
g_free (uislave);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -114,6 +87,18 @@ meta_ui_slave_disable (MetaUISlave *uislave)
|
|||
uislave->no_respawn = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
message_queue_func (MetaMessageQueue *mq,
|
||||
MetaMessage* message,
|
||||
gpointer data)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = data;
|
||||
|
||||
(* uislave->func) (uislave, message, uislave->data);
|
||||
}
|
||||
|
||||
static void
|
||||
respawn_child (MetaUISlave *uislave)
|
||||
{
|
||||
|
@ -147,6 +132,7 @@ respawn_child (MetaUISlave *uislave)
|
|||
uislave->child_pid = child_pid;
|
||||
uislave->in_pipe = inpipe;
|
||||
uislave->err_pipe = errpipe;
|
||||
uislave->out_pipe = outpipe;
|
||||
|
||||
uislave->err_channel = g_io_channel_unix_new (errpipe);
|
||||
|
||||
|
@ -154,11 +140,10 @@ respawn_child (MetaUISlave *uislave)
|
|||
G_IO_IN,
|
||||
error_callback,
|
||||
uislave);
|
||||
|
||||
uislave->out_poll.fd = outpipe;
|
||||
uislave->out_poll.events = G_IO_IN;
|
||||
|
||||
g_source_add_poll ((GSource*)uislave, &uislave->out_poll);
|
||||
uislave->mq = meta_message_queue_new (outpipe,
|
||||
message_queue_func,
|
||||
uislave);
|
||||
|
||||
meta_verbose ("Spawned UI slave with PID %d\n", uislave->child_pid);
|
||||
}
|
||||
|
@ -172,72 +157,6 @@ respawn_child (MetaUISlave *uislave)
|
|||
g_free (envp[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
append_pending (MetaUISlave *uislave)
|
||||
{
|
||||
int needed;
|
||||
|
||||
needed = uislave->current_required_len - uislave->current_message->len;
|
||||
g_assert (needed >= 0);
|
||||
|
||||
needed = MIN (needed, uislave->buf->len);
|
||||
|
||||
/* Move data from buf to current_message */
|
||||
if (needed > 0)
|
||||
{
|
||||
meta_verbose ("Moving %d bytes from buffer to current incomplete message\n",
|
||||
needed);
|
||||
g_string_append_len (uislave->current_message,
|
||||
uislave->buf->str,
|
||||
needed);
|
||||
g_string_erase (uislave->buf,
|
||||
0, needed);
|
||||
}
|
||||
|
||||
g_assert (uislave->current_message->len <= uislave->current_required_len);
|
||||
|
||||
if (uislave->current_required_len > 0 &&
|
||||
uislave->current_message->len == uislave->current_required_len)
|
||||
{
|
||||
MetaMessage *message;
|
||||
MetaMessageFooter *footer;
|
||||
|
||||
message = g_new (MetaMessage, 1);
|
||||
|
||||
memcpy (message,
|
||||
uislave->current_message->str, uislave->current_message->len);
|
||||
|
||||
if (message->header.length != uislave->current_required_len)
|
||||
meta_bug ("Message length changed?\n");
|
||||
|
||||
if (message->header.serial != uislave->last_serial)
|
||||
meta_bug ("Message serial changed?\n");
|
||||
|
||||
footer = META_MESSAGE_FOOTER (message);
|
||||
|
||||
if (footer->checksum == META_MESSAGE_CHECKSUM (message))
|
||||
{
|
||||
g_queue_push_tail (uislave->queue, message);
|
||||
|
||||
meta_verbose ("Added %d-byte message serial %d to queue\n",
|
||||
uislave->current_message->len, message->header.serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_bug ("Bad checksum %d on %d-byte message from UI slave\n",
|
||||
footer->checksum, uislave->current_message->len);
|
||||
}
|
||||
|
||||
uislave->current_required_len = 0;
|
||||
g_string_truncate (uislave->current_message, 0);
|
||||
}
|
||||
else if (uislave->current_required_len > 0)
|
||||
{
|
||||
meta_verbose ("Storing %d bytes of incomplete message\n",
|
||||
uislave->current_message->len);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
error_callback (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
|
@ -266,220 +185,20 @@ error_callback (GIOChannel *source,
|
|||
#undef BUFSIZE
|
||||
}
|
||||
|
||||
static void
|
||||
mq_queue_messages (MetaUISlave *uislave)
|
||||
{
|
||||
if (uislave->out_poll.revents & G_IO_IN)
|
||||
{
|
||||
ReadResult res;
|
||||
|
||||
res = read_data (uislave->buf, uislave->out_poll.fd);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case READ_OK:
|
||||
meta_verbose ("Read data from slave, %d bytes in buffer\n",
|
||||
uislave->buf->len);
|
||||
break;
|
||||
case READ_EOF:
|
||||
meta_verbose ("EOF reading stdout from slave process\n");
|
||||
break;
|
||||
|
||||
case READ_FAILED:
|
||||
/* read_data printed the error */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (uislave->buf->len > 0)
|
||||
{
|
||||
if (uislave->current_required_len > 0)
|
||||
{
|
||||
/* We had a pending message. */
|
||||
append_pending (uislave);
|
||||
}
|
||||
else if (uislave->buf->len > META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
/* See if we can start a current message */
|
||||
const char *p;
|
||||
int esc_pos;
|
||||
const char *esc;
|
||||
MetaMessageHeader header;
|
||||
|
||||
g_assert (uislave->current_required_len == 0);
|
||||
g_assert (uislave->current_message->len == 0);
|
||||
|
||||
meta_verbose ("Scanning for escape sequence in %d bytes\n",
|
||||
uislave->buf->len);
|
||||
|
||||
/* note that the data from the UI slave includes the nul byte */
|
||||
esc = META_MESSAGE_ESCAPE;
|
||||
|
||||
esc_pos = -1;
|
||||
p = uislave->buf->str;
|
||||
while (p != (uislave->buf->str + uislave->buf->len) &&
|
||||
esc_pos < META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
++esc_pos;
|
||||
if (*p != esc[esc_pos])
|
||||
esc_pos = -1;
|
||||
|
||||
++p;
|
||||
}
|
||||
|
||||
if (esc_pos == META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
/* We found an entire escape sequence; can safely toss
|
||||
* out the entire buffer before it
|
||||
*/
|
||||
int ignored;
|
||||
|
||||
ignored = p - uislave->buf->str;
|
||||
ignored -= META_MESSAGE_ESCAPE_LEN;
|
||||
|
||||
g_assert (ignored >= 0);
|
||||
|
||||
if (ignored > 0)
|
||||
{
|
||||
g_string_erase (uislave->buf, 0, ignored);
|
||||
meta_verbose ("Ignoring %d bytes before escape, new buffer len %d\n",
|
||||
ignored, uislave->buf->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (p == (uislave->buf->str + META_MESSAGE_ESCAPE_LEN));
|
||||
}
|
||||
}
|
||||
else if (esc_pos < 0)
|
||||
{
|
||||
/* End of buffer doesn't begin an escape sequence;
|
||||
* toss out entire buffer.
|
||||
*/
|
||||
meta_verbose ("Emptying %d-byte buffer not containing escape sequence\n",
|
||||
uislave->buf->len);
|
||||
g_string_truncate (uislave->buf, 0);
|
||||
goto need_more_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_verbose ("Buffer ends with partial escape sequence: '%s'\n",
|
||||
uislave->buf->str + (uislave->buf->len - esc_pos));
|
||||
goto need_more_data;
|
||||
}
|
||||
|
||||
g_assert (strcmp (uislave->buf->str, META_MESSAGE_ESCAPE) == 0);
|
||||
|
||||
if (uislave->buf->len < (META_MESSAGE_ESCAPE_LEN + sizeof (MetaMessageHeader)))
|
||||
{
|
||||
meta_verbose ("Buffer has full escape sequence but lacks header\n");
|
||||
goto need_more_data;
|
||||
}
|
||||
|
||||
g_string_erase (uislave->buf, 0, META_MESSAGE_ESCAPE_LEN);
|
||||
meta_verbose ("Stripped escape off front of buffer, new buffer len %d\n",
|
||||
uislave->buf->len);
|
||||
|
||||
g_assert (uislave->buf->len >= sizeof (MetaMessageHeader));
|
||||
|
||||
memcpy (&header, uislave->buf->str, sizeof (MetaMessageHeader));
|
||||
|
||||
/* Length includes the header even though it's in the header. */
|
||||
meta_verbose ("Read header, code: %d length: %d serial: %d\n",
|
||||
header.message_code, header.length, header.serial);
|
||||
|
||||
if (header.serial != uislave->last_serial + 1)
|
||||
meta_bug ("Wrong message serial number %d from UI slave!\n", header.serial);
|
||||
|
||||
uislave->last_serial = header.serial;
|
||||
uislave->current_required_len = header.length;
|
||||
|
||||
append_pending (uislave);
|
||||
}
|
||||
else
|
||||
goto need_more_data;
|
||||
}
|
||||
|
||||
need_more_data:
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_messages_pending (MetaUISlave *uislave)
|
||||
{
|
||||
return uislave->queue->length > 0 ||
|
||||
uislave->buf->len > 0 ||
|
||||
uislave->current_message->len > 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_prepare (GSource *source, gint *timeout)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
mq_queue_messages (uislave);
|
||||
|
||||
return mq_messages_pending (uislave);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_check (GSource *source)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
mq_queue_messages (uislave);
|
||||
uislave->out_poll.revents = 0;
|
||||
|
||||
return mq_messages_pending (uislave);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
if (uislave->queue->length > 0)
|
||||
{
|
||||
MetaUISlaveFunc func;
|
||||
MetaMessage *msg;
|
||||
static int count = 0;
|
||||
|
||||
++count;
|
||||
|
||||
msg = g_queue_pop_head (uislave->queue);
|
||||
func = (MetaUISlaveFunc) callback;
|
||||
|
||||
(* func) (uislave, msg, user_data);
|
||||
|
||||
meta_verbose ("%d messages dispatched\n", count);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
kill_child (MetaUISlave *uislave)
|
||||
{
|
||||
if (uislave->mq)
|
||||
meta_message_queue_free (uislave->mq);
|
||||
|
||||
if (uislave->errwatch != 0)
|
||||
g_source_remove (uislave->errwatch);
|
||||
|
||||
if (uislave->err_channel)
|
||||
g_io_channel_unref (uislave->err_channel);
|
||||
|
||||
if (uislave->out_poll.fd >= 0)
|
||||
{
|
||||
g_source_remove_poll ((GSource*)uislave, &uislave->out_poll);
|
||||
close (uislave->out_poll.fd);
|
||||
}
|
||||
if (uislave->out_pipe >= 0)
|
||||
close (uislave->out_pipe);
|
||||
|
||||
if (uislave->in_pipe >= 0)
|
||||
close (uislave->in_pipe);
|
||||
|
@ -487,21 +206,6 @@ kill_child (MetaUISlave *uislave)
|
|||
if (uislave->err_pipe >= 0)
|
||||
close (uislave->err_pipe);
|
||||
|
||||
while (uislave->queue->length > 0)
|
||||
{
|
||||
MetaMessage *msg;
|
||||
|
||||
msg = g_queue_pop_head (uislave->queue);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
if (uislave->buf->len > 0)
|
||||
g_string_truncate (uislave->buf, 0);
|
||||
|
||||
if (uislave->current_message->len > 0)
|
||||
g_string_truncate (uislave->current_message, 0);
|
||||
|
||||
if (uislave->child_pid > 0)
|
||||
{
|
||||
/* don't care if this fails except in verbose mode */
|
||||
|
@ -520,67 +224,84 @@ kill_child (MetaUISlave *uislave)
|
|||
static void
|
||||
reset_vals (MetaUISlave *uislave)
|
||||
{
|
||||
uislave->mq = NULL;
|
||||
uislave->child_pid = 0;
|
||||
uislave->in_pipe = -1;
|
||||
uislave->err_pipe = -1;
|
||||
uislave->out_poll.fd = -1;
|
||||
uislave->no_respawn = FALSE;
|
||||
uislave->out_pipe = -1;
|
||||
uislave->err_channel = NULL;
|
||||
uislave->errwatch = 0;
|
||||
uislave->current_required_len = 0;
|
||||
uislave->last_serial = -1;
|
||||
/* don't reset no_respawn, it's a permanent thing. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Message delivery
|
||||
*/
|
||||
|
||||
static int
|
||||
write_bytes (int fd, void *buf, int bytes)
|
||||
{
|
||||
const char *p;
|
||||
int left;
|
||||
|
||||
left = bytes;
|
||||
p = (char*) buf;
|
||||
while (left > 0)
|
||||
{
|
||||
int written;
|
||||
|
||||
written = write (fd, p, left);
|
||||
|
||||
if (written < 0)
|
||||
return -1;
|
||||
|
||||
left -= written;
|
||||
p += written;
|
||||
}
|
||||
|
||||
g_assert (p == ((char*)buf) + bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mq_destroy (GSource *source)
|
||||
send_message (MetaUISlave *uislave, MetaMessage *message)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
meta_verbose ("Deleting UI slave for display '%s'\n",
|
||||
uislave->display_name);
|
||||
static int serial = 0;
|
||||
MetaMessageFooter *footer;
|
||||
|
||||
kill_child (uislave);
|
||||
|
||||
g_string_free (uislave->buf, TRUE);
|
||||
g_string_free (uislave->current_message, TRUE);
|
||||
message->header.serial = serial;
|
||||
footer = META_MESSAGE_FOOTER (message);
|
||||
|
||||
g_queue_free (uislave->queue);
|
||||
|
||||
g_free (uislave->display_name);
|
||||
footer->checksum = META_MESSAGE_CHECKSUM (message);
|
||||
++serial;
|
||||
|
||||
/* source itself is freed by glib */
|
||||
if (write_bytes (uislave->in_pipe,
|
||||
META_MESSAGE_ESCAPE, META_MESSAGE_ESCAPE_LEN) < 0)
|
||||
meta_warning ("Failed to write escape sequence: %s\n",
|
||||
g_strerror (errno));
|
||||
if (write_bytes (uislave->in_pipe,
|
||||
message, message->header.length) < 0)
|
||||
meta_warning ("Failed to write message: %s\n",
|
||||
g_strerror (errno));
|
||||
}
|
||||
|
||||
static ReadResult
|
||||
read_data (GString *str,
|
||||
gint fd)
|
||||
void
|
||||
meta_ui_slave_show_tip (MetaUISlave *uislave,
|
||||
int root_x,
|
||||
int root_y,
|
||||
const char *markup_text)
|
||||
{
|
||||
#define BUFSIZE 4000
|
||||
gint bytes;
|
||||
gchar buf[BUFSIZE];
|
||||
MetaMessageShowTip showtip;
|
||||
|
||||
again:
|
||||
|
||||
bytes = read (fd, &buf, BUFSIZE);
|
||||
memset (&showtip, 0, META_MESSAGE_LENGTH (MetaMessageShowTip));
|
||||
showtip.header.message_code = MetaMessageShowTipCode;
|
||||
showtip.header.length = META_MESSAGE_LENGTH (MetaMessageShowTip);
|
||||
|
||||
if (bytes == 0)
|
||||
return READ_EOF;
|
||||
else if (bytes > 0)
|
||||
{
|
||||
g_string_append_len (str, buf, bytes);
|
||||
return READ_OK;
|
||||
}
|
||||
else if (bytes < 0 && errno == EINTR)
|
||||
goto again;
|
||||
else if (bytes < 0)
|
||||
{
|
||||
meta_warning (_("Failed to read data from UI slave: %s\n"),
|
||||
g_strerror (errno));
|
||||
|
||||
return READ_FAILED;
|
||||
}
|
||||
else
|
||||
return READ_OK;
|
||||
showtip.root_x = root_x;
|
||||
showtip.root_y = root_y;
|
||||
strncpy (showtip.markup, markup_text, META_MESSAGE_MAX_TIP_LEN);
|
||||
showtip.markup[META_MESSAGE_MAX_TIP_LEN] = '\0';
|
||||
|
||||
send_message (uislave, (MetaMessage*)&showtip);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "util.h"
|
||||
#include "uislave/messages.h"
|
||||
#include "messagequeue.h"
|
||||
#include "display.h"
|
||||
|
||||
typedef void (* MetaUISlaveFunc) (MetaUISlave *uislave,
|
||||
|
@ -32,20 +33,19 @@ typedef void (* MetaUISlaveFunc) (MetaUISlave *uislave,
|
|||
|
||||
struct _MetaUISlave
|
||||
{
|
||||
GSource source;
|
||||
|
||||
char *display_name;
|
||||
int child_pid;
|
||||
int in_pipe;
|
||||
int out_pipe;
|
||||
int err_pipe;
|
||||
GPollFD out_poll;
|
||||
GIOChannel *err_channel;
|
||||
unsigned int errwatch;
|
||||
GQueue *queue;
|
||||
GString *buf;
|
||||
GString *current_message;
|
||||
int current_required_len;
|
||||
int last_serial;
|
||||
|
||||
MetaMessageQueue *mq;
|
||||
|
||||
MetaUISlaveFunc func;
|
||||
gpointer data;
|
||||
|
||||
/* if we determine that our available slave is hosed,
|
||||
* set this bit.
|
||||
*/
|
||||
|
@ -58,5 +58,9 @@ MetaUISlave* meta_ui_slave_new (const char *display_name,
|
|||
void meta_ui_slave_free (MetaUISlave *uislave);
|
||||
void meta_ui_slave_disable (MetaUISlave *uislave);
|
||||
|
||||
void meta_ui_slave_show_tip (MetaUISlave *uislave,
|
||||
int root_x,
|
||||
int root_y,
|
||||
const char *markup_text);
|
||||
|
||||
#endif
|
||||
|
|
5
src/uislave/.cvsignore
Normal file
5
src/uislave/.cvsignore
Normal file
|
@ -0,0 +1,5 @@
|
|||
Makefile.in
|
||||
Makefile
|
||||
.libs
|
||||
.deps
|
||||
metacity-uislave
|
|
@ -2,6 +2,8 @@
|
|||
INCLUDES=@UISLAVE_CFLAGS@ -DHOST_ALIAS=\"@HOST_ALIAS@\"
|
||||
|
||||
metacity_uislave_SOURCES = \
|
||||
fixedtip.h \
|
||||
fixedtip.c \
|
||||
main.c \
|
||||
messages.c \
|
||||
messages.h \
|
||||
|
|
78
src/uislave/fixedtip.c
Normal file
78
src/uislave/fixedtip.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* Metacity fixed tooltip routine */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "fixedtip.h"
|
||||
|
||||
static GtkWidget *tip = NULL;
|
||||
static GtkWidget *label = NULL;
|
||||
|
||||
static gint
|
||||
expose_handler (GtkTooltips *tooltips)
|
||||
{
|
||||
gtk_paint_flat_box (tip->style, tip->window,
|
||||
GTK_STATE_NORMAL, GTK_SHADOW_OUT,
|
||||
NULL, tip, "tooltip",
|
||||
0, 0, -1, -1);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_fixed_tip_show (int root_x, int root_y,
|
||||
const char *markup_text)
|
||||
{
|
||||
if (tip == NULL)
|
||||
{
|
||||
tip = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
gtk_widget_set_app_paintable (tip, TRUE);
|
||||
gtk_window_set_policy (GTK_WINDOW (tip), FALSE, FALSE, TRUE);
|
||||
gtk_widget_set_name (tip, "gtk-tooltips");
|
||||
gtk_container_set_border_width (GTK_CONTAINER (tip), 4);
|
||||
|
||||
gtk_signal_connect_object (GTK_OBJECT (tip),
|
||||
"expose_event",
|
||||
GTK_SIGNAL_FUNC (expose_handler),
|
||||
NULL);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
|
||||
gtk_widget_show (label);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (tip), label);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (tip),
|
||||
"destroy",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
||||
&tip);
|
||||
}
|
||||
|
||||
gtk_widget_set_uposition (tip, root_x, root_y);
|
||||
gtk_label_set_markup (GTK_LABEL (label), markup_text);
|
||||
|
||||
gtk_widget_show (tip);
|
||||
}
|
||||
|
||||
void
|
||||
meta_fixed_tip_hide (void)
|
||||
{
|
||||
gtk_widget_destroy (tip);
|
||||
}
|
32
src/uislave/fixedtip.h
Normal file
32
src/uislave/fixedtip.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* Metacity fixed tooltip routine */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_FIXED_TIP_H
|
||||
#define META_FIXED_TIP_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
void meta_fixed_tip_show (int root_x, int root_y,
|
||||
const char *markup_text);
|
||||
void meta_fixed_tip_hide (void);
|
||||
|
||||
|
||||
#endif
|
|
@ -20,6 +20,9 @@
|
|||
*/
|
||||
|
||||
#include "messages.h"
|
||||
#include "messagequeue.h"
|
||||
#include "fixedtip.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -27,6 +30,47 @@
|
|||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void message_callback (MetaMessageQueue *mq,
|
||||
MetaMessage *message,
|
||||
gpointer data);
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
MetaMessageQueue *mq;
|
||||
|
||||
/* report our nature to the window manager */
|
||||
meta_message_send_check ();
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
mq = meta_message_queue_new (0, message_callback, NULL);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
message_callback (MetaMessageQueue *mq,
|
||||
MetaMessage *message,
|
||||
gpointer data)
|
||||
{
|
||||
switch (message->header.message_code)
|
||||
{
|
||||
case MetaMessageShowTipCode:
|
||||
meta_fixed_tip_show (message->show_tip.root_x,
|
||||
message->show_tip.root_y,
|
||||
message->show_tip.markup);
|
||||
break;
|
||||
|
||||
default:
|
||||
meta_ui_warning ("Unhandled message code %d\n",
|
||||
message->header.message_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_ui_warning (const char *format, ...)
|
||||
{
|
||||
|
@ -44,22 +88,16 @@ meta_ui_warning (const char *format, ...)
|
|||
g_free (str);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
|
||||
/* report our nature to the window manager */
|
||||
meta_message_send_check ();
|
||||
write (1, "abcdefghijklmnopqrstuvwxyz", 27);
|
||||
|
||||
#if 1
|
||||
/* Try breaking message queue system. */
|
||||
i = 0;
|
||||
while (i < 1500)
|
||||
{
|
||||
meta_message_send_check ();
|
||||
write (1, "abcdefghijklmnopqrstuvwxyz", 27);
|
||||
|
||||
if (g_random_boolean ())
|
||||
{
|
||||
int j;
|
||||
|
@ -79,18 +117,6 @@ main (int argc, char **argv)
|
|||
|
||||
++i;
|
||||
}
|
||||
#endif
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -20,19 +20,458 @@
|
|||
*/
|
||||
|
||||
#include "messagequeue.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef METACITY_COMPILE
|
||||
#include "util.h"
|
||||
#else
|
||||
#include "main.h"
|
||||
void
|
||||
meta_debug_spew (const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
meta_verbose (const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
meta_bug (const char *format, ...)
|
||||
{
|
||||
/* stop us in a debugger */
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
meta_warning (const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
meta_fatal (const char *format, ...)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
#endif /* !METACITY_COMPILE */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
READ_FAILED = 0, /* FALSE */
|
||||
READ_OK,
|
||||
READ_EOF
|
||||
} ReadResult;
|
||||
|
||||
static ReadResult read_data (GString *str,
|
||||
gint fd);
|
||||
|
||||
/* Message queue main loop source */
|
||||
static gboolean mq_prepare (GSource *source,
|
||||
gint *timeout);
|
||||
static gboolean mq_check (GSource *source);
|
||||
static gboolean mq_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data);
|
||||
static void mq_destroy (GSource *source);
|
||||
|
||||
static GSourceFuncs mq_funcs = {
|
||||
mq_prepare,
|
||||
mq_check,
|
||||
mq_dispatch,
|
||||
mq_destroy
|
||||
};
|
||||
|
||||
struct _MetaMessageQueue
|
||||
{
|
||||
GSource source;
|
||||
|
||||
GPollFD out_poll;
|
||||
GQueue *queue;
|
||||
GString *buf;
|
||||
GString *current_message;
|
||||
int current_required_len;
|
||||
int last_serial;
|
||||
};
|
||||
|
||||
MetaMessageQueue*
|
||||
meta_message_queue_new (int fd,
|
||||
MetaMessageQueueFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
MetaMessageQueue *mq;
|
||||
GSource *source;
|
||||
|
||||
source = g_source_new (&mq_funcs, sizeof (MetaMessageQueue));
|
||||
|
||||
mq = (MetaMessageQueue*) source;
|
||||
|
||||
mq->queue = g_queue_new ();
|
||||
mq->buf = g_string_new ("");
|
||||
mq->current_message = g_string_new ("");
|
||||
mq->current_required_len = 0;
|
||||
mq->last_serial = -1;
|
||||
mq->out_poll.fd = fd;
|
||||
mq->out_poll.events = G_IO_IN;
|
||||
|
||||
g_source_add_poll (source, &mq->out_poll);
|
||||
|
||||
g_source_set_priority (source, G_PRIORITY_DEFAULT);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
|
||||
g_source_set_callback (source, (GSourceFunc) func, data, NULL);
|
||||
|
||||
g_source_attach (source, NULL);
|
||||
|
||||
return mq;
|
||||
}
|
||||
|
||||
void
|
||||
meta_message_queue_free (MetaMessageQueue *mq)
|
||||
{
|
||||
|
||||
GSource *source;
|
||||
|
||||
source = (GSource*) mq;
|
||||
|
||||
g_source_destroy (source);
|
||||
}
|
||||
|
||||
static void
|
||||
append_pending (MetaMessageQueue *mq)
|
||||
{
|
||||
int needed;
|
||||
|
||||
needed = mq->current_required_len - mq->current_message->len;
|
||||
g_assert (needed >= 0);
|
||||
|
||||
needed = MIN (needed, mq->buf->len);
|
||||
|
||||
/* Move data from buf to current_message */
|
||||
if (needed > 0)
|
||||
{
|
||||
meta_verbose ("Moving %d bytes from buffer to current incomplete message\n",
|
||||
needed);
|
||||
g_string_append_len (mq->current_message,
|
||||
mq->buf->str,
|
||||
needed);
|
||||
g_string_erase (mq->buf,
|
||||
0, needed);
|
||||
}
|
||||
|
||||
g_assert (mq->current_message->len <= mq->current_required_len);
|
||||
|
||||
if (mq->current_required_len > 0 &&
|
||||
mq->current_message->len == mq->current_required_len)
|
||||
{
|
||||
MetaMessage *message;
|
||||
MetaMessageFooter *footer;
|
||||
|
||||
message = g_new (MetaMessage, 1);
|
||||
|
||||
memcpy (message,
|
||||
mq->current_message->str, mq->current_message->len);
|
||||
|
||||
if (message->header.length != mq->current_required_len)
|
||||
meta_bug ("Message length changed?\n");
|
||||
|
||||
if (message->header.serial != mq->last_serial)
|
||||
meta_bug ("Message serial changed?\n");
|
||||
|
||||
footer = META_MESSAGE_FOOTER (message);
|
||||
|
||||
if (footer->checksum == META_MESSAGE_CHECKSUM (message))
|
||||
{
|
||||
g_queue_push_tail (mq->queue, message);
|
||||
|
||||
meta_verbose ("Added %d-byte message serial %d to queue\n",
|
||||
mq->current_message->len, message->header.serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_bug ("Bad checksum %d on %d-byte message from UI slave\n",
|
||||
footer->checksum, mq->current_message->len);
|
||||
}
|
||||
|
||||
mq->current_required_len = 0;
|
||||
g_string_truncate (mq->current_message, 0);
|
||||
}
|
||||
else if (mq->current_required_len > 0)
|
||||
{
|
||||
meta_verbose ("Storing %d bytes of incomplete message\n",
|
||||
mq->current_message->len);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mq_queue_messages (MetaMessageQueue *mq)
|
||||
{
|
||||
if (mq->out_poll.revents & G_IO_IN)
|
||||
{
|
||||
ReadResult res;
|
||||
|
||||
res = read_data (mq->buf, mq->out_poll.fd);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case READ_OK:
|
||||
meta_verbose ("Read data from slave, %d bytes in buffer\n",
|
||||
mq->buf->len);
|
||||
break;
|
||||
case READ_EOF:
|
||||
meta_verbose ("EOF reading stdout from slave process\n");
|
||||
break;
|
||||
|
||||
case READ_FAILED:
|
||||
/* read_data printed the error */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (mq->buf->len > 0)
|
||||
{
|
||||
if (mq->current_required_len > 0)
|
||||
{
|
||||
/* We had a pending message. */
|
||||
append_pending (mq);
|
||||
}
|
||||
else if (mq->buf->len > META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
/* See if we can start a current message */
|
||||
const char *p;
|
||||
int esc_pos;
|
||||
const char *esc;
|
||||
MetaMessageHeader header;
|
||||
|
||||
g_assert (mq->current_required_len == 0);
|
||||
g_assert (mq->current_message->len == 0);
|
||||
|
||||
meta_verbose ("Scanning for escape sequence in %d bytes\n",
|
||||
mq->buf->len);
|
||||
|
||||
/* note that the data from the UI slave includes the nul byte */
|
||||
esc = META_MESSAGE_ESCAPE;
|
||||
|
||||
esc_pos = -1;
|
||||
p = mq->buf->str;
|
||||
while (p != (mq->buf->str + mq->buf->len))
|
||||
{
|
||||
if (*p == *esc)
|
||||
{
|
||||
esc_pos = 0;
|
||||
while (*p == esc[esc_pos])
|
||||
{
|
||||
++esc_pos;
|
||||
++p;
|
||||
|
||||
if (esc_pos == META_MESSAGE_ESCAPE_LEN ||
|
||||
p == (mq->buf->str + mq->buf->len))
|
||||
goto out;
|
||||
}
|
||||
|
||||
esc_pos = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (esc_pos == META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
/* We found an entire escape sequence; can safely toss
|
||||
* out the entire buffer before it
|
||||
*/
|
||||
int ignored;
|
||||
|
||||
g_assert (esc[META_MESSAGE_ESCAPE_LEN-1] == *(p-1));
|
||||
|
||||
ignored = p - mq->buf->str;
|
||||
ignored -= META_MESSAGE_ESCAPE_LEN;
|
||||
|
||||
g_assert (ignored >= 0);
|
||||
g_assert (mq->buf->str[ignored] == esc[0]);
|
||||
|
||||
if (ignored > 0)
|
||||
{
|
||||
g_string_erase (mq->buf, 0, ignored);
|
||||
meta_verbose ("Ignoring %d bytes before escape, new buffer len %d\n",
|
||||
ignored, mq->buf->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (p == (mq->buf->str + META_MESSAGE_ESCAPE_LEN));
|
||||
}
|
||||
}
|
||||
else if (esc_pos < 0)
|
||||
{
|
||||
/* End of buffer doesn't begin an escape sequence;
|
||||
* toss out entire buffer.
|
||||
*/
|
||||
meta_verbose ("Emptying %d-byte buffer not containing escape sequence\n",
|
||||
mq->buf->len);
|
||||
g_string_truncate (mq->buf, 0);
|
||||
goto need_more_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_verbose ("Buffer ends with partial escape sequence\n");
|
||||
goto need_more_data;
|
||||
}
|
||||
|
||||
g_assert (strcmp (mq->buf->str, META_MESSAGE_ESCAPE) == 0);
|
||||
|
||||
if (mq->buf->len < (META_MESSAGE_ESCAPE_LEN + sizeof (MetaMessageHeader)))
|
||||
{
|
||||
meta_verbose ("Buffer has full escape sequence but lacks header\n");
|
||||
goto need_more_data;
|
||||
}
|
||||
|
||||
g_string_erase (mq->buf, 0, META_MESSAGE_ESCAPE_LEN);
|
||||
meta_verbose ("Stripped escape off front of buffer, new buffer len %d\n",
|
||||
mq->buf->len);
|
||||
|
||||
g_assert (mq->buf->len >= sizeof (MetaMessageHeader));
|
||||
|
||||
memcpy (&header, mq->buf->str, sizeof (MetaMessageHeader));
|
||||
|
||||
/* Length includes the header even though it's in the header. */
|
||||
meta_verbose ("Read header, code: %d length: %d serial: %d\n",
|
||||
header.message_code, header.length, header.serial);
|
||||
|
||||
if (header.serial != mq->last_serial + 1)
|
||||
meta_bug ("Wrong message serial number %d from UI slave!\n", header.serial);
|
||||
|
||||
mq->last_serial = header.serial;
|
||||
mq->current_required_len = header.length;
|
||||
|
||||
append_pending (mq);
|
||||
}
|
||||
else
|
||||
goto need_more_data;
|
||||
}
|
||||
|
||||
need_more_data:
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_messages_pending (MetaMessageQueue *mq)
|
||||
{
|
||||
return mq->queue->length > 0 ||
|
||||
mq->buf->len > 0 ||
|
||||
mq->current_message->len > 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_prepare (GSource *source, gint *timeout)
|
||||
{
|
||||
MetaMessageQueue *mq;
|
||||
|
||||
mq = (MetaMessageQueue*) source;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
mq_queue_messages (mq);
|
||||
|
||||
return mq_messages_pending (mq);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_check (GSource *source)
|
||||
{
|
||||
MetaMessageQueue *mq;
|
||||
|
||||
mq = (MetaMessageQueue*) source;
|
||||
|
||||
mq_queue_messages (mq);
|
||||
mq->out_poll.revents = 0;
|
||||
|
||||
return mq_messages_pending (mq);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
MetaMessageQueue *mq;
|
||||
|
||||
mq = (MetaMessageQueue*) source;
|
||||
|
||||
if (mq->queue->length > 0)
|
||||
{
|
||||
MetaMessageQueueFunc func;
|
||||
MetaMessage *msg;
|
||||
static int count = 0;
|
||||
|
||||
++count;
|
||||
|
||||
msg = g_queue_pop_head (mq->queue);
|
||||
func = (MetaMessageQueueFunc) callback;
|
||||
|
||||
(* func) (mq, msg, user_data);
|
||||
|
||||
meta_verbose ("%d messages dispatched\n", count);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
mq_destroy (GSource *source)
|
||||
{
|
||||
MetaMessageQueue *mq;
|
||||
|
||||
mq = (MetaMessageQueue*) source;
|
||||
|
||||
while (mq->queue->length > 0)
|
||||
{
|
||||
MetaMessage *msg;
|
||||
|
||||
msg = g_queue_pop_head (mq->queue);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
g_string_free (mq->buf, TRUE);
|
||||
g_string_free (mq->current_message, TRUE);
|
||||
|
||||
g_queue_free (mq->queue);
|
||||
|
||||
/* source itself is freed by glib */
|
||||
}
|
||||
|
||||
static ReadResult
|
||||
read_data (GString *str,
|
||||
gint fd)
|
||||
{
|
||||
#define BUFSIZE 1024
|
||||
gint bytes;
|
||||
gchar buf[BUFSIZE];
|
||||
|
||||
again:
|
||||
|
||||
bytes = read (fd, &buf, BUFSIZE);
|
||||
|
||||
if (bytes == 0)
|
||||
return READ_EOF;
|
||||
else if (bytes > 0)
|
||||
{
|
||||
g_string_append_len (str, buf, bytes);
|
||||
return READ_OK;
|
||||
}
|
||||
else if (bytes < 0 && errno == EINTR)
|
||||
goto again;
|
||||
else if (bytes < 0)
|
||||
{
|
||||
meta_warning (_("Failed to read data from UI slave: %s\n"),
|
||||
g_strerror (errno));
|
||||
|
||||
return READ_FAILED;
|
||||
}
|
||||
else
|
||||
return READ_OK;
|
||||
}
|
||||
|
|
|
@ -36,18 +36,6 @@ typedef void (* MetaMessageQueueFunc) (MetaMessageQueue *mq,
|
|||
MetaMessage *message,
|
||||
gpointer data);
|
||||
|
||||
struct _MetaMessageQueue
|
||||
{
|
||||
GSource source;
|
||||
|
||||
GPollFD out_poll;
|
||||
GQueue *queue;
|
||||
GString *buf;
|
||||
GString *current_message;
|
||||
int current_required_len;
|
||||
int last_serial;
|
||||
};
|
||||
|
||||
MetaMessageQueue* meta_message_queue_new (int fd,
|
||||
MetaMessageQueueFunc func,
|
||||
gpointer data);
|
||||
|
|
|
@ -42,9 +42,6 @@ static ReadResult read_data (GString *str,
|
|||
|
||||
static void send_message (MetaMessage *message);
|
||||
|
||||
#define META_MESSAGE_LENGTH(real_type) \
|
||||
(G_STRUCT_OFFSET (real_type, footer) + sizeof (MetaMessageFooter))
|
||||
|
||||
void
|
||||
meta_message_send_check (void)
|
||||
{
|
||||
|
@ -53,10 +50,13 @@ meta_message_send_check (void)
|
|||
memset (&check, 0, META_MESSAGE_LENGTH (MetaMessageCheck));
|
||||
check.header.message_code = MetaMessageCheckCode;
|
||||
check.header.length = META_MESSAGE_LENGTH (MetaMessageCheck);
|
||||
strcpy (check.metacity_version, VERSION);
|
||||
strcpy (check.host_alias, HOST_ALIAS);
|
||||
|
||||
strncpy (check.metacity_version, VERSION, META_MESSAGE_MAX_VERSION_LEN);
|
||||
check.metacity_version[META_MESSAGE_MAX_VERSION_LEN] = '\0';
|
||||
|
||||
strncpy (check.host_alias, HOST_ALIAS, META_MESSAGE_MAX_HOST_ALIAS_LEN);
|
||||
check.host_alias[META_MESSAGE_MAX_HOST_ALIAS_LEN] = '\0';
|
||||
|
||||
check.messages_version = META_MESSAGES_VERSION;
|
||||
|
||||
send_message ((MetaMessage*)&check);
|
||||
|
|
|
@ -51,12 +51,14 @@
|
|||
/* This is totally useless of course. Playing around. */
|
||||
#define META_MESSAGE_CHECKSUM(msg) ((msg)->header.length | (msg)->header.serial << 16)
|
||||
#define META_MESSAGE_FOOTER(msg) ((MetaMessageFooter*) (((char*)(msg)) + ((msg)->header.length - sizeof (MetaMessageFooter))));
|
||||
#define META_MESSAGE_LENGTH(real_type) \
|
||||
(G_STRUCT_OFFSET (real_type, footer) + sizeof (MetaMessageFooter))
|
||||
|
||||
#define META_MESSAGE_MAX_SIZE (sizeof(MetaMessage));
|
||||
|
||||
#define META_MESSAGE_MAX_VERSION_LEN 15
|
||||
#define META_MESSAGE_MAX_HOST_ALIAS_LEN 50
|
||||
#define META_MESSAGE_MAX_TIP_TEXT 128
|
||||
#define META_MESSAGE_MAX_TIP_LEN 128
|
||||
|
||||
typedef union _MetaMessage MetaMessage;
|
||||
typedef struct _MetaMessageHeader MetaMessageHeader;
|
||||
|
@ -111,7 +113,7 @@ struct _MetaMessageShowTip
|
|||
MetaMessageHeader header;
|
||||
int root_x;
|
||||
int root_y;
|
||||
char markup[META_MESSAGE_MAX_TIP_TEXT];
|
||||
char markup[META_MESSAGE_MAX_TIP_LEN + 1];
|
||||
MetaMessageFooter footer;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue