summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrhp <rhp>2001-06-03 07:41:36 +0000
committerrhp <rhp>2001-06-03 07:41:36 +0000
commit11fde3a11a88d8e13d6e6c99d8012c60b8ad6547 (patch)
tree808db94c6a90d94fe212729f576845a99e37dcf6 /src
parentc82a582a940e2a1cf71f53e48c27b998f4be316e (diff)
downloadmetacity-11fde3a11a88d8e13d6e6c99d8012c60b8ad6547.tar.gz
metacity-11fde3a11a88d8e13d6e6c99d8012c60b8ad6547.tar.bz2
...
Diffstat (limited to 'src')
-rw-r--r--src/.cvsignore7
-rw-r--r--src/Makefile.am17
-rw-r--r--src/display.c2
-rw-r--r--src/fixedtip.c78
-rw-r--r--src/fixedtip.h32
-rw-r--r--src/frame.c9
-rw-r--r--src/main.c4
-rw-r--r--src/screen.h4
-rw-r--r--src/uislave.c475
-rw-r--r--src/uislave.h20
-rw-r--r--src/uislave/.cvsignore5
-rw-r--r--src/uislave/Makefile.am2
-rw-r--r--src/uislave/fixedtip.c78
-rw-r--r--src/uislave/fixedtip.h32
-rw-r--r--src/uislave/main.c70
-rw-r--r--src/uislave/messagequeue.c439
-rw-r--r--src/uislave/messagequeue.h12
-rw-r--r--src/uislave/messages.c10
-rw-r--r--src/uislave/messages.h6
19 files changed, 870 insertions, 432 deletions
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 0000000..37889d6
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,7 @@
+.libs
+Makefile.in
+Makefile
+.deps
+metacity
+messagequeue.h
+messagequeue.c
diff --git a/src/Makefile.am b/src/Makefile.am
index eef9aae..9f4f4f2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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= \
diff --git a/src/display.c b/src/display.c
index 95718f8..61bc14f 100644
--- a/src/display.c
+++ b/src/display.c
@@ -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?
diff --git a/src/fixedtip.c b/src/fixedtip.c
new file mode 100644
index 0000000..bb12e40
--- /dev/null
+++ b/src/fixedtip.c
@@ -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);
+}
diff --git a/src/fixedtip.h b/src/fixedtip.h
new file mode 100644
index 0000000..4b637fc
--- /dev/null
+++ b/src/fixedtip.h
@@ -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
diff --git a/src/frame.c b/src/frame.c
index 6d4adf9..2f42dbe 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -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;
}
diff --git a/src/main.c b/src/main.c
index c1c3d9c..bfd62b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);
diff --git a/src/screen.h b/src/screen.h
index c66cef6..b335133 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -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,
diff --git a/src/uislave.c b/src/uislave.c
index 1e372c2..994cb59 100644
--- a/src/uislave.c
+++ b/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);
-
-/* 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
-};
+static void message_queue_func (MetaMessageQueue *mq,
+ MetaMessage* message,
+ gpointer data);
+
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);
+
+ kill_child (uislave);
- g_source_destroy (source);
+ g_free (uislave->display_name);
+
+ g_free (uislave);
}
void
@@ -115,6 +88,18 @@ meta_ui_slave_disable (MetaUISlave *uislave)
}
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)
{
GError *error;
@@ -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,
@@ -267,219 +186,19 @@ error_callback (GIOChannel *source,
}
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. */
}
-static void
-mq_destroy (GSource *source)
+/*
+ * Message delivery
+ */
+
+static int
+write_bytes (int fd, void *buf, int bytes)
{
- MetaUISlave *uislave;
+ const char *p;
+ int left;
- uislave = (MetaUISlave*) source;
+ left = bytes;
+ p = (char*) buf;
+ while (left > 0)
+ {
+ int written;
- meta_verbose ("Deleting UI slave for display '%s'\n",
- uislave->display_name);
-
- kill_child (uislave);
+ written = write (fd, p, left);
+
+ if (written < 0)
+ return -1;
+
+ left -= written;
+ p += written;
+ }
- g_string_free (uislave->buf, TRUE);
- g_string_free (uislave->current_message, TRUE);
+ g_assert (p == ((char*)buf) + bytes);
- g_queue_free (uislave->queue);
+ return 0;
+}
- g_free (uislave->display_name);
+static void
+send_message (MetaUISlave *uislave, MetaMessage *message)
+{
+ static int serial = 0;
+ MetaMessageFooter *footer;
+
+ message->header.serial = serial;
+ footer = META_MESSAGE_FOOTER (message);
- /* source itself is freed by glib */
+ footer->checksum = META_MESSAGE_CHECKSUM (message);
+ ++serial;
+
+ 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);
}
diff --git a/src/uislave.h b/src/uislave.h
index 9b959b6..09c59dd 100644
--- a/src/uislave.h
+++ b/src/uislave.h
@@ -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
diff --git a/src/uislave/.cvsignore b/src/uislave/.cvsignore
new file mode 100644
index 0000000..603f53e
--- /dev/null
+++ b/src/uislave/.cvsignore
@@ -0,0 +1,5 @@
+Makefile.in
+Makefile
+.libs
+.deps
+metacity-uislave
diff --git a/src/uislave/Makefile.am b/src/uislave/Makefile.am
index 89b6f26..b70f946 100644
--- a/src/uislave/Makefile.am
+++ b/src/uislave/Makefile.am
@@ -2,6 +2,8 @@
INCLUDES=@UISLAVE_CFLAGS@ -DHOST_ALIAS=\"@HOST_ALIAS@\"
metacity_uislave_SOURCES = \
+ fixedtip.h \
+ fixedtip.c \
main.c \
messages.c \
messages.h \
diff --git a/src/uislave/fixedtip.c b/src/uislave/fixedtip.c
new file mode 100644
index 0000000..bb12e40
--- /dev/null
+++ b/src/uislave/fixedtip.c
@@ -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);
+}
diff --git a/src/uislave/fixedtip.h b/src/uislave/fixedtip.h
new file mode 100644
index 0000000..4b637fc
--- /dev/null
+++ b/src/uislave/fixedtip.h
@@ -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
diff --git a/src/uislave/main.c b/src/uislave/main.c
index 13d7efc..fc4f9ae 100644
--- a/src/uislave/main.c
+++ b/src/uislave/main.c
@@ -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
diff --git a/src/uislave/messagequeue.c b/src/uislave/messagequeue.c
index 20fd755..da9e69a 100644
--- a/src/uislave/messagequeue.c
+++ b/src/uislave/messagequeue.c
@@ -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;
}
diff --git a/src/uislave/messagequeue.h b/src/uislave/messagequeue.h
index 6d38de7..763716f 100644
--- a/src/uislave/messagequeue.h
+++ b/src/uislave/messagequeue.h
@@ -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);
diff --git a/src/uislave/messages.c b/src/uislave/messages.c
index 1fb1df4..fe3eb16 100644
--- a/src/uislave/messages.c
+++ b/src/uislave/messages.c
@@ -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);
diff --git a/src/uislave/messages.h b/src/uislave/messages.h
index 50fa3a9..c4fadd2 100644
--- a/src/uislave/messages.h
+++ b/src/uislave/messages.h
@@ -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;
};