summaryrefslogtreecommitdiff
path: root/plugins/resistance
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/resistance')
-rw-r--r--plugins/resistance/.cvsignore8
-rw-r--r--plugins/resistance/Makefile.am32
-rw-r--r--plugins/resistance/resistance.c275
-rw-r--r--plugins/resistance/resistance.glade109
-rw-r--r--plugins/resistance/resistance.gladep8
-rw-r--r--plugins/resistance/resistance.h2
-rw-r--r--plugins/resistance/resistance_config.c64
7 files changed, 498 insertions, 0 deletions
diff --git a/plugins/resistance/.cvsignore b/plugins/resistance/.cvsignore
new file mode 100644
index 00000000..fe97c5fa
--- /dev/null
+++ b/plugins/resistance/.cvsignore
@@ -0,0 +1,8 @@
+.deps
+.libs
+Makefile
+Makefile.in
+resistance-config.la
+resistance.la
+resistance_config_la-resistance_config.lo
+resistance_la-resistance.lo
diff --git a/plugins/resistance/Makefile.am b/plugins/resistance/Makefile.am
new file mode 100644
index 00000000..9f95f947
--- /dev/null
+++ b/plugins/resistance/Makefile.am
@@ -0,0 +1,32 @@
+plugindir=$(libdir)/openbox/plugins
+
+CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \
+ $(XML_CFLAGS) @CPPFLAGS@ \
+ -DPLUGINDIR=\"$(plugindir)\"
+
+INCLUDES=-I../.. -I../../tools
+
+plugin_LTLIBRARIES=resistance.la
+if OBCONF
+plugin_LTLIBRARIES+=resistance-config.la
+endif
+
+resistance_la_CPPFLAGS=-DG_LOG_DOMAIN=\"Plugin-Resistance\"
+resistance_la_LDFLAGS=-module -avoid-version
+resistance_la_SOURCES=resistance.c
+
+if OBCONF
+resistance_config_la_CPPFLAGS=-DG_LOG_DOMAIN=\"Plugin-Resistance\" \
+ $(GTK_CFLAGS) $(GLADE_CFLAGS)
+resistance_config_la_LDFLAGS=-module -avoid-version
+resistance_config_la_SOURCES=resistance_config.c
+endif
+
+noinst_HEADERS=resistance.h
+
+noinst_DATA=resistance.glade resistance.gladep
+
+MAINTAINERCLEANFILES= Makefile.in
+
+distclean-local:
+ $(RM) *\~ *.orig *.rej .\#*
diff --git a/plugins/resistance/resistance.c b/plugins/resistance/resistance.c
new file mode 100644
index 00000000..91c10c0e
--- /dev/null
+++ b/plugins/resistance/resistance.c
@@ -0,0 +1,275 @@
+#include "kernel/dispatch.h"
+#include "kernel/client.h"
+#include "kernel/frame.h"
+#include "kernel/stacking.h"
+#include "kernel/screen.h"
+#include "parser/parse.h"
+#include "resistance.h"
+#include <glib.h>
+
+static int resistance;
+static gboolean resist_windows;
+
+static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d)
+{
+ xmlNodePtr n;
+
+ if ((n = parse_find_node("strength", node)))
+ resistance = parse_int(doc, n);
+ if ((n = parse_find_node("windows", node)))
+ resist_windows = parse_bool(doc, n);
+}
+
+void plugin_setup_config()
+{
+ resistance = DEFAULT_RESISTANCE;
+ resist_windows = DEFAULT_RESIST_WINDOWS;
+
+ parse_register("resistance", parse_xml, NULL);
+}
+
+static void resist_move(Client *c, int *x, int *y)
+{
+ GList *it;
+ Rect *area;
+ int l, t, r, b; /* requested edges */
+ int al, at, ar, ab; /* screen area edges */
+ int cl, ct, cr, cb; /* current edges */
+ int w, h; /* current size */
+ Client *snapx = NULL, *snapy = NULL;
+
+ w = c->frame->area.width;
+ h = c->frame->area.height;
+
+ l = *x;
+ t = *y;
+ r = l + w - 1;
+ b = t + h - 1;
+
+ cl = c->frame->area.x;
+ ct = c->frame->area.y;
+ cr = cl + c->frame->area.width - 1;
+ cb = ct + c->frame->area.height - 1;
+
+ /* snap to other clients */
+ if (resist_windows)
+ for (it = stacking_list; it != NULL; it = it->next) {
+ Client *target;
+ int tl, tt, tr, tb; /* 1 past the target's edges on each side */
+
+ if (!WINDOW_IS_CLIENT(it->data))
+ continue;
+ target = it->data;
+ /* don't snap to self or non-visibles */
+ if (!target->frame->visible || target == c) continue;
+
+ tl = target->frame->area.x - 1;
+ tt = target->frame->area.y - 1;
+ tr = tl + target->frame->area.width + 1;
+ tb = tt + target->frame->area.height + 1;
+
+ /* snapx and snapy ensure that the window snaps to the top-most
+ window edge available, without going all the way from
+ bottom-to-top in the stacking list
+ */
+ if (snapx == NULL) {
+ if (ct < tb && cb > tt) {
+ if (cl >= tr && l < tr && l >= tr - resistance)
+ *x = tr, snapx = target;
+ else if (cr <= tl && r > tl && r <= tl + resistance)
+ *x = tl - w + 1, snapx = target;
+ if (snapx != NULL) {
+ /* try to corner snap to the window */
+ if (ct > tt && t <= tt && t > tt - resistance)
+ *y = tt + 1, snapy = target;
+ else if (cb < tb && b >= tb && b < tb + resistance)
+ *y = tb - h, snapy = target;
+ }
+ }
+ }
+ if (snapy == NULL) {
+ if (cl < tr && cr > tl) {
+ if (ct >= tb && t < tb && t >= tb - resistance)
+ *y = tb, snapy = target;
+ else if (cb <= tt && b > tt && b <= tt + resistance)
+ *y = tt - h + 1, snapy = target;
+ if (snapy != NULL) {
+ /* try to corner snap to the window */
+ if (cl > tl && l <= tl && l > tl - resistance)
+ *x = tl + 1, snapx = target;
+ else if (cr < tr && r >= tr && r < tr + resistance)
+ *x = tr - w, snapx = target;
+ }
+ }
+ }
+
+ if (snapx && snapy) break;
+ }
+
+ /* get the screen boundaries */
+ area = screen_area(c->desktop);
+ al = area->x;
+ at = area->y;
+ ar = al + area->width - 1;
+ ab = at + area->height - 1;
+
+ /* snap to screen edges */
+ if (cl >= al && l < al && l >= al - resistance)
+ *x = al;
+ else if (cr <= ar && r > ar && r <= ar + resistance)
+ *x = ar - w + 1;
+ if (ct >= at && t < at && t >= at - resistance)
+ *y = at;
+ else if (cb <= ab && b > ab && b < ab + resistance)
+ *y = ab - h + 1;
+}
+
+static void resist_size(Client *c, int *w, int *h, Corner corn)
+{
+ GList *it;
+ Client *target; /* target */
+ int l, t, r, b; /* my left, top, right and bottom sides */
+ int dlt, drb; /* my destination left/top and right/bottom sides */
+ int tl, tt, tr, tb; /* target's left, top, right and bottom bottom sides */
+ Rect *area;
+ int al, at, ar, ab; /* screen boundaries */
+ Client *snapx = NULL, *snapy = NULL;
+
+ /* don't snap windows with size increments */
+ if (c->size_inc.width > 1 || c->size_inc.height > 1)
+ return;
+
+ l = c->frame->area.x;
+ r = l + c->frame->area.width - 1;
+ t = c->frame->area.y;
+ b = t + c->frame->area.height - 1;
+
+ /* get the screen boundaries */
+ area = screen_area(c->desktop);
+ al = area->x;
+ at = area->y;
+ ar = al + area->width - 1;
+ ab = at + area->height - 1;
+
+ /* snap to other windows */
+ if (resist_windows) {
+ for (it = stacking_list; it != NULL; it = it->next) {
+ if (!WINDOW_IS_CLIENT(it->data))
+ continue;
+ target = it->data;
+
+ /* don't snap to invisibles or ourself */
+ if (!target->frame->visible || target == c) continue;
+
+ tl = target->frame->area.x;
+ tr = target->frame->area.x + target->frame->area.width - 1;
+ tt = target->frame->area.y;
+ tb = target->frame->area.y + target->frame->area.height - 1;
+
+ if (snapx == NULL) {
+ /* horizontal snapping */
+ if (t < tb && b > tt) {
+ switch (corn) {
+ case Corner_TopLeft:
+ case Corner_BottomLeft:
+ dlt = l;
+ drb = r + *w - c->frame->area.width;
+ if (r < tl && drb >= tl && drb < tl + resistance)
+ *w = tl - l, snapx = target;
+ break;
+ case Corner_TopRight:
+ case Corner_BottomRight:
+ dlt = l - *w + c->frame->area.width;
+ drb = r;
+ if (l > tr && dlt <= tr && dlt > tr - resistance)
+ *w = r - tr, snapx = target;
+ break;
+ }
+ }
+ }
+
+ if (snapy == NULL) {
+ /* vertical snapping */
+ if (l < tr && r > tl) {
+ switch (corn) {
+ case Corner_TopLeft:
+ case Corner_TopRight:
+ dlt = t;
+ drb = b + *h - c->frame->area.height;
+ if (b < tt && drb >= tt && drb < tt + resistance)
+ *h = tt - t, snapy = target;
+ break;
+ case Corner_BottomLeft:
+ case Corner_BottomRight:
+ dlt = t - *h + c->frame->area.height;
+ drb = b;
+ if (t > tb && dlt <= tb && dlt > tb - resistance)
+ *h = b - tb, snapy = target;
+ break;
+ }
+ }
+ }
+
+ /* snapped both ways */
+ if (snapx && snapy) break;
+ }
+ }
+
+ /* snap to screen edges */
+
+ /* horizontal snapping */
+ switch (corn) {
+ case Corner_TopLeft:
+ case Corner_BottomLeft:
+ dlt = l;
+ drb = r + *w - c->frame->area.width;
+ if (r <= ar && drb > ar && drb <= ar + resistance)
+ *w = ar - l + 1;
+ break;
+ case Corner_TopRight:
+ case Corner_BottomRight:
+ dlt = l - *w + c->frame->area.width;
+ drb = r;
+ if (l >= al && dlt < al && dlt >= al - resistance)
+ *w = r - al + 1;
+ break;
+ }
+
+ /* vertical snapping */
+ switch (corn) {
+ case Corner_TopLeft:
+ case Corner_TopRight:
+ dlt = t;
+ drb = b + *h - c->frame->area.height;
+ if (b <= ab && drb > ab && drb <= ab + resistance)
+ *h = ab - t + 1;
+ break;
+ case Corner_BottomLeft:
+ case Corner_BottomRight:
+ dlt = t - *h + c->frame->area.height;
+ drb = b;
+ if (t >= at && dlt < at && dlt >= at - resistance)
+ *h = b - at + 1;
+ break;
+ }
+}
+
+static void event(ObEvent *e, void *foo)
+{
+ if (e->type == Event_Client_Moving)
+ resist_move(e->data.c.client, &e->data.c.num[0], &e->data.c.num[1]);
+ else if (e->type == Event_Client_Resizing)
+ resist_size(e->data.c.client, &e->data.c.num[0], &e->data.c.num[1],
+ e->data.c.num[2]);
+}
+
+void plugin_startup()
+{
+ dispatch_register(Event_Client_Moving | Event_Client_Resizing,
+ (EventHandler)event, NULL);
+}
+
+void plugin_shutdown()
+{
+ dispatch_register(0, (EventHandler)event, NULL);
+}
diff --git a/plugins/resistance/resistance.glade b/plugins/resistance/resistance.glade
new file mode 100644
index 00000000..ecb52b0e
--- /dev/null
+++ b/plugins/resistance/resistance.glade
@@ -0,0 +1,109 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="resistwindow">
+ <property name="title" translatable="yes"></property>
+ <property name="type">GTK_WINDOW_POPUP</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Strength</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.49</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">resist_strength</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="resist_strength">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Set to the amount of resistance to provide when moving or resizing a window past a screen or window edge. A value of 0 disables resistance.</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 0 30 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="resist_windows">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Resist other _Windows</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/plugins/resistance/resistance.gladep b/plugins/resistance/resistance.gladep
new file mode 100644
index 00000000..1951d46b
--- /dev/null
+++ b/plugins/resistance/resistance.gladep
@@ -0,0 +1,8 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
+
+<glade-project>
+ <name>resistance</name>
+ <program_name>resistance</program_name>
+ <gnome_support>FALSE</gnome_support>
+</glade-project>
diff --git a/plugins/resistance/resistance.h b/plugins/resistance/resistance.h
new file mode 100644
index 00000000..5bec224b
--- /dev/null
+++ b/plugins/resistance/resistance.h
@@ -0,0 +1,2 @@
+#define DEFAULT_RESISTANCE 10
+#define DEFAULT_RESIST_WINDOWS TRUE
diff --git a/plugins/resistance/resistance_config.c b/plugins/resistance/resistance_config.c
new file mode 100644
index 00000000..1384fe3f
--- /dev/null
+++ b/plugins/resistance/resistance_config.c
@@ -0,0 +1,64 @@
+#include "plugins/obconf_interface.h"
+#include "parser/parse.h"
+#include "resistance.h"
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+static GtkWidget *conf_widget;
+static GtkCheckButton *conf_resist_windows;
+static GtkSpinButton *conf_resist_strength;
+static gboolean conf_edited = FALSE;
+
+int plugin_interface_version() { return OBCONF_INTERFACE_VERSION; }
+
+char *plugin_name() { return "Resistance"; }
+char *plugin_plugin_name() { return "resistance"; }
+void plugin_icon() {}
+
+GtkWidget *plugin_toplevel_widget() { return conf_widget; }
+
+gboolean plugin_edited() { return conf_edited; }
+
+void plugin_load(xmlDocPtr doc, xmlNodePtr root)
+{
+ xmlNodePtr node, n;
+
+ gtk_spin_button_set_value(conf_resist_strength, DEFAULT_RESISTANCE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(conf_resist_windows),
+ DEFAULT_RESIST_WINDOWS);
+
+ node = parse_find_node("resistance", root);
+ while (node) {
+ if ((n = parse_find_node("strength", node)))
+ gtk_spin_button_set_value(conf_resist_strength,
+ parse_int(doc, n));
+ if ((n = parse_find_node("windows", node)))
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON(conf_resist_windows),
+ parse_bool(doc, n));
+
+ node = parse_find_node("resistance", node->next);
+ }
+}
+
+void plugin_save(xmlDocPtr doc, xmlNodePtr root)
+{
+}
+
+void plugin_startup()
+{
+ GladeXML *xml;
+
+ xml = glade_xml_new("obconf.glade", NULL, NULL);
+ glade_xml_signal_autoconnect(xml);
+
+ conf_widget = glade_xml_get_widget(xml, "resistwindow");
+ conf_resist_strength =
+ GTK_SPIN_BUTTON(glade_xml_get_widget(xml, "resist_strength"));
+ conf_resist_windows =
+ GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "resist_windows"));
+}
+
+void plugin_shutdown()
+{
+}